概述
马尔可夫随机场(Markov Random Field, MRF)和能量模型(Energy-Based Model, EBM)是概率图模型中的核心概念,它们通过能量函数而不是直接的概率分解来定义联合分布。1
这种表示方式特别适合建模无向依赖关系,在条件随机场、图像建模、图神经网络等领域有广泛应用。
马尔可夫随机场基础
无向图模型的问题
在贝叶斯网络中,联合分布可以分解为条件概率的乘积:
但在无向图中,由于没有天然的拓扑顺序,不能直接做类似的分解。
团与最大团
团(Clique):图中两两相邻的节点集合。
最大团(Maximal Clique):不能被其他团包含的团。
团示例:
●──●──● {X1, X2} 是团
│ │ {X1, X3} 不是团(X2和X3不相邻)
●──●──●
Hammersley-Clifford定理
定理:如果一个正的(严格正)分布 满足马尔可夫性质,那么它可以因子分解为势函数的乘积:
其中:
- 是图的最大团集合
- 是定义在团 上的势函数(Potential Function)
- 是配分函数(Partition Function)
势函数的性质
势函数 必须是严格正的(),通常用指数形式表示:
其中 是能量函数。
能量模型(Energy-Based Models)
从势函数到能量函数
定义能量函数 ,联合分布为:
其中 是配分函数。
能量函数的直观理解
| 概念 | 物理类比 |
|---|---|
| 能量 | 系统能量 |
| 玻尔兹曼分布 | |
| 低能量状态 | 稳定、概率高 |
| 高能量状态 | 不稳定、概率低 |
| 配分函数 | 归一化常数 |
常见的能量函数形式
1. 对数线性模型
其中 是特征函数, 是权重。
2. 高斯MRF
这对应于高斯分布。
3. Hopfield网络能量
条件随机场(CRF)
CRF的定义
条件随机场是在给定输入条件下对输出序列建模的无向模型。相比于HMM,CRF可以直接建模任意特征的依赖关系。
线性链CRF是最常用的形式:
势函数的参数化
通常使用指数线性形式:
其中 是特征函数, 是参数。
特征函数示例
def build_feature_functions():
"""
CRF特征函数示例
"""
features = []
# 状态特征:当前词性和观测
for y in ['NN', 'VB', 'JJ', ...]:
for word in vocabulary:
features.append(
lambda y_prev, y, X, t, y=y, word=word:
1 if y_prev == y and X[t] == word else 0
)
# 转移特征:词性转移
for y_prev in POS_tags:
for y in POS_tags:
features.append(
lambda y_prev, y, X, t:
1 if y_prev == y_prev and y == y else 0
)
return features配分函数的计算困境
配分函数的定义
计算复杂度
对于 个二元变量,配分函数涉及 项的求和,指数级复杂度!
与精确推断的联系
配分函数的计算等价于:
近似方法
对比散度训练(Contrastive Divergence)
最大似然学习的困难
学习能量模型需要最大化观测数据的对数似然:
梯度:
第一项可以从观测数据直接计算,第二项需要对 采样——这正是问题所在!
CD-k算法
Hinton提出的对比散度算法使用短链MCMC近似期望:
def contrastive_divergence(model, data, k=1, learning_rate=0.01):
"""
对比散度(CD-k)算法
使用k步Gibbs采样从当前模型生成样本
"""
# 第一项:从真实数据计算
positive_grad = compute_gradient_from_data(model, data)
# 第二项:从模型采样(CD-k)
# 初始化为真实数据
samples = data.clone()
# 运行k步Gibbs采样
for _ in range(k):
samples = gibbs_step(model, samples)
# 计算负相梯度
negative_grad = compute_gradient_from_data(model, samples)
# 梯度更新
grad = positive_grad - negative_grad
model.parameters -= learning_rate * grad
return grad
def gibbs_step(model, x):
"""
吉布斯采样一步
对于RBM可以交替更新可见层和隐藏层
"""
# 采样隐藏层
h_prob = model.hidden_activation(x)
h = (torch.rand_like(h_prob) < h_prob).float()
# 采样可见层
x_recon_prob = model.visible_activation(h)
x_recon = (torch.rand_like(x_recon_prob) < x_recon_prob).float()
return x_reconCD-k的理论分析
CD-k的性质:
- 通常就足够好
- 梯度是有偏的,但偏差随 增大而减小
- 比完整MCMC训练快得多
持续对比散度(PCD)
class PersistentCD(nn.Module):
"""
持久对比散度
维护一组"幻想粒子"持续采样
"""
def __init__(self, model, num_particles=100, visible_dim=784, hidden_dim=500):
super().__init__()
self.model = model
self.num_particles = num_particles
# 维护幻想粒子
self.particles = torch.randn(num_particles, visible_dim).sign() # 二值数据
def step(self, data_batch):
# 正相梯度
pos_grad = self.compute_grad(self.model, data_batch)
# 负相梯度:从幻想粒子采样
for _ in range(k_steps):
self.particles = self.gibbs_step(self.particles)
neg_grad = self.compute_grad(self.model, self.particles)
# 更新模型
grad = pos_grad - neg_grad
self.update_parameters(grad)
return grad.norm()
def gibbs_step(self, x):
h_prob = torch.sigmoid(x @ self.model.W + self.model.h_bias)
h = (torch.rand_like(h_prob) < h_prob).float()
x_prob = torch.sigmoid(h @ self.model.W.T + self.model.v_bias)
x = (torch.rand_like(x_prob) < x_prob).float()
return x能量模型与神经网络的融合
能量模型作为神经网络层
现代深度学习中,能量模型被嵌入到神经网络中:
class EnergyBasedLayer(nn.Module):
"""
基于能量的神经网络层
学习一个能量函数
"""
def __init__(self, input_dim, hidden_dim):
super().__init__()
self.energy_net = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 1) # 能量是标量
)
def forward(self, x):
"""
返回能量
"""
return self.energy_net(x)
def energy(self, x):
"""
计算样本的能量
"""
return self.forward(x)
def log_prob(self, x):
"""
计算对数概率(需要配分函数)
使用近似方法
"""
E = self.energy(x)
# 近似:使用JEM风格的能量归一化
return -E - self.log_Z_approx
def sample(self, num_samples, steps=100):
"""
从能量模型采样
使用MCMC
"""
samples = torch.randn(num_samples, self.input_dim)
samples.requires_grad = True
optimizer = torch.optim.SGD([samples], lr=1.0)
for step in range(steps):
optimizer.zero_grad()
energy = self.energy(samples)
# Langevin动态
energy.backward()
# 添加噪声(退火)
samples.grad += torch.randn_like(samples.grad) * 0.01
optimizer.step()
return samples.detach()联合能量模型(JEM)
class JEM(nn.Module):
"""
联合能量模型(JEM)
结合分类器和能量模型
"""
def __init__(self, classifier, energy_model):
super().__init__()
self.classifier = classifier
self.energy_model = energy_model
def forward(self, x):
"""
返回分类logits和能量
"""
logits = self.classifier(x)
energy = self.energy_model(x)
return logits, energy
def classify(self, x):
return self.classifier(x)
def log_prob(self, x):
"""
估计对数概率
"""
return -self.energy_model(x)
def train_step(self, x_real, y_real, x_fake=None):
"""
训练JEM
使用FiLM条件化分类器
"""
# 真实数据的对数似然
log_prob_real = self.log_prob(x_real)
# 分类损失
logits = self.classifier(x_real)
cls_loss = F.cross_entropy(logits, y_real)
# 能量正则化
energy_real = self.energy_model(x_real).mean()
# 如果有生成样本
if x_fake is not None:
log_prob_fake = self.log_prob(x_fake)
loss = -log_prob_real.mean() + cls_loss + 0.1 * energy_real
else:
loss = -log_prob_real.mean() + cls_loss + 0.1 * energy_real
return loss基于能量的生成模型
能量引导的扩散模型
能量函数可以引导扩散模型的采样过程:
class EnergyGuidedDiffusion(nn.Module):
"""
能量引导的扩散模型
在采样过程中使用能量函数引导
"""
def __init__(self, diffusion_model, energy_fn):
super().__init__()
self.diffusion = diffusion_model
self.energy = energy_fn
def energy_guided_sample(self, shape, num_steps=1000, guidance_scale=1.0):
"""
能量引导采样
"""
# 从纯噪声开始
x = torch.randn(shape, device=next(self.parameters()).device)
for t in reversed(range(num_steps)):
# 预测噪声
noise_pred = self.diffusion.predict_noise(x, t)
# 能量梯度引导
x.requires_grad = True
energy = self.energy(x)
energy_grad = torch.autograd.grad(energy.sum(), x)[0]
# 组合预测
guided_noise = noise_pred + guidance_scale * energy_grad
# 去噪步骤
x = self.diffusion.step(x, guided_noise, t)
return x.detach()图像建模中的应用
MRF用于图像去噪
class MRFImageDenoising(nn.Module):
"""
MRF图像去噪模型
能量函数包含:
- 数据项:观测与重建的一致性
- 平滑项:邻域像素的平滑性
"""
def __init__(self, num_neighbors=8):
super().__init__()
self.num_neighbors = num_neighbors
# 数据项参数
self.data_weight = 1.0
# 平滑项参数
self.smooth_weight = 0.5
def energy(self, x, y):
"""
计算MRF能量
Args:
x: 观测图像
y: 重建图像
Returns:
energy: 标量能量
"""
# 数据项:L2损失
E_data = self.data_weight * ((x - y) ** 2).sum()
# 平滑项:邻域差异
E_smooth = 0
for dy, dx in [(0, 1), (0, -1), (1, 0), (-1, 0),
(1, 1), (1, -1), (-1, 1), (-1, -1)]:
shifted = torch.roll(y, shifts=(dy, dx), dims=(0, 1))
E_smooth += ((y - shifted) ** 2).sum()
E_smooth = self.smooth_weight * E_smooth
return E_data + E_smooth
def gibbs_sampling(self, x_init, observed, num_steps=100):
"""
吉布斯采样去噪
"""
y = x_init.clone()
for _ in range(num_steps):
# 随机选择像素
i = torch.randint(0, y.shape[0], (1,)).item()
j = torch.randint(0, y.shape[1], (1,)).item()
# 计算每个可能值的能量
energies = []
for val in range(256): # 假设灰度图
y_test = y.clone()
y_test[i, j] = val
energies.append(self.energy(observed, y_test))
# 采样新值(玻尔兹曼分布)
energies = torch.tensor(energies)
probs = F.softmax(-energies, dim=0)
new_val = torch.multinomial(probs, 1).item()
y[i, j] = new_val
return y卷积MRF
class ConvolutionalMRF(nn.Module):
"""
卷积马尔可夫随机场
使用卷积定义邻域势函数
"""
def __init__(self, in_channels, hidden_channels, kernel_size=3):
super().__init__()
# 数据项网络
self.data_net = nn.Conv2d(in_channels, hidden_channels, 1)
# 平滑项网络(卷积势函数)
self.smooth_net = nn.Conv2d(
in_channels * 2,
hidden_channels,
kernel_size,
padding=kernel_size//2,
padding_mode='reflect'
)
# 能量输出
self.energy_head = nn.Conv2d(hidden_channels, 1, 1)
def forward(self, x):
"""
计算每个像素位置的能量
"""
# 数据项
data_energy = self.data_net(x) ** 2
# 平滑项:中心像素与邻域的差异
neighbors = F.pad(x, (1, 1, 1, 1), mode='replicate')
diff = x - neighbors
smooth_energy = self.smooth_net(diff) ** 2
# 总能量
energy = self.energy_head(data_energy + smooth_energy)
return energy与相关模型的关系
MRF vs 贝叶斯网络
| 特性 | MRF | 贝叶斯网络 |
|---|---|---|
| 图类型 | 无向 | 有向 |
| 分解形式 | 势函数乘积 | 条件概率乘积 |
| 归一化 | 配分函数 | 自然归一化 |
| 适用场景 | 对称依赖 | 因果关系 |
| 推断复杂度 | 通常更难 | 部分可分解 |
MRF vs 神经网络
| 特性 | MRF | 神经网络 |
|---|---|---|
| 表示形式 | 能量函数 | 层级特征 |
| 学习目标 | 最大似然 | 经验风险最小化 |
| 不确定性 | 自然概率解释 | 需要额外建模 |
| 可解释性 | 能量直观 | 特征重要性 |
能量模型 vs GAN
| 特性 | 能量模型 | GAN |
|---|---|---|
| 训练 | 对比散度等 | 对抗训练 |
| 采样 | MCMC | 生成器网络 |
| 损失函数 | 能量/似然 | 对抗损失 |
| 模式覆盖 | 理论保证 | 可能模式崩溃 |
与现有wiki内容的联系
| 主题 | 相关文件 |
|---|---|
| 条件随机场 | conditional-random-fields-sequence |
| 概率图模型 | probabilistic-graphical-models-comprehensive |
| 因子图与消息传递 | factor-graphs-belief-propagation-unified |
| 能量基础模型 | energy-based-models-deep-learning |
| MCMC采样 | mcmc-methods |
参考
相关阅读
- 条件随机场与序列建模 — NLP应用
- 马尔可夫网络 — 无向图模型基础
- 因子图与置信传播 — 推断算法
- 深度学习中的能量模型 — 现代EBM
- MCMC方法 — 采样技术
- 变分推断 — 近似推断方法
Footnotes
-
Koller, D., & Friedman, N. (2009). Probabilistic Graphical Models: Principles and Techniques. MIT Press. ↩