离散概率空间 vs 线性空间
概率必须非负、总和为 1——这不是线性空间。但 softmax 之前的 logit 空间是自由的。从黑白球实验中看到从"三角形"到"全平面"的跨越。
实验设计
设样本空间为 10 次放回取样。两组实验:
| 组别 | 颜色 | 可能结果 | 概率分布 |
|---|---|---|---|
| A | 黑白 | $$\{黑, 白\}$$ | $$p_{黑} + p_{白} = 1$$ |
| B | 黑白灰 | $$\{黑, 白, 灰\}$$ | $$p_{黑} + p_{白} + p_{灰} = 1$$ |
10 次放回后,各组得到一个频率向量:
A 组: (黑=6, 白=4) → 经验概率 p = (0.6, 0.4)
B 组: (黑=6, 白=3, 灰=1) → 经验概率 p = (0.6, 0.3, 0.1)
这个向量
$$\mathbf{p}$$生活在概率单纯形上。
单纯形不是线性空间
A 组(二分类)
二分类的概率分布只有一个自由度:
$$p_{黑} = p, \quad p_{白} = 1-p, \quad 0 \leq p \leq 1$$这个空间是实数轴上的一个线段:
p=0: ○白 p=0.5: ●──○ p=1: ●黑
[0, 1] 区间,两端封闭
线性空间要求:任意线性组合还在空间内。但这里:
- $$p = 0.5$$ 在空间中(黑白各半)
- $$p = -0.5$$ 不在空间中(概率不能为负)
- $$p = 1.5$$ 不在空间中(概率不能大于 1)
所以概率单纯形 不是 线性空间——它是有界闭凸集。
B 组(三分类)
三分类的概率分布在二维平面上是一个三角形(2-单纯形):
白
● (0,1,0)
/ \
/ \
/ \
/ \
(1,0,0)●─────────●(0,0,1)
黑 灰
三点分别对应三组极端情况。内部任意一点对应一个有效概率分布。但这个空间仍然被边界封锁——你不能有负概率,也不能让总和超过 1。
Softmax:从三角形到全平面
Softmax 的参数是 logits
$$\mathbf{z} \in \mathbb{R}^k$$,没有任何约束:
z = (z_黑, z_白) A 组: z ∈ ℝ²,完全自由
z = (z_黑, z_白, z_灰) B 组: z ∈ ℝ³,完全自由
通过 softmax:
$$p_i = \frac{e^{z_i}}{\sum_j e^{z_j}}$$| z 空间 | p 空间 | |
|---|---|---|
| 约束 | 无 | $$p_i \geq 0, \sum p_i = 1$$ |
| 范围 | $$z_i \in (-\infty, +\infty)$$ | $$p_i \in [0, 1]$$ |
| 线性? | 是 | 否 |
| 加法封闭 | ✅ $$z_1 + z_2 \in \mathbb{R}$$ | ❌ $$p_1 + p_2$$ 无意义 |
| 数乘封闭 | ✅ $$2z \in \mathbb{R}$$ | ❌ $$2p$$ 不再归一化 |
Softmax 把一个无约束的线性空间映射到了有约束的单纯形上。

图2 A 组(二分类)的概率空间是一条线段 [0,1],而 logit 空间是整个实数轴:

图3 B 组(三分类)的概率空间是一个三角形(2-单纯形),内部每个点对应一个有效概率分布:

图4 同一组 logits 在 ℝ³ 里自由行走,softmax 把它们映射到概率空间——一条自由的路径被限制在了三角形内:

图5 对数变换(log)将概率空间均匀铺满的网格映射到整个平面:

点彩实验:概率密度如何在 logit 空间展开
取 6:3:1 的三色球(黑:白:灰),每次 10 次放回取样,重复 5000 组。每一组计算经验概率
$$\mathbf{p}$$,然后取 log 得到 logits
$$\mathbf{z}$$。把
$$\mathbf{p}$$画在三角形上,
$$\mathbf{z}$$画在平面上——空间变了,点的密度也跟着变了。


