贝叶斯深度学习入门:从不确定性到贝叶斯神经网络

标准深度网络通常只吐出一个「点预测」:输入一张图,它告诉你这是猫的概率是 0.93。但它不会告诉你这个数字有多可信。在医疗诊断、自动驾驶、金融风控这类高风险场景里,知道模型「有多确定」往往和知道它「预测了什么」同样重要。一个把肺结节判为良性的模型,如果同时承认「我很不确定」,医生就该转人工复核;而一个自信满满却毫无依据的模型反而更危险。

本篇面向已经掌握深度学习基础、想理解模型不确定性的工程师,依次讲清四件事:为什么需要不确定性、贝叶斯视角如何把权重变成分布、贝叶斯神经网络(BNN)与两种主流近似方法(变分推断、MC Dropout),最后用 PyTorch 跑一个带不确定性估计的最小示例。

为什么需要不确定性:认知不确定性 vs 偶然不确定性

不确定性不是单一概念,至少可以分成两类,区分它们决定了你能「做什么」:

  • 偶然不确定性(Aleatoric Uncertainty):来自数据本身的噪声与随机性,即使采到无穷多数据也无法消除。例如传感器测量误差、标注者之间的分歧。它又分「同质」(噪声大小恒定,即同方差)与「异质」(噪声随输入变化,即异方差,比如输入越模糊噪声越大)。
  • 认知不确定性(Epistemic Uncertainty):来自模型自身知识不足,根因是训练数据覆盖不全、模型没见过的区域太多。它可以通过采集更多相关数据来减小。一句话概括:这是「模型不知道自己不知道」的那部分。

区分二者的意义很实际:偶然不确定性标出了任务本身的天花板,告诉你再怎么调模型也消除不了的误差;认知不确定性则告诉你「该去哪里补数据」。贝叶斯方法最擅长建模的正是认知不确定性,也能顺带扩展到建模偶然不确定性。

贝叶斯视角:权重是分布,不是点估计

普通训练(比如 SGD)得到的是一组权重的「点估计」w*,也就是损失函数在参数空间里的一个最优点。贝叶斯视角拒绝这种单一答案,它把权重 w 看成随机变量:

  • 先验(Prior) p(w):在看到任何数据之前,你对权重长什么样的信念,通常是简单的分布(如零均值高斯)。

  • 后验(Posterior) p(w|D):看到训练数据 D = {(x_i, y_i)} 之后,权重应该长什么样,由贝叶斯定理给出:

    p(w|D) = p(D|w) · p(w) / p(D) ∝ p(D|w) · p(w)

  • 预测(Predictive):对新输入 x*,预测分布不再依赖单一权重,而是对所有权重后验取期望(边缘化):

    p(y* | x*, D) = ∫ p(y* | x*, w) · p(w|D) dw

直觉上,贝叶斯预测是「让无穷多个不同权重的模型各自投票,再按后验概率加权平均」,所以天然带有一个衡量分歧程度的方差。

难点在于:后验 p(w|D) 几乎从来没解析解,那个对权重的积分也不可解。于是「如何近似后验与预测分布」成了贝叶斯深度学习的全部重心。

贝叶斯神经网络(BNN):把贝叶斯装进神经网络

贝叶斯神经网络(Bayesian Neural Network,BNN)就是「每一层权重都是分布、而非定值」的神经网络。训练不再去求一个 w*,而是去求权重上的后验分布。直接算后验太难,于是有了两条主流近似路线。

变分推断:用一个好算的分布去逼近后验

变分推断的核心思路是:用一个带参数 θ 的、形式简单的分布 q_θ(w) 去逼近真实后验 p(w|D),衡量标准是两个分布的 KL 散度。训练目标是最大化「证据下界」(ELBO):

log p(D) ≥ E_{q_θ(w)}[ log p(D|w) ] − KL( q_θ(w) ‖ p(w) )

等号右边第一项鼓励 q 拟合数据(似然项),第二项约束 q 不要离先验太远。Bayes by Backprop(Blundell 等人,2015)用重参数化技巧直接对 ELBO 做反向传播,把每个权重替换成一个小分布来训练。

MC Dropout:用现成的 Dropout 近似贝叶斯

这是工程上最省力的近似,核心洞见来自 Gal 与 Ghahramani:如果在神经网络的每个权重层之后都放 Dropout,并把 Dropout 的训练解释成在「深度高斯过程」上做近似贝叶斯推断,那么推理时只要保持 Dropout 开启、多次前向采样,这批样本的均值和方差就能近似后验预测分布。

做法只需两步:

  1. 训练阶段和平时完全一样(标准 Dropout 训练)。
  2. 推理阶段调用 model.train() 让 Dropout 在预测时仍然生效,对同一个输入前向跑 T 次,收集这 T 次输出,用均值当点估计、方差当不确定性。

它的优点是几乎零改动、额外计算开销小、能直接套在已有模型上;局限是对后验的近似偏乐观,方差校准不一定完美,复杂后验形状也表达不出来。

来源核验:Gal, Y. 与 Ghahramani, Z.《Dropout as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning》,ICML 2016,arXiv:1506.02142。标题、作者、会议与核心主张(把 Dropout 训练视为深度高斯过程上的近似贝叶斯推断,并用 MC Dropout 估计模型不确定性)已通过 arXiv 摘要页核验(已核验)。

实战:用 PyTorch 做带不确定性估计的最小示例

下面用 MC Dropout 在一个一维回归任务上直观展示不确定性。我们先造一条带噪声的 y = sin(x) 曲线,训练一个带 Dropout 的小网络,然后推理时多次采样,对比「训练数据覆盖区」与「数据空白区」的方差差异。

import torch
import torch.nn as nn
import torch.optim as optim

  # 生成带噪声的一维回归数据:y = sin(x) + 噪声
torch.manual_seed(0)
n_train = 80
x = torch.linspace(-3.0, 3.0, n_train).unsqueeze(1)
y = torch.sin(x) + 0.15 * torch.randn(n_train, 1)

  # 定义带 Dropout 的 MLP;关键:推理阶段也保留 Dropout
class MCDropoutMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(1, 64),
            nn.ReLU(),
            nn.Dropout(0.1),
            nn.Linear(64, 64),
            nn.ReLU(),
            nn.Dropout(0.1),
            nn.Linear(64, 1),
        )

    def forward(self, x):
        return self.net(x)

model = MCDropoutMLP()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)

  # 训练阶段:标准 MSE 优化,MC Dropout 不改动训练流程
for epoch in range(2000):
    optimizer.zero_grad()
    loss = criterion(model(x), y)
    loss.backward()
    optimizer.step()

  # 推理阶段:保持 Dropout 开启,多次前向采样,用均值与方差刻画不确定性
def predict_with_uncertainty(model, x_test, n_samples=50):
    model.train()  # train() 模式让 Dropout 在推理时仍生效
    predictions = [model(x_test) for _ in range(n_samples)]
    preds = torch.stack(predictions, dim=0)
    mean = preds.mean(dim=0)
    var = preds.var(dim=0)
    return mean, var

x_test = torch.linspace(-5.0, 5.0, 200).unsqueeze(1)
mean, var = predict_with_uncertainty(model, x_test)

  # 区间外方差明显更大,正是认知不确定性的直观体现
print("测试点预测均值形状:", mean.shape)
print("训练区间内方差:", var[x_test.abs() < 3].mean().item())
print("训练区间外方差:", var[x_test.abs() >= 3].mean().item())

运行后你会看到:在训练数据覆盖的 [-3, 3] 区间内,多次采样的方差很小,说明模型「很有把握」;而在 [-5, -3)(3, 5] 这类数据空白区,方差明显放大,说明模型「知道自己没见过」。这就是认知不确定性最直观的样子。把 mean 当预测值、var 的开方当置信区间半径,你就能画出让业务方放心的「带误差带的预测曲线」。

来源核验:PyTorch 官方站点(已核验)确认其为开源机器学习框架,提供 torchtorch.nnautogradoptim 等组件;本篇示例使用 nn.Modulenn.Dropout 构建网络。TensorFlow Probability 官方文档(已核验)确认其为「用于概率推理与统计分析的库」,构建于 TensorFlow,提供分布、bijectors、概率层、JointDistribution 以及变分推断与 MCMC 工具,是做 BNN 的另一条成熟路线。

小结

回到开头的四个问题,一句话收束:

  • 为什么需要不确定性:高风险决策里,「我有多确定」和「我预测了什么」同等重要,它区分了任务噪声的天花板与模型知识的缺口。
  • 贝叶斯视角:权重不再是点,而是带先验、后验的分布;预测是对后验的边缘化,天然携带不确定性。
  • BNN 与近似:真实后验算不出,于是用变分推断(学一个分布 q 逼近后验,最大化 ELBO)或用 MC Dropout(保持 Dropout 做多次采样)来近似。
  • MC Dropout 最省力:训练照旧、推理多采样,均值即预测、方差即认知不确定性。

什么时候该用?主动学习(挑「最不确定」的样本去标注)、异常检测(高不确定性即异常)、少样本与分布外检测,以及任何「预测错了代价很高」的场景。

参考与延伸阅读

  1. Gal, Y. 与 Ghahramani, Z.《Dropout as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning》,ICML 2016,arXiv:1506.02142(已核验)。
  2. TensorFlow Probability 官方文档(已核验):概率推理与统计分析库,构建于 TensorFlow,含分布、bijectors、概率层、JointDistribution、变分推断与 MCMC。
  3. PyTorch 官方文档(已核验):开源机器学习框架,torch/torch.nn/autograd/optim 组件,本篇示例使用其 nn.ModuleDropout
  4. Blundell, C. 等人,2015,《Weight Uncertainty in Neural Networks》(Bayes by Backprop)(待核实,本文未做 WebFetch 核验,建议引用前自行核对)。
  5. Kendall, A. 与 Gal, Y.,2017,《What Uncertainties Do We Need in Bayesian Deep Learning for Computer Vision》(偶然与认知不确定性分解)(待核实,本文未做 WebFetch 核验,建议引用前自行核对)。
本文累计阅读