随机梯度下降(SGD)深度解析:更新规则、动态学习率与凸收敛性分析)
人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载随机梯度下降Stochastic Gradient DescentSGD是《动手学深度学习》d2l-zh全书从头到尾反复使用的训练算法但前几章只使用它而未解释它为何有效。本文基于 chapter_optimization/sgd_origin.md及其中文版 chapter_optimization/sgd.md系统梳理 SGD 的数学原理、单样本更新规则的来源、动态学习率的三类经典调度策略并完整呈现凸目标下收敛性证明的推导过程同时结合 d2l-zh 仓库中d2l工具包的源码实现d2l/torch.py、d2l/mxnet.py进行佐证。读完本文你将能解释为什么深度学习训练几乎总是用 SGD 而非全量梯度下降、为什么学习率必须随时间衰减以及SGD 在凸问题上以 $\mathcal{O}(1/\sqrt{T})$ 速率收敛这些关键问题。从全量梯度下降到随机梯度更新在深度学习中目标函数通常是训练数据集中每个样本的损失函数的平均值。给定 $n$ 个样本的训练数据集假设 $f_i(\mathbf{x})$ 是关于索引 $i$ 的训练样本的损失函数其中 $\mathbf{x}$ 是参数向量则目标函数为$$f(\mathbf{x}) \frac{1}{n} \sum_{i 1}^n f_i(\mathbf{x}).$$$\mathbf{x}$ 处目标函数的梯度为$$\nabla f(\mathbf{x}) \frac{1}{n} \sum_{i 1}^n \nabla f_i(\mathbf{x}).$$计算代价从 $\mathcal{O}(n)$ 到 $\mathcal{O}(1)$如果使用全量梯度下降则每个自变量迭代的计算代价为 $\mathcal{O}(n)$它随 $n$ 线性增长。当训练数据集较大时每次迭代的梯度下降计算代价将较高——每更新一步都要把全部样本的梯度算一遍。随机梯度下降SGD可以降低每次迭代时的计算代价。在 SGD 的每次迭代中我们对数据样本随机均匀采样一个索引 $i$$i\in{1,\ldots, n}$并计算梯度 $\nabla f_i(\mathbf{x})$ 以更新 $\mathbf{x}$$$\mathbf{x} \leftarrow \mathbf{x} - \eta \nabla f_i(\mathbf{x}),$$其中 $\eta$ 是学习率。可以看到每次迭代的计算代价从梯度下降的 $\mathcal{O}(n)$ 降至常数 $\mathcal{O}(1)$。无偏估计随机梯度为什么可信随机梯度之所以平均而言有效是因为它是完整梯度的无偏估计$$\mathbb{E}i \nabla f_i(\mathbf{x}) \frac{1}{n} \sum{i 1}^n \nabla f_i(\mathbf{x}) \nabla f(\mathbf{x}).$$这意味着在期望意义上随机梯度是对真实梯度的良好估计单次更新引入的偏差会被后续多次更新的平均所抵消这是 SGD 一切理论分析见下文凸收敛性分析的基石。二维轨迹实验模拟噪声梯度为了直观对比 SGD 与梯度下降本节沿用梯度下降章节的目标函数在梯度上叠加均值为 0、方差为 1 的正态噪声来模拟随机梯度。目标函数及其梯度定义为def f(x1, x2): # 目标函数 return x1 ** 2 2 * x2 ** 2 def f_grad(x1, x2): # 目标函数的梯度 return 2 * x1, 4 * x2接下来实现带学习率函数lr的 SGD 步进函数。注意返回值中的s1, s2是train_2d要求的内部状态变量在本节用不到恒为 0# mxnet / pytorch / paddle 版本 def sgd(x1, x2, s1, s2, f_grad): g1, g2 f_grad(x1, x2) # 模拟有噪声的梯度 g1 d2l.normal(0.0, 1, (1,)).item() g2 d2l.normal(0.0, 1, (1,)).item() eta_t eta * lr() return (x1 - eta_t * g1, x2 - eta_t * g2, 0, 0) # tensorflow 版本 def sgd(x1, x2, s1, s2, f_grad): g1, g2 f_grad(x1, x2) # 模拟有噪声的梯度 g1 d2l.normal([1], 0.0, 1) g2 d2l.normal([1], 0.0, 1) eta_t eta * lr() return (x1 - eta_t * g1, x2 - eta_t * g2, 0, 0)先用常数学习率跑 50 步def constant_lr(): return 1 eta 0.1 lr constant_lr # 常数学习速度 d2l.show_trace_2d(f, d2l.train_2d(sgd, steps50, f_gradf_grad))观察轨迹可以发现SGD 中变量的轨迹比梯度下降嘈杂得多这是梯度的随机性质造成的即使接近最小值仍会通过 $\eta \nabla f_i(\mathbf{x})$ 注入不确定性。即使经过 50 次迭代质量仍然不高更糟糕的是继续增加步数也不会改善。这给我们留下唯一选择改变学习率 $\eta$。若学习率太小一开始无法取得有意义进展若太大则得不到好解。解决这对矛盾目标的唯一方法是在优化过程中动态降低学习率。这也是在sgd步长函数中引入学习率函数lr的原因——上面的示例中学习率调度功能处于休眠状态因为lr被设为常量。源码佐证train_2d与show_trace_2d上述实验中调用的d2l.train_2d与d2l.show_trace_2d是 d2l-zh 工具包为二维优化可视化提供的基础设施在四个框架模块中各有实现d2l/torch.py、d2l/mxnet.py、d2l/paddle.py、d2l/tensorflow.py。以 d2l/torch.py 为例train_2d(trainer, steps20, f_gradNone)从起点x1, x2, s1, s2 -5, -2, 0, 0出发循环steps次调用传入的trainer步进函数记录每一步的坐标并打印最后一步结果show_trace_2d(f, results)将轨迹以橙色圆点折线绘制在目标函数的等高线图上坐标范围固定为 $x_1\in[-5.5, 1.0]$、$x_2\in[-3.0, 1.0]$。两个函数共同构成了本节及后续优化章节如 chapter_optimization/gd.md、chapter_optimization/minibatch-sgd.md的标准实验画布。噪声梯度由d2l.normal生成在 torch 后端即torch.normal的别名见 d2l/torch.py 中normal torch.normal一行。动态学习率三类基本调度策略用与时间相关的学习率 $\eta(t)$ 取代常数 $\eta$会增加控制优化算法收敛的复杂性需要确定 $\eta$ 的衰减速度。如果太快会过早停止优化如果太慢会在优化上浪费太多时间。以下是调整 $\eta$ 的三类基本策略更高级的策略将在后续章节讨论$$ \begin{aligned} \eta(t) \eta_i \text{ if } t_i \leq t \leq t_{i1} \text{分段常数} \ \eta(t) \eta_0 \cdot e^{-\lambda t} \text{指数衰减} \ \eta(t) \eta_0 \cdot (\beta t 1)^{-\alpha} \text{多项式衰减} \end{aligned} $$分段常数piecewise constant每当优化进度停滞就降低学习率这是训练深度网络的常见策略指数衰减exponential decay衰减更激进但往往导致算法在收敛之前过早停止多项式衰减polynomial decay取 $\alpha 0.5$ 是受欢迎的选择在凸优化情形下有大量证明表明该速率表现良好。指数衰减的实验表现def exponential_lr(): # 在函数外部定义而在内部更新的全局变量 global t t 1 return math.exp(-0.1 * t) t 1 lr exponential_lr d2l.show_trace_2d(f, d2l.train_2d(sgd, steps1000, f_gradf_grad))如预期参数方差大幅减少但代价是未能收敛到最优解 $\mathbf{x} (0, 0)$——即使经过 1000 次迭代仍离最优解很远算法实际上无法收敛。这是因为指数衰减后期学习率趋近于 0更新步长过小参数被困在半路。多项式衰减的实验表现def polynomial_lr(): # 在函数外部定义而在内部更新的全局变量 global t t 1 return (1 0.1 * t) ** (-0.5) t 1 lr polynomial_lr d2l.show_trace_2d(f, d2l.train_2d(sgd, steps50, f_gradf_grad))学习率按迭代次数的平方根倒数衰减即 $\eta(t)\propto t^{-1/2}$对应上文 $\alpha0.5$ 的多项式衰减仅 50 次迭代后收敛就明显优于前两种方案。这直观印证了凸优化理论中的结论平方根倒数的衰减速率恰到好处——既不过快导致停滞也不过慢导致方差过大。更多可能性与理论边界关于学习率还有其他选择例如从较小的学习率开始然后快速上升再缓慢降低甚至在较小和较大学习率之间交替。但本文聚焦于可以进行全面理论分析的学习率计划即凸环境下的学习率。对一般的非凸问题很难获得有意义的收敛保证因为总体而言最小化非线性非凸问题是 NP 困难的。凸目标的收敛性分析以下对凸目标函数的 SGD 收敛性分析是可选的主要用于传达对问题的更多直觉只涉及最简单的证明之一Nesterov Vial, 2000。假设对任意 $\boldsymbol{\xi}$目标函数 $f(\boldsymbol{\xi}, \mathbf{x})$ 关于 $\mathbf{x}$ 都是凸的考虑 SGD 更新$$\mathbf{x}{t1} \mathbf{x}{t} - \eta_t \partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x}),$$其中 $f(\boldsymbol{\xi}_t, \mathbf{x})$ 是第 $t$ 步从某个分布中抽取的训练样本 $\boldsymbol{\xi}_t$ 对应的目标函数$\mathbf{x}$ 是模型参数。定义期望风险$$R(\mathbf{x}) E_{\boldsymbol{\xi}}[f(\boldsymbol{\xi}, \mathbf{x})],$$其关于 $\mathbf{x}$ 的最小值记为 $R^$并设 $\mathbf{x}^$ 为最小化子假设它存在于 $\mathbf{x}$ 的定义域内。我们希望跟踪当前参数 $\mathbf{x}_t$ 与风险最小化子 $\mathbf{x}^*$ 之间的距离是否随时间改善$$\begin{aligned} |\mathbf{x}{t1} - \mathbf{x}^*|^2 \ |\mathbf{x}{t} - \eta_t \partial_\mathbf{x} f(\boldsymbol{\xi}t, \mathbf{x}) - \mathbf{x}^*|^2 \ |\mathbf{x}{t} - \mathbf{x}^|^2 \eta_t^2 |\partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})|^2 - 2 \eta_t \left\langle \mathbf{x}_t - \mathbf{x}^, \partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})\right\rangle. \end{aligned}$$三个关键假设与不等式分析依赖三个工具性假设/不等式梯度范数有界假设随机梯度 $\partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})$ 的 $L_2$ 范数被常数 $L$ 界定故有$$\eta_t^2 |\partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})|^2 \leq \eta_t^2 L^2.$$凸性的一阶条件对任何凸函数 $f$所有 $\mathbf{x}$ 和 $\mathbf{y}$ 均满足 $f(\mathbf{y}) \geq f(\mathbf{x}) \langle f(\mathbf{x}), \mathbf{y} - \mathbf{x} \rangle$于是$$f(\boldsymbol{\xi}_t, \mathbf{x}^) \geq f(\boldsymbol{\xi}_t, \mathbf{x}_t) \left\langle \mathbf{x}^- \mathbf{x}t, \partial{\mathbf{x}} f(\boldsymbol{\xi}_t, \mathbf{x}_t) \right\rangle.$$期望层面的距离追踪单次更新序列的距离可能因碰到的 $\boldsymbol{\xi}_t$ 而增加因此只能对期望进行分析。推导从单步进度到全局上界将两个不等式代入距离展开式得到时间 $t1$ 时参数距离的界$$|\mathbf{x}{t} - \mathbf{x}^*|^2 - |\mathbf{x}{t1} - \mathbf{x}^|^2 \geq 2 \eta_t (f(\boldsymbol{\xi}_t, \mathbf{x}_t) - f(\boldsymbol{\xi}_t, \mathbf{x}^)) - \eta_t^2 L^2.$$这意味着只要当前损失与最优损失之差超过 $\eta_t L^2/2$算法就能取得进展。由于该差值必然收敛到零学习率 $\eta_t$ 也必须消失趋于 0。对上式取期望$$E\left[|\mathbf{x}_{t} - \mathbf{x}^*|^2\right] - E\left[|\mathbf{x}_{t1} - \mathbf{x}^*|^2\right] \geq 2 \eta_t [E[R(\mathbf{x}_t)] - R^*] - \eta_t^2 L^2.$$对 $t \in {1, \ldots, T}$ 求和中间项相互抵消望远镜求和舍去低阶项$$|\mathbf{x}1 - \mathbf{x}^*|^2 \geq 2 \left (\sum{t1}^T \eta_t \right) [E[R(\mathbf{x}_t)] - R^*] - L^2 \sum_{t1}^T \eta_t^2.$$由于 $\mathbf{x}_1$ 是给定的初始值此处期望可以去掉。接着定义优化路径的加权平均平滑版本$$\bar{\mathbf{x}} \stackrel{\mathrm{def}}{} \frac{\sum_{t1}^T \eta_t \mathbf{x}t}{\sum{t1}^T \eta_t}.$$利用詹森不等式令 $\alpha_i \eta_t/\sum_{t1}^T \eta_t$与 $R$ 的凸性有 $E[R(\mathbf{x}_t)] \geq E[R(\bar{\mathbf{x}})]$从而$$\sum_{t1}^T \eta_t E[R(\mathbf{x}_t)] \geq \sum_{t1}^T \eta_t E\left[R(\bar{\mathbf{x}})\right].$$代入上述不等式最终得到核心界$$\left[E[\bar{\mathbf{x}}]\right] - R^* \leq \frac{r^2 L^2 \sum_{t1}^T \eta_t^2}{2 \sum_{t1}^T \eta_t},$$其中 $r^2 \stackrel{\mathrm{def}}{} |\mathbf{x}_1 - \mathbf{x}^*|^2$ 是初始参数与最优参数之间距离的界。收敛速率的结论该界揭示收敛速度取决于两个量——随机梯度范数的上界 $L$以及初始参数值离最优结果的距离 $r$。注意界是对 $\bar{\mathbf{x}}$优化路径的平滑版而非 $\mathbf{x}_T$ 给出的。当 $r, L, T$ 已知时可选择学习率$$\eta \frac{r}{L \sqrt{T}},$$得到的上界为 $rL/\sqrt{T}$即 SGD以 $\mathcal{O}(1/\sqrt{T})$ 的速率收敛到最优解。这正是学习率应随迭代次数按平方根倒数衰减这一实践直觉的理论来源——与上一节多项式衰减实验的观察完全吻合。随机梯度与有限样本有放回与无放回采样本节讨论一个此前论述中快而松散的细节。理想化地说SGD 假设从分布 $p(x, y)$ 中采样样本 $x_i$通常带标签 $y_i$并以此更新参数对有限样本可将其视为由离散分布$$p(x, y) \frac{1}{n} \sum_{i1}^n \delta_{x_i}(x) \delta_{y_i}(y)$$定义的采样过程其中 $\delta$ 为指示函数。但本节玩具实验中实际做的是向非随机梯度添加噪声即假装有成对的 $(x_i, y_i)$——这在此处是合理的详见练习 2 的讨论。更值得警惕的是此前的所有讨论中我们并非按理想分布采样而是恰好遍历所有实例一次每个 epoch 内每个样本被用且仅用一次。为什么这样更好考虑反面情形——有放回地从离散分布中采样 $n$ 个观测值。随机选择元素 $i$ 的概率是 $1/n$因此它至少被选中一次的概率为$$P(\mathrm{choose~} i) 1 - P(\mathrm{omit~} i) 1 - (1-1/n)^n \approx 1-e^{-1} \approx 0.63.$$类似推理可知某个样本训练示例被选中恰好一次的概率为$${n \choose 1} \frac{1}{n} \left(1-\frac{1}{n}\right)^{n-1} \frac{n}{n-1} \left(1-\frac{1}{n}\right)^{n} \approx e^{-1} \approx 0.37.$$这意味着有放回采样下约有 37% 的样本被重复使用、约 37% 的样本被遗漏导致方差增加、数据效率降低。因此实践中采用无放回采样——这也是本书各章训练的默认选择。最后需要注意重复遍历训练数据集时每个 epoch 都会以不同的随机顺序遍历它从而保证各 epoch 之间梯度估计的多样性。这一随机打乱 完整遍历的机制正是后续 chapter_optimization/minibatch-sgd.md 中小批量 SGD 的基础。小结对于凸问题可以证明在广泛的学习率选择下随机梯度下降将收敛到最优解对深度学习非凸而言情况通常并非如此但对凸问题的分析能提供重要洞见——应逐步降低学习率尽管不能太快学习率太小或太大都会出问题实践中通常需要多次实验才能找到合适的学习率当训练数据集中样本更多时梯度下降每次迭代的计算代价更高因此这些情况下优先选择随机梯度下降非凸情形下 SGD 的最优性保证一般不可用因为需要检查的局部最小值数量可能是指数级的。练习尝试不同的随机梯度下降学习率计划和不同的迭代次数进行实验特别是根据迭代次数绘制与最优解 $(0, 0)$ 的距离证明对函数 $f(x_1, x_2) x_1^2 2 x_2^2$向梯度添加正态噪声等同于最小化损失函数 $f(\mathbf{x}, \mathbf{w}) (x_1 - w_1)^2 2 (x_2 - w_2)^2$其中 $\mathbf{x}$ 从正态分布中提取分别用有放回与无放回方式从 ${(x_1, y_1), \ldots, (x_n, y_n)}$ 采样比较 SGD 的收敛性如果某些梯度或其关联的某些坐标始终比其他梯度大你会如何修改 SGD 求解器假设 $f(x) x^2 (1 \sin x)$$f$ 有多少个局部最小值能否改造 $f$使其最小化需要评估所有局部最小值延伸阅读本文是优化章节三件套的第一环与其姊妹篇 梯度下降 chapter_optimization/gd.md全量梯度和 小批量随机梯度下降 chapter_optimization/minibatch-sgd.md两者折中共同构成完整的梯度优化谱系相关实验基础设施train_2d、show_trace_2d、sgd步进函数可分别查阅 d2l/torch.py、d2l/mxnet.py、d2l/paddle.py 与 d2l/tensorflow.py。赞分享人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载相关推荐《动手学深度学习》随机梯度下降SGD精讲无偏梯度、学习率调度与收敛性分析《动手学深度学习》随机梯度下降SGD精讲无偏梯度、学习率调度与收敛性分析 随机梯度下降Stochastic Gradient DescentSGD是人工智能深度学习机器学习教程《动手学深度学习》d2l-zh微积分入门导数、梯度与链式法则《动手学深度学习》d2l zh微积分入门导数、梯度与链式法则 本节是《动手学深度学习》d2l zh预备知识章节之一对应仓库文件 chapter_pr人工智能深度学习机器学习教程《动手学深度学习》优化算法全景解析从梯度下降到 Adam 与学习率调度《动手学深度学习》优化算法全景解析从梯度下降到 Adam 与学习率调度 《动手学深度学习》d2l zh在优化算法一章 章节索引 https://li人工智能深度学习机器学习教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考