9

我使用 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
4

4 回答 4

9

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)

试验对象中检索训练好的模型:

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 课程中使用了这种方法。

于 2019-03-28T02:27:09.527 回答
3

使f_nn返回模型。

def f_nn(params):
    # ...
    return {'loss': -acc, 'status': STATUS_OK, 'model': model}

这些模型将在trials下的对象上可用results。我输入了一些样本数据,然后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 限制了普通键值对的长度,因此一旦您的值以兆字节为单位,您可能必须将其作为附件。)来源。

于 2019-03-10T03:51:08.197 回答
3

我不知道如何将一些变量发送到f_nn或另一个 hyperopt 目标显式。但我使用两种方法来完成相同的任务。
第一种方法是一些全局变量(不喜欢它,因为它不明确),第二种方法是将度量值保存到文件中,然后读取并与当前度量进行比较。最后一种方法在我看来更好。

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

这种方法有几个优点:您可以将度量和模型保持在一起,甚至可以将某些版本或数据版本控制系统应用于它 - 这样您就可以在将来恢复实验的结果。

编辑
它可能会导致意外的行为,如果有以前运行的一些指标,但你不删除它。因此您可以采用代码 - 优化后删除指标或使用时间戳等来区分您的实验数据。

于 2019-01-20T09:29:49.000 回答
1

很容易实现一个全局变量来保存模型。为了清楚起见,我建议将其保存为trials对象下的属性。根据我的使用经验hyperopt,除非您将所有剩余参数(未调整)包装到 adict中以输入目标函数(例如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}

...

## 
于 2021-03-09T03:43:19.610 回答