再談遷移學習:微調網絡

在《站在巨人的肩膀上:遷移學習》一文中,咱們談到了一種遷移學習方法:將預訓練的卷積神經網絡做爲特徵提取器,而後使用一個標準的機器學習分類模型(好比Logistic迴歸),以所提取的特徵進行訓練,獲得分類器,這個過程至關於用預訓練的網絡取代上一代的手工特徵提取方法。這種遷移學習方法,在較小的數據集(好比17flowers)上也能取得不錯的準確率。git

在那篇文章中,我還提到了另一種遷移學習:微調網絡,這篇文章就來談談微調網絡。github

所謂微調網絡,至關於給預訓練的模型作一個「換頭術」,即「切掉」最後的全鏈接層(能夠想象爲卷積神經網絡的「頭部」),而後接上一個新的參數隨機初始化的全鏈接層,接下來咱們在這個動過「手術」的卷積神經網絡上用咱們比較小的數據集進行訓練。算法

在新模型上進行訓練,有幾點須要注意:bash

  1. 開始訓練時,「頭部」如下的層(也就是沒有被替換的網絡層)的參數須要固定(frozen),也就是進行前向計算,但反向傳遞時不更新參數,訓練過程只更新新替換上的全鏈接層的參數。
  2. 使用一個很是小的學習率進行訓練,好比0.001
  3. 最後,做爲可選,在全鏈接層的參數學習得差很少的時候,咱們能夠將「頭部」如下的層解凍(unfrozen),再總體訓練整個網絡。

特徵提取和微調網絡

對照一下上一篇文章中的特徵提取,咱們以直觀的圖形來展示它們之間的不一樣:微信

若是咱們在VGG16預訓練模型上進行特徵提取,其結構以下圖所示:網絡

對比原模型結構,從最後一個卷積池化層直接輸出,即特徵提取。而微調網絡則以下圖所示:架構

一般狀況下,新替換的全鏈接層參數要比原來的全鏈接層參數要少,由於咱們是在比較小的數據集上進行訓練。訓練過程一般分兩個階段,第一階段固定卷積層的參數,第二階段則全放開:機器學習

相比特徵提取這種遷移學習方法,網絡微調一般能獲得更高的準確度。但記住,天下沒有免費的午飯這個原則,微調網絡須要作更多的工做:函數

