PyTorch深度学习实战 |损失函数

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 本文介绍了PyTorch深度学习中四种核心损失函数及其应用场景。交叉熵损失(CrossEntropyLoss)适用于多分类任务,二进制交叉熵损失(BCELoss)专用于二分类问题,KL散度损失(KLDivLoss)用于衡量概率分布差异(如VAE模型),均方误差(MSELoss)则是回归任务的基础损失函数。通过具体代码示例(如图像分类、广告点击预测、房价预测等),文章展示了每种损失函数的PyTorch实现方式,并比较了不同损失函数的适用场景和计算特点,帮助读者根据任务需求选择合适的损失函数。

 🧭 引言:损失函数

    在深度学习的广阔领域中,如果说神经网络是结构精密的引擎,那么损失函数(Loss

Function)就是指引引擎方向的罗盘和灵魂。它承担着至关重要的任务:量化模型的预测结果与

真实标签之间的差距,并将这个差距转化为可供优化器使用的梯度,驱动着整个反向传播过程。

一个优秀的模型离不开一个恰当的损失函数。它不仅决定了模型的学习目标,更直接影响了模型的

收敛速度和最终性能。PyTorch 作为最主流的深度学习框架之一,提供了丰富且高效的损失函数模

块,涵盖了从简单的回归到复杂的生成模型等各类任务。

      然而,面对 nn.CrossEntropyLoss()、nn.BCELoss() 等众多选择,初学者往往感到困惑:它们

之间有何不同?我该在什么场景下使用哪一个?本文将脱离枯燥的理论推导,以 PyTorch 实战代

码和具体的应用场景为核心,带你深入理解几个在深度学习实战中最为关键的损失函数。我们将通

过实际例子,逐一探讨以下核心组件:

【1】交叉熵损失 (Cross-Entropy Loss): 多分类任务的基石。

【2】二进制交叉熵损失 (Binary Cross-Entropy Loss): 专用于二分类任务的精确工具。

【3】KL 散度损失 (KL Divergence Loss): 在变分自编码器(VAE)等生成模型中衡量分布差异的

【4】均方误差(Mean Squared Error, MSE):回归问题中最常用的损失函数

重要方法。

     读完本文,你将不仅知道如何调用 PyTorch 中的损失函数,更能理解它们背后的数学意义和应

用场景,从而自信地为你的下一个深度学习项目选择最合适的“罗盘”。


📘交叉熵损失

交叉熵在信息论中用于度量两个概率分布间的差异性。将上述相对熵(KL散度)公式拆开,可以

得到 相对熵=交叉熵-熵

image.gif

因此,对于一个离散随机变量的两个概率分布 P和 Q来说,它们的交叉熵定义为:

image.gif

在机器学习训练时,输入的数据和它对应的标签(比如图片是 “猫” 还是 “狗”)都是确定的。这就

意味着,真实的概率分布其实是 “固定” 的 —— 比如某个样本的真实标签是 “猫”,那真实分布就是

“猫的概率 = 100%,狗的概率 = 0%”。既然真实分布固定,那它的熵(衡量不确定性的那个值)也

会是一个固定不变的数。而交叉熵的公式里,包含了两部分:一部分是真实分布和预测分布的 “相

对熵”(KL 散度,衡量两者差异),另一部分就是真实分布的熵(那个固定的数)。所以,交叉熵

其实就等于 “相对熵 + 一个固定值”。因为固定值不影响 “谁大谁小” 的比较,所以交叉熵和相对熵

一样,都能用来衡量预测分布和真实分布的差异 —— 值越小,说明预测得越准。而且交叉熵的计

算公式比相对熵更简单,算起来方便。所以机器学习里,大家更爱用交叉熵当损失函数来算

Loss。

举个栗子🌰:交叉熵损失函数

image.gif

二分类中的损失函数比较简单这里就不多介绍了,这里我们来看一下多分类中的损失函数。

下面这个是一个图片分类的问题,图片中有🐱🐕🐂3种类别,我们现在训练出了一个模型,并对

我们的样本进行预测,得到预测值。现在我们基于这个例子来说明多分类中的交叉熵误差(

只关注该样本的真实标记类别的预测概率)。

💡 深度学习案例:图像分类任务

我们有一个简单的图像分类任务,需要将图片分为 3 个类别:猫(Cat, 索引 0)、狗(Dog, 索引

1)、鸟(Bird, 索引 2)。假设我们的神经网络已经跑完了前向传播,并输出了一个批次(Batch

Size = 2)的原始分数,我们称之为 Logits

image.gif

