深度学习优化函数详解(4)-- momentum 动量法

本文通过生动的比喻和直观的图表介绍了动量法在深度学习优化中的应用原理。动量法模仿小球沿斜坡加速下滚的过程,利用历史梯度的方向和大小,通过累积动量来加速神经网络的训练收敛速度。

深度学习优化函数详解系列目录

本系列课程代码,欢迎star:
https://github.com/tsycnh/mlbasic

深度学习优化函数详解(0)-- 线性回归问题
深度学习优化函数详解(1)-- Gradient Descent 梯度下降法
深度学习优化函数详解(2)-- SGD 随机梯度下降
深度学习优化函数详解(3)-- mini-batch SGD 小批量随机梯度下降
深度学习优化函数详解(4)-- momentum 动量法
深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG)
深度学习优化函数详解(6)-- adagrad

本文延续该系列的上一篇 深度学习优化函数详解(3)-- mini-batch SGD 小批量随机梯度下降

如果把梯度下降法想象成一个小球从山坡到山谷的过程,那么前面几篇文章的小球是这样移动的:从A点开始,计算当前A点的坡度,沿着坡度最大的方向走一段路,停下到B。在B点再看一看周围坡度最大的地方,沿着这个坡度方向走一段路,再停下。确切的来说,这并不像一个球,更像是一个正在下山的盲人,每走一步都要停下来,用拐杖来来探探四周的路,再走一步停下来,周而复始,直到走到山谷。而一个真正的小球要比这聪明多了,从A点滚动到B点的时候,小球带有一定的初速度,在当前初速度下继续加速下降,小球会越滚越快,更快的奔向谷底。momentum 动量法就是模拟这一过程来加速神经网络的优化的。

后文的公式推导不加特别说明都是基于 mini-batch SGD 的,请注意。

公式推导

更多实验数据背景及模型定义请参看该系列的前几篇文章。

这里写图片描述

上图直观的解释了动量法的全部内容。
A为起始点,首先计算A点的梯度 ∇ a \nabla a a ,然后下降到B点,
θ n e w = θ − α ∇ a \theta_{new} = \theta - \alpha\nabla a θnew=θαa
θ \theta θ 为参数 α \alpha α 为学习率。
到了B点需要加上A点的梯度,这里梯度需要有一个衰减值 γ \gamma γ ,推荐取0.9。这样的做法可以让早期的梯度对当前梯度的影响越来越小,如果没有衰减值,模型往往会震荡难以收敛,甚至发散。所以B点的参数更新公式是这样的:
v t = γ v t − 1 + α ∇ b v_t = \gamma v_{t-1} + \alpha \nabla b vt=γvt1+αb
θ n e w = θ − v t \theta_{new} = \theta - v_t θnew=θvt
其中 v t − 1 v_{t-1} vt1 表示之前所有步骤所累积的动量和。
这样一步一步下去,带着初速度的小球就会极速的奔向谷底。

实验

由于样本数量较少,动量的实验未使用SGD,每一次更新loss使用全部数据
这里写图片描述
学习率 α = 0.01 \alpha = 0.01 α=0.01,衰减率 γ = 0.9 \gamma = 0.9 γ=0.9
对比Gradient Descent
这里写图片描述

仔细看右上角的等高线图就可以看见,momentum方法每一步走的都要更远一些。由于累加了动量,会带着之前的速度向前方冲去。比如一开始loss冲入了山谷,由于有之前的动量,继续朝着对面的山坡冲了上去。随着动量的更新,慢慢地最终收敛到了最小值。

注:对比图可能看起来GD算法要好于momentum方法,这仅仅是由于数据集比较简单。本文旨在从理论和实际实验中去学习momentum方法,不对结果对比做太多讨论。实验的结果往往和数据集、参数选择有很大关系。

本文实验代码:https://github.com/tsycnh/mlbasic/blob/master/p4 momentum.py

