Caffe学习——Imagenet分类
2015-12-19 21:09
369 查看
Caffe学习——Imagenet分类
1. Caffe安装
参考Alten Li的Caffe安装[1]。2. Imagenet分类
代码来自Caffe的Notebook Examples[2]。在导入Caffe前,先在sys.path中插入Caffe的路径:examples文件夹下有子文件夹pycaffe(猜是安装Caffe时执行“make pycaffe”生成的文件夹),并没有python文件夹;python文件夹属于caffe文件夹的子文件夹。所以,如果把根文件夹设为'/home/parallel/caffe/',导入caffe也是有效的。import numpy as np import matplotlib.pyplot as plt %matplotlib inline # Make sure that caffe is on the python path: caffe_root = '/home/parallel/caffe/examples/' # this file is expected to be in {caffe_root}/examples import sys sys.path.insert(0, caffe_root + 'python') import caffefigure.figsize为图像的大小(分别为宽和高,单位为英寸);image.interpolation为'nearest'表示当屏幕像素和图像像素不一致时,并没有在像素间计算插入值(可以理解为过渡值),所以如果屏幕像素过高,只是复制距这个像素点最近的像素值,所以每个像素值看起来像是个小方块。默认imshow显示采用的cmap为'jet',这里用'gray',所以显示的图像都是灰度图像。
plt.rcParams['figure.figsize'] = (10, 10) plt.rcParams['image.interpolation'] = 'nearest' plt.rcParams['image.cmap'] = 'gray'set_mode_cpu设置Caffe跑CPU模式。deploy.prototxt里定义了网络架构,后缀为.caffemodel为Caffe训练后得到的模型,最后定义网络的类型为'TEST',这时网络只有前向计算得到输出结果,没有反向计算调整caffe模型的参数。
caffe.set_mode_cpu() net = caffe.Net(caffe_root + 'models/bvlc_reference_caffenet/deploy.prototxt', caffe_root + 'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel', caffe.TEST)io为Caffe的数据输入模块,Transformer初始化时将输入数据的索引设为'data',同时设置了输入数据(这里为图像)的大小。set_transpose负责将索引为'data'的输入数据做维度上的交换:如果原始图像为RGB图像,那么0对应R通道,1对应G通道,2对应B通道,(2,0,1)transpose后'data'变为BGR。mean.npy为像素的平均值,这个文件caffe可以自己生成(?:以后用到再说)。set_raw_scale将输入数据缩放为原来的255倍。(2,1,0)转置又将BGR图像转换为RGB图像。
# input preprocessing: 'data' is the name of the input blob == net.inputs[0] transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape}) transformer.set_transpose('data', (2,0,1)) transformer.set_mean('data', np.load('/home/parallel/caffe/python/caffe/imagenet/ilsvrc_2012_mean.npy').mean(1).mean(1)) # mean pixel transformer.set_raw_scale('data', 255) # the reference model operates on images in [0,255] range instead of [0,1] transformer.set_channel_swap('data', (2,1,0)) # the reference model has channels in BGR order instead of RGB设置块大小为50,通道数为3,图像大小为227*227。然后用上面设置的transformer对加载的图像'cat.jpg'做预处理。
# set net to batch size of 50 net.blobs['data'].reshape(50,3,227,227) net.blobs['data'].data[...] = transformer.preprocess('data', caffe.io.load_image(caffe_root + 'images/cat.jpg'))前向计算输出结果给out。打印out中概率('prob')最大的索引,输入为50个图像为一组,这里应该是把'cat.jpg'复制了50张(从data[0]到data[49])。所以'prob'标签后面的[0]可以修改为49及以内的任何正整数。
out = net.forward() print("Predicted class is #{}.".format(out['prob'][0].argmax()))显示图像。imshow设置的'cmap'应该为'gray',不清楚为什么这里会显示彩色图像。
plt.imshow(transformer.deprocess('data', net.blobs['data'].data[0]))加载groundtruch标签,存放在synset_words.txt里面。如果没有这个文件加载给labels,会执行get_ilsvrc_aux.sh批处理文件获取该文件。
# load labels imagenet_labels_filename = '/home/parallel/caffe/data/ilsvrc12/synset_words.txt' try: labels = np.loadtxt(imagenet_labels_filename, str, delimiter='\t') except: !../data/ilsvrc12/get_ilsvrc_aux.sh labels = np.loadtxt(imagenet_labels_filename, str, delimiter='\t')获取'prob'最大的6个预测索引,这里最大的概率对应的索引应该为281,对应的标签为'n02123045 tabby, tabby cat'。
# sort top k predictions from softmax output top_k = net.blobs['prob'].data[0].flatten().argsort()[-1:-6:-1] print labels[top_k]设置为CPU模式,输出结果为最好的3次,每次都是1个前向计算(感觉3次输入1样,所以基本上没什么差异)。CPU每次前向计算花费的时间为6.45秒;
# CPU mode net.forward() # call once for allocation %timeit net.forward() 1 loops, best of 3: 6.45 s per loop设置为GPU模式,同理得到每次前向计算花费的时间为0.233秒。
# GPU mode caffe.set_device(0) caffe.set_mode_gpu() net.forward() # call once for allocation %timeit net.forward() 1 loops, best of 3: 223 ms per loop
网络架构的绘制使用graphviz[3]。
net.blobs里包含网络每块特征地图的字典索引k和对应内容v的大小,net.params训练后的网络参数[4]。
net.params为事先设置的参数尺寸(output channels, input channels, filter height filter width)。
根据net.params中的filter size来计算net.blobs的(batch size, output channels, height, width)。
data: 50张图片为1组输入,通道数为3(RGB),图像宽度和高度为227。
conv1:(227-11)/4+1=55
pool1 :(55-3)/2+1=27
conv2:(27-5+4)/1+1=27
pool2 :(27-3)/2+1=13
conv3:(13-3+2)/1+1=13
conv4:(13-3+2)/1+1=13
conv5:13
pool5 :(13-3)/2+1=6
[(k, v.data.shape) for k, v in net.blobs.items()] [('data', (50, 3, 227, 227)), ('conv1', (50, 96, 55, 55)), ('pool1', (50, 96, 27, 27)), ('norm1', (50, 96, 27, 27)), ('conv2', (50, 256, 27, 27)), ('pool2', (50, 256, 13, 13)), ('norm2', (50, 256, 13, 13)), ('conv3', (50, 384, 13, 13)), ('conv4', (50, 384, 13, 13)), ('conv5', (50, 256, 13, 13)), ('pool5', (50, 256, 6, 6)), ('fc6', (50, 4096)), ('fc7', (50, 4096)), ('fc8', (50, 1000)), ('prob', (50, 1000))] [(k, v[0].data.shape) for k, v in net.params.items()] [('conv1', (96, 3, 11, 11)), ('conv2', (256, 48, 5, 5)), ('conv3', (384, 256, 3, 3)), ('conv4', (384, 192, 3, 3)), ('conv5', (256, 192, 3, 3)), ('fc6', (4096, 9216)), ('fc7', (4096, 4096)), ('fc8', (1000, 4096))]
vis_square是把data归一化,然后把n个data放在同一张图片里显示出来。
params存储网络中间层的网络参数,conv1层的参数尺寸为(96, 3, 11, 11),params['conv1'][0].data为conv1的权重参数,filters转置后的尺寸为(96, 11, 11, 3),符合vis_square函数中data的定义(n, height, width, channels)。
filters = net.params['conv1'][0].data vis_square(filters.transpose(0, 2, 3, 1))
conv2层的参数尺寸为(256,48,5,5),params['conv2'][0].data为conv2的权重参数,这里只显示其中的48个。注意到conv1的output channels为96,conv2的input channels为48,说明剩下的48个output channels都被丢弃了。
filters = net.params['conv2'][0].data vis_square(filters[:48].reshape(48**2, 5, 5))
blobs存储网络中间层的输出数据,显示conv1层前36个特征图。根据blobs的定义,data[0, :36]应该是第1张图片的前36个output channels。
feat = net.blobs['conv1'].data[0, :36] vis_square(feat, padval=1)
显示conv2层前36个特征图。
feat = net.blobs['conv2'].data[0, :36] vis_square(feat, padval=1)显示conv3层所有的特征图。
feat = net.blobs['conv3'].data[0] vis_square(feat, padval=0.5)显示conv4层所有的特征图。
feat = net.blobs['conv4'].data[0] vis_square(feat, padval=0.5)显示conv5层所有的特征图。
feat = net.blobs['conv5'].data[0] vis_square(feat, padval=0.5)显示pool5层所有的特征图。
feat = net.blobs['pool5'].data[0] vis_square(feat, padval=1)
全连接层的params的结构为(output channels, input channels),所以fc6和fc7的直方图横轴都为4096。上面的图为全连接层4096个神经元的输出值,下面的图为对这些神经元的响应值的强度为直方图的输入,可知fc6大多数神经元的响应值都在40以下,和fc7相比,直方图的斜率的绝对值应该是偏小。也就是说全连接层前后相连,越往后神经元的响应值越不会均匀分布化,而通过神经元间的竞争所以最后一层全连接层'prob'产生的尖峰即为优胜的神经元,这个神经元对应的索引决定了对象属于哪一类。
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['fc7'].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.plot(feat.flat)
3. 参考链接
[1] /article/2416837.html[2] http://nbviewer.ipython.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb
[3] http://blog.csdn.net/honyniu/article/details/46391569
[4] http://blog.csdn.net/guoyilin/article/details/42873747
相关文章推荐
- 大神眼中的React Native--备用
- AngularJS 表格
- JsplitPane
- js从数组中删除指定值(不是指定位置)的元素
- React事件处理函数的bind复用和name复用
- html iframe用法
- createjs接触
- leetcode刷题日记——Delete Node in a Linked List
- 关于H5播放视频文件的问题
- React表单元素的使用
- jQuery插件的理解 $.extend()与$.fn.extend()
- 延迟加载页面的例子
- thinkphp 用jquery ajax前后台交互
- vs2013编译caffe的io.cpp文件错误,open close无法识别
- html5 canvas 笔记三(绘制文本和图片)
- JSON与JSONP
- javaScript
- html5 canvas 笔记二(添加样式和颜色)
- js函数中使用el表达式传入多个参数时的问题
- 几个可能会用到的前端库