深度学习调参指南:超参数搜索的可执行流程与常见问题排查

发布时间:2026/10/28 18:15:45
深度学习调参指南:超参数搜索的可执行流程与常见问题排查

简介:深度学习调参指南中文版是一份面向工程师与研究者的系统性调优手册,由Google等机构的研究人员撰写,聚焦模型性能最大化过程中最耗时的超参数调整环节。内容从模型架构、优化器与Batch Size的选择讲起,延伸到损失函数取舍、正则化技术应用、增量调整策略与探索—利用平衡,并给出工作流实施和训练排错的可操作建议,适合具备机器学习基础的读者按章节对照实验。包体为单个PDF文件,压缩后约3.09MB,内含完整中文译本,目录按「开始新项目」「提高模型性能的科学方法」等模块组织,便于按主题检索。目前已有904人学习下载。读者可从中获得一套减少盲目试错的调参流程:先确定可行的初始配置与训练吞吐量,再以科学实验的方式设计下一轮实验,同时理解学习率、批大小等参数的联动影响,对实际项目落地与论文复现均有参考价值。

1. 调参不是玄学:这份中文手册把超参数搜索拆成了可执行流程

上周有位做视觉的同行问我,模型训到 78% 就卡住不动了,是不是该换个架构。我让他把最近二十次实验的配置列出来,结果学习率、batch size、正则强度三样东西同时在变——这样做得到的结论并不能说明调参有效,反而更像是在随机尝试。这份深度学习调参指南中文版处理的正是这个场景:它把“如何把模型性能最大化”拆成一组有先后顺序的动作,从新项目开始时要定下的三项配置,到每轮实验只回答一个问题,再到训练步数、输入管道和检查点这类工程细节。它适合已经能跑通训练脚本、但实验结果还靠运气的工程师和研究生;纯新手可以先补基础概念,这份手册不负责从零讲反向传播。

2. 新项目起手三件事:架构、优化器与 Batch Size 的定盘顺序

很多人把调参理解成“训起来之后调学习率”,手册的第一章把时间线往前推了一大截:真正决定后面能不能调得动的,是项目开头那三个一次性决定——架构、优化器、batch size。这三样如果选得随意,后面每一轮实验都会带着系统性偏差,你在错误的基础上做再精细的搜索也只是把噪声拟合得更漂亮。

手册在进入第一章之前先列了四条前置假设,我觉得比正文更值得先对照检查:问题定义和数据清洗已经完成;训练与评估的工作流已经能稳定跑通,换模型只需要改配置;评估指标已经选定,并且尽可能贴近部署环境里的真实度量;有足够的算力同时跑起若干个训练。这四条缺任何一条,调参都会变成在流沙上盖楼。尤其是第三条,指标选错的话,后面所有实验排序都是错的。

2.1 架构复用:先找一篇贴脸的论文,再谈自定义

手册给的第一条建议朴素到有点反直觉:新项目不要自己设计架构,先复用一个成熟、常用的模型。理由很实际——成熟的架构有公开的参考配置、有别人踩过的坑、有可对比的基线数字,你起的第一个模型能多快进入“能训练出结果”的状态,直接决定了后面探索的效率。

这里有个容易被忽略的认知:选架构,本质上是在选一族模型,而不是选一个模型。层数、层宽、激活函数类型、归一化放在哪一层之后,这些都是这一族里的超参数,你选 ResNet 还是选 Transformer,只是选了不同的参数空间。所以“复用”不等于“照抄”,而是“拿一个已知能工作的参数空间当起点”。

我一般的判断顺序是这样的:

判断项通过标准不通过怎么办
任务形态输入输出结构一致(分类对分类、序列对序列)改输出头,主干仍可复用
数据规模与参考工作的量级相差不超过一个数量级同步缩放模型宽度与正则强度
参考配置论文或开源实现里有完整的训练配置自己补一轮小规模搜索补上

复现的时候,把论文里没写清楚的默认值全部确定下来并记进配置文件:权重初始化方式、归一化的位置、数据增强的强度、warmup 比例。这些东西论文里常常一笔带过,但你换一个值结果能差两个点。我的习惯是先跑一个“啥花活都不加”的干净基线,mixup、复杂衰减、多尺度推理这些先都不要,等基线稳定复现了再一个个加。

提示:基线的目标不是刷到最好,而是“明显好于随机猜,并且隔一周再跑一次结果还能对上”。做不到可复现,后面的对比实验全都没有意义。

