训练模型时,很多事情一开始无法预测。尤其是你不知道需要多少轮次才能得到最佳验证损失。通常简单的办法是:训练足够多的轮次,这时模型已经开始过拟合了,根据第一次运行来确定训练所需要的正确轮次,然后使用这个最佳轮数从头开始启动一个新的训练。当然,这种方法很浪费。更好的办法是使用回调函数。
如果监控的目标在设定轮数内不再改善,可以用EarlyStopping回调函数来中断训练。这个回调函数通常与ModelCheckpoint结合使用,后者可以在训练过程中持续的不断保存模型(你也可以选择只保存目前的最佳模型,即一轮结束后具有最佳性能的模型)
import keras
# 通过fit的callbacks参数将回调函数传入模型中,这个参数接收一个回调函数列表,你可以传入任意个回调函数
callback_lists = [
keras.callbacks.EarlyStopping(monitor = 'acc', # 监控模型的验证精度
patience = 1,), # 如果精度在多于一轮的时间(即两轮)内不再改善,就中断训练
# ModelCheckpoint用于在每轮过后保存当前权重
keras.callbacks.ModelCheckpoint(filepath = 'my_model.h5', # 目标文件的保存路径
# 这两个参数的意思是,如果val_loss没有改善,那么不需要覆盖模型文件,
# 这就可以始终保存在训练过程中见到的最佳模型
monitor = 'val_loss', save_best_only = True,)
]
model.compile(optimizer = 'rmsprop', loss = 'binary_crossentropy', metrics = ['acc'])
# 由于回调函数要监控验证损失和验证精度,所以在调用fit时需要传入validation_data(验证数据)
model.fit(x, y, epochs = 10,
batch_size = 32,
callbacks = callbacks_list,
validation_data = (x_val, y_val))
如果验证损失不再改善,你可以使用这个回调函数来降低学习率。在训练过程中如果出现了损失平台(loss plateau),那么增大或减小学习率都是跳出局部最小值的有效策略。这里可以用到ReduceLROnPlateau回调函数。
callback_list = [
keras.callbacks.ReduceLROnPlateau(monitor = 'val_loss', # 监控模型的验证损失
factor = 0.1, # 触发时将学习率除以10
patience = 10) # 如果验证损失在10轮内都没有改善,那么就触发这个回调函数
]
# 由于回调函数要监控验证损失和验证精度,所以在调用fit时需要传入validation_data(验证数据)
model.fit(x, y, epochs = 10,
batch_size = 32,
callbacks = callbacks_list,
validation_data = (x_val, y_val))
如果你需要在训练过程中采取特定行动,而这项行动又没有包含在内置的回调函数中,那么可以编写自己的回调函数。这种回调函数的实现形式是创建keras.callbacks.Callback类的子类。然后你可以实现下面这些方法,它们分别在训练过程中的不同时间被调用。
on_epoch_begin # 在每轮开始时被调用
on_epoch_end # 在每轮结束时被调用
on_batch_begin # 在处理每个批量之前被调用
on_batch_end # 在处理每个批量之后被调用
on_train_begin # 在训练开始时被调用
on_train_end # 在训练结束时被调用
这些方法被调用时都有一个logs参数,这个参数是一个字典,里面包好前一个批量、前一个轮次或前一次训练的信息(训练的指标和验证指标等)。此外,回调函数还可以访问下列属性:
下面是一个回调函数的简单示例,它可以在每轮结束后将模型每层激活保存到硬盘(格式为Numpy数组),这个激活是对验证集的第一个样本计算得到的。
import keras
import numpy as np
class ActivationLogger(keras.callbacks.Callback):
def set_model(self, model):
self.model = model # 在训练之前由父模型调用,告诉回调函数是哪个模型在调用它
layer_outputs = [layer.output for layer in model.layers]
self.activations_model = keras.models.Model(model.input,
layer_outputs) # 模型实例,返回每层的激活
def on_epoch_end(self, epoch, logs = None):
if self.validation_data is None:
raise RuntimeError('Requires validation_data')
validation_sample = self.validation_data[0][0:1] # 获取验证数据的第一个输入样本
activation = self.activations_model.predict(validation_sample)
f = open('activation_at_epoch_' + str(epoch) + '.npz', 'w') # 将数据保存到硬盘
np.savez(f, activations)
f.close()