type
Post
status
Published
date
Mar 6, 2026
slug
summary
tags
DL
开发
思考
精选
category
知行合一
icon
password
这里写文章的前言:
一个简单的开头,简述这篇文章讨论的问题、目标、人物、背景是什么?并简述你给出的答案。
可以说说你的故事:阻碍、努力、结果成果,意外与转折。
目录
- GD 梯度下降 (Gradient Descent)
- BGD:每批次用全部数据计算一次梯度更新参数,最基础的GD。
- SGD:每次随机选用一个样本计算梯度,减少计算量。
- MBGD:小批次梯度下降,是BGD和SGD的折中。
- 动量优化(决定了梯度更新的方式)
- Momentum:加速收敛,减少震荡。
- NAG:提前看
- 自适应
- AdaGrad:无需手动学习率。
- RMSProp:避免AdaGrad学习率下降过快。
- Adadelta:RMSProp变种
- 流行
- Adam:Momentum + RMSProp加速收敛,减少震荡。
- AdamW:优化版Adam,泛化更好。
- 稀疏优化器
- FTRL:L1 + L2 + AdaGrad
- AdaGrad:设计稀疏特征学习率更大
梯度计算
梯度是 loss 对模型参数的偏导数,通过反向传播计算,表示 loss 增长最快的方向。
当然,我们的目的是让loss更小,所以我们沿梯度反方向更新参数。
对于应用工程师,我们在这里不深究梯度计算的原理,网上有很多优质的定义,大家可以自行参阅。
核心是利用:反向传播(Backpropagation) + 链式法则
梯度更新
这才是不同优化器的作用所在。
最基本的梯度更新:Gradient Descent
假设我们已经计算出了梯度:
最简单的更新方式:
其中:
- = 参数
- = 梯度
- = 学习率
很好理解,梯度 = 上坡最快方向,更新 = 往反方向走
所以:
为什么简单梯度更新不好?
SGD 有三个问题:
1 震荡问题
如果 loss surface 是平底峡谷,来回震荡。
2 收敛慢
在平缓区域:梯度很小,更新非常慢。
3 学习率难调
太大 → 发散

太小 → 收敛慢

第一类改进:Momentum动量(梯度优化)
核心思想:
不要只看当前梯度,要结合历史梯度

