首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >从零理解Softmax在分类问题作用

从零理解Softmax在分类问题作用

作者头像
索旭东
发布2026-03-31 19:00:06
发布2026-03-31 19:00:06
200
举报
文章被收录于专栏:具身小站具身小站

1

为什么需要 Softmax?

从一个实际问题开始

假设你训练了一个神经网络,让它识别图像中是 猫、狗还是鸟 (3分类问题)。网络的最后一层通常有3个神经元,每个输出一个数值,我们称这些数值为 logits (原始得分)。

在一次推理中,网络可能输出:

代码语言:javascript
复制
[5.2, 1.3, -0.8]

第一个神经元(猫)输出 5.2

第二个神经元(狗)输出 1.3

第三个神经元(鸟)输出 -0.8

现在面临的问题

这些数字很难解释 :5.2 比 1.3 大,我们知道模型更倾向于“猫”,但“更倾向于”是什么意思?能说“猫的概率是 5.2”吗?概率应该在 0~1 之间。

数字范围不固定 :下一次推理可能输出 [10.5, -2.3, 5.1],范围完全不一样,无法统一比较。

我们需要概率 :在很多应用中,我们需要知道“模型有多确信”。比如在机器人决策中,如果模型对“猫”的置信度只有 51%,我们可能选择不行动或请求人工确认。

我们的需求

我们需要一个函数,能把任意实数向量转换成:

  • 每个值都在 0~1 之间
  • 所有值之和为 1 (符合概率的定义)
  • 保持原始大小关系 (原来大的值,转换后概率也大)

这就是 Softmax 要解决的问题。

2

Softmax 是什么?

数学定义

对于输入 向量 $z=[z1,z2,...,zK]$,Softmax 的输出 $pi$为:

其中 $K$ 是类别总数。

逐步拆解

用上面的例子 [5.2, 1.3, -0.8]:

第1步:取指数

$e^{5.2} \approx 181.27$

$e^{1.3} \approx 3.67$

$e^{-0.8} \approx 0.45$

第2步:求和

总和 = 181.27 + 3.67 + 0.45 = 185.39

第3步:归一化

$p_1=181.27/185.39 \approx 0.978$(猫的概率 97.8%)

$p_2=3.67/185.39 \approx 0.020$(狗的概率 2.0%)

$p_3=0.45/185.39 \approx 0.002$(鸟的概率 0.2%)

关键观察

指数的作用:$e^{5.2}$远大于 $e^{1.3}$,放大了原始差异。5.2 和 1.3 原本只差 4 倍左右,经过指数后变成 181 vs 3.7,相差约 50 倍。这让模型对“最可能”的类别更加自信。

分母的作用:除以总和,确保所有输出加起来为 1。

为什么用指数,不用其他函数? 指数函数有几个好性质:

  • 输出永远为正
  • 单调递增(保持顺序)
  • 导数形式简单(便于反向传播)

3

Softmax 的核心作用

作用

说明

为什么重要

归一化为概率

将任意实数映射到(0,1),且和为1

输出有明确概率意义,便于解释和决策

放大差异

让大的值更大,小的值更小

增强模型对主要预测的置信度

提供不确定性估计

概率值反映了模型的置信程度

机器人可根据置信度决定是否执行动作

可导

处处光滑可导

可以用梯度下降优化

一个实际场景

在机器人抓取任务中,模型需要判断抓取是否可能成功:

输出 [成功概率 0.95, 失败概率 0.05] → 机器人可以自信执行

输出 [成功概率 0.51, 失败概率 0.49] → 机器人应该谨慎,可能需重新观察

没有 Softmax,你只能得到像 [8.2, 7.9] 这样的原始得分,无法做出这种置信度判断。

特点

说明

示例/类比

输出和为1

所有类别概率之和为1

[0.7, 0.2, 0.1]

对输入敏感

输入微小的变化会导致输出变化

指数运算放大了差异

不变性

所有输入加上同一个常数,输出不变

因为指数和分母会同步变化

通常搭配交叉熵损失

Softmax + 交叉熵是分类任务的标准配置

