第一部分:用matlab接口操作网络,包括网络生成,数据读取及修改,存储caffeemodel,返回layer的类型
1.设置网络:
model = './models/bvlc_reference_caffenet/deploy.prototxt';
weights ='./models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel';
2.启动网络前,设置运行模式cpu/gpu,模式和设备的设置必须在创建一个net或solver之前。
caffe.set_mode_cpu();
caffe.set_mode_gpu();
caffe.set_device(gpu_id); //使用 GPU,指定 GPU 的 ID 号
3.创建网络:
net = caffe.Net(model, weights, 'test'); % 创建网络并加载权值
或者
net = caffe.Net(model, 'test'); % 创建网络,但不加载权值
net.copy_from(weights); % 加载权值
4.你可以存取网络中任意的 blob。若希望用 1 来填充’data’这个 blob:
net.blobs('data').set_data(ones(net.blobs('data').shape));
5.若希望将 ‘data’这个blob中的所有值都乘以 10,Caffe使用单精度float型数据。如果你的数据不是单精度的,set_data会自动将数据转换为单精度。
net.blobs('data').set_data(net.blobs('data').get_data() * 10);
6.你可以访问每一层,对网络进行调整(surgery)。例如,将 conv1 的参数乘以 10:
net.params('conv1', 1).set_data(net.params('conv1', 1).get_data() * 10); % 设置权值
net.params('conv1', 2).set_data(net.params('conv1', 2).get_data() * 10); % 设置偏置
或者,你也可以使用以下命令:
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);
7.保存刚刚修改的网络:
net.save('my_net.caffemodel');
8.得到 layer 的类型(返回一个 string):
layer_type = net.layers('conv1').type;
第二部分:网络的前向传导(forward)与后向传播(backward)
1.Forward 可使用 net.forward 或者 net.forward_prefilled 函数。
net.forward()传入包含了输入数据的 N-D arrays 形式的单元阵列(cell array),返回包含输出数据的单元阵列。
net.forward_prefilled()使用了 forward 过程中,input blobs(s)中已经存在的数据。
如果没有输入就不会产生输出。
在创建了类似 datmean_data = caffe.io.read_mean('./data/ilsvrc12/imagenet_mean.binaryproto');a = 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();//计算之后再读取原块的数据
2.Backward 用法相似,使用 net.backward()或者 net.backward_prefilled()
用 get_diff()和 set_diff() 替换 get_data() 和 set_data()。
在创建了类似 prob_diff = rand(net.blobs('prob').shape);产生输出blobs的梯度后,你可以运行:
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();//返回计算后的数据
然而,上述的 backward 计算不能得到正确结果,因为 Caffe 认为它不需要 backward 计算(prob(accuracy)层不需要反向计算,还有data层也是)。
为了得到正确的 backward 结果,你需要在网络 prototxt 文件中设置'force_backward: true' 。
3.在完成前向和后向计算之后,你可以获得中间blobs的data和diff。例如,你可以在前向计算后获取pool5的特征。
pool5_feat = net.blobs('pool5').get_data();//刚才上面第一部分是通过caffemodel来提取数据的,这里得到的是自己通过计算之后的特征(视觉层)
第三部分:调整网络的形状
1.假设一次性只在神经网络中放入一张(而不是十张)图像:
net.blobs('data').reshape([227 227 3 1]); % 改造 blob 'data'
net.reshape();
这样,整个网络形状就会被调整。现在 net.blobs('prob').shape 应该为[1000 1]; //1表示批处理的个数
第四部分:训练网络
1.假设已经创建了 ImageNET Tutorial 的训练和验证的 lmdb 数据库。若要创建在 LSVRC2012 分类数据集上的 Solver 并进行训练:
solver = caffe.Solver('./models/bvlc_reference_caffenet/solver.prototxt');//solver中含有网络的定义,而网络定义data中含有数据源
训练时,使用以下命令:
solver.solve();
或者只训练 1000 iterations(以便在训练更多的 iterations 之前,你可以对网络做一些其它修改)
solver.step(1000);
2.来获取迭代数量:
iter = solver.iter();
3.获取训练/测试网络:
train_net = solver.net;
test_net = solver.test_nets(1);
4.假设从一个snapshot中恢复网络训练:
solver.restore('your_snapshot.solverstate');
第五部分:输入和输出
caffe.io 类提供了基础的输入函数 load_image 和 read_mean。
1.读取 ILSVRC 2012的均值文件:
mean_data = caffe.io.read_mean('./data/ilsvrc12/imagenet_mean.binaryproto');
2.读取caffe例子图片,重新调整尺寸为[width, height],假设我们想要 width = 256;height = 256;
记住caffe读取的图片,width 是第一维度,通道为 BGR,这与 Matlab 通常存储图片的方式不同。
im_data = caffe.io.load_image('./examples/images/cat.jpg');
im_data = imresize(im_data, [width, height]); % resize using Matlab's imresize
im_data = im_data - mean_data;
若不想使用 caffe.io.load_image,而想使用 Matlab 自带接口加载图像,你可以这样做:
im_data = imread('./examples/images/cat.jpg'); % read image
im_data = im_data(:, :, [3, 2, 1]); % 从 RGB 转换为 BGR
im_data = permute(im_data, [2, 1, 3]); % 改变 width 与 height 位置
im_data = single(im_data); % 转换为单精度
3.在 caffe/matlab/hdf5creation 中展示了如何用 Matlab 读取与写入 HDF5数据,而 Matlab 自身在输出方面的功能十分强大:
4.清除 Nets 和 Solvers
Call caffe.reset_all() 清除你创建的所有 solvers或独立的 nets。
第六部分:数据层
Caffe 中数据流以 Blobs 进行传输。数据层将输入转换为 blob 加载数据,将 blob 转换为其他格式保存输出。
均值消去、特征缩放等基本数据处理都在数据层进行配置。
数据层加载 leveldb 或 lmdb 的数据库存储格式保证快速传输。
layer{ # 数据层
name: data
type: Data
top: "data" # 是数据本身:“data”的命名只是方便使用
top: "label" # 是数据标签:“label”的命名只是方便使用
include {
phase: TRAIN # 表明这是在训练阶段才包括进去
}
data_param{ #数据库具体配置
source: "lmdb文件夹路径" # 数据库路径
backend: LMDB # 默认为LEVELDB (LMDB 支持并行读取)
batch_size: 64 # 批量处理,提高效率
}
transform_param{
mirror: true
crop_size: 227
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
scale: 0.00390625 # 默认为1, 特征归一化系数,将范围为[0, 255]的 MNIST 数据归一化为[0, 1]
}
}
------------------------------------------------------------------------------------------------------------------------------
matlab函数cat
问题:两个图像矩阵A=M*N*K1,B=M*N*K2,第三维K1,K2表示数量,matlab怎么快速实现他们在第三维数量上的叠加。
答:cat(3,A,B)
------------------------------------------------------------------------------------------------------------------------------
matlab函数meshgrid
问题:使用matlab怎么能够产生这样的一组数组呢?
x = 1,2,3,4
y = 5,6
产生一组点:
(1,5) (1,6)
(2,5) (2,6)
(3,5) (3,6)
(4,5) (4,6)
答案:
x = [1,2,3,4];
y = [5,6];
[X,Y] = meshgrid(x,y);
[X(:), Y(:)]
-----------------------------------------------------------------------------------------------------------------------------------
Matlab 的标号从 1 开始,且以列(column)为主,则 blob 通常的 4 个维度在 Matlab,中用 [width, height, channels, num]表示, width 是第一维。
-----------------------------------------------------------------------------------------------------------------------------------
tic和toc用来记录matlab命令执行的时间。
tic用来保存当前时间,而后使用toc来记录程序完成时间。
两者往往结合使用,用法如下:
tic
operations
toc
显示时间单位:秒
-----------------------------------------------------------------------------------------------------------------------------------
matlab启动前(临时设置变量) 每次启动的都加载用 ~/.bashrc ,查看变量用echo $LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH=/opt/intel/mkl/lib/intel64:/usr/local/cuda7.5/lib64(:为分割号)
$ export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6
matlab启动后 (startup.m)放在caffe文件夹下,运行一下就可以了
addpath(genpath(pwd));
fprintf('caffe startup\n');
或者手敲命令
addpath('~/caffe-master');//只用添加主文件夹 或者 addpath ./matlab
help caffe 可测试路径是否添加成功
-----------------------------------------------------------------------------------------------------------------------------------
画图
figure;plot(scores);
axis([0, 999, -0.1, 0.5]);
grid on
或文件夹下使用gnuplot进行画图:
gnuplot plot-p-at-k.gnuplot
-----------------------------------------------------------------------------------------------------------------------------------
matlab 图片集转成.mat格式,便于检索后根据索引号来显示对应的图片
%文件夹下图片按顺序全部转为mat
image_folder_path = '/home/nielsen/caffe-master/data/image1000test200/train/';
ext = '*.jpg';
dis = dir([image_folder_path ext]);
nms = {dis.name};
my_images = cell(length(nms),1);%
for k = 1:length(nms)
nm = [image_folder_path nms{k}]; % 注意要加上路径
my_images{k} = imread(nm);
end
save('train_images.mat','my_images');
%显示图片
clc;
clear all;
load train_images.mat
p1 = my_images{2};
imshow(p1);
-----------------------------------------------------------------------------------
%用于显示检索结果的图片的显示
%x_one_distance.mat 存储的是top距离
%y_one_index 存储的是top图片的索引-----
%z_one_label 存储的是标签(类别号)
%假设显示前k个最接近的图片,使用matlab读取这k个原图片并顺序显示
k = 20;
load x_one_distance.mat %内部x_distance
load y_one_index.mat %内部y_index
load z_one_label.mat %内部z_label
load train_images.mat %内部my_images
%load y_index.mat
imgs = cell(1,k);
%y_index = y_index(:,2); %批量时候的检索
for i=1:k
img_index = y_index(i);
imgs{i} = my_images{img_index};
subplot(4,5,i); %以4行5列显示
imshow(imgs{i});
end
-----------------------------------------------------------------------------------
%用路径显示图片
train = importdata('/home/nielsen/caffe-new/data/cifar10/train_pairwised.txt'); %数据库标签,取第二列的标签data = train.data;
train_path = train.textdata;%提路径
train_label = train.data;%提标签
index = y_index(1:k,:);%取出前k行的索引
path = train_path(index,:);
label = train_label(index,:);
for i=1:k
subplot(4,5,i); %以4行5列显示
imshow(path{i});
title(label(i));
end