news 2026/9/20 8:37:26

在 Ray Tune 中使用 BayesOptSearch 进行贝叶斯超参数优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 Ray Tune 中使用 BayesOptSearch 进行贝叶斯超参数优化

在 Ray Tune 中使用 BayesOptSearch 进行贝叶斯超参数优化

【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray

导读

本文围绕 Ray Tune 官方示例 bayesopt_example.py(对应文档 bayesopt_example.rst 与配套 Notebook bayesopt_example.ipynb),完整讲解如何将bayesian-optimization库的高斯过程贝叶斯优化集成到 Ray Tune 中,用BayesOptSearch搜索算法自动寻找最优超参数。读完本文,你将掌握:环境安装与版本约束、目标函数与搜索空间的组织方式、BayesOptSearch全部核心参数(utility 函数、并发限制、随机初始化步数、收敛提前终止等)的语义与默认值,以及与AsyncHyperBandScheduler调度器组合使用的完整可运行代码,并能对照 搜索算法源码 理解底层实现原理。

BayesOpt 与 Ray Tune 的集成方式

什么是 BayesOptSearch

BayesOptSearch是 Ray Tune 为bayesian-optimization库(pip 包名bayesian-optimization,类名为bayes_opt.BayesianOptimization)封装的搜索算法(Searcher),代码位于 python/ray/tune/search/bayesopt/bayesopt_search.py。

从原理上讲,BayesianOptimization是一个基于高斯过程(Gaussian Process)的受限全局优化工具,核心目标是用尽可能少的迭代次数逼近未知函数的最大值(Ray Tune 内部通过_metric_op符号翻转支持最小化目标,见源码第 205-208 行)。它属于"无导数"(derivative-free)与"黑盒"(black-box)优化范畴,特别适合目标函数评估代价高昂、需要权衡探索(exploration)与利用(exploitation)的场景。

Ray Tune 的定位是"优化任意显式或隐式目标函数"——超参数调优只是最常见的应用。BayesOptSearch在 Tune 中扮演"搜索算法"(Search Algorithm)角色,负责根据历史 trial 的结果建议下一组超参数配置;它通常与"调度器"(Scheduler,如提前停止低效 trial 的AsyncHyperBandScheduler)协同工作。在 doc/source/tune/key-concepts.rst 的搜索算法总览表中,BayesOptSearch被归类为"Bayesian Optimization"类集成,官方推荐示例即本文所讲的 bayesopt_example。

安装与版本约束

示例源码 docstring 与BayesOptSearch.__init__中的断言均明确要求先安装 BayesOpt 库:

pip install bayesian-optimization==1.4.3

需要说明的是,仓库内不同文档记录的版本号并不完全一致:

  • bayesopt_search.py 与构造函数断言中推荐bayesian-optimization==1.4.3
  • 配套 Notebook bayesopt_example.ipynb 中安装命令为!pip install -q bayesian-optimization==1.2.0 "ray[tune]"(该 Notebook 生成于 2022 年,属于历史运行环境)。

实际使用时建议以当前仓库源码标注的1.4.3为准,同时通过pip install "ray[tune]"安装 Ray Tune。若未安装 BayesOpt,构造BayesOptSearch会直接抛出断言错误(源码第 168-171 行),提示安装命令。

完整示例:最小化一个简单目标函数

以下代码来自 python/ray/tune/examples/bayesopt_example.py,是官方文档通过literalinclude直接嵌入到 RST 中的正文(见 bayesopt_example.rst),它同时验证了BayesOptSearch可以与其他调度器(此处为AsyncHyperBandScheduler)组合使用:

"""This example demonstrates the usage of BayesOpt with Ray Tune. It also checks that it is usable with a separate scheduler. Requires the BayesOpt library to be installed (`pip install bayesian-optimization`). """ import time from ray import tune from ray.tune.schedulers import AsyncHyperBandScheduler from ray.tune.search import ConcurrencyLimiter from ray.tune.search.bayesopt import BayesOptSearch def evaluation_fn(step, width, height): return (0.1 + width * step / 100) ** (-1) + height * 0.1 def easy_objective(config): # Hyperparameters width, height = config["width"], config["height"] for step in range(config["steps"]): # Iterative training function - can be any arbitrary training procedure intermediate_score = evaluation_fn(step, width, height) # Feed the score back back to Tune. tune.report({"iterations": step, "mean_loss": intermediate_score}) time.sleep(0.1) if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument( "--smoke-test", action="store_true", help="Finish quickly for testing" ) args, _ = parser.parse_known_args() algo = BayesOptSearch(utility_kwargs={"kind": "ucb", "kappa": 2.5, "xi": 0.0}) algo = ConcurrencyLimiter(algo, max_concurrent=4) scheduler = AsyncHyperBandScheduler() tuner = tune.Tuner( easy_objective, tune_config=tune.TuneConfig( metric="mean_loss", mode="min", search_alg=algo, scheduler=scheduler, num_samples=10 if args.smoke_test else 1000, ), run_config=tune.RunConfig(name="my_exp"), param_space={ "steps": 100, "width": tune.uniform(0, 20), "height": tune.uniform(-100, 100), }, ) results = tuner.fit() print("Best hyperparameters found were: ", results.get_best_result().config)

