🎓 レベル:標準 | 重要度:A(必須)
📎 前提:モデル記述から推論まで | 関連:階層モデルの実例と再パラメータ化・収束診断
⚠️ 要最新確認:PyMC 6.0.1 / ArviZ 1.2.0 で検証。
要点(BLUF)
- PPL を使っても収束は保証されません。発散(divergence)・高い ・低い ESS が警告サイン。NUTS は漏斗のような難所で発散を報告します。
- 主な処方:非中心化(漏斗)・
target_acceptを上げる・弱情報事前にする・再パラメータ化。 - 実装で Neal の漏斗の**中心化(発散22・std 過小)→ 非中心化(発散0・std 回収)**を確かめます(階層モデルの実例と再パラメータ化 の PyMC 版)。
1. PPL でも詰まる
PPL は推論を自動化しますが、事後の幾何が悪ければ NUTS でも正しくサンプリングできません。階層モデルの漏斗(階層モデルの実例と再パラメータ化)が典型で、首の強い曲率でリープフロッグ積分が破綻します。違いは、NUTS がその破綻を発散として自己申告してくれること。だから「発散が出たら結果を疑う」が鉄則です。
2. 警告サインの読み方
| サイン | 意味 | 取得 |
|---|---|---|
| 発散(divergence) | 軌道が破綻した点。その近傍を探索できず推定が偏る | idata.sample_stats["diverging"].sum() |
| チェーン間が一致せず未収束(収束診断) | az.rhat(idata) | |
| 低い ESS | 相関が強く実質情報が少ない | az.ess(idata) |
| トレースの張り付き | 一部領域に閉じ込め | トレースプロット |
発散が数個でも出たら、その結果は信頼できません(特に裾・首を取りこぼす)。
3. コード:漏斗の発散を検出し、非中心化で解消する
Neal の漏斗(、)を PyMC で、中心化と非中心化で比べます。
import numpy as np, pymc as pm, arviz as az
D = 9
def run(centered):
with pm.Model() as m:
v = pm.Normal("v", 0, 3)
if centered:
x = pm.Normal("x", 0, pm.math.exp(v/2), shape=D) # 中心化(漏斗)
else:
z = pm.Normal("z", 0, 1, shape=D) # 非中心化
x = pm.Deterministic("x", pm.math.exp(v/2)*z) # x=exp(v/2)·z
idata = pm.sample(1500, tune=1500, chains=4, cores=1,
random_seed=0, progressbar=False, target_accept=0.9)
ndiv = int(idata.sample_stats["diverging"].values.sum())
vd = idata.posterior["v"].values.flatten()
return ndiv, vd.std(), float(az.rhat(idata)["v"].values), float(az.ess(idata)["v"].values)
print("真の周辺 v~N(0,3²):std(v)=3 を回収したい / 発散0が理想")
for centered, name in [(True, "中心化"), (False, "非中心化")]:
nd, sdv, rhat, ess = run(centered)
print(f" {name}: 発散={nd:>4} std(v)={sdv:.2f} r_hat(v)={rhat:.3f} ESS(v)={ess:.0f}")
出力:
真の周辺 v~N(0,3²):std(v)=3 を回収したい / 発散0が理想
中心化: 発散= 22 std(v)=2.21 r_hat(v)=1.043 ESS(v)=101
非中心化: 発散= 0 std(v)=3.01 r_hat(v)=1.002 ESS(v)=13326
出力の意味:中心化は発散 22 回・( 超で要注意)・ESS わずか で、 の std を と過小評価(首に入れず裾を取りこぼし)。非中心化に書き換えると発散 0・・ESS で、真の std を回収します。pm.Deterministic("x", exp(v/2)*z) の一行で幾何が直り、すべての診断が健全になりました。発散の有無が、結果を信じてよいかの最初の関門です。
4. トラブルシュート処方箋
発散・未収束が出たときの定番手順(上から試す):
- 非中心化:階層モデル・漏斗ならまずこれ(§3)。最も効くことが多い。
target_acceptを上げる(例 ):ステップ幅が小さくなり発散が減る。代わりに遅くなる。- 弱情報事前にする(無情報事前と弱情報事前):平坦すぎる事前は事後を病的にする。 に
HalfNormalなど。 - モデルの単位・スケールを揃える(標準化):極端なスケール差は幾何を悪くする。
- tune(ウォームアップ)を増やす:適応が足りないと未収束。
- それでもダメならモデルの再定式化(パラメータの取り方を変える)。
「発散が出たまま target_accept だけ上げて誤魔化す」のは危険——根本は幾何なので、非中心化など構造の修正を優先します。
⚠️ よくある誤解
- 「NUTS なら発散しない」ではない:漏斗・強相関で発散します。だから自己申告してくれる(§1)。
- 「発散が少しなら無視してよい」ではない:数個でも、その近傍(しばしば最も重要な裾)を取りこぼします。原因を潰します。
- 「
target_acceptを上げれば必ず直る」ではない:軽い発散は減らせますが、根本の幾何(漏斗)は非中心化が要る(§4)。 - 「 なら発散は気にしなくてよい」ではない: が良く見えても発散で裾を逃すことがある。発散・・ESS を全部確認します。
まとめ(Phase 9)
第9章では、手実装してきた推論を PPL で宣言的に書く方法を学びました——PPL の位置づけと閉形式との一致(確率的プログラミング概観)、モデルから事後予測までの一気通貫ワークフロー(モデル記述から推論まで)、そして発散の診断と非中心化による解消(本ノート)。第2〜8章の数理(共役・MCMC・階層・診断・再パラメータ化)が、PPL という実務の道具に結実しました。最終章では、関数・深層・ノンパラメトリックへ広がる発展トピックに触れます。
関連ノート
- モデル記述から推論まで
- 階層モデルの実例と再パラメータ化(非中心化の数理・本ノートは PyMC 版)
- 収束診断(R-hat・ESS の中身)
- ハミルトニアンモンテカルロとNUTS(発散が起きる仕組み)
- 第9章 確率的プログラミング 目次
- ベイズ統計テキスト 全体目次