如何在pymc3中创建容器

时间:2016-04-15 18:26:22

标签: 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中的新采样器能帮助我使用这个模型。我试图将贝叶斯方法应用于单分子实验。

2 个答案:

答案 0 :(得分:1)

不是在循环中创建许多单独的正态分布的1-D变量,而是可以进行自定义分布(通过扩展Continuous),该分布知道用于计算整个路径的对数可能性的公式。您可以从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)

这应该更快地运行很多

答案 1 :(得分:0)

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

# 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处进行编译。我正在运行Ubuntu的相当快的PC(24Gb RAM)上运行。我尝试使用GPU,但运行速度稍慢。我怀疑是内存问题,因为它在运行时使用了99.8%的内存。我和Stan一起尝试了相同的计算,只需要2分钟就可以运行。