keras:如何保存历史对象的训练历史属性

Posted

技术标签:

【中文标题】keras:如何保存历史对象的训练历史属性【英文标题】:keras: how to save the training history attribute of the history object 【发布时间】:2017-04-24 23:50:39 【问题描述】:

在 Keras 中,我们可以将model.fit 的输出返回到历史记录,如下所示:

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

现在,如何将历史对象的历史属性保存到文件中以供进一步使用(例如绘制 acc 或 loss 对 epochs 的图)?

【问题讨论】:

如果有帮助,您也可以使用 keras 的 CSVLogger() 回调,如下所述:keras.io/callbacks/#csvlogger 有没有人推荐一种方法来保存fit返回的历史对象?它在.params 属性中包含有用的信息,我也想保留这些信息。是的,我可以单独保存 paramshistory 属性或组合成一个字典,但我对保存整个 history 对象的简单方法感兴趣。 【参考方案1】:

我使用的是以下内容:

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

通过这种方式,我将历史记录保存为字典,以防以后想绘制损失或准确性。

【讨论】:

谢谢!我刚刚对此进行了测试,并且可以正常工作。如果可以的话,我会将其标记为正确答案。我不确定实际的 History 对象包含哪些其他信息,但 history.history 拥有我需要的一切。 只是好奇,为什么这里不能使用 JSON 格式?与二进制 pickle 文件不同,它是一个纯文本文件,可以在 Python 之外轻松读取(也许 JSON 格式会导致文件更大) 现在如何加载导出的文件? 您可以使用pickle.load 加载导出的文件。例如,history = pickle.load(open('/trainHistoryDict'), "rb") @ArturoMoncada-Torres,您的代码 sn-p 有一个括号) 在错误的位置关闭。应该是这样的:history = pickle.load(open('/trainHistoryDict', "rb"))。不过小问题。【参考方案2】:

另一种方法:

由于history.historydict,您也可以将其转换为pandas DataFrame 对象,然后可以根据需要进行保存。

一步一步:

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)

【讨论】:

如何重新加载? 您可以使用 pd.read_csv('history.csv') 将其作为数据帧读取【参考方案3】:

最简单的方法:

保存:

np.save('my_history.npy',history.history)

加载中:

history=np.load('my_history.npy',allow_pickle='TRUE').item()

那么历史就是一个字典,你可以使用键检索所有想要的值。

【讨论】:

【参考方案4】:

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)

【讨论】:

这在 tensorflow keras 中不再起作用。我遇到了问题:TypeError:“float32”类型的对象不是 JSON 可序列化的。我不得不使用 json.dump(str(hist.history, f))。【参考方案5】:

history 对象有一个 history 字段是一个字典,其中包含跨越每个训练时期的不同训练指标。所以例如history.history['loss'][99] 将在第 100 个训练阶段返回模型的损失。为了保存你可以pickle这个字典或者简单地保存这个字典中的不同列表到适当的文件。

【讨论】:

【参考方案6】:

我遇到了一个问题,即 keras 列表中的值不是 json 可序列化的。因此,我写了这两个方便的函数,以供我使用。

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

其中 saveHist 只需要获取应该保存 json 文件的路径,以及从 keras fitfit_generator 方法返回的历史对象。

【讨论】:

感谢您提供重新加载的代码。将额外的历史记录(即来自model.fit())附加到重新加载的历史记录的方法也会很好。我现在正在研究。 @MarkCramer 不应该是保存原始历史对象中的所有参数,重新加载历史对象并使用它来设置模型,在重新加载的模型上运行拟合并将结果捕获到新的历史对象中,然后将新历史对象中的信息连接到原始历史对象中? @jschabs,是的,就是这样,但不幸的是它很复杂。我已经想通了,所以我想我会提供一个答案。 给我newchars, decodedbytes = self.decode(data, self.errors)【参考方案7】:

我确信有很多方法可以做到这一点,但我摆弄了一下,想出了一个自己的版本。

首先,自定义回调可以在每个 epoch 结束时抓取和更新历史记录。在那里我还有一个回调来保存模型。这两个都很方便,因为如果您崩溃或关机,您可以在最后一个完成的时期开始训练。

class LossHistory(Callback):
    
    # https://***.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://***.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_filename 设置为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) 就会恢复您的历史记录。

funkiness 来自 json 和列表,但如果不通过迭代对其进行转换,我就无法让它工作。无论如何,我知道这行得通,因为我这几天一直在努力。 pickle.dumphttps://***.com/a/44674337/852795 的答案可能会更好,但我不知道那是什么。如果我在这里遗漏了任何内容,或者您​​无法使其正常工作,请告诉我。

【讨论】:

谢谢!很有用!您可以通过将历史记录存储在内存中而不是在每个时期之后从文件中加载历史记录来加快速度,但是鉴于与实际训练相比,这种加载/保存时间非常短,我认为可以保留代码原样。 追加是一个不错的选择! @ias - 完全正确 - 但如何 - 传递打开的 fh ..?【参考方案8】:

您可以将tf.keras.callbacks.History的History属性保存在.txt形式

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)

【讨论】:

【参考方案9】:

在训练过程结束时保存历史记录时,上述答案很有用。如果您想在训练期间保存历史记录,CSVLogger 回调将很有帮助。

以下代码以数据表文件log.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])

【讨论】:

如何重新加载?

以上是关于keras:如何保存历史对象的训练历史属性的主要内容,如果未能解决你的问题,请参考以下文章

Keras - 管理历史

AttributeError:“numpy.ndarray”对象没有属性“历史”

sklearn 管道 + keras 顺序模型 - 如何获取历史记录?

保存不同时期的 model.fit 历史

使用Keras训练神经网络备忘录

history=model.fit_generator() 为啥 keras 历史是空的?