梯度形式简洁

4

怎么使用 Softmax

在 PyTorch 中的使用

代码语言:javascript
复制
import torch
import torch.nn as nn

# 假设模型的原始输出(logits)
logits = torch.tensor([[5.2, 1.3, -0.8]])  # shape: (1, 3),1个样本,3个类别

# 方法1:手动计算(理解原理)
softmax = nn.Softmax(dim=1)  # dim=1 表示在类别维度上做softmax
probs = softmax(logits)
print(probs)  # tensor([[0.9775, 0.0198, 0.0027]])

# 方法2:直接调用函数(更简洁)
probs = torch.softmax(logits, dim=1)

# 方法3:获取预测类别(最常用)
pred_class = torch.argmax(logits, dim=1)  # 直接取最大值位置,不用先softmax
print(pred_class)  # tensor([0]),表示类别0(猫)

推理时的使用

在推理时,根据需求不同:

代码语言:javascript
复制
model.eval()
with torch.no_grad():
    logits = model(image)

    # 如果需要概率(如不确定性估计)
    probs = torch.softmax(logits, dim=1)

    # 如果只需要类别
    pred = torch.argmax(logits, dim=1)

    # 如果需要前几个候选
    top_probs, top_indices = torch.topk(probs, k=3, dim=1)

5

Softmax 的“温度”概念

这是一个进阶但很有用的概念。有时我们希望控制 Softmax 输出分布的“平滑度”,这时引入 温度参数 $T$:

  • T=1 :标准 Softmax
  • T > 1
  • T < 1

应用场景:

  • 知识蒸馏 :用高温度让教师模型的输出更平滑,提供更多信息给学生模型
  • 强化学习 :控制探索与利用的平衡
  • 机器人决策 :需要更多探索时用高温度,需要稳定执行时用低温度

示例:

代码语言:javascript
复制
def softmax_with_temperature(logits, temperature=1.0):
    return torch.softmax(logits / temperature, dim=-1)

# 原始输出
logits = torch.tensor([5.2, 1.3, -0.8])

probs_T1 = softmax_with_temperature(logits, T=1)    # [0.978, 0.020, 0.002]
probs_T2 = softmax_with_temperature(logits, T=2)    # [0.825, 0.137, 0.038] 更平滑
probs_T05 = softmax_with_temperature(logits, T=0.5) # [0.999, 0.001, 0.000] 更尖锐

6

Softmax 与其他激活函数的对比

激活函数

输出范围

主要用途

特点

Softmax

(0,1),和为1

多分类输出层

输出可解释为概率

Sigmoid

(0,1)

二分类输出层

每个输出独立,可多标签

Tanh

(-1,1)

隐藏层

零中心,适合RNN

ReLU

[0,∞)

隐藏层

计算简单,缓解梯度消失

关键区别:

  • Softmax 是 多个输出相互依赖 的(因为和为1)
  • Sigmoid 是 每个输出独立 的,适合多标签分类(一张图同时有猫和狗)

7

一个完整的例子

代码语言:javascript
复制
import torch
import torch.nn as nn

# 一个简单的分类模型
class SimpleClassifier(nn.Module):
    def __init__(self, input_size=784, num_classes=10):
        super().__init__()
        self.fc1 = nn.Linear(input_size, 256)
        self.fc2 = nn.Linear(256, 128)
        self.fc3 = nn.Linear(128, num_classes)  # 输出层,没有激活函数
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.relu(self.fc2(x))
        x = self.fc3(x)  # logits,没有softmax
        return x

# 训练
model = SimpleClassifier()
criterion = nn.CrossEntropyLoss()  # 内部包含softmax
optimizer = torch.optim.Adam(model.parameters())

# 前向传播
logits = model(images)  # 得到 logits
loss = criterion(logits, labels)  # 直接计算损失

# 推理
model.eval()
with torch.no_grad():
    logits = model(image)
    probs = torch.softmax(logits, dim=1)  # 需要概率时加softmax
    pred = torch.argmax(logits, dim=1)    # 只需要类别时直接取最大值
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 具身小站 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档