引言
记录学习官网的例程中的一些重要语句,遇到的问题等,内容分散,建议顺序查看。
主要是调用Caffe的Python接口
源文件就在{caffe_root}/examples中(目录下面的中文标题也附有链接),安装sudo pip install jupyter
打开即可运行,初学者最好是放在它指定的目录,如,否则要改很多路径。
注:eaxmples是用jupyter notebook写的,部分Cell中出现了一些特殊的用法:
1. 感叹号‘!’:用于执行系统命令,如 !pwd
2. 百分号‘%’:用法太多,如 %matplotlib inline 显示绘图窗口 详见Jupyter Notebook Viewer
目录
- 引言
- 目录
- 编辑模型参数
- 1. 设计卷积核
- 2. 将分类器转换为全卷积网络
- 编辑模型参数
- 上一篇:Caffe实战之Python接口系列(五)Multilabel classification on PASCAL using python data-layers
- 下一篇:Caffe实战之Python接口系列(七)R-CNN detection
编辑模型参数
- 通过编辑模型参数,可以将Caffe网络转换为您的特定需求。 网络的数据(data),梯度(diff)和参数(params)都在pycaffe中暴露。
1. 设计卷积核
为了展示如何加载,操作和保存参数,将卷积核设计到一个只有单个卷积层的简单网络中。 该网络有两个blob,用于输入的
data
和用于卷积输出的conv
以及用于卷积核权重和偏置的一个参数conv
。# Load the net, list its data and params, and filter an example image.caffe.set_mode_cpu() net = caffe.Net('net_surgery/conv.prototxt', caffe.TEST) print("blobs {}\nparams {}".format(net.blobs.keys(), net.params.keys()))# load image and prepare as a single input batch for Caffeim = np.array(caffe.io.load_image('images/cat_gray.jpg', color=False)).squeeze() plt.title("original image") plt.imshow(im) plt.axis('off')im_input = im[np.newaxis, np.newaxis, :, :] net.blobs['data'].reshape(*im_input.shape) net.blobs['data'].data[...] = im_input
- 用高斯噪声初始化卷积权重,同时将偏置初始化为零。 这些随机卷积核的输出有点像边缘检测。
提高卷积核的偏置将相应地提高其输出
# pick first filter outputconv0 = net.blobs['conv'].data[0, 0] print("pre-surgery output mean {:.2f}".format(conv0.mean()))# set first filter bias to 1net.params['conv'][1].data[0] = 1. net.forward() print("post-surgery output mean {:.2f}".format(conv0.mean()))
改变卷积核权重更令人兴奋,因为我们可以分配任何的核,如高斯模糊,边缘的Sobel算子等等。 下面将第0个卷积核转换为高斯模糊,将第1和第2卷积核转换为Sobel算子的水平和垂直梯度。
ksize = net.params['conv'][0].data.shape[2:]# make Gaussian blursigma = 1. y, x = np.mgrid[-ksize[0]//2 + 1:ksize[0]//2 + 1, -ksize[1]//2 + 1:ksize[1]//2 + 1] g = np.exp(-((x**2 + y**2)/(2.0*sigma**2))) gaussian = (g / g.sum()).astype(np.float32) net.params['conv'][0].data[0] = gaussian# make Sobel operator for edge detectionnet.params['conv'][0].data[1:] = 0. sobel = np.array((-1, -2, -1, 0, 0, 0, 1, 2, 1), dtype=np.float32).reshape((3,3)) net.params['conv'][0].data[1, 0, 1:-1, 1:-1] = sobel # horizontal net.params['conv'][0].data[2, 0, 1:-1, 1:-1] = sobel.T # vertical show_filters(net)
2. 将分类器转换为全卷积网络
- 采用标准的Caffe Reference ImageNet模型“CaffeNet”并将其转换为完全卷积网,以便在大输入上进行高效,密集的推理。 该模型生成的分类图覆盖给定的输入大小而不是单个分类。 特别是451×451输入上的8×8分类图仅在3倍的时间内提供64倍的输出。 该计算通过分摊重叠感受域的计算来利用卷积网络(convnet)结构的内在效率。
- 为此,我们将CaffeNet的InnerProduct矩阵乘法层转换为卷积层。 这是唯一的变化:其他层类型与空间大小无关。 卷积是平移不变的,激活是逐元素操作,等等。 通过在
pool5
上加上一个步幅为1的6×6卷积核,fc6
内积变为卷积fc6-conv
。 回到图像空间,这给出了每个227×227框的分类,其中步长为32像素。 请记住输出图/感受野大小的等式,output =(input - kernel_size)/ stride + 1,并计算索引详细信息以便清楚地理解。 该架构的唯一改变是将全连接的分类器内积层更改为卷积层且卷积核大小是 6 x 6,因为参考模型分类器将
pool5
的36个元素作为输入且步长设置为1来密集分类。 请注意,这些层已重命名,以便Caffe在将层名称映射到预训练模型时不会尝试盲目加载旧参数。# Load the original network and extract the fully connected layers' parameters.net = caffe.Net('../models/bvlc_reference_caffenet/deploy.prototxt', '../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel', caffe.TEST) params = ['fc6', 'fc7', 'fc8']# 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)
考虑内积参数的形状。 权重尺寸是输出和输入尺寸,而偏置尺寸是输出尺寸。
# Load the fully convolutional network to transplant the parameters.net_full_conv = caffe.Net('net_surgery/bvlc_caffenet_full_conv.prototxt', '../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel',caffe.TEST) params_full_conv = ['fc6-conv', 'fc7-conv', 'fc8-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)
- 卷积权重维度为
output × input × height × width
。 要将内积权重映射到卷积核,可以将平铺的内积矢量卷成channel × height × width
卷积核矩阵中,但实际上它们在内存中是相同的(如row major数组),因此我们可以直接分配它们。 偏置与内积完全相同 下面开始移植
for pr, pr_conv in zip(params, params_full_conv):conv_params[pr_conv][0].flat = fc_params[pr][0].flat # flat unrolls the arraysconv_params[pr_conv][1][...] = fc_params[pr][1]
保存新的模型权重
net_full_conv.save('net_surgery/bvlc_caffenet_full_conv.caffemodel')
最后,让我们从示例猫图像中制作分类图,并将“虎猫”的置信度可视化为概率热图。 这给出了451×451输入的重叠区域的8x8预测。
import numpy as np import matplotlib.pyplot as plt %matplotlib inline# load input and configure preprocessingim = caffe.io.load_image('images/cat.jpg') transformer = caffe.io.Transformer({ 'data': net_full_conv.blobs['data'].data.shape}) transformer.set_mean('data', np.load('../python/caffe/imagenet/ilsvrc_2012_mean.npy').mean(1).mean(1)) transformer.set_transpose('data', (2,0,1)) transformer.set_channel_swap('data', (2,1,0)) transformer.set_raw_scale('data', 255.0)# make classification map by forward and print prediction indices at each locationout = net_full_conv.forward_all(data=np.asarray([transformer.preprocess('data', im)])) print out['prob'][0].argmax(axis=0)# show net input and confidence map (probability of the top prediction at each location)plt.subplot(1, 2, 1) plt.imshow(transformer.deprocess('data', net_full_conv.blobs['data'].data[0])) plt.subplot(1, 2, 2) plt.imshow(out['prob'][0,281])
- 分类包括各种猫 - 282 =虎猫,281 =虎斑猫,283 =波斯猫 - 以及狐狸和其他哺乳动物。
- 通过这种方式,可以被提取为图像上的密集特征(例如,参见
net_full_conv.blobs['fc6'].data
),这可能比分类图本身更有用。 - 请注意,此模型并不完全适用于滑动窗口检测,因为它是针对整个图像分类进行训练的。 不过它可以正常工作。 滑动窗口训练和微调可以通过定义滑动窗口的GT和损失来完成,以便为每个位置制作损失图并像往常一样解决。 (这是读者的练习。)