fbpx

Keras 教學 - 如何透過資料擴增法利用少量資料訓練 CNN 網路

如何在少量資料的情況下改善 CNN 模型訓練的效果?

前面的教學有提過神經網路會需要大量的資料來進行訓練,尤其是 CCN 應用在影像訓練的領域,時常遇到標記的訓練圖片數量不足。為了在這樣的情況也能獲得不錯的訓練效果,我們接下來會陸續介紹三種技巧,可以用來提高 CNN 網路訓練的效率與成效。

接下來要介紹的三種方法分別為:

  • 資料擴增法 (Data augmentation)
  • 預先訓練神經網路的特徵萃取法 (Feature extraction with a pertrained network)
  • 微調預先訓練神經網路法 (Fine-tuning a pretrained network)

從 Kaggle 下載與準備訓練資料

Kaggle 下載的檔案全部都是圖片,由於我們想要從頭訓練一個可以分辨貓或狗的 CNN 網路,開始以前需要先將影像資料進行處理,轉換為可以送進 Keras 網路進行訓練的「張量」。並且依據我們選用的損失函數方法,處理對應標準答案的格式。

由於我們今天不會用到全部的資料,我們只會在兩種類別取用 1000 張進行訓練,500 張進行測試。接著利用「資料擴增工法」來提高正確率。詳細的資料前處理可以參考 GitHub 程式碼 keras-cat-vs-dog-datagen.ipynb,裡面也有比較完整的說明。

透過「資料擴增法」增加可以進行訓練的樣本數量

如果我們的訓練影像 Dataset 不足,可以透過資料擴增法增加樣本數量。實現方法為將原本的影像進行隨機縮放、旋轉、平移、翻轉等影像處理技巧,來創造更多的訓練樣本。假設樣本真的很難取得,那麼我們也可以透過資料擴增法,將影像資料做一點「變化」,稍微加工一下這樣就有更多資料可以讓模型進行學習。Keras ImageDataGenerator 可以幫助我們實現影像資料擴增,這樣的工作有點像是針對取樣的目標多拍幾張照片的意思。

以下的對照組使用 2,000 張貓狗照片樣本進行訓練,差不多在 5 Epoch 時就達到最小值,正確率約 0.7,少量資料造成 Over Fitting,效果不佳~數據如下:

再來透過影像資料產生更多樣本,透過以下的 Python 把訓練資料進行一些影像處理:

ImageDataGenerator(
      rotation_range=40,      # 隨機旋轉的角度
      width_shift_range=0.2,  # 隨機水平平移的 % 比例
      height_shift_range=0.2, # 隨機垂直平移的 % 比例
      shear_range=0.2,        # 隨機傾斜的角度
      zoom_range=0.2,         # 隨機縮放的比例
      horizontal_flip=True,   # 隨機左右翻轉
      fill_mode='nearest')    # 邊界像素填補,由於影像調整後周圍會出現缺少的像素,設定 nearest 會以最接近的像素填補

以下四張照片是透過 ImageDataGenerator 產生的樣本,可以看到同一張照片經過影像處理產生了更多的學習樣本。

CNN Image Data Generator

當我將貓與狗的訓練樣本由 2,000 擴增為 3,200,並且重新建立模型(詳細的程式碼可以參考 GitHub),這裡我們有動一點手腳,就是在卷積層傳入全連接層 (Full Connection Layer) 的時候加入了 Dropout Layer,這樣會隨機丟棄 50% 的資訊,用意是不要讓網路的學習過於狹隘,不然很容易造成 Over Fitting。完成的網路模型如下:

from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
                        input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))                # 加入 Dropout 0.5 隨機丟棄 50%
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])

model.summary()

CNN-network-cat-vs-dog

透過這樣的修改,可以將正確率提昇至 0.85。結果如下:

完整的程式碼可以參考 CoLab Keras 利用資料擴增法訓練貓狗分類器GitHub ipynb 範例檔案。

這一篇文章介紹透過資料擴增法製造更多的樣本數,解此提昇模型訓練的準確性。接下來我們會介紹另一個常用的方法,可以透過已經訓練好的模型進行二次訓練,也是目前常用的訓練方式,敬請期待...