09aaab-Softmax是什么?
09aaab-Softmax是什么?🔥
本文档详细解释 Softmax 函数的核心概念,涵盖数学定义与逐元素拆解、手算示例、三大核心性质(保序性、平移不变性、非缩放不变性)、数值稳定技巧 的原理证明、与 Sigmoid 的对比,以及在 Transformer 注意力机制中的关键作用 🛠️
章节阅读路线图 🗺️
- 什么是Softmax → 从直观类比出发,先了解 Softmax 是什么,再给出严谨数学定义
- 核心公式 → 掌握公式后,逐元素拆解 和分母的作用
- 手算示例 → 通过具体数值验证公式理解
- 核心性质 → 深入理解保序性、平移不变性和非缩放不变性
- 数值稳定性 → 学习数值溢出问题及 技巧的数学原理
- 代码示例 → 通过 NumPy 和 PyTorch 代码实战加深理解
- 总结 → 回顾核心要点
1. 什么是 Softmax?🤔
本章从直观类比出发,介绍 Softmax 的基本概念和定义
1.1 直观类比:投票计数器 🗳️
想象一个班级评选"最受欢迎的同学",每个同学都给其他人打分(分数可以是任意实数,正数表示喜欢,负数表示讨厌)。但最终我们需要的是得票百分比——每个人的支持率加起来等于 100%。
Softmax 函数就像一个"投票计数器":
- 输入:任意实数分数(可正可负,可大可小)→ 就像同学们的"支持度打分"
- 输出:
[0, 1]区间的概率值,且总和为 1 → 就像最终的"得票百分比"
更重要的是,Softmax 不是简单地按比例缩放——它通过指数函数 放大差异,让高分者获得更高的权重,低分者被进一步压制。
1.2 基本定义
Softmax 函数(又称 softargmax、归一化指数函数)是一个将任意实数向量转换为概率分布的函数。给定一个 维实数向量 ,Softmax 对每个元素 的输出为:
其中 是自然对数的底数。
输出满足两个条件(概率分布的定义):
- 每个输出值在 区间内:
- 所有输出值之和恰好为 1:
参考资料:
- Softmax function -- Wikipedia ⭐值得阅读
- Softmax Function Definition -- DeepAI
- The Softmax Function, Simplified -- Medium
- Softmax函数 -- 维基百科
2. 核心公式 📝
本章逐元素拆解 Softmax 公式,解释每一步的含义
Softmax 的计算分为两步:
第1步:指数化 → 对每个输入 计算
第2步:归一化 → 将每个指数值除以所有指数值之和
用数学语言表达:
2.1 为什么要用指数函数 ?
指数函数在 Softmax 中承担了三个关键角色:
- 将任意实数映射为正数: 对所有 成立,保证输出为正
- 放大差异:指数函数的增长速度极快, 而 ,即使输入只差 2,输出已差约 7 倍——让高分者脱颖而出
- 保持单调性: 是严格递增的,,即输入顺序得以保留
2.2 为什么分母要用求和?
分母 的作用是归一化——把所有指数值加起来作为"总基数",然后用每个指数值除以总基数。这样做的结果是:
- 每个输出都变成了相对占比(0 到 1 之间)
- 所有输出加起来恰好等于 1
- 形成了合法的概率分布
3. 手算示例 🔍
本章通过一个具体数值演示 Softmax 的计算全过程
假设输入向量 ,我们来一步步计算 Softmax:
第1步:计算
第2步:计算分母(所有指数值之和)
第3步:计算每个 Softmax 值
验证: ✅
观察:
- 输入最高的 2.0 获得了 65.9% 的概率权重
- 输入最低的 0.1 只获得了 9.9% 的权重
- 输入之间的原始差距是 ,但 Softmax 输出的权重差距是
4. 核心性质 📐
本章介绍 Softmax 的三大数学性质:保序性、平移不变性和非缩放不变性
4.1 保序性(Order Preservation)
定义:Softmax 保持输入的顺序不变。如果 ,则 。
直观理解:打分最高的同学,最终得票率也最高。Softmax 不会"颠覆"排名。
数学原因:指数函数 是严格单调递增的,且除以同一个正分母不改变大小关系。
4.2 平移不变性(Translation Invariance)
定义:对输入向量的所有元素同时加上同一个常数 ,Softmax 的输出不变。
直观理解:假设所有同学的分数都加了 10 分(平移),但每个人加的一样多,那么最终得票百分比不变。
实际意义:这个性质是数值稳定性技巧的理论基础——我们可以安全地减去 来防止数值溢出,而不改变结果。
4.3 非缩放不变性(Non-Scaling Invariance)
定义:对输入向量的所有元素同时乘以一个正数 (),Softmax 的输出会改变。
直观理解:当 时,所有分数被"拉大",高分的优势被指数函数进一步放大,输出分布更"尖锐"(更集中在最大值);当 时,分数被"压缩",输出分布更"平滑"(更均匀)。
在注意力机制中的体现:缩放因子 正是利用了这一点——通过缩小点积分数,防止 Softmax 输出过于尖锐(进入梯度很小的饱和区)。
参考资料:
- Softmax Preserves Order, Is Translation Invariant But Not Scaling Invariant -- Omniverse ⭐值得阅读
- On the Properties of the Softmax Function with Application in Game Theory -- arXiv
- The softmax function: Properties, motivation, and interpretation -- Stanford ALPS Lab
5. 数值稳定性 ⚠️
本章解释 Softmax 的数值溢出问题及 技巧的数学原理
5.1 问题:直接计算可能产生 NaN
考虑输入 ,直接按公式计算:
这会导致 ,计算失败。
5.2 解决方案:减去最大值
利用平移不变性,从每个元素中减去最大值 :
5.3 数学证明
令 (即 ),则:
5.4 为什么这样就稳定了?
- 减去最大值后,所有指数输入 ,因此
- 最大值对应的项 ,保证分母
- 不会出现 的溢出
- 分母 也防止了除以零
参考资料:
- Numerically Stable Softmax and Cross Entropy -- Jay Mody ⭐值得阅读
- Numerically stable softmax -- Stack Overflow
- You Don't Really Know Softmax -- Sewade Ogun ⭐值得阅读
- Numerically Stable Softmax -- Brian Lester
6. 代码示例 💻
本章提供 NumPy 手动实现和 PyTorch 原生实现的对比
6.1 NumPy 手动实现(含数值稳定版)
import numpy as np # 导入 NumPy,用于数组运算
"""Softmax 函数的朴素实现(不推荐,数值不稳定)
参数:
x: 输入向量,形状 (K,),元素为任意实数
返回:
概率分布向量,形状 (K,),元素 ∈ (0,1),和为 1
示例:
softmax_naive(np.array([2.0, 1.0, 0.1])) → [0.659, 0.242, 0.099]
"""
def softmax_naive(x):
# 直接计算 e^x / sum(e^x),数据流动:[2.0,1.0,0.1] → [0.659,0.242,0.099]
exp_x = np.exp(x) # 计算每个元素的指数,示例:e^2.0=7.389
return exp_x / np.sum(exp_x) # 归一化,数据流动:[7.389,2.718,1.105] → [0.659,0.242,0.099]
"""Softmax 函数的数值稳定实现(推荐)
参数:
x: 输入向量,形状 (K,),元素为任意实数
返回:
概率分布向量,形状 (K,),元素 ∈ (0,1),和为 1
示例:
softmax(np.array([1000, 2000, -4000])) → [0., 1., 0.]
"""
def softmax(x):
# 减去最大值防止溢出,数据流动:[1000,2000,-4000] - 2000 → [-1000,0,-6000]
x_shifted = x - np.max(x) # 利用平移不变性,结果不变但数值稳定
exp_x = np.exp(x_shifted) # 指数化,所有值 ≤ 1,不会溢出
return exp_x / np.sum(exp_x) # 归一化,分母 ≥ 1,不出现除零
# ========== 测试 ==========
# 普通输入,示例:三个分数 [2.0, 1.0, 0.1]
x_small = np.array([2.0, 1.0, 0.1])
print("普通输入:", softmax(x_small)) # 输出:[0.65900114 0.24243297 0.09856589]
print("和:", np.sum(softmax(x_small))) # 输出:1.0
# 大数值输入,朴素版会溢出,示例:[1000, 2000, -4000]
x_large = np.array([1000.0, 2000.0, -4000.0])
print("大数值输入(稳定版):", softmax(x_large)) # 输出:[0. 1. 0.]
print("和:", np.sum(softmax(x_large))) # 输出:1.0
6.2 PyTorch 原生实现
import torch # 导入 PyTorch 核心库
import torch.nn as nn # 导入神经网络模块
# 方式1:使用 torch.softmax(函数式 API)
x = torch.tensor([2.0, 1.0, 0.1]) # 创建输入张量,示例:三个分数 [2.0, 1.0, 0.1]
output = torch.softmax(x, dim=0) # dim=0 沿第0维做 Softmax,数据流动:[2.0,1.0,0.1] → [0.659,0.242,0.099]
print("torch.softmax 输出:", output) # 输出:tensor([0.6590, 0.2424, 0.0986])
print("和:", output.sum()) # 输出:tensor(1.0000)
# 方式2:使用 nn.Softmax(模块化 API)
softmax_layer = nn.Softmax(dim=0) # 创建 Softmax 层,dim=0 沿第0维计算
output2 = softmax_layer(x) # 前向传播,输出同上
print("nn.Softmax 输出:", output2)
# 二维输入示例(batch处理),形状 [batch_size=2, num_classes=3]
x_batch = torch.randn(2, 3) # 随机生成 2 个样本,每个有 3 个类别的 logits
output_batch = torch.softmax(x_batch, dim=1) # dim=1 沿类别维度做 Softmax
print("每行和:", output_batch.sum(dim=1)) # 输出:tensor([1.0000, 1.0000])
6.3 PyTorch 内置的数值稳定处理
PyTorch 的 torch.softmax 和 F.softmax 内部已经实现了 的数值稳定技巧,开发者无需手动处理。此外,PyTorch 还提供了 F.log_softmax,它在计算 时使用更稳定的 技巧,避免了 的问题,推荐与 NLLLoss 配合使用。
import torch.nn.functional as F # 导入函数式 API
x = torch.tensor([2.0, 1.0, 0.1]) # 创建输入张量
log_probs = F.log_softmax(x, dim=0) # 计算 log_softmax,内部已做数值稳定处理
print("log_softmax:", log_probs) # 输出:tensor([-0.4170, -1.4170, -2.3170])
print("exp(log_softmax):", torch.exp(log_probs)) # 还原为 Softmax,验证一致性
参考资料:
- Softmax -- PyTorch 官方文档 ⭐值得阅读
- torch.nn.functional.softmax -- PyTorch
- 以softmax与交叉熵的实例解释numpy的部分用法 -- 知乎
- Python实现Softmax函数 -- 百度智能云
7. 总结 📝
| 要点 | 说明 |
|---|---|
| 定义 | ,将任意实数向量转为概率分布 |
| 输出 | 每个值在 ,全部之和为 |
| 保序性 | |
| 平移不变性 | 所有元素加同一常数,输出不变 → 数值稳定技巧的数学基础 |
| 非缩放不变性 | 所有元素乘同一系数(),输出改变 → 注意力缩放因子的理论依据 |
| 数值稳定 | 计算前先减去 ,利用平移不变性,防止 |
| 在注意力中 | 将 分数转为概率权重,放大差异实现"聚焦",确保加权求和的数学合理性 |
🔴 关键理解:
- Softmax 的本质是"指数化 + 归一化",将原始分数转化为合法概率分布
- 数值稳定技巧 不是 trick,而是平移不变性的直接推论
- 在 Transformer 中,Softmax 是注意力"聚焦"能力的数学核心——没有它,模型无法区分"该关注谁"
最后更新时间:2026-05-26