贝叶斯神经网络
贝叶斯神经网络(Bayesian Neural Networks,BNN)是将贝叶斯统计方法与深度学习结合的产物,通过对网络权重引入概率分布来建模不确定性。与传统神经网络的点估计不同,BNN学习的是权重的后验分布,从而能够自然地量化预测的不确定性。1
为什么需要不确定性?
传统深度学习的问题
传统神经网络通过最大似然估计(MLE)或最大后验估计(MAP)得到权重的点估计 :
这种方法存在以下问题:
| 问题 | 描述 |
|---|---|
| 过拟合 | 点估计无法捕获模型的不确定性 |
| 过自信 | 模型对其预测过于确信 |
| 泛化能力差 | 在分布外数据上表现不可预测 |
不确定性的价值
在许多实际应用中,知道”模型不确定”与知道”正确答案”同样重要:
- 自动驾驶:检测到不确定场景时可以让人类接管
- 医疗诊断:不确定时建议更多检查
- 科学发现:量化预测的可信度
贝叶斯神经网络定义
概率模型
BNN定义了一个完整的概率模型:
-
先验分布 :在观察数据之前,对权重的先验信念
常见选择:各向同性高斯分布
-
似然函数 :给定权重和数据,观测结果的概率
- 回归:
- 分类:
-
后验分布 :观察数据后,对权重的更新信念
通过贝叶斯公式:
预测分布
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 Dropout | Dropout作为近似贝叶斯 | 低 | 近似 |
| 集成方法 | 用有限模型集合逼近 | 可调 | 取决于集成大小 |
详见:
- MC Dropout — Dropout的贝叶斯解释
- Bayes by Backprop — 变分推断方法
- Laplace近似 — Hessian近似方法
- 变分推断基础 — VI理论框架
BNN的训练目标
变分推断视角
使用变分分布 逼近真实后验 ,最大化证据下界(ELBO):
其中:
- :重构似然(数据拟合项)
- :正则化项(与先验的偏离度)
与标准训练的对比
| 方面 | 标准训练 | BNN训练 |
|---|---|---|
| 参数 | 点估计 | 分布 |
| 损失函数 | ||
| 正则化 | L2/Dropout | KL散度项 |
| 输出 | 确定预测 | 预测分布 |
与其他方法的联系
与高斯过程的关系
当网络宽度趋于无穷大且权重为先验高斯时,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目标 | |
| 总方差分解 | |
| 偶然不确定性 | 数据的固有噪声(不可减少) |
| 认知不确定性 | 模型的不确定性(可减少) |
参考
相关文章
- MC Dropout — Dropout的贝叶斯解释与实现
- Bayes by Backprop — 变分推断贝叶斯神经网络
- Laplace近似 — Hessian近似方法
- 变分推断 — VI理论基础
- 信息论基础 — 熵、互信息与KL散度