运行方式:

python python/ray/tune/examples/bayesopt_example.py # 完整运行 1000 次采样 python python/ray/tune/examples/bayesopt_example.py --smoke-test # 快速验证,仅 10 次采样

代码结构拆解

示例由三部分构成,每一部分都对应 Tune 的一个核心概念:

  1. 目标函数(Trainable)easy_objective(config)接收 Tune 传入的配置字典,在一个模拟训练循环中逐step计算evaluation_fn(step, width, height)的中间得分,并通过tune.report(...)iterationsmean_loss实时回报给 Tune。time.sleep(0.1)用于模拟真实训练中每步的耗时,使贝叶斯优化在高代价目标上的价值更直观。注释也明确说明:这里可以是任意训练过程(如 PyTorch / TensorFlow 训练循环)。

  2. 搜索空间(Search Space)param_spacesteps是固定参数(每次采样都是 100),widthheight是连续超参数,分别采样自tune.uniform(0, 20)tune.uniform(-100, 100)。关键假设是:最优超参数位于该空间之内;空间越大,在有限时间内找到它们就越难。

  3. 搜索算法 + 调度器BayesOptSearch负责建议下一组配置,ConcurrencyLimiter(algo, max_concurrent=4)将同时运行的 trial 数限制为 4,AsyncHyperBandScheduler负责提前停止表现不佳的 trial。三者通过tune.TuneConfig(search_alg=..., scheduler=...)注入Tuner

运行结果解读

示例以mean_loss为指标、mode="min"为目标方向运行num_samples次采样。Notebook 中记录了一次 10 trial 的实际运行输出(见 bayesopt_example.ipynb):

  • 最优 trial:mean_loss=-9.536507956046009,对应参数width=19.398197043239886height=-95.88310114083951
  • 日志目录:~/ray_results/objective_2022-07-22_15-30-08,每个 trial 均完整执行了 100 步迭代。

结果表中neg_mean_loss列即-mean_loss,这是因为 Tune 在最大化框架下跟踪最小化目标。trial 名称前缀objective_来自目标函数名,RunConfig(name="my_exp")则用于自定义实验目录名。

BayesOptSearch 核心参数详解

对照 bayesopt_search.py 的类 docstring 与构造函数(第 153-235 行),BayesOptSearch的完整参数语义如下:

