加载经过训练的Keras模型并继续训练


95

我想知道是否有可能保存经过部分训练的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))

3
你测试过了吗?我认为没有理由不起作用。
maz

我现在看到的是,加载模型后,我的准确性下降了大约10%(仅在第一个时期)。如果重新加载有效,这当然是由新的训练数据引起的。但是我只想确保确实如此。
Wilmar van Ommeren

6
您是直接使用model.save保存模型,还是使用模型检查点(keras.io/callbacks/#example-model-checkpoints)?如果您使用model.save,那么是否有可能保存的是最新模型(即最后一个时期),而不是最佳模型(最低错误)?你能提供实际的代码吗?
maz

我保存的是最新模型,而不是最佳模型(直到这一点,我还不知道那是不可能的)。我将准备一些代码
Wilmar van Ommeren

3
那么,您不能重新加载该数据并继续使用相同的火车数据进行训练吗?这样可以确保您可以在结果可比的情况下重新加载。
MarcinMożejko17年

Answers:


36

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


1
@Marcin:使用keras时save(),会保存模型的最佳结果(损失最小)还是模型的最后结果(最后更新)?谢谢
莱恩狮

4
最后更新。模型检查点回调用于保存最佳回调。
洒红节

2
@Khaj您是指这个keras.io/callbacks/#modelcheckpoint吗?默认情况下,它会保存最近的更新(不是最佳更新);最佳save_best_only=True设置只有在明确设置的情况下才能保存。
flow2k

7

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

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严重超调,从而导致精度大大降低。


5

以上大多数答案都涵盖了重点。如果您正在使用最新的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)

这种方法将在保存模型之前重新开始训练。正如其他人所提到的,如果你想保存最好的模型的重量或要保存模型的加权每次你需要使用keras回调函数(ModelCheckpoint)的选项,如时代save_weights_only=Truesave_freq='epoch'save_best_only

有关更多详细信息,请在此处检查在此处查看另一个示例。


1
很好,这看起来很有希望-感谢您提供的信息。在此示例中,在我看来,您好像是在使用用于训练的相同数据上对模型进行训练。如果是这样,我会以为正确的方法是加载新的训练数据子集以进行重新训练(以反映引入到流程中的新信息)?
bibzzzz

1
@bibzzzz同意你的观点。很好的评论。我想演示对相同数据进行再培训以提高性能。要点清楚地显示了在保存模型之前停止该操作的性能方面的改进。我完全同意您对不同的数据进行再培训,以后再尝试。谢谢!
Vishnuvardhan Janapati

很好-您已经很好地展示了这一点,谢谢。
bibzzzz

2

注意,Keras有时在加载的模型上有问题,如此处所示。这可能会解释一些情况,其中您并非从相同的训练准确性开始。


1

所有上述帮助,保存模型和权重后,您必须从与LR相同的学习rate()中恢复。直接在优化器上进行设置。

请注意,由于模型可能已达到局部最小值(可能是全局最小值),因此无法保证从那里得到改善。除非您打算以受控方式提高学习率并将模型推向不远处的可能更好的最小值,否则没有必要恢复模型以搜索另一个局部最小值。


这是为什么?我不能使用比以前更小的LR吗?
lte__

实际上,如果您收到更多数据,则继续培训可能会为您提供更好的模型。因此,有必要恢复模型以搜索另一个局部最小值。
科里·莱文森

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.