如何在pymc3中创建容器

How to create a container in pymc3

我正在尝试为 Langevin 方程(谐波势中的布朗粒子)的特定结果的似然函数建立模型:

这是我在 pymc2 中似乎有效的模型: https://github.com/hstrey/BayesianAnalysis/blob/master/Langevin%20simulation.ipynb

#define the model/function to be fitted.
def model(x): 
    t = pm.Uniform('t', 0.1, 20, value=2.0)
    A = pm.Uniform('A', 0.1, 10, value=1.0)

    @pm.deterministic(plot=False)
    def S(t=t):
       return 1-np.exp(-4*delta_t/t)

    @pm.deterministic(plot=False)
    def s(t=t):
       return np.exp(-2*delta_t/t)

    path = np.empty(N, dtype=object)

    path[0]=pm.Normal('path_0',mu=0, tau=1/A, value=x[0], observed=True)
    for i in range(1,N):
        path[i] = pm.Normal('path_%i' % i,
                        mu=path[i-1]*s,
                        tau=1/A/S,
                        value=x[i],
                        observed=True)
        return locals()

mcmc = pm.MCMC( model(x) )
mcmc.sample( 20000, 2000, 10 )

基本思想是每个点都依赖于链(马尔可夫链)中的前一个点。顺便说一句,x是一个数据数组,N是它的长度,delta_t是时间步长=0.01。知道如何在 pymc3 中实现这个吗?我试过了:

# define the model/function for diffusion in a harmonic potential
DHP_model = pm.Model()
with DHP_model:
    t = pm.Uniform('t', 0.1, 20)
    A = pm.Uniform('A', 0.1, 10)

    S=1-pm.exp(-4*delta_t/t)

    s=pm.exp(-2*delta_t/t)

    path = np.empty(N, dtype=object)

    path[0]=pm.Normal('path_0',mu=0, tau=1/A, observed=x[0])
    for i in range(1,N):
        path[i] = pm.Normal('path_%i' % i,
                        mu=path[i-1]*s,
                        tau=1/A/S,
                        observed=x[i])

不幸的是,我一尝试 运行 模型就崩溃了。我在我的机器上尝试了一些 pymc3 示例(教程),这很有效。

提前致谢。我真的希望 pymc3 中的新采样器能帮助我处理这个模型。我正在尝试将贝叶斯方法应用于单分子实验。

因为我没有看到我的问题的答案,所以让我自己回答。我提出了以下解决方案:

# now lets model this data using pymc
# define the model/function for diffusion in a harmonic potential
DHP_model = pm.Model()
with DHP_model:
    D = pm.Gamma('D',mu=mu_D,sd=sd_D)
    A = pm.Gamma('A',mu=mu_A,sd=sd_A)

    S=1.0-pm.exp(-2.0*delta_t*D/A)

    ss=pm.exp(-delta_t*D/A)

    path=pm.Normal('path_0',mu=0.0, tau=1/A, observed=x[0])
    for i in range(1,N):
        path = pm.Normal('path_%i' % i,
                        mu=path*ss,
                        tau=1.0/A/S,
                        observed=x[i])

    start = pm.find_MAP()
    print(start)
    trace = pm.sample(100000, start=start)

不幸的是,此代码需要 6 小时到 2 天的时间来编译 N=50。我 运行正在一台速度相当快的 PC (24Gb RAM) 运行正在 Ubuntu。我尝试使用 GPU,但 运行 速度稍慢。我怀疑内存问题,因为它在 运行ning 时使用了 99.8% 的内存。我用 Stan 尝试了相同的计算,只需 2 分钟即可达到 运行.

无需在循环中创建许多单独的正态分布的一维变量,您可以创建自定义分布(通过扩展 Continuous),该分布知道用于计算整个路径的对数似然的公式。您可以 bootstrap 这个似然公式脱离 pymc3 已经知道的正态似然公式。有关示例,请参阅 the built-in AR1 class

因为你的粒子遵循马尔可夫属性,你的可能性看起来像

import theano.tensor as T

def logp(path):
    now = path[1:]
    prev = path[:-1]

    loglik_first = pm.Normal.dist(mu=0., tau=1./A).logp(path[0])
    loglik_rest = T.sum(pm.Normal.dist(mu=prev*ss, tau=1./A/S).logp(now))
    loglik_final = loglik_first + loglik_rest

    return loglik_final

我猜您想在每个时间步都为 ss 绘制一个值,在这种情况下您应该确保指定 ss = pm.exp(..., shape=len(x)-1),以便 prev*ss 在上面的块被解释为逐元素乘法。

然后你可以用

指定你的观察结果
path = MyLangevin('path', ..., observed=x)

这应该运行快很多