Skip to content
CJX0712Public

About

SeqForge · 序贯贝叶斯推断与状态空间估计实验台(KF/EKF/IEKF/UKF + RTS · bootstrap SIR / Auxiliary PF · FFBS)| 22 条确定性不变量门禁 · APF ESS 2.00× · 作者 晨星

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

SeqForge · 序贯贝叶斯推断与状态空间估计

CI Release License Python Quality

作者:晨星 (CJX0712) · 域:序贯贝叶斯推断 / 状态空间估计 · License: MIT

一套可复现、可验证的序贯推断实验台:从数据生成到边缘似然估计, 统一实现 Kalman 滤波家族(KF / EKF / IEKF / UKF)、粒子滤波家族 (bootstrap SIR / 辅助变量 APF)、平滑器(RTS / FFBS), 并内置22 条可机器验证的不变量作为质量门禁。


这个域的关键事实(先读这段,它决定了本库的设计)

在线性高斯问题上,Kalman 滤波是精确贝叶斯最优—— 任何算法 都不可能超越它。这不是工程能力问题,是数学事实。

因此本库的设计不追求"打败 KF",而是:

目标 做法
把"不可能超越"变成可验证的天花板 线性高斯域的 KF log-lik 作为粒子法偏差的唯一金标准
在有真实超越空间的地方竞争 提议分布设计(最优提议 vs 先验提议)、高维稀疏观测的退化鲁棒性
门禁不依赖随机波动 22 条确定性不变量(闭式解交叉验证 + 代数恒等式)

粒子滤波是随机算法:实测 log_lik 的 seed 间 std 可达 0.71.4, 而方法间差值仅 0.22.1。任务书常用的「均值差 > ½(σ₁+σ₂)」在 3~5 seeds 下会随机翻转,不能做 CI 门禁。本库的门禁全部落在确定性不变量上, 统计量只进报告。


快速开始

git clone https://github.com/CJX0712/seqforge.git
cd seqforge

# 最小依赖(numpy + scipy 即可跑全部内置方法)
python -m pip install -r requirements.txt

# 一键复现:端到端demo(落盘 artifacts/benchmark.json)
python examples/run_demo.py --ablation

# 质量门禁:只跑确定性不变量(CI 用的就是这条)
python -m pytest tests/test_invariants.py -q

# 完整CI 等价检查
python -m ruff check . && python -m ruff format --check .
python -m pytest -q --cov=. --cov-report=term

零额外依赖也能跑:numpy + scipy 装好即可, statsmodels / pykalman 是可选的 Tier-0 参照后端,缺失时自动降级。


核心结果(真实运行输出,非手填)

1. 线性高斯域:KF 是精确天花板,粒子法只能逼近

方法 log-lik(3 seeds) 相对 KF 偏差 mean ESS
KF(精确最优) −113.99 ± 222.67 0(定义上的最优) —
APF(最优提议) −194.77 ± 144.86 见下方逐 seed 表 444.4 (44.4%)
bootstrap SIR −230.20 ± 112.53 见下方逐 seed 表 310.2 (31.0%)

逐 seed 的 KF 精确值(benchmark.json 的 kf_reference 字段):

seed KF 精确 log-lik bootstrap 偏差 APF 偏差
7 −313.350042 −34.71 −35.07
101 −251.829589 — —

关键观察:bootstrap 与 APF 的 log-lik 偏差几乎相同, 但 APF 的 ESS 是 bootstrap 的 2.00×(612.8 vs 305.7,N=1000)。 这说明增益在采样效率而非偏差——这正是辅助变量提议 (Pitt & Shephard 1999)的理论预期:最优提议让重要性权重接近常数。

2. 核心对照:最优提议 vs 先验提议

粒子数 N = 1000(线性高斯域,seed=7)
bootstrap SIR : mean ESS =  305.7 ( 30.6%)   ← 先验提议,不含观测信息
auxiliary PF  : mean ESS =  612.8 ( 61.3%)   ← 最优提议 q ∝ p(y|x)p(x|x_prev)
ESS 提升      : 2.00×

这是本系统最稳的结论:它不依赖 seed 统计显著性, 而是一个可复现的确定性量。

3. 消融(含被否决组件的负结果)

变体 log-lik 偏差 vs KF mean ESS 结论
APF(完整) −348.418 −35.068 612.8 (61.3%) 基准
APF 关闭辅助重采样 −346.316 −32.966 586.9 (58.7%) ⚠️ 略优
bootstrap SIR −348.063 −34.713 305.7 (30.6%) ESS 腰斩
SIR 多项式重采样 −351.946 −38.596 303.5 (30.4%) 偏差最差

