wake-up-neo.net

keras: So speichern Sie die Trainingshistorie

In Keras können wir die Ausgabe von model.fit wie folgt in eine Historie zurückgeben:

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

Nun, wie kann der Verlauf für eine weitere Verwendung in einer Datei gespeichert werden (z. B. Zeichnen von Zugriffen oder Ausfällen gegen Epochen)?

25
jingweimo

Was ich benutze, ist folgendes:

    with open('/trainHistoryDict', 'wb') as file_pi:
        pickle.dump(history.history, file_pi)

Auf diese Weise speichere ich die Historie als Wörterbuch, falls ich den Verlust oder die Genauigkeit später darstellen möchte. 

33
AEndrs

Ein history-Objekt hat ein history-Feld, ein Wörterbuch, in dem verschiedene Trainingsmetriken für jede Trainingsepoche enthalten sind. So z. history.history['loss'][99] wird in einer 100. Epoche des Trainings einen Verlust Ihres Modells zurückgeben. Um dies zu speichern, können Sie dieses Wörterbuch pickle oder einfach verschiedene Listen aus diesem Wörterbuch in die entsprechende Datei speichern.

9
Marcin Możejko

Ein anderer Weg, dies zu tun:

Wie history.history ist ein dict, Sie können es auch in ein pandasDataFrame - Objekt konvertieren, das dann Ihren Anforderungen entsprechend gespeichert werden kann.

Schritt für Schritt:

import pandas as pd

# assuming you stored your model.fit results in a 'history' variable:
history = model.fit(x_train, y_train, epochs=10)

# convert the history.history dict to a pandas DataFrame:     
hist_df = pd.DataFrame(history.history) 

# save to json:  
hist_json_file = 'history.json' 
with open(hist_json_file, mode='w') as f:
    hist_df.to_json(f)

# or save to csv: 
hist_csv_file = 'history.csv'
with open(hist_csv_file, mode='w') as f:
    hist_df.to_csv(f)
6
s.k

Die model-Historie kann wie folgt in einer Datei gespeichert werden

import json
hist = model.fit(X_train, y_train, epochs=5, batch_size=batch_size,validation_split=0.1)
with open('file.json', 'w') as f:
    json.dump(hist.history, f)

Ich bin auf das Problem gestoßen, dass die Werte in der Liste in Keras nicht json seriazable sind. Deshalb habe ich diese zwei praktischen Funktionen für meine Verwendung geschrieben.

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

    new_hist = {}
    for key in list(history.history.keys()):
        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 f:
        json.dump(new_hist, f, separators=(',', ':'), sort_keys=True, indent=4) 

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

dabei muss saveHist nur den Pfad abrufen, an dem die Json-Datei gespeichert werden soll, und das History-Objekt von der fit- oder fit_generator-Methode der Keras zurückgegeben. 

1
Kev1n91

Ich bin sicher, es gibt viele Möglichkeiten, dies zu tun, aber ich habe herumgespielt und mir eine eigene Version ausgedacht.

Erstens ermöglicht ein benutzerdefinierter Rückruf das Abrufen und Aktualisieren des Verlaufs am Ende jeder Epoche. Dort habe ich auch einen Rückruf, um das Modell zu speichern. Beides ist praktisch, denn wenn Sie abstürzen oder das System herunterfahren, können Sie das Training in der letzten abgeschlossenen Epoche beginnen.

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]

Zweitens gibt es hier einige "Hilfsfunktionen", mit denen Sie genau das tun können, was Sie sagen. Diese werden alle vom LossHistory() Rückruf aufgerufen.

# 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

Danach müssen Sie nur noch history_filename Auf data/model-history.json Und model_filesname Auf data/model.h5 Setzen. Ein abschließender Tweak, um sicherzustellen, dass Sie am Ende des Trainings nicht Ihre Historie durcheinander bringen, vorausgesetzt, Sie stoppen und starten und bleiben bei den Rückrufen:

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)

Wann immer Sie möchten, erhält history = loadHist(history_filename) Ihren Verlauf zurück.

Die Frechheit kommt vom Json und den Listen, aber ich konnte es nicht zum Laufen bringen, ohne es durch Iteration zu konvertieren. Wie auch immer, ich weiß, dass dies funktioniert, weil ich seit Tagen daran arbeite. Die Antwort pickled.dump Unter https://stackoverflow.com/a/44674337/852795 ist vielleicht besser, aber ich weiß nicht, was das ist. Wenn ich hier etwas verpasst habe oder Sie es nicht zum Laufen bringen können, lassen Sie es mich wissen.

0
Mark Cramer