1. 程式人生 > >如何fine tuning

如何fine tuning

為什麼要fine-tuning?###

我們有自己的影象識別任務,然而我們的資料集太小,直接進行訓練很容易出現過擬合現象
所以比較好的解決方案是先在一個大資料集中訓練以提取比較準確的淺層特徵,然後再針對這個訓練過的網路利用我們的資料集進行訓練,那麼效果就會好很多。這個過程就是fine-tuning。

model zoo###
大家都注意到了這個情況,所以
(1)FeifeiLi帶頭建立imagenet,這個影象庫非常巨大,滿足我們預先訓練的各種要求,另外近期Google釋出Open Images,包含900w labeled images,媲美Imagenet dataset。
(2)有些網路結構非常經典,比如Alexnet,Googlenet,VGGnet,ResNet等等,如果我們想利用這些網路去做自己的應用,就首先要把它們在大資料集(imagenet等等)中訓練,然後再用自己的資料訓練;顯然前面一步是重複的步驟,並且非常耗時耗力(可能花費數臺機器數週時間)。所以針對上述問題各種深度學習庫(caffe、Tensorflow、torch)等等就預先用經典網路訓練在imagenet上訓練,把模型(各個引數)公佈網上,我們直接拿來用即可,省去了大量pre-train的時間。這些模型(引數)就是model zoo

how to fine-tuning###
1.在imagenet訓練最終輸出是1000個分類,所以網路結構大概是經典網路—全連線層(前面)—最後的全連線層(1000輸出)。
2.如果我們要進行fine-tuning
我們設計自己的網路
(1)經典網路—全連線層(前面)—最後的全連線層(我們的類別輸出)
(2)經典網路—全連線層(all new)
(3)經典網路—卷積池化層(new)-全連線層(all new)
上述三種分別對應網路改動從小到大,對應的學習速率會有所區別。
在改動過程中,網路名稱相同的引數會直接搬過來,不同的會根據設定初始化
一定注意改動過程中size要匹配!

作者:陳繼科
連結:

https://www.jianshu.com/p/0bccc60c7819
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。

FineTuning機制的分析

為什麼用FineTuning
使用別人訓練好的網路模型進行訓練,前提是必須和別人用同一個網路,因為引數是根據網路而來的。當然最後一層是可以修改的,因為我們的資料可能並沒有1000類,而只有幾類。把最後一層的輸出類別和層的名稱改一下。用別人的引數、修改後的網路和自己的資料進行訓練,使得引數適應自己的資料,這樣一個過程,通常稱之為微調(fine tuning). 也就是說,我們所擁有的資料很小,不足以訓練一個網路,這是用別人訓練過的引數以及網路訓練我們自己的資料的過程就是微調(fine tuning)。

怎麼FineTunning
Fine tuning 之所以有效的原因是,用到的網路是同一個網路,用到的引數是別人已經訓練好的資料,所以在準確率上會有保證,這時候再稍微調整別人訓練好的引數,往往會能達到我們想要的效果。

調整net檔案
因為我們自己的資料集變化了,所以要修改net網路檔案,大部分的內容都不變,變的只有data層、output層、batch的大小、前幾層的學習率。data層需要改成我們自己的資料,output層的修改主要包括層的名字(使用不同的名字,預訓練網路中該層的引數會重新初始化)和輸出類別數目,並且要減小batch的大小,但是要和GPU的大小成比例。

對於學習率的調整是很重要的,如果有的層的引數不需要更新,可以把學習率設定為0.比如有4個全連線層,希望C層的引數不會改變,C前面的AB層的引數也不會改變,這種情況也就是D層的梯度不往前反向傳播到D層的輸入blob(也就是C層的輸出blob 沒有得到梯度),你可以通過設定D層的學習率為0,layer的梯度就不會反向傳播了,前面的所有layer的引數也就不會改變了。對於有引數的更新的層,學習率可以減小10倍或100倍(最後一層除外),對於最後一層的學習率可以提高10倍,加快學習速率,因為該層需要重新學習。

調整solver檔案
solver.prototxt檔案中的引數一般只需要修改net訓練網路的名稱、學習率、最大迭代次數和snapshot。首先將net從預訓練使用的net換為現在使用的net,然後降低學習率(一般降低10倍或者100倍),同時,將最大迭代次數和snapshot的數目相對減少。

Fine Tuning的原理
Fine tuning的原理就是利用已知的網路結構和已知的網路引數,修改output層為我們自己的層,微調最後一層前的所有層的引數,加大最後一層的學習率,因為最後一層我們需要重新學習,所以與其它層相比要有相對較大的學習率,這樣就有效利用了深度神經網路強大的泛化能力,又免去了設計複雜的模型以及耗時良久的訓練,所以fine tuning是當資料量不足時的一個比較合適的選擇。

fine-tuning的作用

查詢的一些關於fine-tuning的解釋

在網路訓練中,第一層特徵並不特化到任務上,特徵是如何註冊那個從一般到特殊的,詳細參考NIPS2014上Bengio大神的文章:How transferable are features in deep neural networks?

(1)fine tuning的過程其實就是用訓練好的引數(可以從已訓練好的模型中獲得)初始化自己的網路,然後用自己的資料接著訓練,引數的調整方法與from scratch訓練過程一樣(梯度下降)。對於初始化過程,我們可以稱自己的網路為目標網路,訓練好的模型對應網路為源網路,要求目標網路待初始化的層要與源網路的層相同(層的名字、型別以及層的設定引數等等均相同)。

