来到卷积神经网络详解的最后一章,在前面四篇博客里,我们首先对CNN的整体框架进行讲解,然后结合代码对卷积层、池化处理、全连接网络层以及计算cost的前向传播,计算梯度值的反向传播都分别进行讲解。这一章,我们要把这些全部捏合起来,构建一个CNN神经网络,并在MNIST数据集上进行分类训练和测试。
在那之前,我们还有两个在工程中很实用的概念没有提到:
Stochastic Gradient Descent,以下简称SGDMomentum在标准的梯度下降算法中,我们对目标函数 J(θ) 按照以下公式进行参数更新:
θ=θ−α∇θE[J(θ)] 从上式可以看到,传统的GD算法中的cost和gradient是将整个训练集的数据考虑进去,再进行更新的。而SGD的思路是,每次进行参数学习更新时,只考虑一个训练样本或者一部分训练样本的贡献。那每次迭代的参数更新变为:
θ=θ−α∇θJ(θ;set[x(i),y(i)]) 从上式可以看到,SGD算法的参数更新的每一次迭代只考虑一个batch的训练数据,一般来说,最小的batch size取值为256。SGD的优点: - 减小在参数更新中的方差,让训练的收敛更平稳; - 可以利用高度并行化的设计来提升算法的效率。
基于冲量的参数更新:
v=γv+α∇θJ(θ;set[x(i),y(i)]) θ=θ−v 每一步梯度下降的大小和方向,我们也参考上一步的v,要是方向一致,就大步往前走;要是忽左忽右,就快步走出这个区域。加入冲量的思想可以很好解决局部最优,加快网络的收敛。γ 的取值一般在 (0,1] 范围内,一般来说,在初始化的训练稳定之前, γ 取0.5,之后取值0.9及更大。
% 冲量 mom = 0.5; momIncrease = 20; velocity = zeros(size(theta)); %%====================================================================== %% 随机梯度下降 it = 0; for e = 1:epochs % 随机打乱训练样本的顺序 rp = randperm(m); for s=1:minibatch:(m-minibatch+1) it = it + 1; % 在每一次it达到momIncrease时,更新冲量 if it == momIncrease mom = options.momentum; end; % 按照minibatch获取训练数据 mb_data = data(:,:,rp(s:s+minibatch-1)); mb_labels = labels(rp(s:s+minibatch-1)); % 计算目标函数值 [cost grad] = funObj(theta,mb_data,mb_labels); % 更新theta,ufldl教程Optimization: Stochastic Gradient Descent velocity = mom*velocity+alpha*grad; theta = theta-velocity; fprintf('Epoch %d: Cost on iteration %d is %f\n',e,it,cost); end; % 每次迭代后衰减learning rate alpha = alpha/2.0; end;在我们的实现代码中,冲量的初始取值为0.5,当迭代次数达到momIncrease后,冲量取值变为0.9。
cnnTrain.m是整个CNN网络训练分类MNIST数据集的主函数,对每部分的代码分别进行介绍。
这部分的代码是为网络训练做准备,包括载入MNIST训练集,参数初始化等。
%% 第一步:初始化参数,载入训练数据 % 参数配置 % MNIST数据库图片的大小为28×28 imageDim = 28; % 要分类的类别数 numClasses = 10; %卷积层的特征提取模块的维数(滤波器维数) filterDim = 9; % 特征提取滤波器的个数 numFilters = 20; % 池化的维数,应该整除imageDim-filterDim+1 poolDim = 2; % 载入MNIST数据库的训练数据 addpath function/; images = loadMNISTImages('../MNIST/train-images-idx3-ubyte'); images = reshape(images,imageDim,imageDim,[]); labels = loadMNISTLabels('../MNIST/train-labels-idx1-ubyte'); % 将分类标签0重新映射到10 labels(labels==0) = 10; % 初始化参数 theta = cnnInitParams(imageDim,filterDim,numFilters,poolDim,numClasses);minibatch大小设置为256,冲量取值为0.95,总的迭代次数是3。
%% 训练CNN网络 options.epochs = 3; options.minibatch = 256; options.alpha = 1e-1; options.momentum = .95; opttheta = minFuncSGD(@(x,y,z) cnnCost(x,y,z,numClasses,filterDim,... numFilters,poolDim),theta,images,labels,options);在完成3次迭代后,整个CNN网络收敛,在测试数据集上的预测准确率达到97.1%。结果如下:
. . . Epoch 3: Cost on iteration 687 is 0.119978 Epoch 3: Cost on iteration 688 is 0.126712 Epoch 3: Cost on iteration 689 is 0.087837 Epoch 3: Cost on iteration 690 is 0.100424 Epoch 3: Cost on iteration 691 is 0.112769 Epoch 3: Cost on iteration 692 is 0.062723 Epoch 3: Cost on iteration 693 is 0.120102 Epoch 3: Cost on iteration 694 is 0.144303 Epoch 3: Cost on iteration 695 is 0.126082 Epoch 3: Cost on iteration 696 is 0.140024 Epoch 3: Cost on iteration 697 is 0.074275 Epoch 3: Cost on iteration 698 is 0.123467 Epoch 3: Cost on iteration 699 is 0.154408 Epoch 3: Cost on iteration 700 is 0.095232 Epoch 3: Cost on iteration 701 is 0.098181 Epoch 3: Cost on iteration 702 is 0.111052 Accuracy is 0.971000整个工程代码我已经上传到github上,欢迎下载运行,有很详细的注释帮助理解卷积神经网络的每一步。
后续我还会用pytorch来实现这个cnn网络,对比效果,同时也练练手。请关注代码的github地址:
https://github.com/wblgers/stanford_dl_cnn
http://ufldl.stanford.edu/tutorial/supervised/OptimizationStochasticGradientDescent/ http://blog.csdn.net/nuoman_cheng/article/details/50426943