关键观察:
- 概率空间(左):点被锁在三角形里。靠近真实分布
(0.6, 0.3, 0.1)的地方点最密——那是采样回落到真值的区域。 - Logit 空间(右):点散布在整个平面上。三角形中心的密集区域映射到了平面上的某一团,而三角形边缘(概率接近 0 或 1 的点)映射到了很远的地方——log 把靠近边界的点推到了平面上很远的位置。
这张点彩图回答了上面 “负 logits 是否只是输入合法性” 的问题——不只是合法性。logits 的负值对应了概率 ≤ 0.5 的情形(相对其他类证据较弱),正值对应概率 > 0.5。真正的概率密度团簇在 logit 空间里变成了椭圆状的云,而三角形边缘的稀疏地带变成了平面的散落尘埃。
这就是 softmax 的"等距映射"——三角形上的均匀网格被映射到对数空间后,网格在远处变得稀疏,在中心变得密集。这不是线性变换,而是一个"从有界到无界"的拓扑变换。
为什么 logit 点不是遍布全平面?
这个问题很有价值——也是点彩图能揭示的最关键的 insight。
每次只有 10 次放回取样,这意味着经验概率是量化的:(黑, 白, 灰) 的计数是 0 到 10 的整数,且总和必须等于 10。三个数满足这个约束有多少种?
实际 5000 次试验只命中了其中 44 种组合。log(p) 把这 44 种离散组合映射到平面上 44 个点——所以点看起来聚在几个团里。
提高每组次数会发生什么?

10 次和 50 次时,概率是粗量化的——logit 点被限制在有限的格子上。到 500 次时,概率几乎是连续的,logit 点开始覆盖整个区域。但注意:所有点仍然围绕真实分布 (6:3:1) 形成的等高线,因为采样源自同一个真实分布。
要想 logit 点真正覆盖整个 ℝ² 平面,需要变化真实分布本身。当一个神经网络在训练时,参数的每次更新都在改变 logits——logit 空间确实可以收敛到任何位置。点彩图展示的是采样分布,不是空间的界限。
可视化:logits 的自由度
A 组(二分类)实际上自由度是 1——softmax 对 logits 平移不敏感:
$$\text{softmax}(z_1 + c, z_2 + c) = \text{softmax}(z_1, z_2)$$所以有效自由度 = k − 1。但关键是:这 k−1 个自由度取任意实数值,不需要在 [0, 1] 内。
| 概率 p | Logit z | |
|---|---|---|
| A 组(2 色) | 线段 [0,1] | ℝ¹ 全线 |
| B 组(3 色) | 三角形内部 | ℝ² 全平面 |
| 允许负值? | ❌ | ✅ |
| 允许 >1? | ❌ | ✅ |
代码验证
import torch
import torch.nn.functional as F
# === A 组:黑白球,10 次放回 ===
print("=== A组 黑白二分类 ===")
counts_a = torch.tensor([6, 4], dtype=torch.float32)
p_a = counts_a / counts_a.sum()
print(f"概率 p: {p_a}")
# 从概率计算 logits(加 log,再中心化)
logits_a = torch.log(p_a)
print(f"logits z: {logits_a}")
print(f"softmax(z): {F.softmax(logits_a, dim=-1)}")
# 验证:logits 可以取任意值,softmax 仍然有效
for val in [-5, -2, 0, 2, 5]:
z_test = torch.tensor([val, 0.0])
p_test = F.softmax(z_test, dim=-1)
print(f" z=({val:3d}, 0) → p=({p_test[0]:.4f}, {p_test[1]:.4f})")
# 验证:概率空间有限制,logit 空间无限制
# p 必须满足 p∈[0,1], 但 z 可以是任何数
print(f"\n概率 p 的取值范围: [0, 1]")
print(f"logits z 的取值范围: (-∞, +∞) ← 线性空间")
# === B 组:黑白灰球,10 次放回 ===
print("\n=== B组 黑白灰三分类 ===")
counts_b = torch.tensor([6, 3, 1], dtype=torch.float32)
p_b = counts_b / counts_b.sum()
print(f"概率 p: {p_b}, 总和={p_b.sum().item()}")
logits_b = torch.log(p_b)
print(f"logits z: {logits_b}")
print(f"softmax(z): {F.softmax(logits_b, dim=-1)}")
# 验证:概率只能走三角形内部,logits 可以走全平面
print("\n概率空间的移动(沿边界):")
p_moves = [
(0.8, 0.15, 0.05),
(0.5, 0.4, 0.1),
(0.3, 0.3, 0.4),
]
for p in p_moves:
p_t = torch.tensor(p)
z_t = torch.log(p_t)
print(f" p=({p[0]:.1f},{p[1]:.1f},{p[2]:.1f}) ← z=({z_t[0]:.1f},{z_t[1]:.1f},{z_t[2]:.1f})")
print("\nLogits 空间的自由行走(允许负数、允许任意值):")
z_moves = [
(5.0, 0.0, -2.0),
(-1.0, 3.0, 0.5),
(0.0, 0.0, 0.0),
]
for z in z_moves:
z_t = torch.tensor(z)
p_t = F.softmax(z_t, dim=-1)
print(f" z=({z[0]:.1f},{z[1]:.1f},{z[2]:.1f}) → p=({p_t[0]:.3f},{p_t[1]:.3f},{p_t[2]:.3f})")
输出:
=== A组 黑白二分类 ===
概率 p: tensor([0.6000, 0.4000])
logits z: tensor([-0.5108, -0.9163])
softmax(z): tensor([0.6000, 0.4000])
# logits 可以取任意值,softmax 仍然有效
z=( -5, 0) → p=(0.0067, 0.9933)
z=( -2, 0) → p=(0.1192, 0.8808)
z=( 0, 0) → p=(0.5000, 0.5000)
z=( 2, 0) → p=(0.8808, 0.1192)
z=( 5, 0) → p=(0.9933, 0.0067)
概率 p 的取值范围: [0, 1]
logits z 的取值范围: (-∞, +∞) ← 线性空间
=== B组 黑白灰三分类 ===
概率 p: tensor([0.6000, 0.3000, 0.1000]), 总和=1.0
logits z: tensor([-0.5108, -1.2040, -2.3026])
softmax(z): tensor([0.6000, 0.3000, 0.1000])
Logits 空间的自由行走:
z=(5.0, 0.0, -2.0) → p=(0.993, 0.007, 0.001)
z=(-1.0, 3.0, 0.5) → p=(0.014, 0.776, 0.210)
z=(0.0, 0.0, 0.0) → p=(0.333, 0.333, 0.333)
频率 = 概率:FFT 的谱视角
在中文里,“频率"既指信号振动的快慢(frequency),也指事件发生的多少(frequency of occurrence)。这不是语言的巧合——这两个"频率"共享同一个数学结构:傅里叶变换。
把三色球的概率向量
$$p = [0.6, 0.3, 0.1]$$直接做 FFT:
import numpy as np
p = np.array([0.6, 0.3, 0.1])
F = np.fft.fft(p) # 概率 → 频谱
p_recovered = np.fft.ifft(F).real # 频谱 → 概率
表4 偏斜分布 p=[0.6,0.3,0.1] 的 FFT:
| 频率分量 | 值 | 含义 |
|---|---|---|
| F[0] = 1.0 | DC 分量 | 总概率 = 1,守恒量 |
| F[1] = 0.40 − 0.17j | 基频 | 分布不均匀的证据 |
| F[2] = 0.40 + 0.17j | 倍频 | F[1] 的共轭,保证实数性 |
表5 均匀分布 p=[1/3,1/3,1/3] 的 FFT:
| 频率分量 | 值 | 含义 |
|---|---|---|
| F[0] = 1.0 | DC 分量 | 总概率 = 1 |
| F[1] = 0 | 基频 | 零能量,均匀分布无结构 |
| F[2] = 0 | 倍频 | 零能量 |
当概率分布完全均匀时,所有高频分量为零——和信号分析完全一样:白噪声没有结构,均匀分布也没有结构。概率分布的"偏斜"程度编码在非零频率分量的幅度里。
统一的谱视图
FFT/IFT
概率质量函数 ◄──────────────────► 频谱(特征函数)
p(x) φ(ω)
┌───┐ ┌───┐
│0.6│ 黑 │DC │ = 总概率
│0.3│ 白 ─┤ ├─ 高频 = 结构信息
│0.1│ 灰 ─┤ ├─ 共轭 = 实数约束
└───┘ └───┘
▲ ▲
│ softmax(z) │ 所有信息可逆
│ ←→ log(p) │ 完全恢复
▼ ▼
Logit 空间 复频域
z ∈ ℝᵏ F ∈ ℂᵏ
概率空间里的"概率之和为 1"在频域里变成了 “DC = 1”。概率空间的"非负性约束"在频域里变成了"共轭对称性”。两者等效——只是换了一个观测角度。
信号处理中的一句老话适用这里:没有一个域比另一个更真实——它们只是同一个测度的不同基底。
时域与频域:不可同时精确,但可以同时学习
留一个问题给读者思考。
看这两句中文:
“我的确累了” “我的的确确累了”
“的确"在第一句出现了一次,在第二句出现了两次。频率变了——softmax 能抓到"的确"的频率翻倍,生成梯度去学习。
但词的"邻接"呢?“的的确确"里的 AABB 叠词模式(的→的确→确),频率域看不到。你把 [我的确累了] 按词袋打散——得到 {我,的确,累,了} 各 0.25,和原文的顺序毫无关系。
这就是频率域的盲区:词序信息全部丢失。
信号处理里用短时傅里叶变换解决——窗口滑动,每帧独立做 FFT,时域和频域同时保留:
信号: sin(2πt) + sin(5πt) + sin(3πt)
↓
┌──────────────────────────┐
│ STFT: 帧帧 FFT │
│ 窗口1: 低频强 │
│ 窗口2: 高频强 │ → 时变频谱图
│ 窗口3: 中频强 │
└──────────────────────────┘
NLP 里的对应物就是 Attention:
序列: "我的的确确累了"
↓
┌──────────────────────────┐
│ Self-Attention │
│ t=0 "我": 关注"的确" │
│ t=1 "的": 关注"的确" │
│ t=2 "的确": 关注"的确"+"确" │ → token-token 权重矩阵
│ t=3 "确": 关注"的确"+"累" │ 每个时间步看到不同的频率分布
│ t=4 "累": 关注"了" │
└──────────────────────────┘
每一次 Attention 计算
$$QK^T$$,本质上是在当前时间点上重新做傅里叶风格的谱分解:哪些 token 的信号强(相似度大),哪些弱。这个分解在每个时间步是不同的——所以 Transformer 既保留了"哪个词经常出现”(频域),也保留了"谁挨着谁、谁关注谁”(时域)。
三个域的对应
| 信号处理 | 概率/ML | 解决的问题 |
|---|---|---|
| 时域 $$f(t)$$ | 词序列 “我-的确-累了” | 谁挨着谁 |
| 频域 $$F(\omega)$$ | 词袋概率 softmax(p) | 哪个词重要 |
| 时频域 STFT | Transformer Attention | 同时拥有两者 |
这就是 WMT 翻译模型能从词袋进化到 Attention/Transformer 的原因——频率给出了"这是什么",序列给出了"它怎么排列的"。两者交汇的地方,就是理解。
结论
| 概念 | 数学空间 | 特性 | 不是线性空间的原因 |
|---|---|---|---|
| 概率 $$\mathbf{p}$$ | k-维单纯形 | $$\sum p_i = 1, p_i \geq 0$$ | 有界、封闭、凸组合不保持 |
| Logits $$\mathbf{z}$$ | $$\mathbb{R}^k$$ | $$z_i \in (-\infty, \infty)$$ | ✅ 无约束,线性封闭 |
| Softmax | $$\mathbb{R}^k \to \Delta^k$$ | 前向:exp + 归一化,收束为有效概率 | — |
| log | $$\Delta^k \to \mathbb{R}^k$$(带常数模糊) | p ↦ z − log(Σe^z),还原到平移等价类 | ✅ |
Softmax 做的事:把一个无约束的欧几里得空间(线性空间)映射到了有约束的概率单纯形上。 反过来,log 把概率拉回线性空间。
这就是分类任务能用梯度下降的根本原因——模型在 logit 空间(线性)里做参数更新,softmax 保证更新后的 logits 总能变成有效的概率分布。如果你直接在概率空间里做梯度下降,你会撞墙:概率不能为负、不能大于 1、必须保持总和为 1——三个约束锁死了优化。
回到 WMT:翻译模型在 56K 维的 logit 空间里自由行走(梯度可以大胆地更新任何 logit),softmax 把每一步更新映射到 56K 维的概率单纯形上。K_lang 限制 softmax 分母相当于缩小了单纯形的有效维度——从 56652 维缩到 170 维。
May the Code be with us.
License: GPLv3
本文《Watermelon》系列采用 GNU 通用公共许可证第三版 (GNU General Public License v3.0) 协议进行开源发布与分发。