預先訓練神經網路的特徵萃取法
我們知道 CNN 卷積層的訓練需要很多數據與運算資源,在資料集不足的情況下,從頭訓練卷積層不是一個聰明的方法。何不直接採用大神訓練好的卷積層,加速 AI Time to Market。這樣的方法稱為預先訓練神經網路的特徵萃取法 (Feature extraction with a pertrained network),由於在 CNN 架構中訓練 Convolutional Layer 成本是很高的,太少的樣本不足以訓練出具有特徵擷取意義的網路。Convolutional Layer 如下:
Convolutional 主要用來擷取特徵,在不同的業務需求下,前端對於影響的特徵擷取其實是可以共用的。所以我們想站在巨人的肩膀上,直接使用一些典型網路已經訓練好的 Convolutional Base 來擷取特徵,透過特徵重新訓練自己的 Full Connection 分類網路,加速產品 Time To Market 的時間。
什麼是 CNN 特徵?
卷積神經網路是一種深度學習模型,其中包含了許多卷積層和池化層。這些層的目的是對輸入數據進行過濾和降維,以提取出有用的特徵。這些提取出來的特徵稱為 CNN 特徵。CNN 特徵通常用來解決圖像識別和分類任務,因為它們能夠很好地捕捉圖像中的細節和結構信息。例如,在臉部識別任務中,CNN 特徵可能會捕捉到眼睛、鼻子和嘴巴的位置和形狀等信息,以此來識別不同的人臉。在使用 CNN 特徵時,通常會先對輸入數據進行預處理,例如對圖像進行縮放和正規化,然后再輸入到卷積神經網路中進行訓練。訓練完成后,可以提取出網路中的 CNN 特徵,並將它們用作其他模型的輸入,例如分類器或識別器等等。
目前已經有許多不同的特徵萃取法可以用於 CNN 訓練,例如:
- 卷積層:卷積層將對輸入數據進行卷積運算,並使用過濾器來提取特徵。卷積層通常會結合多個過濾器,以提取出不同的特徵。
- 池化層:池化層會對輸入數據進行下采樣,以縮小數據的維度並提取出重要的特徵。
- 全連接層:全連接層會對輸入數據進行線性轉換,以提取出高維度數據中的有用特徵。
在 CNN 訓練過程中,通常會使用多個卷積層和池化層來進行特徵萃取,然後再使用全連接層進行分類或識別。通常情況下,較深的網路能夠更好地捕捉較細節的特徵,但也會需要更多的訓練數據和更長的訓練時間。
由於卷積網路可以學習影像特徵,越接近 Input 的 Layer 所能理解的特徵越「普適」而且抽象,像是紋理、顏色等等。越後面的 Layer 所學習到的特徵越接近物體的描述,像是耳朵、眼睛等等。目前已經有很多已經訓練好的 CNN Model 可以使用,Keras 也內建許多常用的模型,接下來我們透過常用的 VGG16 Model 實現對 Full Connection Layer 重新訓練來提昇辨識效果。
載入 Keras VGG16 模型進行重新訓練
我們先透過 keras.applications 載入 VGG16 網路並且顯示網路資訊,如下:
# 載入 VGG 網路 Convolutional Base from keras.applications import VGG16 conv_base = VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3)) conv_base.summary()
透過已經訓練好的卷積網路來萃取特徵,這裡的程式將圖片影像直接送入卷積網路,將計算出的數值儲存起來,後續會用來訓練分類網路。範例程式如下:
def extract_features(directory, sample_count): features = np.zeros(shape=(sample_count, 4, 4, 512)) labels = np.zeros(shape=(sample_count)) generator = datagen.flow_from_directory( directory, target_size=(150, 150), batch_size=batch_size, class_mode='binary') i = 0 for inputs_batch, labels_batch in generator: features_batch = conv_base.predict(inputs_batch) features[i * batch_size : (i + 1) * batch_size] = features_batch labels[i * batch_size : (i + 1) * batch_size] = labels_batch i += 1 if i * batch_size >= sample_count: break return features, labels
上面的程式有一個重點,就是「features_batch = conv_base.predict(inputs_batch)」表示要訓練的圖片先透過既有的 CNN 抽取特徵。
接下來開始透過擷取好的特徵重新訓練分類網路,這裡是用特徵來訓練而不是圖片喔,如下:
from keras import models from keras import layers from keras import optimizers model = models.Sequential() model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512)) model.add(layers.Dropout(0.5)) model.add(layers.Dense(1, activation='sigmoid')) model.compile(optimizer=optimizers.RMSprop(lr=2e-5), loss='binary_crossentropy', metrics=['acc']) history = model.fit(train_features, train_labels, epochs=30, batch_size=20, validation_data=(validation_features, validation_labels))
最後驗證一下正確率:
透過這樣的方法可以獲得將約 0.9 的正確性,效果比前一篇介紹的資料擴增法又好上一點。如果合併兩種方法 (資料擴充 + 特增萃取),成本會高一些,但是可以提升到 0.95 的正確性。這裡附上完整的 Python CoLab 預先訓練神經網路的特徵萃取法範例,同步提供 GitHub File「Keras 利用預先訓練神經網路特徵萃取法訓練貓狗分類器」。
Keras 除了 VGG 以外還有提供更多典型網路,像是:DenseNet, NASNet, InceptionResNetV2, ResNet 50, Inception v3, Xception, VGG16, VGG19, MobileNet, MobileNet V2 等等,有興趣的程序猿可以玩看看,依據我之前的測試,根據不同的場景不同的 Model 都會有不同的表現。今天先介紹到這裡,下次見.......