Matcaffe食用指南

非官方的matcaffe食用教程

基础配置

设置运算模式

1
2
3
4
5
6
7
if exist('use_gpu', 'var') && use_gpu
caffe.set_mode_gpu();
gpu_id = 0;
caffe.set_device(gpu_id);
else
caffe.set_mode_cpu();
end

设置网络结构和对应的参数

bvlc_alexnet.caffemodel就是对应的网络权重文件
deploy.prototxt就是对应的网络结构文件

1
2
3
model_dir = '/home/weijian/caffe/models/bvlc_alexnet/';
net_model = [model_dir 'deploy.prototxt'];
net_weights = [model_dir 'bvlc_alexnet.caffemodel'];
> 开始创建一个网络

1
2
3
4
net = caffe.Net(net_model, net_weights, 'test');
% 或者这样也是可以的
net = caffe.Net(model, 'test');
net.copy_from(weights);

操作参数与模型保存

输出网路结构和blob、layer名称

1
2
3
net
net.blob_names
net.layer_names

操作blobs

1
2
3
4
% 将data类型的blob统一填充为1
net.blobs('data').set_data(ones(net.blobs('data').shape));
% 将data的blob统一乘以10
net.blobs('data').set_data(net.blobs('data').get_data() * 10);

操作层的参数

1
2
3
4
5
6
7
% 获取conv1层的第1个blob也就是weights
net.params('conv1', 1).set_data(net.params('conv1', 1).get_data() * 10); % set weights
% 获取conv1层的第2个blob也就是bias
net.params('conv1', 2).set_data(net.params('conv1', 2).get_data() * 10); % set bias
% 也可以如下图所示 利用layer来操作参数
% net.layers('conv1').params(1).set_data(net.layers('conv1').params(1).get_data() * 10);
% net.layers('conv1').params(2).set_data(net.layers('conv1').params(2).get_data() * 10);

在当前目录下保存经过调整的模型

1
net.save('my_new_net.caffemodel');

卷积核的显示

获取层:通过名字获取下标--->通过下标获取对应的层

1
2
3
4
5
6
7
8
% name2layer_index是名字到层下标(layer_index)的映射
% net.name2layer_index('conv2')就是conv2的层下标,通过net.layer_vec()函数就能获取对应的层的数据。
% 因此nth_layer就是conv2层,是一个caffe.Layer对象。
nth_layer = net.layer_vec(net.name2layer_index('conv2'));
nth_layer
% 获得一层的类型(string)
layer_type = net.layers('conv1').type;
layer_type

获取卷积核:这一层的第一个卷积核,也就是caffe.Blob对象。

1
2
3
4
5
6
% 提取conv2层的参数组的第1个数据得到nth_layer_blob1_data是一个caffe.Blob对象 
nth_layer_blob1_data = nth_layer.params(1).get_data();

% 取nth_layer_blob1_data的大小
sizeB = size(nth_layer_blob1_data); % 利用size函数得到nth_layer_blob1_data的每一维的大小
GridL = ceil(sqrt(sizeB(4))); % 对sizeB的第四维数据求出平方根 再向右取整ceil(3.5)=4

对卷积核(caffe.Blob)进行数据处理和并实现可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
% 缩放sizeB(1)和sizeB(2)的大小
scale = 4;
border = 2; % 设置border为2为Padding操作做准备 实现只卷积不降维的效果
sizeB(1) = sizeB(1) * scale;
sizeB(2) = sizeB(2) * scale;

% zeros生成零矩阵
% 矩阵大小为(border+sizeB(1))*GridL+border乘以(border+sizeB(2))*GridL+border乘以1
background = zeros((border+sizeB(1))*GridL+border,(border+sizeB(2))*GridL+border,1);

% 求出矩阵nth_layer_blob1_data的最大值和最小值
minV = min(nth_layer_blob1_data(:));
maxV = max(nth_layer_blob1_data(:));

% 求均值
nth_layer_blob1_data = (nth_layer_blob1_data - minV) / (maxV - minV);
for i = 1:sizeB(4)
x = ceil(i / GridL);
y = mod(i - 1,GridL) + 1; % mod函数进行求余数操作
patch = imresize(nth_layer_blob1_data(:,:,1,i),[sizeB(1) sizeB(2)],'nearest');
patch = (patch - min(patch(:))) / (max(patch(:)) - min(patch(:)));
background(border + (x-1)*(border+sizeB(1)) + 1 : x*(border+sizeB(1)),border + (y-1)*(border+sizeB(2)) + 1 : y*(border+sizeB(2)),:) = patch;
end;

展示可视化效果

1
2
3
4
figure(1);
imshow(background);
colormap('jet');
colorbar();

前向和后向计算

前向计算

前向和后向计算可以使用net.forward或者net.forward_prefilled实现。
函数net.forward将一个包含输入blob(s)的cell数组作为输入,并输出一个包含输出blob(s)的cell数组。
函数net.forward_prefilled将使用输入blob(s)中的已有数据进行计算,没有输入数据,没有输出数据。
在通过一些方法(如:data = rand(net.blobs('data').shape);)产生输入数据后,你可以运行:

1
2
3
4
5
6
7
8
data = rand(net.blobs('data').shape);
% class(data)=double class({data})=cell
res = net.forward({data});
% prob = res{1};
% 或者
net.blobs('data').set_data(data);
net.forward_prefilled();
prob = net.blobs('prob').get_data();
> 后向计算

后向计算使用net.backward或者net.backward_prefilled,并且把get_data和set_data替换为get_diff和set_diff。
在通过一些方法(例如prob_diff = rand(net.blobs('prob').shape);)产生输出blobs的梯度

1
2
3
4
5
6
7
prob_diff = rand(net.blobs('prob').shape);
res = net.backward({prob_diff});
data_diff = res{1};
% 或者
net.blobs('prob').set_diff(prob_diff);
net.backward_prefilled();
data_diff = net.blobs('data').get_diff();
然而,如上的后向计算并不能得到正确的结果,因为Caffe默认网络不需要后向计算。为了获取正确的后向计算结果,你需要在你的网络prototxt文件中设置force_backward: true

Reshape

Reshape层的作用:在不改变数据的情况下,改变输入的维度

1
2
3
4
% 假设你想要运行1幅图像,而不是10幅时:
net.blobs('data').reshape([227 227 3 1]); % reshape blob 'data'
net.reshape();
% 然后,整个网络就reshape了,此时net.blobs('prob').shape应该是[1000 1];

开始训练

开始训练

1
2
3
4
5
6
7
solver = caffe.Solver('./models/bvlc_reference_caffenet/solver.prototxt');
solver
solver.solve(); % 执行训练
solver.step(500); % 如果只想训练迭代1000次
iter = solver.iter(); %来获取迭代数量:
train_net = solver.net; % 来获取这个网络
test_net = solver.test_nets(1);

假设从一个snapshot中恢复网络训练:

1
solver.restore('your_snapshot.solverstate');
## 清除nets和solvers

调用caffe.reset_all()来清理你所创建的所有的solvers,和stand-alone nets。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!