Charger un modèle Keras entraîné et continuer la formation

98

Je me demandais s'il était possible d'enregistrer un modèle Keras partiellement formé et de continuer la formation après avoir chargé à nouveau le modèle.

La raison en est que j'aurai plus de données d'entraînement à l'avenir et je ne veux pas recycler à nouveau le modèle entier.

Les fonctions que j'utilise sont:

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

Edit 1: ajout d'un exemple entièrement fonctionnel

Avec le premier ensemble de données après 10 époques, la perte de la dernière époque sera de 0,0748 et la précision de 0,9863.

Après avoir enregistré, supprimé et rechargé le modèle, la perte et la précision du modèle entraîné sur le deuxième jeu de données seront respectivement de 0,1711 et 0,9504.

Est-ce que cela est dû aux nouvelles données d'entraînement ou à un modèle complètement réentraîné?

"""
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
la source
3
L'avez-vous testé? Je ne vois aucune raison pour que cela ne fonctionne pas.
maz
Ce que je vois maintenant, c'est que ma précision diminue d'environ 10% après le chargement du modèle (uniquement dans les premières époques). Si le rechargement fonctionne, cela est bien sûr causé par les nouvelles données d'entraînement. Mais je veux juste m'assurer que c'est bien le cas.
Wilmar van Ommeren
7
Enregistrez-vous votre modèle directement avec model.save ou utilisez-vous un point de contrôle de modèle ( keras.io/callbacks/#example-model-checkpoints )? Si vous utilisez model.save, y aurait-il une chance que vous sauvegardiez le dernier modèle (c'est-à-dire la dernière époque) au lieu du meilleur (erreur la plus faible)? Pouvez-vous fournir un code réel?
maz
J'enregistre mon dernier modèle, pas le meilleur (jusqu'à ce point, je ne savais pas que c'était possible). Je vais préparer du code
Wilmar van Ommeren
3
Alors ne pourriez-vous pas recharger cela et continuer à vous entraîner sur les mêmes données de train? Cela devrait vous assurer que le rechargement est correct si les résultats sont comparables.
Marcin Możejko

Réponses:

36

En fait - model.saveenregistre toutes les informations nécessaires pour redémarrer la formation dans votre cas. La seule chose qui pourrait être gâchée par le rechargement du modèle est l'état de votre optimiseur. Pour vérifier cela, essayez de saverecharger le modèle et entraînez-le sur les données d'entraînement.

Marcin Możejko
la source
1
@Marcin: lors de l'utilisation de keras save(), enregistre-t-il le meilleur résultat (perte la plus faible) du modèle ou le dernier résultat (dernière mise à jour) du modèle? merci
Lion Lai
5
dernière mise à jour. Le rappel de point de contrôle du modèle sert à enregistrer le meilleur.
Holi
2
@Khaj Faites-vous référence à ce keras.io/callbacks/#modelcheckpoint ? Il semble que par défaut, il enregistre la dernière mise à jour (pas la meilleure); le meilleur n'est enregistré que s'il save_best_only=Trueest défini explicitement.
flow2k
7

Le problème peut être que vous utilisez un optimiseur différent - ou des arguments différents pour votre optimiseur. J'ai juste eu le même problème avec un modèle pré-entraîné personnalisé, en utilisant

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

pour le modèle pré-entraîné, dans lequel le taux d'apprentissage d'origine commence à 0,0003 et pendant la pré-formation, il est réduit au taux d'apprentissage min_learning, qui est de 0,000003

Je viens de copier cette ligne dans le script qui utilise le modèle pré-entraîné et a une très mauvaise précision. Jusqu'à ce que je remarque que le dernier taux d'apprentissage du modèle pré-entraîné était le taux d'apprentissage minimum, soit 0,000003. Et si je commence avec ce taux d'apprentissage, j'obtiens exactement les mêmes précisions au départ que la sortie du modèle pré-entraîné - ce qui est logique, car en commençant par un taux d'apprentissage 100 fois supérieur au dernier taux d'apprentissage utilisé dans le pré-entraîné Le modèle entraînera un énorme dépassement de GD et donc une précision fortement diminuée.

Wolfgang
la source
5

La plupart des réponses ci-dessus couvraient des points importants. Si vous utilisez Tensorflow récent ( TF2.1ou supérieur), l'exemple suivant vous aidera. La partie modèle du code provient du site Web 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)

Veuillez enregistrer le modèle au format * .tf. D'après mon expérience, si vous avez défini un custom_loss, le format * .h5 n'enregistrera pas l'état de l'optimiseur et ne servira donc pas votre objectif si vous souhaitez recycler le modèle d'où nous sommes partis.

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

Cette approche redémarrera la formation là où nous avons quitté avant d'enregistrer le modèle. Comme mentionné par d' autres, si vous voulez enregistrer des poids de meilleur modèle ou que vous souhaitez enregistrer des poids de modèle chaque époque vous devez utiliser la fonction keras callbacks (ModelCheckpoint) avec des options telles que save_weights_only=True, save_freq='epoch'et save_best_only.

Pour plus de détails, veuillez consulter ici et un autre exemple ici .

Vishnuvardhan Janapati
la source
1
sympa, cela semble très prometteur - merci pour l'info. dans cet exemple, il me semble que vous reconvertissez le modèle sur les mêmes données que celles utilisées pour la formation. dans l'affirmative, j'aurais pensé que la bonne approche serait de charger un nouveau sous-ensemble de données de formation sur lesquelles se recycler (afin de refléter les nouvelles informations introduites dans le processus)?
bibzzzz le
1
@bibzzzz D'accord avec vous. Très bon commentaire. Je voulais faire une démonstration de recyclage sur les mêmes données pour améliorer les performances. L'essentiel montre clairement l'amélioration des performances là où il a été arrêté avant d'enregistrer le modèle. Je serais tout à fait d'accord avec vous pour me recycler sur différentes données et j'essaierai plus tard. Merci!
Vishnuvardhan Janapati le
excellent - vous l'avez très bien démontré, merci.
bibzzzz le
2

Notez que Keras a parfois des problèmes avec les modèles chargés, comme ici . Cela peut expliquer les cas dans lesquels vous ne partez pas de la même précision entraînée.

shahar_m
la source
1

Tout ce qui précède vous aide devez reprendre à partir du même taux d'apprentissage () que le LR lorsque le modèle et les poids ont été enregistrés. Réglez-le directement sur l'optimiseur.

Notez que l'amélioration à partir de là n'est pas garantie, car le modèle peut avoir atteint le minimum local, qui peut être global. Il ne sert à rien de reprendre un modèle pour rechercher un autre minimum local, à moins que vous n'ayez l'intention d'augmenter le taux d'apprentissage de manière contrôlée et de pousser le modèle vers un minimum éventuellement meilleur non loin.

flowgrad
la source
Pourquoi donc? Puis-je utiliser un LR plus petit qu'avant?
lte__
En fait, la formation continue PEUT vous amener à un meilleur modèle si vous recevez plus de données. Il y a donc lieu de reprendre un modèle afin de rechercher un autre minimum local.
Corey Levinson