【问题标题】:Loading a trained Keras model and continue training加载经过训练的 Keras 模型并继续训练
【发布时间】:2017-07-28 17:00:42
【问题描述】:

我想知道是否可以保存部分训练的 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 个 epoch 之后,最后一个 epoch 的损失将为 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

【问题讨论】:

  • 你测试了吗?我认为没有理由不这样做。
  • 我现在看到的是,在加载模型后,我的准确率下降了大约 10%(仅在第一个 epoch 中)。如果重新加载有效,这当然是由新的训练数据引起的。但我只是想确保确实如此。
  • 您是直接使用 model.save 保存模型还是使用模型检查点 (keras.io/callbacks/#example-model-checkpoints) ?如果您使用的是 model.save,您是否有可能保存最新的模型(即最后一个时代)而不是最好的模型(最低错误)?能否提供实际代码?
  • 我正在保存我的最新模型,而不是最好的模型(直到此时我才知道这是可能的)。我会准备一些代码
  • 那么您不能重新加载它并继续使用相同的火车数据进行训练吗?如果结果具有可比性,这应该可以确保重新加载是可以的。

标签: python tensorflow neural-network keras resuming-training


【解决方案1】:

实际上 - model.save 保存了在您的情况下重新开始培训所需的所有信息。唯一可能被重新加载模型破坏的是您的优化器状态。要检查这一点 - 尝试 save 并重新加载模型并根据训练数据对其进行训练。

【讨论】:

  • @Marcin:在使用kerassave()时,是保存模型的最佳结果(损失最低)还是模型的最后结果(最后更新)?谢谢
  • 上次更新。模型检查点回调是为了保存最好的。
  • @Khaj 你指的是keras.io/callbacks/#modelcheckpoint吗?似乎默认情况下,它会保存最后一次更新(不是最好的更新);只有明确设置了save_best_only=True,才会保存最好的。
  • 问题,model.save在学习率调度或者学习率衰减的情况下是否保存了学习率。我想做在线学习,我不希望我得到的每个示例都与我使用的训练数据具有相同的效果。
【解决方案2】:

以上大部分答案都涵盖了重点。如果您使用的是最新的 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 格式。根据我的经验,如果您定义了任何 custom_loss,*.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)

这种方法会在保存模型之前从我们离开的地方重新开始训练。正如其他人所提到的,如果您想保存最佳模型的权重,或者您想在每个时期保存模型的权重,您需要使用带有 save_weights_only=Truesave_freq='epoch'save_best_only 等选项的 keras 回调函数(ModelCheckpoint) .

更多详情,请查看here 和另一个示例here

【讨论】:

  • 很好,这看起来很有希望 - 感谢您提供信息。在此示例中,在我看来,您似乎是在使用用于训练的相同数据重新训练模型。如果是这样,我会认为正确的方法是加载一个新的训练数据子集以进行重新训练(以反映引入过程中的新信息)?
  • @bibzzzz 同意你的看法。非常好的评论。我想演示对相同数据进行再培训以提高性能。要点清楚地显示了在保存模型之前停止的性能改进。我完全同意你对不同的数据进行重新训练,稍后再试。谢谢!
  • 非常好 - 你已经很好地证明了这一点,谢谢。
  • 您确定“请将模型保存为 *.tf 格式。根据我的经验,如果您定义了任何 custom_loss,*.h5 格式将不会保存优化器状态”,因为它从未被提及在 Keras 文档中。 tensorflow.org/guide/keras/save_and_serialize
【解决方案3】:

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

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

对于预训练模型,原始学习率从 0.0003 开始​​,在预训练期间降低到 min_learning 率,即 0.000003

我刚刚将该行复制到使用预训练模型的脚本中,但准确度非常差。直到我注意到预训练模型的最后一个学习率是最小学习率,即 0.000003。如果我从那个学习率开始,我会得到与预训练模型的输出完全相同的精度——这是有道理的,因为从一个比预训练中使用的最后一个学习率大 100 倍的学习率开始模型将导致 GD 的巨大超调,从而严重降低精度。

【讨论】:

    【解决方案4】:

    请注意,Keras 有时会在加载模型时出现问题,例如 here。 这可能解释了您没有从相同的训练精度开始的情况。

    【讨论】:

      【解决方案5】:

      以上所有都有帮助,您必须在保存模型和权重时从与 LR 相同的学习率()恢复。直接在优化器上设置。

      请注意,不能保证从那里得到改进,因为模型可能已经达到局部最小值,这可能是全局的。没有必要为了寻找另一个局部最小值而恢复模型,除非您打算以受控方式提高学习率并将模型推到不远处可能更好的最小值。

      【讨论】:

      • 这是为什么呢?我不能使用比以前更小的 LR 吗?
      • 实际上,如果您收到更多数据,继续训练可能会让您获得更好的模型。因此,有必要恢复模型以搜索另一个局部最小值。
      【解决方案6】:

      您可能还会遇到概念漂移,请参阅Should you retrain a model when new observations are available。还有一堆学术论文讨论的灾难性遗忘的概念。这是 MNIST Empirical investigation of catastrophic forgetting

      【讨论】:

        【解决方案7】:

        如果您使用的是 TF2,请使用新的 saved_model 方法(格式 pb)。更多信息请见herehere

        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
        

        【讨论】:

          猜你喜欢
          • 2020-06-20
          • 2018-08-28
          • 2020-05-12
          • 2021-03-30
          • 2018-01-05
          • 2019-12-05
          • 1970-01-01
          • 1970-01-01
          • 2020-09-30
          相关资源
          最近更新 更多