从pymc3

时间:2015-10-21 00:43:02

标签: python pymc3

我遇到了一个常见的问题,我想知道是否有人可以提供帮助。我经常想在两种模式下使用pymc3:训练(即实际运行参数推断)和评估(即使用推断参数来生成预测)。

总的来说,我想要一个后验过度预测,而不仅仅是逐点估计(这是贝叶斯框架的一部分,不是吗?)。当您的训练数据得到修复时,通常可以通过将类似形式的模拟变量添加到观察变量来实现。例如,

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中有一个hack这样做;因为theano,它在pymc3中更难。)

2 个答案:

答案 0 :(得分:9)

注意:此功能现在作为pymc.sample_ppc方法包含在核心代码中。查看the docs了解详情。

根据twiecki发给我的link(2017年7月去世),有一些技巧可以解决我的问题。第一种是将训练数据放入共享的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']将包含一个数组列表,每个数组都是使用trace中的一组参数生成的。

请注意,您甚至可以修改从跟踪中提取的参数。例如,我有一个使用GaussianRandomWalk变量的模型,我想在未来生成预测。虽然你可以允许pymc3对未来进行采样(即允许随机游走变量发散),但我只想使用与最后推断值对应的系数的固定值。该逻辑可以在run_ppc函数中实现。

值得一提的是run_ppc功能非常慢。它需要与运行实际推理一样多的时间。我怀疑这与使用theano的一些低效率有关。

编辑:最初包含的链接似乎已经死了。

答案 1 :(得分:0)

@santon的以上回答是正确的。我只是补充。

现在,您无需编写自己的方法run_ppcpymc3提供了sample_posterior_predictive的方法。