使用简单的贝叶斯优化进行参数寻优
©️ Copyright 2023 @ Authors
作者:
金昱丞 📨
日期:2023-09-23
共享协议:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
快速开始:点击上方的 开始连接 按钮,选择 `bohrium-notebook` 镜像及任何一款节点配置,稍等片刻即可运行。如您遇到任何问题,请联系 bohrium@dp.tech 。
目标
简单了解贝叶斯优化的应用场景,学习如何使用贝叶斯优化解决实际问题
在学习本教程后,你将能够:
- 了解贝叶斯优化的应用场景
- 掌握如何在python中使用贝叶斯优化解决参数寻优问题
背景
在机器学习和实验研究场合,研究者们常常需要进行参数调优。例如,调整机器学习的训练超参数,使算法能够取得最优的效果;或是更改合成实验中不同反应物的配比以获得最优的产率。
主动学习
在大多数场合,对数据进行采样是非常昂贵的,研究者们通常无法对每个超参数组合进行采样,以建立精确的【超参数组合-目标结果】对应关系函数 f(x) 。主动学习提倡最大程度减少标记成本(采样数)的同时,尽可能提高对应关系函数 f(x) 的精度。主动学习的目的是减少不确定性,因此通常建议标记 f(x) 中不确定性最高的点,用方差来度量未标记点的不确定性。
为了找到 f(x) 中不确定性最高的点,我们需要一个代理模型来确定函数在未采样位置的取值。该代理模型应该能足够灵活以对真实函数进行建模。使用高斯过程(GP)是一种常见的选择,这既因为它具有灵活性,又可以为我们提供不确定性估计。
通常假设 f(x) 是均匀分布。 每次采样都会提供新的数据点,并根据贝叶斯规则更新代理模型。每次采样更新后,采样点附近的不确定性都会降低,代理模型会更加接近Ground Truth。可以继续添加更多的训练点,从而获得更准确的 f(x) 的估计。但为了尽量减少评估次数,通常选择当前最不确定的位置作为下一次采样的点。通过这种方式,我们可以在几次迭代中估算出真实的分布。
贝叶斯优化
进行主动学习来准确估计 f(x) ,是一种找到最优参数的方法。然而,实际研究中我们往往只关注最优的参数组合,并不关心较差参数组合的效果。这就是贝叶斯优化的核心问题:“根据我们目前所知道的,我们下一步应该评估哪一点?”在主动学习案例中,我们选择了最不确定的点以探索函数。但是在贝叶斯优化中,我们需要平衡探索不确定区域(可能意外地具有最优的参数组合)与关注我们已经知道具有较优参数组合的区域(开发)。
在贝叶斯优化中,通常会使用采集函数来权衡开发和探索之间的联系。采集函数是启发式的,用于评估一个点的理想程度。在每一步中,我们通过优化采集功能来确定下一步要评估的最佳点。然后,我们更新模型并重复此过程以确定要评估的下一个点。
关于采集函数如何工作,以及更详细的贝叶斯优化细节可以参考此处:Exploring Bayesian Optimization
使用BayesianOptimization库进行贝叶斯优化
本部分介绍如何使用现有的python工具实现贝叶斯优化,详细代码见BayesianOptimization官方github仓库
让我们先过一个简单的例子~
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple Requirement already satisfied: bayesian-optimization in /opt/conda/lib/python3.8/site-packages (1.4.3) Requirement already satisfied: scikit-learn>=0.18.0 in /opt/conda/lib/python3.8/site-packages (from bayesian-optimization) (1.0.2) Requirement already satisfied: scipy>=1.0.0 in /opt/conda/lib/python3.8/site-packages (from bayesian-optimization) (1.7.3) Requirement already satisfied: numpy>=1.9.0 in /opt/conda/lib/python3.8/site-packages (from bayesian-optimization) (1.22.4) Requirement already satisfied: colorama>=0.4.6 in /opt/conda/lib/python3.8/site-packages (from bayesian-optimization) (0.4.6) Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/lib/python3.8/site-packages (from scikit-learn>=0.18.0->bayesian-optimization) (3.1.0) Requirement already satisfied: joblib>=0.11 in /opt/conda/lib/python3.8/site-packages (from scikit-learn>=0.18.0->bayesian-optimization) (1.2.0) WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
一维函数贝叶斯优化
单个参数的最优值搜索是实验中最常见的场景之一。尽管最小二乘法等方法也可以解决这个问题,但在这里我们尝试用贝叶斯优化来进行参数寻优。
设置目标函数
首先,我们创建一个具有多个局部最大值的一维函数作为这个例子里的目标函数。
需要注意的是,在实践中这个函数是未知的 ,我们只能通过在不同的点上依次对函数进行采样获得这个函数相关的信息。贝叶斯优化的工作原理是构造最适合观测数据的函数的后验分布,并通过平衡探索和开发来选择下一个探测点。
创建一个贝叶斯优化对象
输入要最大化的目标函数、它的变量及其对应的范围。启动算法需要至少2次初始采样,采样点可以是随机的,也可以是用户定义的。
在本例中,我们使用上限置信度(UCB)作为采集函数。通过UCB控制采样时探索和开发的平衡。
调整kappa的值可以控制贝叶斯优化的探索与利用的trade-off。kappa越高,说明我们对当前的知识较不置信,需要更多探索。kappa越低,说明我们可以更直接利用当前的知识,进行更直接的优化利用。适当设置kappa可以帮助我们在贝叶斯优化中找到更好的平衡,防止过拟合现有数据,并进行足够的探索试错。
| iter | target | x | ------------------------------------- | 1 | 0.8198 | 3.109 | | 2 | 0.746 | 7.775 | =====================================
绘制和可视化算法的每一步
在随机探测两个点后,我们可以拟合一个高斯过程并开始贝叶斯优化过程。可以看到plot_gp(optimizer, x, y),随着我们离观测值越来越远,不确定性也在增加。
可以看出经过几轮迭代之后,算法就能非常接近真正的最大值。此外,探索的初始随机点集越大,算法就越不容易因为过于保守而陷入局部极小值。