116 votes

keras : comment sauvegarder l'attribut de l'historique de formation de l'objet historique

Dans Keras, nous pouvons retourner la sortie de model.fit à une histoire comme suit :

 history = model.fit(X_train, y_train, 
                     batch_size=batch_size, 
                     nb_epoch=nb_epoch,
                     validation_data=(X_test, y_test))

Maintenant, comment sauvegarder l'attribut historique de l'objet historique dans un fichier pour d'autres utilisations (par exemple, tracer des graphiques de gains ou de pertes en fonction des époques) ?

2 votes

Si cela vous aide, vous pouvez aussi bien utiliser la fonction CSVLogger() de keras, comme décrit ici : keras.io/callbacks/#csvlogger

1 votes

Quelqu'un peut-il recommander une méthode permettant de sauvegarder l'objet historique renvoyé par la fonction fit ? Il contient des informations utiles dans .params attribut que j'aimerais garder aussi. Oui, je peux sauvegarder le params & history séparément ou les combiner dans un dict, par exemple, mais je suis intéressé par un moyen simple de sauvegarder l'ensemble de la history objet.

7voto

Kev1n91 Points 1240

Je suis tombé sur le problème que les valeurs à l'intérieur de la liste dans keras ne sont pas json seriazable. Par conséquent, j'ai écrit ces deux fonctions pratiques pour mon usage.

import json,codecs
import numpy as np
def saveHist(path,history):

    new_hist = {}
    for key in list(history.history.keys()):
        new_hist[key]=history.history[key]
        if type(history.history[key]) == np.ndarray:
            new_hist[key] = history.history[key].tolist()
        elif type(history.history[key]) == list:
           if  type(history.history[key][0]) == np.float64:
               new_hist[key] = list(map(float, history.history[key]))

    print(new_hist)
    with codecs.open(path, 'w', encoding='utf-8') as file:
        json.dump(new_hist, file, separators=(',', ':'), sort_keys=True, indent=4) 

def loadHist(path):
    with codecs.open(path, 'r', encoding='utf-8') as file:
        n = json.loads(file.read())
    return n

où saveHist a juste besoin d'obtenir le chemin vers l'endroit où le fichier json doit être sauvegardé, et l'objet historique renvoyé par la fonction keras fit ou fit_generator méthode.

1 votes

