本章内容:
- 如何使用Bayes_opt实现参数优化,及案例?
- 如何使用HyperOpt实现参数优化,及案例?
- 如何使用Optuna实现参数优化,及案例?
HPO库 | 优劣评价 | 推荐指数 |
---|---|---|
bayes_opt | ✅实现基于高斯过程的贝叶斯优化 ✅当参数空间由大量连续型参数构成时⛔包含大量离散型参数时避免使用⛔算力/时间稀缺时避免使用 | ⭐⭐ |
hyperopt | ✅实现基于TPE的贝叶斯优化✅支持各类提效工具✅进度条清晰,展示美观,较少怪异警告或报错✅可推广/拓展至深度学习领域⛔不支持基于高斯过程的贝叶斯优化⛔代码限制多、较为复杂,灵活性较差 | ⭐⭐⭐⭐ |
optuna | ✅(可能需结合其他库)实现基于各类算法的贝叶斯优化✅代码最简洁,同时具备一定的灵活性✅可推广/拓展至深度学习领域⛔非关键性功能维护不佳,有怪异警告与报错 | ⭐⭐⭐⭐ |
📖 以上三个库都不支持基于Python环境的并行或加速,大多数优化算法库只能够支持基于数据库(如MangoDB,mySQL)的并行或加速,但以上库都可以被部署在分布式计算平台。
关于贝叶斯参数优化实现方式,需要了解的几点:
- 贝叶斯优化需要自定义目标函数、参数空间、优化器,通常不直接调库;
- 不同的贝叶斯方式下,定义目标函数、参数空间、优化器的规则不同,各有自己的规则
基于以上两点,下面介绍三种HPO库时,主要内容为①介绍自定义的规则,②案例的整个流程;
另外以下案例中,弱评估器均采用随机森林。
1 基于Bayes_opt实现GP优化
📖 使用Bayes_opt时,通常为以下情况:
- 当且仅当必须要实现基于高斯过程的贝叶斯优化时;
- 算法的参数空间中有大量连续型参数;
因为bayes_opt对参数空间的处理方法较原始,缺乏相应的提升/监控供销,对算力的要求较高,往往不是调参的第一选择。
📖 bayes_opt特点
- 运行时间(越小越好):bayes_opt<随机网格搜索<网格搜索
- 模型效果(越大越好):bayes_opt>随机网格搜索>网格搜索
- 优化过程无法复现,但优化结果可以复现
- 效率不足。
实际上在迭代到170次时,贝叶斯优化就已经找到了最小损失,但由于没有提前停止机制,模型还持续地迭代了130次才停下,如果bayes_opt支持提前停止机制,贝叶斯优化所需的实际迭代时间可能会更少。
同时,由于Bayes_opt只能够在参数空间提取浮点数,bayes_opt在随机森林上的搜索效率是较低的,即便在10次不同的迭代中分别取到了[88.89, 88.23……]等值,在取整后只能获得一个备选值88,但bayes_opt无法辨别这种区别,因此可能取出了众多无效的观测点。如果使用其他贝叶斯优化器,贝叶斯优化的效率将会更高。 - 支持灵活修改采集函数与高斯过程中的种种参数,详细介绍可参考:https://github.com/fmfn/BayesianOptimization/blob/master/examples/advanced-tour.ipynb
1.1 📖 bayes_opt对目标函数的规则
-
目标函数的输入必须是具体的超参数,而不能是整个超参数空间,更不能是数据、算法等超参数以外的元素。因此在定义目标函数时,我们需要让超参数作为目标函数的输入。
示例:括号内必须是弱评估器的超参数def bayesopt_objective(n_estimators,max_depth):
-
超参数的输入值只能是浮点数,不支持整数与字符串。因此当算法的实际参数需要输入字符串时,该参数不能使用bayes_opt进行调整,当算法的实际参数需要输入整数时,则需要在目标函数中规定参数的类型。
示例:括号里的超参数只能是浮点数:比如随机森林的参数criterion输入内容为‘gini’,这就是字符串,所以criterion这个参数不能放到里面。def bayesopt_objective(n_estimators,max_depth):
示例:整数参数需要在设定时改为浮点数格式,如红色部分所示:树的棵数只能是整数,所以需要在设定时使用int()改为浮点数。
def bayesopt_objective(n_estimators): model=RFR(n_estimators=int(n_estimators)
-
bayes_opt只支持寻找𝑓(𝑥)的最大值,不支持寻找最小值。因此当定义的目标函数是某种损失时,目标函数的输出需要取负(即,如果使用RMSE,则应该让目标函数输出负RMSE,这样最大化负RMSE后,才是最小化真正的RMSE。)当定义的目标函数是准确率,或者auc等指标,则可以让目标函数的输出保持原样。
1.2 📖 bayes_opt对参数空间的规则
- 必须使用字典方式来定义参数空间,其中键为参数名称,值为参数的取值范围;
- 只支持填写参数空间的上界与下界,不支持填写步长等参数,且为双向闭区间;
- 会将所有参数都当作连续型超参进行处理,因此bayes_opt会直接取出闭区间中任意浮点数作为备选参数(这也是设定目标函数时,为什么要int()的原因)。
由于以上规则,输入bayes_opt的参数空间天生会比其他贝叶斯优化库更大/更密,因此需要的迭代次数也更多。
1.3 📖 bayes_opt的随机性注意事项
- 随机性无法控制。即使填写随机数种子,优化算法每次运行一定都会不一样,即优化算法无法被复现。
- 最佳超参数的结果可以被复现。
取出最佳参数组合以及最佳分数,该最佳参数组合被输入到交叉验证中后,是一定可以复现其最佳分数的。
如果没能复现最佳分数,则是交叉验证过程的随机数种子设置存在问题,或者优化算法的迭代流程存在问题。
1.4 🗣 案例:bayes_opt参数优化_房价数据集_python
# pip install bayesian-optimization
from bayes_opt import BayesianOptimization
from sklearn.ensemble import RandomForestRegressor as RFR
from sklearn.model_selection import KFold,cross_validate
- 🗣 自定义随机森林模型和交叉验证模型,返回测试集的根均方误差
# 自定义随机森林模型和交叉验证模型,返回测试集的根均方误差
def bayesopt_objective(n_estimators,max_depth,max_features,min_impurity_decrease):
model=RFR(n_estimators=int(n_estimators)
,max_depth=int(max_depth)
,max_features=int(max_features)
,min_impurity_decrease=min_impurity_decrease
,random_state=7
,n_jobs=-1
)
cv=KFold(n_splits=5,shuffle=True,random_state=7)
validation_loss=cross_validate(model
,X,y
,scoring='neg_root_mean_squared_error'
,cv=cv
,n_jobs=-1
,error_score='raise' # 出错时报错,但不停止,如果设置为nan,将停止迭代
)
return np.mean(validation_loss['test_score'])
- 🗣 自定义优化器
# 自定义优化器
def param_bayes_opt(init_points,n_iter):
opt=BayesianOptimization(bayesopt_objective
,param_grid_simple
,random_state=7)
# 使用优化器
opt.maximize(init_points=init_points # 抽取多少个初始观测值
,n_iter=n_iter # 总共观测/迭代次数
)
# 返回优化结果
params_best=opt.max['params'