使用确定性分布的PyMC3代码中的AssertionError

时间:2017-09-13 15:12:39

标签: python theano pymc pymc3 mcmc

过去几天我一直在努力习惯PyMC最终从我直接编码的一些模型中做一些MCMC的分布抽样(我最终对参数估计感兴趣)。

据我所知,没有那么多人展示他们的代码(如外部C或FORTRAN代码),他们成功地使用PyMC3。到目前为止,我发现了herehere信息贿赂。

因此,从简单的问题开始,我尝试用PyMC3重现现有Python代码的一些结果,这些代码使用'复杂'(读取:比文档示例更多)不使用PyMC的分布来执行MCMC,即这个简单的result我的笔记本电脑上的10000个样本在2秒内运行。

要在PyMC3中定义确定性变量,应该使用@theano.compile.ops.as_op装饰器(在PyMC中它是@deterministic,现在在PyMC3中已弃用),这就是我所做的。

这是我的代码(我使用Spyder和IPython),受到PyMC documentation的启发,我在第二个单元格之后遇到AssertionError(在估算过程中,所以在采样之前)。 我过去两天一直试图解决这个问题,但我真的不明白错误是什么。我相信它应该是某种PyMC或Theano技巧,我还没有抓到,因为我相信我真的很接近。

#%% Define model
import numpy,math
import matplotlib.pyplot as plt
import random as random

import theano.tensor as t
import theano

random.seed(1)  # set random seed

# copy-pasted function from the specific model used in the source and adapted with as_op 
@theano.compile.ops.as_op(itypes=[t.iscalar, t.dscalar, t.fscalar, t.fscalar],otypes=[t.dvector])
def sampleFromSalpeter(N, alpha, M_min, M_max):        
    log_M_Min = math.log(M_min)
    log_M_Max = math.log(M_max)
    maxlik = math.pow(M_min, 1.0 - alpha)
    Masses = []
    while (len(Masses) < N):            
        logM = random.uniform(log_M_Min,log_M_Max)
        M    = math.exp(logM)            
        likelihood = math.pow(M, 1.0 - alpha)            
        u = random.uniform(0.0,maxlik)
        if (u < likelihood):
            Masses.append(M)
    return Masses

# SAME function as above, used to make test data (so no Theano here)
def sampleFromSalpeterDATA(N, alpha, M_min, M_max):        
    log_M_Min = math.log(M_min)
    log_M_Max = math.log(M_max)        
    maxlik = math.pow(M_min, 1.0 - alpha)        
    Masses = []        
    while (len(Masses) < N):            
        logM = random.uniform(log_M_Min,log_M_Max)
        M    = math.exp(logM)            
        likelihood = math.pow(M, 1.0 - alpha)            
        u = random.uniform(0.0,maxlik)
        if (u < likelihood):
            Masses.append(M)
    return Masses

# Generate toy data.
N      = 1000000  # Draw 1 Million stellar masses.
alpha  = 2.35
M_min  = 1.0
M_max  = 100.0
Masses = sampleFromSalpeterDATA(N, alpha, M_min, M_max)

#%% Estimation process
import pymc3 as pm
basic_model = pm.Model()
with basic_model:

    # Priors for unknown model parameters
    alpha2 = pm.Normal('alpha2', mu=3, sd=10)

    N2=t.constant(1000000)
    M_min2  = t.constant(1.0)
    M_max2  = t.constant(100.0)

    # Expected value of outcome
    m =  sampleFromSalpeter(N2, alpha2, M_min2, M_max2)

    # Likelihood (sampling distribution) of observations
    Y_obs = pm.Normal('Y_obs', mu=m, sd=10, observed=Masses)

#%% Sample
with basic_model:
    step = pm.Metropolis()
    trace = pm.sample(10000, step=step)

#%% Plot posteriors
_ = pm.traceplot(trace)
pm.summary(trace)

1 个答案:

答案 0 :(得分:0)

我在Discourse of PyMC得到了答案。我确实非常接近,因为我只需要更改函数定义的最后一行以返回[numpy.array(Masses)]。

现在,似乎这段代码需要大约300小时才能运行(而不是没有PyMC的原始实现中的2秒),我想知道是否有人知道它为什么这么慢? 我实际上早先尝试过非常简单的发行版并使用as_op,并注意到一个相当大的减速但是甚至没有这么多。 我猜原始代码直接在logp上运行,是不是它有什么区别呢?