学习率大概是深度学习里最玄学的超参数。Adam 的默认值 1e-3 在某个任务上完美工作,换个数据集就 loss 爆炸;你把它调小一个数量级,收敛又慢得像挤牙膏。我最早以为这是运气问题,直到后来明白:学习率本质上是在回答一个几何问题——这一步到底该迈多远?而这个问题,Prodigy 说可以让优化器自己回答。

Prodigy 是 2023 年出现的一个优化器(论文原稿),它的卖点是“无参数学习率”:你不用去纠结该设 1e-3 还是 1e-4,默认把 lr 设成 1.0 就行。它自己会找到合适的大小。但这不是魔法,秘密藏在它的一个内部变量里,这个变量叫 d。
学习率为什么难调?因为你缺了一个距离信息
设想你在旷野里找宝藏,手里只有一个指南针(梯度方向),但没有地图。你的最佳策略是什么?如果确信宝藏很远,你可以大步流星;如果已经到了附近,你必须小碎步。所以,步长应该和你到宝藏的距离成正比。
梯度下降也是一样。数学上,凸函数的最优学习率通常满足一个关系:步长乘以梯度范数,不能超过当前点到最优点距离的量级。也就是说,你想要最优步长,就必须知道“参数离最优点还有多远”。
凸优化经典分析里,常常假设这个距离 D 已知,然后设置学习率为 D 除以某个梯度累积量。但在深度学习中,D 不仅是未知的,甚至是无法预先估计的。
Adam 的解决方法是:不去管 D,直接用一个固定 lr 加上自适应梯度缩放。这在很多场景下 work 得很好,但 lr 一旦跨任务迁移,往往就需要重新调。Prodigy 的出发点是:与其猜 lr,不如去猜 D,然后让数学公式自己把 lr 算出来。
d 是什么?它是在优化过程中被“测”出来的距离
Prodigy 的 d,全称是 distance to optimum,即当前初始点到最优点距离的实时估计。注意,这个估计不是随便给一个值,而是基于每次更新后参数位置的变化推导出来的。
为了做到这一点,Prodigy 维护了两个额外的量:参考点 z,和梯度平方累积 s。你可以把 z 想象成一个“影子参数”——它不是一个独立的模型,而是按照一个固定的规则跟着 x 移动。通过观察 x 与 z 的分裂程度,算法可以反推出“最优点至少离我多远”。
一个简化的三步流程
- 累积梯度能量:每得到一个梯度 g,就把它平方累加到 s 中。s 代表历史梯度的大小,用来归一化。
- 分别移动 x 和 z:参数 x 使用归一化后的梯度(大致是 g 除以 sqrt(s))移动;而参考点 z 使用另一种规则移动,通常与 d 直接关联,形成“对照实验”。
- 从分裂程度提取 d:计算 x – z 在各个坐标上的值,除以 sqrt(s) 对应坐标,取其中的极值。由于凸性,这个极值一定是真实距离 D 的下界。于是 d 更新为 max(旧d,新候选值)。
第三步用到了优化理论里一个著名的上界不等式。简单地说,如果有一个目标点 x*,无论它在哪里,x 和 z 的差异都受到 x* 与初始点距离的约束。所以,你观测到的分裂程度越大,x* 就至少必须离你越远。Prodigy 只是把这个直觉翻译成了严格的数学公式。
d 只增不减,学习率不会爆炸吗?
这是我看论文时最直接的一个疑问。后来想通了:d 只是学习率公式中的一个因子,而不是全部。实际的有效步长由 d 除以平方根 s(再配合动量)决定。s 随着训练一路累加,相当于一个“历史刹车片”。即使 d 在缓慢增长,s 增长得更快,所以有效学习率整体并不会单调爆炸。
更重要的是,d 的递增是有物理意义的:它代表你发现“原来目标点比想象中还要远”,于是把步长下限往上修正。而 s 的增大表示“已经积累了足够的梯度信息”,步长可以自动降下来。这两个过程正好给出了一个类似 warmup 后衰减的学习率曲线,只不过完全自适应。
和上一代 D-Adaptation 比,Prodigy 改了什么?
Prodigy 的前身是 2023 年初的 D-Adaptation。D-Adaptation 第一次成功地在 Adam 框架里自动估计 d,但它对初始 d 的选择过于敏感。原因在于,它的 d 一旦被初始值设定,就会直接作用到第一步的步长上。初始 d 设大了,第一步就可能飞出去;设小了,则要跑很久才能把 d 拉到真实水平。Prodigy 通过调整 d 的更新公式和归一化方式,让 d0 的具体数值成为“无标度”的——你设 1e-6 还是 1e-2,最终都会收敛到几乎同样的 d 轨迹。
| 优化器 | 需要手动设学习率? | 对初始 d0 的敏感度 | 距离估计方式 |
|---|---|---|---|
| AdamW | 是,lr 是关键超参 | 不适用 | 无 |
| D-Adaptation | 否,lr=1 | 高,d0 不对会发散或极慢 | 简单下界,方差大 |
| Prodigy | 否,lr=1 | 低,d0 默认 1e-6 可用 | 更紧的下界,方差小 |
我用 Prodigy 的真实体验:它隐藏了一个超参数
我之前在一个序列标注任务上对比 AdamW 和 Prodigy。用 AdamW,我花了 20 多组实验找到一个不错的 lr;而 Prodigy 我直接 lr=1.0, d0=默认,跑出来的结果就逼近了调过的 AdamW。这让我很震撼。
但接着我就踩坑了——为了“加速”,我把 d0 从 1e-6 调大到 1e-3,结果训练 loss 震荡,最终效果反而变差。我才意识到,Prodigy 并不真的没有超参数,它只是把“学习率”变成了“初始距离估计”。虽然它对 d0 的量级不敏感,但极端值依然会显著影响训练动力学。
如果你要用 Prodigy,我建议:先默认,别动 d0。如果发现前期 loss 平坦,可以把 d0 适当调大一点(比如乘以 100),但不要一下子加到 1。如果后期震荡,则适当减小 d0。
FAQ:关于 d 的几个常见误解
d 是参数向量的维度吗?
不是。d 是一个全局标量,代表算法对于“初始点到最优点距离”的估计值。每个参数坐标共享同一个 d。
d 一直增大,学习率是不是也在一直增大?
不是的。d 确实只增不减,但实际学习率还要除以梯度累积量(和动量相关)。在训练后期,这些累积量增长得更快,有效学习率反而会下降。
Prodigy 真的是“零超参数”优化器吗?
严格说,它只是把学习率这个超参数变成了内部自适应的量。你仍然要设置 d0、β1、β2、weight decay 等。只是其中学习率这一项被大幅简化了。
如果要看更精确的数学表达
论文中,d 的更新可以抽象为 d = max(d_old, sup_i |x_i – z_i| / sqrt(s_i)),而实际步长中还额外引入了除 s 之外的归一化,以保证有界性。具体公式请参考论文原文,但上面的直觉已经足够帮你理解它的行为。
最后说一点我的判断。Prodigy 的 d 自适应机制揭示了一个很美的优化思想:很多你以为是超参数的东西,本质上都是某个几何量的“投影”。学习率不是任意魔数,它和“距离”存在直接的函数关系。谁把这个关系找出来,谁就能让机器自己设置超参数。但反过来看,这个世界并没有免费的午餐——Prodigy 仍然需要你信任它的假设:目标在某种意义上是凸的,或者至少在局部表现得像凸的。当你的损失面非常崎岖、随机噪声特别大时,d 的估计仍会失真。所以,Prodigy 不是替代 Adam 的银弹,而是给那些“不想调学习率”的时刻准备的一把好武器。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/411.html