这篇从实战角度讲怎么用Optuna做超参数搜索,包括剪枝策略、并行调度和结果导出等进阶用法。你将学到怎么加速搜索过程、避免浪费算力、在海量参数空间中高效找到最优解。适合已经入门Optuna、想在实际项目中高效调参的机器学习工程师使用,让超参数搜索又快又准不再盲目试错。这些方法在实践中屡试不爽。掌握后能提升专业能力。

岗位关联

调参如探店。从前你靠手气一家家试吃,今天跟着一位懂门道的老餮,学会科学点菜、提前撤盘、多点开花,用最少的时间找到那条街上最好吃的那家店。 对 AI 从业者而言,掌握 Optuna 意味着把调参从“手动碰运气”升级为“自动化寻优”,省下的不只是算力,更是你宝贵的迭代时间与职业自信。

目录
  1. 可视化演示
  2. Optuna三件套
  3. TPE采样算法
  4. 剪枝策略
  5. 并行调度
  6. 搜索空间设计
  7. 结果导出与生产
  8. 实战调优案例
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动态演示Optuna框架超参数搜索实的核心机制,通过基础/核心/应用/扩展四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Optuna框架超参数搜索实:剪枝策略 剪枝策略加速搜索 并行调度与分布式搜索 核心机制可视化 Optuna框架超参数搜索实整体架构与关键组件

Optuna三件套

把调参想象成去一条陌生的美食街找最好吃的餐厅。你随身带着一本笔记本(Study),每推开一家店(Trial),就在笔记本上记下这家店的招牌菜配方(超参数)、上菜速度(训练时间)和口味评分(目标函数值)。Optuna 帮你做的就是这件事,只是它比人更耐心、更系统。

在代码层面,三件套对应三个对象:study 是整个搜索过程的容器,负责记录每一次试验的完整“食评”;objective 是你定义的一个函数,它接收一组超参数,跑一遍训练,返回一个分数;trial 则是单次试验的档案,里面记录了这一组参数和对应分数。每次试验结束后,分数自动回流到 study,成为下一轮采样的参考。

理解了三件套,你就能看懂 Optuna 的所有 API——它们都是在帮助这三者更好地协作。接下来要问的是:凭什么 study 能越记越聪明?答案在下一节:TPE 采样算法。

score=f(objective,trial)→study.\text{score} = f(\text{objective}, \text{trial}) \rightarrow \text{study}.
目标函数是“菜谱”,Trial 是“试吃记录”,Study 是“美食笔记”——三者合在一起构成搜索闭环。
  1. 定义目标函数objective 接收 trial,用 trial.suggest_* 提出参数并返回评价分数
    objective(trial)↦score\text{objective}(\text{trial}) \mapsto \text{score}
  2. 执行单次试验Optuna 每次调用 trial 即完成一轮“试吃”
    trial=run(params)\text{trial} = \text{run}(\text{params})
  3. 记录进研究分数写入 study 的日志,成为后续采样依据
    study.log←score\text{study}.\text{log} \gets \text{score}

TPE采样算法

如果你已经记下了十家店的口味评分,下一家该去哪试?普通人可能随机挑,也可能只去评分最高的店附近反复吃。TPE 的做法更像一位经验老道的食评家:把历史上的高分“配方”和低分“配方”分开,分别在两者上统计参数分布,然后选出“最可能超越当前最高分”的新配方。

具体地说,TPE 用两个密度函数描述参数空间:l(x) 来自表现好的历史试验,g(x) 来自表现差的。每轮采样时,它计算每个候选点的期望提升(EI),选 EI 最大的点去跑下一轮试验。这个策略让它在好区域附近加密采样,同时不放弃探索未知区域。

TPE 的聪明之处在于,它从来不是漫无目的地随机搜索,而是不断从历史中学习。你唯一要做的,是给它一个合理的搜索空间——这就引出了后面要讲的“搜索空间设计”。现在,先把视线放到搜索过程中的浪费问题上:如果一家店试到一半已经明显难吃,还要等它上完所有菜吗?

EI(x)=γ⋅l(x)+(1−γ)⋅g(x)g(x)⋅(y∗−ylow)EI(x) = \frac{\gamma \cdot l(x) + (1 - \gamma) \cdot g(x)}{g(x)} \cdot (y^* - y_{\text{low}})
可以这样理解:把公式看作“这桌菜比现在最好的一桌更好的概率乘以可能好多少”,Optuna 每次挑这个值最大的候选去试吃。
  1. 区分优劣两组用历史最优值 y* 把过去试验分成“好”与“差”两组
    ylow≤y∗≤yhighy_{\text{low}} \le y^* \le y_{\text{high}}
  2. 估计密度函数分别对两组参数做核密度估计,得到 l(x) 和 g(x)
    l(x)∝good trials,g(x)∝bad trialsl(x) \propto \text{good trials}, \quad g(x) \propto \text{bad trials}
  3. 计算期望提升EI 值越大说明该点越值得尝试
    argmaxx EI(x)\text{argmax}_x \, EI(x)

剪枝策略

试吃讲究效率:一道菜尝一口就知道后厨水平不行,何必等满桌菜上齐再买单?剪枝策略做的正是这件事。在训练深度模型时,很多超参数组合跑不到几个 epoch 就已经明显落后于历史中位数,此时继续跑纯属浪费 GPU。Optuna 的 MedianPruner 会在每次中间报告后检查:当前分数是否低于历史中位数?如果是,就提前终止这个 trial。

剪枝器有多种,最常用的是中位数剪枝(MedianPruner)和 ASHA 剪枝(SuccessiveHalving)。前者适合大多数场景,后者在大量并行 trial 时效果更好。要启用剪枝,目标函数里必须用 trial.report(score, step) 中间报告分数,并用 trial.should_prune() 检查是否应该提前退出。

剪枝节省的是单次试验的时间。如果预算紧张、只想跑少量 trial,剪枝价值有限;但当你准备跑几百个 trial 时,它往往能砍掉一半以上的计算量。不过,剪枝只对“中间过程能反映最终结果”的训练有效——如果前几个 epoch 噪声极大,剪枝可能误杀好参数。这时可以调大 n_startup_trials,让前若干次试验不剪枝。

prune ifscorecurrent(t)<median(score<t)\text{prune if} \quad \text{score}_{\text{current}}(t) < \text{median}(\text{score}_{<t})
类比“尝一口撤盘”,剪枝把大量明显不行的实验在早期拦下,把算力留给更有希望的参数组合。
  1. 中间报告每个 epoch 结束调用 trial.report() 上报当前分数
    score(t)→trial\text{score}(t) \to \text{trial}
  2. 历史对比剪枝器计算同一训练步数下历史试验中位数
    m^t=median({scorei(t)})\hat{m}_t = \text{median}(\{\text{score}_i(t)\})
  3. 判早停当前分数低于中位数则触发 should_prune()
    true  ⟺  score(t)<m^t\text{true} \iff \text{score}(t) < \hat{m}_t

并行调度

一个人探店效率有限,叫上几个朋友分头行动,各自试不同的店,再回来汇总笔记,整个搜索就快多了。Optuna 的并行调度就是这个思路。单机多核可以直接设 n_jobs=-1,让多个 trial 同时跑;跨机器则需要配置 RDBStorage(比如 SQLite 或 PostgreSQL),让每个 worker 共享同一个 study,各自采样、各自训练、共同写入结果。

并行带来两个好处:一是吞吐量提升,单位时间内能完成的 trial 数量翻倍;二是探索多样性增加,多个 worker 同时采样,天然覆盖更广的参数区域。但并行不是没有代价——多个 trial 同时抢占 CPU/GPU,单个 trial 可能变慢,极端情况下总耗时反而上升。所以并行度要结合资源情况动态调整。

并行调度解决的是“怎么多快好省地跑更多 trial”。接下来,在跑之前还得解决一个问题:搜索空间怎么设计?参数范围太窄会错过好店,太宽会浪费大量 trial 在荒芜区域。

T并行=T串行Nworker×(1+δ)T_{\text{并行}} = \frac{T_{\text{串行}}}{N_{\text{worker}}} \times (1 + \delta)
理想情况下加速比等于 worker 数,但通信开销与资源争抢会带来一个损耗系数 δ,让实际效果略低于线性加速。
  1. 计算理想加速N 个 worker 并行,理论耗时降为串行的 1/N
    Tideal=T串行/NT_{\text{ideal}} = T_{\text{串行}} / N
  2. 加入损耗由于进程通信、数据库写入竞争等原因引入 δ
    Treal=Tideal×(1+δ)T_{\text{real}} = T_{\text{ideal}} \times (1 + \delta)
  3. 判断收益当 δ 过大时应降低并行度
    N∗=argminN TrealN^* = \text{argmin}_N \, T_{\text{real}}

搜索空间设计

菜单设计决定了你能点到什么菜。搜索空间就是调参的“菜单”:如果把学习率限制在 [0.0001, 0.01],那 1.0 这种离谱值根本不会出现;如果把神经元数量范围定成 [1, 2],那再好的采样器也找不到合适的容量。Optuna 通过 trial.suggest_int、suggest_float、suggest_categorical、suggest_loguniform 等接口定义不同类型的参数。

设计空间时有个关键技巧:数量级差距很大的参数(比如学习率 1e-5 到 1e-1)应该用 loguniform 而非 uniform,因为前者在对数尺度上均匀采样,能让小数值区域获得同等被探索的机会。另外,可以用 suggest_int 配合 step 参数控制离散间隔,用 if trial.suggest_categorical('use_bn', [True, False]) 实现条件参数——只有选择使用 BN 时才采样 BN 相关的其他参数。

好的搜索空间是成功的一半:它决定了采样器活动的“街区”,也决定了剪枝器对比的“基准线”。搜索完成后,One 还有件事要做:把这次探店的经验记录下来,形成可复用的报告和模型文件。

θ∼log⁡-uniform(10−5,10−1)\theta \sim \log\text{-uniform}(10^{-5}, 10^{-1})
相当于把 0.00001 到 0.1 这段“味道浓度”按指数的刻度分成 100 格,而不是线性平分,这样 0.0001 和 0.0002 都能被照顾到。
  1. 选择合适的分布尺度差异大时用对数均匀分布
    θ=10u,u∼U(−5,−1)\theta = 10^{u}, \quad u \sim U(-5, -1)
  2. 离散化参数整数参数用 suggest_int 配合步长
    θ=a+k⋅step,k∈Z\theta = a + k \cdot \text{step}, \quad k \in \mathbb{Z}
  3. 条件空间子参数仅当主开关为真时才启用
    θsub∼P  ⟺  use_bn=True\theta_{\text{sub}} \sim \mathcal{P} \iff \text{use\_bn} = \text{True}

结果导出与生产

美食笔记记在脑子里容易忘,写进文档才能流传。Optuna 同样支持把搜索结果导出:study.trials_dataframe() 可以把所有试验的参数和分数转成 pandas DataFrame,方便你画图、做分析、写报告;study.best_params 和 study.best_value 直接给出最优配置。如果怕中途断电,可以在创建 study 时指定 storage='sqlite:///example.db',所有结果实时落盘;训练出的最佳模型则用 joblib.dump 或 torch.save 保存 checkpoint。

在生产环境中,调参结果的价值不仅在于“找到最优参数”,还在于“持续地找到最优参数”。你可以把 Optuna 封装进定时任务:每天拉取新数据 → 重新定义搜索空间 → 跑一轮优化 → 用新最优参数重训模型 → 部署上线。这样模型就能随数据漂移自动更新,整个过程无需人工干预。

导出与保存听上去简单,实则是工程化的分水岭:能导出,才能复盘;能保存,才能复用;能自动重训,才能让调参这件事从“一次性手工艺”升级为“可持续的基础设施”。最后,我们用一个大而全的实战案例把前面所有概念串起来。

modelnew=retrain(best_params,datatoday)\text{model}_{\text{new}} = \text{retrain}(\text{best\_params}, \text{data}_{\text{today}})
相当于把“今天探店的好配方”记进菜谱,明天开店还能照方抓药,甚至根据今天的客流量微调配方。
  1. 导出试验表一键获得所有试验的数据结构
    df=trials_dataframe()\text{df} = \text{trials\_dataframe}()
  2. 取最优配置从表中提取最优参数与最优分数
    θ∗=argmaxθ score(θ)\theta^* = \text{argmax}_\theta \, \text{score}(\theta)
  3. 部署重训用最优参数训练并保存生产模型
    save(model(θ∗))\text{save}(\text{model}(\theta^*))

实战调优案例

现在把前面所有功夫用在一道综合题上:为一个随机森林分类器调优。目标是最大化验证集 AUC。搜索空间包括树的数量、最大深度、分裂所需最小样本数和是否使用采样策略。整个流程用 optuna.create_study(direction='maximize') 创建研究,设置 timeout=300 限制总时长,并用 MedianPruner 搭配 report/should_prune 做剪枝。

