最近做实验用到MatCaffe,本文就简单总结以下MatCaffe的用法。还没安装的赶快看官网教程安装吧。MatCaffe的用法与PyCaffe挺类似的。
model ='./models/bvlc_reference_caffenet/deploy.prototxt';
weights='./models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel';
上面是设置好的你的prototxt文件路径(网络结构文件)以及caffemodel文件路径(模型文件)。
Mode和device应该在你创建net或者solver之前设置。
用CPU或者GPU:
caffe.set_mode_cpu();
Use GPU and specify its gpu_id:
caffe.set_mode_gpu();
caffe.set_device(gpu_id);
net = caffe.Net(model, weights, 'test');
% create net and load weights
或者可以后来载入weights:
net = caffe.Net(model, 'test');
% create net but not load weights
net.copy_from(weights);
% load weights
网络的具体结构是下面的样子:
layer_vec: [1x23 caffe.Layer]
blob_vec: [1x15 caffe.Blob]
inputs: {'data'}
outputs: {'prob'}
name2layer_index: [23x1 containers.Map]
name2blob_index: [15x1 containers.Map]
layer_names: {23x1 cell}
blob_names: {15x1 cell}
也可以读取每层网络的blob,blob是caffe中网络的数据传输单位,是个4D数组。
net.blobs('data').set_data(ones(net.blobs('data').shape));
如果把blob里面的数据都乘以10,可以这么做:
net.blobs('data').set_data(net.blobs('data').get_data() * 10);
在Matlab中的4D Blob结构是[width, height, channels, num],Matlab的索引是从1开始的。图像中的通道是按照BGR排列的,caffe中数据都是用single类型的,set_data会自动吧你的数据转换成single。
也可以修改每层的数据,比如可以把参数乘以10:
net.params('conv1', 1).set_data(net.params('conv1', 1).get_data() * 10);
% set weights
net.params('conv1', 2).set_data(net.params('conv1', 2).get_data() * 10);
% set bias
也可以这样写:
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_net.caffemodel');
layer_type = net.layers('conv1').type;
前向传输可以用:net.forward 或者 net.forward_prefilled
net.forward接受一个blob输入(N-D数组)输出blob。
net.forward_prefilled用现有的数据作为输入,所以不需要输入,当然也没有输出。
比如创建输入blob:
data = rand(net.blobs('data').shape);
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);
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。
你也可以得到中间blob的data或者diff,比如得到前向传输之后的pool5层的特征:
pool5_feat = net.blobs('pool5').get_data();
比如你想运行一次运行一幅图像而不是十幅:
net.blobs('data').reshape([227 227 3 1]);
% reshape blob 'data'
net.reshape();
整个网络就reshaped了,现在 net.blobs(‘prob’).shape就是[1000 1];
假设你已经有了ImageNet的traing和validation的lmdbs了(在caffe中的数据都是lmdb格式的,这是一种k-v数据库的数据结构),在caffe的ImageNet Tutorial有相关教程。我们现在要在ILSVRC 2012创建train和solver。
solver = caffe.Solver('./models/bvlc_reference_caffenet/solver.prototxt');
Solver的属性:
net: [1x1 caffe.Net]
test_nets: [1x1 caffe.Net]
运行下面开始训练:
solver.solve();
或者只训练1000次:
solver.step(1000);
获得迭代次数:
iter = solver.iter();
获得训练网络和测试网络:
train_net = solver.net;
test_net = solver.test_nets(1);
为了防止训练过程中中断,caffe提供了从sanpshot的恢复功能:
“your_snapshot.solverstate”:
solver.restore('your_snapshot.solverstate');
caffe.io类提供了最基本的load_image和read_mean函数。比如,读取ILSVRC 2012的mean文件:
mean_data = caffe.io.read_mean('./data/ilsvrc12/imagenet_mean.binaryproto');
读入caffe的例子图像,把它resize到width=256,height=256。
im_data = caffe.io.load_image('./examples/images/cat.jpg');
im_data = imresize(im_data, [width, height]);
% resize using Matlab's imresize
一定要记住:width是最快的维度,通道是BGR,这与通常Matlab存储图像是不同的。如果你想自己load图像的话,需要做一些调整:
im_data = imread('./examples/images/cat.jpg');
% read image
im_data = im_data(:, :, [3, 2, 1]);
% convert from RGB to BGR
im_data = permute(im_data, [2, 1, 3]);
% permute width and height
im_data = single(im_data);
% convert to single precision
你也可以看看caffe/matlab/demo/classification_demo.m看看如果从图像中选取crops来进行输入的。
在 caffe/matlab/hdf5creation中展示了如何用matlab读写HDF5。caffe没有提供其他函数来做输出,因为matlab已经有很多方法了。
caffe.reset_all()
清理所有的solvers和创建的stand-alone网路。