(2)Fine-tuning已經成為了使用DL網路的一個常用技巧(trick)。個人認為在使用深度網路做影象處理任務時,使用一個在大的資料集上預訓練好的模型(ex:caffe在imagenet上訓練的caffeNet, VGG16…)在自己資料上微調往往可以得到比直接用自己資料訓練更好的效果,這是因為在imagenet上預訓練的模型引數從微調一開始就處於一個較好的位置,這樣微調能夠更快的使網路收斂。對於相同類別的任務我們可以預設這樣去做比較好,比如我們可以直接利用caffe在imageNet classification task 預訓練的模型做一些其他的分類任務。然而當我們要做一個不同的任務,比如在imageNet上做Detection,那麼可能直接拿在imagenet分類任務上預訓練的模型進行微調就不是最好的了。分類考慮的是影象的一個語義資訊,無論目標出現在哪裡判定出類別就算正確,而檢測不一樣,還需要知道目標的確切位置,所以對於檢測任務,我們也可以使用微調這個trick,但使用的預訓練網路是在目標級別資料庫上訓練的(影象就是一個完整目標或者影象中所有目標都有標記—Bounding Boxes Infomation)。

(3)一般我們在訓練from scratch的時候往往要在一些超大型的資料集上訓練,一個目的是為了讓訓練得到的特徵(尤其是底層特徵)更加多樣。而從genertive pre-training到discriminative fine-tuning的過程是一個對泛化特徵進行面向task的特化的過程。首先,如果你將底層特徵可視化出來,會發現底層特徵多是一些邊、角之類的基礎幾何形狀,高層特徵可能會發生一些有趣的變化,直接反映出你的task。 在大資料集上進行 pretrain 的目的之一是為了獲得豐富、一般化的底層特徵,換言之就是學到豐富的“基礎幾何形狀”。有了這些豐富的基礎幾何形狀,等過渡到小資料集上 finetune 的時候,就可以通過它們組合出上層具有強判別力的特徵。此時,如果你再將組合出來的上層特徵視覺化,就會發現它們已經有模有樣了,見上面辛博的配圖。反之,如果你直接在小資料集上訓練,那麼就難以獲得豐富的、一般化的基礎幾何形狀,也就難以“描繪出”栩栩如生的上層特徵。底層特徵非常重要,如果底層特徵不夠好,特徵型別不夠充分,很可能訓練不出來好的高層抽象。這就是為什麼需要在大規模資料集上進行genertive training的原因之一。

(3)從我們的實驗經驗上來看,網路越深,底層的引數越難得到有效訓練,這也是為什麼經常有人用 vggNet finetune 的原因之一.
使用 backpropagation 進行訓練的時候殘差逐層傳遞,有可能到底層的時候殘差就很小了(gradient vanishing),導致底層的引數train 不動. 這也是樓上辛同學的圖裡底層 feature map 沒有什麼改變的原因之一,因為底層引數本身就很難得到訓練.
(4)finetune 就是直接從別人已經訓練好的網路上拷貝引數,然後針對自己的資料訓練新的模型。

這時候需要比較小的 learning_rate, 因為要在不破壞原有模型的情況下 fit 自己的資料,finetune 的好處就是可以直接獲得我們難以或者無法訓練的底層引數。

(5)在目標檢測中,會使用VGG、Resnet、zf、Alexnet等基礎網路作為特徵提取器。然後呼叫預訓練好的網路(輸出pool5的feature map,詳情參考這篇部落格),根據特定任務進行fine-tuning(有實驗證明:如果不進行fine-tuning,也就是你直接把預訓練模型當做萬金油使用,類似於HOG、SIFT一樣做特徵提取,不針對特定的任務。然後把提取的特徵用於分類,結果發現p5的精度竟然跟f6、f7差不多,而且f6提取到的特徵還比f7的精度略高;如果你進行fine-tuning了,那麼在rcnn中f7、f6的提取到的特徵最後訓練的svm分類器的精度就會飆漲),據此我們明白了一個道理,如果不針對特定任務進行fine-tuning,而是把CNN當做特徵提取器,卷積層所學到的特徵其實就是基礎的共享特徵提取層,就類似於SIFT演算法一樣,可以用於提取各種圖片的特徵,而f6、f7所學習到的特徵是用於針對特定任務的特徵。打個比方:對於人臉性別識別來說,一個CNN模型前面的卷積層所學習到的特徵就類似於學習人臉共性特徵,然後全連線層所學習的特徵就是針對性別分類的特徵了。

題外話:在RCNN中還有另外一個疑問:CNN訓練的時候,本來就是對bounding box的物體進行識別分類訓練,是一個端到端的任務,在訓練的時候最後一層softmax就是分類層,那麼為什麼作者閒著沒事幹要先用CNN做特徵提取(提取fc7層資料),然後再把提取的特徵用於訓練svm分類器?這個是因為svm訓練和cnn訓練過程的正負樣本定義方式各有不同,導致最後採用CNN softmax輸出比採用svm精度還低。

事情是這樣的,cnn在訓練的時候,對訓練資料做了比較寬鬆的標註,比如一個bounding box可能只包含物體的一部分,那麼我也把它標註為正樣本,用於訓練cnn;採用這個方法的主要原因在於因為CNN容易過擬合,所以需要大量的訓練資料,所以在CNN訓練階段我們是對Bounding box的位置限制條件限制的比較鬆(IOU只要大於0.5都被標註為正樣本了);

然而svm訓練的時候,因為svm適用於少樣本訓練,所以對於訓練樣本資料的IOU要求比較嚴格:IOU<0.7的都當成負樣本(rcnn訓練的是svm二分類這裡會存在正負樣本不均衡情況,要對負樣本下采樣或者對正樣本上取樣)。我們只有當bounding box把整個物體都包含進去了,我們才把它標註為物體類別,然後訓練svm。