关键点有三个:第一,搜索空间要有梯度——树数量的范围设为 [50, 500],最大深度 [3, 15],这样采样器在相邻参数间能看到分数差异;第二,设置 n_jobs=4 让 4 个 trial 并行,每个 trial 内部再用随机森林自身的 n_jobs 并行训练;第三,运行完毕后打印 best_params,用 trials_dataframe() 画出参数与分数的散点图,检查是否有异常点或搜索盲区。

跑完这个案例,你就掌握了 Optuna 从基础到进阶的完整闭环:三件套建框架、TPE 指方向、剪枝省时间、并行提效率、空间定边界、导出留经验。调参不再是玄学,而是一套可重复、可量化、可自动化的工程方法。

AUC(θ)→max⁡θ,s.t.∑Ttrial≤timeout\text{AUC}(\theta) \to \max_\theta, \quad \text{s.t.} \sum T_{\text{trial}} \le \text{timeout}
约束条件是“总探店时间不能超过 5 小时”,所有店铺必须在时间内完成试吃并给出排名。
  1. 定义优化方向AUC 越大越好,所以方向是最大化
    max⁡θ AUC(θ)\max_\theta \, \text{AUC}(\theta)
  2. 设置总预算用 timeout 限制总搜索时间
    ∑iTi≤300 s\sum_i T_i \le 300\,\text{s}
  3. 执行并复盘打印最优结果,导出 DataFrame 做可视化
    θ∗=study.best_params\theta^* = \text{study}.\text{best\_params}

AI 应用场景

场景一:AI 平台自动化超参搜索

阶段:模型训练与调优

解决的问题:传统调参依赖算法工程师手动改配置、反复提交训练任务,一次调参可能耗费数天。Optuna 接入 AI 训练平台后,自动从参数空间采样、启停训练任务,并把最优参数直接用于生产模型重训。

具体案例:某推荐系统团队每天新增数亿条用户行为数据,模型需要每日重训。他们用 Optuna 搭建自动调参流水线,每日自动搜索学习率、嵌入维度和树模型参数,搜索完成后自动部署最优模型,全程无需人工干预。

场景二:AutoML 竞赛与实验管理

阶段:实验管理与结果复盘

解决的问题:数据科学竞赛中,参赛者往往需要同时尝试几十种特征工程方案和模型配置,手工记录极易混乱。Optuna 的 trials_dataframe 和可视化接口能把所有实验沉淀为结构化报告。

具体案例:一位 Kaggle 参赛者用 Optuna 同时搜索 LightGBM 和 XGBoost 的 12 个超参数,每轮试验自动记录参数与 CV 分数,最终用导出的 DataFrame 绘制参数重要性图,定位到最关键的两个参数并手动微调,一举进入前排。

Python 演示

python50 行
import optunaimport joblibfrom sklearn.datasets import load_irisfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import cross_val_score  def objective(trial):    n_estimators = trial.suggest_int('n_estimators', 50, 300)    max_depth = trial.suggest_int('max_depth', 3, 15)    min_samples_split = trial.suggest_int('min_samples_split', 2, 10)    use_bootstrap = trial.suggest_categorical('bootstrap', [True, False])     model = RandomForestClassifier(        n_estimators=n_estimators,        max_depth=max_depth,        min_samples_split=min_samples_split,        bootstrap=use_bootstrap,        n_jobs=2,        random_state=42,    )    X, y = load_iris(return_X_y=True)    score = cross_val_score(model, X, y, cv=5, scoring='accuracy').mean()    trial.report(score, 0)    if trial.should_prune():        raise optuna.TrialPruned()    return score  def main():    study = optuna.create_study(direction='maximize', study_name='iris_rf')    study.optimize(objective, n_trials=30, n_jobs=3, timeout=120)    print('best_params:', study.best_params)    print('best_value:', study.best_value)    df = study.trials_dataframe()    df.to_csv('optuna_results.csv', index=False)    best_model = RandomForestClassifier(        n_estimators=study.best_params['n_estimators'],        max_depth=study.best_params['max_depth'],        min_samples_split=study.best_params['min_samples_split'],        bootstrap=study.best_params['bootstrap'],        random_state=42,    )    X, y = load_iris(return_X_y=True)    best_model.fit(X, y)    joblib.dump(best_model, 'best_model.joblib')  if __name__ == '__main__':    main()
目的:用 Optuna 对随机森林做超参数搜索,包含剪枝、并行、结果导出与最优模型保存的完整流程。
  1. study = optuna.create_study(direction='maximize')创建研究方向为“越大越好”的调参容器,相当于打开一本空的美食笔记。
  2. trial.suggest_int('n_estimators', 50, 300)在 50 到 300 之间采样一个整数参数,相当于在菜单上圈定可选范围。
  3. trial.report(score, 0)把当前分数上报给剪枝器,相当于告诉领班“这道菜目前什么水平”。
  4. trial.should_prune()询问剪枝器“这道菜要不要提前撤盘”,返回 True 就终止试验。
  5. study.optimize(objective, n_trials=30, n_jobs=3, timeout=120)启动搜索:最多 30 轮、3 个并行、总时长限制 120 秒。
  6. study.best_params一键取出最优参数组合,相当于翻开美食笔记找到评分最高那桌的完整配方。
  7. study.trials_dataframe()把全部试验记录导出为表格,方便做参数重要性分析和报告。

