FCN網絡的訓練——以SIFT-Flow 數據集為例


參考文章: http://blog.csdn.net/u013059662/article/details/52770198 

caffe的安裝配置,以及fcn的使用在我前邊的文章當中都已經提及到了,這邊不會再細講。在下邊的內容當中,我們來看看如何使用別人提供的數據集來訓練自己的模型!在這篇文章之后,我計划還要再寫如何fine-tune和制作自己的數據集,以及用自己的數據集fine-tune。

(一)數據准備(以SIFT-Flow 數據集為例)

下載數據集:  http://pan.baidu.com/s/1dFxaAtj   ,並解壓至/fcn.berkeleyvision.org/data/下,並將文件夾名重命名為sift-flow這里一定要注意,/fcn.berkeleyvision.org/data/下本來就有一個文件夾叫sift-flow,千萬不要覆蓋。同時,這些原本就存在的文件夾里的東西還要全部復制到新解壓的sift-flow文件夾下邊。你可以先把原本的sift-slow重新命名為sitf-flow_1,然后再解壓復制!

(二) 下載預訓練模型

下載VGG-16的預訓練模型放至/fcn.berkeleyvision.org/ilsvrc-nets/目錄下,並重命名為vgg16-fcn.caffemodel

下載地址: http://pan.baidu.com/s/1gfeF4wN 

(三)源碼修改

1. prototxt文件修改

進入siftflow-fcn32s文件夾下,將test.prototxttrainval.prototxt中的fc6fc7分別替換為其他名稱,例如:fc6_newfc7_new

原因是我們下載的預訓練模型VGG-16原模型中包含有fc6和fc7這兩個全連接層,而在prototxt中,使我們新添加的卷積層,在模型加載時,如果名稱一樣,而結構數據不同,便會報錯。如果改名之后,原來的fc6/7則會被忽略,而使用我們新的層。

2. caffe path的加入

由於FCN代碼和caffe代碼是獨立的文件夾,因此,須將caffe的Python接口加入到path中去。這里有兩種方案,一種是在所有代碼中出現import caffe 之前,加入:

1 import sys
2 sys.path.append('caffe根目錄/python')

另一種一勞永逸的方法是:在終端或者bashrc中將接口加入到PYTHONPATH中:

export PYTHONPATH=caffe根目錄/python:$PYTHONPATH

(四)訓練

1 $ cd cd siftflow-fcn32s/
2 $ python solve.py

這里會遇見幾個問題:

(1)No module named surgery,score

原因是下載的fcn源碼解壓根目錄下有兩個文件:surgery.py和score.py。這兩個文件是下載下來就自帶的,並不是caffe自帶的,也不是前邊我安裝caffe時需要配置的。由於我是在/fcn根目錄/siftflow-fcn32s/這個文件夾下執行的,會導致找不到這兩個文件。所以,解決方案就是:

 cp surgery.py score.py ./siftflow-fcn32s/

將surgery.py和score.py拷貝到siftflow-fcn32s下。


(2)ImportError: No module named setproctitle

解決方案是:安裝setproctitle! sudo pip install setproctitle 

(3)IndexError: list index out of range

解決方案:修改GPU編號為0號GPU

(4)No modulw named siftflow_layers

解決方案:瘋了,干錯把根目錄下邊的所有.py文件全拷貝到siftflow-fcn32s里邊去吧。

好了,現在可以開始訓練了!看看訓練過程:

由於損失loss很大,我也不知道什么時候能收斂,所以先放一放,等跑出結果來我再過來更新!

-------------------------------------------------------------2017.1.12更新----------------------------------------------------------------------

經過半個月的折騰和討論,現在可以確定原先的參考文章是有問題的,這個網絡沒有辦法收斂。下面更正幾條:

1. 一般情況下不要直接修改test.prototxt和trainval.prototxt,而是執行net.py這個腳本,執行完成后也不要test.prototxttrainval.prototxt中的fc6fc7替換為其他名稱.

2. 這是重點,沒有收斂的根源在這里!修改solve.py:

 1 import sys
 2 import caffe
 3 import surgery, score
 4 
 5 import numpy as np
 6 import os
 7 
 8 import setproctitle
 9 setproctitle.setproctitle(os.path.basename(os.getcwd()))
10 
11 vgg_weights = '../ilsvrc-nets/vgg16-fcn.caffemodel'
12 vgg_proto = '../ilsvrc-nets/VGG_ILSVRC_16_layers_deploy.prototxt'
13 # init
14 #caffe.set_device(int(sys.argv[1]))
15 caffe.set_device(0)
16 caffe.set_mode_gpu()
17 
18 #solver = caffe.SGDSolver('solver.prototxt')
19 #solver.net.copy_from(weights)
20 solver = caffe.SGDSolver('solver.prototxt')
21 vgg_net = caffe.Net(vgg_proto, vgg_weights, caffe.TRAIN)
22 surgery.transplant(solver.net, vgg_net)
23 del vgg_net
24 
25 # surgeries
26 interp_layers = [k for k in solver.net.params.keys() if 'up' in k]
27 surgery.interp(solver.net, interp_layers)
28 
29 # scoring
30 test = np.loadtxt('../data/sift-flow/test.txt', dtype=str)
31 
32 for _ in range(50):
33     solver.step(2000)
34     # N.B. metrics on the semantic labels are off b.c. of missing classes;
35     # score manually from the histogram instead for proper evaluation
36     score.seg_tests(solver, False, test, layer='score_sem', gt='sem')
37     score.seg_tests(solver, False, test, layer='score_geo', gt='geo')

