Как сохранить лучшие оптимизированные для hyperopt модели keras и их вес?
Я оптимизировал свою модель keras, используя hyperopt. Теперь, как сохранить лучшую оптимизированную модель 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 ответа
Объект класса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.
Делать 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, пожалуйста, дайте мне знать!)
Вы можете использовать attachments
на пробном объекте, если вы используете MongoDB, так как модель может быть очень большой:
attachments
- словарь пар ключ-значение, ключи которого являются короткими строками (например, имена файлов), а значения - потенциально длинными строками (например, содержимым файлов), которые не следует загружать из базы данных каждый раз, когда мы получаем доступ к записи. (Кроме того, MongoDB ограничивает длину обычных пар ключ-значение, поэтому, если ваше значение указано в мегабайтах, вам может потребоваться сделать его вложением.) Источник.
Я не знаю, как отправить некоторую переменную 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")
Этот подход имеет несколько преимуществ: вы можете хранить метрику и модель вместе и даже применять к ней некоторую систему контроля версий или версий данных, чтобы в будущем можно было восстановить результаты эксперимента.
редактировать
Это может вызвать неожиданное поведение, если есть метрика из предыдущего запуска, но вы не удалите ее. Таким образом, вы можете принять код - удалить метрику после оптимизации или использовать метку времени и т. Д., Чтобы различать данные ваших экспериментов.
Легко реализовать глобальную переменную для сохранения модели. Я бы порекомендовал сохранить его как атрибут под
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}
...
##