原视频:【手撕面试】Adam 的偏差修正:为什么少了它第一步步长被放大三倍,代码只要多两行 UP 主:古希腊掌管代码的神 | 时长:0:58 | tag:手撕面试 链接:https://www.bilibili.com/video/BV1rkJQ6PErc
Adam 的 $m$、$v$ 都从 0 开始做指数滑动平均,早期估计被系统性低估,且 $v$ 低估得比 $m$ 更狠(一个带根号、一个不带),不做偏差修正的话第一步的更新量会被放大到约 3.16 倍;修正就是分别除以 $1-\beta_1^t$ 和 $1-\beta_2^t$,代码只多两行。
30 秒版:Adam 维护梯度的一阶矩 $m$ 和二阶矩 $v$,更新量是 $m/(\sqrt{v}+\epsilon)$,让每个参数按自己的梯度尺度走步。问题是 $m$、$v$ 从 0 初始化:第一步 $m$ 只有真实梯度的 $1-\beta_1=0.1$ 倍,$v$ 只有梯度平方的 $1-\beta_2=0.001$ 倍,开根号后 $\sqrt{v}$ 缩到 $1/31.6$,两边缩水程度不一致,比值被放大 $\frac{0.1}{\sqrt{0.001}}\approx 3.16$ 倍。偏差修正把两个估计分别除以 $(1-\beta_1^t)$、$(1-\beta_2^t)$ 补回来;随 $t$ 增大修正因子趋于 1,自动失效。手写时漏掉这两行,是最常见的扣分点。
手写代码(完整一步):
# t 从 1 开始;beta1=0.9, beta2=0.999, eps=1e-8
m = beta1 * m + (1 - beta1) * g
v = beta2 * v + (1 - beta2) * g * g
m_hat = m / (1 - beta1 ** t) # 偏差修正:多出来的就是这两行
v_hat = v / (1 - beta2 ** t)
theta -= lr * m_hat / (v_hat ** 0.5 + eps)
更新量 $\Delta\theta = \text{lr}\cdot \dfrac{\hat m_t}{\sqrt{\hat v_t}+\epsilon}$:分子是梯度的滑动平均(方向),分母是梯度平方滑动平均的根号(尺度)。效果是梯度大的参数走小步、梯度小的走大步——每个参数的有效步长被归一到 lr 量级附近。
$m_t$、$v_t$ 本质是"从 0 出发的加权平均",权重总和分别是 $1-\beta_1^t$、$1-\beta_2^t$,早期远小于 1,所以估计值被系统性压低。以恒定梯度 $g=1$ 为例,第一步:
$$\hat m_t = \frac{m_t}{1-\beta_1^t}, \qquad \hat v_t = \frac{v_t}{1-\beta_2^t}$$
第一步修正后更新量恰好回到 1 倍;随着 $t$ 增大,$1-\beta^t \to 1$,修正自动消失,不需要手动关。一个容易被追问的细节:即使梯度恒定,未修正的比值也不是恒定 3.16 倍——它先升到约 6.6 倍($t\approx10$–$20$ 步附近),再用上千步慢慢回落到 1,所以"早期步长失真"不只是第一步的事。