Matlab深度學習
文章目錄
- Matlab深度學習
- 前言
- 一、MNIST手寫體數字資料
- 二、用到的深度學習架構-LeNet5
-
- 2-0 LeNet5的網絡架構
- 2-1 架構實作-通過Matlab GUI 拖拽界面
- 2-2 架構實作2-直接寫架構代碼
- 三、代碼
-
- 3-0 機器學習與深度學習對比
- 3-1 SVM分類手寫體數字
- 3-2 ANN分類手寫體數字
- 3-3 深度學習LetNet5
- 測試
- 最後
前言
最近想在matlab環境下跑一下深度學習模型,找到了以下的一篇部落格,但因為該部落格所附錄的資源失效,而且也可能因為版本問題導緻資料集的預處理容易出bug,是以打算改成.mat格式資料上傳到我的部落格資源,友善下載下傳和練習。原部落格位址如下:
https://blog.csdn.net/longlongsvip/article/details/105466512
環境
Matlab: 2020b
GPU:NVIDIA Quadro P620
(注:Matlab2020b好像不支援NVIDIA安培架構顯示卡即不支援30系列,用3090在matlab2020b上測試過,報錯找不到GPU)
一、MNIST手寫體數字資料
MNIST手寫體資料包含60000個訓練樣本(數字0-9),以及測試集資料10000個(數字0-9),這裡不再詳細叙述資料集背景,上文部落格寫得很詳細。 我已經将資料集轉換為.mat檔案格式(省去上文部落格中的複雜預處理步驟),其資料格式如下:

