Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
我的主页
我的Notebooks
我的论文库
我的足迹

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
使用简单的贝叶斯优化进行参数寻优
notebook
Bayesian
中文
notebookBayesian中文
jinyucheng
发布于 2023-09-23
推荐镜像 :Basic Image:bohrium-notebook:2023-04-07
推荐机型 :c2_m4_cpu
赞 2
1
4
使用简单的贝叶斯优化进行参数寻优
目标
背景
主动学习
贝叶斯优化
使用BayesianOptimization库进行贝叶斯优化
一维函数贝叶斯优化
设置目标函数
创建一个贝叶斯优化对象
绘制和可视化算法的每一步

使用简单的贝叶斯优化进行参数寻优

©️ Copyright 2023 @ Authors
作者: 金昱丞 📨
日期:2023-09-23
共享协议:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
快速开始:点击上方的 开始连接 按钮,选择 `bohrium-notebook` 镜像及任何一款节点配置,稍等片刻即可运行。如您遇到任何问题,请联系 bohrium@dp.tech

代码
文本

目标

简单了解贝叶斯优化的应用场景,学习如何使用贝叶斯优化解决实际问题

在学习本教程后,你将能够:

  • 了解贝叶斯优化的应用场景
  • 掌握如何在python中使用贝叶斯优化解决参数寻优问题
代码
文本

背景

在机器学习和实验研究场合,研究者们常常需要进行参数调优。例如,调整机器学习的训练超参数,使算法能够取得最优的效果;或是更改合成实验中不同反应物的配比以获得最优的产率。

主动学习

在大多数场合,对数据进行采样是非常昂贵的,研究者们通常无法对每个超参数组合进行采样,以建立精确的【超参数组合-目标结果】对应关系函数 f(x) 。主动学习提倡最大程度减少标记成本(采样数)的同时,尽可能提高对应关系函数 f(x) 的精度。主动学习的目的是减少不确定性,因此通常建议标记 f(x) 中不确定性最高的点,用方差来度量未标记点的不确定性。

为了找到 f(x) 中不确定性最高的点,我们需要一个代理模型来确定函数在未采样位置的取值。该代理模型应该能足够灵活以对真实函数进行建模。使用高斯过程(GP)是一种常见的选择,这既因为它具有灵活性,又可以为我们提供不确定性估计。

image.png

图1 单次采样可视化。紫色的曲线是 f(x) 的Ground_Truth,黑线和灰色阴影区域表示分布估计的平均值(μ)和不确定性(μ±σ)

通常假设 f(x) 是均匀分布。 每次采样都会提供新的数据点,并根据贝叶斯规则更新代理模型。每次采样更新后,采样点附近的不确定性都会降低,代理模型会更加接近Ground Truth。可以继续添加更多的训练点,从而获得更准确的 f(x) 的估计。但为了尽量减少评估次数,通常选择当前最不确定的位置作为下一次采样的点。通过这种方式,我们可以在几次迭代中估算出真实的分布。

image.png
图2 多次采样迭代可视化

代码
文本

贝叶斯优化

进行主动学习来准确估计 f(x) ,是一种找到最优参数的方法。然而,实际研究中我们往往只关注最优的参数组合,并不关心较差参数组合的效果。这就是贝叶斯优化的核心问题:“根据我们目前所知道的,我们下一步应该评估哪一点?”在主动学习案例中,我们选择了最不确定的点以探索函数。但是在贝叶斯优化中,我们需要平衡探索不确定区域(可能意外地具有最优的参数组合)与关注我们已经知道具有较优参数组合的区域(开发)。

在贝叶斯优化中,通常会使用采集函数来权衡开发和探索之间的联系。采集函数是启发式的,用于评估一个点的理想程度。在每一步中,我们通过优化采集功能来确定下一步要评估的最佳点。然后,我们更新模型并重复此过程以确定要评估的下一个点。

image.png

图3 可视化采集函数(下图),星号为下一个采样点

关于采集函数如何工作,以及更详细的贝叶斯优化细节可以参考此处:Exploring Bayesian Optimization

代码
文本

使用BayesianOptimization库进行贝叶斯优化

本部分介绍如何使用现有的python工具实现贝叶斯优化,详细代码见BayesianOptimization官方github仓库

让我们先过一个简单的例子~

代码
文本
[22]
# 安装BayesianOptimization
!pip install bayesian-optimization

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
代码
文本
[23]
# import必要的python库
from bayes_opt import BayesianOptimization
from bayes_opt import UtilityFunction
import numpy as np

import matplotlib.pyplot as plt
from matplotlib import gridspec
%matplotlib inline
代码
文本

一维函数贝叶斯优化

单个参数的最优值搜索是实验中最常见的场景之一。尽管最小二乘法等方法也可以解决这个问题,但在这里我们尝试用贝叶斯优化来进行参数寻优。

设置目标函数

首先,我们创建一个具有多个局部最大值的一维函数作为这个例子里的目标函数。

需要注意的是,在实践中这个函数是未知的 ,我们只能通过在不同的点上依次对函数进行采样获得这个函数相关的信息。贝叶斯优化的工作原理是构造最适合观测数据的函数的后验分布,并通过平衡探索和开发来选择下一个探测点。

代码
文本
[24]
def target(x):
return np.exp(-(x - 2)**2) + np.exp(-(x - 6)**2/10) + 1/ (x**2 + 1)

x = np.linspace(-2, 10, 10000).reshape(-1, 1)
y = target(x)

plt.plot(x, y);
代码
文本

创建一个贝叶斯优化对象

输入要最大化的目标函数、它的变量及其对应的范围。启动算法需要至少2次初始采样,采样点可以是随机的,也可以是用户定义的。

