动手看看:步长怎样改变迭代?

示例函数 f(x) = x² / 2,更新式 xₖ₊₁ = (1 − α)xₖ。改变步长,观察接下来 12 步的 x 值。

±3.00012 步

加载交互实验中;正文包含完整推导。

先把问题缩小到可以手算

考虑 f(x) = x²/2。它的导数为 f′(x) = x,唯一最小点是 x* = 0,最小值为 0。梯度下降每次沿导数的反方向移动:xₖ₊₁ = xₖ − αf′(xₖ)。把导数代入,便得到 xₖ₊₁ = (1 − α)xₖ,其中 α 是固定步长。

反复代入可得 xₖ = (1 − α)ᵏx₀。此时,算法能否收敛不再是模糊的直觉,而是几何数列的问题:对任意初值都收敛到 0,需要 |1 − α| < 1,也就是 0 < α < 2。若初值本来就是 0,迭代当然会一直停在最小点。

同样收敛,轨迹也可以不同

当 0 < α < 1 时,1 − α 为正,非零初值保持原来的符号,绝对值逐次缩小。α = 1 时,一步就到达最小点。1 < α < 2 时,因子为负,迭代会跨过最小点、左右交替,但距离仍在缩小。因此,看到参数振荡,并不能立刻断言算法发散。

边界也值得单独检查。α = 0 时没有更新;α = 2 时,非零初值在 x₀ 和 −x₀ 之间反复跳动;α < 0 或 α > 2 时,非零初值的绝对值不断放大。这里的函数值满足 f(xₖ₊₁) = (1 − α)²f(xₖ),所以稳定区间内的函数值非增;只要尚未到达最小点,下一步的函数值就严格下降。

  • α = 0.5:误差每一步缩小为原来的一半。
  • α = 1.5:误差大小也减半,但符号交替。
  • α = 2.1:误差大小每一步变为原来的 1.1 倍。

把推导变成一个小实验

下面的代码只用 Python 标准语法。固定初值,逐个改变步长,同时观察参数和函数值。实验的目的不是替代证明,而是检查公式、实现和直觉是否一致。

for alpha in (0.5, 1.0, 1.5, 2.0, 2.1):
    x = 4.0
    print(f"alpha={alpha}")
    for k in range(6):
        print(k, round(x, 6), round(x * x / 2, 6))
        x = (1 - alpha) * x

不要把数字 2 当成通用规则

这里的区间来自函数本身。若改为 f(x) = ax²/2,且 a > 0,条件就变成 0 < α < 2/a。对多维正定二次函数 f(x) = xᵀAx/2,其中 A 为实对称正定矩阵,固定步长收敛的条件是 0 < α < 2/λmax(A)。不同方向的曲率不同,最陡的方向限制了稳定步长。

一般非线性问题还需要检查光滑性、凸性等假设,不能直接套用这一维例子的结论。读到一个步长建议时,先问清楚目标函数是什么、结论依赖哪些条件,再决定它是否适用于手头的问题。