1. 程式人生 > 其它 >重用預訓練層

重用預訓練層

用Keras進行遷移學習

假如Fashion MNIST資料集包含了8個類別,例如,除涼鞋和襯衫之外的所有類別。有人在該資料集上建立並訓練的Keras模型,並獲得了相當不錯的效能(精度>90%)。將此模型稱為模型A。現在要處理另一項任務:有涼鞋和襯衫的影象,想要訓練一個二元分類器(正=襯衫,負=涼鞋)。資料集非常小,只有200張帶標籤的影象。當使用與模型A相同的架構訓練一個新模型(稱為模型B)時,它的的效能相當好(97.2%)

首先,需要載入模型A並基於該模型的層建立一個新模型。來重用輸出層之外的所有層:

import tensorflow as tf
from tensorflow import keras

model_A=keras.models.load_model('my_model_A.h5')
model_B_on_A=keras.models.Sequential(model_A.layers[:-1])
model_B_on_A.add(keras.layers.Dense(1,activation='sigmoid'))

model_A和model_B_on_A現在共享一些層。當訓練model_B_on_A時,也會影響model_A。如果想避免這種情況,需要在重用model_A的層之前對其進行克隆。為此,需要使用clone_model()來克隆模型A的架構,然後複製其權重(因為clone_model()不會克隆權重):

model_A_clone=kersa.models.clone_model(model_A)
model_A_clone.set_weights(model_A.get_weights())

現在開始可以為任務B訓練model_B_on_A,但是由於新的輸出層是隨機初始化的,它會產生較大的錯誤(至少在前幾個輪次內),因為將存在較大的錯誤梯度,這可能會破壞重用的權重。為了避免這種情況,一種方法是在前幾個輪次凍結重用的層,給新層一些時間來學習合理的權重。為此,可以將每一層的可訓練屬性設定為False並編譯模型

for layer in model_B_on_A.layers[:-1]:
    layers.trainable=False

model_B_on_A.compile(loss='binary_crossentropy',optimizer='sgd',metrics=['accuracy'])
# 凍結或解凍層之後,必須總是要編譯模型

凍結後,可以在訓練模型幾個輪次後,然後解凍重用的層(這需要再次編譯模型),並繼續進行訓練來微調任務B的重用層。解凍重用層後,降低學習率通常是個好主意,可以再次避免損壞重用的權重:

history=model_B_on_A.fit(X_train_B,y_train_B,epochs=4,validation_data=(X_valid_B,y_valid_B))

for layer in model_B_on_A.layers[:-1]:
    layer.trainable=True
optimizer=keras.optimizers.SGD(lr=1e-4)
model_B_on_A.compile(loss='binary_crossentropy',optimizer=optimizer,metrics=['accuracy'])

history=model_B_on_A.fit(X_train_B,y_train_B,epochs=16,validation_data=(X_valid_B,y_valid_B))