由上圖可以看出,圖檔是以一維的形式存儲的,其資料次元為1 x 784,即原28 x 28 次元的圖檔壓縮成了一維,是以在使用的時候需要将圖檔恢複為二維形式(代碼下面給出)。
二、用到的深度學習架構-LeNet5
2-0 LeNet5的網絡架構
2-1 架構實作-通過Matlab GUI 拖拽界面
打開matlab APP 的Deep Network Designer
打開後如下圖所示:(可以選擇好預訓練的網絡,也可以建立空白網絡)
點選空白網絡,根據LetNet5[1]的網絡結構搭建網絡(拖拽搭建)
搭建完成後點選分析,沒問題後就可以導出(導出-生成代碼)網絡了
2-2 架構實作2-直接寫架構代碼
很明顯,以上步驟是非必要的,老手可以直接寫層代碼來實作…
layers = [
imageInputLayer([28 28 1],"Name","imageinput")
convolution2dLayer([5 5],6,"Name","conv1","Padding","same")
tanhLayer("Name","tanh1")
maxPooling2dLayer([2 2],"Name","maxpool1","Stride",[2 2])
convolution2dLayer([5 5],16,"Name","conv2")
tanhLayer("Name","tanh2")
maxPooling2dLayer([2 2],"Name","maxpool","Stride",[2 2])
fullyConnectedLayer(120,"Name","fc1")
fullyConnectedLayer(84,"Name","fc2")
fullyConnectedLayer(10,"Name","fc")
softmaxLayer("Name","softmax")
classificationLayer("Name","classoutput")];
三、代碼
3-0 機器學習與深度學習對比
在進行實作深度網絡前,可以先用傳統機器學習的方法進行對比,有助于更好了解深度學習網絡架構的優越性。
3-1 SVM分類手寫體數字
SVM作為機器學習的老大哥,在小樣本,小分類數的情況下一直表現優異,但資料量龐大和分類數量比較多的情況下不一定合适。SVM在本例的評價如下:
運作時間:1星 (不管是訓練還是測試都非常慢)
準确率: 1星
用到的SVM分類器為libsvm工具箱,其調用代碼如下:
load handwriting.mat %載入資料集
model=svmtrain(y_train,x_train,'-c 2 -g 0.10'); %訓練
[predicted_label]=svmpredict(y_test,x_test,model); %測試
3-2 ANN分類手寫體數字
相對于SVM,ANN人工神經網絡更适合于處理資料量龐大的情況,但是相對與本例的LetNet-5而言,ANN忽略了輸入圖檔的空間資訊,即輸入的資料是一維訓練資料。設計的ANN網絡結構如下:
這裡我用了3層隐藏層的ANN網絡,其中第一層有100個神經元,第二層60個神經元,第三層40個神經元,第四層10個神經元。ANN在本例的表現評價如下:
運作時間:2星
準确率: 3星(Accuracy:95%)
ANN的實作用matlab自帶的ANN工具箱,其調用代碼如下:
load handwriting.mat %載入手寫體數字資料集
for i=1:size(y_train)
if y_train(i)==0
y_train(i)=10; %這裡把數字0标簽換成10,不然出bug
end
end
for j=1:size(y_test)
if y_test(j)==0
y_test(j)=10; %這裡把數字0标簽換成10,不然出bug
end
end
class=y_train;
[input,minI,maxI]=premnmx(x_train');
s = length( class) ;
output = zeros( s , 2 ) ;%構造輸出矩陣
for i = 1 : s
output( i , class( i ) ) = 1 ;
end
%% 網絡參數
net = newff( minmax(input) , [100 60 40 10] , { 'logsig' 'logsig' 'logsig' 'purelin' } , 'traingdx' ) ; %建立神經網絡
%激活函數有'tansig' 'logsig'以及'purelin'三種
net.trainparam.show = 50 ; %顯示中間結果的周期
net.trainparam.epochs = 7000 ; %最大疊代次數(學習次數)
net.trainparam.goal = 0.01 ; %神經網絡訓練的目标誤差
net.trainParam.lr = 0.001 ; %學習速率(Learning rate)
%% 開始訓練
net = train( net, input , output' ) ; %其中input為訓練集的輸入信号,對應output為訓練集的輸出結果
%% GPU訓練
% gpudev=gpuDevice;%事先聲明gpudev變量為gpu裝置類
% gpudev.AvailableMemory;%實時獲得目前gpu的可用記憶體
% input=single(input);%将double型的P轉為single型
% output=single(output);%将double型的T轉為single型
% net = train( net, input , output' , 'useGPU','only' ) ; %GPU
%% 測試
tic
testInput=tramnmx(x_test',minI,maxI);
Y=sim(net,testInput);
[s1 , s2] = size( Y ) ; %統計識别正确率
hitNum = 0 ;
predictChar=[]; %輸出結果
for i = 1 : s2
[m , Index] = max( Y( : , i ) ) ;
predictChar=[predictChar;Index];
if( Index == y_test(i) )
hitNum = hitNum + 1 ;
end
end
sprintf('識别率是 %3.3f%%',100 * hitNum / s2 )
toc
3-3 深度學習LetNet5
通過第二節獲得層參數layers後,就可以直接将該參數用于深度學習訓練,當然訓練前需要進行資料格式的轉換,把一維資料轉換為二維圖檔資料。LetNet5在本例的評價如下:
運作時間:3星(GPU訓練)
準确率: 4星
代碼如下:
Datapre.m(一維資料轉換為二維)
load handwriting.mat
% 将一維資料轉為二維圖像資料
%% 訓練集
X=x_train;
X = permute(X,[2 1]); %交換資料次元
X = X./255; %歸一化
X=reshape(X,[28,28,1,size(X,2)]);
X = dlarray(X, 'SSCB');
Y=categorical(y_train);
%% 測試集
X2=x_test;
X2 = permute(X2,[2 1]); %交換資料次元
X2 = X2./255; %歸一化
X2=reshape(X2,[28,28,1,size(X2,2)]);
X2 = dlarray(X2, 'SSCB');
Y2=categorical(y_test);
%% 儲存資料
save XY.mat X Y X2 Y2
CNNTrain.m(網絡訓練)
load XY.mat
XTrain=X; %訓練集
YTrain=Y; %訓練集标簽
XTest=X2; %測試集
Ytest=Y2; %測試集标簽
layers = [
imageInputLayer([28 28 1],"Name","imageinput")
convolution2dLayer([5 5],6,"Name","conv1","Padding","same")
tanhLayer("Name","tanh1")
maxPooling2dLayer([2 2],"Name","maxpool1","Stride",[2 2])
convolution2dLayer([5 5],16,"Name","conv2")
tanhLayer("Name","tanh2")
maxPooling2dLayer([2 2],"Name","maxpool","Stride",[2 2])
fullyConnectedLayer(120,"Name","fc1")
fullyConnectedLayer(84,"Name","fc2")
fullyConnectedLayer(10,"Name","fc")
softmaxLayer("Name","softmax")
classificationLayer("Name","classoutput")];
options = trainingOptions('sgdm', ... %優化器
'LearnRateSchedule','piecewise', ... %學習率
'LearnRateDropFactor',0.2, ...
'LearnRateDropPeriod',5, ...
'MaxEpochs',20, ... %最大學習整個資料集的次數
'MiniBatchSize',128, ... %每次學習樣本數
'Plots','training-progress'); %畫出整個訓練過程
%訓練網絡
trainNet = trainNetwork(XTrain, YTrain,layers,options);
save Minist_LeNet5 trainNet %訓練完後儲存模型
yTest = classify(trainNet, XTest); %測試訓練後的模型
accuracy = sum(yTest == Ytest)/numel(yTest); %模型在測試集的準确率
disp(accuracy) %列印測試集準确率
CNNTest.m(通過JPG圖檔進行測試)
load('Minist_LeNet5'); %導入訓練好的LeNet5網絡
test_image = imread('1.jpg'); %導入手寫體數字圖檔
shape = size(test_image);
dimension=numel(shape);
if dimension > 2
test_image = rgb2gray(test_image); %灰階化
end
test_image = imresize(test_image, [28,28]); %保證輸入為28*28
test_image = imcomplement(test_image); %反轉,使得輸入網絡時一定要保證圖檔 背景是黑色,數字部分是白色
test_image=double(test_image);
test_image=test_image'; %旋轉
test_image=test_image./255; %歸一化
result = classify(trainNet, test_image); %利用LetNet5分類
disp(result);
測試
測試用的是自己用windows畫圖工具畫的10個數字,如下:
CNNTest.m運作結果:
最後
手寫體數字識别.mat資料集已經上傳到我的部落格資源,到我的部落格資源就可以下載下傳了。
MNIST手寫體數字資料集官網
http://yann.lecun.com/exdb/mnist/
參考文獻
[1] Lecun Y , Bottou L . Gradient-based learning applied to document recognition[J]. Proceedings of the IEEE, 1998, 86(11):2278-2324.