可以對比一下之前的solve.py,發現區別在這:

紅色框出來的是原先的內容,被我注釋掉了,換成了下面四行!為什么要這樣做呢?我們來看看這個transplant函數的定義吧:

所以,原先的方法僅僅是從vgg-16模型中拷貝參數,但是並沒有改造原先的網絡,這才是不收斂的根源啊!

3.修改solver.prototxt:

 1 train_net: "trainval.prototxt"
 2 test_net: "test.prototxt"
 3 test_iter: 200
 4 # make test net, but don't invoke it from the solver itself
 5 test_interval: 999999999
 6 display: 20
 7 average_loss: 20
 8 lr_policy: "fixed"
 9 # lr for unnormalized softmax 
10 base_lr: 1e-10
11 # high momentum
12 momentum: 0.99
13 # no gradient accumulation
14 iter_size: 1
15 max_iter: 300000
16 weight_decay: 0.0005
17 snapshot:4000
18 snapshot_prefix:"snapshot/train"
19 test_initialization: false

這里我們增加了 snapshot:4000 snapshot_prefix:"snapshot/train" ,每4000次我們會在當前目錄下的snapshot下保存一下模型(需要提前建立snapshot目錄)。
4. 有的人可能會出現out of memory錯誤。這里有兩種判斷:(1)根本沒法迭代,那么你就要把batchsize設置小一點了。默認是 iter_size: 1 (solver.prototxt),另外在siftflow_layers.py中 top[0].reshape(1, *self.data.shape) 這里默認也是1,batchsize = iter_size* 1。如果已經是最小了,即這兩個地方都是1了,如果你還是out of memory,那么要么更換好的硬件(GPU),要么resize 數據集到更小的尺寸。(2)如果先提示“Begin seg tests”,然后out of memory,那么是在執行score.py時內存溢出了,這時還是上面的兩種解決方案。

好了,上面是我這段時間研究后的補充,感謝小伙伴@踏雪霏鴻 ,最初是他發現了這里的錯誤,最終幫助大家解決了問題。下面我們就可以重新開始訓練模型了!

1 python solve.py

這一次收斂速度會非常快,而且loss會降到很可觀的數字。

這里我沒有一直跑下去,因為我准備用voc數據集,所以跑了一會就去跑voc數據集了。但是,這次是有小伙伴做過測試的,效果可以,所以基本上siftflow32s的訓練步驟就是這些了!需要訓練siftflow-fcn32s的朋友可以按這個走,然后用訓練得到的32s的模型去訓練16s的模型,最后用16s的模型去訓練8s的。

5. 最后,由於從32s->16s和16s->8s不需要重新構造卷積層,所以上面第二點提到的注釋和替換的那部分就不需要了,直接用solver.net.copy_from(weights)就可以了!

其二,deploy.prototxt的第一層(input層),維度要和輸入圖片大小對應,如下圖:

因為siftflow數據集是256*256的,要一一對應。如果發現要訓練的模型下沒有deploy.prototxt這個文件,可以從test.prototxt或者trainval.prototxt復制,然后刪除最后一層loss層:

再添加一層輸入層,這個輸入層可以從voc-fcn8s這個文件夾里的deploy.protottx里邊復制,內容如下(注意根據輸入圖片的尺寸修改):

其三,很多人要用自己的數據集訓練fcn,那怎么做呢?

是這樣的,我們可以先用fcn32s的模型(已經訓練好的)和自己的數據集再訓練一遍得到新的fcn32s,這其實有專業術語——fine-tune.

然后用上面訓練好的fcn32s和自己的數據集,訓練出fcn16s。最后,再用上一步的fcn16s和自己的數據集訓練出fcn8s。

-------------------------------------------------------結束語--------------------------------------------------------------------------

雖然這樣一篇博客看上去好像也沒有多少東西,但是卻凝結了我和很多人長時間努力的汗水,晝夜奮戰搞出來的。我相信,在看過我這篇文章之前,應該是沒有多少中文資料的,要么只言片語,要么誤導性的。后面也許會有一些博客陸續出來,那基本上也是的小伙伴們寫的,但是基本上比較簡單,言簡意賅,不會像我這么細致寫出來。

為什么要做這樣一件工作呢?辛苦搞出來的東西,就這樣送人了,而且還要再花時間寫這么長的博文,打這么多的字。我希望后來人能少走一些彎路,不像我這么痛苦;同時,我希望看過我博客的人也能秉承奉獻的精神,把自己的工作公開出來,避免別人少走彎路,這既是對自己工作的總結和梳理,也是對后來人的極大幫助!搞學術不能閉門造車,希望我等共勉!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM