轻量级、多功能且平台无关的架构

Optuna 完全用 Python 编写,并且依赖项很少。这意味着一旦您对 Optuna 感兴趣,我们就可以快速进入实际示例。

二次函数示例

通常,Optuna 用于优化超参数,但作为示例,让我们优化一个简单的二次函数:\((x - 2)^2\)

首先,导入 optuna

import optuna

在 Optuna 中,传统上要优化的函数名为 objective

def objective(trial):
    x = trial.suggest_float("x", -10, 10)
    return (x - 2) ** 2

此函数返回 \((x - 2)^2\) 的值。我们的目标是找到使 objective 函数输出最小化的 x 值。这就是“优化”。在优化过程中,Optuna 会使用不同的 x 值反复调用和评估目标函数。

一个 Trial 对象对应于目标函数的一次单独执行,并在每次调用函数时在内部实例化。

“suggest”API(例如,suggest_float())在目标函数内部调用,以获取 trial 的参数。suggest_float() 在提供的范围内均匀选择参数。在我们的示例中,范围是从 \(-10\)\(10\)

为了开始优化,我们创建一个 study 对象,并将目标函数传递给方法 optimize(),如下所示。

study = optuna.create_study()
study.optimize(objective, n_trials=100)

您可以按如下方式获取最佳参数。

best_params = study.best_params
found_x = best_params["x"]
print(f"Found x: {found_x}, (x - 2)^2: {(found_x - 2) ** 2}")
Found x: 2.006698664607871, (x - 2)^2: 4.4872107528744237e-05

我们可以看到 Optuna 找到的 x 值接近最优值 2

注意

当用于在机器学习中搜索超参数时,目标函数通常会返回模型的损失或准确率。

Study 对象

让我们根据如下内容澄清 Optuna 中的术语

  • Trial:目标函数的一次调用

  • Study:一次优化会话,即一组 trial

  • Parameter:一个需要优化其值的变量,例如上面示例中的 x

在 Optuna 中,我们使用 study 对象来管理优化。方法 create_study() 返回一个 study 对象。study 对象具有用于分析优化结果的有用属性。

获取参数名称和参数值字典

{'x': 2.006698664607871}

获取目标函数的最佳观测值

study.best_value
4.4872107528744237e-05

获取最佳 trial

study.best_trial
FrozenTrial(number=52, state=<TrialState.COMPLETE: 1>, values=[4.4872107528744237e-05], datetime_start=datetime.datetime(2025, 11, 10, 5, 17, 48, 529409), datetime_complete=datetime.datetime(2025, 11, 10, 5, 17, 48, 530558), params={'x': 2.006698664607871}, user_attrs={}, system_attrs={}, intermediate_values={}, distributions={'x': FloatDistribution(high=10.0, log=False, low=-10.0, step=None)}, trial_id=52, value=None)

获取所有 trial

study.trials
for trial in study.trials[:2]:  # Show first two trials
    print(trial)
FrozenTrial(number=0, state=<TrialState.COMPLETE: 1>, values=[10.88077703675539], datetime_start=datetime.datetime(2025, 11, 10, 5, 17, 48, 475905), datetime_complete=datetime.datetime(2025, 11, 10, 5, 17, 48, 476506), params={'x': -1.298602285325618}, user_attrs={}, system_attrs={}, intermediate_values={}, distributions={'x': FloatDistribution(high=10.0, log=False, low=-10.0, step=None)}, trial_id=0, value=None)
FrozenTrial(number=1, state=<TrialState.COMPLETE: 1>, values=[43.633281258046665], datetime_start=datetime.datetime(2025, 11, 10, 5, 17, 48, 476659), datetime_complete=datetime.datetime(2025, 11, 10, 5, 17, 48, 476807), params={'x': -4.605549277542835}, user_attrs={}, system_attrs={}, intermediate_values={}, distributions={'x': FloatDistribution(high=10.0, log=False, low=-10.0, step=None)}, trial_id=1, value=None)

获取 trial 的数量

len(study.trials)
100

通过再次执行 optimize(),我们可以继续优化。

study.optimize(objective, n_trials=100)

获取更新后的 trial 数量

len(study.trials)
200

由于目标函数非常简单,最后 100 个 trial 没有改进结果。但是,我们可以再次检查结果

best_params = study.best_params
found_x = best_params["x"]
print(f"Found x: {found_x}, (x - 2)^2: {(found_x - 2) ** 2}")
Found x: 2.005097031517559, (x - 2)^2: 2.597973029098893e-05

脚本总运行时间: (0 分钟 0.267 秒)

由 Sphinx-Gallery 生成的画廊