Cargar un modelo entrenado de Keras y continuar entrenando

98

Me preguntaba si era posible guardar un modelo Keras parcialmente entrenado y continuar el entrenamiento después de cargar el modelo nuevamente.

La razón de esto es que tendré más datos de entrenamiento en el futuro y no quiero volver a entrenar todo el modelo.

Las funciones que estoy usando son:

#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)

Edición 1: ejemplo agregado completamente funcional

Con el primer conjunto de datos después de 10 épocas, la pérdida de la última época será de 0.0748 y la precisión de 0.9863.

Después de guardar, eliminar y volver a cargar el modelo, la pérdida y precisión del modelo entrenado en el segundo conjunto de datos será 0.1711 y 0.9504 respectivamente.

¿Esto se debe a los nuevos datos de entrenamiento o a un modelo completamente reentrenado?

"""
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))
Wilmar van Ommeren
fuente
3
¿Lo has probado? No veo ninguna razón para que eso no funcione.
maz
Lo que veo ahora es que mi precisión cae en aproximadamente un 10 por ciento después de cargar el modelo (solo en las primeras épocas). Si la recarga funciona, esto se debe, por supuesto, a los nuevos datos de entrenamiento. Pero solo quiero asegurarme de que este sea el caso.
Wilmar van Ommeren
7
¿Está guardando su modelo directamente con model.save o está utilizando un punto de control de modelo ( keras.io/callbacks/#example-model-checkpoints )? Si está utilizando model.save, ¿existe la posibilidad de que esté guardando el último modelo (es decir, la última época) en lugar del mejor (error más bajo)? ¿Puede proporcionar el código real?
maz
Estoy guardando mi último modelo, no el mejor (hasta este momento no sabía que era posible). Prepararé un código
Wilmar van Ommeren
3
Entonces, ¿no podrías recargar eso y continuar entrenando con los mismos datos del tren? Esto debería asegurarle que la recarga está bien si los resultados fueran comparables.
Marcin Możejko

Respuestas:

36

En realidad, model.saveguarda toda la información necesaria para reiniciar el entrenamiento en su caso. Lo único que podría estropearse al volver a cargar el modelo es el estado del optimizador. Para comprobarlo, intente savevolver a cargar el modelo y entrenarlo con datos de entrenamiento.

Marcin Możejko
fuente
1
@Marcin: al usar keras save(), ¿guarda el mejor resultado (menor pérdida) del modelo o el último resultado (última actualización) del modelo? gracias
Lion Lai
5
última actualización. La devolución de llamada del punto de control del modelo es para guardar la mejor.
Holi
2
@Khaj ¿Te refieres a este keras.io/callbacks/#modelcheckpoint ? Parece que por defecto guarda la última actualización (no la mejor); el mejor solo se guarda si save_best_only=Truese establece explícitamente.
flow2k
7

El problema podría ser que usa un optimizador diferente, o diferentes argumentos para su optimizador. Acabo de tener el mismo problema con un modelo preentrenado personalizado, usando

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

para el modelo preentrenado, en el que la tasa de aprendizaje original comienza en 0.0003 y durante el preentrenamiento se reduce a la tasa min_learning, que es 0.000003

Simplemente copié esa línea en el script que usa el modelo preentrenado y obtuve muy malas precisiones. Hasta que me di cuenta de que la última tasa de aprendizaje del modelo preentrenado era la tasa de aprendizaje mínima, es decir, 0,000003. Y si empiezo con esa tasa de aprendizaje, obtengo exactamente las mismas precisiones para comenzar con la salida del modelo preentrenado, lo cual tiene sentido, ya que comenzar con una tasa de aprendizaje que es 100 veces mayor que la última tasa de aprendizaje utilizada en el modelo preentrenado El modelo dará como resultado un gran sobrepaso de GD y, por lo tanto, una precisión muy disminuida.

Wolfgang
fuente
5

La mayoría de las respuestas anteriores cubrieron puntos importantes. Si está utilizando Tensorflow reciente ( TF2.1o superior), el siguiente ejemplo lo ayudará. La parte modelo del código es del sitio web de 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)

Guarde el modelo en formato * .tf. Según mi experiencia, si tiene una pérdida personalizada definida, el formato * .h5 no guardará el estado del optimizador y, por lo tanto, no cumplirá su propósito si desea volver a entrenar el modelo desde donde lo dejamos.

# 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)

Este enfoque reiniciará el entrenamiento donde lo dejamos antes de guardar el modelo. Como han mencionado otros, si desea guardar los pesos de mejor modelo o desea guardar los pesos de modelo de cada época necesita utilizar Keras devoluciones de llamada de función (ModelCheckpoint) con opciones tales como save_weights_only=True, save_freq='epoch', y save_best_only.

Para obtener más detalles, consulte aquí y otro ejemplo aquí .

Vishnuvardhan Janapati
fuente
1
bueno, esto parece muy prometedor, gracias por la información. en este ejemplo, me parece que está volviendo a entrenar el modelo con los mismos datos que se usaron para el entrenamiento. Si es así, habría pensado que el enfoque correcto sería cargar un nuevo subconjunto de datos de entrenamiento para volver a entrenar (para reflejar la nueva información que se introduce en el proceso).
bibzzzz
1
@bibzzzz Estoy de acuerdo contigo. Muy buen comentario. Quería demostrar el reentrenamiento con los mismos datos para mejorar el rendimiento. La esencia muestra claramente una mejora en el rendimiento donde se detuvo antes de guardar el modelo. Estoy completamente de acuerdo con usted para volver a capacitarse en diferentes datos y lo intentaré más tarde. ¡Gracias!
Vishnuvardhan Janapati
excelente, lo ha demostrado muy bien, gracias.
bibzzzz
2

Tenga en cuenta que Keras a veces tiene problemas con los modelos cargados, como aquí . Esto podría explicar los casos en los que no comienza con la misma precisión entrenada.

shahar_m
fuente
1

Todo lo anterior ayuda, debes reanudar desde la misma tasa de aprendizaje () que el LR cuando se guardaron el modelo y los pesos. Configúrelo directamente en el optimizador.

Tenga en cuenta que la mejora desde allí no está garantizada, porque el modelo puede haber alcanzado el mínimo local, que puede ser global. No tiene sentido reanudar un modelo para buscar otro mínimo local, a menos que intente aumentar la tasa de aprendizaje de manera controlada y empuje el modelo a un mínimo posiblemente mejor no muy lejos.

flowgrad
fuente
¿Porqué es eso? ¿No puedo usar un LR más pequeño que antes?
lte__
En realidad, la capacitación continua PUEDE llevarlo a un modelo mejor si recibe más datos. Por tanto, conviene reanudar un modelo para buscar otro mínimo local.
Corey Levinson