<think>我们被要求提供torch.nn.CrossEntropyLoss的函数定义和参数说明。根据引用[1]和引用[2]中的信息,我们可以总结如下:
CrossEntropyLoss是PyTorch中用于多分类问题的损失函数。它结合了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参数的设置。