1、hyperopt干什么
这个python库可以在给定的参数空间中随机取点,每一组参数训练一个模型,最后记录和比较所有模型的表现,给出表现最好的一组参数。
它兼容大部分的机器学习任务,不需要对你的模型做什么太大的修改(只需要改一下超参数的写法,把超参数写到字典里面,例如lr改成params['lr'])。
2、hyperopt的使用
a) 安装并导入需要的程序
pip install hyperopt
from hyperopt import hp, STATUS_OK, Trials, fmin
b) 定义参数空间
space = {
'lr':hp.loguniform('lr',-9,-5),
'lambda_l2':hp.loguniform('lambda_l2',-5,0),
'batch_size'hp.choice('batch_size',[8,16])
}
严格地说这里的参数指的是机器学习任务中的超参数,即训练过程中不进行梯度下降的部分。
参数空间是一个字典,在参数空间中,我定义了学习率lr,L2正则化系数lambda_l2,以及minibatch的大小batch_size。
其中,学习率和正则化系数的取值范围是一个均匀对数的范围,例如hp.loguniform('lr',-9,-5)就意味着取值范围是exp(-9)到exp(-5),指数在 [-9, -5] 之间均匀分布。注意这里确实是自然指数,不是10为底的指数。
minibatch大小的取值范围则是离散的,从给定的8和16中二选一。(你可可以把这个列表改成你需要的那些值)
除了loguniform和choice,hp中的参数空间还有:uniform(线性空间中均匀随机取值)、quniform(线性离散取值)、qloguniform等
c) 把调参的任务描述为一个以参数为输入的函数
例如,在我的参数空间中有lr, lambda_l2, batch_size这三个参数,我希望最后得到一个最小化测试集的f1指数的模型,可以写成如下的方式(我的代码其实就是训练模型并输出测试集上的f1指数,你把中间的部分改成你的训练代码就行,注意要把参数换成params['batch_size']这种形式):
def trainAmodel(params): #params={'lr':??, 'lambda_l2':??, 'batch_size':??}
global X_train,X_test,Y_test,Y_train
print('Params testing: ', params)
# 创建模型 & 训练模型
model_v1 = V1_utils.modelV1(X_train.shape[1:],params)
opt = tensorflow.keras.optimizers.Adam(lr=params['lr'])
model_v1.compile(loss="binary_crossentropy", metrics=['accuracy'], optimizer=opt)
steps_per_epoch = (np.shape(X_train)[0] + params['batch_size'] - 1) // params['batch_size']
history = model_v1.fit_generator(generator=data_generator(X_train, Y_train, params['batch_size']),
steps_per_epoch=steps_per_epoch,
epochs=30,
verbose=0,
validation_data=(X_test[::20], Y_test[::20]),
)
# 评估模型
testres = model_v1.predict_generator(pre_generator(X_test, 4), verbose=0)
testf1s, cache = V1_utils.fmeasure(Y_test, cvres)
p, r = cache
print("f1 = {}, precision = {}, recall = {}".format(testf1s, p, r))
# 返回关心的指标(越小越好),状态
return {
'loss':-testf1s,
'status':STATUS_OK
}
注意,fmin默认是把指标越小认为表现越好,所以如果指标是f1指数、正确率这种越大越好的,可以加上负号,就变成越小越好。
另外,如果你希望在中途保存表现最好的模型,可以保存最好的表现,实时对比,如果更好就保存新的模型(我就不写了)。
d) 最后调用fmin开始跑不同参数下的模型,并保存。
trials = Trials()
best = fmin(trainAmodel, space, algo=tpe.suggest, max_evals=50, trials=trials)
import numpy as np
filename= 'model/v1/log_v1_4.npz'
np.savez(filename,trails=trials,best=best)
fmin的参数:
max_evals:要跑多少个模型,这个视你的需要,跑的越多肯多越有可能找到表现更好的模型,但是也意味着耗时增加。
algo:我还不清楚,应该是选择参数的算法?我直接用的suggest,也许选择一些算法能提高搜索效率。
3、结果
trials中会保留每一次训练的超参数、模型表现,我们可以根据这些画出模型在参数空间中的表现,帮助我们选择最后的超参数。例如我的这个结果: