以下内容为该学习地址的学习笔记,是该栏的第二篇
学习地址:Advanced tour of the Bayesian Optimization package — Bayesian Optimization documentation
1. Suggest-Evaluate-Register范式
贝叶斯优化是一种用于优化复杂和昂贵的目标函数的策略,特别适用于函数评估开销高或不可微的情况。它通过构建一个代理模型(通常是高斯过程)来近似目标函数,然后使用这个模型来选择下一个评估点,以期望最大化目标函数。
核心概念
-
代理模型:贝叶斯优化使用高斯过程(GP)作为代理模型,来近似目标函数。代理模型提供了目标函数在所有未评估点上的预测分布。
高斯过程是一种非参数的贝叶斯方法,用于回归和分类任务。它通过假设目标函数的所有可能值都服从一个联合高斯分布,来进行预测。
为什么用GP作为代理模型
- 不确定性估计:GP能够自然地提供预测的不确定性估计,这是选择采集函数时非常有用的信息。每个预测点不仅有一个均值,还有一个方差,表示对这个预测的信心程度。
- 灵活性:GP是一种非参数模型,不需要指定具体的函数形式,只需指定一个协方差函数(核函数)。这使得它能够很好地拟合复杂和非线性的目标函数。
- 良好的性能:在小数据集上,GP通常具有良好的预测性能。对于贝叶斯优化,通常每次评估目标函数的代价很高,因此数据点相对较少,GP在这种情况下表现出色。
-
采集函数:采集函数(如UCB、EI、PI等)根据代理模型提供的信息,选择下一个评估点。采集函数在探索(探索未知区域)和利用(利用已知高值区域)之间进行权衡。
- 探索(Exploration):探索未知区域,即选择那些尚未评估或评估次数较少的点。这样做的目的是发现可能的全局最优解。
- 利用(Exploitation):利用已知的高值区域,即选择那些已经显示出高目标值的点。这样做的目的是在已知的优良区域内进一步优化。
采集函数通过在这两者之间进行权衡,来决定下一个采样点。不同类型的采集函数有不同的平衡策略:
- UCB(Upper Confidence Bound):上置信界采集函数平衡了均值和不确定性,通过调整参数(如
kappa
)来控制探索和利用的比例。 - EI(Expected Improvement):期望改进采集函数评估在某一点上期望的目标值改进量。
- PI(Probability of Improvement):改进概率采集函数评估在某一点上目标值超过当前最优值的概率。
-
黑盒函数:目标函数被视为“黑盒”,即其内部机制未知,只能通过输入-输出对来了解其行为。
在贝叶斯优化中,maximize
方法实际上是对 suggest
、probe
和 register
方法的封装。如果需要对优化循环进行更细粒度的控制,可以使用Suggest-Evaluate-Register范式。
以下是一个关于贝叶斯优化的示例,展示了如何在分布式环境中运行贝叶斯优化,即在不同的核心/机器/服务器上并行评估目标函数。具体可以查看示例文件夹中的 async_optimization.py
脚本。
首先,定义目标函数、参数边界,并实例化优化对象。这个函数是一个简单的二次函数,目的是模拟一个需要优化的复杂函数。
# 定义黑盒函数
def black_box_function(x, y):
return -x ** 2 - (y - 1) ** 2 + 1
注意,黑盒函数的评估不会由优化器对象执行。我们模拟一个情景:黑盒函数可能在不同的机器上执行,可能用不同的语言编写,甚至可能是化学实验的结果。无论具体情况如何,只要不直接调用 probe
或 maximize
方法,优化器对象将忽略黑盒函数。
f=None
:表示优化器不会自动评估目标函数。 通常在贝叶斯优化中,优化器会在内部调用目标函数来评估某个点的目标值。但是,有些情况下我们希望手动控制目标函数的评估过程。例如,目标函数可能在不同的机器上并行计算,或者目标函数的计算非常复杂,需要特别的处理。这时,将f
设为None
,可以让用户自己决定何时以及如何评估目标函数。pbounds
:定义参数的搜索空间,即x
在2
到2
之间,y
在3
到3
之间。这有助于优化器在合理的范围内进行探索,避免在无效或不合理的区域浪费时间和计算资源。 贝叶斯优化需要知道参数的范围,以便在这个范围内进行采样和优化。pbounds
定义了每个参数的上下界。verbose=2
:设定输出信息的详细程度。参数控制优化过程中的日志输出详细程度。常见的取值有:0
:无输出。1
:输出基本信息。2
:输出详细信息,包括每一步优化的结果和状态。
random_state=1
:固定随机种子以保证结果的可重复性。贝叶斯优化中有许多随机过程,例如初始采样点的选择和代理模型中的随机因素。为了确保每次运行的结果一致,可以固定随机种子。这可以确保每次运行代码时,生成的随机数序列是相同的,从而保证优化结果的一致性和可重复性。这对于调试和对比不同优化方案特别重要。
# 实例化贝叶斯优化对象
from bayes_opt import BayesianOptimization
optimizer = BayesianOptimization(
f=None, # 由于我们要手动控制评估过程,这里设置为None
pbounds={'x': (-2, 2), 'y': (-3, 3)}, # 参数边界
verbose=2, # 输出详细程度
random_state=1, # 随机种子,确保结果可复现
)
创建一个采集函数实例:我们还需要一个 UtilityFunction
实例。这个函数用于决定下一次采样的点。
kind="ucb"
:表示使用上置信界(UCB)作为采集函数。kappa=2.5
:UCB的参数,用于调节探索与利用的平衡。xi=0.0
:另一个用于调节采集函数的参数。
# 导入UtilityFunction并实例化
from bayes_opt import UtilityFunction
utility = UtilityFunction(kind="ucb", kappa=2.5, xi=0.0)
使用优化器的 suggest
方法获取下一个需要评估的点:suggest
方法根据当前的代理模型和采集函数,建议下一个评估点。 我们可以随时调用优化器的 suggest
方法。返回的是优化器希望探测的下一个参数组合。
# 获取下一个探测点
next_point_to_probe = optimizer.suggest(utility)
print("Next point to probe is:", next_point_to_probe)
# 输出: Next point to probe is: {'x': -0.331911981189704, 'y': 1.3219469606529488}
你现在可以在建议的点上评估你的函数。
在 Python 中,**
运算符用于将字典解包为关键字参数传递给函数。这对于动态地将参数传递给函数非常有用。当我们调用 black_box_function
时,通常需要传递具体的参数:target = black_box_function(x=-0.331911981189704, y=1.3219469606529488)
。使用 **next_point_to_probe
可以简化这一过程。**
运算符将字典 next_point_to_probe
中的键值对解包为关键字参数传递给函数,如下。
# 在建议的点上评估目标函数
target = black_box_function(**next_point_to_probe)
print("Found the target value to be:", target)
# 输出: Found the target value to be: 0.7861845912690542
将评估结果反馈给优化器:最后一步是告诉优化器在该点上观察到的目标值。
register
方法将评估点及其目标值记录下来,以便优化器更新代理模型。
# 注册评估结果
optimizer.register(
params=next_point_to_probe, # 评估点
target=target, # 评估结果
Suggest-Evaluate-Register范式
贝叶斯优化中的 maximize
方法是对 suggest
、probe
和 register
方法的封装。如果需要更多控制权,可以使用Suggest-Evaluate-Register范式:
- Suggest:获取下一个评估点。
- Evaluate:在建议的点上评估目标函数。
- Register:将评估结果反馈给优化器。
1.1 maximize
循环
贝叶斯优化过程的一个关键部分是 maximize
方法,它通过不断重复以下步骤来优化目标函数:
- 通过采集函数建议下一个评估点。
- 在建议的点上评估目标函数。
- 将评估结果注册到优化器中。
for _ in range(5):
next_point = optimizer.suggest(utility) # 获取下一个评估点
target = black_box_function(**next_point) # 在建议的点上评估目标函数
optimizer.register(params=next_point, target=target) # 将评估结果注册到优化器中
print(target, next_point) # 打印当前评估的目标值和对应的参数点
print(optimizer.max) # 打印找到的最大目标值和对应的参数点
在这个循环中,我们运行5次迭代。在每次迭代中:
- 使用采集函数
suggest
获取下一个评估点。 - 在建议的点上评估目标函数
black_box_function
,并获取目标值。 - 将评估的参数点和目标值注册到优化器中。
- 打印当前评估的目标值和对应的参数点。
最后,我们打印在整个优化过程中找到的最大目标值和对应的参数点。
# 输出:
#-18.49187152919165 {'x': 1.8861546000771092, 'y': -2.9917780942581977}
#0.7911494590443674 {'x': -0.31764604716962586, 'y': 1.3285597809731806}
#-6.999999999999999 {'x': -1.9999999999999998, 'y': 3.0}
#-7.0 {'x': 2.0, 'y': 3.0}
#-7.503866814436659 {'x': -2.0, 'y': -1.1222315647536345}
#{'target': 0.7911494590443674, 'params': {'x': -0.31764604716962586, 'y': 1.3285597809731806}}
完整代码如下:
优化过程:
- 使用
BayesianOptimization
类和UtilityFunction
类进行贝叶斯优化。 - 通过循环迭代进行最大化循环,每次迭代中:
- 使用
optimizer.suggest(utility)
获取下一个评估点。 - 在建议的点上评估
black_box_function
,获取目标值。 - 将评估的参数点和目标值注册到优化器中。
- 打印当前评估的目标值和对应的参数点。
- 使用
- 最后打印找到的最大目标值和对应的参数点 (
optimizer.max
)。
# 定义黑盒函数,接受两个参数x和y,返回计算的目标值
def black_box_function(x, y):
return -x ** 2 - (y - 1) ** 2 + 1
# 从bayes_opt库中导入BayesianOptimization类
from bayes_opt import BayesianOptimization
# 实例化贝叶斯优化对象
optimizer = BayesianOptimization(
f=None, # 设置为None,表示优化器不会自动评估目标函数
pbounds={'x': (-2, 2), 'y': (-3, 3)}, # 定义参数的搜索空间,x在-2到2之间,y在-3到3之间
verbose=2, # 设置输出信息的详细程度为2
random_state=1 # 固定随机种子为1,保证结果的可重复性
)
# 从bayes_opt库中导入UtilityFunction类
from bayes_opt import UtilityFunction
# 实例化一个UCB(上置信界)采集函数对象
utility = UtilityFunction(kind="ucb", kappa=2.5, xi=0.0)
# 进行5次迭代的最大化循环
for _ in range(5):
# 使用采集函数获取下一个评估点
next_point = optimizer.suggest(utility)
# 在建议的点上评估黑盒函数,获取目标值
target = black_box_function(**next_point)
# 将评估的参数点和目标值注册到优化器中
optimizer.register(params=next_point, target=target)
# 打印当前评估的目标值和对应的参数点
print(target, next_point)
# 打印找到的最大目标值和对应的参数点
print(optimizer.max)
在这段代码中(与下面第二点的对比):
- 使用了
UtilityFunction
类来定义一个采集函数(Acquisition Function),例如使用上置信界(Upper Confidence Bound, UCB)作为采集函数。 - 然后通过循环进行多次迭代,在每次迭代中:
- 使用
optimizer.suggest(utility)
基于当前后验分布和采集函数选择下一个评估点。 - 在选定的点上评估目标函数,并将结果注册到优化器中。
- 使用
- 这种方式利用采集函数来在每次迭代中选择下一个评估点,通常是根据探索(Exploration)和开发(Exploitation)的平衡来进行优化。
- 和下面第二个方法比,使用采集函数的方式更加灵活,允许根据具体的采集策略来选择下一个评估点,例如在探索和开发之间寻找平衡。UCB 是一种常用的采集函数,它结合了目标函数的均值和方差,以便在不同的空间区域中进行探索和利用。
2. 处理离散参数的贝叶斯优化discrete parameters
在贝叶斯优化中,通常假设参数是连续的。然而,在实际应用中,有些参数可能只能取离散值(参数只能取整数值或者在有限的几个值中选择)。贝叶斯优化的高斯过程模型对处理离散参数并不是非常直观或容易(高斯过程的贝叶斯优化的性质不允许以简单/直观的方式处理离散参数 ),但我们可以通过一些技巧来实现对离散参数的优化。
- 定义带有离散参数的函数:这个函数
func_with_discrete_params
接受三个参数x
、y
和d
,其中d
是一个离散参数。通过assert
语句确保d
是一个整数。函数的返回值是一个复杂的表达式,用于模拟函数对离散参数的依赖。 - 定义目标函数,将连续变量转换为离散变量:在这个
function_to_be_optimized
函数中,我们将一个连续变量w
转换为离散变量d
,并调用前面定义的func_with_discrete_params
函数。这样做的目的是将优化过程中的连续参数转换为离散参数,从而处理离散参数的问题。 - 导入贝叶斯优化模块并初始化优化器:首先,导入
BayesianOptimization
类。然后,实例化一个BayesianOptimization
对象optimizer
。在这个过程中,指定目标函数f
和参数的搜索空间pbounds
。verbose
参数设定输出信息的详细程度,random_state
用于设置随机种子,以确保结果的可重复性。 - 设置高斯过程的参数:通过
set_gp_params
方法设置高斯过程的参数,这里设置了一个小的alpha
值,以增加模型的稳定性。 - 进行贝叶斯优化
# 定义一个带有离散参数d的函数
def func_with_discrete_params(x, y, d):
# 确保d是一个整数
assert type(d) == int
# 返回函数值,模拟d必须是离散的需求
return ((x + y + d) // (1 + d)) / (1 + (x + y) ** 2)
# 定义目标函数,包含一个离散参数w
def function_to_be_optimized(x, y, w):
d = int(w) # 将连续变量w转换为离散变量d
return func_with_discrete_params(x, y, d) # 调用包含离散参数的函数
# 导入贝叶斯优化模块中的BayesianOptimization类
from bayes_opt import BayesianOptimization
# 实例化贝叶斯优化对象
optimizer = BayesianOptimization(
f=function_to_be_optimized, # 设置目标函数
pbounds={'x': (-10, 10), 'y': (-10, 10), 'w': (0, 5)}, # 定义参数的搜索空间
verbose=2, # 设置输出信息的详细程度
random_state=1 # 固定随机种子以保证结果的可重复性
)
# 设置高斯过程的参数
optimizer.set_gp_params(alpha=1e-3)
# 进行贝叶斯优化
optimizer.maximize()
# 输出每次迭代的结果,如下为输出
| iter | target | w | x | y |
-------------------------------------------------------------
| 1 | -0.06199 | 2.085 | 4.406 | -9.998 |
| 2 | -0.0344 | 1.512 | -7.065 | -8.153 |
| 3 | -0.2177 | 0.9313 | -3.089 | -2.065 |
| 4 | 0.1865 | 2.694 | -1.616 | 3.704 |
| 5 | -0.2187 | 1.022 | 7.562 | -9.452 |
| 6 | 0.1868 | 2.533 | -1.728 | 3.815 |
| 7 | 0.05119 | 3.957 | -0.6151 | 6.785 |
| 8 | 0.1761 | 0.5799 | 1.181 | 4.054 |
| 9 | 0.04045 | 4.004 | 4.304 | 2.656 |
| 10 | 0.07509 | 0.0 | 4.843 | 7.759 |
| 11 | 0.3512 | 0.0 | -5.713 | 7.072 |
| 12 | -0.8068 | 0.0 | -9.09 | 8.6 |
| 13 | 0.3774 | 0.3974 | -4.19 | 6.264 |
| 14 | 0.157 | 0.0 | -3.587 | 8.534 |
| 15 | -0.7891 | 0.4794 | -5.536 | 4.298 |
| 16 | 0.1176 | 1.038 | -4.671 | 7.41 |
| 17 | 0.1815 | 0.4815 | -2.66 | 6.6 |
| 18 | 0.08677 | 1.933 | -0.1438 | 4.839 |
| 19 | 0.1687 | 1.139 | -0.4707 | 2.69 |
| 20 | 0.1133 | 2.363 | 1.344 | 2.736 |
| 21 | 0.2401 | 0.0 | 1.441 | 1.949 |
| 22 | 0.1568 | 0.1832 | 3.2 | 2.904 |
| 23 | 0.2722 | 0.9731 | 2.625 | 0.5406 |
| 24 | 0.0 | 1.149 | 0.7191 | 0.2267 |
| 25 | 0.1686 | 0.0 | 4.181 | 0.5867 |
| 26 | 0.0644 | 2.276 | 3.975 | -0.1631 |
| 27 | 0.4397 | 0.08737 | 2.66 | -1.531 |
| 28 | 0.2904 | 0.0 | 3.913 | -2.35 |
| 29 | -0.9874 | 0.0 | 1.992 | -3.005 |
| 30 | 0.3001 | 0.2116 | 3.375 | -0.9955 |
=============================================================
每次迭代的结果会输出到控制台,包括目标值和对应的参数组合。通过不断迭代,贝叶斯优化能够找到使目标函数最大化的参数组合。
为什么这样可以处理离散参数?
- 连续优化:贝叶斯优化在连续空间中进行,对参数
w
进行优化。 - 离散转换:在每次评估目标函数时,将连续参数
w
转换为离散参数d
,确保评估过程符合离散参数的要求。 - 平衡性:这种方法保留了贝叶斯优化在连续空间中的优势,同时在评估时满足了离散参数的约束。
在这段代码中:
- 通过
optimizer.set_gp_params(alpha=1e-3)
来设置高斯过程的参数,然后直接调用optimizer.maximize()
方法来执行贝叶斯优化过程。 - 这种方式的核心是使用高斯过程(Gaussian Process, GP)作为后验模型,通过最大化后验概率来进行优化。GP会根据初始数据集和每次迭代的新观测结果更新后验分布,以便更好地预测未知区域的目标函数值。
- 直接调用
maximize()
方法的方式更加直接,它使用了贝叶斯优化的核心思想,即通过高斯过程建模目标函数,并在每次迭代中尝试最大化后验概率,从而找到最优解。
3. 调整底层高斯过程Tuning the underlying Gaussian Process
贝叶斯优化算法利用高斯过程回归来优化参数空间中的目标函数。这种方法基于已观察到的参数组合及其对应的目标值,通过高斯过程建立了一个预测模型。这个模型不仅预测目标函数在参数空间中的表现,还提供了预测的不确定性信息。这些预测用于指导下一步探索的最佳点。
3.1 Passing parameters to the GP向 GP 传递参数
有时根据具体问题的需求,调整基础高斯过程的默认参数可能会提高优化效果。您可以使用 optimizer.set_gp_params
方法来实现这一点:
# 导入贝叶斯优化模块中的BayesianOptimization类
from bayes_opt import BayesianOptimization
# 定义黑盒函数
def black_box_function(x, y):
return -x ** 2 - (y - 1) ** 2 + 1
# 实例化贝叶斯优化对象
optimizer = BayesianOptimization(
f=black_box_function, # 设置优化的目标函数为 black_box_function
pbounds={'x': (-2, 2), 'y': (-3, 3)}, # 设置参数的搜索空间,x 在 -2 到 2 之间,y 在 -3 到 3 之间
verbose=2, # 设置优化过程的输出详细程度为2
random_state=1, # 设置随机种子以保证结果的可重复性
)
# 设置高斯过程的参数
optimizer.set_gp_params(alpha=1e-3, n_restarts_optimizer=5)
# 最大化优化过程
optimizer.maximize(
init_points=1, # 初始探索点的数量
n_iter=5 # 迭代优化的次数
)
- 贝叶斯优化算法通过建立一个高斯过程模型来模拟目标函数在参数空间中的行为。这个模型不仅预测目标函数的值,还提供了每个预测的置信度。
optimizer.set_gp_params
允许调整高斯过程的参数,例如alpha
控制高斯过程的噪声水平,n_restarts_optimizer
控制优化器重新启动的次数。
3.2 调整alpha
参数
对于具有离散参数或者目标空间表现不稳定的函数,增加 alpha
参数的值可能是有益的。这个参数控制高斯过程模型对噪声的容忍程度,因此增加它可以增强模型的灵活性,使其能够更好地适应噪声和不确定性。
3.3 更换内核Changing kernels
默认情况下,贝叶斯优化使用 Matern 2.5 核函数。根据您的具体应用场景,调整高斯过程的核函数可能对优化结果有显著影响。这需要根据具体问题选择合适的核函数,可以参考 scikit-learn 文档了解更多详细信息。学习地址:https://scikit-learn.org/stable/modules/gaussian_process.html#kernels-for-gaussian-processes。
Observers Continued
观察者是订阅和监听事件的对象:观察者是一种设计模式,用于订阅并监听由贝叶斯优化对象触发的特定事件。在贝叶斯优化过程中,例如在每一步优化、优化开始或结束时,会触发不同类型的事件。(观察者是一种设计模式,它允许一个对象(观察者)订阅另一个对象(主体,即贝叶斯优化对象)的事件。当事件发生时,观察者会收到通知,并执行预先定义的操作。)
事件触发时调用回调函数:当某个事件被触发时,系统会调用预先注册的回调函数来处理这个事件。回调函数的定义包括了对事件发生时的响应和处理逻辑。这些回调函数能够使用到两个重要的参数:事件本身和贝叶斯优化BayesianOptimization
的实例。
回调函数的指定和查找:可以在订阅时指定回调。如果没有指定,它将update
从观察者那里寻找方法。(用户可以在订阅事件的同时指定特定的回调函数。如果在订阅时没有显式地指定回调函数,系统将默认查找观察者对象中的 update
方法作为回调函数。这种设计使得观察者能够作为事件的处理者,即使没有显式定义特定的回调函数。)
通过这种方式,贝叶斯优化算法可以将不同的事件通知给订阅者,订阅者则根据事件类型执行相应的操作。
# 导入必要的模块和类
from bayes_opt.event import DEFAULT_EVENTS, Events
from bayes_opt import BayesianOptimization
# 1.
# 定义黑盒函数(示例中使用的目标函数)
def black_box_function(x, y):
return -x ** 2 - (y - 1) ** 2 + 1
# 实例化贝叶斯优化对象
optimizer = BayesianOptimization(
f=black_box_function, # 设置优化的目标函数为 black_box_function
pbounds={'x': (-2, 2), 'y': (-3, 3)}, # 设置参数的搜索空间,x 在 -2 到 2 之间,y 在 -3 到 3 之间
verbose=2, # 设置输出详细程度为2
random_state=1, # 设置随机种子以保证结果的可重复性
)
# 定义一个基本的观察者类
class BasicObserver:
def update(self, event, instance):
"""处理事件和 `BayesianOptimization` 实例的方法."""
print("Event `{}` was observed".format(event))
# 实例化基本观察者对象
my_observer = BasicObserver()
# 订阅优化步骤事件(OPTIMIZATION_STEP),并使用观察者对象 `my_observer` 进行订阅
optimizer.subscribe(
event=Events.OPTIMIZATION_STEP, # 订阅优化步骤事件
subscriber=my_observer, # 使用 `my_observer` 作为订阅者
callback=None, # 使用默认的 `update` 方法作为回调函数
)
# 2. 另外,您可以选择传递完全不同的回调函数作为事件的处理函数
def my_callback(event, instance):
#print("在这里自定义操作!")
print("Go nuts here!")
# 订阅优化开始事件(OPTIMIZATION_START),并传入自定义的回调函数 `my_callback`
optimizer.subscribe(
event=Events.OPTIMIZATION_START, # 订阅优化开始事件
subscriber="Any hashable object", # 任何可散列对象都可以作为订阅者
callback=my_callback, # 使用 `my_callback` 作为回调函数
)
# 最大化贝叶斯优化过程,初始化1个探索点,迭代2次
optimizer.maximize(init_points=1, n_iter=2)
#输出结果
#Go nuts here!
#Event `optimization:step` was observed
#Event `optimization:step` was observed
#Event `optimization:step` was observed
# 输出所有默认事件的列表,您可以查看所有默认事件的列表DEFAULT_EVENTS
print("所有默认事件列表:", DEFAULT_EVENTS)
# 输出结果:['optimization:start', 'optimization:step', 'optimization:end']
- 导入模块和类:从
bayes_opt
包中导入所需的类和模块,包括BayesianOptimization
和事件相关的类。 - 定义黑盒函数:这是贝叶斯优化中要优化的目标函数示例。
- 实例化贝叶斯优化对象:创建一个
BayesianOptimization
对象,设置目标函数、参数搜索空间、输出详细程度和随机种子。 - 定义基本观察者类:创建一个简单的观察者类,其中包含一个
update
方法,用于处理观察到的事件。 - 实例化观察者对象:创建一个基本观察者对象
my_observer
。 - 订阅优化步骤事件:使用
subscribe
方法订阅优化步骤事件OPTIMIZATION_STEP
,并指定my_observer
作为订阅者。 - 自定义回调函数:定义了一个自定义的回调函数
my_callback
,用于处理优化开始事件OPTIMIZATION_START
。 - 订阅优化开始事件:使用
subscribe
方法订阅优化开始事件OPTIMIZATION_START
,并传入my_callback
作为回调函数。 - 最大化优化过程:调用
maximize
方法开始贝叶斯优化过程,初始化1个探索点并进行2次迭代。 - 自定义操作输出:在回调函数中输出了一条自定义消息。
- 观察到的事件输出:输出了多条观察到的事件消息。
- 默认事件列表输出:输出了所有默认事件的列表。