Merci d'offrir le code pour recharger. Ce qui aurait également été bien serait un moyen d'ajouter un historique supplémentaire (c'est-à-dire de model.fit() ) à l'historique rechargé. Je suis en train de faire des recherches là-dessus.

0 votes

@MarkCramer ne devrait-il pas s'agir de sauvegarder tous les paramètres de l'objet historique original, de recharger l'objet historique et de l'utiliser pour configurer le modèle, d'exécuter l'ajustement sur le modèle rechargé et de capturer les résultats dans un nouvel objet historique, puis de concaténer les informations contenues dans le nouvel objet historique dans l'objet historique original ?

0 votes

@jschabs, oui, c'est comme ça, mais malheureusement c'est compliqué. J'ai trouvé la solution donc je pense que je vais proposer une réponse.

3voto

Mark Cramer Points 108

Je suis sûr qu'il existe de nombreuses façons de procéder, mais j'ai bricolé et j'ai créé ma propre version.

Tout d'abord, un callback personnalisé permet de saisir et de mettre à jour l'historique à la fin de chaque époque. J'y ai aussi une callback pour sauvegarder le modèle. Ces deux fonctions sont pratiques car si vous vous plantez ou si vous vous arrêtez, vous pouvez reprendre l'entraînement à la dernière époque terminée.

class LossHistory(Callback):

    # https://stackoverflow.com/a/53653154/852795
    def on_epoch_end(self, epoch, logs = None):
        new_history = {}
        for k, v in logs.items(): # compile new history from logs
            new_history[k] = [v] # convert values into lists
        current_history = loadHist(history_filename) # load history from current training
        current_history = appendHist(current_history, new_history) # append the logs
        saveHist(history_filename, current_history) # save history from current training

model_checkpoint = ModelCheckpoint(model_filename, verbose = 0, period = 1)
history_checkpoint = LossHistory()
callbacks_list = [model_checkpoint, history_checkpoint]

Ensuite, voici quelques fonctions d'aide qui font exactement ce qu'elles sont censées faire. Elles sont toutes appelées par la fonction LossHistory() le rappel.

# https://stackoverflow.com/a/54092401/852795
import json, codecs

def saveHist(path, history):
    with codecs.open(path, 'w', encoding='utf-8') as f:
        json.dump(history, f, separators=(',', ':'), sort_keys=True, indent=4) 

def loadHist(path):
    n = {} # set history to empty
    if os.path.exists(path): # reload history if it exists
        with codecs.open(path, 'r', encoding='utf-8') as f:
            n = json.loads(f.read())
    return n

def appendHist(h1, h2):
    if h1 == {}:
        return h2
    else:
        dest = {}
        for key, value in h1.items():
            dest[key] = value + h2[key]
        return dest

Après cela, tout ce dont vous avez besoin est de définir history_filename à quelque chose comme data/model-history.json ainsi que l'ensemble model_filesname à quelque chose comme data/model.h5 . Une dernière astuce pour être sûr de ne pas gâcher votre historique à la fin de l'entraînement, en supposant que vous vous arrêtez et recommencez, et que vous maintenez les rappels, est de faire ceci :

new_history = model.fit(X_train, y_train, 
                     batch_size = batch_size, 
                     nb_epoch = nb_epoch,
                     validation_data=(X_test, y_test),
                     callbacks=callbacks_list)

history = appendHist(history, new_history.history)

Quand vous voulez, history = loadHist(history_filename) récupère votre histoire.

Le problème vient du json et des listes mais je n'ai pas réussi à le faire fonctionner sans le convertir par itération. Quoi qu'il en soit, je sais que cela fonctionne parce que j'ai travaillé dessus pendant des jours maintenant. Le site pickled.dump réponse à https://stackoverflow.com/a/44674337/852795 pourrait être meilleur, mais je ne sais pas ce que c'est. Si j'ai oublié quelque chose ou si vous n'arrivez pas à le faire fonctionner, faites-le moi savoir.

1 votes

Merci ! Très utile ! Vous pouvez accélérer un peu le processus en stockant l'historique en mémoire au lieu de le charger depuis un fichier après chaque époque, mais étant donné que ce chargement/sauvegarde est une très petite quantité de temps par rapport à l'entraînement réel, je pense qu'il est bon de garder le code tel quel.

1 votes

L'appendice est une belle touche !

0 votes

@ias - exactement - mais comment - passer le fh ouvert autour.. ?

1voto

Ankur Points 9

Vous pouvez sauvegarder l'attribut Historique de tf.keras.callbacks.History sur .txt formulaire

with open("./result_model.txt",'w') as f:
    for k in history.history.keys():
        print(k,file=f)
        for i in history.history[k]:
            print(i,file=f)

0voto

tngotran Points 181

Les réponses ci-dessus sont utiles pour sauvegarder l'historique à la fin du processus de formation. Si vous voulez sauvegarder l'historique pendant la formation, le callback CSVLogger sera utile.

Le code ci-dessous enregistre le poids du modèle et l'historique de formation sous la forme d'un fichier de type datasheet journal.csv .

model_cb = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path)
history_cb = tf.keras.callbacks.CSVLogger('./log.csv', separator=",", append=False)

history = model.fit(callbacks=[model_cb, history_cb])

0 votes

Comment le recharger ?

0 votes

CSVLogger Il ne sauvegarde pas l'objet historique pendant la formation mais à la fin de la formation. Ainsi, si la formation est interrompue, l'historique est perdu. Une idée sur la façon de le réparer ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X