更新方式:
解释:
- = 当前速度(动量), = 上次迭代速度(动量)
- = 当前梯度
- = 动念衰减系数,比如指定 90%历史方向 + 10%当前梯度
- = 第 次迭代时的模型参数
- = 学习率
替代了原有的 优化的是「梯度方向」
方向 = 当前梯度 + 历史惯性
效果:当在峡谷时:减速。当在正确方向时:加速。
第二类改进:AdaGrad(学习率自适应)
SGD中,所有参数学习率一样但现实中有些参数更新频繁,有些参数很少更新
AdaGrad记录历史梯度平方:
累积梯度平方:
参数更新:
解释:
- = 历史梯度平方累积
- = 当前梯度gt=∇L(θt)
- = 第 次迭代时的模型参数
- = 初始学习率
- = 防止除零的小常数(例如 )
- = 当前迭代步数
替代了 优化的是「学习率」
频繁更新的参数,历史梯度累计更大(分母更大),降低其学习率。低频参数则加速。
第三类改进:RMSProp(学习率自适应优化)
AdaGrad存在梯度一直累加问题,会导致学习率越来越小。
RMSProp通过「只记录最近梯度」进行改进:
梯度平方的指数移动平均:
参数更新:
解释:
- = 梯度平方的指数移动平均
- = 当前梯度gt=∇L(θt)
- = 衰减系数(通常 0.9)
- = 当前模型参数
- = 学习率
- = 防止除零的小常数
- = 当前迭代步数
替代了 优化的是「学习率」
速度为最近梯度平方的平均值,通过滑动窗口实现
第三类改进:Adam(同时优化梯度和学习率)
Adam是目前最流行的优化器,结合了 Momentum + RMSProp 的核心思想。
维护两个量:
一阶矩(动量),即Momentum,负责优化梯度
二阶矩(梯度平方),即RMSProp,负责优化学习率
更新:
解释:
- = 第 $t$ 次迭代时模型参数
- = 当前梯度
- = 梯度一阶矩估计(梯度的指数移动平均)
- = 梯度二阶矩估计(梯度平方的指数移动平均)
- = 纠偏一阶矩 注意看右下角有一个t方、因为刚开始没有历史,而β又偏大。
- = 纠偏二阶矩 所以需要放大一下,否则太小。
- = 一阶矩衰减系数(通常 0.9)
- = 二阶矩衰减系数(通常 0.999)
- = 学习率
- = 防止除零的小常数(例如 $10^{-8}$)
- = 当前迭代步数
就是结合了上面两个。注意纠偏
- 用 代替
- 用 替代
进一步改进
NAG加速梯度(Nesterov Accelerated Gradient)
核心思想:
先沿动量方向预测未来位置,再在那个位置计算梯度。
Momentum 动量可能带着参数往错误方向冲太远,NAG 通过提前看一步的方式改进
下一步预计位置(通过动量算):
计算梯度:
更新动量:
更新参数:
解释:
- = 当前动量
- = 上一步动量
- = 在预测位置计算的梯度
- = 动量衰减系数
- = 学习率
- = 预测参数位置
Momentum:
- 用「历史动量 + 当前梯度」更新当前动量。
- 再用当前动量更新参数,到下一个位置。
NAG:
- 先用「历史动量」计算「预测位置的梯度」
- 然后根据「历史动量 + 预测位置的梯度」计算当前动量
(如果下一步梯度方向发生变化,此时可以抵消或者修正)
- 再用当前动量更新参数,到下一个位置。
用预计 和 共同确定
AdamW 正则化防止过拟合
Adam 原始更新:
AdamW 梯度更新:
为什么要多一项 呢?问题出在这里:
给定模型当前参数损失函数:
其中
- :数据损失
- :L2 正则化
梯度变成
更新:
可以看到右上角多了一项,λθ 也被除以 √v
也就是说正则化强度会被 自适应缩放。此时不同参数的 weight decay 强度不同,这就破坏了 L2 的本意。
所以AdamW很简单,就是不要把 L2 写进 Loss 的梯度里,避免被学习率适应影响。
而是在后面更新 的时候再减掉
AdamW 梯度更新也可以写成:
其实就是一组权重
其中 是一个小于1的数,乘以这个数可以实现decay,避免权重太大。
解释
- = 当前参数
- = 纠偏一阶矩(Momentum)
- = 纠偏二阶矩(RMSProp)
- = 学习率
- = weight decay 系数
- = 防止除零
其他改进
FTRL(Follow-The-Regularized-Leader)
人如其名:跟随过去表现最好的参数
核心思想:
选择一个参数,使得过去所有损失 + 正则化 最小。
- 结合 L1 正则 + L2 正则 + AdaGrad 的思想,专门为大规模稀疏特征设计。
- 我们不只看当前梯度,而是看 所有历史梯度的累积。
典型应用:
Google 广告系统大量使用 FTRL。
更新公式
累计梯度:
参数更新:
实际实现形式:
如果
则
否则
解释
- = 当前梯度
- = 历史累计梯度
- = 第 i 个参数梯度平方累积
- = 累计梯度变量
- = 学习率
- = 平滑参数
- = L1 正则
- = L2 正则
推导
首先我们知道AdaGrad
把符号改一下,防止除0的我们先不关心
其中
其实可以看出原本的 变成了 即「有效学习率」
转化为优化问题:
解释:
- = 损失函数的一阶近似
- 是不让参数跳太远
求导:
得到:
就是 SGD。
FTRL 的核心优势:
因此非常适合:
最后总结
优化器的演进其实是解决不同问题:
优化器 | 解决问题 |
Momentum | 震荡 |
NAG | 「动量」方向误差 |
AdaGrad | 参数「学习率」不同 |
RMSProp | AdaGrad 「学习率」衰减 |
Adadelta | 自动「学习率」 |
Adam | Momentum + RMSProp |
AdamW | Adam 正则问题 |
FTRL | 稀疏特征 + 在线学习 |
所有优化器其实都是:
区别只是:
优化器 | update |
SGD | g |
Momentum | v |
AdaGrad | g / √G |
RMSProp | g / √v |
Adam | m / √v |
扫盲:现代深度学习训练代码用的基本都是MBGD
这是一段很经典的深度学习训练代码:
我们训练时候的Batch(大小由batch_size指定)与BGD(Batch Gradient Descent)名字里面的Batch不一样,而BGD名字里的Batch指的是整个数据集“批量“处理。而常见代码中的Batch就是Mini Batch。
为什么要用MBGD而不是BGD?
Batch Gradient Descent 每次用全部训练数据计算一次梯度,然后更新参数。
- 成本太高:如果有1个亿的样本,需要完整扫描计算,且一个epoch只更新一次,收敛慢。
- 必须等待:必须等所有数据到了,才能进行一次迭代。
- 硬件压力:每次显存需要载入全量数据、成本极高。
为什么要用MBGD而不是SGD?
- 梯度变化大:每个样本千奇百怪、梯度方差大、震荡、难以收敛。
- 计算效率低:GPU可以进行并行计算、而SGD浪费了这个能力。
- 梯度噪声大:单样本无法代表整体样本。
什么是稀疏模型?
稀疏模型到底是什么意思?模型还有稀疏的吗,不应该是数据稀疏吗?
这是一个非常好的问题。很多人第一次听到“稀疏模型”都会困惑,因为更常见的是“稀疏数据”。其实 稀疏模型和稀疏数据是两个不同概念。
稀疏数据
稀疏数据指的是:输入「特征」大部分是 0
例如One-Hot编码
维度可能达到 10^6 甚至 10^9,但每个样本只有几十个非零
所以叫:sparse data(稀疏数据)
稀疏模型
稀疏模型指的是:模型「参数」大部分是 0
例如一个线性模型:
如果训练结果是:
只有少数权重非零。
这就叫:sparse model(稀疏模型)
为什么我们希望模型稀疏?原因有三个:
- 自动特征选择:如果w_i = 0,这个特征可以直接丢掉了
- 计算更快:只有非0位置要计算
- 防止过拟合:模型容易记住噪声
如何让模型稀疏?最经典的是:
- L1 正则:
- FTRL: 因为更新时有一个条件: 很多 feature 权重直接变 0。
扩展思考
为什么 L1 正则会产生稀疏模型,而 L2 不会?
核心原因:L1 惩罚对小权重有“固定拉力”,而 L2 的拉力会越来越小。
L1 正则:( )
梯度:(大小基本是常数)
所以权重更新像:
不管 w 的数值大小,都有固定力度往 0 拉,一旦跨过 0 就会直接变成 0 → 产生稀疏。
L2 正则:( )
梯度:
更新:
当 w 数值很小时,梯度也很小,所以只是无限接近 0,但几乎不会变成 0。
根本原因:因为 L1 的梯度(导数)是常数,不随 w 变小而变小。
- Author:YelloooBlue
- URL:https://tangly1024.com/article/31be32f0-1b7f-8049-8ea2-c13d20b9934d
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!