import torch
import torch.nn as nn
import torch.nn.functional as F
# 1. 定义 Logits (模型的原始输出)
# Batch Size = 2, 类别数 C = 3 (猫, 狗, 鸟)
# Logits 是模型最后一层线性层的输出,未经 Softmax 激活。
logits = torch.tensor([
    [2.0, 1.0, 0.1],  # 样本 1 的 Logits:模型倾向于猫 (索引 0)
    [0.5, 3.0, 1.5]   # 样本 2 的 Logits:模型强烈倾向于狗 (索引 1)
], dtype=torch.float32)
# 2. 定义真实标签 (Target)
# 注意:PyTorch 的 nn.CrossEntropyLoss 要求 Target 是类别的索引,而不是 One-Hot 编码。
# 样本 1 真实标签是 狗 (索引 1)
# 样本 2 真实标签是 狗 (索引 1)
target = torch.tensor([1, 1], dtype=torch.long) 
# --- A. 使用 PyTorch 内置函数 (推荐方式) ---
# nn.CrossEntropyLoss 内部会自动完成 Softmax 激活和 NLL 损失计算
loss_fn = nn.CrossEntropyLoss()
loss_ce = loss_fn(logits, target)
print(f"PyTorch nn.CrossEntropyLoss 结果: {loss_ce.item():.4f}")
# --------------------------------------------------------------------
# --- B. 手动拆解计算 (用于理解原理) ---
print("\n--- 手动拆解计算过程 ---")
# 1. Softmax: 将 Logits 转换为概率分布 (q)
probabilities = F.softmax(logits, dim=1)
print(f"Softmax 概率分布 (q):\n{probabilities.detach().numpy()}")
# 2. 找出正确类别的预测概率 q_k
# 样本 1 (真实标签是 1): q_1 = 0.2458
# 样本 2 (真实标签是 1): q_1 = 0.8123
# 3. 计算负对数损失: L = - log(q_k)
# 样本 1 损失: -log(0.2458) ≈ 1.4036
# 样本 2 损失: -log(0.8123) ≈ 0.2079
loss_manual = F.nll_loss(torch.log(probabilities), target) 
# 或者直接:loss_manual = (-torch.log(probabilities[0, target[0]]) - torch.log(probabilities[1, target[1]])) / 2
print(f"手动计算的平均 NLL 损失: {loss_manual.item():.4f}")

image.gif

🍬总结一下:

  在代码实战中,需要传入的参数是,一个是所有模型最后一层线性层的输出,一个是真实的索引

标签值。


📘二进制交叉熵损失

BCE 损失专门用于二分类问题,即任务的输出只有两种可能:0 或 1(如:是/否、正/负、点击/未

点击)。具体公式如下图所示:

image.gif

💡 深度学习案例:广告点击预测

我们正在训练一个模型来预测用户是否会点击某个广告。这是一个典型的二分类问题,输出为:1

(点击)0 (未点击)

在 PyTorch 中,实现 BCE 损失有两种常用且重要的写法:

image.gif

使用 nn.BCELoss() (需要先进行 Sigmoid 激活)

     nn.BCELoss() 要求输入必须是 [0, 1] 之间的概率值。这意味着模型的 Logits 输出必须先通过

Sigmoid 函数转化为概率。

import torch
import torch.nn as nn
# 1. 定义真实标签 (Target)
# 注意:BCE 损失要求 Target 必须是 float 类型
target = torch.tensor([1.0, 0.0, 1.0, 0.0], dtype=torch.float32) 
# 2. 定义模型输出 Logits (未经 Sigmoid 激活的原始分数)
logits = torch.tensor([-0.5, 1.2, 5.0, -3.0], dtype=torch.float32)
# 3. 将 Logits 转换为概率 (Sigmoid激活)
# Sigmoid 将 Logits 映射到 [0, 1] 区间
predicted_probabilities = torch.sigmoid(logits) 
# predicted_probabilities 结果: [0.3775, 0.7686, 0.9933, 0.0474]
print(f"预测概率 (Sigmoid后): {predicted_probabilities.detach().numpy()}")
# 4. 使用 nn.BCELoss 进行计算
loss_fn_bce = nn.BCELoss()
loss_bce = loss_fn_bce(predicted_probabilities, target)
print(f"nn.BCELoss 结果: {loss_bce.item():.4f}")

image.gif

使用 nn.BCEWithLogitsLoss() (PyTorch 推荐,数值更稳定)

在深度学习实践中,更推荐使用 nn.BCEWithLogitsLoss。它在内部自动集成了 Sigmoid 激活和

BCE 损失的计算。

重要区别: 它的输入是原始 Logits,不需要手动进行 Sigmoid 激活。

# 1. 再次使用原始 Logits 和 Target
# logits: [-0.5, 1.2, 5.0, -3.0]
# target: [1.0, 0.0, 1.0, 0.0]
# 2. 使用 nn.BCEWithLogitsLoss (直接输入 Logits)
loss_fn_bce_logits = nn.BCEWithLogitsLoss()
loss_bce_logits = loss_fn_bce_logits(logits, target)
print(f"nn.BCEWithLogitsLoss 结果: {loss_bce_logits.item():.4f}")

image.gif

🍬总结一下:

两者的不同点在于,是否需要手动的进行Sigmoid 激活


📘KL 散度损失

KL 散度在深度学习中主要用于衡量两个概率分布之间的差异,而不是像交叉熵那样直接衡量预测

值和真实标签之间的误差。它在生成模型和知识蒸馏中有着非常重要的作用。

相对熵在信息论中用来描述两个概率分布差异的熵,叫作KL散度。对于一个离散随机变量的

两个概率分布P和 Q来说,它们的相对熵定义为:

image.gif

举个栗子🌰

我们用 “天气预测” 的例子来计算 KL 散度,直观理解它如何衡量两个概率分布的差异。

真实的天气概率分布 P(比如根据历史数据统计):

晴天:60%(0.6)

阴天:30%(0.3)

雨天:10%(0.1)

某预测模型给出的天气概率分布 Q:

晴天:70%(0.7)

阴天:20%(0.2)

雨天:10%(0.1)

image.gif

💡 深度学习案例:变分自编码器 (VAE)

KL 散度最典型的应用是在 变分自编码器(VAE) 中。在 VAE 的损失函数中,KL 散度项负责正则

(Regularization),它迫使编码器(Encoder)学习到的潜在空间分布接近于一个预设的简单分

布(通常是标准高斯分布)。

💡 PyTorch 代码实现

import torch
import torch.nn as nn
import torch.nn.functional as F
# 场景设定:我们要让模型预测分布 Q 接近目标分布 P
# 1. 定义目标分布 P (真实分布/目标分布)
# 注意:P 必须是概率值 (0 到 1 之间)
target_distribution_P = torch.tensor([0.2, 0.5, 0.3], dtype=torch.float32)
# 2. 定义模型输出 Logits (Q 分布的原始分数)
# 模型希望通过 Logits 得到接近 P 的概率分布 Q
model_logits = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32)
# 3. 计算 Q 分布的 Log-Probabilities (nn.KLDivLoss 的第一个输入)
# 为了确保输入是 Log-Probabilities,我们使用 log_softmax
log_probabilities_Q = F.log_softmax(model_logits, dim=0)
print(f"目标分布 P: {target_distribution_P.detach().numpy()}")
print(f"Log(Q) 分布: {log_probabilities_Q.detach().numpy()}")
# 4. 使用 nn.KLDivLoss 进行计算
# reduction='batchmean' (默认) - 求平均,但对于 KL 散度,通常使用 'sum' 或 'batchmean'
# reduction='sum' 更接近原始数学定义 D_KL(P||Q)
loss_fn_kl = nn.KLDivLoss(reduction='batchmean') 
# PyTorch 计算的是 D_KL(P || Q) 的近似值。
# 输入顺序:(Log-Probabilities of Q, Probabilities of P)
loss_kl = loss_fn_kl(log_probabilities_Q, target_distribution_P)
print(f"\nnn.KLDivLoss 结果 (batchmean): {loss_kl.item():.6f}")
# 示例:如果 P 和 Q 接近,损失会很小。
# 接近 P 的 Logits
good_logits = torch.log(target_distribution_P) 
good_log_Q = F.log_softmax(good_logits, dim=0)
loss_good = loss_fn_kl(good_log_Q, target_distribution_P)
print(f"如果 P 和 Q 接近时的损失: {loss_good.item():.6f}")

image.gif

目标分布 P: [0.2 0.5 0.3]

Log(Q) 分布: [-2.407606   -1.4076059  -0.40760595]


nn.KLDivLoss 结果 (batchmean): 0.092651

如果 P 和 Q 接近时的损失: 0.000000

🍬总结一下:

在代码计算的时候,输入是模型的预测分布和目标分布


📘均方误差 (MSE)

均方误差 (MSE),或称为 L2 损失,是回归任务的基准损失函数。它的核心目标是:使模型的预测

值在数值上尽可能地接近真实值

📐MSE 损失的计算公式如下:

