非官方的matcaffe食用教程
基础配置
设置运算模式
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就是对应的网络结构文件
model_dir = '/home/weijian/caffe/models/bvlc_alexnet/';
net_model = [model_dir 'deploy.prototxt'];
net_weights = [model_dir 'bvlc_alexnet.caffemodel'];
开始创建一个网络
net = caffe.Net(net_model, net_weights, 'test');
% 或者这样也是可以的
net = caffe.Net(model, 'test');
net.copy_from(weights);
操作参数与模型保存
输出网路结构和blob、layer名称
net
net.blob_names
net.layer_names
操作blobs
% 将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);
操作层的参数
% 获取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);
在当前目录下保存经过调整的模型
net.save('my_new_net.caffemodel');
卷积核的显示
获取层:通过名字获取下标—>通过下标获取对应的层
% 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对象。
% 提取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)进行数据处理和并实现可视化
% 缩放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;
展示可视化效果
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);)产生输入数据后,你可以运行:
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的梯度
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幅图像,而不是10幅时:
net.blobs('data').reshape([227 227 3 1]); % reshape blob 'data'
net.reshape();
% 然后,整个网络就reshape了,此时net.blobs('prob').shape应该是[1000 1];
开始训练
开始训练
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中恢复网络训练:
solver.restore('your_snapshot.solverstate');
清除nets和solvers
调用caffe.reset_all()来清理你所创建的所有的solvers,和stand-alone nets。