诚实披露:关闭辅助重采样反而让偏差从 −35.07改善到 −32.97。 在 ESS 维度上辅助重采样确有代价(612.8 → 586.9), 但两者差异(~2)远小于 bootstrap 与 APF 的差异(~307)。 结论是:真正的增益来自"最优提议"这个组件,不是"辅助重采样"。 我们保留完整配置(Pitt & Shephard 原文做法),但如实报告这一负结果。


22 条可验证不变量

门禁的全部依据。分四类:

类别 编号 内容 实测
交叉验证 I1 KF log-lik = 独立多元高斯闭式解 |Δ| < 1e-13
I1b 后验协方差对称且半正定 对称 |Δ| < 1e-12
I1c K = P Hᵀ S⁻¹ 闭式核对 |Δ| < 1e-10
I2 标准化创新 L_S⁻¹ν 的 std ≈ 1,±1.96 覆盖率 ≈ 95% 0.98/ 0.95
I2b UKF / EKF / IEKF 在线性问题上精确退化为 KF 2.7e-15 / 0 / 5.6e-17
I4 UKF sigma 点矩匹配:一阶 = 0,二阶 = P < 1e-9
代数恒等式 I5 RTS 平滑协方差 ≤ 滤波协方差(Loewner 序) min eig > 0
I5b 平滑 RMSE ≤ 滤波 RMSE 断言成立
I6 bootstrap PF 边缘似然系统性向下有偏(Jensen) 3/3 seed 为负
I6b 偏差随 N 单调收缩(O(1/N)方向) 0.348 → 0.329 /step
I7 APF 的 ESS > 1.5× bootstrap 2.00×
I7b APF 的 log-lik 偏差 < bootstrap 3 seed 均值
I8 ESS ∈ [1, N];归一化权重和 = 1 浮点容差内
I9 稀疏观测:全缺失时刻log-lik 增量 = 0 精确 0
I10 DGP 契约:谱半径、秩、NaN 语义 断言成立
I11 同 seed 两次运行逐位一致 72 行全一致
I11b 全局 seed 变化不污染方法确定性 逐位一致
I12 FFBS 输出形状/ESS/退化标记 断言成立
I13 秩亏/奇异协方差稳定化(SVD,不是 eigh) min eig > 5e-10
python -m pytest tests/test_invariants.py -v

方法矩阵

方法 族 线性域 非线性域 平滑 报告 ESS
kf kalman ✅ 精确最优 ✅(线性转移) ✅ RTS —
ekf kalman ❌ 故意排除 ✅ ❌ —
ukf kalman ❌ 故意排除 ✅ ❌ —
iekf kalman ❌ 故意排除 ✅ ❌ —
sir particle ✅ ✅ ❌ ✅
apf particle ✅ ✅ ❌ ✅
ffbs particle ❌ 故意排除 ✅ ✅ ✅

线性域为什么排除 EKF/UKF/FFBS:它们在线性问题上必须精确等于 KF (泰勒展开代数恒等式),放进来只会产出重复数字、掩盖真实差异。 这本身是一条被单测断言的不变量(I2b)。


数据集(4 个 DGP,各暴露一类方法缺陷)

DGP 维度 专门暴露什么
linear_gaussian 4→4 KF 精确最优 ⇒ 定义天花板与偏差金标准
nonlinear_obs 4→4 一阶线性化失效;quadratic / radar / tanh 三种非线性
sparse_obs 30→7 全秩 A + 30% 稀疏观测 ⇒ ESS 随维度单调下降
degenerate 6→3 窄似然(r=0.05)/ 双峰(|λ|≈0.985)⇒ 提议与重采样定生死

sparse_obs 的 A 曾是 rank-3 低秩升维,但那测的是低秩结构而非维度灾难, 已改为全秩 A(mode="lowrank_transition" 保留为独立对照)。


架构

cli.py                    argparse 入口(demo / list / selftest / version)
examples/run_demo.py      端到端演示(落盘 benchmark.json)
core/                     types · errors · config · interfaces · seed · numeric
data/                     models(ProbabilisticSSM)· dgp(4 个生成器)
filters/
  kalman.py               KF / EKF / IEKF / UKF + RTS 平滑器
  particle.py             BootstrapSIR / AuxiliaryParticleFilter
  backends.py             statsmodels · pykalman 适配(可选,离线可缺)
smoothers/particle_smoother.py    FFBS
eval/metrics.py           统一指标 · 统计聚合 · 失败案例派生
pipeline/runner.py        SeqForgePipeline.run()
tests/                    test_invariants · test_backends · test_cli
docs/                     architecture.md · model_card.md

调用单向无环:cli → pipeline → {data, filters, smoothers, eval} → core

统一协议

