概率与分布 本节摘要:概率是 AI 表达不确定性的语言。一个分类器输出 ,一个语言模型从 5 万个候选里挑下一个词,一个扩散模型从学到的分布里采样生成图像——全是概率在运作。模型的每一次预测都是一个概率分布,每一个损失函数都在度量「预测分布离真实分布有多远」,每一次训练都在调参让一个分布更像另一个。本节从概率的三大公理出发,讲清样本空间、事件、条件概率与独立性;区分离散型的概率质量函数(PMF)与连续型的概率密度函数(PDF);逐一实现伯努利、类别、均匀、正态、泊松五大分布;推导期望与方差;用中心极限定理解释为何正态分布无处不在;讲清对数概率为何能避免下溢、softmax 如何把原始分数(logits)变成合法分布,以及带「减最大值」数值稳定技巧的
本节摘要:概率是 AI 表达不确定性的语言。一个分类器输出
[0.03, 0.91, 0.06],一个语言模型从 5 万个候选里挑下一个词,一个扩散模型从学到的分布里采样生成图像——全是概率在运作。模型的每一次预测都是一个概率分布,每一个损失函数都在度量「预测分布离真实分布有多远」,每一次训练都在调参让一个分布更像另一个。本节从概率的三大公理出发,讲清样本空间、事件、条件概率与独立性;区分离散型的概率质量函数(PMF)与连续型的概率密度函数(PDF);逐一实现伯努利、类别、均匀、正态、泊松五大分布;推导期望与方差;用中心极限定理解释为何正态分布无处不在;讲清对数概率为何能避免下溢、softmax 如何把原始分数(logits)变成合法分布,以及带「减最大值」数值稳定技巧的 log-softmax;最后把交叉熵损失与负对数似然联系起来——它是几乎一切分类训练的目标。
对应原课程:Phase 01 · Lesson 06 ·
probability-and-distributions(原英文phases/01-math-foundations/06-probability-and-distributions/docs/en.md)。前置:第 1~4 节。
阅读完本节,你应当能够:
一个分类器输出 [0.03, 0.91, 0.06];一个语言模型从 5 万个候选词里选下一个;一个扩散模型从学到的分布采样生成图像——这都是概率在起作用。
模型的每个预测都是概率分布,每个损失都在度量预测分布与真实分布的距离,每步训练都在调参让一个分布更像另一个。不懂概率,你读不了一篇 ML 论文、调不了一个模型,也理解不了为什么训练损失会变 NaN。
样本空间 S 是所有可能结果的集合。事件是样本空间的子集。概率把事件映射到 [0,1] 区间。
掷硬币:S = {H, T},P(H)=0.5, P(T)=0.5 掷骰子:S = {1,2,3,4,5,6},P(偶数) = P({2,4,6}) = 3/6 = 0.5
三大公理定义了全部概率:
P(A) ≥ 0;P(S) = 1(总有某事发生);P(A 或 B) = P(A) + P(B)。其余一切(贝叶斯定理、期望、分布)都从这三条推出。
P(A|B) 是「已知 B 发生时 A 发生」的概率:
P(A|B) = P(A 且 B) / P(B) 例:扑克牌 P(国王 | 人头牌) = P(国王 且 人头牌) / P(人头牌) = (4/52) / (12/52) = 4/12 = 1/3
两事件独立:知道一个对另一个毫无信息。
独立: P(A|B) = P(A) 等价于: P(A 且 B) = P(A) · P(B)
掷硬币独立;不放回抽牌不独立。
离散随机变量有概率质量函数(PMF),每个结果有可直接读出的概率,所有概率之和为 1。
连续随机变量有概率密度函数(PDF),单点密度不是概率——概率来自对密度在区间上积分。f(x) 可以大于 1(密度非概率),∫f(x)dx = 1。
这一区别对 ML 重要:分类输出是 PMF(离散选择),VAE 隐空间用 PDF(连续)。
伯努利(Bernoulli):一次试验、两种结果。建模二分类。
P(X=1)=p, P(X=0)=1−p, 均值=p, 方差=p(1−p)
类别(Categorical):一次试验、k 种结果。建模多分类(softmax 输出)。
P(X=i)=pᵢ, Σpᵢ=1
均匀(Uniform):所有结果等概率。用于随机初始化。
正态/高斯(Normal/Gaussian):钟形曲线,参数为均值 μ、方差 σ²。
f(x) = (1/√(2πσ²)) · exp(−(x−μ)² / (2σ²)) 标准正态 μ=0,σ=1: 68% 数据在 1σ 内,95% 在 2σ 内,99.7% 在 3σ 内
泊松(Poisson):固定区间内稀有事件计数。
P(X=k) = (λᵏ · e⁻λ) / k!, 均值=λ, 方差=λ
期望是加权平均:
离散:E[X] = Σ xᵢ · P(X=xᵢ) 连续:E[X] = ∫ x · f(x) dx
方差度量围绕均值的散布:
Var(X) = E[(X − E[X])²] = E[X²] − (E[X])² 标准差 = √Var(X)
在 ML 里,期望以损失函数(数据分布上的平均损失)的形式出现;方差告诉你模型稳定性——梯度方差高意味着训练噪声大。
联合分布 P(X,Y) 描述两个随机变量一起的分布。边际分布把另一个变量「求和消掉」:P(X=x) = Σ_y P(X=x, Y=y)。
| Y=0(不带伞) | Y=1(带伞) | 边际 P(X) | |
|---|---|---|---|
| X=0(晴) | 0.40 | 0.10 | 0.50 |
| X=1(雨) | 0.05 | 0.45 | 0.50 |
| 边际 P(Y) | 0.45 | 0.55 | 1.00 |
中心极限定理(CLT):许多独立随机变量的和(或均值),无论原始分布如何,都收敛到正态分布。
掷 1 颗骰子: 均匀(平) 2 颗骰子的均值: 三角(尖) 30 颗骰子的均值:近完美钟形
由此:测量误差近似正态(许多独立小源叠加);神经网络权重用正态初始化;SGD 梯度噪声近似正态(许多样本梯度求和);正态是「给定均值与方差时熵最大的分布」。
原始概率有数值问题。许多小概率相乘迅速下溢为零:
P(句子) = P(w₁)·P(w₂)·…·P(wₙ) = 0.01·0.003·0.02·… → 0(约 30 项后下溢)
对数概率修复之:乘变加。
log P(句子) = log P(w₁) + log P(w₂) + … + log P(wₙ) = −4.6 + −5.8 + −3.9 + … → 有限
规则:log(a·b) = log(a) + log(b);对数概率恒 ≤ 0(因 0 < P ≤ 1);越负越不可能;交叉熵损失就是正确类的负对数概率。
神经网络输出原始分数(logits),softmax 把它转成合法概率分布:
softmax(zᵢ) = exp(zᵢ) / Σⱼ exp(zⱼ) 性质:所有输出 ∈ (0,1);输出之和为 1;保持输入相对序;exp() 放大 logit 间差异。
Softmax 技巧:指数化前减去最大 logit,防止溢出。
z = [100, 101, 102],exp(102) 溢出 z_shifted = z − max(z) = [−2, −1, 0],exp(0)=1(安全) 结果相同,无溢出。
Log-softmax 把 softmax 与 log 合一以保数值稳定,PyTorch 交叉熵损失内部就用它。
采样即按分布抽取随机值。ML 里:Dropout 随机采样要置零的神经元;数据增强采样随机变换;语言模型从预测分布采样下一个 token;扩散模型采样噪声并逐步去噪。从任意分布采样需要逆变换采样、拒绝采样或重参数化技巧(VAE 用)等技术。
完整源码见 phases/01-math-foundations/06-probability-and-distributions/code/probability.py。
def bernoulli_pmf(k, p): return p if k == 1 else (1 - p) def categorical_pmf(k, probs): return probs[k] def poisson_pmf(k, lam): return (lam ** k) * math.exp(-lam) / factorial(k) def uniform_pdf(x, a, b): return 1.0 / (b - a) if a <= x <= b else 0.0 def normal_pdf(x, mu, sigma): coeff = 1.0 / (sigma * math.sqrt(2 * math.pi)) return coeff * math.exp(-0.5 * ((x - mu) / sigma) ** 2)
def expected_value(values, probs): return sum(v * p for v, p in zip(values, probs)) def variance(values, probs): mu = expected_value(values, probs) return sum(p * (v - mu) ** 2 for v, p in zip(values, probs))
def sample_categorical(probs, n=1): cumulative = []; total = 0 for p in probs: # 累积分布 total += p; cumulative.append(total) samples = [] for _ in range(n): r = random.random() for i, c in enumerate(cumulative): if r <= c: samples.append(i); break return samples def sample_normal_box_muller(mu, sigma, n=1): # 两个均匀 → 一个正态 z = math.sqrt(-2 * math.log(random.random())) * math.cos(2*math.pi*random.random()) return mu + sigma * z
def softmax(logits): m = max(logits) # ← 关键:减最大值防溢出 exps = [math.exp(z - m) for z in logits] total = sum(exps) return [e / total for e in exps] def log_softmax(logits): m = max(logits) log_sum_exp = m + math.log(sum(math.exp(z - m) for z in logits)) return [z - log_sum_exp for z in logits] def cross_entropy_loss(logits, target_index): return -log_softmax(logits)[target_index] # = 负对数似然
def demonstrate_clt(dist_fn, n_samples, n_averages): averages = [] for _ in range(n_averages): samples = [dist_fn() for _ in range(n_samples)] averages.append(sum(samples) / len(samples)) return averages # 不论 dist_fn 是什么,averages 都趋于正态
设计要点:
softmax减最大值、cross_entropy用log_softmax而非log(softmax(...))——这两个细节是把教科书公式变成生产代码的关键(见第 13 节数值稳定性)。
NumPy 与 SciPy 把上述全部压成一行:
import numpy as np from scipy import stats from scipy.special import softmax, log_softmax normal = stats.norm(loc=0, scale=1) samples = normal.rvs(size=10000) # 采样 print(np.mean(samples), np.std(samples)) print(normal.cdf(1.96)) # P(X < 1.96) ≈ 0.975 logits = np.array([2.0, 1.0, 0.1]) print(softmax(logits)) # 概率 print(log_softmax(logits)) # 对数概率
你刚从零搭过这些,现在你知道库函数在做什么。
本节产物:
code/probability.py):PMF/PDF、期望方差、采样器、softmax/log-softmax/交叉熵。后续章节(第 7 节贝叶斯、第 9 节信息论、第 16 节采样方法)会反复复用。outputs/),用于讲授 PMF/PDF 区别与中心极限定理。[2.0, 0.5, −1.0, 3.0, 0.1]、正确类为 3,算交叉熵损失,与 PyTorch nn.CrossEntropyLoss 对照。P(A|B)=P(A∩B)/P(B) 是贝叶斯思维的根基;独立等价于 P(A∩B)=P(A)·P(B)。下一节,我们把条件概率升级成贝叶斯定理——一套「用新证据更新信念」的形式化机器,它是朴素贝叶斯、贝叶斯推断、VAE、不确定性量化的共同数学骨架。