贝叶斯神经网络

贝叶斯神经网络(Bayesian Neural Networks,BNN)是将贝叶斯统计方法与深度学习结合的产物,通过对网络权重引入概率分布来建模不确定性。与传统神经网络的点估计不同,BNN学习的是权重的后验分布,从而能够自然地量化预测的不确定性。1

为什么需要不确定性?

传统深度学习的问题

传统神经网络通过最大似然估计(MLE)或最大后验估计(MAP)得到权重的点估计

这种方法存在以下问题:

问题描述
过拟合点估计无法捕获模型的不确定性
过自信模型对其预测过于确信
泛化能力差在分布外数据上表现不可预测

不确定性的价值

在许多实际应用中,知道”模型不确定”与知道”正确答案”同样重要:

  • 自动驾驶:检测到不确定场景时可以让人类接管
  • 医疗诊断:不确定时建议更多检查
  • 科学发现:量化预测的可信度

贝叶斯神经网络定义

概率模型

BNN定义了一个完整的概率模型:

  1. 先验分布 :在观察数据之前,对权重的先验信念

    常见选择:各向同性高斯分布

  2. 似然函数 :给定权重和数据,观测结果的概率

    • 回归:
    • 分类:
  3. 后验分布 :观察数据后,对权重的更新信念

    通过贝叶斯公式:

预测分布

BNN的核心输出是预测分布,而非单点预测:

这本质上是权重的后验分布下的预测期望,包含了所有权重配置的不确定性。

不确定性分类

在贝叶斯深度学习中,不确定性主要分为两类:

偶然不确定性(Aleatoric Uncertainty)

定义:数据本身的随机性或观测噪声,即使拥有无限多的数据也无法消除。

来源

  • 传感器噪声
  • 数据标注模糊
  • 本质随机过程

建模方式:在似然函数中引入噪声参数

class HeteroscedasticRegression(nn.Module):
    """
    异方差回归:噪声依赖于输入
    p(y|x) = N(y|f(x), σ²(x))
    """
    def __init__(self):
        super().__init__()
        self.mean_net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, 1)
        )
        self.var_net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, 1),
            nn.Softplus()  # 确保方差为正
        )
    
    def forward(self, x):
        mean = self.mean_net(x)
        log_var = self.var_net(x)  # log(σ²) 便于数值稳定
        return mean, log_var

认知不确定性(Epistemic Uncertainty)

定义:模型参数的不确定性,源于训练数据的有限性,可通过更多数据减少。

来源

  • 训练数据不足
  • 模型假设的不确定性
  • 参数的后验不确定性

建模方式:对权重引入后验分布

# 点估计:单组权重
w_point = model.state_dict()
 
# 贝叶斯:权重分布
w_samples = [posterior_sample() for _ in range(100)]

两者的直观对比

                    不确定性
                      ↑
                      │
         Epistemic   │        ╭─────╮
         (模型不确定性) │       ╱ Aleatoric ╲
                      │      ╱  (数据噪声)  ╲
                      │     ╱                ╲
                      │    ╱──────────────────╲
                      └───┴──────────────────────→ 数据量
                            
                           数据少 → 不确定性高
                           数据多 → Aleatoric主导

数学表达

总预测方差可分解为:

推断的挑战

计算复杂度

贝叶斯推断的核心困难在于后验分布的计算

分母(证据/边缘似然):

对于大型神经网络:

  • 积分维度: - 个权重参数
  • 无法解析求解

近似推断方法

方法基本思想计算复杂度近似质量
MCMC采样直接从后验采样极高渐近精确
变分推断用简单分布逼近后验中等有偏
Laplace近似用高斯逼近后验中等局部最优
MC DropoutDropout作为近似贝叶斯近似
集成方法用有限模型集合逼近可调取决于集成大小

详见:

BNN的训练目标

变分推断视角

使用变分分布 逼近真实后验 ,最大化证据下界(ELBO):

其中:

  • :重构似然(数据拟合项)
  • :正则化项(与先验的偏离度)

与标准训练的对比

方面标准训练BNN训练
参数点估计 分布
损失函数
正则化L2/DropoutKL散度项
输出确定预测预测分布

与其他方法的联系

与高斯过程的关系

当网络宽度趋于无穷大且权重为先验高斯时,BNN收敛于高斯过程2