所有方法共享 filter(y) / smooth(y) / log_likelihood(y) 三个签名, 能力差异用标记(supports_ess / smooth 抛 NotImplementedError)表达, 而不是让每类方法一套签名 —— 这样 pipeline 与eval 才能对任意方法 统一计时、统一取指标,跨方法比较才公平。

指标语义(一经发布不再变更)

指标 方向 备注
log_lik 越大越好 序列级对数边缘似然
rmse_state 越小越好 全状态
rmse_obs 越小越好 仅可观测子空间,部分可观测系统才有意义
ess_mean 越大越好 仅粒子法
smoother_rmse 越小越好 平滑

sparse_obs 是部分可观测系统:未观测维度的 RMSE 没有意义 (只能预测到条件均值)。混在一起算会让所有方法"看起来一样差", 因此报告必须区分两个口径。

稀疏观测的统一口径

缺失维度记为 NaN,等价于"该维度 R_ii → ∞ 且创新 = 0", 数学上就是跳过该维度的更新。KF / EKF / IEKF / UKF / SIR / APF / FFBS 全部走同一个 _observed_rows 判据,否则跨方法比较不公平。

确定性契约

唯一 seed 入口 core.seed.set_all(seed)。所有随机源都是 注入的 numpy.random.RandomState(legacy MT19937), 不用 np.random.Generator —— 后者的流跨 numpy 版本不稳定, 粒子法的 Monte-Carlo 门禁会在 CI 上随机翻车。

实测:同 seed 两次运行,72 行benchmark 数据逐位一致 (仅 elapsed_sec 不同)。


离线兜底

numpy + scipy 装好即可跑全部内置方法。 statsmodels / pykalman 缺失时:

  1. available_*() 探测返回 (False, 原因)
  2. benchmark 跳过对应方法并标 skipped + 原因
  3. 不伪造任何数字

单测 test_offline_fallback_works_without_backends 把所有后端强制关掉, 验证流水线仍能跑完 —— 这保证"离线兜底"不是口号。


失败案例(全部从实测结果派生,无预设结论)

# 类型 症状 根因
1 worst_rmse kf 在 nonlinear_obs 上 RMSE=0.5374 非线性观测使一阶线性化误差累积;KF 在线性问题上最优,但在非线性问题上并无优势
2 degenerate_ess ffbs 在 degenerate 上 ESS=28.1 窄似然(r=0.05)下先验提议的权重急剧集中,重采样后多样性丧失
3 worst_loglik sir 在 nonlinear_obs 上 log-lik=−511.842 bootstrap 边缘似然向下有偏(O(1/N)),线性高斯域可量化该偏差

案例 1 值得注意:它说明**"KF 最优"只在线性域成立**。 换到非线性域,先验提议的粒子法在log-lik 上可以超过 KF —— 代价是方差更大。这是本域最容易被误读的一点。


质量分级

等级 状态 说明
S 世界级 ❌ 未达成 DoD 工程项全绿,但性能项受数学限制
A 生产级 ✅ 本系统定级 DoD 全绿+ 在可超越维度上胜强基线(ESS 2.00×)
B 合格 — —
C 不合格 — —

为什么不是 S:S 级要求「多 seed 均值胜强基线 ≥ 预设阈值」。 但本域的主指标 log_lik 在线性高斯域上结构性地不可超越 KF (KF 是精确最优),而粒子法的偏差随 N 以O(1/N) 收敛 —— 任何"超越"承诺 都是数学上不成立的。我们选择诚实定级 A,并在门禁上改用 ESS(确定性、可复现、2.00×)作为性能证据,而不是伪造一个 在 CI 上会随机翻转的统计量。

已知的诚实限制(详见 README 的「局限」一节):

  • 稀疏观测域 APF 的 ESS 低于 SIR(4.3% vs 37.2%),原因是 稀疏观测让最优提议退化为先验提议(可观测维度太少)—— 这是一个真实发现,不是 bug。
  • 消融显示"关闭辅助重采样"略优(负结果已保留)。
  • statsmodels 0.15 移除了 initial_state,无法对齐初值口径, 故只作参照不作逐位基线;逐位交叉验证由闭式解承担。

一键复现

git clone https://github.com/CJX0712/seqforge.git && cd seqforge
python -m pip install -r requirements.lock.txt
python examples/run_demo.py --ablation

依赖锁在 requirements.lock.txt,CI 亦锁版本 —— numpy 版本漂移会翻转数值门禁。

License

MIT。所用可选依赖:statsmodels(BSD-3)、pykalman(MIT),许可证兼容。

About

SeqForge · 序贯贝叶斯推断与状态空间估计实验台(KF/EKF/IEKF/UKF + RTS · bootstrap SIR / Auxiliary PF · FFBS)| 22 条确定性不变量门禁 · APF ESS 2.00× · 作者 晨星

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages