PyTorch 深度学习笔记(十一):Softmax 与 Sigmoid 在多分类与二分类任务中的对比

在深度学习中,Softmax 和 Sigmoid 是两种常用的激活函数,广泛应用于分类任务。它们在多分类(类别数 $K > 2$)和二分类($K = 2$)任务中各有优势。本笔记将逐步对比它们的数学原理、适用场景、PyTorch 实现方式及注意事项,帮助您选择合适的函数。


1. 数学定义与原理
  • Sigmoid 函数

    • 适用于二分类任务,输出一个概率值(0 到 1),表示样本属于正类的概率。
    • 数学公式:
      $$ \sigma(x) = \frac{1}{1 + e^{-x}} $$
    • 特点:输出值在 $[0, 1]$ 区间,常用于二分类的输出层。
  • Softmax 函数

    • 适用于多分类任务,输出一个概率分布,所有类别的概率和为 1。
    • 数学公式:
      $$ \sigma(\mathbf{z})i = \frac{e^{z_i}}{\sum{j=1}^{K} e^{z_j}} \quad \text{for} \quad i=1, \dotsc, K $$
    • 特点:将原始分数(logits)转换为概率,$K$ 是类别数。

关键对比

  • Sigmoid 输出单个概率值,Softmax 输出概率向量。
  • 在二分类任务中,Sigmoid 更直接;Softmax 也可用于二分类,但输出两个概率值(如 $[P(\text{class0}), P(\text{class1})]$),其中 $P(\text{class1}) = 1 - P(\text{class0})$,等价于 Sigmoid。

2. 适用任务对比
特征 Sigmoid Softmax
任务类型 二分类($K=2$) 多分类($K>2$)
输出形式 单个概率值($P(\text{正类})$) 概率分布(和为 1)
损失函数 二元交叉熵(BCE) 交叉熵(Cross-Entropy)
优点 计算简单,适合二分类 直接处理多类别,输出可解释性强
缺点 在多分类中不适用 在二分类中可能冗余(输出两个值)
适用场景 图像二分类(如猫 vs 狗)、文本情感分析(正/负) 图像多分类(如 MNIST 数字识别)、自然语言处理(如词性标注)

解释

  • 在二分类任务中,Sigmoid 是首选,因为它直接输出一个概率值(例如,$P(\text{猫}) = 0.8$ 表示 80% 概率为猫)。
  • 在多分类任务中,Softmax 是标准选择,因为它确保所有类别的概率和为 1(例如,在 10 类分类中,输出 $[0.1, 0.7, 0.2, \dotsc]$)。
  • 注意:在二分类中,Softmax 也可用,但通常不推荐,因为它增加计算开销(输出两个值)。Sigmoid 更高效。

3. PyTorch 实现示例

在 PyTorch 中,选择正确的激活函数和损失函数至关重要。以下示例展示如何实现。

二分类任务(使用 Sigmoid)
  • 输出层:一个神经元 + Sigmoid。
  • 损失函数:二元交叉熵(BCEWithLogitsLoss 更稳定,内部包含 Sigmoid)。
  • 代码:
    import torch
    import torch.nn as nn
    import torch.optim as optim
    
    # 定义模型(简单全连接网络)
    class BinaryClassifier(nn.Module):
        def __init__(self, input_size, hidden_size):
            super().__init__()
            self.fc1 = nn.Linear(input_size, hidden_size)
            self.relu = nn.ReLU()
            self.fc2 = nn.Linear(hidden_size, 1)  # 输出一个值(logits)
            # 使用 BCEWithLogitsLoss,无需显式添加 Sigmoid
    
        def forward(self, x):
            x = self.fc1(x)
            x = self.relu(x)
            x = self.fc2(x)  # 输出 logits
            return x
    
    # 参数设置
    input_size = 10  # 输入特征维度
    hidden_size = 64
    model = BinaryClassifier(input_size, hidden_size)
    loss_fn = nn.BCEWithLogitsLoss()  # 包含 Sigmoid 的损失函数
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    
    # 训练示例(假设 data 和 labels 已定义)
    # labels 应为浮点型(0 或 1),如 torch.tensor([1.0, 0.0, ...])
    outputs = model(data)
    loss = loss_fn(outputs.squeeze(), labels)  # squeeze 去除多余维度
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    

多分类任务(使用 Softmax)
  • 输出层:$K$ 个神经元,通常不显式添加 Softmax(因为 CrossEntropyLoss 内部包含)。
  • 损失函数:交叉熵(CrossEntropyLoss)。
  • 代码:
    import torch
    import torch.nn as nn
    import torch.optim as optim
    
    # 定义模型
    class MultiClassClassifier(nn.Module):
        def __init__(self, input_size, hidden_size, num_classes):
            super().__init__()
            self.fc1 = nn.Linear(input_size, hidden_size)
            self.relu = nn.ReLU()
            self.fc2 = nn.Linear(hidden_size, num_classes)  # 输出 K 个值(logits)
            # 使用 CrossEntropyLoss,无需显式添加 Softmax
    
        def forward(self, x):
            x = self.fc1(x)
            x = self.relu(x)
            x = self.fc2(x)  # 输出 logits
            return x
    
    # 参数设置
    input_size = 10
    hidden_size = 64
    num_classes = 5  # 类别数 K>2
    model = MultiClassClassifier(input_size, hidden_size, num_classes)
    loss_fn = nn.CrossEntropyLoss()  # 包含 Softmax 的损失函数
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    
    # 训练示例(labels 应为整数型,如 torch.tensor([0, 2, 1, ...]))
    outputs = model(data)
    loss = loss_fn(outputs, labels)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    

关键点

  • 输出层:在 PyTorch 中,通常不在模型输出层显式添加 nn.Softmaxnn.Sigmoid,因为损失函数(如 CrossEntropyLossBCEWithLogitsLoss)已内部处理。这能提高数值稳定性。
  • 损失函数选择
    • Sigmoid + 二分类:使用 BCEWithLogitsLoss(推荐)或 BCELoss(需手动添加 Sigmoid)。
    • Softmax + 多分类:使用 CrossEntropyLoss
  • 二分类使用 Softmax 的替代方案:如果必须用 Softmax,可设置输出层为两个神经元:
    self.fc2 = nn.Linear(hidden_size, 2)  # K=2
    loss_fn = nn.CrossEntropyLoss()
    

    但 Sigmoid 更简洁。

4. 注意事项与常见问题
  • 梯度问题
    • Sigmoid 在极端值(如 $x \to \pm\infty$)时梯度接近 0,可能导致梯度消失。使用 BCEWithLogitsLoss 可缓解。
    • Softmax 在计算时涉及指数运算,需注意数值溢出(PyTorch 的 CrossEntropyLoss 已优化)。
  • 概率解释
    • Sigmoid 输出 $P(\text{正类})$,可直接用于阈值判断(如 >0.5 为正类)。
    • Softmax 输出概率分布,可用 torch.argmax 获取预测类别。
  • 性能影响
    • 在二分类中,Sigmoid 比 Softmax 计算量小(输出一个值 vs 两个值)。
    • 在多分类中,Softmax 是标准,避免使用多个 Sigmoid(可能导致概率和不等于 1)。
  • 实际建议
    • 二分类:优先使用 Sigmoid + BCEWithLogitsLoss
    • 多分类:使用 Softmax(通过 CrossEntropyLoss)。
    • 混合任务:如多标签分类(每个标签独立二分类),可使用多个 Sigmoid。

5. 总结
  • Sigmoid:理想选择用于二分类任务,输出简单概率值,PyTorch 实现高效。
  • Softmax:标准用于多分类任务,输出概率分布,确保类别间竞争关系。
  • 在 PyTorch 中,正确选择损失函数(如 BCEWithLogitsLossCrossEntropyLoss)是关键,避免显式添加激活函数以提高稳定性和性能。通过本对比,您可根据任务需求灵活应用。
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