In [46]:
import caffe
import numpy as np
import matplotlib.pyplot as plt
import os
from keras.datasets import mnist
from caffe.proto import caffe_pb2
import google.protobuf.text_format
plt.rcParams['image.cmap'] = 'gray'
%matplotlib inline
Loading the model
In [2]:
model_def = 'example_caffe_mnist_model.prototxt'
model_weights = 'mnist.caffemodel'
net = caffe.Net(model_def, model_weights, caffe.TEST)
A Caffe net offers a layer dict that maps layer names to layer objects. These objects do not provide very much information though, but access to their weights and the type of the layer.
In [3]:
net.layer_dict
Out[3]:
In [6]:
conv_layer = net.layer_dict['conv2d_1']
conv_layer.type, conv_layer.blobs[0].data.shape
Out[6]:
In [19]:
for name, blob in net.blobs.items():
print('{}: \t {}'.format(name, blob.data.shape))
In [10]:
net.params
Out[10]:
In [23]:
for name, param in net.params.items():
print('{}:\t {} \t{}'.format(name, param[0].data.shape, param[1].data.shape))
The weights are also accessible through the layer blobs.
In [24]:
for layer in net.layers:
try:
print (layer.type + '\t' + str(layer.blobs[0].data.shape), str(layer.blobs[1].data.shape))
except:
continue
In [29]:
weights = net.params['conv2d_1'][0].data
weights.shape
Out[29]:
For visualizing the weights the axis still have to be moved around.
In [36]:
for i in range(32):
plt.imshow(np.moveaxis(weights[i], 0, -1)[..., 0])
plt.show()
Layers that have no weights simply keep empty lists as their blob vector.
In [27]:
list(net.layer_dict['dropout_1'].blobs)
Out[27]:
For getting activations, first data has to be passed through the network. Then the activations can be read out from the blobs. If the activations are defined as in place operations, the net input will not be stored in any blob and can therefore not be recovered. This problem can be circumvented if the network definition is changed so that in place operations are avoided. This can also be done programatically as follows.
In [40]:
def remove_inplace(model_def):
protonet = caffe_pb2.NetParameter()
with open(model_def, 'r') as fp:
google.protobuf.text_format.Parse(str(fp.read()), protonet)
replaced_tops = {}
for layer in protonet.layer:
# Check whehter bottoms were renamed.
for i in range(len(layer.bottom)):
if layer.bottom[i] in replaced_tops.keys():
layer.bottom[i] = replaced_tops[layer.bottom[i]]
if layer.bottom == layer.top:
for i in range(len(layer.top)):
# Retain the mapping from the old to the new name.
new_top = layer.top[i] + '_' + layer.name
replaced_tops[layer.top[i]] = new_top
# Redefine layer.top
layer.top[i] = new_top
return protonet
model_def = 'example_caffe_mnist_model_deploy.prototxt'
protonet_no_inplace = remove_inplace(model_def)
protonet_no_inplace
Out[40]:
In [38]:
model_def = 'example_caffe_network_no_inplace_deploy.prototxt'
model_weights = 'mnist.caffemodel'
net_no_inplace = caffe.Net(model_def, model_weights, caffe.TEST)
In [22]:
net_no_inplace.layer_dict
Out[22]:
In [25]:
net_no_inplace.blobs
Out[25]:
In [47]:
# Loading and preprocessing data.
data = mnist.load_data()[1][0]
# Normalize data.
data = data / data.max()
plt.imshow(data[0, :, :])
seven = data[0, :, :]
print(seven.shape)
seven = seven[np.newaxis, ...]
print(seven.shape)
Feeding the input and forwarding it.
In [49]:
net_no_inplace.blobs['data'].data[...] = seven
output = net_no_inplace.forward()
output['prob'][0].argmax()
Out[49]:
In [50]:
activations = net_no_inplace.blobs['relu_1'].data
for i in range(32):
plt.imshow(activations[0, i, :, :])
plt.title('Feature map %d' % i)
plt.show()
In [51]:
net_input = net_no_inplace.blobs['conv2d_1'].data
for i in range(32):
plt.imshow(net_input[0, i, :, :])
plt.title('Feature map %d' % i)
plt.show()
In [ ]:
In [55]:
model_def = 'example_caffe_mnist_model.prototxt'
f = open(model_def, 'r')
protonet = caffe_pb2.NetParameter()
google.protobuf.text_format.Parse(str(f.read()), protonet)
f.close()
protonet
Out[55]:
In [56]:
type(protonet)
Out[56]:
Parsed messages for the layer can be found in message.layer
list.
In [57]:
for i in range(0, len(protonet.layer)):
if protonet.layer[i].type == 'Convolution':
print('layer %s has kernel_size %d'
% (protonet.layer[i].name,
protonet.layer[i].convolution_param.kernel_size[0]))
lconv_proto = protonet.layer[i]
In [58]:
len(protonet.layer), len(net.layers)
Out[58]:
In [ ]: