Mímisbrunnr知恵の泉

← ベイズ統計 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:モデル記述から推論まで | 関連:階層モデルの実例と再パラメータ化収束診断

⚠️ 要最新確認:PyMC 6.0.1 / ArviZ 1.2.0 で検証。

要点(BLUF)

1. PPL でも詰まる

PPL は推論を自動化しますが、事後の幾何が悪ければ NUTS でも正しくサンプリングできません。階層モデルの漏斗(階層モデルの実例と再パラメータ化)が典型で、首の強い曲率でリープフロッグ積分が破綻します。違いは、NUTS がその破綻を発散として自己申告してくれること。だから「発散が出たら結果を疑う」が鉄則です。

2. 警告サインの読み方

サイン意味取得
発散(divergence)軌道が破綻した点。その近傍を探索できず推定が偏るidata.sample_stats["diverging"].sum()
R^>1.01\hat R>1.01チェーン間が一致せず未収束(収束診断az.rhat(idata)
低い ESS相関が強く実質情報が少ないaz.ess(idata)
トレースの張り付き一部領域に閉じ込めトレースプロット

発散が数個でも出たら、その結果は信頼できません(特に裾・首を取りこぼす)。

3. コード:漏斗の発散を検出し、非中心化で解消する

Neal の漏斗(vN(0,32)v\sim\mathcal N(0,3^2)xiN(0,ev)x_i\sim\mathcal N(0,e^{v}))を 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 回R^=1.043\hat R=1.0431.011.01 超で要注意)・ESS わずか 101101 で、vv の std を 2.212.21過小評価(首に入れず裾を取りこぼし)。非中心化に書き換えると発散 0R^=1.002\hat R=1.002・ESS 1332613326 で、真の std 3.03.0 を回収します。pm.Deterministic("x", exp(v/2)*z) の一行で幾何が直り、すべての診断が健全になりました。発散の有無が、結果を信じてよいかの最初の関門です。

4. トラブルシュート処方箋

発散・未収束が出たときの定番手順(上から試す):

  1. 非中心化:階層モデル・漏斗ならまずこれ(§3)。最も効くことが多い。
  2. target_accept を上げる(例 0.90.950.990.9\to0.95\to0.99):ステップ幅が小さくなり発散が減る。代わりに遅くなる。
  3. 弱情報事前にする(無情報事前と弱情報事前):平坦すぎる事前は事後を病的にする。σ\sigmaHalfNormal など。
  4. モデルの単位・スケールを揃える(標準化):極端なスケール差は幾何を悪くする。
  5. tune(ウォームアップ)を増やす:適応が足りないと未収束。
  6. それでもダメならモデルの再定式化(パラメータの取り方を変える)。

「発散が出たまま target_accept だけ上げて誤魔化す」のは危険——根本は幾何なので、非中心化など構造の修正を優先します。

⚠️ よくある誤解

まとめ(Phase 9)

第9章では、手実装してきた推論を PPL で宣言的に書く方法を学びました——PPL の位置づけと閉形式との一致(確率的プログラミング概観)、モデルから事後予測までの一気通貫ワークフロー(モデル記述から推論まで)、そして発散の診断と非中心化による解消(本ノート)。第2〜8章の数理(共役・MCMC・階層・診断・再パラメータ化)が、PPL という実務の道具に結実しました。最終章では、関数・深層・ノンパラメトリックへ広がる発展トピックに触れます。

関連ノート