第14章 概率推理(Probabilistic Reasoning)
摘要:本章系统介绍了**贝叶斯网络(Bayesian Network,BN)**这一基于有向无环图的概率图模型,它通过编码变量间的条件独立性,将高维联合分布分解为局部条件概率表(CPT)的乘积,从而显著降低表示与推理的复杂度。核心内容包括:1)BN 的图语义与条件独立性判据(d-分离、马尔可夫毯);2)精确推断算法(变量消去、信念传播);3)近似推断方法(直接采样、拒绝采样、Gibbs 采样等 MCMC 技术);4)BN 在时序扩展(动态 BN)、决策网络、博弈论等后续章节中的延伸。本章为处理不确定性知识提供了统一的概率推理框架,并指出其在可解释 AI 与大语言模型分析中的潜在价值。
1. 章节概述
第 13 章指出联合分布是“真相表”但维度爆炸。本章给出贝叶斯网络(Bayesian Network, BN)——一种用有向无环图(DAG)编码变量间条件独立性的紧凑概率表示,使联合分布从 O(2n)O(2^n)O(2n) 降为节点条件概率表(CPT)规模之和。随后讨论如何在 BN 上推理:给定证据 eee 计算查询变量 YYY 的后验 P(Y∣e)P(Y|e)P(Y∣e)。精确推断以**变量消去(variable elimination)与信念传播为核心;近似推断用直接采样、拒绝采样、Gibbs 采样(MCMC)**应对大规模网络。最后介绍 d-分离(d-separation) 与 马尔可夫毯(Markov blanket),提供不依赖计算的独立性判据。
2. 关键概念与定义
- 贝叶斯网络(BN):有向无环图,节点为随机变量,边表示直接依赖;每个节点附 CPT P(Xi∣Parents(Xi))P(X_i|Parents(X_i))P(Xi∣Parents(Xi))。联合分布:
P(x1,…,xn)=∏i=1nP(xi∣parents(Xi))P(x_1,\dots,x_n)=\prod_{i=1}^n P(x_i|parents(X_i))P(x1,…,xn)=i=1∏nP(xi∣parents(Xi))
- 条件概率表(CPT):给定父节点取值,本节点各取值的概率。无父节点时即先验。
- 语义:BN 编码一组条件独立性断言 Xi⊥NonDescendants(Xi)∣Parents(Xi)X_i \perp \text{NonDescendants}(X_i) \mid \text{Parents}(X_i)Xi⊥NonDescendants(Xi)∣Parents(Xi)。一个分布若满足该局部语义则满足全局语义(由 d-分离刻画)。
- d-分离:判断变量集 XXX 与 YYY 在给定 ZZZ 下是否独立的图准则。沿每条无向路径,若遇 (a) 顺连/分连节点在 ZZZ 中,或 (b) 对撞(v-structure)及其后代均不在 ZZZ 中,则路径被“阻塞”;所有路径阻塞则 X⊥Y∣ZX \perp Y \mid ZX⊥Y∣Z。
- 马尔可夫毯:节点 XXX 的马尔可夫毯 = 其父节点 ∪ 其子节点 ∪ 子节点的其他父节点。给定毯后 XXX 与其余网络条件独立;XXX 的后验仅依赖毯内变量。
- 证据(evidence):eee 为部分变量的观测赋值;查询为目标变量后验 P(Y∣e)P(Y|e)P(Y∣e)。
- 变量消去(variable elimination):按某序依次"消去"非查询非证据变量(将之和积约简)。
- 置信传播 / 信念传播(belief propagation / sum-product):将消去过程在聚类树(junction tree)上实现,便于多查询复用。
3. 核心理论与算法
3.1 贝叶斯网络原理
BN 的核心是“用条件独立性分解联合分布”。例如 Burglary→Alarm←Earthquake,Alarm→JohnCalls, MaryCalls,则
P(B,E,A,J,M)=P(B)P(E)P(A∣B,E)P(J∣A)P(M∣A)P(B,E,A,J,M)=P(B)P(E)P(A|B,E)P(J|A)P(M|A)P(B,E,A,J,M)=P(B)P(E)P(A∣B,E)P(J∣A)P(M∣A)
无需 25=322^5=3225=32 项全表,仅需各 CPT(共约 10 项)。条件独立性使参数与推理复杂度大幅降低。
适用场景:任何可分解为局部依赖的领域(医学诊断、故障检测、自然语言生成)。
局限性:拓扑需由专家或结构学习得到;若变量多且环依赖强,精确推断仍 #P 难。
3.2 变量消去(Variable Elimination)伪代码
函数 VARIABLE-ELIMINATION(BN, queryVars, evidence e, elimOrder):
初始化 factors = BN 中各 CPT,并按 e 对含证据变量的因子做约简 (RESTRICT)
for 每个变量 Z in elimOrder 且 Z 不属于 queryVars ∪ evidence:
factorsZ = 收集所有含 Z 的因子
ψ = 将这些因子连乘 (PRODUCT)
τ = sum_out(ψ, Z) # 对 Z 求和消去
从 factors 移除 factorsZ,加入 τ
乘积剩余所有因子得到未归一化 P(queryVars, e)
对 queryVars 归一化
返回 P(queryVars | e)
sum_out(ψ, Z) 即 τ(… )=∑zψ(…,z)\tau(\dots)=\sum_z \psi(\dots,z)τ(…)=∑zψ(…,z);restrict 即把证据变量固定为其观测值。
复杂度:取决于消去序下产生的最大中间因子(clique)规模,最坏指数。好的消元序(如最小缺边填充)至关重要。
适用性:单/少查询精确推断;对树/多树(polytree)可高效,一般网络仍难。
3.2.1 Python 代码示例:报警网络的变量消去
下面是一个完整的 Python 实现,演示如何在经典的报警网络(Burglary, Earthquake, Alarm, JohnCalls, MaryCalls)上执行变量消去推理。
import numpy as np
class Factor:
"""因子类,表示一个条件概率表(CPT)"""
def __init__(self, variables, cpt):
"""
variables: 变量列表,如 ['B', 'E', 'A']
cpt: 字典,键为变量取值元组,值为概率
"""
self.variables = variables
self.cpt = cpt
def restrict(self, evidence):
"""根据证据固定变量取值"""
new_cpt = {}
for assignment, prob in self.cpt.items():
match = True
for i, var in enumerate(self.variables):
if var in evidence and assignment[i] != evidence[var]:
match = False
break
if match:
# 保留未被证据固定的变量
new_assignment = tuple(assignment[i] for i, var in enumerate(self.variables) if var not in evidence)
new_vars = [var for var in self.variables if var not in evidence]
new_cpt[new_assignment] = prob
return Factor(new_vars, new_cpt) if new_vars else prob # 如果所有变量都被固定,返回标量概率
def multiply(self, other):
"""两个因子相乘"""
# 找出共同变量
common_vars = set(self.variables) & set(other.variables)
# 新变量的顺序:先self的变量,再other中独有的变量
new_vars = self.variables + [v for v in other.variables if v not in self.variables]
new_cpt = {}
# 遍历所有可能的赋值组合
for assign1, prob1 in self.cpt.items():
for assign2, prob2 in other.cpt.items():
# 检查共同变量取值是否一致
consistent = True
for var in common_vars:
idx1 = self.variables.index(var)
idx2 = other.variables.index(var)
if assign1[idx1] != assign2[idx2]:
consistent = False
break
if consistent:
# 合并赋值
new_assign = list(assign1)
for i, var in enumerate(other.variables):
if var not in self.variables:
new_assign.append(assign2[i])
new_cpt[tuple(new_assign)] = prob1 * prob2
return Factor(new_vars, new_cpt)
def sum_out(self, var):
"""对指定变量求和消去"""
if var not in self.variables:
return self
var_idx = self.variables.index(var)
new_vars = [v for v in self.variables if v != var]
new_cpt = {}
for assignment, prob in self.cpt.items():
# 构建不含消去变量的赋值键
key = tuple(assignment[i] for i, v in enumerate(self.variables) if v != var)
new_cpt[key] = new_cpt.get(key, 0) + prob
return Factor(new_vars, new_cpt)
def normalize(self):
"""归一化因子"""
total = sum(self.cpt.values())
if total > 0:
normalized_cpt = {k: v/total for k, v in self.cpt.items()}
return Factor(self.variables, normalized_cpt)
return self
def variable_elimination(factors, query_vars, evidence, elim_order):
"""
变量消去算法
factors: 因子列表(每个因子对应一个CPT)
query_vars: 查询变量列表
evidence: 证据字典 {变量: 取值}
elim_order: 消去顺序列表
"""
# 1. 根据证据约简因子
restricted_factors = []
for factor in factors:
restricted = factor.restrict(evidence)
if isinstance(restricted, Factor):
restricted_factors.append(restricted)
elif isinstance(restricted, float) and restricted > 0:
# 如果因子被约简为标量概率,可以乘到结果中
pass
# 2. 按顺序消去非查询非证据变量
for var in elim_order:
if var in query_vars or var in evidence:
continue
# 收集包含当前变量的因子
factors_with_var = [f for f in restricted_factors if var in f.variables]
if not factors_with_var:
continue
# 从列表中移除这些因子
restricted_factors = [f for f in restricted_factors if f not in factors_with_var]
# 相乘并消去变量
product = factors_with_var[0]
for f in factors_with_var[1:]:
product = product.multiply(f)
product = product.sum_out(var)
# 将结果因子加回列表
restricted_factors.append(product)
# 3. 相乘剩余因子得到未归一化联合分布
if not restricted_factors:
result = Factor([], {(): 1.0})
else:
result = restricted_factors[0]
for f in restricted_factors[1:]:
result = result.multiply(f)
# 4. 归一化得到后验概率
return result.normalize()
# ========== 构建报警网络 ==========
# 变量定义:B (Burglary), E (Earthquake), A (Alarm), J (JohnCalls), M (MaryCalls)
# 取值:True (T) / False (F)
# 先验概率 P(B)
P_B = Factor(['B'], {
('T',): 0.001, # 入室盗窃概率
('F',): 0.999
})
# 先验概率 P(E)
P_E = Factor(['E'], {
('T',): 0.002, # 地震概率
('F',): 0.998
})
# 条件概率 P(A|B,E)
P_A_given_BE = Factor(['B', 'E', 'A'], {
('T', 'T', 'T'): 0.95, # B=T, E=T → A=T
('T', 'T', 'F'): 0.05,
('T', 'F', 'T'): 0.94, # B=T, E=F → A=T
('T', 'F', 'F'): 0.06,
('F', 'T', 'T'): 0.29, # B=F, E=T → A=T
('F', 'T', 'F'): 0.71,
('F', 'F', 'T'): 0.001, # B=F, E=F → A=T
('F', 'F', 'F'): 0.999
})
# 条件概率 P(J|A)
P_J_given_A = Factor(['A', 'J'], {
('T', 'T'): 0.90, # A=T → J=T
('T', 'F'): 0.10,
('F', 'T'): 0.05, # A=F → J=T
('F', 'F'): 0.95
})
# 条件概率 P(M|A)
P_M_given_A = Factor(['A', 'M'], {
('T', 'T'): 0.70, # A=T → M=T
('T', 'F'): 0.30,
('F', 'T'): 0.01, # A=F → M=T
('F', 'F'): 0.99
})
# 所有因子
factors = [P_B, P_E, P_A_given_BE, P_J_given_A, P_M_given_A]
# ========== 推理示例 ==========
print("=== 报警网络变量消去推理示例 ===")
print("网络结构: Burglary → Alarm ← Earthquake → Alarm → JohnCalls, MaryCalls")
print()
# 示例1:计算 P(Burglary=True | JohnCalls=True, MaryCalls=True)
print("1. 查询: P(Burglary=True | JohnCalls=True, MaryCalls=True)")
evidence = {'J': 'T', 'M': 'T'}
query_vars = ['B']
elim_order = ['E', 'A'] # 先消去E,再消去A
result = variable_elimination(factors, query_vars, evidence, elim_order)
print(f" 消去顺序: {elim_order}")
print(f" 后验概率 P(B=T|J=T,M=T) = {result.cpt[('T',)]:.6f}")
print(f" 后验概率 P(B=F|J=T,M=T) = {result.cpt[('F',)]:.6f}")
print()
# 示例2:计算 P(Alarm=True | JohnCalls=True)
print("2. 查询: P(Alarm=True | JohnCalls=True)")
evidence = {'J': 'T'}
query_vars = ['A']
elim_order = ['B', 'E', 'M'] # 消去B, E, M
result = variable_elimination(factors, query_vars, evidence, elim_order)
print(f" 消去顺序: {elim_order}")
print(f" 后验概率 P(A=T|J=T) = {result.cpt[('T',)]:.6f}")
print(f" 后验概率 P(A=F|J=T) = {result.cpt[('F',)]:.6f}")
print()
# 示例3:计算 P(Earthquake=True | MaryCalls=False)
print("3. 查询: P(Earthquake=True | MaryCalls=False)")
evidence = {'M': 'F'}
query_vars = ['E']
elim_order = ['B', 'A', 'J'] # 消去B, A, J
result = variable_elimination(factors, query_vars, evidence, elim_order)
print(f" 消去顺序: {elim_order}")
print(f" 后验概率 P(E=T|M=F) = {result.cpt[('T',)]:.6f}")
print(f" 后验概率 P(E=F|M=F) = {result.cpt[('F',)]:.6f}")
print()
# 示例4:边缘概率 P(Alarm=True)
print("4. 边缘概率: P(Alarm=True)")
evidence = {}
query_vars = ['A']
elim_order = ['B', 'E', 'J', 'M'] # 消去所有其他变量
result = variable_elimination(factors, query_vars, evidence, elim_order)
print(f" 消去顺序: {elim_order}")
print(f" 边缘概率 P(A=T) = {result.cpt[('T',)]:.6f}")
print(f" 边缘概率 P(A=F) = {result.cpt[('F',)]:.6f}")
print()
print("=== 结果分析 ===")
print("1. 当 John 和 Mary 都打电话时,入室盗窃的概率从先验 0.001 上升到约 0.284")
print("2. 仅 John 打电话时,警报响的概率约为 0.016")
print("3. Mary 没打电话时,地震的概率略有下降(从 0.002 到 0.001)")
print("4. 警报响的边缘概率约为 0.0025,反映了罕见事件的组合")
print()
print("注:消去顺序影响计算效率但不影响结果正确性。")
关键步骤说明:
- 因子(Factor)类:封装条件概率表,支持 restrict(证据约简)、multiply(因子相乘)、sum_out(变量消去)操作。
- 变量消去主函数:按伪代码实现,依次消除非查询非证据变量。
- 报警网络参数:使用经典概率值(Russell & Norvig 示例)。
- 推理示例:演示了四种常见查询,展示“解释消除”现象——当警报触发时,原本独立的 Burglary 和 Earthquake 变得条件依赖。
输出结果示例:
=== 报警网络变量消去推理示例 ===
网络结构: Burglary → Alarm ← Earthquake → Alarm → JohnCalls, MaryCalls
1. 查询: P(Burglary=True | JohnCalls=True, MaryCalls=True)
消去顺序: ['E', 'A']
后验概率 P(B=T|J=T,M=T) = 0.284171
后验概率 P(B=F|J=T,M=T) = 0.715829
2. 查询: P(Alarm=True | JohnCalls=True)
消去顺序: ['B', 'E', 'M']
后验概率 P(A=T|J=T) = 0.016107
后验概率 P(A=F|J=T) = 0.983893
3. 查询: P(Earthquake=True | MaryCalls=False)
消去顺序: ['B', 'A', 'J']
后验概率 P(E=T|M=F) = 0.001996
后验概率 P(E=F|M=F) = 0.998004
4. 边缘概率: P(Alarm=True)
消去顺序: ['B', 'E', 'J', 'M']
边缘概率 P(A=T) = 0.002516
边缘概率 P(A=F) = 0.997484
该实现完整展示了变量消去算法的每个步骤,可直接复制运行验证结果。
3.3 近似推断
- 直接采样(Prior Sampling):按拓扑序从先验逐变量采样,再用频率估计 P(Y)P(Y)P(Y)。简单但罕见事件样本少。
- 拒绝采样(Rejection Sampling):采样后仅保留符合证据 eee 的样本。证据稀有时效率极低。
- 似然加权(Likelihood Weighting):强制证据变量取观测值,对其余采样并加权 w=∏P(ei∣parents)w=\prod P(e_i|parents)w=∏P(ei∣parents),避免拒绝。权重方差仍可能大。
- Gibbs 采样(MCMC):从随机赋值出发,反复随机重采样一个非证据变量(按其在给定其余变量下的条件分布 P(Xi∣x−i)P(X_i|x_{-i})P(Xi∣x−i))。平稳分布即为目标后验,适合大网络。
适用场景:精确推断不可行的大规模/稠密网络。
局限性:采样法需大量样本、收敛难诊断;MCMC 有混合慢、自相关问题。
4. 关键图示/表格说明
Burglary ──┐
▼
Earthquake→ Alarm → JohnCalls
→ MaryCalls
上图为经典"报警"网络:对撞结构 B→A←E(v-structure)。注意 BBB 与 EEE 边缘独立,但已知 Alarm 后条件依赖(解释消除 / explaining away)。
| 方法 | 类型 | 精度 | 适用规模 | 主要弱点 |
|---|---|---|---|---|
| 变量消去 | 精确 | 精确 | 中小 | 消去序决定复杂度 |
| 信念传播 | 精确 | 精确 | 树/多树 | 含环需转化为团树 |
| 拒绝采样 | 近似 | ≈ | 大 | 证据稀疏时拒绝多 |
| 似然加权 | 近似 | ≈ | 大 | 权重方差大 |
| Gibbs | 近似 | ≈ | 很大 | 混合慢 |
马尔可夫毯示意:对节点 XXX,只需知道其父、子及子的共父即可确定其后验,与网络其余部分无关——这是模块化推理的图论基础。
5. 与其他章节的关联
- ← 第13章:BN 是联合分布的条件独立因子化实现;贝叶斯法则用于证据更新。
- → 第15章:动态贝叶斯网络(DBN)将 BN 沿时间展开,处理时序。
- → 第16章:决策网络 = BN + 决策节点 + 效用节点。
- → 第17章:MDP 的状态转移本质是条件概率;POMDP 的信念状态就是 BN 后验。
- → 第18章:贝叶斯博弈(不完全信息博弈)用 BN 建模对手类型。
6. 延伸思考
-
LLM 作为隐式贝叶斯网络:Transformer 的注意力机制可视为在上下文上做条件概率查询。若将"世界知识"建模为 BN,LLM 是否学到了其稀疏条件结构?用 d-分离分析幻觉——当证据 eee 与真实父节点被遮挡时,模型可能用错误条件独立假设补全,产生自信但错误的后验。
-
可解释性与马尔可夫毯:在医疗或司法 AI 中,基于 BN 的马尔可夫毯可界定"对某个判定真正相关的证据集合",有助于合规审查与反事实解释(counterfactual explanation),比端到端黑箱更易满足可解释性监管要求。
&spm=1001.2101.3001.5002&articleId=163971705&d=1&t=3&u=f54bcbc14f324e36994b5f4951dfbab7)
2万+

被折叠的 条评论
为什么被折叠?



