重用预训练层

用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))
posted @ 2021-09-28 20:15  里列昂遗失的记事本  阅读(57)  评论(0编辑  收藏  举报