2.2 优化器选型:把超参数少的那个放前面

手册里有一句话我特别认同:不存在适用于所有问题和架构的“最佳”优化器,而且光是公平地比较两个优化器,本身就是一项艰难的研究工作。所以工程上的做法不是“找最好的”,而是“先用最不容易出错的”。

判据有两条。第一,同类型任务上最常用的那个;第二,超参数最少的那个。第二条尤其关键——优化器超参数越多,你要花的调优预算就越多,而这些预算本来应该花在架构和数据上。项目初期把优化器超参数当成“冗余超参数”固定住,是很划算的交易。

优化器需要认真对待的超参数适合的阶段实践备注
SGD + Nesterov 动量学习率、动量项目后期冲最后一两个点超参少、泛化常常更好,但对学习率极敏感
Adam学习率、β1、β2、ε新项目起步、不稳定任务默认值能用,但不等于最优;四个都该调
NAdam同 Adam想要 Adam 的鲁棒性再加动量超参数量与 Adam 一致,调优成本相同

比较务实的路径是:起步用 Adam,β1 固定 0.9、β2 固定 0.999、ε 固定 1e-8,只调学习率,先把基线跑出来;等项目成熟、指标开始抠小数点后一位了,再换 SGD + 动量做一轮对比。反过来先上 SGD,很容易在前两周就被“学习率稍微大一点就发散”劝退。

2.3 Batch Size:先量吞吐,再决定要不要加大

关于 batch size,手册给了三条明确结论:它决定训练速度;它不应该被直接用来调验证集性能;通常硬件能支持的最大 batch size 就是理想值。第三条有前提——训练吞吐率必须随着 batch 变大而真的上升。

所以第一步不是选 batch size,是测吞吐率。做法很笨但有效:从 2 的幂开始,64、128、256、512 一路往上跑,每个值跑够几十步,记录每步耗时,直到某一个值直接爆显存。

import time def measure_step_time(step_fn, loader, warmup_steps=5, measure_steps=20): """step_fn: 一次完整的前向+反向+更新;loader: 训练数据迭代器""" it = iter(loader) # 预热:跳过显存分配器、kernel 选择、数据线程启动带来的抖动 for _ in range(warmup_steps): step_fn(next(it)) t0 = time.perf_counter() for _ in range(measure_steps): step_fn(next(it)) elapsed = time.perf_counter() - t0 step_time = elapsed / measure_steps # 每步耗时(秒) throughput = len(next(iter(loader))[0]) / step_time # 样本/秒,用真实 batch 大小 return step_time, throughput

这段代码只做一件事:把“每步耗时”和“每秒样本数”测准。warmup_steps不能省,前几步的耗时会被各种一次性开销污染;measure_steps取 20 到 50 之间比较稳,太少了会被单步抖动带偏。拿到数据之后看两个关系:batch 翻倍时,吞吐率是否接近翻倍;等价地,每步耗时是否近似不变。如果 batch 翻倍而每步耗时也翻倍,说明加速器根本没吃满,瓶颈在数据读取或者多卡同步上,这时候加大 batch 一点用都没有,得先把瓶颈修掉。

还有一个概念叫临界 batch size:在这之前,batch 翻倍能让达到同样效果所需的步数减半,这叫完美缩放;过了这个点,步数减少的幅度就衰减了,再大也不会更省时间。工程上的好消息是,硬件能支持的最大 batch 往往还小于临界值,所以“能用多大用多大”这条经验法则大概率成立。

最后两条红线要记住。第一,梯度累积可以让你在显存不够时模拟大 batch,但它不带来任何吞吐收益,应用型项目里除非被显存逼到墙角,否则不要用。第二,改 batch size 之后,学习率和正则化强度必须重新调,这两个东西跟 batch size 的交互最强。所以项目开头选 batch size 时要想清楚:以后换 batch,等于把调参进度清零重来。

2.4 初始配置:简单、快、够用

手册对初始配置的要求是三个词:简单、相对快、资源消耗相对低,同时结果“合理”。简单指的是尽量不加花活,比如先在常数学习率下跑通,再考虑衰减方案;快指的是模型先小一点、步数先少一点,让每轮实验的周期短下来。

“合理”这个词手册自己也承认很模糊,但给了一个下限:明显好于随机猜,哪怕还差得不能部署。定训练步数时有个权衡——步数多一点,性能更好、调参也更容易;步数少一点,每次实验更快、能并行跑更多组。麻烦在于步数一旦和学习率绑定了,后面再改就得重调学习率。所以初始步数不要拍一个特别大的数,宁可先小后大。

