本章内容:
- 如何使用Bayes_opt实现参数优化,及案例?
- 如何使用HyperOpt实现参数优化,及案例?
- 如何使用Optuna实现参数优化,及案例?
HPO库 | 优劣评价 | 推荐指数 |
---|---|---|
bayes_opt | ?实现基于高斯过程的贝叶斯优化 ?当参数空间由大量连续型参数构成时?包含大量离散型参数时避免使用?算力/时间稀缺时避免使用 | |
hyperopt | ?实现基于TPE的贝叶斯优化?支持各类提效工具?进度条清晰,展示美观,较少怪异警告或报错?可推广/拓展至深度学习领域?不支持基于高斯过程的贝叶斯优化?代码限制多、较为复杂,灵活性较差 | |
optuna | ?(可能需结合其他库)实现基于各类算法的贝叶斯优化?代码最简洁,同时具备一定的灵活性?可推广/拓展至深度学习领域?非关键性功能维护不佳,有怪异警告与报错 |
📖 以上三个库都不支持基于Python环境的并行或加速,大多数优化算法库只能够支持基于数据库(如MangoDB,mySQL)的并行或加速,但以上库都可以被部署在分布式计算平台。
关于贝叶斯参数优化实现方式,需要了解的几点:
- 贝叶斯优化需要自定义目标函数、参数空间、优化器,通常不直接调库;
- 不同的贝叶斯方式下,定义目标函数、参数空间、优化器的规则不同,各有自己的规则
基于以上两点,下面介绍三种HPO库时,主要内容为①介绍自定义的规则,②案例的整个流程;
另外以下案例中,弱评估器均采用随机森林。
📖 使用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对目标函数的规则
-
目标函数的输入必须是具体的超参数,而不能是整个超参数空间,更不能是数据、算法等超参数以外的元素。因此在定义目标函数时,我们需要让超参数作为目标函数的输入。
示例:括号内必须是弱评估器的超参数 -
超参数的输入值只能是浮点数,不支持整数与字符串。因此当算法的实际参数需要输入字符串时,该参数不能使用bayes_opt进行调整,当算法的实际参数需要输入整数时,则需要在目标函数中规定参数的类型。
示例:括号里的超参数只能是浮点数:比如随机森林的参数criterion输入内容为‘gini’,这就是字符串,所以criterion这个参数不能放到里面。示例:整数参数需要在设定时改为浮点数格式,如红色部分所示:树的棵数只能是整数,所以需要在设定时使用int()改为浮点数。
-
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
- 🗣 自定义随机森林模型和交叉验证模型,返回测试集的根均方误差
- 🗣 自定义优化器
- 🗣 自定义最优参数验证
- 🗣 运行
📖 HyperOpt特点
- 最通用优化器;
- 运行时间(越小越好):HyperOpt<bayes_opt<随机网格搜索<网格搜索
- 模型效果(越大越好):HyperOpt>bayes_opt>随机网格搜索>网格搜索;
- 代码精密度要求较高、灵活性较差,略微的改动就可能让代码疯狂报错难以跑通。
- 相比基于高斯过程的贝叶斯优化,基于高斯混合模型的TPE在大多数情况下以更高效率获得更优结果;
- HyperOpt所支持的优化算法也不够多。如果专注地使用TPE方法,则掌握HyperOpt即可,更深入可接触Optuna库。
2.1 📖 HyperOpt对目标函数的规则
- 目标函数的参数空间输入必须是符合hyperopt规定的字典
- Hyperopt只支持寻找𝑓(𝑥)的最小值,不支持寻找最大值
2.2 📖 HyperOpt对参数空间的规则
📖 HyperOpt定义参数空间,有如下几种字典形式
- hp.quniform(“参数名称”, 下界, 上界, 步长) - 适用于均匀分布的浮点数
- hp.uniform(“参数名称”,下界, 上界) - 适用于随机分布的浮点数
- hp.randint(“参数名称”,上界) - 适用于[0,上界)的整数,区间为前闭后开
- hp.choice(“参数名称”,[“字符串1”,“字符串2”,…]) - 适用于字符串类型,最优参数由索引表示
- hp.choice(“参数名称”,[*range(下界,上界,步长)]) - 适用于整数型,最优参数由索引表示
- hp.choice(“参数名称”,[整数1,整数2,整数3,…]) - 适用于整数型,最优参数由索引表示
- hp.choice(“参数名称”,[“字符串1”,整数1,…]) - 适用于字符与整数混合,最优参数由索引表示
如无特殊说明,hp中的参数空间定义方法应当都为前闭后开区间。
HyperOpt定义参数空间,选择字典形式的思路:
- 对于需要取整数的参数值,采用quniform方式构筑参数空间。
- quniform能获得均匀分布的浮点数来替代整数;
- 需要在目标函数中使用int函数限定输入类型。例如,在范围[0,5]中取值时,可以取出[0.0, 1.0, 2.0, 3.0,…]这种均匀浮点数,在输入目标函数时,则必须确保参数值前存在int函数。如果使用hp.choice则不会存在该问题。
- hp.choice最终会返回最优参数的索引,容易与数值型参数的具体值混淆,用于字符串;
- hp.randint只能够支持从0开始进行计数。
2.3 📖HyperOpt的优化器介绍
📖 HyperOpt优化目标函数时,涉及的功能/库
- fmin:用于优化的基础功能
- 在fmin中,我们可以自定义使用的代理模型(参数algo),一般来说我们有tpe.suggest以及rand.suggest两种选项,前者指代TPE方法,后者指代随机网格搜索方法。
- partial:修改算法涉及到的具体参数
- 包括模型具体使用了多少个初始观测值(参数n_start_jobs),以及在计算采集函数值时究竟考虑多少个样本(参数n_EI_candidates)。
- trials:记录整个迭代过程
- 一般输入从hyperopt库中导入的方法Trials()
- 当优化完成之后,可以从保存好的trials中查看损失、参数等各种中间信息;
- early_stop_fn:提前停止
- 一般输入从hyperopt库导入的方法no_progress_loss()
- 这个方法中可以输入具体的数字n,表示当损失连续n次没有下降时,让算法提前停止。
- 由于贝叶斯方法的随机性较高,当样本量不足时需要多次迭代才能够找到最优解,因此一般no_progress_loss()中的数值不会设置得太高。在我们的课程中,由于数据量较少,我设置了一个较高的值来避免迭代停止太早。
2.4 🗣 案例:HyperOpt参数优化_房价数据集_python
- 🗣 设定参数空间
- 🗣 设定目标函数
- 🗣 设定优化过程
- 🗣 设定验证函数
- 🗣 执行实际优化流程
📖 Optuna的特点
- Optuna的优势在于,可以无缝衔接到PyTorch、Tensorflow等深度学习框架上,也可以与sklearn的优化库scikit-optimize结合使用,因此Optuna可以被用于各种各样的优化场景。
- 基于高斯过程的贝叶斯优化比基于TPE的贝叶斯优化运行更加缓慢。
- 不支持提前停止;
- Optuna可能存在抽样BUG,即持续抽到曾经被抽到过的参数组合,并显示警告,这时的迭代可能无效。可以考虑增大参数空间的范围或密度以消除该问题。
3.1 📖 Optuna对目标函数、参数空间的规则
- 不需要将参数或参数空间输入目标函数,而是需要直接在目标函数中定义参数空间
- Optuna优化器会生成一个指代备选参数的变量trial,该变量无法被用户获取或打开,但该变量在优化器中生存,并被输入目标函数。在目标函数中,我们可以通过变量trail所携带的方法来构造参数空间。
- 既可以输出 f ( x ) f(x) f(x)的最大值,也可以输出最小值
3.2 📖 Optuna的优化器介绍
- 调整参数algo来自定义用于执行贝叶斯优化的具体算法;
- 设置样本抽样的算法为TPE,比GP(高斯)迭代速度更快。