ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

《动手学深度学习》随机梯度下降(SGD)精讲:无偏梯度、学习率调度与收敛性分析

《动手学深度学习》随机梯度下降(SGD)精讲:无偏梯度、学习率调度与收敛性分析 人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载随机梯度下降Stochastic Gradient DescentSGD是《动手学深度学习》d2l-zh全书中训练模型时反复使用的默认优化器也是理解 Adam、小批量随机梯度下降等更高级算法的基础。本文以 chapter_optimization/sgd.md 为核心结合仓库内d2l工具库的源码实现系统讲解 SGD 为何能大幅降低单次迭代的计算代价、为何随机梯度是完整梯度的无偏估计、动态学习率的三种经典调度策略以及凸目标下 SGD 收敛率的严格推导。读完本文你将能够独立复现 SGD 的二维轨迹实验并理解学习率必须随时间衰减这一深度学习实践背后的数学动因。从梯度下降到随机梯度下降在前面的章节梯度下降中我们学习了梯度下降的基本原理目标函数沿负梯度方向迭代即可逐步逼近极小值。然而深度学习的实际目标函数通常是训练数据集中每个样本损失的平均值。给定 $n$ 个样本的训练数据集设 $f_i(\mathbf{x})$ 是关于索引 $i$ 的训练样本的损失函数$\mathbf{x}$ 为参数向量则目标函数为$$f(\mathbf{x}) \frac{1}{n} \sum_{i 1}^n f_i(\mathbf{x}).$$其梯度为$$\nabla f(\mathbf{x}) \frac{1}{n} \sum_{i 1}^n \nabla f_i(\mathbf{x}).$$如果使用梯度下降法每个自变量迭代的计算代价为 $\mathcal{O}(n)$随样本量 $n$线性增长。当训练数据集较大时每次迭代的梯度下降计算代价将相当高。这正是 SGD 登场的直接动机。随机梯度更新从 $\mathcal{O}(n)$ 到 $\mathcal{O}(1)$SGD 的核心思想是在每次迭代中随机均匀采样一个索引$i\in{1,\ldots, n}$只计算该样本的梯度 $\nabla f_i(\mathbf{x})$ 来更新参数$$\mathbf{x} \leftarrow \mathbf{x} - \eta \nabla f_i(\mathbf{x}),$$其中 $\eta$ 是学习率。这样一来每次迭代的计算代价从梯度下降的 $\mathcal{O}(n)$ 骤降至常数 $\mathcal{O}(1)$。为什么可以这样偷工减料关键在于随机梯度 $\nabla f_i(\mathbf{x})$ 是完整梯度 $\nabla f(\mathbf{x})$ 的无偏估计$$\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 实现在 d2l-zh 仓库中d2l/torch.py 给出了带批量归一化因子的 SGD 实际实现用于线性回归手写实现章节def sgd(params, lr, batch_size): 小批量随机梯度下降 Defined in :numref:sec_linear_scratch with torch.no_grad(): for param in params: param - lr * param.grad / batch_size param.grad.zero_()值得注意的是仓库中的sgd()已经按batch_size对梯度做了平均这正是小批量随机梯度下降的标准形态参见 小批量随机梯度下降。而本节的sgd实验函数在 d2l/mxnet.py、d2l/tensorflow.py、d2l/paddle.py 中也有对应的等价实现四个框架MXNet、PyTorch、TensorFlow、PaddlePaddle的接口设计保持一致便于读者跨框架对照学习。用噪声模拟随机梯度二维轨迹实验为了直观比较梯度下降与 SGD 的行为差异本节向干净的梯度中添加均值为 0、方差为 1 的随机噪声来模拟随机梯度。目标函数选择经典的椭球函数def f(x1, x2): # 目标函数 return x1 ** 2 2 * x2 ** 2 def f_grad(x1, x2): # 目标函数的梯度 return 2 * x1, 4 * x2SGD 步长函数PyTorch/MXNet/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 版本的噪声采样写法略有不同使用d2l.normal([1], 0.0, 1)核心逻辑一致。函数签名中的s1, s2是预留给后续优化算法如动量法、AdaGrad的内部状态变量在本节中始终返回 0lr则是一个可插拔的学习率函数这正是后面动态学习率实验的挂钩点。使用常数学习率运行 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 次迭代解的质量依然不佳且继续增加步数也不会改善。轨迹绘制的底层机制train_2d 与 show_trace_2d上述实验由d2l工具库的两个函数驱动它们的实现位于 d2l/torch.py四个框架版本位置对应相同def train_2d(trainer, steps20, f_gradNone): 用定制的训练机优化2D目标函数 # s1和s2是稍后将使用的内部状态变量 x1, x2, s1, s2 -5, -2, 0, 0 results [(x1, x2)] for i in range(steps): if f_grad: x1, x2, s1, s2 trainer(x1, x2, s1, s2, f_grad) else: x1, x2, s1, s2 trainer(x1, x2, s1, s2) results.append((x1, x2)) print(fepoch {i 1}, x1: {float(x1):f}, x2: {float(x2):f}) return results def show_trace_2d(f, results): 显示优化过程中2D变量的轨迹 d2l.set_figsize() d2l.plt.plot(*zip(*results), -o, color#ff7f0e) x1, x2 d2l.meshgrid(d2l.arange(-5.5, 1.0, 0.1), d2l.arange(-3.0, 1.0, 0.1), indexingij) d2l.plt.contour(x1, x2, f(x1, x2), colors#1f77b4) d2l.plt.xlabel(x1) d2l.plt.ylabel(x2)从源码可以确认train_2d从 $(-5, -2)$ 出发将每一步的 $(x_1, x_2)$ 记录到results列表中show_trace_2d则在目标函数的等高线contour上叠加橙色折线轨迹从而直观呈现优化路径。这两个函数在全书多个优化章节梯度下降、SGD、动量法、AdaGrad 等中被复用是理解所有基于 2D 目标函数优化实验的统一入口。学习率困境太小没进展太大不收敛噪声实验揭示了 SGD 与梯度下降的本质差异即使接近最小值参数仍被瞬时梯度的随机性扰动。而仅靠固定学习率 $\eta$ 无法调和一对矛盾——学习率太小初始阶段几乎没有任何有意义的进展学习率太大无法获得好的解如上文所示轨迹剧烈震荡。解决这两个相互冲突目标的唯一方法是在优化过程中动态降低学习率。这也是sgd步长函数中引入学习率函数lr的原因在上面常数学习率的例子中学习率调度的功能处于休眠状态因为我们把lr设成了常量。动态学习率三种经典调度策略用与时间相关的学习率 $\eta(t)$ 取代固定 $\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))实现要点t是定义在函数外部、在函数内部通过global关键字更新的全局变量每次调用lr()都会使 $t$ 自增 1返回 $e^{-0.1t}$。运行结果与预期一致参数的方差大大减少但代价是未能收敛到最优解 $\mathbf{x} (0, 0)$——即使经过 1000 个迭代步骤仍然离最优解很远算法根本无法收敛。这是因为学习率衰减过快导致后期步长趋近于零。多项式衰减实验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))多项式衰减中学习率随迭代次数的平方根倒数衰减$\alpha 0.5$。与指数衰减对比鲜明仅仅 50 次迭代之后收敛就明显更好——既保留了足够的下降动力又在接近最优解时自动缩小步长以抑制噪声。更多调度选择与理论边界除了上述三种策略还存在更多选择例如从较小的学习率开始、迅速升高后再缓慢降低warmup 思想的雏形甚至可以在较小和较大学习率之间交替切换。本书在此将注意力集中在可以进行全面理论分析的调度上——即凸环境下的学习率。对于一般非凸问题很难获得有意义的收敛保证因为总体而言最小化非线性非凸问题是 NP 困难的该判断源自原始文档对 Tibshirani 2015 讲义笔记的引用。凸目标下的收敛性分析以下对凸目标函数 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$ 步从某分布中抽取的训练样本对应的目标函数。记期望风险为$$R(\mathbf{x}) E_{\boldsymbol{\xi}}[f(\boldsymbol{\xi}, \mathbf{x})],$$$R^$ 为关于 $\mathbf{x}$ 的最低风险$\mathbf{x}^$ 为风险最小化器假设存在于 $\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}$$假设随机梯度的 $L_2$ 范数受常数 $L$ 限制$$\eta_t^2 |\partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})|^2 \leq \eta_t^2 L^2.$$由于对任意凸函数 $f$ 都有 $f(\mathbf{y}) \geq f(\mathbf{x}) \langle f(\mathbf{x}), \mathbf{y} - \mathbf{x} \rangle$对所有 $\mathbf{x}, \mathbf{y}$由凸性可得$$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.$$将上述两式代入距离展开式得到 $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$ 也必须消失趋向零。对不等式取期望$$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.$$定义优化路径的平滑版本加权平均参数$$\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}})]$代入后得到最终边界$$ \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$ 表示因为 $\bar{\mathbf{x}}$ 是优化路径的平滑版本。只要已知 $r, L$ 和 $T$就可以选择学习率 $\eta r/(L \sqrt{T})$此时上界为 $rL/\sqrt{T}$即以 $\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)$。但需要澄清两点事实本节实验并非真正采样玩具示例只是向非随机梯度添加噪声假装有成对的 $(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% 的样本出现一次、约 26% 的样本一次都没被选中$e^{-1} \approx 0.37$剩余部分被多次选中这导致方差增加、数据效率降低。因此实践中采用无放回采样这也是本书各章节的默认选择重复遍历训练数据集时会以不同的随机顺序遍历它。小结对于凸问题可以证明在广泛的学习率选择下随机梯度下降都将收敛到最优解对深度学习而言情况通常并非如此但凸问题的分析提供了有价值的优化洞见逐步降低学习率但不要降得太快学习率过小或过大都会引发问题实践中往往需要多次实验才能找到合适的学习率当训练数据集中样本更多时梯度下降每次迭代的计算代价更高因此这些场景下首选随机梯度下降非凸情形下 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)}$ 分别使用有放回与无放回方法采样时比较随机梯度下降的收敛性。如果某些梯度或其关联的某些坐标始终比所有其他梯度都大应如何修改随机梯度下降求解器假设 $f(x) x^2 (1 \sin x)$。$f$ 有多少个局部最小值请尝试修改 $f$使最小化它时必须评估所有局部最小值。延伸阅读路径本文的完整代码与公式均来自 chapter_optimization/sgd.md可结合以下仓库资源深入研读SGD 的前置知识见 梯度下降SGD 与批量训练的折中方案见 小批量随机梯度下降动量和自适应学习率算法见 动量法、AdaGrad 等章节d2l工具库的完整实现位于 d2l/torch.py、d2l/mxnet.py、d2l/tensorflow.py、d2l/paddle.py可按对应框架查阅train_2d、show_trace_2d与sgd等函数。赞分享人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载相关推荐《动手学深度学习》优化算法全景解析从梯度下降到 Adam 与学习率调度《动手学深度学习》优化算法全景解析从梯度下降到 Adam 与学习率调度 《动手学深度学习》d2l zh在优化算法一章 章节索引 https://li人工智能深度学习机器学习教程numpy-ml在线学习随机梯度下降与自适应学习率numpy ml在线学习随机梯度下降与自适应学习率 在机器学习模型训练过程中学习率Learning Rate, LR是决定模型收敛速度和最终性能的关键超机器学习人工智能终极指南30分钟构建你的个人AI大脑让智能助手真正记住一切终极指南30分钟构建你的个人AI大脑让智能助手真正记住一切 你是否厌倦了每次都要重新向AI助手解释相同的事情gbrain正是你需要的解决方案——这是一个开人工智能RAGAgent 记忆MCP 服务知识管理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表