首先訓練時間很長,相比特徵提取只作前向運算,而後訓練一個簡單的Logisitic迴歸算法,速度很快,微調網絡由於是在很深的網絡模型上訓練,特別是第二階段要進行全面的反向傳遞,耗時更長。在個人GTX 960顯卡上用17flowers數據集,訓練了幾個小時,尚未訓練完,結果我睡着了:(,也不知道最終花了多長時間。post

其次須要調整的超參數比較多,好比選擇多大的學習率,全鏈接網絡設計多少個節點比較合適,這個依賴經驗,但在某些特別的數據集上,可能須要多嘗試幾回才能獲得比較好的結果。

網絡層及索引

在「動手術」以前,咱們須要瞭解模型的結構,最起碼咱們須要知道層的名稱及索引,沒有這些信息,就如同盲人拿起手術刀。在keras中,要了解層的信息很是簡單:

print("[INFO] loading network ...")
model = VGG16(weights="imagenet", include_top=args["include_top"] > 0)

print("[INFO] showing layers ...")
for (i, layer) in enumerate(model.layers):
  print("[INFO] {}\t{}".format(i, layer.__class__.__name__))
複製代碼

VGG16的模型結構以下:

能夠看到第20 ~ 22層爲全鏈接層,這也是微調網絡要替換的層。

網絡「換頭術」

首先,咱們定義一組全鏈接層:INPUT => FC => RELU => DO => FC => SOFTMAX。相比VGG16中的全鏈接層,這個更加簡單,參數更少。而後將基本模型的輸出做爲模型的輸入,完成拼接。這個拼接在keras中也至關簡單。

class FCHeadNet:
  @staticmethod
  def build(base_model, classes, D):
    # initialize the head model that will be placed on top of
    # the base, then add a FC layer
    head_model = base_model.output
    head_model = Flatten(name="flatten")(head_model)
    head_model = Dense(D, activation="relu")(head_model)
    head_model = Dropout(0.5)(head_model)

    # add a softmax layer
    head_model = Dense(classes, activation="softmax")(head_model)

    return head_model
複製代碼

由於在VGG16的構造函數中有一個include_top參數,能夠決定是否包含頭部的全鏈接層,因此這個「換頭」步驟至關簡單:

base_model = VGG16(weights="imagenet", include_top=False, input_tensor=Input(shape=(224, 224, 3)))

# initialize the new head of the network, a set of FC layers followed by a softmax classifier
head_model = FCHeadNet.build(base_model, len(class_names), 256)

# place the head FC model on top of the base model -- this will become the actual model we will train
model = Model(inputs=base_model.input, outputs=head_model)
複製代碼

這時獲得的model就是通過「換頭術」的網絡模型。

訓練

微調網絡的訓練和以前談到的模型訓練過程差很少,只是多了一個freeze層的動做,其實是進行兩個訓練過程。如何固定層的參數呢?一句話就能夠搞定:

for layer in base_model.layers:
  layer.trainable = False
複製代碼

「解凍」相似,只是layer.trainable值設爲True。

爲了更快的收斂,儘快的學習到全鏈接層的參數,在第一階段建議採用RMSprop優化器。但學習率須要選擇一個比較小的值,例如0.001。

在通過一個至關長時間的訓練以後,新模型在17flowers數據集上的結果以下:

[INFO] evaluating after fine-tuning ...
              precision    recall  f1-score   support

    bluebell       0.95      0.95      0.95        20
   buttercup       1.00      0.90      0.95        20
   coltsfoot       0.95      0.91      0.93        22
     cowslip       0.93      0.87      0.90        15
      crocus       1.00      1.00      1.00        23
    daffodil       0.92      1.00      0.96        23
       daisy       1.00      0.94      0.97        16
   dandelion       0.94      0.94      0.94        16
  fritillary       1.00      0.95      0.98        21
        iris       0.96      0.96      0.96        27
  lilyvalley       0.94      0.89      0.91        18
       pansy       0.90      0.95      0.92        19
    snowdrop       0.86      0.95      0.90        20
   sunflower       0.95      1.00      0.98        20
   tigerlily       0.96      0.96      0.96        23
       tulip       0.70      0.78      0.74        18
  windflower       1.00      0.95      0.97        19

   micro avg       0.94      0.94      0.94       340
   macro avg       0.94      0.93      0.94       340
weighted avg       0.94      0.94      0.94       340
複製代碼

相比特徵提取這種遷移學習,準確率有了至關可觀的提高。

小結

網絡微調是一項很是強大的技術,咱們無需從頭開始訓練整個網絡。相反,咱們能夠利用預先存在的網絡架構,例如在ImageNet數據集上訓練的最早進模型,該模型由豐富的過濾器組成。使用這些過濾器,咱們能夠「快速啓動」咱們的學習,使咱們可以進行網絡手術,最終獲得更高精度的遷移學習模型,而不是從頭開始訓練,並且工做量少。

以上實例均有完整的代碼,點擊閱讀原文,跳轉到我在github上建的示例代碼。

另外,我在閱讀《Deep Learning for Computer Vision with Python》這本書,在微信公衆號後臺回覆「計算機視覺」關鍵字,能夠免費下載這本書的電子版。

往期回顧

  1. 站在巨人的肩膀上:遷移學習
  2. 聊一聊rank-1和rank-5準確度
  3. 使用數據加強技術提高模型泛化能力

image
相關文章
相關標籤/搜索