Keras: как сохранить атрибут истории обучения объекта истории

В Keras мы можем вернуть вывод model.fit в историю следующим образом:

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

Теперь, как сохранить атрибут истории объекта истории в файл для дальнейшего использования (например, нарисовать графики прибыли или убытка по эпохам)?

Ответ 1

Я использую следующее:

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

Таким образом, я сохраняю историю как словарь в случае, если я хочу позже нанести ущерб или точность.

Ответ 2

Историю model можно сохранить в файл следующим образом

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)

Ответ 3

Объекты A history имеют поле history - словарь, который содержит различные обучающие метрики, охватываемые каждой учебной эпохой. Так, например, history.history['loss'][99] вернет потерю вашей модели в 100-ю эпоху обучения. Чтобы сохранить этот pickle этот словарь или просто сохранить различные списки из этого словаря в соответствующий файл.

Ответ 4

Другой способ сделать это:

Так как history.history является dict, вы также можете преобразовать его в объект DataFrame pandas, который затем можно сохранить в соответствии с вашими потребностями.

Шаг за шагом:

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)

Ответ 5

Я столкнулся с проблемой, заключающейся в том, что значения внутри списка в кератах не являются json-сериализуемыми. Поэтому я написал эти две удобные функции для моего использования.

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

где saveHist просто нужно получить путь, куда должен быть сохранен файл json, и объект истории, возвращенный из метода keras fit или fit_generator.

Ответ 6

Я уверен, что есть много способов сделать это, но я возился и придумал свою собственную версию.

Во-первых, пользовательский обратный вызов позволяет захватывать и обновлять историю в конце каждой эпохи. Там у меня также есть обратный вызов, чтобы сохранить модель. Оба из них удобны, потому что, если вы потерпите крах или остановитесь, вы можете продолжить обучение в последнюю завершенную эпоху.

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]

Во-вторых, вот некоторые "вспомогательные" функции, выполняющие именно то, что они говорят. Все они вызываются из обратного вызова LossHistory().

# 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

После этого все, что вам нужно, это установить для history_filename что-то вроде data/model-history.json, а также установить для model_filesname что-то вроде data/model.h5. Последнее, что нужно сделать, чтобы не испортить свою историю в конце обучения, предполагая, что вы останавливаетесь и начинаете, а также придерживаетесь обратных вызовов, - это сделать следующее:

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)

Когда бы вы ни захотели, history = loadHist(history_filename) возвращает вашу историю.

Забавность исходит от json и списков, но я не смог заставить его работать, не преобразовав его путем итерации. Во всяком случае, я знаю, что это работает, потому что я провернул это в течение нескольких дней. Ответ pickled.dump на fooobar.com/info/504140/... может быть лучше, но я не знаю, что это такое. Если я что-то здесь пропустил или вы не можете заставить его работать, дайте мне знать.