【Pytorch基础】torch.nn.CrossEntropyLoss损失函数介绍

本文详细介绍了PyTorch中交叉熵的定义、数学原理,并通过实例演示了如何在实际项目中使用torch.nn.CrossEntropyLoss进行多分类问题的损失计算。讲解了其在神经网络训练中的作用和权重调整技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 交叉熵的定义

  交叉熵主要是用来判定实际的输出与期望的输出的接近程度,为什么这么说呢,举个例子:在做分类的训练的时候,如果一个样本属于第K类,那么这个类别所对应的输出节点的输出值应该为1,而其他节点的输出都为0,即[0,0,1,0,….0,0],这个数组也就是样本的Label,是神经网络最期望的输出结果。也就是说用它来衡量网络的输出与标签的差异,利用这种差异经过反向传播去更新网络参数。参考文献【1】

2 交叉熵的数学原理

Pytorch常用的交叉熵损失函数CrossEntropyLoss()详解

3 Pytorch交叉熵实现

3.1 举个栗子

  交叉熵损失,是分类任务中最常用的一个损失函数。在Pytorch中是基于下面的公式实现的。
Loss ⁡ ( x ^ , x ) = − ∑ i = 1 n x log ⁡ ( x ^ ) \operatorname{Loss}(\hat{x}, x)=-\sum_{i=1}^{n} x \log (\hat{x}) Loss(x^,x)=i=1nxlog(x^)
其中 x x x是真实标签, x ^ \hat{x} x^ 是预测的类分布(通常是使用softmax将模 型输出转换为概率分布)。
  取单个样本举例, 假设 x 1 = [ 0 , 1 , 0 ] x_1=[0, 1, 0] x1=[0,1,0], 模型预测样本 x 1 x_1 x1的概率为 x 1 ^ = [ 0.1 , 0.5 , 0.4 ] \hat{x_1}=[0.1, 0.5, 0.4] x1^=[0.1,0.5,0.4](因为是分布, 所以属于各个类的和为1)。则样本的损失计算如下所示:

   Loss ⁡ ( x 1 ^ , x 1 ) = − 0 × log ⁡ ( 0.1 ) − 1 × log ⁡ ( 0.5 ) − 0 × log ⁡ ( 0.4 ) = log ⁡ ( 0.5 ) \operatorname{Loss}(\hat{x_1}, x_1)=-0 \times \log (0.1)-1 \times \log (0.5)-0 \times \log (0.4)=\log (0.5) Loss(x1^,x1)=0×log(0.1)1×log(0.5)0×log(0.4)=log(0.5)

更详细的多分类交叉熵损失函数的例子可以参考文献【4】

3.2 Pytorch实现

实际使用中需要注意几点:

  1. torch.nn.CrossEntropyLoss(input, target)中的标签target使用的不是one-hot形式,而是类别的序号。形如 target = [1, 3, 2] 表示3个样本分别属于第1类、第3类、第2类。(单标签多分类问题)
  2. torch.nn.CrossEntropyLoss(input, target)的input是没有归一化的每个类的得分,而不是softmax之后的分布。

  输入的形式大概如下所示

import torch
target = [1, 3, 2]

input_ = [[0.13, -0.18, 0.87],
		 [0.25, -0.04, 0.32],
		 [0.24, -0.54, 0.53]]
# 然后就将他们扔到CrossEntropyLoss函数中,就可以得到损失。
loss_item = torch.nn.CrossEntropyLoss()
loss = loss_item(input, target)

CrossEntropyLoss函数里面的实现,如下所示:

def forward(self, input, target):
    return F.cross_entropy(input, target, weight=self.weight,
                           ignore_index=self.ignore_index, reduction=self.reduction)

是调用的torch.nn.functional(俗称F)中的cross_entropy()函数。

  此处需要区分一下:torch.nn.Module 和 torch.nn.functional(俗称F)中损失函数的区别。Module的损失函数例如CrossEntropyLoss、NLLLoss等是封装之后的损失函数类,是一个类,因此其中的变量可以自动维护。经常是对F中的函数的封装。而F中的损失函数只是单纯的函数。
下面看一下F.cross_entropy函数

3.3 F.cross_entropy

  • input:预测值,(batch,dim),这里dim就是要分类的总类别数
  • target:真实值,(batch),这里为啥是1维的?因为真实值并不是用one-hot形式表示,而是直接传类别id。
  • weight:指定权重,(dim),可选参数,可以给每个类指定一个权重。通常在训练数据中不同类别的样本数量差别较大时,可以使用权重来平衡。
  • ignore_index:指定忽略一个真实值,(int),也就是手动忽略一个真实值。
  • reduction:在[none, mean, sum]中选,string型。none表示不降维,返回和target相同形状;mean表示对一个batch的损失求均值;sum表示对一个batch的损失求和。

其中参数weight、ignore_index、reduction要在实例化CrossEntropyLoss对象时指定,例如:

loss = torch.nn.CrossEntropyLoss(reduction='none')

F中的cross_entropy的实现

return nll_loss(log_softmax(input, dim=1), target, weight, None, ignore_index, None, reduction)

可以看到就是先调用log_softmax,再调用nll_loss。log_softmax就是先softmax再取log。

4 参考文献

[1]Pytorch常用损失函数拆解
[2]Pytorch常用的交叉熵损失函数CrossEntropyLoss()详解
[3]负对数似然(negative log-likelihood)
[4]损失函数|交叉熵损失函数

<think>我们被要求提供torch.nn.CrossEntropyLoss的函数定义和参数说明。根据引用[1]和引用[2]中的信息,我们可以总结如下: CrossEntropyLossPyTorch中用于多分类问题的损失函数。它结合了LogSoftmax和NLLLoss(负对数似然损失)的操作,因此输入应该是每个类的原始分数(logits),而不是经过softmax的概率分布。 ### 函数原型 在PyTorch中,我们通常这样实例化CrossEntropyLoss对象: ```python torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean', label_smoothing=0.0) ``` ### 参数说明 1. **weight** (Tensor, 可选): 给每个类别的手动重缩放权重。如果提供,它应该是一个长度为`C`(类别数)的张量。这在处理类别不平衡的数据集时很有用。默认值为`None`,表示所有类别的权重均为1。 2. **size_average** (bool, 可选): 已弃用(由`reduction`取代)。当设置为`True`时,损失是批次中每个样本损失的平均值。注意,对于某些损失,每个样本有多个元素。如果`size_average`设置为`False`,则对每个小批量的损失求和。当`reduce`为`False`时忽略。默认值:`True` 3. **ignore_index** (int, 可选): 指定一个被忽略的目标值,该值不会影响输入梯度。当`reduction`为`'mean'`时,损失是在非忽略目标上平均的。默认值为`-100`。 4. **reduce** (bool, 可选): 已弃用(由`reduction`取代)。当设置为`False`时,返回每个样本的损失,而不是对批次进行汇总。默认值:`True` 5. **reduction** (string, 可选): 指定应用于输出的归约方式:`'none'` | `'mean'` | `'sum'`。`'none'`:不进行归约,返回每个样本的损失;`'mean'`:取所有损失的平均值;`'sum'`:将所有损失求和。默认值:`'mean'` 6. **label_smoothing** (float, 可选): 标签平滑的程度,取值范围在0.0到1.0之间。当给定一个大于0.0的值时,会使用标签平滑,即真实标签被调整为`1 - label_smoothing + label_smoothing / num_classes`,而其他类别则被调整为`label_smoothing / num_classes`。默认值:`0.0`(不进行平滑)。 ### 数学原理 对于每个样本,损失函数计算如下: 设输入(logits)为$X$,其形状为`(batch_size, C)`(或者对于高维输入,形状为`(batch_size, C, d1, d2, ..., dK)`,其中$K \geq 1$表示额外的维度)。目标$y$可以是类别索引(形状为`(batch_size)`或`(batch_size, d1, d2, ..., dK)`,每个值在$[0, C-1]$范围内),也可以是类别概率(形状与输入相同,但仅当`label_smoothing>0`时使用概率形式,否则必须为类别索引)。 损失的计算公式为: $$ \text{loss}(x, y) = -\sum_{c=1}^{C} w_c \cdot y_c \cdot \log\left(\frac{\exp(x_c)}{\sum_{j=1}^{C}\exp(x_j)}\right) $$ 其中,$w_c$是类别$c$的权重(由`weight`参数指定,如果未指定则$w_c=1$),$y_c$是目标类别$c$的平滑后概率(如果是类别索引,则$y$是一个one-hot向量,但经过平滑调整)。 实际上,由于$y$通常是类别索引,我们可以更高效地计算: $$ \text{loss}(x, y) = -w_y \cdot \log\left(\frac{\exp(x_y)}{\sum_{j=1}^{C}\exp(x_j)}\right) = w_y \left( -x_y + \log\left(\sum_{j=1}^{C}\exp(x_j)\right) \right) $$ 当使用标签平滑时,目标$y$不再是一个one-hot向量,而是一个概率分布。 ### 使用示例 ```python import torch import torch.nn as nn # 创建CrossEntropyLoss对象 loss = nn.CrossEntropyLoss() # 输入为2x3,即2个样本,3个类别 input = torch.randn(2, 3, requires_grad=True) # 目标为两个类别索引 target = torch.tensor([1, 0]) # 计算损失 output = loss(input, target) output.backward() ``` ### 注意事项 - 输入(logits)不需要经过softmax层,因为CrossEntropyLoss内部会先进行log-softmax操作。 - 目标可以是类别索引(LongTensor)或者概率分布(FloatTensor),但通常使用类别索引。当使用标签平滑时,目标可以是概率分布,但也可以直接使用类别索引(此时内部会自动转换为平滑后的概率分布)。 - 当指定`ignore_index`时,目标中等于该值的元素对应的损失将被忽略(在归约时不计入)。 ### 引用 根据引用[1]和引用[2],我们在回答中引用了关于CrossEntropyLoss的用法和参数说明。 ### 相关问题 1. 如何处理多标签分类任务?CrossEntropyLoss是否适用? 2.PyTorch中如何实现带权重的交叉熵损失以处理类别不平衡? 3. 标签平滑(label smoothing)技术是如何工作的?它为什么能提高模型泛化能力? 4. 在语义分割任务中,如何正确使用CrossEntropyLoss处理每个像素的分类? 5. 如何理解CrossEntropyLoss的梯度计算?它对模型训练有什么影响? [^1]: 引用[1]中提到了定义CrossEntropyLoss对象和计算损失。 [^2]: 引用[2]展示了不同reduction参数的设置。</think>### `torch.nn.CrossEntropyLoss` 函数原型与参数详解 #### 函数原型 ```python torch.nn.CrossEntropyLoss( weight: Optional[torch.Tensor] = None, size_average: Optional[bool] = None, ignore_index: int = -100, reduce: Optional[bool] = None, reduction: str = 'mean', label_smoothing: float = 0.0 ) ``` #### 参数说明 1. **`weight`** (Tensor, 可选) - **作用**:各类别的权重张量,用于处理类别不平衡问题 - **要求**:长度等于类别数 $C$ 的一维张量 - **示例**:`weight=torch.tensor([1.0, 0.5, 2.0])` 表示第 0 类权重为 1.0,第 1 类为 0.5,第 2 类为 2.0 - **默认值**:`None`(所有类别权重相等) 2. **`ignore_index`** (int) - **作用**:忽略指定类别的损失计算 - **场景**:当目标标签包含特殊值(如填充值)时 - **默认值**:`-100` 3. **`reduction`** (str) - **作用**:控制损失输出的归约方式 - **可选值**: - `'none'`:返回每个样本的原始损失值(形状与输入相同) - `'mean'`:计算所有样本损失的平均值(默认值) - `'sum'`:对所有样本损失求和 - **示例**: ```python loss_none = nn.CrossEntropyLoss(reduction='none') loss_mean = nn.CrossEntropyLoss(reduction='mean') # 默认 ``` 4. **`label_smoothing`** (float) - **作用**:标签平滑系数,防止模型过拟合 - **范围**:$[0.0, 1.0]$ - **公式**:调整后的目标概率为: $$ y_{\text{new}} = (1 - \epsilon) \cdot y + \frac{\epsilon}{C} $$ 其中 $\epsilon$ 为平滑系数,$C$ 为类别总数 - **默认值**:`0.0`(不启用平滑) #### 数学原理 对于输入 logits $x$ 和目标类别 $y$,损失计算为: $$ \text{loss}(x, y) = -\log\left(\frac{\exp(x_y)}{\sum_{j=1}^{C} \exp(x_j)}\right) = -x_y + \log\left(\sum_{j=1}^{C} \exp(x_j)\right) $$ 当启用标签平滑时,目标概率分布按公式调整[^1]。 #### 输入输出要求 | 参数 | 形状要求 | 数据类型 | 说明 | |------|----------|----------|------| | **输入 (logits)** | $(N, C)$ 或 $(N, C, d_1, d_2, ..., d_K)$ | Float | $N$=批大小,$C$=类别数,$K$≥1 表示高维数据(如图像分割) | | **目标 (target)** | $(N)$ 或 $(N, d_1, d_2, ..., d_K)$ | Long | 每个值为 $[0, C-1]$ 的类别索引 | | **输出 (loss)** | 标量 或 $(N)$ 或 $(N, d_1, ..., d_K)$ | Float | 由 `reduction` 参数决定形状 | #### 使用示例 ```python import torch import torch.nn as nn # 创建损失函数(带类别权重和标签平滑) loss_fn = nn.CrossEntropyLoss( weight=torch.tensor([1.0, 2.0, 0.5]), # 3个类别的权重 reduction='mean', label_smoothing=0.1 ) # 输入数据 (batch_size=2, num_classes=3) logits = torch.tensor([[1.2, 0.5, -0.8], [0.3, 2.1, -1.5]]) targets = torch.tensor([0, 2]) # 真实标签索引 # 计算损失 loss = loss_fn(logits, targets) print(f"Loss: {loss.item():.4f}") ``` #### 注意事项 1. 输入 logits **不需预先 Softmax 处理**(函数内部自动处理) 2. 目标值必须是**类别索引**(非 one-hot 编码) 3. 当 `reduction='none'` 时返回每个样本的损失向量 4. `size_average` 和 `reduce` 参数已弃用,推荐统一使用 `reduction`[^2] #### 与其他损失函数对比 | 损失函数 | 适用场景 | 输入要求 | |----------|----------|----------| | `CrossEntropyLoss` | 单标签多分类 | Logits + 类别索引 | | `BCEWithLogitsLoss` | 二分类/多标签 | Sigmoid 输出 | | `NLLLoss` | 自定义概率输出 | Log-Softmax 输出 | [^1]: 引用[1]中提到了定义CrossEntropyLoss对象和计算损失。 [^2]: 引用[2]展示了不同reduction参数的设置。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值