加载已训练的Keras模型并继续训练

148

我在想是否可以保存部分训练好的Keras模型,然后在加载该模型后继续训练。

原因是我将来会有更多的训练数据,而我不想重新训练整个模型。

我正在使用的功能是:

#Partly train model
model.fit(first_training, first_classes, batch_size=32, nb_epoch=20)

#Save partly trained model
model.save('partly_trained.h5')

#Load partly trained model
from keras.models import load_model
model = load_model('partly_trained.h5')

#Continue training
model.fit(second_training, second_classes, batch_size=32, nb_epoch=20)

编辑1:添加了完全可工作的示例

在第一个数据集上进行10个时期后,最后一个时期的损失将为0.0748,准确度为0.9863。

保存、删除和重新加载模型后,在第二个数据集上训练的模型的损失和准确度分别为0.1711和0.9504。

这是由新的训练数据引起的还是由完全重新训练的模型引起的?

"""
Model by: http://machinelearningmastery.com/
"""
# load (downloaded if needed) the MNIST dataset
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import np_utils
from keras.models import load_model
numpy.random.seed(7)

def baseline_model():
    model = Sequential()
    model.add(Dense(num_pixels, input_dim=num_pixels, init='normal', activation='relu'))
    model.add(Dense(num_classes, init='normal', activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

if __name__ == '__main__':
    # load data
    (X_train, y_train), (X_test, y_test) = mnist.load_data()

    # flatten 28*28 images to a 784 vector for each image
    num_pixels = X_train.shape[1] * X_train.shape[2]
    X_train = X_train.reshape(X_train.shape[0], num_pixels).astype('float32')
    X_test = X_test.reshape(X_test.shape[0], num_pixels).astype('float32')
    # normalize inputs from 0-255 to 0-1
    X_train = X_train / 255
    X_test = X_test / 255
    # one hot encode outputs
    y_train = np_utils.to_categorical(y_train)
    y_test = np_utils.to_categorical(y_test)
    num_classes = y_test.shape[1]

    # build the model
    model = baseline_model()

    #Partly train model
    dataset1_x = X_train[:3000]
    dataset1_y = y_train[:3000]
    model.fit(dataset1_x, dataset1_y, nb_epoch=10, batch_size=200, verbose=2)

    # Final evaluation of the model
    scores = model.evaluate(X_test, y_test, verbose=0)
    print("Baseline Error: %.2f%%" % (100-scores[1]*100))

    #Save partly trained model
    model.save('partly_trained.h5')
    del model

    #Reload model
    model = load_model('partly_trained.h5')

    #Continue training
    dataset2_x = X_train[3000:]
    dataset2_y = y_train[3000:]
    model.fit(dataset2_x, dataset2_y, nb_epoch=10, batch_size=200, verbose=2)
    scores = model.evaluate(X_test, y_test, verbose=0)
    print("Baseline Error: %.2f%%" % (100-scores[1]*100))

编辑2:关于tensorflow.keras的说明

对于tensorflow.keras,请在模型拟合中将参数nb_epochs更改为epochs。导入和basemodel函数如下:

import numpy
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import load_model


numpy.random.seed(7)

def baseline_model():
    model = Sequential()
    model.add(Dense(num_pixels, input_dim=num_pixels, activation='relu'))
    model.add(Dense(num_classes, activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

3
你测试过了吗?我看不出有任何原因不能成功。 - maz
我现在看到的是,在加载模型后,我的准确率会下降约10%(仅在前几个时期)。如果重新加载可以解决这个问题,那么当然是由于新的训练数据造成的。但我只想确保这确实是情况。 - Wilmar van Ommeren
7
你是直接使用 model.save 保存你的模型,还是使用了模型检查点(https://keras.io/callbacks/#example-model-checkpoints)?如果你正在使用 model.save,是否有可能保存的是最新的模型(即最后一个 epoch),而不是最好的模型(误差最小的那个)?能否提供实际代码? - maz
我正在保存我的最新模型,而不是最好的模型(直到这个时候我才知道这是可能的)。我将准备一些代码。 - Wilmar van Ommeren
3
那你不能重新加载数据并继续在同一训练数据上进行训练吗?这将确保如果结果是可比较的,重新加载是可以的。 - Marcin Możejko
显示剩余3条评论
8个回答

51

实际上-model.save保存了重启训练所需的所有信息。唯一可能被重新加载模型破坏的是你的优化器状态。为了检查这一点,请尝试保存和重新加载模型,并在训练数据上进行训练。


1
@Marcin:在使用Keras的save()函数时,它会保存模型的最佳结果(最小损失)还是最后结果(最后一次更新)?谢谢。 - Lion Lai
8
最后更新。模型检查点回调用于保存最佳模型。 - Holi
2
@Khaj 你是指这个链接吗 https://keras.io/callbacks/#modelcheckpoint?默认情况下,它保存的是最后一次更新(而不是最佳更新);只有在显式设置`save_best_only=True`时才会保存最佳更新。 - flow2k
问题:model.save在学习率调度或学习率衰减的情况下是否保存学习率?我想进行在线学习,不希望每个样本都对我使用的训练数据产生相同的影响。 - Mahmoud Youssef
1
model.save 会保存学习率(但不会保存 epoch 数)。 - Robin Davies

33

上面大多数答案都涵盖了重要的要点。如果你正在使用最近的Tensorflow(TF2.1或更高版本),那么以下示例将对你有所帮助。代码的模型部分来自Tensorflow网站。

import tensorflow as tf
from tensorflow import keras
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

def create_model():
  model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),  
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    ])

  model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',metrics=['accuracy'])
  return model

# Create a basic model instance
model=create_model()
model.fit(x_train, y_train, epochs = 10, validation_data = (x_test,y_test),verbose=1)
请以*.tf格式保存模型。根据我的经验,如果你定义了任何自定义损失函数,*.h5格式将不能保存优化器状态,因此如果您想从我们停止的地方重新训练模型,则不会达到您的目的。
# saving the model in tensorflow format
model.save('./MyModel_tf',save_format='tf')


# loading the saved model
loaded_model = tf.keras.models.load_model('./MyModel_tf')

# retraining the model
loaded_model.fit(x_train, y_train, epochs = 10, validation_data = (x_test,y_test),verbose=1)

这种方法会重新启动在保存模型之前的训练。正如其他人所提到的,如果你想保存最佳模型的权重或在每个epoch保存模型的权重,你需要使用keras回调函数(ModelCheckpoint)并设置选项,例如save_weights_only=Truesave_freq='epoch'save_best_only

更多详细信息,请查看这里和另一个例子这里


1
很好,这看起来非常有前途 - 感谢提供的信息。在这个例子中,我觉得你是在用相同的数据重新训练模型。如果是这样,我认为正确的方法应该是加载一个新的训练数据子集进行重新训练(以反映引入到过程中的新信息)。 - bibzzzz
1
@bibzzzz 同意你的观点。非常好的评论。我想展示在相同数据上重新训练以提高性能。这篇文章清楚地展示了在保存模型之前停止时性能的提高。我完全同意你的意见,在不同的数据上重新训练并将在以后尝试。谢谢! - Vishnuvardhan Janapati
1
非常棒 - 你已经非常漂亮地展示了这一点,谢谢。 - bibzzzz
1
你确定这句话的翻译是“请将模型保存在*.tf格式中。根据我的经验,如果你定义了自定义损失函数,*.h5格式将无法保存优化器状态”吗?因为在Keras文档中从未提到过。 https://www.tensorflow.org/guide/keras/save_and_serialize - Wenuka

11

问题可能是您使用了不同的优化器 - 或者对优化器使用了不同的参数。我刚使用一个自定义的预训练模型遇到了同样的问题,使用了

reduce_lr = ReduceLROnPlateau(monitor='loss', factor=lr_reduction_factor,
                              patience=patience, min_lr=min_lr, verbose=1)

对于预训练模型,初始学习率为0.0003,在预训练过程中降至最小学习率0.000003。

我将这行代码复制到使用预训练模型的脚本中,但得到了非常糟糕的准确度。直到我注意到预训练模型的最后一个学习率是最小学习率,即0.000003。如果我以这个学习率开始训练,一开始的准确度与预训练模型的输出完全相同 - 这很有道理,因为从比预训练模型使用的最后一个学习率高100倍的学习率开始将导致梯度下降大幅超调,从而严重降低准确度。


3
请注意,Keras有时会出现已加载模型的问题,例如在这里。这可能会解释为什么你的训练准确性不同于之前的结果。

2

1
所有这些都有帮助,但是当模型和权重保存时,您必须从相同的学习率()恢复。直接在优化器上设置它。
请注意,那之后的改进并不保证,因为模型可能已经达到了局部最小值,这可能是全局最小值。除非您打算以受控方式增加学习率并将模型推入可能更好的最小值,否则没有重新开始搜索另一个局部最小值的意义。

为什么呢?我不能使用比以前更小的LR吗? - lte__
1
实际上,如果您获得更多数据,继续训练可能会使您获得更好的模型。因此,恢复模型以搜索另一个局部最小值是有意义的。 - Corey Levinson

1
如果您正在使用TF2,请使用新的saved_model方法(格式pb)。更多信息请参见此处此处
model.fit(x=X_train, y=y_train, epochs=10,callbacks=[model_callback])#your first training
tf.saved_model.save(model, save_to_dir_path) #save the model
del model #to delete the model
model =  tf.keras.models.load_model(save_to_dir_path)
model.fit(x=X_train, y=y_train, epochs=10,callbacks=[model_callback])#your second training

-1

用已保存的模型训练模型完全没有问题。我使用相同的数据对保存的模型进行了训练,发现其准确性很高。此外,在每个周期中所花费的时间也相当少。

这里是代码,请看一下:

from keras.models import load_model
model = load_model('/content/drive/MyDrive/CustomResNet/saved_models/model_1.h5')
history=model.fit(train_gen,validation_data=valid_gen,epochs=5)

你的答案与这个答案有何不同? - Edward Ji
真正的问题在于它们都没有提到save方法是saved_model.save的别名。所以,没错,它们两个基本上给出了相同的答案,但如果不去看vimzie链接的TF文档,你就无法知道这一点。 - MTKnife

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接