Optuna 如何用 enqueue_trial 与 add_trial 指定先评估的超参数组合
2026/9/15 19:21:56 网站建设 项目流程

Optuna 如何用 enqueue_trial 与 add_trial 指定先评估的超参数组合

【免费下载链接】optunaA hyperparameter optimization framework项目地址: https://gitcode.com/GitHub_Trending/op/optuna

在做超参数优化时,通常有两类现实情况:一是手里已经有一组“开箱即用”的参数(比如初始学习率、默认配置),还没评估过,但希望 Optuna 先跑这些组合,再自动搜索;二是这些组合早就手动评估过了,结果不理想,想把已有结果登记进 Study,让 Optuna 在后续采样时把它们考虑进去。Optuna 为这两种情况各提供一个接口:Study.enqueue_trial把参数组合排入队列、由 Optuna 负责评估;Study.add_trial把已评估完成的 trial(含结果值)直接注册进 Study。本文按这两条路径给出可执行的代码和验证方式。

准备条件

按 安装文档 的说法,Optuna 支持 Python 3.9 或更新版本,推荐通过 pip 安装:

pip install optuna

也可以用 conda 安装:conda install -c conda-forge optuna。如果运行的是文中 LightGBM 完整示例,还需要lightgbmscikit-learnnumpy等依赖(见 教程示例 的 import 部分)。

先明确两个接口的分工(源自 Study 参考文档):

  • enqueue_trial(params, user_attrs=None, skip_if_exists=False):把参数值固定为下一次采样的参数,即“让 Optuna 去评估这组参数”。实现上它创建一个TrialState.WAITING状态的 trial(参数存入system_attrsfixed_params),params必须是字典,否则抛出TypeError("params must be a dictionary.")
  • add_trial(trial):把一个(通常已完成评估的)trial 加入 Study,加入前会先做校验。官方 docstring 明确说,排队等待评估应使用enqueue_trialadd_trial面向已评估完的 trial。

场景一:用 enqueue_trial 让 Optuna 先评估指定参数

以官方 docstring 中的最小示例(出自 optuna/study/study.py 的enqueue_trial文档,只依赖 optuna 本身,可直接复制运行):

import optuna def objective(trial): x = trial.suggest_float("x", 0, 10) return x**2 study = optuna.create_study() study.enqueue_trial({"x": 5}) study.enqueue_trial({"x": 0}, user_attrs={"memo": "optimal"}) study.optimize(objective, n_trials=2)

运行后可用断言核对效果,这组断言同样来自 docstring 示例:

assert study.trials[0].params == {"x": 5} assert study.trials[1].params == {"x": 0} assert study.trials[1].user_attrs == {"memo": "optimal"}

三条断言分别验证:排队的参数组合按入队顺序成为前两个被评估的 trial;user_attrs可以附带与params无关的用户属性(示例中的{"memo": "optimal"})会原样挂在对应 trial 上。

两个可选参数:

  • user_attrs:字典形式的用户自定义属性,除参数值外随 trial 保存。
  • skip_if_exists=True:当 Study 中已存在相同params的 trial 时跳过入队(会打印 “Trial with params ... already exists. Skipping enqueue.” 日志)。docstring 同时提醒:如果多个进程同时用相同的params调用该方法,仍可能产生重复入队。

真实项目中的用法可参考 教程 tutorial/20_recipes/008_specify_params.py:定义一个 LightGBM 目标函数(内部通过trial.suggest_float/trial.suggest_int搜索bagging_fractionbagging_freqmin_child_samples三个参数),创建 Study 后排入两组参数再优化:

study = optuna.create_study(direction="maximize", pruner=optuna.pruners.MedianPruner()) study.enqueue_trial( { "bagging_fraction": 1.0, "bagging_freq": 0, "min_child_samples": 20, } ) study.enqueue_trial( { "bagging_fraction": 0.75, "bagging_freq": 5, "min_child_samples": 20, } ) import logging import sys optuna.logging.get_logger("optuna").addHandler(logging.StreamHandler(sys.stdout)) study.optimize(objective, n_trials=100, timeout=600)

教程中的说明:添加 stdout 流 handler 是为了让日志可见,从而确认 Optuna 按预期工作(前两个 trial 使用排队的参数,之后由 sampler 采样)。

场景二:用 add_trial 登记已评估的结果

如果参数组合已经跑过、手里有结果值,用optuna.trial.create_trial构造一个已完成的 trial,再用study.add_trial注册。构造时(见 optuna/trial/_frozen.py 的create_trial文档)所有参数都是关键字参数,state默认是TrialState.COMPLETE;当状态为COMPLETE时,paramsdistributionsvaluevalues是必填项,且valuevalues不能同时指定。

