如何保存最佳 hyperopt 优化的 keras 模型及其权重?
Posted
技术标签:
【中文标题】如何保存最佳 hyperopt 优化的 keras 模型及其权重?【英文标题】:How to save the best hyperopt optimized keras models and its weights? 【发布时间】:2019-06-13 20:28:43 【问题描述】:我使用 hyperopt 优化了我的 keras 模型。现在我们如何将最佳优化的 keras 模型及其权重保存到磁盘。
我的代码:
from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
from sklearn.metrics import roc_auc_score
import sys
X = []
y = []
X_val = []
y_val = []
space = 'choice': hp.choice('num_layers',
[ 'layers':'two', ,
'layers':'three',
'units3': hp.uniform('units3', 64,1024),
'dropout3': hp.uniform('dropout3', .25,.75)
]),
'units1': hp.choice('units1', [64,1024]),
'units2': hp.choice('units2', [64,1024]),
'dropout1': hp.uniform('dropout1', .25,.75),
'dropout2': hp.uniform('dropout2', .25,.75),
'batch_size' : hp.uniform('batch_size', 20,100),
'nb_epochs' : 100,
'optimizer': hp.choice('optimizer',['adadelta','adam','rmsprop']),
'activation': 'relu'
def f_nn(params):
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.optimizers import Adadelta, Adam, rmsprop
print ('Params testing: ', params)
model = Sequential()
model.add(Dense(output_dim=params['units1'], input_dim = X.shape[1]))
model.add(Activation(params['activation']))
model.add(Dropout(params['dropout1']))
model.add(Dense(output_dim=params['units2'], init = "glorot_uniform"))
model.add(Activation(params['activation']))
model.add(Dropout(params['dropout2']))
if params['choice']['layers']== 'three':
model.add(Dense(output_dim=params['choice']['units3'], init = "glorot_uniform"))
model.add(Activation(params['activation']))
model.add(Dropout(params['choice']['dropout3']))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy', optimizer=params['optimizer'])
model.fit(X, y, nb_epoch=params['nb_epochs'], batch_size=params['batch_size'], verbose = 0)
pred_auc =model.predict_proba(X_val, batch_size = 128, verbose = 0)
acc = roc_auc_score(y_val, pred_auc)
print('AUC:', acc)
sys.stdout.flush()
return 'loss': -acc, 'status': STATUS_OK
trials = Trials()
best = fmin(f_nn, space, algo=tpe.suggest, max_evals=100, trials=trials)
print 'best: '
print best
【问题讨论】:
【参考方案1】:我不知道如何将一些变量发送到f_nn
或另一个超选择目标显式。但我使用两种方法来完成相同的任务。
第一种方法是一些全局变量(不喜欢它,因为它不明确),第二种方法是将度量值保存到文件中,然后读取并与当前度量进行比较。最后一种方法在我看来更好。
def f_nn(params):
...
# I omit a part of the code
pred_auc =model.predict_proba(X_val, batch_size = 128, verbose = 0)
acc = roc_auc_score(y_val, pred_auc)
try:
with open("metric.txt") as f:
min_acc = float(f.read().strip()) # read best metric,
except FileNotFoundError:
min_acc = acc # else just use current value as the best
if acc < min_acc:
model.save("model.hd5") # save best to disc and overwrite metric
with open("metric.txt", "w") as f:
f.write(str(acc))
print('AUC:', acc)
sys.stdout.flush()
return 'loss': -acc, 'status': STATUS_OK
trials = Trials()
best = fmin(f_nn, space, algo=tpe.suggest, max_evals=100, trials=trials)
print 'best: '
print best
from keras.models import load_model
best_model = load_model("model.hd5")
这种方法有几个优点:您可以将度量和模型保持在一起,甚至可以将一些版本或数据版本控制系统应用到它上 - 这样您就可以在未来恢复实验结果。
编辑 如果前一次运行有一些指标,但您没有删除它,它可能会导致意外行为。因此您可以采用代码 - 优化后删除指标或使用时间戳等来区分您的实验数据。
【讨论】:
您也可以使用model.fit
上的ModelCheckpoint 回调来写入文件,但这会从hyperopt 中保存每个模型,而不仅仅是最好的模型。
嗯,可能是一些升级的ModelCheckpoint
回调可以完成任务,好主意【参考方案2】:
让f_nn
返回模型。
def f_nn(params):
# ...
return 'loss': -acc, 'status': STATUS_OK, 'model': model
这些模型将在results
下的trials
对象上可用。我输入了一些样本数据,得到了print(trials.results)
吐出
['loss': 2.8245880603790283, 'status': 'ok', 'model': <keras.engine.training.Model object at 0x000001D725F62B38>, 'loss': 2.4592788219451904, 'status': 'ok', 'model': <keras.engine.training.Model object at 0x000001D70BC3ABA8>]
使用np.argmin
找到最小的损失,然后使用model.save
保存
trials.results[np.argmin([r['loss'] for r in trials.results])]['model']
(旁注,在 C# 中,这将是 trials.results.min(r => r.loss).model
...如果在 Python 中有更好的方法,请告诉我!)
如果您使用 MongoDB,您可能希望在试用对象上使用 attachments
,因为模型可能非常大:
attachments
- 键值对的字典,其键是短字符串(如文件名),其值可能是长字符串(如文件内容),每次访问记录时不应从数据库加载。 (另外,MongoDB 限制了普通键值对的长度,因此一旦您的值以兆字节为单位,您可能必须将其作为附件。)Source.
【讨论】:
【参考方案3】:Trials 类对象存储了与 hyperopt 的每次迭代相关的许多相关信息。我们也可以要求这个对象保存训练好的模型。 您必须在代码库中进行一些小的更改才能实现这一点。
-- return 'loss': -acc, 'status': STATUS_OK
++ return 'loss':loss, 'status': STATUS_OK, 'Trained_Model': model
注意:'Trained_Model' 只是一个键,您可以使用任何其他字符串。
best = fmin(f_nn, space, algo=tpe.suggest, max_evals=100, trials=trials)
model = getBestModelfromTrials(trials)
从 trials 对象中检索经过训练的模型:
import numpy as np
from hyperopt import STATUS_OK
def getBestModelfromTrials(trials):
valid_trial_list = [trial for trial in trials
if STATUS_OK == trial['result']['status']]
losses = [ float(trial['result']['loss']) for trial in valid_trial_list]
index_having_minumum_loss = np.argmin(losses)
best_trial_obj = valid_trial_list[index_having_minumum_loss]
return best_trial_obj['result']['Trained_Model']
注意:我在 Scikit-Learn 课程中使用过这种方法。
【讨论】:
【参考方案4】:很容易实现一个全局变量来保存模型。为了清楚起见,我建议将其保存为trials
对象下的属性。根据我使用hyperopt
的经验,除非您将所有剩余的参数(未调整的)包装到dict
中以输入目标函数(例如objective_fn = partial(objective_fn_withParams, otherParams=otherParams)
,否则很难避免全局变量。
下面提供的示例:
trials = Trials()
trials.mybest = None # initialize an attribute for saving model later
best = fmin(f_nn, space, algo=tpe.suggest, max_evals=100, trials=trials)
trials.mybest['model'].save("model.hd5")
## In your optimization objective function
def f_nn(params):
global trials
model = trainMyKerasModelWithParams(..., params)
...
pred_auc =model.predict_proba(X_val, batch_size = 128, verbose = 0)
acc = roc_auc_score(y_val, pred_auc)
loss = -acc
## Track only best model (for saving later)
if ((trials.mybest is None)
or (loss < trials.mybest['loss'])):
trials.mybest = 'loss': loss,'model': model
...
##
【讨论】:
以上是关于如何保存最佳 hyperopt 优化的 keras 模型及其权重?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 hyperopt 对 Keras 深度学习网络进行超参数优化?
如何将 KerasClassifier、Hyperopt 和 Sklearn 交叉验证放在一起
我们可以使用 Sparktrials 保存 Hyperopt 试验的结果吗