Let’s re-use our classifier net of license plate letters to see how it behaves as a feature map of images including more than one letter. Replacing the innerproduct layers with convolution layers with the same parameters will enable to create a feature map as on the left picture :

I’ll use Caffe’s python interface .

import numpy as np import matplotlib.pyplot as plt % matplotlib inline from PIL import Image import lmdb import caffe plt . rcParams [ 'figure.figsize' ] = ( 1 , 1 ) plt . rcParams [ 'image.interpolation' ] = 'nearest' plt . rcParams [ 'image.cmap' ] = 'gray'

Have a look at the training data
env = lmdb . open ( 'test_lmdb' ) t = [ 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z' , '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ]; def get ( k ): with env . begin () as txn : raw_datum = txn . get ( k ) datum = caffe . proto . caffe_pb2 . Datum () datum . ParseFromString ( raw_datum ) flat_x = np . fromstring ( datum . data , dtype = np . uint8 ) x = flat_x . reshape ( datum . channels , datum . height , datum . width ) y = datum . label plt . imshow ( x [ 0 , ... ], cmap = 'gray' ) plt . show () print t [ y ] get ( b '00000006' ) get ( b '00000009' )

Test the network for classification
caffe . set_mode_cpu () net = caffe . Net ( 'lenet_train_test_withoutdata.prototxt' , 'lenet_iter_2000.caffemodel' , caffe . TEST ) print ( "blobs {} \n params {}" . format ( net . blobs . keys (), net . params . keys ())) im = np . array ( Image . open ( 'input/8.png' )) plt . title ( "original image" ) plt . imshow ( im ) plt . axis ( 'off' )

will output

```
blobs ['data', 'conv1', 'pool1', 'conv2', 'pool2', 'dropout', 'ip1', 'ip2-alpha']
params ['conv1', 'conv2', 'ip1', 'ip2-alpha']
(-0.5, 27.5, 27.5, -0.5)
```

im . shape im_input = im [ np . newaxis , np . newaxis , :, :] net . blobs [ 'data' ] . reshape ( * im_input . shape ) net . blobs [ 'data' ] . data [ ... ] = im_input plt . rcParams [ 'figure.figsize' ] = ( 10 , 10 ) out = net . forward () plt . figure () filt_min , filt_max = net . blobs [ 'conv1' ] . data . min (), net . blobs [ 'conv1' ] . data . max () for i in range ( 9 ): plt . subplot ( 1 , 10 , i + 2 ) plt . title ( "filter #{} output" . format ( i )) plt . imshow ( net . blobs [ 'conv1' ] . data [ 0 , i ], vmin = filt_min , vmax = filt_max ) print ( "The result is {}" . format ( t [ out [ 'ip2-alpha' ] . argmax ()]))

#Feature map

Let’s cast the innerproduct layers ‘ip1’ and ‘ip2-alpha’ into convolution layers ‘ip1-conv’ and ‘ip2-alpha-conv’ :

```
!diff lenet_train_test_withoutdata.prototxt lenet_train_test_featuremap.prototxt
1c1
< name: "LeNet"
---
> name: "LeNetConv"
82,83c82,83
< name: "ip1"
< type: "InnerProduct"
---
> name: "ip1-conv"
> type: "Convolution"
85,92c85,86
< top: "ip1"
< param {
< lr_mult: 1
< }
< param {
< lr_mult: 2
< }
< inner_product_param {
---
> top: "ip1-conv"
> convolution_param {
94,99c88
< weight_filler {
< type: "xavier"
< }
< bias_filler {
< type: "constant"
< }
---
> kernel_size: 1
105,106c94,95
< bottom: "ip1"
< top: "ip1"
---
> bottom: "ip1-conv"
> top: "ip1-conv"
109,119c98,102
< name: "ip2-alpha"
< type: "InnerProduct"
< bottom: "ip1"
< top: "ip2-alpha"
< param {
< lr_mult: 1
< }
< param {
< lr_mult: 2
< }
< inner_product_param {
---
> name: "ip2-alpha-conv"
> type: "Convolution"
> bottom: "ip1-conv"
> top: "ip2-alpha-conv"
> convolution_param {
121,126c104
< weight_filler {
< type: "xavier"
< }
< bias_filler {
< type: "constant"
< }
---
> kernel_size: 1
```

params = [ 'ip1' , 'ip2-alpha' ] # fc_params = {name: (weights, biases)} fc_params = { pr : ( net . params [ pr ][ 0 ] . data , net . params [ pr ][ 1 ] . data ) for pr in params } for fc in params : print '{} weights are {} dimensional and biases are {} dimensional' . format ( fc , fc_params [ fc ][ 0 ] . shape , fc_params [ fc ][ 1 ] . shape )

outputs

```
ip1 weights are (500, 800) dimensional and biases are (500,) dimensional
ip2-alpha weights are (36, 500) dimensional and biases are (36,) dimensional
```

# Load the fully convolutional network to transplant the parameters. net_full_conv = caffe . Net ( 'lenet_train_test_featuremap.prototxt' , 'lenet_iter_2000.caffemodel' , caffe . TEST ) params_full_conv = [ 'ip1-conv' , 'ip2-alpha-conv' ] # conv_params = {name: (weights, biases)} conv_params = { pr : ( net_full_conv . params [ pr ][ 0 ] . data , net_full_conv . params [ pr ][ 1 ] . data ) for pr in params_full_conv } for conv in params_full_conv : print '{} weights are {} dimensional and biases are {} dimensional' . format ( conv , conv_params [ conv ][ 0 ] . shape , conv_params [ conv ][ 1 ] . shape )

outputs

```
ip1-conv weights are (500, 50, 1, 1) dimensional and biases are (500,) dimensional
ip2-alpha-conv weights are (36, 500, 1, 1) dimensional and biases are (36,) dimensional
```

for pr , pr_conv in zip ( params , params_full_conv ): conv_params [ pr_conv ][ 0 ] . flat = fc_params [ pr ][ 0 ] . flat # flat unrolls the arrays conv_params [ pr_conv ][ 1 ][ ... ] = fc_params [ pr ][ 1 ] net_full_conv . save ( 'lenet_train_test__full_conv.caffemodel' ) plt . rcParams [ 'figure.figsize' ] = ( 10 , 5 ) im = np . array ( Image . open ( 'input/p1.jpg' )) plt . title ( "original image" ) plt . imshow ( im ) plt . axis ( 'off' ) im . shape #(322, 800, 3)

import cv2 im_gray = cv2 . cvtColor ( im , cv2 . COLOR_BGR2GRAY ) im_gray = cv2 . resize ( im_gray , None , fx = 0.9 , fy = 0.9 , interpolation = cv2 . INTER_AREA ) plt . title ( "Gray image" ) plt . imshow ( im_gray ) plt . axis ( 'off' ) im_gray . shape #(290, 720)

im_input = im_gray [ np . newaxis , np . newaxis , :, :] net_full_conv . blobs [ 'data' ] . reshape ( * im_input . shape ) net_full_conv . blobs [ 'data' ] . data [ ... ] = im_input out = net_full_conv . forward () out [ 'ip2-alpha-conv' ] . shape # (1, 36, 70, 177) # show net input and confidence map (probability of the top prediction at each location) plt . subplot ( 1 , 2 , 1 ) plt . imshow ( net_full_conv . blobs [ 'data' ] . data [ 0 , 0 ]) plt . subplot ( 1 , 2 , 2 ) plt . imshow ( out [ 'ip2-alpha-conv' ][ 0 , 0 ] )

Here we are !