参数默认值含义与说明
spaceNone连续搜索空间。若以 Tune 搜索空间(如tune.uniform)传入Tuner(param_space=...),会被convert_search_space自动转换;也可直接传入BayesianOptimization原生格式{"width": (0, 20), "height": (-100, 100)}
metricNone目标指标名。缺省时若指定了mode,则使用匿名指标_metric
modeNone"min""max",决定目标是最小化还是最大化(构造函数强制校验,见第 172-173 行)
points_to_evaluateNone优先评估的初始参数建议(dict 列表),用于把已知较优的配置先跑一遍,帮助 GP 更快给出后续建议
utility_kwargs{"kind": "ucb", "kappa": 2.576, "xi": 0.0}效用函数参数,与bayesian-optimization包默认值一致,见第 196-203 行
random_state42BayesOpt 的随机种子
random_search_steps10初始随机搜索的 trial 数,用于避免贝叶斯过程初始阶段在局部过拟合
verbose0BayesOpt 包的日志详细程度
patience5同一配置被重复建议的次数上限。GP 收敛后可能反复建议同一点,超过patiencesuggest返回Searcher.FINISHED,实验提前结束(可能少于num_samples)。设patience=1则配置首次重复即停止
skip_duplicateTrue是否跳过已评估过的配置。False时允许重复建议(适用于噪声目标,或希望坚持跑到num_samples
analysisNone可选的ExperimentAnalysis,用于把历史实验结果注册进高斯过程,实现 warm-start
repeat_float_precision5检测重复配置时对浮点数做哈希的小数精度。值越大查重越严格,被判为"重复"的配置越少(第 100-103 行)

示例中的utility_kwargs={"kind": "ucb", "kappa": 2.5, "xi": 0.0}显式选择了 UCB(Upper Confidence Bound,上置信界)效用函数,并微调kappa=2.5(默认 2.576)。kappa控制探索强度,xi用于 EI(Expected Improvement)类效用函数中的改善期望阈值。

两种搜索空间传参方式

BayesOptSearch同时支持自动转换与手动传参两种方式(源码 docstring 第 105-146 行):

方式一:Tune 搜索空间自动转换(推荐,与示例一致):

from ray import tune from ray.tune.search.bayesopt import BayesOptSearch config = { "width": tune.uniform(0, 20), "height": tune.uniform(-100, 100), } bayesopt = BayesOptSearch(metric="mean_loss", mode="min") tuner = tune.Tuner( my_func, tune_config=tune.TuneConfig(search_alg=bayesopt), param_space=config, ) tuner.fit()

方式二:手动传入 BayesOpt 原生边界格式(此时搜索空间经space参数传入,Tuner不再传param_space):

space = { 'width': (0, 20), 'height': (-100, 100), } bayesopt = BayesOptSearch(space, metric="mean_loss", mode="min") tuner = tune.Tuner( my_func, tune_config=tune.TuneConfig(search_alg=bayesopt), ) tuner.fit()

底层实现原理:从源码看 BayesOptSearch 的工作流程

阅读 bayesopt_search.py 的完整实现,可以梳理出 Tune 与 BayesOpt 交互的完整闭环:

1. 初始化与搜索空间转换(__init__/set_search_properties

  • 构造函数对mode做合法性校验(仅允许min/max),并通过_metric_op(最小化取 -1.0,最大化取 1.0)把"最小化"问题翻转为底层库的"最大化"框架(第 205-208 行);
  • 内部用byo.UtilityFunction(**utility_kwargs)构建效用函数(第 217 行);
  • 若直接传入含tune.uniform等 Domain 对象的space,会先parse_spec_vars解析,检测到未解析搜索空间时给出警告并调用convert_search_space(第 221-228 行);
  • 若搜索空间在构造时尚未就绪(例如由Tuner(param_space=...)注入),则推迟到set_search_properties中通过convert_search_space(config)完成转换并调用_setup_optimizer(第 253-271 行),最终构造byo.BayesianOptimization(f=None, pbounds=..., verbose=..., random_state=...)(第 242-247 行)。

convert_search_space(静态方法,第 448-493 行)对搜索空间的约束很关键:

  • 只支持连续Float:其他类型参数(如整型、类别型)会抛出ValueError(第 481-484 行);
  • 不支持网格搜索:检测到grid_vars直接抛错(第 452-456 行);
  • 不支持量化Quantized采样器会被丢弃并警告(第 464-469 行);
  • 不支持自定义采样方法:非Uniform采样器会被丢弃并警告(第 471-478 行);
  • 嵌套字典参数会以/连接路径作为参数名(第 487 行)。

2. 建议下一个配置(suggest

每次需要新 trial 时,Tune 调用suggest(trial_id)(第 273-356 行):

  • 若设置了points_to_evaluate,先依次弹出这些初始点(第 298-300 行);
  • 否则调用self.optimizer.suggest(self.utility)让高斯过程给出下一个采样点(第 302 行);
  • 对配置做哈希查重(_dict_hash,第 31-38 行按repeat_float_precision精度格式化浮点数后 JSON 序列化):
    • 同一配置重复建议次数超过patience时,记录收敛警告并返回Searcher.FINISHED,实验提前终止(第 312-323 行);
    • 已见过且skip_duplicate=True时跳过该配置返回None(第 325-338 行);
  • random_search_steps个 trial 属于随机初始化阶段(第 340-350 行)。

3. 结果反馈与高斯过程更新(on_trial_complete/_register_result

trial 结束后,Tune 回调on_trial_complete(第 373-410 行):

  • 结果或参数缺失、出错时直接忽略(第 394-395 行);
  • 随机初始化阶段的 trial 结果先缓存到_buffered_trial_results,攒够random_search_steps个后一次性注册给优化器(第 398-410 行),这是为了避免初始阶段 GP 过拟合;
  • _register_result自动过滤 NaN、inf、-inf 结果is_nan_or_inf判断,第 414-416 行),再以_metric_op * result[self.metric]的符号将最小化目标注册进optimizer.register(...)(第 416 行)。

4. 检查点与热启动(save/restore/register_analysis

  • save/restore用 pickle 序列化/反序列化整个 searcher 状态(第 425-446 行),用于实验容错恢复;
  • register_analysis(analysis)(第 358-371 行)可把上一次实验的ExperimentAnalysis结果注册进高斯过程,实现 warm-start,与analysis参数配合使用。

组合调度器:与 AsyncHyperBandScheduler 协同

示例特意"checks that it is usable with a separate scheduler"——即验证BayesOptSearch可以与独立调度器组合。Tune 中搜索算法与调度器职责正交:

  • 搜索算法决定"下一个 trial 试什么超参数";
  • 调度器决定"正在跑的 trial 何时可以提前终止/暂停/分配更多资源"。

示例选用AsyncHyperBandScheduler:它属于 HyperBand 的异步变体,会在训练过程中持续淘汰表现不佳的 trial,从而节省算力。二者组合后,BayesOpt 负责智能探索参数空间,调度器负责及时止损,这在真实的高代价训练任务(如大模型调参)中收益尤其明显。相关的基础用法另见 async_hyperband_example.py。

并发控制:ConcurrencyLimiter 的作用

BayesOptSearch本身是顺序建议下一个配置的;当集群算力充足、希望并行跑多个 trial 时,需要用 python/ray/tune/search/concurrency_limiter.py 中的ConcurrencyLimiter包装:

algo = BayesOptSearch(utility_kwargs={"kind": "ucb", "kappa": 2.5, "xi": 0.0}) algo = ConcurrencyLimiter(algo, max_concurrent=4)

max_concurrent=4将同时运行的 trial 上限设为 4:在任意时刻最多只有 4 个 trial 在跑,已完成的 trial 结果会及时回填高斯过程,用于更新后续建议。这样既充分利用并行资源,又保证贝叶斯模型的采样建议始终基于最新观测。

测试验证与常见问题排查

仓库在 python/ray/tune/tests/test_searchers.py 中覆盖了BayesOptSearch的多种边界行为:

  • 参数校验repeat_float_precision必须为非负整数,传-1、字符串、浮点数或布尔值都会抛错(第 827-839 行);
  • 收敛检测:专门测试了"GP 收敛后应发出警告而非静默停止"的行为——同一配置被反复建议且skip_duplicate=True时,实验会在提示后正常结束(第 844-867 行)。

据此,实际使用中可重点关注以下问题:

  1. 报错BayesOpt must be installed!bayesian-optimization未安装或版本不兼容,按pip install bayesian-optimization==1.4.3安装即可;
  2. 报错BayesOpt does not support parameters of type ...:搜索空间里出现了非连续浮点类型参数。BayesOptSearch只接受连续域;整型参数可改用其他搜索算法(如 Optuna、HyperOpt),或自行把整型表达为连续值后取整;
  3. 报错 grid search 不支持param_space中混入了tune.grid_search(...),需移除或改用连续分布;
  4. 运行很快结束、trial 数少于num_samples:属于正常收敛行为——GP 反复建议同一最优区域,触发patience提前终止。可通过增大patience、设置skip_duplicate=False或扩大搜索空间继续探索(源码第 314-321 行日志中有明确提示);
  5. 结果含 NaN 被静默忽略_register_result会自动丢弃 NaN/inf 观测,若大量出现会拖慢收敛,应检查目标函数。

延伸阅读

  • 官方 API 文档:doc/source/tune/api/suggestion.rst 中bayesopt锚点对应的BayesOptSearchautosummary 条目;
  • 概念导读:doc/source/tune/key-concepts.rst 中搜索算法章节,含 BayesOpt 与其他搜索算法的横向对比表;
  • 搜索算法入口:python/ray/tune/search/bayesopt/init.py;
  • 并发限制实现:python/ray/tune/search/concurrency_limiter.py;
  • 测试用例:python/ray/tune/tests/test_searchers.py;
  • 同类集成示例:HyperOpt(hyperopt_example.py)、Optuna(optuna_example.py)、BOHB(bohb_example.py),以及示例索引页 doc/source/tune/examples/index.rst。

【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 8:35:32

基于ResNet50的单图人脸重建:ModelScope实战与优化指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 8:34:08

AI辅助教材编写:低查重率与一键生成技术解析

1. 项目背景与核心价值去年我在参与高校教材修订项目时,发现一个普遍痛点:教师团队花费大量时间在内容查重和格式调整上,真正用于教学设计的时间不足30%。这促使我开始探索如何用AI技术优化教材编写流程。经过半年多的实测验证,这…

作者头像 李华
网站建设 2026/9/20 8:31:14

平板电脑检测报告PDF结构化解析实战指南

简介:本资源是一份完整的平板电脑专业检测报告,面向电子产品质量工程师、硬件测试人员及智能终端研发从业者,用于指导日常产线检验、来料验收或第三方合规性评估。报告系统覆盖结构检测(外观工艺、接口牢固度、散热与人机工学&…

作者头像 李华
网站建设 2026/9/20 8:25:46

大语言模型应用开发痛点与LangChain解决方案

1. 大语言模型(LLM)应用开发中的典型痛点作为一名长期从事AI应用开发的工程师,我在过去两年里参与了十几个基于大语言模型的项目落地。从最初的兴奋到后来的冷静,我深刻体会到LLM在实际业务场景中面临的挑战远比想象中复杂。以下是…

作者头像 李华
网站建设 2026/9/20 8:25:21

MRI混合噪声去噪:加权中值滤波原理与临床部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华