image.gif

💡 深度学习案例:房价预测

我们正在训练一个模型预测房屋价格(单位:万元),这是一个典型的回归任务。

在 PyTorch 中,我们使用nn.MSELoss() 来实现均方误差。

import torch
import torch.nn as nn
# 1. 定义真实值 (Target)
# 假设有 4 个样本的真实房价 (单位: 万元)
true_prices = torch.tensor([250.0, 300.0, 150.0, 500.0], dtype=torch.float32) 
# 2. 定义模型预测值 (Prediction)
# 模型的预测结果 (Batch Size = 4)
predicted_prices = torch.tensor([245.0, 310.0, 160.0, 400.0], dtype=torch.float32)
# --- A. 使用 PyTorch 内置函数 (推荐方式) ---
# nn.MSELoss() 默认计算平均损失 (reduction='mean')
loss_fn_mse = nn.MSELoss()
loss_mse = loss_fn_mse(predicted_prices, true_prices)
print(f"PyTorch nn.MSELoss 结果: {loss_mse.item():.2f}")
# --- B. 手动计算过程 (用于理解原理) ---
# 1. 计算误差 (Error)
errors = true_prices - predicted_prices 
# errors 结果: [5.0, -10.0, -10.0, 100.0]
# 2. 计算平方误差 (Squared Error)
squared_errors = errors**2
# squared_errors 结果: [25.0, 100.0, 100.0, 10000.0]
# 3. 求均值 (Mean)
manual_loss = torch.mean(squared_errors)
print(f"手动计算结果: {manual_loss.item():.2f}")

image.gif

PyTorch nn.MSELoss 结果: 2556.25

手动计算结果: 2556.25


🍬总结一下:

在代码计算的时候,输入是模型的预测值和真实值

目录
相关文章
|
17天前
|
机器学习/深度学习 数据可视化 PyTorch
PyTorch深度学习实战 | 基于神经网络的水质分类
代码实现# 定义模型x = x.view(x.size(0), -1) # 展平成 (batch_size, 3072)x = self.fc3(x) # 输出return xprint("--- network.py 测试结果 ---")print(f"模型输出尺寸 (Batch, Classes): {output.shape}")语言描述步骤操作 / 组件输入数据形状输出数据形状核心作用1输入数据 (x)原始图像数据(B 为batch_size2展平 (Flatten)
88 0
|
17天前
|
机器学习/深度学习 数据挖掘 PyTorch
PyTorch深度学习实战 |手算​​FCN全卷积神经网络
本文介绍了FCN-8s语义分割网络的实现细节。首先解释了语义分割的概念及其与图像分类的区别,重点分析了FCN网络结构中的全卷积化、上采样和跳跃连接三个关键技术。全卷积化将传统CNN的全连接层改为卷积层,实现像素级分类;上采样通过双线性插值恢复特征图尺寸;跳跃连接则融合高低层特征以提升细节表现。文章详细推导了损失函数的计算过程,并提供了完整的PyTorch实现代码,包括双线性插值权重初始化、VGG16骨干网络和FCN-8s主体结构。最后通过测试验证了模型能正确输出与输入尺寸匹配的预测结果。
207 3
|
17天前
|
机器学习/深度学习 编解码 算法
PyTorch深度学习实战 |手算​​U-net
本文详细解析了U-Net网络架构及其在医学图像分割中的应用。重点对比了U-Net与FCN的核心区别:U-Net采用特征拼接(Concat)保留所有层级信息,而FCN使用特征相加(Add)进行融合。文章深入剖析了U-Net的编码器-瓶颈-解码器结构,解释了其独特的裁剪拼接机制和Overlap-tile策略,并提供了完整的PyTorch实现代码。现代U-Net通过SamePadding实现了输入输出尺寸一致,显著提升了分割精度。文章还探讨了弹性形变数据增强和带空间权重的损失函数设计,为医学图像分析提供了实用解决
150 2
|
17天前
|
机器学习/深度学习 并行计算 PyTorch
PyTorch深度学习实战 |Alexnet网络花分类任务项目版本
本文介绍了基于PyTorch的花卉分类实战项目,包含完整的项目架构和代码实现。项目采用AlexNet网络结构,通过YAML配置文件管理参数,实现了模块化开发。文章详细讲解了数据集处理(5类花卉)、模型训练(包含早停机制和学习率调度)、验证评估和预测功能。项目采用YOLOv5风格的目录结构,包含configs、models、utils等模块,支持命令行参数配置。实验结果显示该架构比简单实现准确率提升4%,最终预测功能可输出top-k分类结果及置信度。完整代码已开源,适合深度学习初学者进阶学习。
172 0
|
17天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch深度学习实战 |层归一化层和FeedForward
本文介绍了PyTorch深度学习中Add&Norm层和FeedForward层的实现原理。Add&Norm层由残差连接(Add)和层归一化(Norm)组成,能加速模型收敛并稳定训练。层归一化会对神经网络每层的输出进行归一化处理,文中详细展示了其计算方法和PyTorch实现代码。FeedForward层是一个两层的全连接网络,通过线性变换提取更深层次特征。文章还分析了Transformer模型中使用层归一化的原因,并提供了完整的代码实现,包括参数初始化和前向传播过程。
111 0
|
17天前
|
机器学习/深度学习 存储 并行计算
PyTorch深度学习实战 |从深度学习入门到项目化的任务(以Alexnet网络花分类任务为例)
本文介绍了PyTorch深度学习实战中的项目化开发方法。作者指出实际项目与玩具数据集的不同之处,强调需要考虑数据标准化、模型保存和实验追踪等工程问题。文章详细讲解了项目化文件结构,包括configs、models、utils等模块的划分,并提供了关键工具函数的实现,如YAML配置加载、模型检查点保存/加载、评估指标计算等。通过一个AlexNet训练示例,展示了如何将模型训练、验证和预测逻辑分离,构建完整的工程闭环。文章强调深度学习实战中80%时间在处理工程问题,只有20%在模型架构上,帮助读者从学习阶段过渡
122 0
|
17天前
|
机器学习/深度学习 数据可视化 PyTorch
PyTorch深度学习实战 |语义分割基础知识
《PyTorch语义分割实战解析》摘要:本文深入探讨语义分割中的标签处理技术,对比P模式与L模式的本质区别。P模式通过调色板实现人机双重视觉效果,底层存储类别索引(0,1,2等),表面呈现彩色可视化效果。针对边缘模糊问题,提出使用255作为忽略标签(IgnoreLabel)的解决方案。文章系统梳理7大评价指标:从基础的像素准确率(PA)到综合性的mIoU和mF1,特别强调mIoU作为核心指标的重要性,其平衡各类别的特性使其成为模型性能评估的黄金标准。通过技术原理与实战经验的结合,为深度学习从业者提供了语义分
136 0
|
17天前
|
机器学习/深度学习 自然语言处理 PyTorch
PyTorch深度学习实战 |手动计算 Transformer和完整的代码实现
本文介绍了基于PyTorch实现Transformer模型的完整过程。主要内容包括:1)Transformer架构的核心组件实现,如多头注意力机制、位置前馈网络、位置编码等;2)模型构建步骤,包括词嵌入层、编码器/解码器块和输出层的实现;3)完整的训练流程,包含数据处理、损失计算和参数优化;4)评估方法验证模型性能。文章通过代码示例详细展示了如何从零开始构建Transformer,并应用于机器翻译任务,同时对模型各层的输入输出维度进行了说明。该实现可作为深度学习实践者学习Transformer架构的实用指南
130 0
|
17天前
|
机器学习/深度学习 人工智能 PyTorch
PyTorch深度学习实战 |基于ViT(Vision Transformer)网络花分类任务
本文介绍了基于PyTorch的ViT(Vision Transformer)模型在花卉分类任务中的实战应用。主要内容包括: 数据集准备:使用包含5类花卉(雏菊、蒲公英、玫瑰、向日葵、郁金香)的数据集,按8:2比例划分为训练集和验证集。 模型架构:实现了一个精简版ViT模型,包含Patch Embedding、CLS Token、位置嵌入和Transformer编码器等核心组件。 训练流程:详细展示了数据加载、模型训练、验证及测试的完整代码实现,包括损失函数、优化器和学习率调度等配置。 辅助功能:提供了设备选
122 0
|
17天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch深度学习实战 |常见层 layer结构的实现和代码实战
本文介绍了PyTorch中常见的7种神经网络层结构及其输入输出逻辑。通过代码示例演示了全连接层(nn.Linear)、卷积层(nn.Conv2d)、LSTM层、GCN图卷积层和Transformer层的使用方法,重点讲解了各层的输入输出维度变换规则。文章以一张海绵宝宝图片为例,详细展示了图像数据的预处理流程,包括使用PIL和OpenCV两种方法读取图片并转换为PyTorch张量的过程。通过"代码+实战"的方式帮助读者理解神经网络层如何对特征进行维度变换,最终实现从原始输入到目标输出的映射
134 0

热门文章

最新文章