MATLAB深度学习入门-以手写数字图像识别为例 程序运行环境为MATLAB 2021b,为深度学习的简单入门介绍,并以手写数字图像识别为例进行说明,程序标注清晰,极易入门学习。 程序中的CNN逐层特征提取图如下所示。

先来点开胃菜,加载数据:

% 加载经典MNIST数据集(MATLAB内置处理版本)
digitDatasetPath = fullfile(matlabroot,'toolbox','nnet','nndemos','nndatasets','DigitDataset');
imds = imageDatastore(digitDatasetPath, 'IncludeSubfolders',true,'LabelSource','foldernames');

这个imageDatastore超好用,自动把6万张28x28的灰度图按文件夹分类加载好了。想看数据长啥样?试试这个:

figure;
perm = randperm(10000,16);
for i = 1:16
    subplot(4,4,i);
    imshow(imds.Files{perm(i)});
end

随机抽16张图拼个九宫格,你会发现有些数字写得那叫一个狂野(人类都未必认得出),正好测试模型的抗造能力。

重头戏来了——搭建CNN网络。咱们搞个三层卷积的轻量级结构:

layers = [
    imageInputLayer([28 28 1], 'Name', 'input')  % 注意通道数要设为1
    
    convolution2dLayer(3, 8, 'Padding','same', 'Name', 'conv1')
    batchNormalizationLayer('Name', 'bn1')
    reluLayer('Name', 'relu1')
    maxPooling2dLayer(2,'Stride',2, 'Name', 'pool1')  % 特征图尺寸减半
    
    convolution2dLayer(3, 16, 'Padding','same', 'Name', 'conv2')
    batchNormalizationLayer('Name', 'bn2')
    reluLayer('Name', 'relu2')
    maxPooling2dLayer(2,'Stride',2, 'Name', 'pool2')
    
    convolution2dLayer(3, 32, 'Padding','same', 'Name', 'conv3')
    batchNormalizationLayer('Name', 'bn3')
    reluLayer('Name', 'relu3')
    
    fullyConnectedLayer(10, 'Name', 'fc')  % 10分类任务
    softmaxLayer('Name', 'softmax')
    classificationLayer('Name', 'output')];

这个结构藏着几个小心机:每层卷积后接BN层加速收敛,用3x3小卷积核捕捉局部特征,池化层逐步压缩空间维度。注意输入尺寸28x28x1要和图片实际尺寸匹配,不然后面训练会报维度错误。

MATLAB深度学习入门-以手写数字图像识别为例 程序运行环境为MATLAB 2021b,为深度学习的简单入门介绍,并以手写数字图像识别为例进行说明,程序标注清晰,极易入门学习。 程序中的CNN逐层特征提取图如下所示。

训练配置也有讲究:

options = trainingOptions('sgdm', ...
    'MaxEpochs',15, ...
    'Shuffle','every-epoch', ...
    'ValidationFrequency',30, ...
    'Verbose',false, ...
    'Plots','training-progress');

偷懒用默认的带动量SGD,关掉verbose避免刷屏。重点看这个'training-progress'选项,训练时会自动画出实时更新的loss曲线,比盯着命令行看数字爽多了。

开练!

% 先分训练集验证集
[imdsTrain, imdsVal] = splitEachLabel(imds,0.8,'randomized');

% 开冲!
net = trainNetwork(imdsTrain, layers, options);

等进度条跑完(CPU大概10分钟,有GPU更快),可以掏出测试集看看战绩:

predictedLabels = classify(net, imdsVal);
trueLabels = imdsVal.Labels;
accuracy = sum(predictedLabels == trueLabels)/numel(trueLabels)

跑得好能达到98%左右的准确率。不过别光看数字,咱们得看看网络到底学了啥——可视化中间层特征:

layerName = 'conv1';  % 换其他层名试试
featureMap = activations(net, imread(imds.Files{1}), layerName);

figure
montage(rescale(featureMap))
title(['第一层卷积特征: ', layerName], 'Interpreter','none')

把输入图喂给activations函数,就能提取指定层的输出。比如第一层卷积出来的特征图,能看到各种边缘响应,越往后的层特征越抽象。

最后给个实用技巧:如果遇到显存不足,在trainingOptions里加个'MiniBatchSize',128调节批次大小。代码全放在Github上了,随便改着玩——把卷积核改成5x5,多加几层全连接,或者换成Adam优化器,观察准确率变化,这才是学习的最佳姿势。

更多推荐