深度学习中的一些理解,pytorch中损失函数怎么操作的?优化器如何优化的?

深度学习中的一些理解,pytorch中损失函数怎么操作的?优化器如何优化的?

这篇文章主要是小编完成 LeNet-5 的代码编写以后,对其中的一些细节,想了解的更清楚一点训练的过程中做了什么是如何计算损失的?参数是怎么更新的?

上一篇文章

本篇任务理解代码:

python 复制代码
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 训练和测试函数
def train(model, device, train_loader, optimizer, criterion, epoch):
    model.train()
    best_model = model
    min_loss = 1
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        if min_loss > loss.item():
            best_model, best_loss = model, loss.item()
        if batch_idx % 100 == 0:
            print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} ({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')
    print("模型训练结束")
    print("保存最好 loss 模型,loss:",min_loss)
    torch.save(best_model.state_dict(),'best-lenet5.pth')

损失的计算

先简单了解代码中的过程:

训练过程中使用的交叉熵损失函数(nn.CrossEntropyLoss)计算模型输出和目标标签之间的误差。具体步骤如下:

  1. 模型前向传播

    • 模型将输入数据(data)传递过来,并计算输出(output)。
  2. 计算损失

    • criterion(output, target) 计算模型输出(output)与目标标签(target)之间的交叉熵损失。
    • 交叉熵损失函数(nn.CrossEntropyLoss)首先对模型的输出进行 softmax 操作,然后计算真实标签与预测标签之间的负对数似然损失(negative log-likelihood loss)。
    • 公式表示为:
      $
      \text{CrossEntropyLoss} = -\sum_{i} y_i \log(\hat{y}_i)
      $
      其中 $ y_i 是目标类别的 o n e − h o t 编码, 是目标类别的 one-hot 编码, 是目标类别的one−hot编码, \hat{y}_i $ 是模型的 softmax 输出。
  3. 反向传播

    • loss.backward() 通过计算损失相对于模型参数的梯度,将这些梯度反向传播回模型。
  4. 优化更新

    • optimizer.step() 使用优化算法(如 SGD)更新模型的参数,以最小化损失。
  5. 保存最优模型

    • 每个批次(batch_idx)的训练过程中,检查当前损失是否为最小值。如果是,则保存当前模型及其损失。
    • 在所有批次结束后,保存具有最小损失的模型参数。

相关的解释和注释:

python 复制代码
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

def train(model, device, train_loader, optimizer, criterion, epoch):
    model.train()
    best_model = model
    min_loss = 1
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        
        # 前向传播
        output = model(data)
        
        # 计算损失
        loss = criterion(output, target)
        
        # 反向传播
        loss.backward()
        
        # 参数更新
        optimizer.step()
        
        # 保存最优模型
        if min_loss > loss.item():
            best_model, best_loss = model, loss.item()
        
        # 打印训练信息
        if batch_idx % 100 == 0:
            print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} ({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')
    
    print("模型训练结束")
    print("保存最好 loss 模型,loss:", min_loss)
    torch.save(best_model.state_dict(), 'best-lenet5.pth')

在训练过程中,nn.CrossEntropyLoss() 会自动处理模型输出和目标标签的比较,进行 softmax 操作并计算损失值。上述代码的每一步都按顺序执行,确保模型在训练过程中不断调整参数,以最小化损失函数,从而提高模型的预测精度。

过程看完了还是很迷糊,进一步了解。

我们可以更详细地了解交叉熵损失函数是如何处理模型输出和目标标签,并计算损失值的。

1. 模型输出

假设我们有一个分类任务,模型的最后一层是全连接层,其输出是一个未归一化的分数向量(logits),表示每个类别的得分。例如,对于 3 个类别,模型输出可能是 output = [2.0, 1.0, 0.1]

2. Softmax 操作

在计算交叉熵损失之前,首先需要将模型的未归一化输出转换为概率分布。这个过程通过 softmax 函数实现:

y ^ i = exp ⁡ ( o i ) ∑ j exp ⁡ ( o j ) \hat{y}i = \frac{\exp(o_i)}{\sum{j} \exp(o_j)} y^i=∑jexp(oj)exp(oi)

其中 o i o_i oi 是第 i i i 个类别的得分, y ^ i \hat{y}_i y^i 是第 i i i 个类别的预测概率。

对于 output = [2.0, 1.0, 0.1],softmax 计算如下:

y ^ 1 = exp ⁡ ( 2.0 ) exp ⁡ ( 2.0 ) + exp ⁡ ( 1.0 ) + exp ⁡ ( 0.1 ) ≈ 0.659 \hat{y}_1 = \frac{\exp(2.0)}{\exp(2.0) + \exp(1.0) + \exp(0.1)} \approx 0.659 y^1=exp(2.0)+exp(1.0)+exp(0.1)exp(2.0)≈0.659
y ^ 2 = exp ⁡ ( 1.0 ) exp ⁡ ( 2.0 ) + exp ⁡ ( 1.0 ) + exp ⁡ ( 0.1 ) ≈ 0.242 \hat{y}_2 = \frac{\exp(1.0)}{\exp(2.0) + \exp(1.0) + \exp(0.1)} \approx 0.242 y^2=exp(2.0)+exp(1.0)+exp(0.1)exp(1.0)≈0.242
y ^ 3 = exp ⁡ ( 0.1 ) exp ⁡ ( 2.0 ) + exp ⁡ ( 1.0 ) + exp ⁡ ( 0.1 ) ≈ 0.099 \hat{y}_3 = \frac{\exp(0.1)}{\exp(2.0) + \exp(1.0) + \exp(0.1)} \approx 0.099 y^3=exp(2.0)+exp(1.0)+exp(0.1)exp(0.1)≈0.099

此时,模型的输出概率分布为 output_probs = [0.659, 0.242, 0.099]

3. 目标标签

目标标签(target)通常是一个标量,表示正确类别的索引。例如,对于类别索引为 0 的目标标签:

target = 0 \text{target} = 0 target=0

4. 交叉熵损失计算

交叉熵损失计算的是目标标签与模型预测概率之间的差异。其公式为:

CrossEntropyLoss = − log ⁡ ( y ^ i ) \text{CrossEntropyLoss} = -\log(\hat{y}_i) CrossEntropyLoss=−log(y^i)

其中 y ^ i \hat{y}_i y^i 是目标标签对应的预测概率。

对于目标标签 0 和输出概率分布 output_probs = [0.659, 0.242, 0.099],交叉熵损失计算如下:

CrossEntropyLoss = − log ⁡ ( 0.659 ) ≈ 0.417 \text{CrossEntropyLoss} = -\log(0.659) \approx 0.417 CrossEntropyLoss=−log(0.659)≈0.417

PyTorch 中的实现

在 PyTorch 中,nn.CrossEntropyLoss 会自动处理 softmax 操作,并计算交叉熵损失。其使用方法如下:

python 复制代码
import torch
import torch.nn as nn

# 模型输出 logits
output = torch.tensor([[2.0, 1.0, 0.1]], requires_grad=True)

# 目标标签
target = torch.tensor([0])

# 定义交叉熵损失函数
criterion = nn.CrossEntropyLoss()

# 计算损失
loss = criterion(output, target)
print(f"Loss: {loss.item()}")

在这个例子中:

  • output 是模型的 logits 输出,形状为 [1, 3],表示批次大小为 1,有 3 个类别。
  • target 是目标标签,形状为 [1],表示正确类别的索引。

nn.CrossEntropyLoss 会先对 output 进行 softmax 操作,然后计算目标标签与预测概率之间的交叉熵损失。

到这里的话差不多就是理解了!

如何进行优化的?

优化器(optimizer)在训练过程中主要负责更新模型的参数,以最小化损失函数。具体来说,优化器通过使用反向传播算法计算的梯度信息来调整模型参数,从而使模型在训练数据上的表现逐渐改善。

SGD(随机梯度下降)优化器为例,optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) 主要完成以下几个任务:

1. 初始化优化器

创建一个 SGD 优化器实例,并将模型的参数、学习率和动量作为输入参数传递给它。

python 复制代码
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
  • model.parameters():模型的可训练参数。
  • lr=0.01:学习率,控制参数更新的步长。
  • momentum=0.9:动量项,帮助加速收敛并减小振荡。

2. 清零梯度

在每个训练批次开始前,清零所有模型参数的梯度。

python 复制代码
optimizer.zero_grad()

这是因为 PyTorch 中的梯度是累积的,因此需要在每次反向传播前清零。

3. 反向传播计算梯度

计算损失函数相对于模型参数的梯度。

python 复制代码
loss.backward()

这一操作通过链式法则计算出损失函数相对于每个参数的偏导数,并存储在每个参数的 grad 属性中。

4. 更新参数

使用计算得到的梯度更新模型参数。

python 复制代码
optimizer.step()

这是优化器的核心操作,它利用当前的梯度信息和优化算法(如随机梯度下降)来更新模型的参数。具体步骤如下:

4.1 基础 SGD 更新公式

对于每个参数 θ \theta θ,其更新公式为:

θ = θ − η ⋅ ∇ θ L ( θ ) \theta = \theta - \eta \cdot \nabla_{\theta} L(\theta) θ=θ−η⋅∇θL(θ)

其中:

  • θ \theta θ:模型参数
  • η \eta η:学习率
  • ∇ θ L ( θ ) \nabla_{\theta} L(\theta) ∇θL(θ):损失函数 L L L 对参数 θ \theta θ 的梯度
4.2 带动量的 SGD

动量的引入可以加速收敛,并减小训练过程中的振荡。动量项 v \mathbf{v} v 的更新公式为:

v = α ⋅ v + η ⋅ ∇ θ L ( θ ) \mathbf{v} = \alpha \cdot \mathbf{v} + \eta \cdot \nabla_{\theta} L(\theta) v=α⋅v+η⋅∇θL(θ)

参数的更新公式为:

θ = θ − v \theta = \theta - \mathbf{v} θ=θ−v

其中:

  • α \alpha α:动量系数(例如 0.9)
  • v \mathbf{v} v:动量项,存储了累积的梯度信息

结合动量的 SGD 更新步骤:

  1. 计算并更新动量项。
  2. 使用动量项更新模型参数。

例子

以下是一个完整的训练步骤的代码示例,展示了优化器如何与模型、数据和损失函数一起工作:

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim

# 假设已经定义并实例化了模型和数据加载器
model = ...  # 模型实例
train_loader = ...  # 训练数据加载器

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# 训练函数
def train(model, device, train_loader, optimizer, criterion, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        
        # 清零梯度
        optimizer.zero_grad()
        
        # 前向传播
        output = model(data)
        
        # 计算损失
        loss = criterion(output, target)
        
        # 反向传播
        loss.backward()
        
        # 更新参数
        optimizer.step()
        
        if batch_idx % 100 == 0:
            print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} ({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')

# 假设已经将模型移动到正确的设备上并加载数据
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

# 进行一个训练周期
train(model, device, train_loader, optimizer, criterion, epoch=1)

总结

优化器的主要工作是使用计算得到的梯度来更新模型的参数,以最小化损失函数。通过多次迭代这一过程,模型的性能在训练数据上逐渐提高,并在验证和测试数据上取得更好的表现。

相关推荐
DisonTangor30 分钟前
阿里通义千问开源Qwen2.5系列模型:Qwen2-VL-72B媲美GPT-4
人工智能·计算机视觉
豆浩宇31 分钟前
Halcon OCR检测 免训练版
c++·人工智能·opencv·算法·计算机视觉·ocr
LLSU1335 分钟前
聚星文社AI软件小说推文软件
人工智能
JackieZhengChina38 分钟前
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
人工智能·智能手机
ShuQiHere39 分钟前
【ShuQiHere】 探索数据挖掘的世界:从概念到应用
人工智能·数据挖掘
嵌入式杂谈39 分钟前
OpenCV计算机视觉:探索图片处理的多种操作
人工智能·opencv·计算机视觉
时光追逐者41 分钟前
分享6个.NET开源的AI和LLM相关项目框架
人工智能·microsoft·ai·c#·.net·.netcore
东隆科技41 分钟前
PicoQuant公司:探索铜铟镓硒(CIGS)太阳能电池技术,引领绿色能源革新
人工智能·能源
DisonTangor1 小时前
上海AI气象大模型提前6天预测“贝碧嘉”台风登陆浦东 今年已多次精准预测
人工智能
人工智能培训咨询叶梓1 小时前
生成式人工智能在无人机群中的应用、挑战和机遇
人工智能·语言模型·自然语言处理·aigc·无人机·多模态·生成式人工智能