常见误区

误区反正都是跑很多组参数,我自己写个 for 循环随机生成参数,效果不是一样的吗?

正解for 循环没有“学习能力”,它不会根据历史结果调整下一组参数;Optuna 的 TPE 采样器会从历史 trial 中学习,在好参数附近加密采样。用循环等于蒙眼探店,用 Optuna 等于边吃边记笔记边调整下家的选择。

为何常见:初学者看到 optimize 内部也是循环执行 objective,误以为只是语法糖,忽略了采样器的智能化。

误区加了 `MedianPruner` 就万事大吉,搜索速度一定显著提升。

正解剪枝只对“中间指标能预测最终结果”的训练有效。如果训练早期噪声极大,剪枝可能误杀好参数,导致最终效果变差。实践中应调大 n_startup_trials,让前若干次试验不剪枝,建立可靠的历史基准。

为何常见:多数教程只演示剪枝带来的加速,很少讨论剪枝的适用条件和误杀风险。

误区设 `n_jobs=16` 就一定比 `n_jobs=4` 快 4 倍,资源越多越好。

正解并行 trial 会争抢 CPU/GPU,单个 trial 训练变慢,且数据库写入有竞争。实测中并行度过高时总耗时可能不降反升,最优并行度需要根据单 trial 的资源占用实测确定。

为何常见:人们直觉上认为并行等于线性加速,忽略了阿姆达尔定律和资源争抢的现实。

误区把学习率范围设成 `[1e-10, 1]`,反正采样器聪明,能自己找到好值。

正解范围过大会稀释采样密度,有限预算下大量 trial 浪费在无效区域。应该根据业务经验或粗跑结果先圈定合理区间,再用 loguniform 处理量级差异。

为何常见:初学者对参数的量级没有概念,倾向于“宁大勿小”,实则适得其反。

误区调参完拿到 `best_params` 就结束了,中间试验记录没必要保存。

正解trials_dataframe 导出的中间结果可用于分析参数重要性、诊断搜索是否收敛、排查异常 trial。没有中间数据,你无法回答“为什么是这个参数”这一关键问题。

为何常见:人的注意力天然集中在“最好”的结果上,容易忽略过程数据对复盘和沟通的价值。

面试题

Q1. 在 Optuna 中,负责记录整个超参数搜索过程(所有试验的总容器)的对象是?

单选题 · easy

  • A.Trial
  • B.Study← 正确答案
  • C.Objective
  • D.Sampler

答案:B。Study 是整个搜索过程的容器,记录所有试验;Trial 是单次试验,Objective 是目标函数,Sampler 是采样算法。类似“美食笔记”是整个探店记录,而单次试吃只是其中一页。

Q2. 下列哪个方法用于在目标函数中声明一个浮点超参数?

单选题 · easy

  • A.trial.suggest_int()
  • B.trial.suggest_categorical()
  • C.trial.suggest_float()← 正确答案
  • D.trial.report()

答案:C。suggest_float 用于浮点连续参数,suggest_int 用于整数,suggest_categorical 用于类别参数,report 用于上报中间分数。对应菜单上“选一个浮点数值”就是 suggest_float。

Q3. TPE 采样器选择下一组超参数时,主要依据是哪个指标?

单选题 · mid

  • A.历史最优值
  • B.随机采样概率
  • C.期望提升← 正确答案
  • D.交叉验证误差

