加載資料
資料集包含手寫數字的合成圖像以及每個圖像的旋轉角度(以度為機關)。
使用 digitTrain4DArrayData 和 digitTest4DArrayData 以四維數組的形式加載訓練圖像和驗證圖像。輸出 YTrain 和 YValidation 是以度為機關的旋轉角度。訓練資料集和驗證資料集各包含 5000 個圖像。
[XTrain,~,YTrain] = digitTrain4DArrayData;
[XValidation,~,YValidation] = digitTest4DArrayData;
使用 imshow 顯示 20 個随機訓練圖像。
numTrainImages = numel(YTrain);
figure
idx = randperm(numTrainImages,20);
for i = 1:numel(idx)
subplot(4,5,i)
imshow(XTrain(:,:,:,idx(i)))
end

檢查資料歸一化
在訓練神經網絡時,最好確定資料在網絡的所有階段均歸一化。對于使用梯度下降的網絡訓練,歸一化有助于訓練的穩定和加速。如果您的資料比例不佳,則損失可能會變為 NaN,并且網絡參數在訓練過程中可能發生偏離。歸一化資料的常用方法包括重新縮放資料,使其範圍變為 [0,1],或使其均值為 0 且标準差為 1。您可以歸一化以下資料:
輸入資料。在将預測變量輸入到網絡之前對其進行歸一化。在此示例中,輸入圖像已歸一化到範圍 [0,1]。
層輸出。您可以使用批量歸一化層來歸一化每個卷積層和全連接配接層的輸出。
響應。如果使用批量歸一化層來歸一化網絡末尾的層輸出,則網絡的預測值在訓練開始時就被歸一化。如果響應的比例與這些預測值完全不同,則網絡訓練可能無法收斂。如果您的響應比例不佳,則嘗試對其進行歸一化,并檢視網絡訓練是否有所改善。如果在訓練之前将響應歸一化,則必須變換經過訓練網絡的預測值,以獲得原始響應的預測值。
繪制響應的分布。響應(以度為機關的旋轉角度)大緻均勻地分布在 -45 和 45 之間,效果很好,無需歸一化。在分類問題中,輸出是類機率,始終需要歸一化。
figure
histogram(YTrain)
axis tight
ylabel('Counts')
xlabel('Rotation Angle')
通常,資料不必完全歸一化。但是,如果在此示例中訓練網絡來預測 100*YTrain 或 YTrain+500 而不是 YTrain,則損失将變為 NaN,并且網絡參數在訓練開始時會發生偏離。即使預測 aY + b 的網絡與預測 Y 的網絡之間的唯一差異是對最終全連接配接層的權重和偏置的簡單重新縮放,也會出現這些結果。
如果輸入或響應的分布非常不均勻或偏斜,您還可以在訓練網絡之前對資料執行非線性變換(例如,取其對數)。
建立網絡層
要求解回歸問題,請建立網絡層并在網絡末尾包含一個回歸層。
第一層定義輸入資料的大小和類型。輸入圖像的大小為 28×28×1。建立與訓練圖像大小相同的圖像輸入層。
網絡的中間層定義網絡的核心架構,大多數計算和學習都在此處進行。
最終層定義輸出資料的大小和類型。對于回歸問題,全連接配接層必須位于網絡末尾的回歸層之前。建立一個大小為 1 的全連接配接輸出層以及一個回歸層。
在 Layer 數組中将所有層組合在一起。
layers = [
imageInputLayer([28 28 1])
convolution2dLayer(3,8,'Padding','same')
batchNormalizationLayer
reluLayer
averagePooling2dLayer(2,'Stride',2)
convolution2dLayer(3,16,'Padding','same')
batchNormalizationLayer
reluLayer
averagePooling2dLayer(2,'Stride',2)
convolution2dLayer(3,32,'Padding','same')
batchNormalizationLayer
reluLayer
convolution2dLayer(3,32,'Padding','same')
batchNormalizationLayer
reluLayer
dropoutLayer(0.2)
fullyConnectedLayer(1)
regressionLayer];
訓練網絡
建立網絡訓練選項。進行 30 輪訓練。将初始學習率設定為 0.001,并在 20 輪訓練後降低學習率。通過指定驗證資料和驗證頻率,監控訓練過程中的網絡準确度。軟體基于訓練資料訓練網絡,并在訓練過程中按固定時間間隔計算基于驗證資料的準确度。驗證資料不用于更新網絡權重。打開訓練進度圖,關閉指令行視窗輸出。
miniBatchSize = 128;
validationFrequency = floor(numel(YTrain)/miniBatchSize);
options = trainingOptions('sgdm', ...
'MiniBatchSize',miniBatchSize, ...
'MaxEpochs',30, ...
'InitialLearnRate',1e-3, ...
'LearnRateSchedule','piecewise', ...
'LearnRateDropFactor',0.1, ...
'LearnRateDropPeriod',20, ...
'Shuffle','every-epoch', ...
'ValidationData',{XValidation,YValidation}, ...
'ValidationFrequency',validationFrequency, ...
'Plots','training-progress', ...
'Verbose',false);
使用 trainNetwork 建立網絡。如果存在相容的 GPU,此指令會使用 GPU。否則,trainNetwork 将使用 CPU。在 GPU 上進行訓練需要具有 3.0 或更高計算能力的支援 CUDA® 的 NVIDIA® GPU。
net = trainNetwork(XTrain,YTrain,layers,options);
檢查 net 的 Layers 屬性中包含的網絡架構的詳細資訊。
net.Layers
ans =
18×1 Layer array with layers:
1 'imageinput' Image Input 28×28×1 images with 'zerocenter' normalization
2 'conv_1' Convolution 8 3×3×1 convolutions with stride [1 1] and padding 'same'
3 'batchnorm_1' Batch Normalization Batch normalization with 8 channels
4 'relu_1' ReLU ReLU
5 'avgpool2d_1' Average Pooling 2×2 average pooling with stride [2 2] and padding [0 0 0 0]
6 'conv_2' Convolution 16 3×3×8 convolutions with stride [1 1] and padding 'same'
7 'batchnorm_2' Batch Normalization Batch normalization with 16 channels
8 'relu_2' ReLU ReLU
9 'avgpool2d_2' Average Pooling 2×2 average pooling with stride [2 2] and padding [0 0 0 0]
10 'conv_3' Convolution 32 3×3×16 convolutions with stride [1 1] and padding 'same'
11 'batchnorm_3' Batch Normalization Batch normalization with 32 channels
12 'relu_3' ReLU ReLU
13 'conv_4' Convolution 32 3×3×32 convolutions with stride [1 1] and padding 'same'
14 'batchnorm_4' Batch Normalization Batch normalization with 32 channels
15 'relu_4' ReLU ReLU
16 'dropout' Dropout 20% dropout
17 'fc' Fully Connected 1 fully connected layer
18 'regressionoutput' Regression Output mean-squared-error with response 'Response'
測試網絡
基于驗證資料評估準确度來測試網絡性能。
使用 predict 預測驗證圖像的旋轉角度。
YPredicted = predict(net,XValidation);
評估性能
通過計算以下值來評估模型性能:
在可接受誤差界限内的預測值的百分比
預測旋轉角度和實際旋轉角度的均方根誤差 (RMSE)
計算預測旋轉角度和實際旋轉角度之間的預測誤差。
predictionError = YValidation - YPredicted;
計算在實際角度的可接受誤差界限内的預測值的數量。将門檻值設定為 10 度。計算此門檻值範圍内的預測值的百分比。
thr = 10;
numCorrect = sum(abs(predictionError) < thr);
numValidationImages = numel(YValidation);
accuracy = numCorrect/numValidationImages
accuracy = 0.9690
使用均方根誤差 (RMSE) 來衡量預測旋轉角度和實際旋轉角度之間的差異。
squares = predictionError.^2;
rmse = sqrt(mean(squares))
rmse = single
4.6062
可視化預測
在散點圖中可視化預測。繪制預測值對真實值的圖。
figure
scatter(YPredicted,YValidation,'+')
xlabel("Predicted Value")
ylabel("True Value")
hold on
plot([-60 60], [-60 60],'r--')
校正數字旋轉
您可以使用 Image Processing Toolbox 中的函數來擺正數字并将它們顯示在一起。使用 imrotate (Image Processing Toolbox) 根據預測的旋轉角度旋轉 49 個樣本數字。
idx = randperm(numValidationImages,49);
for i = 1:numel(idx)
image = XValidation(:,:,:,idx(i));
predictedAngle = YPredicted(idx(i));
imagesRotated(:,:,:,i) = imrotate(image,predictedAngle,'bicubic','crop');
end
顯示原始數字以及校正旋轉後的數字。您可以使用 montage (Image Processing Toolbox) 将數字顯示在同一個圖像上。
figure
subplot(1,2,1)
montage(XValidation(:,:,:,idx))
title('Original')
subplot(1,2,2)
montage(imagesRotated)
title('Corrected')