178 lines
6.0 KiB
Typst
Executable File
178 lines
6.0 KiB
Typst
Executable File
#import "labtemplate.typ": *
|
||
#show: nudtlabpaper.with(
|
||
author: "程景愉",
|
||
id: "202302723005",
|
||
title: "贝叶斯网络编程实验",
|
||
training_type: "普通本科生",
|
||
grade: "2023级",
|
||
major: "网络工程",
|
||
department: "计算机学院",
|
||
advisor: "祝恩",
|
||
jobtitle: "教授",
|
||
lab: "306-707",
|
||
date: "2025.12.31",
|
||
header_str: "贝叶斯网络编程实验报告",
|
||
simple_cover: true,
|
||
)
|
||
|
||
#set page(header: [
|
||
#set par(spacing: 6pt)
|
||
#align(center)[#text(size: 11pt)[人工智能实验报告]]
|
||
#v(-0.3em)
|
||
#line(length: 100%, stroke: (thickness: 1pt))
|
||
],)
|
||
|
||
#show heading: it => if it.level == 1 [
|
||
#v(1em)
|
||
#set text(font: hei, size: 16pt)
|
||
#it.body
|
||
#v(0.5em)
|
||
] else [
|
||
#v(0.8em)
|
||
#set text(font: "New Computer Modern", weight: "bold", style: "italic")
|
||
#it.body
|
||
#v(0.5em)
|
||
]
|
||
|
||
#set heading(numbering: none)
|
||
|
||
|
||
#outline(title: "目录",depth: 2, indent: 1em)
|
||
|
||
#set enum(indent: 0.5em,body-indent: 0.5em,)
|
||
#pagebreak()
|
||
|
||
= 实验介绍
|
||
#para[
|
||
本次实验旨在实现并比较两种贝叶斯网络近似推理算法:拒绝采样(Rejection Sampling)和似然加权(Likelihood Weighting)。
|
||
实验使用的贝叶斯网络模型包含四个布尔变量:Cloudy (C), Sprinkler (S), Rain (R), WetGrass (W)。
|
||
网络结构为 $C \to S, C \to R, S \to W, R \to W$。
|
||
实验目标是根据给定的条件概率表(CPTs),在已知证据 $S=T$ 和 $W=T$ 的情况下,估计 $R=T$ 的后验概率 $P(R=T | S=T, W=T)$。
|
||
]
|
||
|
||
= 实验内容
|
||
#para[
|
||
实验主要包含以下内容:
|
||
]
|
||
+ 根据题目描述的贝叶斯网络结构和条件概率表,构建数据结构表示该网络。
|
||
+ 实现拒绝采样算法:从先验分布中采样,拒绝与证据不一致的样本,利用保留样本中查询变量的频率作为后验概率的估计。
|
||
+ 实现似然加权算法:固定证据变量的值,对非证据变量进行采样,并根据证据变量的条件概率计算样本权重,利用加权频率估计后验概率。
|
||
+ 比较两种算法在不同采样数量(N=100, 1000, ...)下的估计结果与真实值的偏差,分析算法收敛性。
|
||
|
||
= 实验情况
|
||
+ 使用 Python 语言实现算法。
|
||
+ 代码需清晰易读,包含必要的注释。
|
||
+ 计算并输出 $P(R=T | S=T, W=T)$ 的精确值以便对比。
|
||
+ 撰写实验报告,展示核心代码和实验结果。
|
||
|
||
= 实验步骤与实现
|
||
|
||
== 网络定义与概率表
|
||
首先定义网络的条件概率表(CPTs)。
|
||
```python
|
||
# CPTs
|
||
P_C = {True: 0.5, False: 0.5}
|
||
|
||
# P(S | C)
|
||
P_S_given_C = {
|
||
True: {True: 0.10, False: 0.90}, # C=T
|
||
False: {True: 0.50, False: 0.50} # C=F
|
||
}
|
||
|
||
# P(R | C)
|
||
P_R_given_C = {
|
||
True: {True: 0.80, False: 0.20}, # C=T
|
||
False: {True: 0.20, False: 0.80} # C=F
|
||
}
|
||
|
||
# P(W | S, R)
|
||
P_W_given_SR = {
|
||
(True, True): {True: 0.99, False: 0.01},
|
||
(True, False): {True: 0.90, False: 0.10},
|
||
(False, True): {True: 0.90, False: 0.10},
|
||
(False, False): {True: 0.00, False: 1.00}
|
||
}
|
||
```
|
||
|
||
== 拒绝采样 (Rejection Sampling)
|
||
拒绝采样通过生成先验分布的样本,并丢弃那些与证据不符的样本来工作。
|
||
```python
|
||
def rejection_sampling(query_var, query_val, evidence, num_samples):
|
||
consistent_count = 0
|
||
query_match_count = 0
|
||
|
||
for _ in range(num_samples):
|
||
sample = get_prior_sample() # 从联合分布采样
|
||
|
||
# 检查样本是否与证据一致
|
||
is_consistent = True
|
||
for var, val in evidence.items():
|
||
if sample[var] != val:
|
||
is_consistent = False
|
||
break
|
||
|
||
if is_consistent:
|
||
consistent_count += 1
|
||
if sample[query_var] == query_val:
|
||
query_match_count += 1
|
||
|
||
if consistent_count == 0: return 0.0
|
||
return query_match_count / consistent_count
|
||
```
|
||
|
||
== 似然加权 (Likelihood Weighting)
|
||
似然加权强制证据变量取观测值,并将样本权重设为证据变量在其父节点给定情况下的似然概率乘积。
|
||
```python
|
||
def likelihood_weighting(query_var, query_val, evidence, num_samples):
|
||
weighted_counts = {True: 0.0, False: 0.0}
|
||
|
||
for _ in range(num_samples):
|
||
weight = 1.0
|
||
sample = {}
|
||
|
||
# 以 C, S, R, W 的拓扑顺序采样/赋值
|
||
# 若变量在证据中,则赋值为证据值并更新权重
|
||
# 若变量不在证据中,则根据父节点采样
|
||
# (代码细节略,参见附件源程序)
|
||
# ...
|
||
|
||
# 累加权重
|
||
weighted_counts[sample[query_var]] += weight
|
||
|
||
total_weight = sum(weighted_counts.values())
|
||
if total_weight == 0: return 0.0
|
||
return weighted_counts[query_val] / total_weight
|
||
```
|
||
|
||
= 实验结果
|
||
#para[
|
||
首先通过精确计算(枚举联合概率分布)得到理论真实值:
|
||
$P(R=T | S=T, W=T) approx 0.320388$
|
||
]
|
||
|
||
#para[
|
||
下表展示了在不同采样数量 $N$ 下,两种算法的估计结果:
|
||
]
|
||
|
||
#table(
|
||
columns: (auto, auto, auto),
|
||
inset: 10pt,
|
||
align: center,
|
||
[*样本数量 N*], [*拒绝采样结果*], [*似然加权结果*],
|
||
[100], [0.480000], [0.377902],
|
||
[1000], [0.353741], [0.311148],
|
||
[10000], [0.320734], [0.317552],
|
||
[100000], [0.318791], [0.321722],
|
||
[1000000], [0.319916], [0.319471],
|
||
)
|
||
|
||
= 实验总结
|
||
|
||
+ *收敛性*:从实验结果可以看出,随着采样数量 $N$ 的增加,拒绝采样和似然加权算法的结果都逐渐收敛于真实值 $0.320388$。
|
||
|
||
+ *算法比较*:
|
||
- *拒绝采样*:实现简单,直接利用先验分布采样。但在证据概率较低时(本例中证据发生的概率约为 0.278,尚可),会拒绝大量样本,导致计算资源浪费。在样本量较小(如 N=100)时波动较大。
|
||
- *似然加权*:利用了证据信息,所有生成的样本都是有效的(权重不为0),因此在相同采样数量下,通常能提供比拒绝采样更稳定的估计,尤其是当证据发生概率很低时优势更明显。
|
||
|
||
+ *结论*:两种算法均能有效进行近似推理。对于本实验中的简单网络和非极端概率证据,两者在 $N=10000$ 以上时均能给出较好的估计结果。
|