代码
文本
[25]
optimizer = BayesianOptimization(target, {'x': (-2, 10)}, random_state=27)
代码
文本

在本例中,我们使用上限置信度(UCB)作为采集函数。通过UCB控制采样时探索和开发的平衡。

调整kappa的值可以控制贝叶斯优化的探索与利用的trade-off。kappa越高,说明我们对当前的知识较不置信,需要更多探索。kappa越低,说明我们可以更直接利用当前的知识,进行更直接的优化利用。适当设置kappa可以帮助我们在贝叶斯优化中找到更好的平衡,防止过拟合现有数据,并进行足够的探索试错。

代码
文本
[26]
acq_function = UtilityFunction(kind="ucb", kappa=5)
optimizer.maximize(init_points=2, n_iter=0, acquisition_function = acq_function)
|   iter    |  target   |     x     |
-------------------------------------
| 1         | 0.8198    | 3.109     |
| 2         | 0.746     | 7.775     |
=====================================
代码
文本

绘制和可视化算法的每一步

代码
文本
[27]
# 首先定义两个函数来简化绘图
def posterior(optimizer, x_obs, y_obs, grid):
optimizer._gp.fit(x_obs, y_obs)

mu, sigma = optimizer._gp.predict(grid, return_std=True)
return mu, sigma

def plot_gp(optimizer, x, y):
fig = plt.figure(figsize=(16, 10))
steps = len(optimizer.space)
fig.suptitle(
'Gaussian Process and Utility Function After {} Steps'.format(steps),
fontdict={'size':30}
)
gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1])
axis = plt.subplot(gs[0])
acq = plt.subplot(gs[1])
x_obs = np.array([[res["params"]["x"]] for res in optimizer.res])
y_obs = np.array([res["target"] for res in optimizer.res])
mu, sigma = posterior(optimizer, x_obs, y_obs, x)
axis.plot(x, y, linewidth=3, label='Target')
axis.plot(x_obs.flatten(), y_obs, 'D', markersize=8, label=u'Observations', color='r')
axis.plot(x, mu, '--', color='k', label='Prediction')

axis.fill(np.concatenate([x, x[::-1]]),
np.concatenate([mu - 1.9600 * sigma, (mu + 1.9600 * sigma)[::-1]]),
alpha=.6, fc='c', ec='None', label='95% confidence interval')
axis.set_xlim((-2, 10))
axis.set_ylim((None, None))
axis.set_ylabel('f(x)', fontdict={'size':20})
axis.set_xlabel('x', fontdict={'size':20})
utility_function = UtilityFunction(kind="ucb", kappa=5, xi=0)
utility = utility_function.utility(x, optimizer._gp, 0)
acq.plot(x, utility, label='Utility Function', color='purple')
acq.plot(x[np.argmax(utility)], np.max(utility), '*', markersize=15,
label=u'Next Best Guess', markerfacecolor='gold', markeredgecolor='k', markeredgewidth=1)
acq.set_xlim((-2, 10))
acq.set_ylim((0, np.max(utility) + 0.5))
acq.set_ylabel('Utility', fontdict={'size':20})
acq.set_xlabel('x', fontdict={'size':20})
axis.legend(loc=2, bbox_to_anchor=(1.01, 1), borderaxespad=0.)
acq.legend(loc=2, bbox_to_anchor=(1.01, 1), borderaxespad=0.)
代码
文本

在随机探测两个点后,我们可以拟合一个高斯过程并开始贝叶斯优化过程。可以看到plot_gp(optimizer, x, y),随着我们离观测值越来越远,不确定性也在增加。

代码
文本
[28]
plot_gp(optimizer, x, y)
代码
文本
[29]
# After three steps of GP (and two random points)
optimizer.maximize(init_points=0, n_iter=1)
plot_gp(optimizer, x, y)
代码
文本
[30]
# After two steps of GP (and two random points)
optimizer.maximize(init_points=0, n_iter=1, acquisition_function=acq_function)
plot_gp(optimizer, x, y)
代码
文本
[31]
# After three steps of GP (and two random points)
optimizer.maximize(init_points=0, n_iter=1, acquisition_function=acq_function)
plot_gp(optimizer, x, y)
代码
文本
[32]
# After 4 steps of GP (and two random points)
optimizer.maximize(init_points=0, n_iter=1, acquisition_function=acq_function)
plot_gp(optimizer, x, y)
代码
文本
[33]
# After 5 steps of GP (and two random points)
optimizer.maximize(init_points=0, n_iter=1, acquisition_function=acq_function)
plot_gp(optimizer, x, y)
代码
文本
[34]
# After 6 steps of GP (and two random points)
optimizer.maximize(init_points=0, n_iter=1, acquisition_function=acq_function)
plot_gp(optimizer, x, y)
代码
文本
[35]
# After 7 steps of GP (and two random points)
optimizer.maximize(init_points=0, n_iter=1, acquisition_function=acq_function)
plot_gp(optimizer, x, y)
代码
文本

可以看出经过几轮迭代之后,算法就能非常接近真正的最大值。此外,探索的初始随机点集越大,算法就越不容易因为过于保守而陷入局部极小值。

代码
文本
notebook
Bayesian
中文
notebookBayesian中文
已赞2
本文被以下合集收录
优化
Dion@ᯤ²ᴳ
更新于 2024-06-18
1 篇0 人关注
other
凝聚态平方
更新于 2024-03-18
11 篇0 人关注
推荐阅读
公开
使用简单的贝叶斯优化进行参数寻优副本
notebookBayesian中文
notebookBayesian中文
CyrusZHOU
发布于 2024-03-16
1 赞
公开
Play Around RNA Secondary Structure: Prediction and Visualization of RNA
RNA
RNA
Bohrium小助手
发布于 2023-09-26
1 转存文件