PyTorch 损失函数详解:从理论到实践

目录

一、损失函数的基本概念

二、常用损失函数及实现

[1. 均方误差损失(MSELoss)](#1. 均方误差损失(MSELoss))

[2. 平均绝对误差损失(L1Loss/MAELoss)](#2. 平均绝对误差损失(L1Loss/MAELoss))

[3. 交叉熵损失(CrossEntropyLoss)](#3. 交叉熵损失(CrossEntropyLoss))

[4. 二元交叉熵损失(BCELoss)](#4. 二元交叉熵损失(BCELoss))

三、损失函数选择指南

四、损失函数在训练中的应用

五、总结


损失函数是深度学习模型训练的核心组件,它量化了模型预测值与真实值之间的差异,指导模型参数的更新方向。本文将结合 PyTorch 代码实例,详细讲解常用损失函数的原理、适用场景及实现方法。

一、损失函数的基本概念

损失函数(Loss Function)又称代价函数(Cost Function),是衡量模型预测结果与真实标签之间差异的指标。在模型训练过程中,通过优化算法(如梯度下降)最小化损失函数,使模型逐渐逼近最优解。

损失函数的选择取决于具体任务类型:

  • 回归任务:预测连续值(如房价、温度)
  • 分类任务:预测离散类别(如图片分类、垃圾邮件识别)
  • 其他任务:如生成任务、序列标注等

二、常用损失函数及实现

1. 均方误差损失(MSELoss)

均方误差损失是回归任务中最常用的损失函数,计算预测值与真实值之间平方差的平均值。

数学公式 其中,为真实值,为预测值,n为样本数量。

代码实现

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

# 初始化MSE损失函数
mse_loss = nn.MSELoss()

# 示例数据
y_true = torch.tensor([3.0, 5.0, 2.5])  # 真实值
y_pred = torch.tensor([2.5, 5.0, 3.0])  # 预测值

# 计算损失
loss = mse_loss(y_pred, y_true)
print(f'MSE Loss: {loss.item()}')  # 输出:MSE Loss: 0.0833333358168602

特点

  • 对异常值敏感,因为会对误差进行平方
  • 是凸函数,存在唯一全局最小值
  • 适用于大多数回归任务

2. 平均绝对误差损失(L1Loss/MAELoss)

平均绝对误差计算预测值与真实值之间绝对差的平均值,对异常值的敏感性低于 MSE。

数学公式

代码实现

python 复制代码
# 初始化L1损失函数
l1_loss = nn.L1Loss()

# 计算损失
loss = l1_loss(y_pred, y_true)
print(f'L1 Loss: {loss.item()}')  # 输出:L1 Loss: 0.25

特点

  • 对异常值更稳健
  • 梯度在零点处不连续,可能影响收敛速度
  • 适用于存在异常值的回归场景

3. 交叉熵损失(CrossEntropyLoss)

交叉熵损失是多分类任务的标准损失函数,在 PyTorch 中内置了 Softmax 操作,直接作用于模型输出的 logits。

数学公式 其中,C为类别数,为真实标签的 one-hot 编码,为经过 Softmax 处理的预测概率。

代码实现

python 复制代码
def test_cross_entropy():
    # 模型输出的logits(未经过softmax)
    logits = torch.tensor([[1.5, 2.0, 0.5], [0.5, 1.0, 1.5]])
    # 真实标签(类别索引)
    labels = torch.tensor([1, 2])  # 第一个样本属于类别1,第二个样本属于类别2
    
    # 初始化交叉熵损失函数
    criterion = nn.CrossEntropyLoss()
    loss = criterion(logits, labels)
    print(f'Cross Entropy Loss: {loss.item()}')  # 输出:Cross Entropy Loss: 0.6422222256660461

test_cross_entropy()

计算过程解析

  1. 对 logits 应用 Softmax 得到概率分布
  2. 计算真实类别对应的负对数概率
  3. 取平均值作为最终损失

特点

  • 自动包含 Softmax 操作,无需手动添加
  • 适用于多分类任务(类别互斥)
  • 标签格式为类别索引(非 one-hot 编码)

4. 二元交叉熵损失(BCELoss)

二元交叉熵损失用于二分类任务,需要配合 Sigmoid 激活函数使用,确保输入值在 (0,1) 范围内。

数学公式

代码实现

python 复制代码
def test_bce_loss():
    # 模型输出(已通过sigmoid处理)
    y_pred = torch.tensor([[0.7], [0.2], [0.9], [0.7]])
    # 真实标签(0或1)
    y_true = torch.tensor([[1], [0], [1], [0]], dtype=torch.float)
    
    # 方法1:使用BCELoss
    bce_loss = nn.BCELoss()
    loss1 = bce_loss(y_pred, y_true)
    
    # 方法2:使用functional接口
    loss2 = nn.functional.binary_cross_entropy(y_pred, y_true)
    
    print(f'BCELoss: {loss1.item()}')  # 输出:BCELoss: 0.47234177589416504
    print(f'Functional BCELoss: {loss2.item()}')  # 输出:Functional BCELoss: 0.47234177589416504

test_bce_loss()

变种:BCEWithLogitsLoss

对于未经过 Sigmoid 处理的 logits,推荐使用BCEWithLogitsLoss,它内部会自动应用 Sigmoid,数值稳定性更好:

python 复制代码
# 对于logits输入(未经过sigmoid)
logits = torch.tensor([[0.8], [-0.5], [1.2], [0.6]])
bce_with_logits_loss = nn.BCEWithLogitsLoss()
loss = bce_with_logits_loss(logits, y_true)

三、损失函数选择指南

任务类型 推荐损失函数 特点
回归任务 MSELoss 对异常值敏感,适用于大多数回归场景
回归任务(含异常值) L1Loss 对异常值稳健,梯度不连续
多分类任务 CrossEntropyLoss 内置 Softmax,处理互斥类别
二分类任务 BCELoss/BCEWithLogitsLoss 配合 Sigmoid 使用,输出概率值
多标签分类 BCEWithLogitsLoss 每个类别独立判断,可同时属于多个类别

四、损失函数在训练中的应用

以图像分类任务为例,展示损失函数在完整训练流程中的使用:

python 复制代码
import torch
from torch import nn, optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# 数据预处理
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# 加载MNIST数据集
train_dataset = datasets.MNIST(
    root='./data', train=True, download=True, transform=transform
)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)

# 定义简单的全连接网络
class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(28*28, 128)
        self.fc2 = nn.Linear(128, 10)
        
    def forward(self, x):
        x = x.view(-1, 28*28)
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)  # 输出logits,不使用softmax
        return x

# 初始化模型、损失函数和优化器
model = SimpleNet()
criterion = nn.CrossEntropyLoss()  # 多分类任务
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练循环
def train(epochs=5):
    model.train()
    for epoch in range(epochs):
        running_loss = 0.0
        for images, labels in train_loader:
            # 前向传播
            outputs = model(images)
            loss = criterion(outputs, labels)
            
            # 反向传播和优化
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            
            running_loss += loss.item()
        
        # 打印每轮的平均损失
        avg_loss = running_loss / len(train_loader)
        print(f'Epoch {epoch+1}, Loss: {avg_loss:.4f}')

train()

五、总结

损失函数的选择直接影响模型的训练效果和收敛速度,关键要点:

  1. 回归任务优先选择 MSELoss,存在异常值时考虑 L1Loss
  2. 多分类任务使用 CrossEntropyLoss,无需手动添加 Softmax
  3. 二分类任务推荐使用 BCEWithLogitsLoss,数值稳定性更好
  4. 训练过程中需监控损失变化,判断模型是否收敛或过拟合

合理选择损失函数并配合适当的优化器,才能充分发挥模型的学习能力。在实际应用中,可根据具体任务特点和数据分布尝试不同的损失函数,选择表现最佳的方案。

相关推荐
路人蛃23 分钟前
通过国内扣子(Coze)搭建智能体并接入discord机器人
人工智能·python·ubuntu·ai·aigc·个人开发
CV-杨帆34 分钟前
论文阅读:arxiv 2025 A Survey of Large Language Model Agents for Question Answering
论文阅读·人工智能·语言模型
qiqiqi(^_×)38 分钟前
卡在“pycharm正在创建帮助程序目录”
ide·python·pycharm
绝顶大聪明38 分钟前
【深度学习】神经网络-part2
人工智能·深度学习·神经网络
Ching·1 小时前
esp32使用ESP-IDF在Linux下的升级步骤,和遇到的坑Traceback (most recent call last):,及解决
linux·python·esp32·esp_idf升级
加百力1 小时前
AI助手竞争白热化,微软Copilot面临ChatGPT的9亿下载挑战
人工智能·microsoft·copilot
Danceful_YJ1 小时前
16.使用ResNet网络进行Fashion-Mnist分类
人工智能·深度学习·神经网络·resnet
吗喽1543451882 小时前
用python实现自动化布尔盲注
数据库·python·自动化
hbrown2 小时前
Flask+LayUI开发手记(十一):选项集合的数据库扩展类
前端·数据库·python·layui
猫头虎2 小时前
什么是 npm、Yarn、pnpm? 有什么区别? 分别适应什么场景?
前端·python·scrapy·arcgis·npm·beautifulsoup·pip