%用于手写数字识别的卷积神经网络:训练和模拟。
%这个程序实现了用于MNIST手写数字识别的卷积神经网络,由Yann LeCun创建。 CNN类允许创建自己的卷积神经网络,定义任意结构和参数。
%假定MNIST数据库位于“./MNIST”目录中。
clear;
clc;
%将数字加载到工作区
[I,labels,I_test,labels_test] = readMNIST(1000); %前文分析
%定义结构总层数
numLayers = 8;
%降采样层的个数
numSLayers = 3;
%卷积层个数
numCLayers = 3;
%全连接层个数
numFLayers = 2;
%输入图像数(同时处理)。未来版本可能有改进之处,现在只能使用1
numInputs = 1;
%图像尺寸设置
InputWidth = 32;
InputHeight = 32;
%输出个数
numOutputs = 10;
%创建一个具有定义结构的空的卷积神经网络
sinet=cnn(numLayers,numFLayers,numInputs,InputWidth,InputHeight,numOutputs);%cnn.m在后文
%现在定义网络参数
%由于实施细节层总是成对的。 首先必须是降采样,最后(全连接之前)是卷积层。这就是为什么这里的第一层是虚拟的。
sinet.SLayer{1}.SRate = 1;
sinet.SLayer{1}.WS{1} = ones(size(sinet.SLayer{1}.WS{1}));
sinet.SLayer{1}.BS{1} = zeros(size(sinet.SLayer{1}.BS{1}));
sinet.SLayer{1}.TransfFunc = 'purelin';
%这层有1个权重参数,1个偏置参数。
%第二层 - 5x5大小的6个卷积核
sinet.CLayer{2}.numKernels = 6;
sinet.CLayer{2}.KernWidth = 5;
sinet.CLayer{2}.KernHeight = 5;
%这一层有150(6*5*5)个权重参数;
%6个偏置参数。
%第三层
%Subsampling rate
sinet.SLayer{3}.SRate = 2;
%Weights 6
%Biases 6
%第四层 - 16 kernels with 5x5 size
sinet.CLayer{4}.numKernels = 16;
sinet.CLayer{4}.KernWidth = 5;
sinet.CLayer{4}.KernHeight = 5;
%Weights 150
%Biases 6
%Fifth layer
%Subsampling rate
sinet.SLayer{5}.SRate = 2;
%Weights 6 ??不应该是16吗
%Biases 6 ??
%Sixth layer - outputs 120 feature maps 1x1 size
sinet.CLayer{6}.numKernels = 120;
sinet.CLayer{6}.KernWidth = 5;
sinet.CLayer{6}.KernHeight = 5;
%Weights 3000
%Biases 120
%第七层 - fully connected, 84 neurons
%当特征图的大小变为1*1时即为全连接层
sinet.FLayer{7}.numNeurons = 84;
%Weights 10080
%Biases 84
%第八层 - fully connected, 10 output neurons
sinet.FLayer{8}.numNeurons = 10;
%Weights 840
%Biases 10
%初始化网络
sinet = init(sinet);%init.m在后文
%为了消除对称性而进行泛化
sinet.CLayer{4}.ConMap = ...
[1 0 0 0 1 1 1 0 0 1 1 1 1 0 1 1;
1 1 0 0 0 1 1 1 0 0 1 1 1 1 0 1;
1 1 1 0 0 0 1 1 1 0 0 1 0 1 1 1;
0 1 1 1 0 0 1 1 1 1 0 0 1 0 1 1;
0 0 1 1 1 0 0 1 1 1 1 0 1 1 0 1;
0 0 0 1 1 1 0 0 1 1 1 1 0 1 1 1;
]';
%但有些论文提出随机生成连接图。 所以你可以试试:
%sinet.CLayer{6}.ConMap = round(rand(size(sinet.CLayer{6}.ConMap))-0.1);
%(比如matconvnet里的dropout就是有一个dropout的rate然后随机连接的?)
sinet.SLayer{1}.WS{1} = ones(size(sinet.SLayer{1}.WS{1}));
sinet.SLayer{1}.BS{1} = zeros(size(sinet.SLayer{1}.BS{1}));
%在我的实现输出层是普通tansig层而不是[1,2],但我计划实现径向基础输出层
%sinet.FLayer{8}.TransfFunc = 'radbas';定义全连接的一个类型?
%现在是最后的准备
%迭代次数
sinet.epochs = 3;
%Levenberg-Marquardt的随机系数 ?这是什么鬼
sinet.mu = 0.001;
%训练系数
%sinet.teta = [50 50 20 20 20 10 10 10 5 5 5 5 1]/100000;
sinet.teta = 0.0005;
%0 - 每次迭代计算黑森州运行估计(Hessian running estimate)
%1 - 每个cnet.Hrecomp迭代重新计算Hessian近似
%2 - 不进行Hessian计算,纯随机梯度
sinet.HcalcMode = 0;
sinet.Hrecalc = 300; %用于Hessian计算的迭代次数
sinet.HrecalcSamplesNum = 50; %Hessian重新计算的样本数
%Teta减少系数
sinet.teta_dec = 0.4;
%%图像预处理。 结果图像具有0平均值和1标准偏差。详情请参preproc_data
[Ip, labtrn] = preproc_data(I,1000,labels,0);
[I_testp, labtst] = preproc_data(I_test,100,labels_test,0);%preproc_data.m于后文
%实际训练
sinet = train(sinet,Ip,labtrn,I_testp,labtst);%train.m于后文
在这个程序中调用了几个子程序,分别是readMNIST.m,cnn.m,init.m,preproc_data.m和train.m。