答案:C。TPE 核心是选择期望提升(EI)最大的候选点。它从历史试验中分别估计好/差两组参数分布,计算每个候选点的期望改进,取最大者作为下一轮试验。这相当于“挑最可能超越当前最高分的店去试吃”。

Q4. 关于 MedianPruner 剪枝策略,下列说法正确的有?

多选题 · mid

  • A.它需要训练过程上报中间分数← 正确答案
  • B.它是根据历史试验的中间分数中位数来判断是否提前终止← 正确答案
  • C.它对所有模型都一定能加速
  • D.前若干次试验可能不触发剪枝← 正确答案

答案:ABD。MedianPruner 依赖 trial.report 上报中间分数,并与历史同一步数下的中位数比较;早期试验因历史数据不足通常不剪枝(n_startup_trials)。但它对噪声极大的训练可能误杀,所以 C 错。对应“尝一口判断整桌菜”需要基准线,没有基准就先不撤盘。

Q5. 要使多个 Optuna 进程共享同一个 Study,应配置哪种存储?

单选题 · easy

  • A.InMemoryStorage
  • B.RDBStorage← 正确答案
  • C.FileStorage
  • D.NoStorage

答案:B。RDBStorage(如 SQLite/PostgreSQL)让多进程读写同一数据库,实现跨进程共享 study。InMemoryStorage 只存在单进程内存中,无法跨进程共享。相当于多个朋友共享同一本美食笔记,得把笔记放在大家都够得着的桌上。

Q6. 对于量级相差很大的参数(如学习率 1e-5 到 1e-1),应优先使用哪种采样方式?

单选题 · mid

  • A.suggest_uniform
  • B.suggest_loguniform← 正确答案
  • C.suggest_int
  • D.suggest_categorical

答案:B。loguniform 在对数尺度上均匀采样,让小数值区间获得同等探索机会;uniform 在线性尺度上采样,小数值几乎被淹没。相当于味道浓度按指数刻度分层,而不是按线性刻度平分。

Q7. 关于 Optuna 并行调度,说法正确的有?

多选题 · hard

  • A.n_jobs 控制同时执行的 trial 数量← 正确答案
  • B.分布式场景需配置共享存储← 正确答案
  • C.并行度越高,搜索速度一定越快
  • D.并行采样天然增加了探索的多样性← 正确答案

答案:ABD。n_jobs 控制并行 trial 数;分布式需要 RDBStorage 共享进度;多个 worker 同时采样扩大了探索范围。但并行度受资源和通信开销限制,并非越高越好,故 C 错。相当于朋友越多探店越快,但朋友太多会互相挤在同一家店门口。

Q8. 在 TPE 算法中,参数 γ 的主要作用是?

单选题 · hard

  • A.控制学习率大小
  • B.控制好/差两组试验的分位数阈值← 正确答案
  • C.控制并行进程数量
  • D.控制剪枝的严格程度

答案:B。γ 用于划分“好”与“差”两组试验的阈值分位数,例如 γ=0.25 表示前 25% 的试验算好,其余算差,进而分别估计 l(x) 和 g(x)。注意 C 是 n_jobs 的职责,D 是剪枝器的职责。

Q9. 关于 Optuna 结果导出与生产应用,下列说法正确的有?

多选题 · extreme

  • A.trials_dataframe 可导出全部试验的参数与分数← 正确答案
  • B.将 study 保存到 RDB 可支持断点续跑← 正确答案
  • C.生产环境只能使用最优参数,不能再调整搜索空间
  • D.checkpoint 保存的是完整 study 对象

答案:AB。A 正确,DataFrame 导出所有试验记录;B 正确,RDB 存储可持久化 study,重启后继续优化。C 错误,生产环境应根据数据漂移动态调整搜索空间;D 错误,checkpoint 通常保存训练好的模型而非 study 本身。就像菜谱可以不断修订,不必一次定死。

Q10. 下列关于 objective 函数的写法,正确的是?

单选题 · mid

  • A.objective 返回字符串表示结果好坏
  • B.objective 必须接收一个 trial 参数,并返回数值分数← 正确答案
  • C.objective 不需要返回任何值
  • D.objective 只能使用 suggest_float 声明参数

答案:B。objective 必须接收 trial 并用 suggest_* 声明参数,最终返回一个数值分数,Optuna 根据分数更新研究记录。返回字符串或空都会导致搜索无法比较优劣。相当于试吃后必须给个分数,不能只说“还行”。