AI/ML 详解:概率编程与贝叶斯深度学习

Day 38 · 2026-06-24 · 难度 ★★★★☆
面向:有编程经验的非 AI 方向工程师

前面的模型都给你一个点估计——「答案是 0.87」。但 0.87 是「我非常确定」还是「我瞎猜的」?普通神经网络分不清。贝叶斯方法的核心野心:不输出一个数,而是输出一个分布——「大概 0.87,但也可能在 0.6~0.95 之间」。今天讲清这套思想的两大计算引擎(MCMC 采样变分推断)、它给深度学习带来的能力(不确定性量化),以及把这套数学封装成工具的概率编程语言

马尔可夫链蒙特卡洛MCMC

采样贝叶斯推断
一句话类比

你想知道一个海量数据库里某个聚合分布的形状,但没法全表扫描(积分算不出来)。MCMC 派出一个随机游走的爬虫在状态空间里走动,规则是:概率密度高的地方多停留、低的地方少停留。走够久之后,统计爬虫的「访问频率直方图」,就近似了你要的那个分布。它和你熟悉的蒙特卡洛抽样估 p99 是同一个思路——用样本代替全量。

它解决什么问题 + 工作机制

贝叶斯推断的核心是贝叶斯公式:后验 ∝ 似然 × 先验。写成数学是 p(θ|D) = p(D|θ)·p(θ) / p(D)。分子好算(你的模型直接给),要命的是分母 p(D)——它是对所有可能参数 θ 的积分 ∫ p(D|θ)p(θ)dθ,在高维下根本算不出来(这叫「归一化常数」难题)。

MCMC 的妙处:它不需要算那个分母——每一步只看「新旧位置的概率密度比值」,分母在比值里被约掉了。最经典的 Metropolis-Hastings 算法只有四步:

Metropolis-Hastings 一步循环

① 当前点 θ ② 随机提议新点 θ' (在附近抖一下)

