Matlab实现CNN(二)
1.前言
最近需要用到卷積神經網絡(CNN),在還沒完全掌握cuda+caffe+TensorFlow+python這一套傳統的深度學習的流程的時候,想到了matlab,自己查了一下documentation,還真的有深度學習的相關函數。所以給自己提個醒,在需要用到某個成熟的技術時先查一下matlab的幫助文檔,這樣會減少很多時間成本。記得機器學習的大牛Andrew NG.說過在硅谷好多人都是先用matlab/octava先實現自己的想法,再轉化成其他語言。
2.配置需求
要像用matlab實現deep learning,需要更新到2017a版本。GPU加速的話,需要安裝cuda8.0, 自己GPU 的compute capacity 要3.0 以上。
3. 可以完成的任務
我們看一下matlab的新加的深度學習功能可以完成哪些任務
1. 獲取別人訓練好的CNN網絡 2. 遷移學習(transfer learning and fine-tune) 3. 解決分類問題(classifiy problem) 4. 解決回歸問題(regression problem) 5. 物體檢測(object detection) 6. 提取學習到的特征3.1 獲取別人訓練好的網絡
matlab2017中,可以用別人訓練好的現成的網絡,也可以輸入caffe中的網絡。目前已知的可以用的網絡包括用于分類的:Alexnet, vgg16, vgg19。已經用于物體檢測的,RCNN, FastRCNN, Faster RCNN。由于最近一直研究的是分類和回歸問題,物體檢測的CNN在過后補全。這里只舉一個分類的例子。?
Alexnet作為2012年ImageNet的冠軍,它的提出確實影響到了CV的研究熱點,人們驚奇的發現深度網絡的描述能力居然這么強,雖然背后的數學原理一直沒能得到完美的解決,但不妨礙它強大的能力,我們看看她在matlab中是如何做分類的。首先貼出代碼:
用matlab自帶的照片測試一下分類的準確率,得到的結果如下?
bell pepper是甜椒的意思,我們發現效果還是不錯的,感興趣的同學可以多找幾張測試圖片試一下。用 net.Layers
命令可以看Alnexnet的網絡結構,得到以下?
這是一個25層的網絡,每一層都對應著詳細的說明。值得關注的是有5個卷積層(convolution layer)和三個全連接層(full connection layer)。其他的vgg16和vgg19是相同的道理,不過要看清楚網絡的輸入,使用vgg19時,需要改變上邊代碼中的兩行 net = vgg19; cropedim=imresize(cropedim,[224 224]);
剩下的部分是一樣的。當然也可以從caffe中導入自己訓練好的網絡,自己還沒有完全掌握caffe,熟悉這部分的同學可以自己實現一下。
3.2 遷移學習(transfer learning and fine-tune)
所謂遷移學習(transfer learning)就是微調(fine-tune)別人訓練好的網絡中的某些參數,使得它更適合自己的數據集。遷移學習使用的情況是:幾百到幾千個訓練樣本,想快速訓練網絡。網絡的訓練過程就是剛開始為各個參數賦予隨機的值,采用數值的方法(一般是梯度下降法)求讓cost function?達到最小值的各個參數的取值,這些參數主要產生于各個層之間連接時候的權值。Cost function是標定好的數據與通過網絡計算出的數據的差的累加。Cost function越小說明網絡的性能越好。我們看看matlab中是如何用現有的網絡做遷移學習的,我們舉一個手寫體識別的例子,其中matlab自己提供了訓練集和測試集。先貼出代碼:
%% transfer learning %讀取訓練集和測試集 digitDatasetPath = fullfile(matlabroot,'toolbox','nnet','nndemos', ...'nndatasets','DigitDataset'); digitData = imageDatastore(digitDatasetPath, ...'IncludeSubfolders',true,'LabelSource','foldernames'); [trainDigitData,testDigitData] = splitEachLabel(digitData,0.5,'randomize'); %顯示前20個訓練照片 numImages = numel(trainDigitData.Files); idx = randperm(numImages,20); for i = 1:20subplot(4,5,i)I = readimage(trainDigitData, idx(i));imshow(I) end % 獲取matlab自己訓練好的網絡 load(fullfile(matlabroot,'examples','nnet','LettersClassificationNet.mat')) % 改變輸出層的類別個數 layersTransfer = net.Layers(1:end-3); % 顯示新的類別個數 numClasses = numel(categories(trainDigitData.Labels)); % 把最后三層替換成新的類別 layers = [...layersTransferfullyConnectedLayer(numClasses,'WeightLearnRateFactor',20,'BiasLearnRateFactor',20)softmaxLayerclassificationLayer]; optionsTransfer = trainingOptions('sgdm',...'MaxEpochs',5,...'InitialLearnRate',0.0001,...'ExecutionEnvironment','cpu'); % 訓練網絡 netTransfer = trainNetwork(trainDigitData,layers,optionsTransfer); % 顯示測試準確率 YPred = classify(netTransfer,testDigitData); YTest = testDigitData.Labels; accuracy = sum(YPred==YTest)/numel(YTest); % 顯示測試結果 idx = 501:500:5000; figure for i = 1:numel(idx)subplot(3,3,i)I = readimage(testDigitData, idx(i));label = char(YTest(idx(i)));imshow(I)title(label) end代碼的前邊的部分是讀取matlab中自帶的數據集和測試集,把它保存成imageDatastore格式,這種格式只需要提供圖片的路徑信息而不用把圖片全部讀入內存中,因此非常適合大規模的數據集。中間部分是修改訓練好的網絡中的最后三層,原網絡用來識別手寫的字母和數字有36類,而現在的任務只需要識別手寫體數字,所以把它們改成10類,在訓練時使用0.0001的學習率,共計算5輪,用cpu做訓練。代碼的最后部分是測試新訓練好的網絡,因為transfer learn是在現有的網絡基礎上做參數的微調,所以訓練速度很快,我們看一下訓練效果。?
由于是在cpu上做的訓練,而且是transfer learning 所以訓練的過程很快,我們發現重新訓練好的網絡能達到很高的準確率。我們再看gpu上的訓練?
由于參數的初始化是隨機的,因此得到的結果也是隨機的,不過可以看出gpu上做訓練明顯要快很多!GPU的第一輪計算慢是因為數據要重新初始化為gpu矩陣。最后放一張效果圖:?
我們發現識別的效果還是不錯的。
3.3 分類問題(classification problem)
CNN之所以能引起廣泛關注,就是在于它最初在圖像分類方面取得很大的成功,后來人們發現對于其他的分類問題,CNN也有很好的性能。上邊講的遷移學習解決的也是一種分類問題,接下來的敘述也就建立在上文的基礎上。?
我們這里要解決的分類問題,就是訓練自己的分類網絡。之前的遷移學習已經說明,所謂訓練就是為每層網絡之間尋找使得cost function最小的權值,這些權值剛開始是按照某種分布隨機初始化的,我們用數值的方法求cost function的最小值。一般來說,我們用神經網絡建立的是一個非常復雜的模型,我們往往能難找到這個模型的最小值,但可以找到它的極小值(局部最小值),這些極小值已經很接近我們要找到最小值。?
要訓練自己的網絡,我們要先建立自己的網絡,并設置一定的訓練參數。我們看一下matlabs是如何完成的。?
在matlab中用來建立網絡的語句如下:
直接用數組建立網絡,這個例子是建立一個9層的分類網絡,包括輸入層,卷積層1,激活函數層1,標準化層,卷積層2,激活函數層2,全連接層,去最大值層,分類層。至于如何選擇適合自己的網絡結構,我目前還沒有搞太清楚,不過,可以現在別人的網絡基礎上做修改。?
用來設定修改參數的語句如下:
這些參數是CNN網絡的基本參數,MaxEpoch是計算的輪數,它的值越大越容易收斂,InitialLearRate是學習率,太大模型可能不會收斂,太小則收斂的太慢。MiniBatchSize是每次處理的數據的個數,ExcutionEnviroment是訓練網絡的環境,可以在CPU(‘cpu’)上做,也可在GPU(‘gpu’)上做,可以并行(‘paralle’),默認的情況是先測試gpu,如果不可用在測試gpu。在matlab上用gpu訓練網絡時需要cuda8.0, 顯卡計算能力為3.0。這些參數可以用指令gpuDevice來查看。OutputFcn是可以在訓練過程中調用的某些函數。比如:它可以用來畫cost function值的變化。如何像可視化訓練表格(上文輸出的那些)某些數據可以調用相應的函數,我在回歸問題時會再說明。?
設定好網絡結構和訓練參數后,可以用
來訓練自己的網絡,訓練數據可以是ImageDatastore類型,可以是4-D數組,四個維度分別是長度,寬度,通道數,第幾個圖片。因為4-D數組是一次性裝入到內存中的,如果數據量太大時慎用,小心內存不足。同樣,我們舉一個完整的例子,也是利用matlab自帶的數據集去分類手寫體。代碼如下:
%讀取數據集并保存成imageDatastore形式 digitDatasetPath = fullfile(matlabroot,'toolbox','nnet','nndemos',...'nndatasets','DigitDataset'); digitData = imageDatastore(digitDatasetPath,...'IncludeSubfolders',true,'LabelSource','foldernames'); %隨機顯示二十個訓練集中的圖片 figure; perm = randperm(10000,20); for i = 1:20subplot(4,5,i);imshow(digitData.Files{perm(i)}); end %把數據集劃分成訓練集和測試集 trainingNumFiles = 750; rng(1) % For reproducibility [trainDigitData,testDigitData] = splitEachLabel(digitData,...trainingNumFiles,'randomize'); %建立自己的網絡 layers = [imageInputLayer([28 28 1]);convolution2dLayer(5,20);reluLayer();maxPooling2dLayer(2,'Stride',2);fullyConnectedLayer(10);softmaxLayer();classificationLayer()]; %設定訓練參數 options = trainingOptions('sgdm','MaxEpochs',20,...'InitialLearnRate',0.0001); %訓練網絡 convnet = trainNetwork(trainDigitData,layers,options); %測試網絡 YTest = classify(convnet,testDigitData); TTest = testDigitData.Labels; accuracy = sum(YTest == TTest)/numel(TTest); disp(accuracy);我自己的訓練結果如下:?
自己是在gpu上做的,所以時間較短,最后得到分類準確率發現還不錯。
3.4 回歸問題(regression problem)
回歸問題與分類問題的處理方式相同,我們仍然需要訓練集和測試集。在網路結構上有些不同,最后一次必須是Regression layer, 而倒數第二次必須是卷積層。回歸問題的網絡中的參數與分類問題是一樣的,這里不再詳細說明,我們直接分析一個例子,看一下matlab是如何做分類的。這個問題同時看一下function參數的作用。這次要解決的問題是,圖片中的字母到底旋轉了多少度。數據集同樣來自matlab代碼如下:
%讀取數據集 [trainImages,~,trainAngles] = digitTrain4DArrayData; %顯示任意二十個結果 numTrainImages = size(trainImages,4);figure idx = randperm(numTrainImages,20); for i = 1:numel(idx)subplot(4,5,i)imshow(trainImages(:,:,:,idx(i)))drawnow end %建立回歸網絡 layers = [ ...imageInputLayer([28 28 1])convolution2dLayer(12,25)reluLayerfullyConnectedLayer(1)regressionLayer]; %設置訓練參數 functions={...@plotTrainingRMSE,...@(info)stopTrainingAtThreshold(info,0)}; options = trainingOptions('sgdm', ...'MaxEpochs',20, ...'InitialLearnRate',1e-3, ...'MiniBatchSize',128,...'ExecutionEnvironment','gpu',...'OutputFcn',functions); %訓練網絡 net = trainNetwork(trainImages,trainAngles,layers,options); %測試網絡 [testImages,~,testAngles] = digitTest4DArrayData; predictedTestAngles = predict(net,testImages); %查看擬合誤差 predictionError = testAngles - predictedTestAngles; thr = 10; numCorrect = sum(abs(predictionError) < thr); numTestImages = size(testImages,4); accuracy = numCorrect/numTestImages; disp('accuracy'); disp(accuracy); squares = predictionError.^2; rmse = sqrt(mean(squares)); disp('the rmse'); disp(rmse); %train function function plotTrainingRMSE(info)persistent plotObjif info.State == "start"figure;plotObj = animatedline;xlabel("Iteration")ylabel("Training RMSE") elseif info.State == "iteration"addpoints(plotObj,info.Iteration,double(info.TrainingRMSE))drawnow limitrate nocallbacks endendfunction stop = stopTrainingAtThreshold(info,thr)stop = false; if info.State ~= "iteration"return endpersistent TrainingRMSE% Append accuracy for this iteration T= info.TrainingRMSE;% Evaluate mean of iteration accuracy and remove oldest entrystop = T <thr;end得到的回歸結果如下:?
我們在訓練過程中調用兩個函數,plotTrainingRMSE是用來畫cost function是如何變化的,(info)stopTrainingAtThreshold(info,0)是設置訓練提前結束的條件的,可以根據表中的某些參數讓訓練在一定條件下停下來。最后,我們看一下cost function 的變換規律,如下:?
目前為止,我們用cnn解決了最基本的分類問題和回歸問題,此外,還介紹了如何建立網絡和設定參數,后邊將補充檢測部分。
3.3 檢測問題(Detection problem)
同樣用matlab自帶數據集做車輛檢測,關于檢測的網絡有RCNN, Fast RCNN, Faster RCNN, 他們大同小異,差距在于速度的快慢,我們只測試Faster RCNN?
1) 讀取數據
data是個結構體類型的數據,主要是用來四個屬性分別是detector, layers, result, vehicleTraining.?
其中,detector, layers, reault是提前訓練好的檢測子,網絡和測試結果,我們用vehicleTraining重新訓練CNN網絡,用layers來設計網絡結構?
2) 抽取用于訓練的圖像
抽取出的trainingData是table格式的,matlab訓練網絡RCNN網絡只能用table格式。
3) 讀取網絡結構
layers=data.layers;該網絡是個11層的網絡,訓練時我們可以設計自己的網絡結構,也可以在這個網絡的基礎上做訓練。
4) 設置訓練選項
options = trainingOptions('sgdm', ...'InitialLearnRate',1e-6,...'MaxEpochs',1,...'ExecutionEnvironment','gpu',...'CheckpointPath',tempdir);這里設置的是初始學習率為 1e-6, 迭代1輪,用GPU做訓練,在訓練時會把checkpoint的結果存下來。
5) 訓練網絡
detector = trainFasterRCNNObjectDetector(trainingData,layers,options);用trainingData做訓練數據,訓練layers網絡,在訓練過程中選擇option中的訓練參數,同樣用了GPU做訓練,其中的一步如下:?
6) 結果檢測
img=imread('highway.png'); [bbox,score,label]=detect(detector,img); detectedImg=insertShape(img,'Rectangle',bbox); figure,imshow(detectedImg);從Matlab自身圖庫中選擇hightway這張照片,用剛才訓練出的網絡監測里邊的車輛,其中bbox是監測出的包圍盒的坐標,這個可以用來返回。?
這結果顯示如下:
總結
以上是生活随笔為你收集整理的Matlab实现CNN(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java描述设计模式(02):简单工厂模
- 下一篇: DirectUI介绍