3. 把调参变成科学:目标、冗余、固定三类超参数与一轮一问

从这一章开始,手册从“配置”转向“方法”。核心主张是:配置空间大到没有任何自动算法能在没有人工指导的情况下有效搜索,所以真正有效的路径是增量调整——从简单配置开始,一轮加一点,每一轮都保证改进有据可循。

手册把整个循环压成了四步:为下一轮实验确定目标;设计并执行实验;从结果里获取经验;判断要不要把新配置“上线”(这里的上线指更新团队内部的最佳配置,不一定是对外发布)。这四步里最容易被跳过的是第一步和第四步,而它们恰恰决定了你是在做实验还是在做布朗运动。

3.1 探索与利用:大部分时间该花在理解问题上

手册有个观点挺反主流:多数人以为调参的时间主要花在压低验证集错误率上,实际上应该把大部分时间花在“探索”——理解问题结构,只有小部分花在“利用”——抠指标。理由是短期的指标收益经常来自巧合,而理解问题结构带来的收益是复利的。

具体来说,探索能带来四类收益:一是避免保留那些“因为历史原因恰好有效”的改动,这类东西是技术债的主要来源;二是搞清楚验证集对哪些超参数最敏感、哪些超参数之间强交互必须一起调、哪些基本不敏感可以固定住;三是发现新方向,比如发现过拟合严重才知道该上正则;四是砍掉无效方向,让后续实验空间变小。

落到操作上,就是每轮只回答一个问题。想同时验证“新正则器有没有用”和“层数加到 12 会不会更好”,最后一定解释不清收益来自哪里。

3.2 三类超参数怎么分:以“加深模型是否有用”为例

这是整份手册里我认为最值得抄下来的一节。给定一个实验目标,所有超参数都能归到三类:目标超参数(你想测它对模型的影响)、冗余超参数(必须一起优化才能公平比较)、固定超参数(本轮固定不动)。

举个具体例子,目标定为“更深的模型是否能降低验证集错误”:

角色本轮取值为什么
目标超参数层数(6 / 8 / 10 / 12)要测的就是它
冗余超参数学习率最优学习率和模型结构强相关,不分别调就没法公平比
固定超参数激活函数、优化器 β、数据增强强度过去实验表明它们和深度交互弱,固定能省大量算力

这里最容易犯的错是把学习率固定住去比较层数——不同深度的模型最优学习率不一样,你在同一个学习率下比出来的“深模型更差”,很可能只是深模型没被调到最优。这种实验跑完得到的结论是无效的,但它看起来很像一个结论,所以危害更大。

固定超参数不是免费的,它的代价是给你的结论加了一个限定条件:结论只在固定值的这个水平上成立。手册的建议是,当你判断“固定它带来的限制”小于“调它所需的算力”时,才把它转成固定。如果算力无限,所有非目标超参数都该保持冗余状态。

3.3 读结果的三个动作:曲线、isolation 图、边界检查

实验跑完,第一件事是看训练曲线,而不是只看最后一个数字。曲线能告诉你的东西多得多:验证指标还在降说明步数不够;训练降验证升说明该上正则或加数据;曲线周期性抖动说明学习率偏大或者 batch 太小。

第二件事是画 isolation 图——横轴是目标超参数取值,纵轴是该取值下所有试验里最好的验证误差。这张图能直接回答“加深到底有没有用”,而不是被其他超参数的噪声掩盖。

import pandas as pd import matplotlib.pyplot as plt # trials.csv 每行一次试验:目标超参数取值 + 该次试验的最优验证误差 df = pd.read_csv("trials.csv") target, metric = "num_layers", "val_error" # 每个取值只保留最好的一次,避免用平均值掩盖"某些配置根本没调好" best = df.groupby(target)[metric].min().reset_index() fig, ax = plt.subplots(figsize=(6, 4)) ax.plot(best[target], best[metric], marker="o") ax.set_xlabel(target) ax.set_ylabel(f"best {metric}") ax.grid(alpha=0.3) fig.savefig("isolation_%s.png" % target, dpi=150)

逻辑很简单:按目标超参数分组取最小值,画折线。取min()而不是mean()是关键——某个层数下如果跑了五个学习率,你要的是它“最好能到哪”,均值只会把调得好的配置和没调好的配置混在一起。marker="o"是为了看清采样点位置,如果最优点两侧没有邻居点,说明采样密度不够,这一轮的结论不可信。

第三件事是检查搜索空间边界。如果最优点死死贴在区间端点上,几乎可以断定你的区间设窄了,真实最优在区间外面。同理,如果某个取值下的所有试验都很差,也要确认不是学习率没调好导致的。

3.4 上线判定:给每次改动留一条证据链

手册把“上线”定义成更新团队的最佳配置,并且强调每次上线必须有据可循,不能是碰运气碰出来的。我自己的判据是三条:有一组干净的对照实验(只改了一个变量);换两三个随机种子重跑,收益还在;收益幅度大于历史同配置的波动范围。

第三条最容易被忽略。验证集上的提升如果只有 0.2 个点,而同一个配置换个种子能抖动 0.4 个点,那这个“提升”就是噪声。手册里提到的做法是自动化常用绘图,让每次实验结束自动出曲线和对比表,这样你能直接看到抖动带有多宽,而不是靠回忆。

每次上线还要同步记录:配置版本、数据版本、代码提交号。少记一样,三个月后想复现最佳结果就得重新猜。

4. 训练步数与训练管道:max_train_steps、评估与检查点怎么钉死

训练步数看着是个不起眼的数字,实际上是整个调参流程里最难改的一个——它和学习率、衰减方案、正则强度全部耦合。手册专门用一章讲它,逻辑是:先想清楚你能给多少算力,再决定用哪套方法定步数。

4.1 算力不紧张时:用学习率搜索反推步数

不受算力限制的意思是,你可以承受跑“步数足够长、直到模型明显进入平台期”的实验。这种情况下定步数的流程是:

  1. 先设一个明显偏大的max_train_steps,大到你有把握模型会在中途收敛;
  2. 在这个步数下做一轮学习率扫描,按对数尺度取点,比如 1e-5、3e-5、1e-4、3e-4、1e-3、3e-3,每个点跑一次;
  3. 对表现最好的那几个学习率,把验证指标随训练步数的曲线画出来;
  4. 取曲线进入平台期之后一点的位置,作为正式训练步数。

为什么绕这一圈?因为学习率和步数是一对绑定参数,你不知道收敛点在哪,就没法判断当前学习率是“太大导致震荡”还是“步数不够导致没训完”。先有曲线,才有判断依据。

4.2 算力紧张时:两轮策略先短后长

算力紧张是更常见的情况。手册给的是两轮法:第一轮用短步数快速筛,第二轮用完整步数复核。

轮次步数预算数据量目的主要风险
第一轮完整步数的 1/5 到 1/3可子采样快速淘汰明显差的配置排序与长跑不一致
第二轮完整步数全量对第一轮 top-k 复核排序成本高,k 要小

第一轮的关键是“跑得多、跑得浅”,用足够多的配置把搜索空间的形状摸出来;第二轮只保留第一轮排在前面的几个配置,用完整预算重跑。必须做第二轮的真正原因是,有些超参数(尤其是正则化类和衰减类)在短跑里根本体现不出差异,短跑排序和长跑排序不一致是常见现象,跳过复核直接上线,翻车概率很高。

4.3 输入管道与定期评估:让每一步都花在算模型上

输入管道的优化目标只有一个:让加速器不空转。判断方法也很直接——在每步的前后打点,看数据加载占总步时的比例。如果这个比例超过 10%,就值得动手了。常见手段包括预取下一批、多进程并行解码、把能放到加速器上做的预处理搬过去、把能塞进内存的小数据集整体缓存。

有一件事必须提前定好:评估频率。评估太频繁会拖慢训练,太稀疏会错过最好的检查点。我的习惯是每固定步数在固定的一个小验证子集上评估,训练结束再在全量验证集上评一次。这里有个细节很关键——定期评估用的样本必须固定,否则曲线抖动里有一大半来自采样差异,你会把它误判成模型不稳定。

def train_loop(step_fn, eval_fn, save_fn, loader, max_steps=50000, eval_every=1000, keep_best=3): best = [] # 保存 (指标, 步数, 路径),只留最好的 keep_best 个 for step, batch in enumerate(loader, start=1): step_fn(batch) if step % eval_every == 0 or step == max_steps: score = eval_fn() # 固定的验证子集,口径不许变 path = save_fn(step, score) # 先落盘再更新排行榜 best.append((score, step, path)) best.sort(key=lambda x: x[0]) for _, _, old in best[keep_best:]: # 淘汰超出名额的旧检查点 remove_if_exists(old) best = best[:keep_best] if step >= max_steps: break return best

这段骨架做了两件容易被忽略的事:一是先保存再更新排行榜,保证排行榜里的每个路径都真实存在;二是用keep_best限制保留数量,避免磁盘被几万个检查点塞满。eval_every的取法我一般按“总步数的 1/20 左右”给,既能画出像样的曲线,又不至于让评估时间占比过高。eval_fn里不能用随机采样的验证子集,这是这条流水线上最常见的隐形 bug。

4.4 检查点与实验跟踪:后悔药要提前埋

检查点策略的原则是:按验证指标保存,不按训练 loss 保存。训练 loss 最低的那个点经常是过拟合最严重的点。同时保存最近 N 个和最优 K 个——最近 N 个用于训练崩溃时续跑,最优 K 个用于事后挑模型。

实验跟踪这块,很多训练框架都提供了对应的插件或回调机制,挂上去就能把配置、指标曲线和环境信息一起记下来。至少要有这几项:完整配置(包括所有默认值)、每次评估的指标、随机种子、代码版本。少记随机种子,你会遇到“同样的配置跑出两个差 1 个点的结果,然后花一周找原因”的情况。

多主机训练还有几个额外注意点:各设备的 batch 统计量是否要跨设备同步、数据分片有没有重叠、随机种子是不是每台机器不同。这几条任何一条出问题,现象都是“训练能跑但指标就是差一点”,排查起来非常费时间。

5. 常见问题排查:五类翻车现场的现象、原因与解决

调参手册最有价值的部分往往不是“该怎么做”,而是“出问题了看哪里”。手册里关于训练不稳定、搜索空间、评估口径的几节,基本覆盖了我这几年遇到的大部分事故。下面五条按“现象 → 原因 → 解决”整理,都是可以直接照着查的。

5.1 训练早期 loss 尖峰甚至 NaN

现象:前一两百步 loss 正常下降,然后突然窜到几千,或者直接变成 NaN,训练中断。

原因:最常见的是初始学习率相对当前参数尺度太大,前几步梯度范数很大,一次更新把参数推到数值不稳的区域;其次是某些层(尤其是深层的归一化层或注意力层)梯度爆炸;少数情况是数据里混进了异常样本。

解决:优先加学习率预热——前 1% 到 5% 的步数里,学习率从接近 0 线性升到目标值,让参数先走到一个相对稳定的区域;同时加全局梯度范数截断,常见的阈值是 1.0,先截断再更新。如果这两条都不管用,再把学习率降一个量级重试,同时抽查几条训练样本看有没有异常值。

def lr_at(step, base_lr, warmup_steps, total_steps): if step < warmup_steps: return base_lr * (step + 1) / warmup_steps # 线性预热,避免前期大更新 return base_lr # 起步阶段先用常数,别急着上衰减 def clip_grads(params, max_norm=1.0): total = sum((p.grad ** 2).sum() for p in params if p.grad is not None) ** 0.5 if total > max_norm: scale = max_norm / (total + 1e-6) for p in params: if p.grad is not None: p.grad *= scale # 按全局范数等比缩放,保持梯度方向 return total

warmup_steps取总步数的 1% 到 5%,短跑实验里可以取绝对值 500 到 2000 步。max_norm从 1.0 起步,如果你的模型梯度本来就很大,可以试 5.0,但不要为了“让它不报错”一路往上调——截断阈值调太大等于没加。返回值total建议打进日志,它是判断训练是否稳定的最灵敏指标之一。

5.2 加了 BatchNorm 之后小 batch 直接崩

现象:batch size 从 256 降到 32,验证指标掉一大截,训练 loss 抖得厉害,但模型结构没改。

原因:BatchNorm 用当前 batch 的均值和方差做归一化,batch 变小之后这两个统计量的估计噪声急剧变大;更麻烦的是推理时用的是滑动平均统计量,和训练时的分布对不上,训练和推理出现系统性偏差。

解决:优先考虑把 batch 提回去,这是最简单的修复。做不到的话,退而求其次——保持参与梯度计算的 batch 不变,但把统计量的计算拆成固定大小的块(Ghost Batch Norm 的思路),让统计量的有效样本数不随总 batch 缩小;或者换成不依赖 batch 维度的归一化方式;再或者在小 batch 微调阶段直接冻结归一化层的统计量。

5.3 照抄论文的复杂学习率衰减,结果更差