<think>嗯,用户现在想了解深度学习中的损失函数优化器的详细解释和使用方法。之前已经给过他们一个比较全面的回答,里面包含了各种损失函数优化器的对比,以及它们在RNN中的应用示例。现在用户再次提问,可能希望得到更深入的信息,或者更结构化的指导。需要先回顾之前的回答,确保这次的内容不重复,同时补充更多细节。 首先,用户提到的引用资料里,引用[1]强调了损失函数优化器的相互依赖,这一点在之前的回答中也提到过,需要再次强调两者的协同作用。引用[2]解释了损失函数如何衡量预测值和真实值的差距,这里可能需要进一步分类讨论不同类型的损失函数适用场景。引用[3]详细讨论了各种优化器的优缺点,特别是SGD和自适应方法的对比,这部分可以结合之前的建议,给出更具体的选择指南。 用户的需求是详细解释和使用指南,所以应该分模块来组织内容。可能的结构是:损失函数部分按任务类型分类,每种类型给出公式、使用场景、注意事项;优化器部分对比不同算法,适用情况,调参技巧。同时结合用户之前提到的RNN应用,可能需要添加一些实际案例或者代码示例,但用户这次的问题似乎更偏向理论,所以代码可以放在后面作为补充。 另外,用户可能希望了解如何根据具体问题选择损失函数优化器,所以需要给出一些决策流程或选择树。例如,对于分类问题,交叉熵是首选;对于回归问题,MSE或MAE。优化器方面,如果是稀疏数据或需要快速收敛,Adam可能更好,但要注意泛化问题;如果追求稳定性和最终性能,SGD配合学习率调度更合适。 还要注意引用之前的文献,比如在解释SGD和Adam对比时,引用用户提供的资料中的观点,如引用[3]提到的SGD训练时间长但结果可靠,而自适应方法适合复杂网络。同时需要结合之前回答中的引用标识,如[^1]、[^3]等,确保文献引用的一致性。 最后,用户可能希望得到一些常见问题的解答或使用中的注意事项,比如过拟合时的损失函数调整,优化器参数设置等。这部分可以放在最后作为使用技巧,帮助用户解决实际问题。 总结下来,回答的结构应该是: 1. 损失函数详解(分类、回归、序列任务) 2. 优化器对比(SGD、Adam、RMSprop等) 3. 联合使用指南(如何选择组合,调参技巧) 4. 常见问题与解决方案 5. 代码示例(可选) 需要确保每个部分都包含公式、适用场景、优缺点和引用来源。同时语言要清晰,避免过于技术化,让不同层次的读者都能理解。可能还需要检查是否有最新的优化器或损失函数没有提到,比如Nadam或SWATS,但用户提供的引用中没有提到这些,所以可能不需要扩展太多,保持原有结构的基础上深化内容即可。</think>### 深度学习中的损失函数优化详解及使用指南 --- #### 一、损失函数:核心功能与分类选择 损失函数(Loss Function)是模型性能的“指南针”,量化预测值与真实值的偏差,直接影响参数更新方向。以下按任务类型分类详解: ##### 1. **回归任务** - **均方误差(MSE)** $$ L = \frac{1}{n}\sum_{i=1}^n (y_i - \hat{y}_i)^2 $$ - **特点**:对异常值敏感,适用于数据分布均匀的场景(如房价预测)[^1]。 - **改进**:改用平均绝对误差(MAE)$$ L = \frac{1}{n}\sum_{i=1}^n |y_i - \hat{y}_i| $$ 可降低异常值影响[^2]。 ##### 2. **分类任务** - **交叉熵损失(Cross-Entropy)** $$ L = -\sum_{i=1}^n y_i \log(\hat{y}_i) $$ - **适用场景**:多分类问题(如文本分类、图像识别)[^1][^3]。 - **变体**: - **加权交叉熵**:类别不平衡时,为罕见类别分配更高权重。 - **Focal Loss**:降低易分类样本权重,缓解类别不均衡问题(常用于目标检测)。 ##### 3. **序列任务(RNN/LSTM/Transformer)** - **逐时间步损失求和**: 对序列中每个位置计算损失后累加,例如文本生成任务中逐词计算交叉熵[^3]。 $$ L = \sum_{t=1}^T L_t $$ - **注意点**:长序列训练可能因梯度消失/爆炸导致损失震荡,需结合优化器调整[^1]。 --- #### 二、优化器:算法对比与调参策略 优化器通过梯度下降法更新参数,核心目标是高效收敛且避免局部最优。主要算法对比: | 优化器 | 核心公式 | 适用场景 | 注意事项 | |--------------|--------------------------------------------------------------------------|-----------------------------------|-----------------------------------| | **SGD** | $$ \theta_{t+1} = \theta_t - \eta \nabla_\theta L $$ | 凸优化、小批量数据、需稳定收敛[^3] | 需手动调学习率,易困于鞍点[^3] | | **Adam** | $$ \theta_{t+1} = \theta_t - \eta \frac{m_t}{\sqrt{v_t} + \epsilon} $$ | 非凸优化、大数据集、快速收敛[^3] | 自适应学习率可能导致后期震荡 | | **RMSprop** | $$ \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{E[g^2]_t} + \epsilon} g_t $$ | 非平稳目标(如RNN时序建模)[^1] | 需调整衰减率$\gamma$(默认0.9)[^3] | ##### **优化器选择指南** 1. **任务类型决定基准选择**: - **图像分类(CNN)**:优先Adam(快速收敛)。 - **机器翻译(RNN/Transformer)**:优先SGD或RMSprop(长序列稳定性更优)[^1]。 2. **数据特征影响调参**: - **稀疏数据**:使用自适应优化器(Adam、Adagrad),避免手动调学习率[^3]。 - **小数据集**:SGD配合动量(Momentum)可提升泛化能力。 ##### **调参技巧** - **学习率设置**: - Adam初始学习率通常设为$0.001$,SGD设为$0.01 \sim 0.1$[^3]。 - 使用学习率调度(如`ReduceLROnPlateau`)动态调整。 - **梯度裁剪(Gradient Clipping)**: 限制梯度最大值,防止RNN训练中的梯度爆炸[^1]。 ```python torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) ``` --- #### 三、联合应用:损失函数优化器的协同设计 ##### 1. **分类任务实例(PyTorch)** ```python # 定义模型、损失函数优化器 model = Transformer(num_classes=10) criterion = nn.CrossEntropyLoss(weight=class_weights) # 加权交叉熵 optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01) # 添加L2正则 # 训练循环 for inputs, labels in dataloader: optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 5.0) # 梯度裁剪 optimizer.step() ``` ##### 2. **回归任务调优策略** - **损失函数选择**: - 数据含噪声时用MAE,平滑数据用MSE。 - **优化器组合**: - 使用SGD配合余弦退火(Cosine Annealing)学习率,提升收敛稳定性[^3]。 --- #### 四、常见问题与解决方案 1. **损失值震荡不收敛** - **检查点**: - 学习率过大 → 逐步降低学习率或使用自适应优化器。 - 梯度爆炸 → 应用梯度裁剪(如设置`max_norm=5.0`)[^1]。 2. **模型过拟合** - **改进方法**: - 损失函数中增加L2正则项:$$ L = L_{\text{原始}} + \lambda \sum \theta_i^2 $$ - 优化器使用AdamW(解耦权重衰减与梯度更新)。 3. **训练速度过慢** - **加速策略**: - 切换为Adam或Nadam(Nesterov加速的Adam)。 - 增大批量大小(Batch Size)并同步调整学习率[^3]。 --- ### 代码示例:RNN时间序列预测 ```python import torch import torch.nn as nn # 定义模型与损失函数 class RNN_Model(nn.Module): def __init__(self, input_size, hidden_size): super().__init__() self.rnn = nn.GRU(input_size, hidden_size, batch_first=True) self.fc = nn.Linear(hidden_size, 1) # 预测单变量 def forward(self, x): out, _ = self.rnn(x) return self.fc(out[:, -1, :]) # 取最后一个时间步输出 model = RNN_Model(input_size=3, hidden_size=128) criterion = nn.MSELoss() # 回归任务用MSE optimizer = torch.optim.RMSprop(model.parameters(), lr=0.005) # 训练流程 for epoch in range(100): for seq, target in train_loader: optimizer.zero_grad() pred = model(seq) loss = criterion(pred, target) loss.backward() nn.utils.clip_grad_value_(model.parameters(), 10.0) # 梯度值裁剪 optimizer.step() ``` --- ### 关键结论 1. **损失函数**需根据任务类型(回归/分类/生成)和数据特性(噪声、不平衡性)选择。 2. **优化器**的核心矛盾是收敛速度与泛化性能:Adam类适合快速实验,SGD类适合最终调优[^3]。 3. **联合调参**时,正则化、学习率调度与梯度管理缺一不可,需通过实验验证组合效果。
评论 17
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值