扯了这么多,来点实际的,卷积对于神经网络究竟有什么好处呢?
如果你看了上面所有的计算过程,我们可以发现至少两个好处,一个是卷积降低了数据数量,可以说是抽提了数据,数据变得少,如果不使用卷积,我们普通的bpnn需要处理的数据将是非常巨大的。stdcoutzyx在博客中有过计算,你可以仔细看一下。卷积神经网络的另一个核心思想是:局部感受野(local field),权值共享以及时间或空间亚采样这三种思想结合起来,获得了某种程度的位移、尺度、形变不变性。说起来很炫吧,但是我也不知道如何解释,你可以参看此处。
Talk is cheap,show me the code. 话不多说,直接上代码。
trainCNN.m
%% CNN
close all;clear all;
train_dir=dir('train/*.jpg');%训练的文件夹 下面获取训练的文件列表
for i = 1: length(train_dir)
imgs_name{i} = train_dir(i).name;
end
imgs_sample = cell(6);%样本分组 我们六个点数 分成六组 一组多少个样品就有多少数组 按照最多的那一组确定最大维度
imgs_sample_num = zeros(1,6);%6组数据,保存每一组数据最多多少个样本 例如[79,79,79,79,79,79] 表示第一组79样本 第二组79....
max_size = [0 0];% 这些样本中最大的长和宽
%% 将数字分类放置
for i = 1 : length(imgs_name)%每一张图
img_name = imgs_name{i};%取出名字img_name 例如1(2)
imgs = im2bw(imread(['train/',img_name]));%读取图片
tmp_num = str2num(img_name(1)) ;%读取点数
imgs_sample_num(tmp_num) = imgs_sample_num(tmp_num) + 1; %在这一组里面 样本的下标加1
imgs_sample{tmp_num, imgs_sample_num(tmp_num)} = imgs;% 将这个样本 保存到imgs_sample 第一维是点数 第二维是样本的下标
tmp_size = size(imgs); % 样本图片的大小 下面两行分别获取图片的最大长和宽
if max_size(1,1) < tmp_size(1,1); max_size(1,1) = tmp_size(1,1); end%找最大的 宽度
if max_size(1,2) < tmp_size(1,2); max_size(1,2) = tmp_size(1,2); end%找最大的 长度
end
max_size = [24 40];% 这些样本中最大的长和宽
%% 归一化所有样本,使其等大小
for i = 1 : 6% 对于这6类图像对象 例如数字0
for j = 1 : imgs_sample_num(i) %取其中一类 然后 遍历这一类里面多有的对象
temp = zeros(max_size);%[0 0] 例如max_size 是[32,30]
imgs_size = size(imgs_sample{i, j});% 0 这一类的一张图
temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs_sample{i, j};%映射到最大的
imgs_sample{i, j} = temp;
% imshow(temp);
end
end
%cnn网络
runcnn(imgs_sample, imgs_sample_num, max_size);runcnn.m
%%CNN 训练的主要步骤
function y = runcnn(imgs_sample, imgs_sample_num, max_size)
path(path, 'DeepLearnToolbox-master/CNN/')
path(path, 'DeepLearnToolbox-master/util/')
% 网络训练集构造
[a, b] = buildtrainset_cnn(imgs_sample, imgs_sample_num);
% 24×40的原图片
cnn.layers = {
struct('type', 'i') %input layer
struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer outputmaps 6个特征图输出 卷积大小是5*5
struct('type', 's', 'scale', 2) %sub sampling layer max pooling 层 2*2
struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer
struct('type', 's', 'scale', 2) %sub sampling layer
};
cnn = cnnsetup(cnn, a, b);
% 学习率
opts.alpha = 2;
% 每次挑出一个batchsize的batch来训练,也就是每用batchsize个样本就调整一次权值,而不是
% 把所有样本都输入了,计算所有样本的误差了才调整一次权值
opts.batchsize = size(a, 3);
% 训练次数,用同样的样本集。我训练的时候:
%100 200 500 2000 都没有效果 错误率 83 4000 的时候效果明显 错误率7
opts.numepochs = 4000;
%训练模型
cnn = cnntrain(cnn, a, b, opts);
%保存模型,为以后识别程序
save cnn;
% 测试
image_dir=dir('test/*.jpg');
for i = 1: length(image_dir)
str_name = image_dir(i).name;
imgs_test{i} = str_name;
end
rightnum = 0;%正确个数
sumnum = 0;%总共样本
for i = 1 : length(imgs_test)
sumnum=sumnum+1;
img_name = imgs_test{i};
imgs = im2bw(imread(['test/',img_name]));%读取图片
tmp_num = str2num(img_name(1));
%% 等大小化
temp = zeros(max_size);
imgs_size = size(imgs);
temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs;
imgs = temp;
input_size = size(temp);
testInput(:, :, 1) = reshape(temp', input_size(1,1), input_size(1,2));
testInput(:, :, 2) = reshape(temp', input_size(1,1), input_size(1,2));
% 然后就用测试样本来测试
cnn = cnnff(cnn, testInput);
cnn.o
[~, mans] = max(cnn.o);
if mans(1,1)==tmp_num
rightnum=rightnum+1;
end
% img_name
% mans = mans
end
rightdata = [rightnum, sumnum-rightnum]
rightnum/sumnum
figure(88)
pie(rightdata, {'right', 'wrong'});
%plot mean squared error
figure(89)
plot(cnn.rL);
endbuildtrainset_cnn.m
% 创建数据集
function [inputs outputs] = buildtrainset_cnn(imgs, number)
i = 1;
for k = 1 : 6
for j = 1 : number(k)
input = imgs{k, j};
input_size = size(input);
inputs(:, :, i) = reshape(input', input_size(1,1), input_size(1,2));%这里的操作 转置矩阵 作为输入
outputs(:, i) = zeros(6, 1);
outputs(k, i) = 1;
i = i + 1;
end
end
end
值得指出的是,cnn训练的时间比较久,而且最开始被他欺骗了,请看我上面代码的注释,如果只是训练100次或者500次,甚至2000次都不能够让我的模型有作用,我也是一直怀疑是不是我哪里的数据处理错了,或者哪个矩阵弄反了,又回过头仔细琢磨验证码识别的那个代码,以及DeepLearnToolbox的范例代码,还是觉得没有问题啊,果断决定将训练次数提升到4000次,这时候奇迹出现了,误差曲线在3500的时候下降到差不多3的样子,应该是我的数据比较大的问题吧。4000次训练在我机器上需要1个多小时,还是比较耗时的。