这提供了:

  • 理论基础:BNN是高斯过程的有限近似
  • 不确定性解释:从函数空间角度看BNN
  • NTK联系:无限宽网络的预测等价于核方法

与集成方法的关系

深度集成(Deep Ensembles)可视为对BNN的实用近似:

其中 是不同随机初始化下独立训练的模型。

详见 神经网络表达能力 — NTK理论。

PyTorch 基础实现框架

import torch
import torch.nn as nn
from torch.distributions import Normal, kl_divergence
 
class BayesianLayer(nn.Module):
    """
    贝叶斯层的基类
    子类需要实现:
    - sample_weights(): 从后验分布采样权重
    - kl_loss(): 计算与先验的KL散度
    """
    def forward(self, x):
        raise NotImplementedError
    
    def kl_loss(self):
        raise NotImplementedError
 
class BayesianLinear(BayesianLayer):
    """
    贝叶斯线性层:权重和偏置为高斯分布
    """
    def __init__(self, in_features, out_features, prior_std=1.0):
        super().__init__()
        self.in_features = in_features
        self.out_features = out_features
        
        # 变分参数:均值和对数方差
        self.weight_mu = nn.Parameter(torch.randn(out_features, in_features) * 0.1)
        self.weight_log_var = nn.Parameter(torch.zeros(out_features, in_features) - 6)  # log(0.001)
        
        self.bias_mu = nn.Parameter(torch.zeros(out_features))
        self.bias_log_var = nn.Parameter(torch.zeros(out_features) - 6)
        
        # 先验分布(固定标准差)
        self.prior_std = prior_std
    
    def sample_weights(self):
        """重参数化采样"""
        weight_std = torch.exp(0.5 * self.weight_log_var)
        bias_std = torch.exp(0.5 * self.bias_log_var)
        
        weight = self.weight_mu + torch.randn_like(self.weight_mu) * weight_std
        bias = self.bias_mu + torch.randn_like(self.bias_mu) * bias_std
        
        return weight, bias
    
    def kl_loss(self):
        """计算与先验的KL散度(高斯到高斯)"""
        prior = Normal(0, self.prior_std)
        
        # 权重的KL
        q_weight = Normal(self.weight_mu, torch.exp(0.5 * self.weight_log_var))
        kl_weight = kl_divergence(q_weight, prior).sum()
        
        # 偏置的KL
        q_bias = Normal(self.bias_mu, torch.exp(0.5 * self.bias_log_var))
        kl_bias = kl_divergence(q_bias, prior).sum()
        
        return kl_weight + kl_bias
    
    def forward(self, x):
        weight, bias = self.sample_weights()
        return torch.nn.functional.linear(x, weight, bias)
 
class BayesianMLP(nn.Module):
    """贝叶斯多层感知机"""
    
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.layer1 = BayesianLinear(input_dim, hidden_dim)
        self.layer2 = BayesianLinear(hidden_dim, hidden_dim)
        self.output = BayesianLinear(hidden_dim, output_dim)
        self.relu = nn.ReLU()
    
    def forward(self, x):
        x = self.relu(self.layer1(x))
        x = self.relu(self.layer2(x))
        return self.output(x)
    
    def kl_loss(self):
        """总KL损失"""
        return self.layer1.kl_loss() + self.layer2.kl_loss() + self.output.kl_loss()
    
    def predict(self, x, n_samples=50):
        """
        贝叶斯预测:多次采样获取预测分布
        """
        predictions = []
        
        with torch.no_grad():
            for _ in range(n_samples):
                pred = self(x)
                predictions.append(pred)
        
        predictions = torch.stack(predictions)  # (n_samples, batch, output)
        
        # 预测均值和方差
        mean = predictions.mean(dim=0)
        variance = predictions.var(dim=0)
        
        return mean, variance, predictions

核心公式速查

概念公式
后验分布
预测分布
ELBO目标
总方差分解
偶然不确定性数据的固有噪声(不可减少)
认知不确定性模型的不确定性(可减少)

参考

相关文章

Footnotes

  1. Jospin, L.V., et al. (2020). “Hands-On Bayesian Neural Networks: A Tutorial for Deep Learning Users”. arXiv:2007.06823.

  2. Lee, J., et al. (2018). “Deep Neural Networks as Gaussian Processes”. ICLR 2018.