正如caffe的examples所提,CNN model并不是一个黑盒,caffe提供了工具来查看cnn各层的所有输出
代码如下:
# 显示每一层
for layer_name, blob in net.blobs.iteritems():
print layer_name + '\t' + str(blob.data.shape)
第i次循环体内部
结果为:
data (50, 3, 227, 227) 网络的输入,batch_number = 50,图像为227*227*3的RGB图像
conv1 (50, 96, 55, 55) 第一个conv层的输出图像大小为55*55,feature maps个数为96
pool1 (50, 96, 27, 27) 第一个pool层的图像尺寸为27*27,feature map个数为96
norm1 (50, 96, 27, 27) 第一个norm层的图像尺寸为27*27,feature map个数为96conv2 (50, 256, 27, 27) 第二个conv层的图像尺寸为27*27,feature map个数为256
pool2 (50, 256, 13, 13) 第二个pool层的图像尺寸为13*13,feature map个数为256
norm2 (50, 256, 13, 13) 第二个norm层的图像尺寸为13*13,feature map个数为256conv3 (50, 384, 13, 13) 第三个conv层的图像尺寸为13*13,feature map个数为384
conv4 (50, 384, 13, 13) 第四个conv层的图像尺寸为13*13,feature map个数为384
conv5 (50, 256, 13, 13) 第五个conv层的图像尺寸为13*13,feature map个数为256
pool5 (50, 256, 6, 6) 第五个pool层的图像尺寸为13*13,feature map个数为256fc6 (50, 4096)
第六个fc层的图像尺寸为4096fc7 (50, 4096)
第七个fc层的图像尺寸为4096fc8 (50, 1000)
第八个fc层的图像尺寸为1000prob (50, 1000)
probablies层的尺寸为1000
下面画出该数据,从图中观察更为形象
代码如下:
for layer_name, param in net.params.iteritems():
print layer_name + '\t' + str(param[0].data.shape), str(param[1].data.shape)
第i次循环体内部
结果如下:
conv1 (96, 3, 11, 11) (96,) 第一个conv层的filters的尺寸,这里的3是因为输入层的data为rgb,可以看做三个feature maps
conv2 (256, 48, 5, 5) (256,) 第二个conv层的filters尺寸
conv3 (384, 256, 3, 3) (384,)第三个conv层的filters尺寸
conv4 (384, 192, 3, 3) (384,)第四个conv层的filters尺寸
conv5 (256, 192, 3, 3) (256,)第五个conv层的filters尺寸
fc6 (4096, 9216) (4096,)第一个fc层的权值尺寸
fc7 (4096, 4096) (4096,)第二个fc层的权值尺寸
fc8 (1000, 4096) (1000,)第三个fc层的权值尺寸
应该注意到,由于pool层和norm层并没有需要优化的参数,所以参数中并没有关于pool层和norm层的信息
下面给出filters如何对输入数据进行filter的一幅形象化的图
def vis_square(data):
# 输入的数据为一个ndarray,尺寸可以为(n, height, width)或者是 (n, height, width, 3)
# 前者即为n个灰度图像的数据,后者为n个rgb图像的数据
# 在一个sqrt(n) by sqrt(n)的格子中,显示每一幅图像
# 对输入的图像进行normlization
data = (data - data.min()) / (data.max() - data.min())
# 强制性地使输入的图像个数为平方数,不足平方数时,手动添加几幅
n = int(np.ceil(np.sqrt(data.shape[0])))
# 每幅小图像之间加入小空隙
padding = (((0, n ** 2 - data.shape[0]),
(0, 1), (0, 1)) # add some space between filters
+ ((0, 0),) * (data.ndim - 3)) # don't pad the last dimension (if there is one)
data = np.pad(data, padding, mode='constant', constant_values=1) # pad with ones (white)
# 将所有输入的data图像平复在一个ndarray-data中(tile the filters into an image)
data = data.reshape((n, n) + data.shape[1:]).transpose((0, 2, 1, 3) + tuple(range(4, data.ndim + 1)))
# data的一个小例子,e.g., (3,120,120)
# 即,这里的data是一个2d 或者 3d 的ndarray
data = data.reshape((n * data.shape[1], n * data.shape[3]) + data.shape[4:])
# 显示data所对应的图像
plt.imshow(data); plt.axis('off')
代码如下:
# the parameters are a list of [weights, biases]
filters = net.params['conv1'][0].data
vis_square(filters.transpose(0, 2, 3, 1))
结果如下:共96幅图像(96个filters,每个filters为11*11*3)
代码如下:
feat = net.blobs['conv1'].data[0, :36]
vis_square(feat)
代码如下:
feat = net.blobs['pool5'].data[0]
vis_square(feat)
代码如下:
feat = net.blobs['fc6'].data[0]
plt.subplot(2, 1, 1)
plt.plot(feat.flat)
plt.subplot(2, 1, 2)
_ = plt.hist(feat.flat[feat.flat > 0], bins=100)
代码如下:
feat = net.blobs['prob'].data[0]
plt.figure(figsize=(15, 3))
plt.plot(feat.flat)
在获取了net后:
如何获取网络各层的数据:net.blobs[‘layer name’].data[0]
如何获取网络各层的参数数据:net.params[‘layer name’][0].data