介绍
本示例用于说明如何训练数字图像分类的堆栈自动编码器。
多隐藏层神经网络可用于处理复杂数据集的分类问题,如图片。每一个层可以从不同的抽象层次进行学习。但是,训练包含多隐藏层的神经网络比较困难。
一个可行的方法是每次只训练一个层。这个过程可以通过自动编码器的神经网络实现。
首先通过无监督的自动编码器对隐藏层的每一层进行单独训练,
然后训练最后一层softmax层;
最后把各层进行组合形成一个堆栈网络,通过监督策略进行最后的训练。
数据准备
数据集导入
[xTrainImages,tTrain] = digitTrainCellArrayData;
>> size(xTrainImages)
ans =
1 5000
>> size(xTrainImages{1})
ans =
28 28
xTrainImages中是1行5000列的cell,每一个cell是28×28的矩阵。
数据作图
for i = 1:20
subplot(4,5,i);
imshow(xTrainImages{i});
end
for i = 1:20
subplot(4,5,i);
imshow(xTrainImages{i+20});
end
tTrain是10行5000列的矩阵。每一列对应一幅前述的图片。10行中只有某一行为1。若第i行为1,则此图片对应的数值为i。若第10行为1,则此图片对应的数值为0。
>> size(tTrain)
ans =
10 5000
训练第一个自动编码器
首先不使用标记,对稀疏自动编码器(sparse autoencoder)进行训练。
自动编码器将输入复制为输出。所以自动编码器的输入的维度和输出的维度相同。若自动编码器隐藏层的输入维度比输出维度小,那么自动编码器学习到的是输入的压缩表示(compressed representation)。
随机数种子初始化
rng('default')
设置自动编码器的维度。针对待训练的此组图片集,可以将自动编码器的层数小于输入数据的维度。
hiddenSize1 = 100;
待训练的自动编码器是一个稀疏的自动编码器。
在第一层中采用正则化(regularizers)进行学习。可通过配置相关参数对这些正则化的影响进行控制。
autoenc1 = trainAutoencoder(xTrainImages,hiddenSize1, ...
'MaxEpochs',400, ...
'L2WeightRegularization',0.004, ...
'SparsityRegularization',4, ...
'SparsityProportion',0.15, ...
'ScaleData', false);
作图如下:
自动编码器性能分析
从上图可见,终止条件为迭代到达设定次数。从下图可见,在整个迭代过程中,初始20次时误差迅速下降,初始100次迭代中误差几乎下降到稳定值,最后200次迭代过程误差几乎不变。
编码器的权重图如下,从图中可见编码器学习到了数字图像的笔划(curls and stroke patterns)。100维的输出是对输入维度的压缩。
plotWeights(autoenc1);
训练第二个自动编码器
自动译码器的输入数据是从训练集中提取的向量。首先,需要采用第一个自动编码器生成这些特征。
feat1 = encode(autoenc1,xTrainImages);
第二个自动编码器的训练过程和第一个网络的训练过程接近。主要区别是第二个自动编码器的训练数据是第一个自动编码器生成的。同时,把第二个自动编码器的维度将至50,所以第二个隐藏层学习到的是输入数据的更加小的表示。
hiddenSize2 = 50;
autoenc2 = trainAutoencoder(feat1,hiddenSize2, ...
'MaxEpochs',100, ...
'L2WeightRegularization',0.002, ...
'SparsityRegularization',4, ...
'SparsityProportion',0.1, ...
'ScaleData', false);
第二个自动编码器如下图所示
view(autoenc2)
训练过程如下:
迭代终止条件为达到了设定的最大迭代次数。
迭代过程如下所示,与第一个编码器过程类似。
提取第二个编码器生产的特征
feat2 = encode(autoenc2,feat1);
初始的训练数据维度是28×28=784维。通过第一个自动编码器后,维度降至100维;通过第二个自动编码器后,维度降至50维。
然后可以训练最后一个softmax层。
训练最后的softmax层
softmax层用于对训练得到的50维向量进行分类。与之前的自动编码器层不同,之前的自动编码器层使用的是无监督的学习过程。softmax层使用一开始提供的监督数据tTrain进行训练。
softnet = trainSoftmaxLayer(feat2,tTrain,'MaxEpochs',400);
训练图如下:
训练结果如下
迭代终止条件是到达了设定的最大迭代次数。
堆栈神经网络的构建
上述各节已经单独训练了三个神经网络。
组装过程如下:
stackednet = stack(autoenc1,autoenc2,softnet);
图示如下:
view(stackednet)
之后,可以在测试集上进行测试。为了在这个组合网络上使用图片数据,需要将图片的维度进行重整。
imageWidth = 28;
imageHeight = 28;
inputSize = imageWidth*imageHeight;
% Load the test images
[xTestImages,tTest] = digitTestCellArrayData;
% Turn the test images into vectors and put them in a matrix
xTest = zeros(inputSize,numel(xTestImages));
for i = 1:numel(xTestImages)
xTest(:,i) = xTestImages{i}(:);
end
在confusions视图上查看测试结果,如下图所示。
y = stackednet(xTest);
plotconfusion(tTest,y);
每一行最右侧的绿色数字是分类正确率,红色数字是分类错误率。从图中可见,分类正确率最高为63.1%,最低为44.4%。
对堆栈神经网络的进一步精细调整
堆栈神经网络的性能可以通过在整个多层网络上使用后向传播算法( backpropagation)进一步提升。
通过监督模式,重新训练整个网络。(需要对输入数据的维度进行重整)
% Turn the training images into vectors and put them in a matrix
xTrain = zeros(inputSize,numel(xTrainImages));
for i = 1:numel(xTrainImages)
xTrain(:,i) = xTrainImages{i}(:);
end
% Perform fine tuning
stackednet = train(stackednet,xTrain,tTrain);
迭代终止原因为梯度降至最小值。
再一次在confusion视图上展示分类效果。
y = stackednet(xTest);
plotconfusion(tTest,y);
从图中可见,分类效果得到了大幅度提升。分类正确率最高为99.8%,最低为96.3%。
【说明:真的很神奇,后续继续研究其机理】