本例中使用的数据集包含10,000张数字从0到9的合成图像。这些图像是通过对使用不同字体创建的数字的图像应用随机转换而生成的。每个数字图像是28 × 28像素。数据集每个类别包含相同数量的图像。使用imageDataStore读取图像。
digitDatasetPath = fullfile(matlabroot,'toolbox','nnet','nndemos','nndatasets','DigitDataset');
Imds = imageDatastore(digitDatasetPath,'IncludeSubfolders',true, 'LabelSource','foldernames');
从数据集中随机选择并绘制20幅图像。
figure
numImages = 10000;
rng(100);
perm = randperm(numImages,20);
for np = 1:20
subplot(4,5,np);
imshow(Imds.Files{perm(np)});
end
您可以看到,第1、2、3和4行中的8表现出相当大的可变性,但都可以识别为8。样本中的其他重复数字也是如此。这与自然笔迹是一致的,在个人之间,甚至在同一个人的笔迹中,任何数字在翻译、旋转和其他小变形方面都有很大的不同。使用小波散射,我们希望建立这些数字的表示,以掩盖这种不相关的可变性。
数据划分
为了实验结果的可重复再现性,使用rng()函数设置随机种子。
对imageDatastore的文件进行洗选,并将10,000张图像分成两组,一组用于训练,另一组用于测试。将80%的数据(即8000张图像)分配给训练集,并保留剩下的2000张图像用于测试。
rng(10);
Imds = shuffle(Imds);
[trainImds,testImds] = splitEachLabel(Imds,0.8); % splitEachLabel函数从数据集中取80%的数据作为训练集,20%的数据作为测试集
Ttrain = tall(trainImds); % 从训练和测试数据集创建tall数组,用于卷积神经网络训练。
Ttest = tall(testImds);
自定义卷积层数为1层的CNN
训练一个拥有1个卷积层简单的卷积神经网络,来识别数字。构建1个卷积核大小为3 × 3的卷积神经网络,卷积层数为2,每个卷积层的步长为1 × 1。在卷积层之后是RELU激活。使用全连接层,然后使用softmax层将完全连接层的输出归一化为概率。使用交叉熵损失函数进行学习。
imageSize = [28 28 1];
layers_1 = [ ...
imageInputLayer([28 28 1]) % 输入层 输入数据长×宽×通道为28*28*1
convolution2dLayer(3,32) % 卷积层 3为卷积核大小,32为卷积通道数
reluLayer % 激活层
fullyConnectedLayer(10) % 全连接层,10为数据集类别数量
softmaxLayer % softmax分类激活函数
classificationLayer]; % 分类层
使用动量随机梯度下降(sgdm),学习率为0.0001进行训练。将epoch的最大数目设置为10。
% 网络训练优化器为动量随机梯度下降(sgdm),epoch为10,学习率0.0001;'Plots','training-progress'为绘制训练损失函数,'ExecutionEnvironment','cpu'为设置CPU进行训练
options_1 = trainingOptions('sgdm', ...
'MaxEpochs',10,...
'InitialLearnRate',1e-4, ...
'Verbose',false, ...
'Plots','training-progress','ExecutionEnvironment','cpu');
训练网络。对于训练和测试,我们使用与散射变换相同的数据集。
reset(trainImds); %reset - 将数据存储重置为初始状态
reset(testImds);
net_1 = trainNetwork(trainImds,layers_1,options_1);
在训练结束时,CNN在训练集上的表现接近100%。使用经过训练的网络对hold -out测试集进行预测。
YPred = classify(net_1,testImds,'ExecutionEnvironment','cpu'); % 使用训练好的net_1进行测试
DCNNaccuracy_1 = sum(YPred == testImds.Labels)/numel(YPred)*100
DCNNaccuracy_1 = 95.5000
简单CNN在hold -out测试集上的分类正确率达到95.5%。
绘制CNN的混淆图。
figure;
confusionchart(testImds.Labels,YPred);
title('Test-Set Confusion Chart -- CNN_1')
自定义卷积层数为2层的CNN
训练一个拥有2个卷积层简单的卷积神经网络,来识别数字。构建1个卷积核大小为3 × 3的卷积神经网络,卷积层数为2,每个卷积层的步长为1 × 1。在卷积层之后是RELU激活。使用全连接层,然后使用softmax层将完全连接层的输出归一化为概率。使用交叉熵损失函数进行学习。
imageSize = [28 28 1];
layers_2 = [ ...
imageInputLayer([28 28 1])
convolution2dLayer(3,32)
reluLayer
convolution2dLayer(3,64) % 新增卷积层,通道数量为64
reluLayer
fullyConnectedLayer(10)
softmaxLayer
classificationLayer];
使用动量随机梯度下降,学习率为0.0001进行训练。将epoch的最大数目设置为10。
options_2 = trainingOptions('sgdm', ...
'MaxEpochs',10,...
'InitialLearnRate',1e-4, ...
'Verbose',false, ...
'Plots','training-progress','ExecutionEnvironment','cpu');
训练网络。对于训练和测试,我们使用与散射变换相同的数据集。
reset(trainImds);
reset(testImds);
net = trainNetwork(trainImds,layers_2,options_2);
在训练结束时,CNN在训练集上的表现接近100%。使用经过训练的网络对hold -out测试集进行预测。
YPred = classify(net,testImds,'ExecutionEnvironment','cpu');
DCNNaccuracy_2 = sum(YPred == testImds.Labels)/numel(YPred)*100
DCNNaccuracy_2 = 97.6500
简单CNN在hold -out测试集上的分类正确率达到97.65%。
绘制CNN的混淆图。
figure;
confusionchart(testImds.Labels,YPred);
title('Test-Set Confusion Chart -- CNN_2')
总结
本例使用两个简单的CNN分类器对手写数字进行识别。
对于两个CNN分类器,设置了不同的卷积层数来对比分类精度。实验结果表明,增加卷积层的数量可以提高网络精度,实现更高的判别准确率。
然而,这并非是绝对的。过多的卷积层会使得网络精度下降(读者可自行进行实验探究)。
在实际应用中,应当设置性能与数据集数据相匹配的卷积神经网络以保证识别准确率。