同样以官方 docstring 中的最小示例(出自 optuna/study/study.py 的add_trial文档):

import optuna from optuna.distributions import FloatDistribution def objective(trial): x = trial.suggest_float("x", 0, 10) return x**2 study = optuna.create_study() assert len(study.trials) == 0 trial = optuna.trial.create_trial( params={"x": 2.0}, distributions={"x": FloatDistribution(0, 10)}, value=4.0, ) study.add_trial(trial) assert len(study.trials) == 1 study.optimize(objective, n_trials=3) assert len(study.trials) == 4

验证逻辑:注册后 Study 里有 1 个 trial;再跑 3 次优化后共 4 个。docstring 还给出了跨 Study 迁移的用法:对study.trials逐个other_study.add_trial(trial),即可把已评估结果整体搬进另一个 Study。

对应教程中 LightGBM 场景的完整写法是(参数与分布范围和enqueue_trial场景保持一致,value为文档示例中的示例值 0.94 / 0.95):

study = optuna.create_study(direction="maximize", pruner=optuna.pruners.MedianPruner()) study.add_trial( optuna.trial.create_trial( params={ "bagging_fraction": 1.0, "bagging_freq": 0, "min_child_samples": 20, }, distributions={ "bagging_fraction": optuna.distributions.FloatDistribution(0.4, 1.0 + 1e-12), "bagging_freq": optuna.distributions.IntDistribution(0, 7), "min_child_samples": optuna.distributions.IntDistribution(5, 100), }, value=0.94, ) ) study.add_trial( optuna.trial.create_trial( params={ "bagging_fraction": 0.75, "bagging_freq": 5, "min_child_samples": 20, }, distributions={ "bagging_fraction": optuna.distributions.FloatDistribution(0.4, 1.0 + 1e-12), "bagging_freq": optuna.distributions.IntDistribution(0, 7), "min_child_samples": optuna.distributions.IntDistribution(5, 100), }, value=0.95, ) ) study.optimize(objective, n_trials=100, timeout=600)

教程对这一场景的表述是:登记这些结果后,“Optuna will sample hyperparameters taking them into account”,即后续采样会把已登记的结果纳入考虑。

distributions必须与目标函数中suggest_*的搜索范围一致(示例中FloatDistribution(0.4, 1.0 + 1e-12)对应trial.suggest_float("bagging_fraction", 0.4, 1.0 + 1e-12)),否则 trial 在加入时的校验或后续采样语义会对不上。多目标 Study 下要特别注意:add_trial会检查 trial 的值数量与 Study 目标数是否一致,不一致会抛出ValueError(提示 “The added trial has N values, which is different from the number of objectives ...”),多目标时请使用values序列而不是value

需要批量登记时可用study.add_trials(trials),它内部就是逐个调用add_trial,同样逐个校验。

常见限制:SQLite 下的并行优化

FAQ 中有一条与enqueue_trial直接相关的限制:为并发评估已排队的 trial,RDBStorage使用SELECT ... FOR UPDATE语法,而 SQLite3 不支持该语法,因此官方不建议用 SQLite3 做并行优化(还可能遇到 “database is locked” 错误)。如果必须在文件式存储下做这类场景,FAQ 给出的替代方案是 Journal 存储:

import optuna from optuna.storages import JournalStorage from optuna.storages.journal import JournalFileBackend storage = JournalStorage(JournalFileBackend("optuna_journal_storage.log")) study = optuna.create_study(storage=storage)

单进程串行优化则不受此限制,默认 InMemory/RDB 存储都可以正常使用这两个接口。

小结与延伸阅读

两个接口对应两条清晰的路径:还没评估、想让 Optuna 排队先跑的用enqueue_trial(WAITING 状态,按入队顺序评估);已有结果、想让 Optuna 采样时利用这些结果的用add_trial+optuna.trial.create_trial(COMPLETE 状态,必须带paramsdistributionsvalue/values)。验证手段分别是断言 trial 的params顺序与user_attrs、trial 数量变化,以及在 LightGBM 教程中用 stdout 日志确认前两组参数被优先评估。完整可运行的教程见 tutorial/20_recipes/008_specify_params.py,接口定义与文档可对照 optuna/study/study.py、optuna/trial/_frozen.py 与 Study API 参考、trial API 参考。

【免费下载链接】optunaA hyperparameter optimization framework项目地址: https://gitcode.com/GitHub_Trending/op/optuna

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询