PyTorch优化器详解:zero_grad()、loss.backward()、step() 的妙用

本文详细解释了深度学习中优化器(optimizer)的三个关键方法:optimizer.zero_grad()清除梯度,loss.backward()计算梯度并反向传播,optimizer.step()根据梯度更新参数。这些步骤构成模型训练的基本循环,对理解模型性能至关重要。
该文章已生成可运行项目,

目录

一、概述

二、代码实际应用及作用解析

1、optimizer.zero_grad()

2、loss.backward()

3、optimizer.step()

三、总结


本文重点讨论深度学习中的优化器的部分使用


一、概述

在深度学习和机器学习领域中,"optimizer"(优化器)是指一种用于优化模型参数以最小化损失函数的算法或工具。优化器的主要任务是更新模型的权重或参数,使其逐渐收敛到损失函数的最小值或局部最小值,从而提高模型的性能。

优化器在训练神经网络等机器学习模型时非常重要,因为模型参数的更新通常依赖于损失函数的梯度。

二、代码实际应用及作用解析

def train(dataloader,model,loss_fn,optimizer):
    model.train()
    batch_size_sum = 1
    for x,y in dataloader:
        x,y = x.to(device),y.to(device)
        pred = model.forward(x)
        loss = loss_fn(pred,y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        loss_value = loss.item()
        print(f"loss:{loss_value:>7f} [number:{batch_size_sum}]")
        batch_size_sum += 1

上述代码为函数在实际案例中应用,下列将以具体使用进行分析

1、optimizer.zero_grad()

清空模型参数的梯度,以确保每次迭代的梯度计算都是基于当前小批量数据的,而不会受之前迭代的影响。这是为了避免在优化过程中梯度的不正确累积。

import torch

x = torch.tensor([1., 1.], requires_grad=True)
y = 200 * x
# 定义损失
loss = y.sum()
print("x:", x)
print("y:", y)
print("loss:", loss)
print("反向传播前, 参数的梯度为: ", x.grad)
# 进行反向传播
loss.backward()
print("反向传播后, 参数的梯度为: ", x.grad)
# 定义优化器
optim = torch.optim.Adam([x], lr=0.001)  # Adam, lr = 0.001
print("更新参数前, x为: ", x)
optim.step()
print("更新参数后, x为: ", x)
# 再进行一次网络运算
y = 100 * x
# 定义损失
loss = y.sum()
# 进行optimizer.zero_grad()
optim.zero_grad()
loss.backward()  # 计算梯度grad, 更新 x*grad
print("进行optimizer.zero_grad(), 参数的梯度为: ", x.grad)

下列为结果展示:

该函数可以清楚之前累计的梯度值,若不使用,则梯度为tensor([200,200])

2、loss.backward()

根据当前的损失值(通常是一个标量)计算模型参数的梯度。它会从损失开始,然后通过模型的各个层反向传播梯度,最终计算出每个参数相对于损失的梯度。这些梯度将被用于后续的参数更新,以减小损失。

3、optimizer.step()

根据优化器的配置和计算得到的梯度来更新模型参数。具体地,它执行了参数更新的操作,通常是将当前参数减去学习率乘以参数的梯度。学习率是一个超参数,用于控制参数更新的步长大小。通过不断地执行 optimizer.step(),模型的参数将逐渐调整,以减小损失函数。

下列为loss.backward() 和 optimizer.step()的具体用法:

import torch


x = torch.tensor([1., 2.], requires_grad=True)
y = 100 * x
loss = y.sum()
print("x:", x)
print("y:", y)
print("loss:", loss)
print("反向传播前, 参数的梯度为: ", x.grad)
loss.backward()  
print("反向传播后, 参数的梯度为: ", x.grad)
optim = torch.optim.Adam([x], lr=0.001) 
print("更新参数前, x为: ", x)
optim.step()  
print("更新参数后, x为: ", x)

结果展示:

三、总结

这三行代码通常组成了深度学习模型训练的核心循环。在整个训练过程中,它们会被重复执行多次,模型的参数会根据损失函数的梯度逐渐调整,以最小化损失并提高模型性能。学习如何正确地使用这三行代码是深度学习入门的重要一步,因为它们构成了模型训练的基础。同时,理解这些代码背后的原理也有助于更好地调整超参数和选择合适的优化器,以改进模型的训练效果。

本文章已经生成可运行项目
<think>我们正在讨论Transformer模型的编码器-解码器架构中的损失函数定义和应用。根据引用[3],损失函数是交叉熵损失,用于最小化预测概率分布和实际概率分布之间的差异。我们将详细展开这一过程。 ### 一、损失函数的定义 在Transformer的编码器-解码器模型中,损失函数定义为**交叉熵损失(Cross-Entropy Loss)**。具体来说: - 解码器在每个时间步$t$输出一个概率分布$P_t$,表示目标词汇表中每个词出现的概率。 - 真实标签是一个one-hot向量$y_t$,表示在时间步$t$应该出现的正确词。 交叉熵损失计算的是预测分布$P_t$与真实分布$y_t$之间的差异: $$ \mathcal{L}_t = - \sum_{i=1}^{V} y_{t,i} \log(P_{t,i}) $$ 其中: - $V$是目标词汇表的大小, - $y_{t,i}$是真实标签的第$i$个元素(0或1), - $P_{t,i}$是模型预测的第$i$个词的概率。 由于$y_t$是one-hot向量(只有正确词的位置为1,其余为0),上式简化为: $$ \mathcal{L}_t = - \log(P_{t, k}) $$ 其中$k$是时间步$t$的正确词的索引。 整个序列的损失是各个时间步损失的平均: $$ \mathcal{L} = \frac{1}{T} \sum_{t=1}^{T} \mathcal{L}_t $$ 其中$T$是目标序列的长度(不包括起始符`<sos>`,但包括结束符`<eos>`)[^3]。 ### 二、损失函数在训练过程中的应用 #### 1. 前向传播过程 以机器翻译为例(英译法): - **输入序列(编码器)**:`["The", "cat", "sat", "on", "the", "mat"]` - **目标序列(解码器)**:`["<sos>", "Le", "chat", "s'est", "assis", "sur", "le", "tapis", "<eos>"]` 训练时采用**教师强制(Teacher Forcing)**,即解码器每一步的输入是真实的目标序列(但右移一位,以`<sos>`开头)[^1]。 #### 2. 损失计算步骤(示例时间步) 假设在解码器的第2个时间步(即输入为`<sos>`和`Le`后): - 模型预测下一个词的概率分布$P_2$(目标词汇表为法语): - `chat`: 0.85 - `chien`: 0.1 - `tapis`: 0.05 - ...(其他词概率很小) - 真实标签$y_2$ = `"chat"`(即one-hot向量中`chat`对应位置为1)。 则该时间步的损失: $$ \mathcal{L}_2 = - \log(0.85) \approx 0.1625 $$ #### 3. 掩码机制(避免填充项影响) 实际训练中,不同句子的长度不同,通常需要填充(padding)至相同长度。例如: - 目标序列:`["<sos>", "Le", "chat", "<eos>", "<pad>", "<pad>"]` - 损失计算时,应忽略填充位置(`<pad>`)的损失。 具体实现时,使用**掩码变量**$M$(mask): $$ \mathcal{L} = \frac{ \sum_{t=1}^{T} M_t \cdot \mathcal{L}_t }{ \sum_{t=1}^{T} M_t } $$ 其中$M_t = 1$表示时间步$t$不是填充项,否则为0[^1]。 #### 4. 反向传播与参数更新 损失$\mathcal{L}$计算完成后,通过反向传播同时更新: - 编码器的所有参数(包括嵌入层、自注意力层等) - 解码器的所有参数(包括掩码自注意力层、编码器-解码器注意力层等) 优化器通常使用Adam,更新公式为: $$ \theta_{new} = \theta_{old} - \eta \cdot \nabla_\theta \mathcal{L} $$ 其中$\eta$是学习率[^3]。 ### 三、类比解释 #### 类比场景:语言考试评分 - **编码器**:理解考题(如英语阅读理解题) - **解码器**:用目标语言(如法语)写出答案 - **损失函数**:评分标准(逐词比对参考答案) 具体过程: 1. 考生(解码器)根据对考题的理解(编码器输出)逐步写出答案。 2. 每写一个词,考官就对比参考答案: - 若写对(如“chat”),扣分少($-\log(0.85)$) - 若写错(如误写“chien”),扣分多($-\log(0.1)=2.3$) 3. **忽略无效部分**:答案若需补足长度(如要求写50词,实际只写40词),后10个填充位置不扣分(掩码机制)。 4. **最终成绩**:所有有效词的平均扣分($\mathcal{L}$)。 5. **改进方向**:考官不仅指出总分,还分析每处错误(反向传播),考生据此调整答题策略(参数更新)。 ### 四、与纯生成模型(如VAE)的对比 引用[4]提到变分自编码器(VAE)的解码器也使用重建损失(如交叉熵),但目标不同: | 对比项 | Transformer解码器 | VAE解码器 | |---------------|-----------------------------|------------------------| | **损失目标** | 预测序列的下一个词 | 重构原始输入数据(如图像)| | **损失类型** | 词级交叉熵 | 像素级交叉熵或均方误差 | | **训练数据** | 平行语料(句对) | 单语数据(无配对标签) | | **额外损失** | 无 | KL散度(约束潜变量分布) | > 例如:VAE中总损失为$\mathcal{L}_{VAE} = \mathbb{E}_{z \sim q}[\log p(x|z)] - \beta D_{KL}(q(z|x) \| p(z))$,其中第一部分是重建损失[^4]。 ### 五、总结流程 1. **输入**:源序列$X$,目标序列$Y=(y_1, y_2, \dots, y_T)$。 2. **编码器处理**:生成上下文表示$H_{enc} = \text{Encoder}(X)$。 3. **解码器预测**: - 输入:$Y_{\text{shifted}} = (\text{<sos>}, y_1, \dots, y_{T-1})$ - 输出:每一步的概率分布$P_t = \text{Decoder}(Y_{\text{shifted}}, H_{enc})$ 4. **损失计算**: $$ \mathcal{L} = \frac{1}{\text{有效词数}} \sum_{t: y_t \neq \text{<pad>}} -\log P_t(y_t) $$ 5. **参数更新**:通过$\nabla_\theta \mathcal{L}$更新编码器和解码器参数。 通过最小化该损失,模型学习到: - 编码器:提取源序列的语义信息(如“cat sat on mat”表示猫在垫子上) - 解码器:基于语义生成准确的目标序列(如“Le chat s'est assis sur le tapis”) --- §§相关问题§§ 1. 交叉熵损失函数在处理长尾分布(低频词较多)时有什么缺陷?如何改进? 2. 除了交叉熵,生成任务中还能使用哪些损失函数(如BLEU、ROUGE)?它们能否直接优化? 3. 教师强制训练导致推理时出现曝光偏差(Exposure Bias)的原理是什么?如何缓解? 4. 在编码器-解码器模型中,损失函数梯度是如何反向传播到编码器的?请用数学公式描述。</think>### 损失函数在编码器-解码器训练中的定义与应用详解 #### 一、核心损失函数定义 在Transformer的编码器-解码器架构中,**交叉熵损失(Cross-Entropy Loss)** 是核心训练目标,其数学定义为: $$ \mathcal{L} = -\sum_{t=1}^{T} \log P(y_t^* | y_{<t}^*, X) $$ 其中: - $T$:目标序列长度 - $y_t^*$:时间步$t$的真实词(标签) - $y_{<t}^*$:$t$时刻前的真实词序列 - $X$:编码器处理的源序列 - $P(y_t^* | \cdot)$:解码器预测正确词的概率 该函数直接惩罚预测概率分布与真实分布的差异[^3]。例如当解码器在$t=2$步预测目标词"chat"的概率为0.85时: $$ \mathcal{L}_2 = -\log(0.85) \approx 0.16 $$ 若错误预测为"chien"(概率0.1): $$ \mathcal{L}_2 = -\log(0.1) \approx 2.3 $$ **惩罚力度与错误程度成正比**。 #### 二、训练流程中的损失应用 以机器翻译为例(英→法): ```mermaid graph LR A[源序列: “The cat sat”] --> B(编码器) B --> C[上下文向量] C --> D(解码器) D --> E[预测序列: “Le chat s'est”] E --> F[损失计算] ``` 1. **前向传播**: - 编码器将源序列编码为上下文矩阵$H_{enc} \in \mathbb{R}^{n \times d_{model}}$ - 解码器基于$H_{enc}$和教师强制输入`<sos> Le chat`生成预测: - $t=1$:输入`<sos>` → 输出$P_1$(`Le`概率0.9) - $t=2$:输入`Le` → 输出$P_2$(`chat`概率0.85) - $t=3$:输入`chat` → 输出$P_3$(`s'est`概率0.7) 2. **损失计算**: $$ \mathcal{L} = \frac{1}{3} \left[ -\log(0.9) - \log(0.85) - \log(0.7) \right] \approx 0.42 $$ 实际实现需添加**掩码机制**,避免填充符`<pad>`影响损失[^1]: ```python def batch_loss(preds, labels, mask): per_step_loss = F.cross_entropy(preds, labels, reduction='none') masked_loss = (per_step_loss * mask).sum() / mask.sum() # 仅计算有效词 return masked_loss ``` 3. **反向传播**: - 损失梯度同时反向传播至: - 解码器的交叉注意力层 → 调整对编码器输出的关注权重 - 解码器的词嵌入层 → 修正目标语言表示 - 编码器的自注意力层 → 优化源语言理解 - 参数更新公式: $$ \theta_{new} = \theta_{old} - \eta \nabla_\theta \mathcal{L} $$ 其中$\eta$为学习率[^3] #### 三、关键组件中的损失作用 1. **编码器-解码器注意力层**: - 该层输出的上下文向量$c_t = \sum_i \alpha_{ti} h_i$直接影响$P(y_t|\cdot)$ - 损失梯度迫使注意力权重$\alpha_{ti}$聚焦相关源词(如预测"sat"时关注源词"sat")[^2] 2. **掩码机制**: - 训练时防止解码器窥视未来词(如图示): ``` 时间步 可见范围 t=1: [<sos>] t=2: [<sos>, Le] t=3: [<sos>, Le, chat] ``` - 损失计算仅依赖已生成的词,与推理过程一致 #### 四、现实类比:驾驶教练教学 假设训练过程如驾校教学: - **编码器** = 路况分析系统(理解道路环境) - **解码器** = 学员驾驶员(生成驾驶动作) - **损失函数** = 教练的实时纠错 具体场景: 1. 前方出现弯道(源序列:"弯道, 限速30") 2. 学员操作: - $t=1$:方向盘右转10° → 概率0.8 - $t=2$:踩刹车50%力度 → 概率0.6 3. 教练评分: - 理想操作:转15°+刹车70% - 损失计算:$\mathcal{L} = -[\log(0.8) + \log(0.6)] \approx 0.75$ 4. 错误反馈: - 编码器调整:更精准识别弯道曲率 - 解码器调整:修正转向和刹车力度决策 #### 五、与其他架构的对比 | 模型类型 | 损失函数目标 | 反向传播路径 | |----------------|-----------------------|-----------------------| | Transformer | 序列生成交叉熵[^3] | 编码器+解码器联合更新 | | BERT(纯编码器)| 掩码词预测交叉熵[^2] | 仅更新编码器 | | VAE(生成模型)| 重构损失+KL散度[^4] | 编码器→潜空间→解码器 | > **关键区别**:Transformer的损失通过教师强制实现**逐词监督**,而VAE的损失关注整体数据分布匹配[^4]。 #### 六、实际训练效果示例 在IWSLT2017德英翻译任务中: - 初始损失值:$\mathcal{L} \approx 9.0$(随机预测,$-\log(1/50000) \approx 10.9$) - 训练100 epoch后:$\mathcal{L} \approx 1.2$(BLEU分数35+) - 典型错误模式: - 损失峰值常出现在长序列结尾(注意力分散) - 低频词(如专业术语)贡献更高损失值 通过最小化交叉熵损失,模型逐步学会: 1. **编码器**:提取源语言的深层语义特征 2. **解码器**:基于语义生成语法准确的目标语言序列 3. **注意力机制**:建立源词与目标词的精确对齐[^2] ---
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值