Main Content

训练堆叠自编码器进行图像分类

此示例说明如何训练堆叠自编码器以对数字图像进行分类。

具有多个隐含层的神经网络可用于处理复杂数据(例如图像)的分类问题。每个层都可以学习不同抽象级别的特征。然而,在实际工作中,训练具有多个隐含层的神经网络可能会很困难。

一种有效训练具有多个层的神经网络的方法是一次训练一个层。为此,您可以为每个所需的隐含层训练一种称为自编码器的特殊类型的网络。

此示例说明如何训练具有两个隐含层的神经网络以对图像中的数字进行分类。首先,使用自编码器以无监督方式单独训练各隐含层。然后训练最终 softmax 层,并将这些层连接在一起形成堆叠网络,该网络最后以有监督方式进行训练。

数据集

此示例始终使用合成数据进行训练和测试。已通过对使用不同字体创建的数字图像应用随机仿射变换来生成合成图像。

每个数字图像为 28×28 像素,共有 5000 个训练样本。您可以加载训练数据,并查看其中一些图像。

% Load the training data into memory
[xTrainImages,tTrain] = digitTrainCellArrayData;

% Display some of the training images
clf
for i = 1:20
    subplot(4,5,i);
    imshow(xTrainImages{i});
end

图像的标签存储在一个 10×5000 矩阵中,其中每列都有一个元素为 1,指示该数字所属的类,该列中的所有其他元素为 0。请注意,如果第十个元素是 1,则数字图像是零。

训练第一个自编码器

首先在不使用标签的情况下基于训练数据训练稀疏自编码器。

自编码器是一种神经网络,该网络会尝试在其输出端复制其输入。因此,其输入的大小将与其输出的大小相同。当隐藏层中的神经元数量小于输入的大小时,自编码器将学习输入的压缩表示。

神经网络在训练前具有随机初始化的权重。因此,每次训练的结果都不同。为避免此行为,请显式设置随机数生成器种子。

rng('default')

设置自编码器的隐含层的大小。对于要训练的自编码器,最好使隐含层的大小小于输入大小。

hiddenSize1 = 100;

您将训练的自编码器的类型是稀疏自编码器。该自编码器使用正则项来学习第一层中的稀疏表示。您可以设置各种参数来控制这些正则项的影响:

  • L2WeightRegularization 控制 L2 正则项对网络权重(而不是偏置)的影响。这通常应该非常小。

  • SparsityRegularization 控制稀疏正则项的影响,该正则项会尝试对隐含层的输出的稀疏性施加约束。请注意,这与将稀疏正则项应用于权重不同。

  • SparsityProportion 是稀疏正则项的参数。它控制隐含层的输出的稀疏性。较低的 SparsityProportion 值通常导致只为少数训练样本提供高输出,从而使隐藏层中的每个神经元“专门化”。例如,如果 SparsityProportion 设置为 0.1,这相当于说隐藏层中的每个神经元针对训练样本的平均输出值应该为 0.1。此值必须介于 0 和 1 之间。理想值因问题的性质而异。

现在训练自编码器,指定上述正则项的值。

autoenc1 = trainAutoencoder(xTrainImages,hiddenSize1, ...
    'MaxEpochs',400, ...
    'L2WeightRegularization',0.004, ...
    'SparsityRegularization',4, ...
    'SparsityProportion',0.15, ...
    'ScaleData', false);

您可以查看自编码器的图。自编码器由一个编码器和一个解码器组成。编码器将输入映射为隐含表示,解码器则尝试进行逆映射以重新构造原始输入。

view(autoenc1)

可视化第一个自编码器的权重

自编码器的编码器部分所学习的映射可用于从数据中提取特征。编码器中的每个神经元都具有一个与之相关联的权重向量,该向量将进行相应调整以响应特定可视化特征。您可以查看这些特征的表示。

figure()
plotWeights(autoenc1);

您可以看到,自编码器学习的特征代表了数字图像中的弯曲和笔划图案。

自编码器的隐含层的 100 维输出是输入的压缩版本,它汇总了对上面可视化的特征的响应。基于从训练数据中提取的一组向量训练下一个自编码器。首先,必须使用经过训练的自编码器中的编码器生成特征。

feat1 = encode(autoenc1,xTrainImages);

训练第二个自编码器

训练完第一个自编码器后,您需要以相似的方式训练第二个自编码器。主要区别在于您将使用从第一个自编码器生成的特征作为第二个自编码器中的训练数据。此外,您还需要将隐含表示的大小减小到 50,以便第二个自编码器中的编码器学习输入数据的更小表示。

hiddenSize2 = 50;
autoenc2 = trainAutoencoder(feat1,hiddenSize2, ...
    'MaxEpochs',100, ...
    'L2WeightRegularization',0.002, ...
    'SparsityRegularization',4, ...
    'SparsityProportion',0.1, ...
    'ScaleData', false);

同样,您可以使用 view 函数查看自编码器的图。

view(autoenc2)

您可以将前一组特征传递给第二个自编码器中的编码器,以此提取第二组特征。

feat2 = encode(autoenc2,feat1);

训练数据中的原始向量具有 784 个维度。原始数据通过第一个编码器后,维度减小到 100 维。应用第二个编码器后,维度进一步减小到 50 维。您现在可以训练最终层,以将这些 50 维向量分类为不同的数字类。

训练最终 softmax 层

训练 softmax 层以对 50 维特征向量进行分类。与自编码器不同,您将使用训练数据的标签以有监督方式训练 softmax 层。

softnet = trainSoftmaxLayer(feat2,tTrain,'MaxEpochs',400);

您可以使用 view 函数查看 softmax 层的图。

view(softnet)

形成堆叠神经网络

您已单独训练了组成堆叠神经网络的三个网络。现在,您可以查看已经过训练的三个神经网络。它们是 autoenc1autoenc2softnet

view(autoenc1)

view(autoenc2)

view(softnet)

如前面所述,自编码器中的编码器已用于提取特征。您可以将自编码器中的编码器与 softmax 层堆叠在一起,以形成用于分类的堆叠网络。

stackednet = stack(autoenc1,autoenc2,softnet);

您可以使用 view 函数查看堆叠网络的图。该网络由自编码器中的编码器和 softmax 层构成。

view(stackednet)

在搭建了完整网络之后,您可以基于测试集计算结果。要将图像用于堆叠网络,必须将测试图像重构为矩阵。这可以通过先堆叠图像的各列以形成向量,然后根据这些向量形成矩阵来完成。

% Get the number of pixels in each image
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

您可以使用混淆矩阵来可视化结果。矩阵右下角方块中的数字表示整体准确度。

y = stackednet(xTest);
plotconfusion(tTest,y);

微调堆叠神经网络

通过对整个多层网络执行反向传播,可以改进堆叠神经网络的结果。此过程通常称为微调。

通过以有监督方式基于训练数据重新训练网络来微调网络。在您执行此操作之前,必须将训练图像重构为矩阵,就像对测试图像所做的那样。

% 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);

然后使用混淆矩阵再次查看结果。

y = stackednet(xTest);
plotconfusion(tTest,y);

总结

此示例说明了如何训练堆叠神经网络以使用自编码器对图像中的数字进行分类。所述步骤可以应用于其他类似问题,例如对字母图像进行分类,或者对特定类别的对象的小型图像进行分类。