1. 程式人生 > >MATCONVNET進行FCN語義分割

MATCONVNET進行FCN語義分割

CN語義分割演算法已經在很多主流深度學習平臺上實現了,包括Caffe、TenserFlow、MatConvNet等。這篇部落格主要介紹如何在MatConvNet上執行起FCN語義分割,包括CPU和GPU版本。博主的平臺是Matlab2017a+Cuda8.0。

下載中心

配置步驟

1.下載程式碼

這裡需要下載兩份程式碼,一個是FCN的程式碼,另一個是MatConvNet程式碼,將MatConvNet中的程式碼放入根目錄下,將資料夾名重新命名為matconvnet。

2. 配置MatConvNet

2.1 使用CPU

使用CPU的話直接編譯就可以了,不需要進行額外配置。(至少博主目前使用的v1.0-beta23是這樣,如果你使用的版本不同最好參照官網說明)。具體編譯過程參見2.3的程式碼

2.2 使用GPU,CUDA加速

需要有支援cuda的顯示卡,在英偉達官網下載cudnn庫,將檔案放入local資料夾下。

同時,在編譯MatConvNet過程中,需要指定該資料夾,參見下面的編譯程式碼。

2.3 編譯MatConvNet

下面的指令碼是博主寫的,原先程式碼裡面沒用,使用enableGpu變數來控制是否編譯GPU版本,每次切換平臺都需要重新編譯,所以有個if 1控制是否重新編譯。使用GPU時注意下面的路徑設定,配置好之後直接執行下面的指令碼就可以了。

1234567891011121314clearaddpath('utils','models','matconvnet/matlab');globalenableGpu;enableGpu=true;vl_setupnn();if1% recompile when change patform
ifenableGpuvl_compilenn('enableGpu',true,'enableCudnn',true,'enableDouble',false,...'cudnnRoot','matconvnet/local/cudnn');elsevl_compilenn();endend

如果是cuda7.5及以下,直接使用官方版本的MatConvNet就可以了,博主使用cuda8.0,在使用的時候做了些修改,具體改了哪些博主也忘記了(當時跑一個跟蹤demo,改的時候也沒注意,反正就是名字啊,目錄啊什麼的,自己debug完全可以解決),後面會釋出博主修改後的matconvnet。

如果出現編譯錯誤,那麼就需要自己定位錯誤,自己debug了,可能出現問題的原因主要有:編譯環境配置(編譯器,路徑,cuda版本等),程式碼版本問題(目前博主沒遇到過,因為MatConvNet在歷史上有幾次大變動,模型資料格式都變了,所以版本對應是可能導致問題的原因之一)等等0.0

3.下載資料

3.0 VGG-VD-16預訓練模型

這裡要知道,FCN是會呼叫VGG模型的,所以要下載 imagenet-vgg-verydeep-16.mat 模型檔案,並方法./data/models/資料夾下。

3.1 訓練資料

在下載中心下載資料,放入./data/archives資料夾下,並根據程式碼中的設定重新命名:

根據選擇版本的voc資料庫 重新命名為 VOC2010trainval.tar/ VOC2011trainval.tar /VOC2012trainval.tar

benchmark.targz 重新命名為 berkeleyVoc12Segments.tar.gz

這裡也可以選擇直接執行fcnTrain,Matlab會自己下載,只是擔心官網下載速度慢,發現使用迅雷下載速度會更快,於是建議自己下載兩個資料壓縮包,然後重新命名,放入對應資料夾下,執行指令碼時會自動檢查資料並解壓到對應目錄。

3.2 預訓練模型

如果你不想訓練自己的模型,直接使用預訓練好的模型(這也是MatConvNet最方便的一點),那麼直接下載預訓練好的模型放到./data/models/目錄下即可。

4.除錯訓練

這一步也是最麻煩的,因為每個人遇到的問題都可能不同,所以多半時候需要自己debug,這裡只提供一些個人經驗了,如果有補充可以在評論區進行回覆,博主可以進一步完善。

4.1 執行除錯

直接執行fcnTrain()函式,這是注意其中設定的路徑是否與自己設定的路徑對應,第一步就是其中的VOCSetup的兩個函式,其中會對資料進行解壓縮處理,保證配置正確,才能定位到資料。如果提示找不到資料,那麼打斷點除錯,看看缺了哪些資料,這些資料是否可以不要。

博主使用Matlab2017a,Cuda8.0,cudnn,硬體平臺是gtx1070,後面的問題和解決僅供參考,博主在除錯過程中分別遇到如下問題:

問題1:getDatasetStatistics: computing segmentation stats for training image 1 報錯

錯誤定位到:getDatasetStatistics.m 檔案 Line 9

1lb=imread(sprintf(imdb.paths.classSegmentation,imdb.images.name{train(i)}));

經過除錯,下面這個地方,看出問題來了吧,這裡把’\’替換成’\\’ 或者 ‘/’ 就可以了,否則檔案是讀不出來的

解決:將Line9處的程式碼替換為:

1lb=imread(sprintf(strrep(imdb.paths.classSegmentation,'\', '\\'),imdb.images.name{train(i)}));

問題2:fcnTrain(line95) 錯誤程式碼 Reference to non-existent field ‘gpus’.

錯誤資訊:

Error in fcnTrain (line 95)
bopts.useGpu = numel(opts.train.gpus) > 0 ;

錯誤資訊是所,opts.train沒有gpus欄位,那麼就要從opts.train查起了,經過除錯發現整個opts.train都是空的,檢查了下發現可能是需要在輸入引數中進行設定?然後再github上直接找到了答案

解決:trainOpts 替換為opts.train 並將Line23 修改為 opts.train = [];

問題3:和問題1一樣,字串的問題,如下圖

解決:定位錯誤到getbatch.m Line51, 替換成如下程式碼:

1labelsPath=sprintf(strrep(imdb.paths.classSegmentation,'\', '\\'),imdb.images.name{images(i)});

版本在不斷更新,並且希望將自己的經驗彙總貢獻一篇教程,或者遇到了其它問題,可以在下方留言給博主。

開心的訓練吧:

CPU:

直接成功

GPU:

需要再進行debug

1. 雖然編譯了gpu版本的matconvnet,但是 opts.train.gpus 依然為空,最後使用的還是CPU,於是就到github去查了一下,迅速找到答案:opts.train.gpus = [1] ;

2. 然後又爆出錯誤:The CUDA error code was: CUDA_ERROR_ILLEGAL_ADDRESS. 繼續Google,地址問題,輕鬆解決。

*18年2月8日補充:關於CUDA_ERROR_ILLEGAL_ADDRESS:

博主曾經採用CUDA8.0、VS2013和matconvnet-1.o-beta23測試成功(具體解決方法事後想不起來,太久遠了,似乎是折騰了許久cudnn版本)

一旦牽扯到環境,問題通常都比較復(玄)雜(學),下面的引用是評論區馬同學對各個環境進行的測試,最終使用GTX1070+win10調通fcn:

GTX 1070顯示卡 + windows10

一開始使用matconvnet-1.0-beta25.tar.gz + matlab2017b + CUDA8.0 會出現The CUDA error code was: CUDA_ERROR_ILLEGAL_ADDRESS的情況,
(1)在使用 CUDA8.0 時無論搭配哪種版本的 cudnn都無法解決這種問題,所以將CUDA8.0降為CUDA7.5,但是又會出現 Unsupported gpu architecture ‘compute_61’的情況,根據
http://blog.csdn.net/a1154761720/article/details/53395414 中的解決方法解決了。
(2)matconvnet-1.0-beta25.tar.gz編譯GPU時只能用vs2015,vs2013不能使用,CUDA7.5編譯又只能用vs2013.所以不能最新的matconvnet。
(3)CUDA8.0對應matlab2017,降低CUDA的版本,也就降低了matlab的版本,降為matlab2015
(4)最後的配置為
CUDA7.5 + matlab2015 + vs2013,可以直接下載別人編譯好的檔案
部落格地址為 http://blog.csdn.net/zhjm07054115/article/details/51569450
視訊以及程式碼的地址為 http://www.studyai.com/course/detail/64bf671f1ecf44ed9a8404a198604321

再次感謝馬同學的測試和分享!

GTX1070超頻到1860MHz之後,大約訓練6個小時就可以出結果了,還是相當給力的。(博主訓練一般就停了,6小時是根據同學訓練的時間預估的)

4.2 預訓練除錯

上面搞定,這個就簡單多了,使用預訓練模型的方式有三種,根據fcnTest中的 switch case 發現三種分別是matconvnet、ModelZoo、TVG。

‘matconvnet’就是使用自己訓練儲存好的網路模型,以‘input’為起點

‘ModelZoo’就是使用Caffe的模型,這裡我們發現目錄中還有一個檔案fcnTestModelZoo,如果使用matcaffe,那麼可以從這個指令碼開始。

‘TVG’是什麼呢?我不清楚,它以’coarse’層結尾,而下載的模型是以upscore結尾的。

所以我們經過簡單除錯,發現需要修改的地方只有五個:

1. 修改modelPath為我們下載的模型檔案

2. 修改modelFamily為 ‘TVG’

3. 修改‘TVG’結尾為‘upscore’(原先是‘coarse’),發現我們下載的模型並沒有‘coarse’

4. 和訓練時候一樣的字串文字,修改Line114為: labelsPath = sprintf(strrep(imdb.paths.classSegmentation, ‘\’, ‘\\’), name) ;

5. 如果使用gpu,單個GPU情況下,修改opts.gpus = [1]

123456789101112131415161718192021%experimentanddatapathsopts.expDir='data/fcn32s-voc11';opts.dataDir='data/voc11';%opts.modelPath='data/fcn32-voc11/net-epoch-50.mat';opts.modelPath='data/models/pascal-fcn32s-dag.mat';// Line 9opts.modelFamily='TVG';[opts,varargin]=vl_argparse(opts,varargin);........case'TVG'// Line 88net=dagnn.DagNN.loadobj(load(opts.modelPath));net.mode='test';%predVar=net.getVarIndex('coarse');predVar=net.getVarIndex('upscore');inputVar='data';imageNeedsToBeMultiple=false;end

結果儲存在結果路徑下面,重新執行如果不刪除原先的結果檔案,那麼會直接顯示結果而不會再訓練,所以要刪掉原先檔案再訓練。

如果要測試自己的資料,那麼直接im = imread(…) 的地方修改就可以了,總之調通之後,自己看程式碼吧

測試

開心的執行demo吧

雖然訓練時間很長,檢測速度還是挺快的,檢測時候大概需要3G視訊記憶體