基于MC Dropout的Aleatoric/Epistemic不确定性估计

430 阅读3分钟

Monte Carlo Dropout( MC Dropout)用于不确定性估计的数学基础,它背后的理论来自一篇非常有影响力的论文:

"Dropout as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning " — Yarin Gal & Zoubin Ghahramani, ICML 2016

在贝叶斯学习中,预测的目标是所谓的后验预测分布(posterior predictive distribution)

p(yx,D)=p(yx,θ)p(θD)dθ1Tt=1Tp(yx,θt)p(y | x, D) = \int p(y | x, \theta) \cdot p(\theta | D) \, d\theta \\ \approx \frac{1}{T} \sum_{t=1}^T p(y|x, \theta_t)
  • 也就是:在所有可能的参数下,对应的预测加权平均。但这个积分太复杂 → 所以我们用 Dropout + 多次 forward 来采样近似这个积分。因此,p(yx,D)p(y | x, D)是可计算的,即预测不确定性是可直接计算的。

🎯 多次 forward(每次用不同 Dropout mask):

  • 得到多个模型参数不同的 softmax 结果 → 可以计算平均(期望预测)、方差(不确定性)、熵 → 评价不确定程度。
  • 实际上就是:

总结:利用Dropout 模拟多个可能模型对当前输入的预测,进而估计整体的预测分布。


🧠 不确定性分解公式回顾:

总预测不确定性(预测熵):

H[yx,D]=Ep(θD)[H[yx,θ]]Aleatoric 不确定性+I[y,θx,D]Epistemic 不确定性H[y∣x,D]= \underbrace{\mathbb{E}_{p(\theta|D)}[H[y \mid x, \theta]]}_{\text{Aleatoric 不确定性}} + \underbrace{I[y, \theta \mid x, D]}_{\text{Epistemic 不确定性}}

这个公式可以直译为:

总的不确定性 = 模型之间预测差异有多大+模型内部每次预测平均有多不确定

注意 总预测不确定性(预测熵)H[yx,D]H[y|x,D]是可以直接计算的:

H[p]=plogpH[p] = -p\log p
H[yx,D]=H[Eθp(θD)[p(yx,θ)]]H[y|x,D] = H[E_{\theta\sim p(\theta|D)}[p(y|x,\theta)]]

🎯 一、什么是 Aleatoric(期望熵)?

Ep(θD)[H[yx,θ]]Aleatoric 不确定性\underbrace{\mathbb{E}_{p(\theta|D)}[H[y \mid x, \theta]]}_{\text{Aleatoric 不确定性}}

这部分的直觉是:

  • 假设我们对一个输入 xx,从多个模型(Dropout 实例)中做出 T 次预测;
  • 每个模型都给出自己的预测概率 p(yx,θt)p(y|x, \theta_t),其中有些预测“摇摆”,有些预测“坚定”;
  • 然后我们看每次预测中自己有多不确定(预测分布的 ,再对这些熵取平均。

🔍 关键理解

即便模型本身很稳定(不同模型预测结果都差不多),但预测分布本身也可能非常模糊(比如分布为 [0.5, 0.5]) ⇒ 说明是 数据本身就模糊、含糊、不可预测 ⇒ 属于 Aleatoric 不确定性。

🧪 类比:

多个医生(模型)独立看了同一张模糊的 X 光片(难以判断),他们一致地觉得不确定 ⇒ 病人问题来自于“图像本身太模糊”。


🧠 二、什么是 Epistemic(互信息)?

I[y,θx,D]=H[yx,D]Ep(θD)[H[yx,θ]]I[y,θ∣x,D]= H[y|x,D] - \mathbb{E}_{p(\theta|D)}[H[y|x, \theta]]

即:总预测熵 减去平均单个模型预测熵

这部分衡量的是:

  • 不同模型预测的结果之间差异有多大

  • 如果模型之间意见不合(有的预测 A,有的预测 B,有的预测 C),那说明:

    • 模型对这个输入还没“学明白”;
    • 是模型缺乏知识(见得少)导致的 ⇒ 属于 Epistemic 不确定性。

🧪 类比:

多个医生独立看了一张 X 光图,有的说“有病”,有的说“没病” ⇒ 模型之间不一致,说明医生之间缺乏共同知识 ⇒ 是模型的问题,不是图像的问题。


🔬 三、一个图示直觉(分类任务)

假设你输入图像 x,多次 MC Dropout 得到这些分布(横轴为类别):

情况一:模型稳定但每次都不确定(高 Aleatoric)

模型1模型2模型3
[0.5, 0.5][0.5, 0.5][0.5, 0.5]
  • 每次模型都“自己不确定” → 高 Aleatoric
  • 但每次模型都一样 → 低 Epistemic
  • 总不确定性 ≈ 每次都模糊

情况二:模型都很自信但互相预测不同(高 Epistemic)

模型1模型2模型3
[0.9, 0.1][0.2, 0.8][0.1, 0.9]
  • 每次模型都很确定 → Aleatoric 很低
  • 但预测结果差异大 → 模型之间不一致 → Epistemic 高
  • 总不确定性 ≈ 来自模型意见不合

总结口语解释

不确定性类型来自哪里?
Aleatoric每次模型预测“自己都不太确定”
Epistemic模型之间意见不合,不一致

✅ 四、代码示例:用 MC Dropout 分离 Aleatoric 和 Epistemic 不确定性(分类任务)

明确区分 Epistemic(模型)和 Aleatoric(数据)不确定性,你需要使用 贝叶斯建模技术(例如 MC Dropout 或 Deep Ensembles),并对每个输入进行多次预测,从而统计模型行为的分布特性

以下是一个在 分类任务中使用 MC Dropout 的完整示例(PyTorch 实现):

🔧 假设条件:

  • 你有一个分类模型,最后一层是 nn.Softmax
  • 模型中包含 Dropout 层,且推理阶段需保持 Dropout 开启(MC Dropout)。
  • 模型每次预测都输出 [batch_size, num_classes] 的概率分布。

🧩 步骤 1:多次预测(T 次)

def enable_dropout(model):
    """启用 Dropout 的 inference 阶段行为"""
    for m in model.modules():
        if isinstance(m, nn.Dropout):
            m.train()

def mc_predictions(model, x, T=20):
    """返回 T 次 MC Dropout 预测的 softmax 概率 [T, B, C]"""
    model.eval()
    enable_dropout(model)
    preds = []
    for _ in range(T):
        logits = model(x)  # 输出 logits
        probs = torch.softmax(logits, dim=-1)
        preds.append(probs)
    return torch.stack(preds)  # shape: [T, B, C]

🧮 步骤 2:分解不确定性

def compute_uncertainty(mc_probs):
    """
    mc_probs: [T, B, C] — T 次 softmax 概率
    返回:
        - predictive_entropy: [B]
        - expected_entropy:   [B]
        - epistemic:          [B]
        - aleatoric:          [B]
    """
    mean_probs = mc_probs.mean(dim=0)  # [B, C]
    log_mean_probs = torch.log(mean_probs + 1e-8)

    # 总预测不确定性(熵)
    predictive_entropy = - (mean_probs * log_mean_probs).sum(dim=-1)  # [B]

    # 每次预测的熵
    log_mc_probs = torch.log(mc_probs + 1e-8)
    entropies_per_sample = - (mc_probs * log_mc_probs).sum(dim=-1)  # [T, B]
    expected_entropy = entropies_per_sample.mean(dim=0)  # [B]

    # 模型不确定性(Epistemic) = predictive_entropy - expected_entropy
    epistemic = predictive_entropy - expected_entropy
    aleatoric = expected_entropy

    return {
        'predictive_entropy': predictive_entropy,
        'epistemic': epistemic,
        'aleatoric': aleatoric
    }

✅ 输出解释举例:

# 你输入一个样本 x 得到的结果
{
    'predictive_entropy': tensor([0.98]),
    'epistemic': tensor([0.65]),
    'aleatoric': tensor([0.33])
}

说明这个样本有:

  • 总不确定性 0.98;
  • 其中 65% 来源于模型缺乏知识(模型不确定性);
  • 33% 是数据本身模糊(数据不确定性)。