非官方的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对象。
| nth_layer_blob1_data = nth_layer.params(1).get_data();
sizeB = size(nth_layer_blob1_data); GridL = ceil(sqrt(sizeB(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 );
% 求均值 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 )) / (max(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); 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。