现象:把论文里的 warmup + 余弦衰减 + 分段下降整套搬过来,反而比一开始的常数学习率还差,而且训到后面指标还在抖。

原因:衰减方案和总步数强耦合。余弦衰减的形状是按论文自己的步数画的,你换一个步数,衰减曲线对应的“快慢节奏”就全变了;另外论文的超参数是在它自己的 batch 和数据规模上选的,直接搬过来本来就未必合适。

解决:退回常数学习率或最简单的线性衰减建立基线,确认基线能跑出合理结果;再逐步加组件,一次只加一个。衰减的终点一般取初始学习率的 1/10 到 1/100,衰减太快等于提前停止学习。warmup 只放在最前面一小段,不要占太大比例。

5.4 最优值死死贴在搜索边界上

现象:画完 isolation 图,最优点落在区间的端点上,比如学习率搜索范围是 1e-4 到 1e-2,最好的点是 1e-2。

原因:搜索空间设窄了,真实最优在区间外;也可能是采样尺度不对,学习率这类跨数量级的参数如果按线性采样,大部分点会挤在数值大的那一侧。

解决:把边界往外扩一个数量级重跑一轮,同时确认扩张后的区间外不是发散区(学习率太大时曲线会直接起飞,这时候端点最优反而是正常的)。学习率、权重衰减这类参数一律按对数尺度采样。如果最优点附近没有邻居点,说明采样密度不够,得在好区域加密。

5.5 验证集指标虚高,上线就掉点

现象:离线验证集指标很漂亮,部署到真实环境差一大截。

原因:三种可能——验证集和训练集存在同源泄漏(同一批数据的不同切片、同一场景的相邻帧);评估脚本的预处理和训练时不一致(裁剪方式、归一化参数、后处理阈值);用验证集调参的次数太多,已经过拟合到验证集上。

解决:先查数据切分,按时间或按主体切,不要随机切;然后把评估脚本固化成一个只读的模块,训练和评估共用同一份预处理代码;最后留一个只在最终确认时用一次的 holdout 集,平时不碰。手册里提到评估指标应尽可能代表部署环境中测量的内容,这条在指标设计阶段就要落实,事后补是补不回来的。

6. 进阶收口:quasi-random search 的采样点怎么花在刀刃上

探索阶段用什么搜索算法,手册的答案有点朴素:准随机搜索(quasi-random search),而不是那些听起来更高级的黑盒优化。理由是探索阶段维度通常不高(三到六个超参数),目标也不是找到全局最优,而是“把大致好的区域圈出来”;这时候覆盖均匀、可完全并行、不引入任何模型假设的准随机采样,性价比最高。复杂的贝叶斯优化更适合在已经圈定的窄区域里做精修。

采样点数量上,我的经验是先给 20 到 30 个点看趋势,如果 isolation 图上最优点附近没有邻居,再在好区域加密 10 到 20 个点。低于 20 个点,你很难区分“这个超参数没用”和“采样没采到”。

from scipy.stats import qmc import numpy as np d = 4 # 待搜超参数个数 sampler = qmc.LatinHypercube(d=d, seed=0) u = sampler.random(n=24) # 24 个试验点,[0,1) 区间内均匀铺开 def log_uniform(x, lo, hi): # 学习率、权重衰减这类跨数量级参数必须走对数 return 10 ** (np.log10(lo) + x * (np.log10(hi) - np.log10(lo))) def uniform(x, lo, hi): # 层数、dropout 这类线性参数 return lo + x * (hi - lo) configs = [{ "lr": log_uniform(row[0], 1e-5, 1e-2), "weight_decay": log_uniform(row[1], 1e-6, 1e-2), "dropout": uniform(row[2], 0.0, 0.5), "num_layers": int(uniform(row[3], 4, 16)), } for row in u]

d要和实际待搜参数个数严格对上,多一个少一个整批点都白跑;n=24是我在单卡预算下比较舒服的值,能并行就往上加;每个维度用哪种映射必须按参数性质来分,学习率走对数、dropout 走线性,搞反了会让采样点严重偏斜。跑完这一批,把结果按目标超参数分组画 isolation 图,再决定下一轮往哪加密——这一步比多跑几十个点更重要。

从那以后我每次开新项目,都会先用 20 个左右的准随机点把搜索空间摸一遍,把最优点和边界的关系画出来,再决定要不要加大算力。跳过这一步直接抄别人的“最佳配置”,是这几年我付出代价最大的一类错误。希望帮到你。

本文还有配套的精品资源,点击获取