③ 算接受率 a = min(1, p(θ')/p(θ)) ← 分母约掉了!

④ 掷骰子:以概率 a 移到 θ',否则留在 θ

重复百万次 → 停留点的分布 ≈ 真实后验

朴素随机抖动在高维里效率极低(像喝醉的人乱走)。现代采样器用哈密顿蒙特卡洛(HMC)——借物理里「小球在能量曲面上滚」的思想,让提议顺着梯度走,一步迈得远又少被拒绝。但 HMC 要手调「滚多少步」,调不好就废。NUTS(No-U-Turn Sampler,Hoffman & Gelman 2011)让算法自动决定何时该停(小球开始往回掉头时就停),这就是 PyMC / Stan 今天默认采样器的由来。

代码示例
import numpy as np

# 从一个未归一化的目标分布采样(双峰),演示 MCMC 不需要分母
def target(x):           # 只需密度的"形状",不需积分常数
    return np.exp(-(x-2)**2/0.5) + np.exp(-(x+2)**2/0.5)

samples, x = [], 0.0
for _ in range(50000):
    x_new = x + np.random.normal(0, 1)      # ② 在附近提议
    a = min(1, target(x_new) / target(x))  # ③ 比值,常数约掉
    if np.random.rand() < a:                 # ④ 掷骰子决定是否接受
        x = x_new
    samples.append(x)

# 丢掉前段"预热(burn-in)"未收敛的样本,剩下的就近似目标分布
print(np.mean(samples[5000:]), np.std(samples[5000:]))
常见误区 + 实践场景
"采样器跑完就一定对了"——错。MCMC 最大的坑是没收敛你却以为收敛了:链可能卡在一个峰里出不来,或样本间高度自相关(等于有效样本数很少)。所以必须看诊断——R-hat(多条链是否走到一致,应 ≈ 1.0)和 ESS(有效样本数,太低说明样本冗余)。不看诊断的贝叶斯结果等于没做。
📌 超个体场景:做个人 A/B 决策(比如两个文案哪个转化率高),样本量往往很小(各 30 次点击)。频率派只给「3.2% vs 4.1%」的点估计,看不出差异是否可信。用 MCMC 跑个贝叶斯比例模型,直接得到「B 比 A 好的概率是 73%」——小样本下贝叶斯把不确定性诚实交还给你,比虚假精确的点估计更适合拍板。
Takeaway + 思考题
💡 MCMC 把「算不出的积分」换成「采得到的样本」——用随机游走的停留频率,绕过了贝叶斯公式里最难的归一化常数。
🤔 你日常哪些「凭经验估一个数」的判断,其实背后是个分布?如果把它当分布看,你的决策会变吗?

变分推断Variational Inference

近似推断优化ELBO
一句话类比

MCMC 慢且难扩展——百万样本对大数据集是灾难。变分推断(VI)换思路:与其精确采样那个复杂后验,不如找一个简单分布(比如高斯)去「拟合」它。这就像用一个预计算的物化视图 / 缓存去近似一个昂贵的实时聚合查询——牺牲一点精度,换巨大的速度。VI 把「推断问题」变成了你最熟的「优化问题」:调参数让近似分布尽量贴近真后验。

它解决什么问题 + 工作机制

设真后验是 p(θ|D)(算不出),引入一个带参数 φ 的简单分布 qφ(θ)(比如均值方差待定的高斯)。目标:调 φ,让 q 和 p 的「距离」最小。距离用 KL 散度衡量(Day 33 讲过:两个分布的信息差)。

但 KL(q‖p) 里又藏着那个算不出的后验。数学上一变形,最小化 KL 等价于最大化一个叫 ELBO(证据下界)的量

ELBO = Eq[ log p(D|θ) ] − KL( qφ(θ) ‖ p(θ) )
    第一项:拟合数据    第二项:别离先验太远(正则)

直觉拆解:第一项逼 q 解释好观测数据(似然要高);第二项是个「拉回先验」的弹簧,防止过拟合。两项拔河——这正是「拟合 vs 正则」的贝叶斯版本,你在 Day 10 见过同样的张力。ELBO 之所以叫「下界」,是因为它永远 ≤ 真实证据 log p(D),把它顶高,就等于把 q 推向 p。

关键是 ELBO 可以求梯度,于是能用 Adam 直接跑。把高斯的「采样」改写成「均值 + 标准差 × 标准噪声」,梯度就能穿过随机采样回流——这个重参数化技巧(reparameterization trick)是 Kingma & Welling 的 VAE 论文(2013)的核心,也是 VAE、扩散模型背后的同一块积木。PyMC / NumPyro 里这套自动化版本叫 ADVI

代码示例
import pymc as pm
import numpy as np

y = np.random.normal(5, 2, size=200)   # 假数据:真均值 5

with pm.Model() as model:
    mu = pm.Normal("mu", 0, 10)        # 先验:均值不知道
    sigma = pm.HalfNormal("sigma", 5)
    pm.Normal("obs", mu, sigma, observed=y) # 似然

    # 不用 MCMC 采样,改用变分推断拟合 —— 大数据集快几个量级
    approx = pm.fit(20000, method="advi")   # 最大化 ELBO
    idata = approx.sample(1000)            # 从拟合好的 q 里抽样

print(idata.posterior["mu"].mean().item())  # ≈ 5,且带后验区间
常见误区 + 实践场景
"VI 和 MCMC 结果一样,只是更快"——不全对。VI 有个系统性偏差:用 KL(q‖p) 当目标会让 q 低估不确定性(倾向"缩进"真后验的一个峰里,方差偏小)。所以速度优势有代价——它给的置信区间往往过窄、过于自信。规模小、要严谨结论用 MCMC;规模大、要可扩展(如深度模型)用 VI。知道这个权衡,才不会被过窄的区间骗了。
📌 超个体场景:你训练任何带随机层(dropout、隐变量)的模型时,背后都在用 VI 的思想。理解 ELBO 让你看懂为什么 VAE / 扩散模型的损失函数长那样(重构项 + KL 正则项)——它们都是 ELBO 的变体,下次读这类论文不再是天书。
Takeaway + 思考题
💡 变分推断把「采样」换成「优化」——找一个简单分布去贴近复杂后验,用梯度下降解贝叶斯,代价是会低估不确定性。
🤔 「用简单模型近似复杂真相,换取可计算性」——这个权衡在你的工程经验里还出现在哪些地方(缓存?降维?索引?)

不确定性量化Uncertainty Quantification

贝叶斯深度学习可靠性
一句话类比

普通神经网络永远「自信满满」——哪怕喂它一张从没见过的乱码图,它也会斩钉截铁说「这是猫,99%」。这就像一个从不返回错误码、永远返回 200 OK 的服务,哪怕后端早就崩了。不确定性量化(UQ)给模型装上一个诚实的「我不知道」信号——区分「我见过类似数据,有把握」和「这超出我的认知范围,别信我」。

它解决什么问题 + 工作机制

关键是区分两种本质不同的不确定性,这个区分是整个领域的地基:

偶然不确定性 Aleatoric数据本身的噪声,不可消除
 例:抛硬币、传感器抖动。给再多数据也是 50/50,加数据没用

认知不确定性 Epistemic模型的无知,可消除
 例:训练集没覆盖的区域。加数据 / 加训练就能降低

类比分布式排障:aleatoric ≈ 网络固有抖动(认了);
epistemic ≈ 这条链路我从没监控过(补监控就好了)

怎么让神经网络给出 epistemic 信号?核心思路:别只信一个模型,要看「一群模型」的分歧。数据密集处大家答案一致(低不确定);没见过的区域各模型乱猜、互相打架(高不确定)。两种最实用的实现:

  • MC Dropout(Gal & Ghahramani 2015):推理时不关掉 dropout,同一输入跑 N 次、每次随机丢不同神经元 → N 个不同预测,它们的方差就是不确定性。理论上等价于一种廉价变分推断——几乎零成本给现成模型加上贝叶斯能力。
  • Deep Ensembles(Lakshminarayanan 2016):独立训练 5 个模型(不同随机种子),预测时看分歧。简单粗暴,但实测校准质量常常最好,是工业界强基线。
代码示例
import torch

# MC Dropout:推理时保持 dropout 打开,跑多次拿分歧
def predict_with_uncertainty(model, x, n=30):
    model.train()              # 关键:train 模式让 dropout 仍激活
    preds = torch.stack([model(x) for _ in range(n)])  # N 次随机前向
    mean = preds.mean(0)      # 预测值
    std  = preds.std(0)       # 不确定性:分歧大 = 模型没把握
    return mean, std

mean, std = predict_with_uncertainty(my_net, x_test)
# std 高的样本 → 模型在"瞎猜",应转人工审核或拒答
mask = std.squeeze() > 0.3
print(f"需人工复核的样本数: {mask.sum().item()}")
常见误区 + 实践场景
"Softmax 输出 0.99 就代表模型很确定"——大错。Softmax 概率是类别间的相对排序,不是校准过的置信度。现代神经网络出了名地过度自信,对完全没见过的输入也能给 99%。真正的 epistemic 不确定性必须靠模型分歧(MC Dropout / Ensemble)拿,不能直接读 softmax——把 softmax 当置信度,是部署 AI 时最常见也最危险的误判。
📌 超个体场景:搭AI 工作流时给每个模型节点加一道「不确定性闸门」——高不确定的输出自动转人工或触发二次验证,低不确定的才放行自动化。这就是把「人机协同」做成可量化的开关:模型有把握时全自动,没把握时才占用你的注意力。UQ 让「该信任 AI 到什么程度」从玄学变成数字。
Takeaway + 思考题
💡 普通模型永远返回 200 OK;不确定性量化给它装上诚实的「我不知道」——而且要分清「数据噪声(认了)」和「我没见过(可补)」两种来源。
🤔 如果你的 AI 助手能可靠地说「这个我没把握」,你的协作方式会怎么变?信任的前提是不是「它知道自己不知道」?

概率编程语言PyMC / Stan

工具声明式
一句话类比

前面三个概念的数学都很硬。概率编程语言(PPL)是把它们封装成一门声明式语言:你只「声明」概率模型(先验是什么、数据怎么生成),推断引擎自动帮你跑 MCMC 或 VI。这正是 SQL 之于数据库 的关系——你写「想要什么(what)」,查询优化器决定「怎么算(how)」。PyMC / Stan 就是概率世界的 SQL,把你从手写采样器里解放出来。

它解决什么问题 + 工作机制

没有 PPL 之前,每换一个模型你都得重写 Metropolis 接受率、梯度、收敛诊断——极易出错。PPL 的核心机制是把模型定义和推断算法解耦

声明式 vs 命令式

命令式(手写):自己写采样循环、接受率、梯度、诊断 → 几百行、易错

声明式(PPL)
  ① 写先验 prior + ② 写似然 likelihood + ③ 绑观测数据
  ↓ 引擎自动微分 + NUTS/ADVI
  ④ 拿后验分布 + R-hat/ESS 诊断

你只管描述"世界怎么生成数据",推断交给引擎

主流选择:Stan——统计学界金标准、最严谨,独立 DSL;PyMC——纯 Python、上手最快;NumPyro——架在 JAX 上、GPU 加速、最快,适合大模型贝叶斯。它们共享同一套引擎核心:自动微分 + NUTS 采样 + 变分推断,区别只在语法与速度。

代码示例
import pymc as pm
import numpy as np

# 贝叶斯线性回归:注意我们只"声明"模型,不写任何采样逻辑
x = np.linspace(0, 10, 50)
y = 2.5 * x + 1.0 + np.random.normal(0, 1, 50)   # 真斜率 2.5

with pm.Model() as model:
    slope = pm.Normal("slope", 0, 5)     # ① 先验
    inter = pm.Normal("inter", 0, 5)
    noise = pm.HalfNormal("noise", 2)
    # ② 似然 + ③ 绑数据
    pm.Normal("y", slope*x + inter, noise, observed=y)

    idata = pm.sample(1000)   # ④ 引擎自动 NUTS 采样 + 诊断

# 得到的不是一个斜率,而是斜率的整个后验分布
pm.summary(idata)  # 输出均值、94% 区间、r_hat、ess
常见误区 + 实践场景
"PPL 是统计学家的玩具,深度学习用不上"——过时了。NumPyro / Pyro 正为贝叶斯深度学习而生:可把神经网络权重设成分布、用变分推断训练,得到自带不确定性的网络。而且会读概率模型 ≠ 会建对模型——先验选得离谱、结构错了,引擎照样跑出一堆漂亮但错误的后验。PPL 降低了计算门槛,没降低建模思维的门槛。
📌 超个体场景:用 PyMC 做个人决策建模——把你对一件事的先验信念("这项目大概 6 成能成")写成分布,每来一条新证据就更新后验。这是把贝叶斯更新变成可执行代码的思维训练:它逼你显式写下「我原本信什么、新证据多强、更新后信什么」,比拍脑袋可靠得多。
Takeaway + 思考题
💡 概率编程语言是「贝叶斯世界的 SQL」——你声明模型,引擎自动推断;它降低了计算门槛,但建模的判断力仍然在你。
🤔 SQL 让不懂 B+ 树的人也能查数据库。PPL 让不懂 MCMC 的人也能做贝叶斯——这种「声明式抽象」下一个会颠覆的领域是什么?

深入资源Further Reading

深入思考Deep Questions

1. 频率派给点估计 + 置信区间,贝叶斯给后验分布。对一个工程师做实际决策,这两套框架的本质差异是什么?什么时候该用哪个?
本质差异在「概率」指的是什么。频率派:参数是固定真值,概率描述「反复实验时数据的波动」——「95% 置信区间」真实含义是「这套程序重复 100 次,约 95 次的区间会盖住真值」,不是「真值有 95% 概率落在此区间」(这是大众普遍的误读)。贝叶斯:参数本身是随机变量,「94% 区间」就是字面意思——「给定数据和先验,参数有 94% 概率在这」,可直接拿去决策。工程取舍:(a) 小样本 + 有先验→贝叶斯,能把领域知识写进先验,小数据下更稳;(b) 大样本 + 要标准化报告→频率派,更快、业界默认、不用辩论先验;(c) 要做下游决策→贝叶斯,完整后验能直接算「选 A 比 B 好的概率」。对你做超个体的个人决策(样本天然小、你有强先验),贝叶斯思维往往更合身——它逼你显式写下信念并随证据更新。
2. MCMC 精确但慢,VI 快但低估不确定性。这个「精度 vs 速度」的权衡,和你在分布式系统里见过的哪些取舍同构?有没有「两者兼得」的中间路线?
这是强一致 vs 最终一致在推断世界的翻版。MCMC 像强一致读:渐近正确,但慢、难水平扩展。VI 像读缓存:快、可扩展,但可能读到「偏窄」的近似(类比略陈旧的副本)。而且 VI 的偏差是系统性的(总低估方差),就像缓存 staleness 有方向性,可预判和补偿。中间路线确实有:(a) 归一化流——给 VI 用更灵活的 q 分布(不止高斯),逼近能力大增;(b) SVGD / 粒子变分——用一群粒子兼顾采样的灵活和优化的速度;(c) VI 预热 + MCMC 精修——先用 VI 快速定位后验大致位置,再用少量 MCMC 步精修,类似「缓存预取 + 关键路径强一致校验」。工程哲学一致:先快速近似定位,再按需局部精确化。
3. 「认知不确定性(epistemic)可以靠加数据消除,偶然不确定性(aleatoric)不能」——这个区分对设计 AI 系统的「主动学习」和「拒答策略」有什么直接指导?
这个区分是主动学习(active learning)的理论核心。主动学习要解决「该花钱标注哪些样本」——答案:专挑 epistemic 高的。因为 epistemic 高 = 模型没见过这类数据 = 标注它能真正消除无知;反之 aleatoric 高的样本(本就是 50/50 噪声),标了也没用。所以「按总不确定性排序标注」是错的,必须先分解出 epistemic 那部分。对拒答 / 转人工策略同样关键:(a) epistemic 高→「超出我的认知范围」→应拒答或转人工,且值得反馈进训练集形成闭环;(b) aleatoric 高→「这事本质就不确定」→拒答没意义(换模型也一样),应如实给出概率让人带不确定性决策。混淆两者会让系统要么过度拒答(把噪声当无知),要么盲目自信(把无知当噪声)——成熟的 AI 应对这两种「不知道」给出不同行为。
4. 重参数化技巧(reparameterization trick)让梯度能「穿过」随机采样。为什么这一个小技巧能同时点燃 VAE、扩散模型、变分推断三个领域?它的深层意义是什么?
深层意义:它把「随机性」和「可微性」调和了,这是整个深度生成模型的命门。背景:神经网络靠反向传播训练,但「从分布里采样」本身不可微——你没法对「掷骰子」求导。重参数化的巧妙:把「从 N(μ,σ²) 采样」改写成「z = μ + σ·ε,其中 ε~N(0,1)」。随机性被外包给与参数无关的 ε,μ、σ 变成确定性的可微变换,梯度便能绕过 ε、顺着 μ/σ 回流。为什么点燃三个领域:它们本质都是「学一个带随机隐变量的生成过程」——VAE 学编码-解码、扩散模型学逐步去噪、贝叶斯网络学权重分布,全卡在「怎么对采样求导」这一关。重参数化一举打通,让它们都能用 SGD + Adam 端到端训练。这也是为什么 Day 20 的扩散模型、今天的 VI、生成模型底层是同一块积木——一个看似不起眼的代数变形,决定了一整代生成式 AI 能否用梯度训练,是「可微编程」吞下「概率建模」的关键接口。
5. 贝叶斯的核心是「先验 + 证据 → 后验」的更新循环。如果把人的认知、科学的进步、甚至佛学的「缘起」都看成贝叶斯更新,这个视角能照亮什么,又会遮蔽什么?
能照亮的:(a) 认知层面——「带先验看世界、用证据更新」精确刻画了学习:婴儿先验很弱,专家先验很强却更难被新证据撼动——这正是「专家偏见」的贝叶斯解释(强先验需更强证据才能翻转)。(b) 科学哲学——科学进步是集体后验的更新,范式转移(Kuhn)就是反常证据终于压过旧先验的「相变」。(c) 东方思想——佛学「缘起」讲一切依条件生灭、无固定自性,与贝叶斯「信念随证据流转、无绝对确定」有迷人呼应;「执」可类比为先验过强、拒绝更新的退化态。会遮蔽的:(i) 贝叶斯假设假设空间稳定,但真实认知的突破常是创造出原本不在假设空间里的新概念——这是框架装不下的「无中生有」(你没法给还没被想到的假设赋先验);(ii) 它把认知简化为信息处理,可能遮蔽具身、情感、直觉这些非命题性的知;(iii) 佛学的「证悟」指向超越概念分别的体验,而贝叶斯是一套概念分别的精致机器——用它解释证悟,恰恰可能错过证悟要解构的东西。所以这是把好用的透镜,别误当成眼睛本身——这也很「贝叶斯」:对「贝叶斯是万能视角」这个先验,本身就该保持可被更新的谦逊。