web-dev-qa-db-ja.com

pymc3の推定パラメーターから予測を生成する

誰かが助けてくれるかどうか疑問に思っている一般的な問題に遭遇します。 pymc3を2つのモードで使用したいことがよくあります。トレーニング(つまり、実際にパラメーターに対して推論を実行する)と評価(つまり、推論されたパラメーターを使用して予測を生成する)です。

一般に、ポイントごとの見積もりだけでなく、予測よりも後向きにしたいと思います(これは、ベイズフレームワークの利点の一部ですよね?)。トレーニングデータが修正されると、これは通常、観測された変数に同様の形式のシミュレートされた変数を追加することによって実現されます。例えば、

_from pymc3 import *

with basic_model:

    # Priors for unknown model parameters
    alpha = Normal('alpha', mu=0, sd=10)
    beta = Normal('beta', mu=0, sd=10, shape=2)
    sigma = HalfNormal('sigma', sd=1)

    # Expected value of outcome
    mu = alpha + beta[0]*X1 + beta[1]*X2

    # Likelihood (sampling distribution) of observations
    Y_obs = Normal('Y_obs', mu=mu, sd=sigma, observed=Y)
    Y_sim = Normal('Y_sim', mu=mu, sd=sigma, shape=len(X1))

    start = find_MAP()
    step = NUTS(scaling=start)
    trace = sample(2000, step, start=start)
_

しかし、データが変更された場合はどうなりますか?新しいデータに基づいて予測を生成したいが、推論を繰り返し実行しないとしましょう。理想的には、predict_posterior(X1_new, X2_new, 'Y_sim', trace=trace)またはpredict_point(X1_new, X2_new, 'Y_sim', vals=trace[-1])のような関数があり、theano計算グラフを介して新しいデータを実行するだけです。

私の質問の一部は、pymc3がtheano計算グラフをどのように実装するかに関係していると思います。関数_model.Y_sim.eval_は私が望むものに似ているように見えますが、入力として_Y_sim_が必要であり、指定したものを返すだけのようです。

このプロセスは非常に一般的だと思いますが、それを行う方法が見つからないようです。どんな助けでも大歓迎です。 (pymc2でこれを行うためのハックがあることにも注意してください。pymc3ではtheanoのためにもっと難しいです。)

19
santon

注:この機能は、pymc.sample_ppcメソッドとしてコアコードに組み込まれるようになりました。詳細については、 ドキュメント を確認してください。

Twieckiから送られてきた link (2017年7月現在は無効)に基づいて、私の問題を解決するためのいくつかのトリックがあります。 1つ目は、トレーニングデータを共有theano変数に入れることです。これにより、theano計算グラフを台無しにすることなく、後でデータを変更できます。

X1_shared = theano.shared(X1)
X2_shared = theano.shared(X2)

次に、モデルを作成し、通常どおり推論を実行しますが、共有変数を使用します。

with basic_model:

    # Priors for unknown model parameters
    alpha = Normal('alpha', mu=0, sd=10)
    beta = Normal('beta', mu=0, sd=10, shape=2)
    sigma = HalfNormal('sigma', sd=1)

    # Expected value of outcome
    mu = alpha + beta[0]*X1_shared + beta[1]*X2_shared

    # Likelihood (sampling distribution) of observations
    Y_obs = Normal('Y_obs', mu=mu, sd=sigma, observed=Y)

    start = find_MAP()
    step = NUTS(scaling=start)
    trace = sample(2000, step, start=start)

最後に、開発中の関数(最終的にはpymc3に追加される可能性があります)があり、新しいデータの事後確率を予測できます。

from collections import defaultdict

def run_ppc(trace, samples=100, model=None):
    """Generate Posterior Predictive samples from a model given a trace.
    """
    if model is None:
         model = pm.modelcontext(model)

    ppc = defaultdict(list)
    for idx in np.random.randint(0, len(trace), samples):
        param = trace[idx]
        for obs in model.observed_RVs:
            ppc[obs.name].append(obs.distribution.random(point=param))

    return ppc

次に、予測を実行する新しいデータを渡します。

X1_shared.set_value(X1_new)
X2_shared.set_value(X2_new)

最後に、新しいデータの事後予測サンプルを生成できます。

ppc = run_ppc(trace, model=model, samples=200)

変数ppcは、モデルで観測された各変数のキーを含む辞書です。したがって、この場合、ppc['Y_obs']には配列のリストが含まれ、各配列はトレースからの単一のパラメーターセットを使用して生成されます。

トレースから抽出されたパラメータを変更することもできることに注意してください。たとえば、GaussianRandomWalk変数を使用するモデルがあり、将来の予測を生成したいと考えていました。 pymc3が将来的にサンプリングできるようにする(つまり、ランダムウォーク変数を発散させる)ことはできますが、最後に推測された値に対応する係数の固定値を使用したかっただけです。このロジックは、run_ppc関数で実装できます。

run_ppc関数は非常に遅いことにも言及する価値があります。実際の推論を実行するのと同じくらいの時間がかかります。これは、theanoの使用方法に関連する非効率性に関係していると思います。

編集:最初に含まれていたリンクは死んでいるようです。

11
santon

@santonからの上記の回答は正しいです。私はそれに追加しているだけです。

これで、独自のメソッドrun_ppcを作成する必要はありません。 pymc3は、同じことを行うsample_posterior_predictiveメソッドを提供します。

1
Ashok Rayal