MATCONVNET進行FCN語義分割
CN語義分割演算法已經在很多主流深度學習平臺上實現了,包括Caffe、TenserFlow、MatConvNet等。這篇部落格主要介紹如何在MatConvNet上執行起FCN語義分割,包括CPU和GPU版本。博主的平臺是Matlab2017a+Cuda8.0。
下載中心
- FCN-Paper論文:下載地址 [可選]
- MatConvNet:下載地址
- FCN-MatConvNet:下載地址
- VOC2011訓練資料:下載地址[voc10],下載地址[voc11],下載地址[voc12]
- VOC12語義分割Benchmark:下載地址
- MatConvNet-VGG預訓練模型:下載地址
- MatConvNet-FCN預訓練模型:
- Caffe FCN預訓練模型:下載地址 [可選]
- CUDA加速,cuDNN執行庫:下載地址 [可選]
配置步驟
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時注意下面的路徑設定,配置好之後直接執行下面的指令碼就可以了。
1234567891011121314 | clearaddpath('utils','models','matconvnet/matlab');globalenableGpu;enableGpu=true;vl_setupnn();if1% recompile when change patform |
如果是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
1 | lb=imread(sprintf(imdb.paths.classSegmentation,imdb.images.name{train(i)})); |
經過除錯,下面這個地方,看出問題來了吧,這裡把’\’替換成’\\’ 或者 ‘/’ 就可以了,否則檔案是讀不出來的
解決:將Line9處的程式碼替換為:
1 | lb=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, 替換成如下程式碼:
1 | labelsPath=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視訊記憶體