【问题标题】:PyMC: sampling step by step?PyMC:逐步采样?
【发布时间】:2014-03-23 10:10:59
【问题描述】:

我想知道为什么采样器在逐步采样时速度非常慢。 例如,如果我运行:

mcmc = MCMC(model)
mcmc.sample(1000)

采样速度很快。但是,如果我运行:

mcmc = MCMC(model)
for i in arange(1000):
    mcmc.sample(1)

采样速度较慢(采样越多,速度越慢)。

如果您想知道我为什么要问这个.. 好吧,我需要逐步采样,因为我想在采样器的每一步之后对变量的值执行一些操作。

有没有办法加快速度?

提前谢谢你!

------------------ 编辑 ---------------------------- ----------------------------------

这里我更详细地介绍了具体问题:

我有两个模型在竞争,它们是一个更大模型的一部分,该模型有一个分类变量作为两者之间的“开关”。

在这个玩具示例中,我有观察到的向量“Y”,可以用泊松或几何分布来解释。分类变量“switch_model”在 = 0 时选择几何模型,在 =1 时选择泊松模型。

在每个样本之后,如果 switch_model 选择几何模型,我希望泊松模型的变量不要更新,因为它们不会影响可能性,因此它们只是逐渐消失。如果 switch_model 选择 Poisson 模型,则相反。

基本上,我在每个步骤中所做的就是通过手动将其后退一步来“更改”未选择模型的值。

我希望我的解释和注释代码足够清楚。如果您需要更多详细信息,请告诉我。

import numpy as np
import pymc as pm
import pandas as pd
import matplotlib.pyplot as plt

# OBSERVED VALUES
Y = np.array([0, 1, 2, 3, 8])

# PRIOR ON THE MODELS
pi = (0.5, 0.5)

switch_model = pm.Categorical("switch_model", p = pi) 
# switch_model = 0 for Geometric, switch_model = 1 for Poisson

p = pm.Uniform('p', lower = 0, upper = 1) # Prior of the parameter of the geometric distribution
mu = pm.Uniform('mu', lower = 0, upper = 10) # Prior of the parameter of the Poisson distribution


# LIKELIHOOD
@pm.observed
def Ylike(value = Y, mu = mu, p = p, M = switch_model):
    if M == 0:
        out = pm.geometric_like(value+1, p)
    elif M == 1:
        out = pm.poisson_like(value, mu)
    return out

model = pm.Model([Ylike, p, mu, switch_model])

mcmc = pm.MCMC(model)

n_samples = 5000

traces = {}
for var in mcmc.stochastics:
    traces[str(var)] = np.zeros(n_samples)


bar = pm.progressbar.progress_bar(n_samples)
bar.update(0)

mcmc.sample(1, progress_bar=False)
for var in mcmc.stochastics:
    traces[str(var)][0] = mcmc.trace(var)[-1]


for i in np.arange(1,n_samples):
    mcmc.sample(1, progress_bar=False)
    bar.update(i)
    for var in mcmc.stochastics:
        traces[str(var)][i] = mcmc.trace(var)[-1]
    if mcmc.trace('switch_model')[-1] == 0: # Gemetric wins
        traces['mu'][i] = traces['mu'][i-1] # One step back for the sampler of the Poisson parameter
        mu.value = traces['mu'][i-1]

    elif mcmc.trace('switch_model')[-1] == 1: # Poisson wins
        traces['p'][i] = traces['p'][i-1] # One step back for the sampler of the Geometric parameter
        p.value = traces['p'][i-1]

print '\n\n'

traces=pd.DataFrame(traces)

traces['mu'][traces['switch_model'] == 0] = np.nan
traces['p'][traces['switch_model'] == 1] = np.nan

print traces.describe()

traces.plot()
plt.show()

【问题讨论】:

    标签: pymc mcmc


    【解决方案1】:

    之所以这么慢,是因为 Python 的 for 循环非常慢,尤其是与 FORTRAN 循环相比时(PyMC 基本上是用它编写的。)如果您可以显示更详细的代码,它可能是更容易看到您正在尝试做什么并提供更快的替代算法。

    【讨论】:

    • 感谢您的回复。我添加了一个玩具示例来解释我的问题。澄清一下,在 for 循环中,mcmc.sample(1) 之后的所有操作根本不需要太多时间。基本上删除它们只会减少 10% 的时间,这与 for 循环的时间长度相比是微不足道的样本(10000)
    • 我猜更改 mu.value 和 p.value 会改变下一次调用 mcmc.sample 的结果?
    • 是的,确实如此。由于采样器是马尔可夫链,因此更改 mu.value 和 p.value 确实会影响对 mcmc.sample 的下一次调用
    • 所以,由于每个样本的结果都依赖于前一个样本的结果,因此您不能使用 mcmc.sample(5000) 来加快速度。如果您将循环强制为列表理解,您可能可以加快一点速度,但是当涉及到您的算法时,老实说,我对统计数据了解得不够多,无法说明如何更改它。
    • 是的,很遗憾我不能使用 mcmc.sample(5000) 出于这个原因。一种解决方法可能是告诉采样器不要在“switch_model”是几何时从“mu”中采样,如果“switch_model”是泊松时不要从p中采样。但我不知道如何做到这一点.. 还是谢谢你!
    【解决方案2】:

    实际上,我找到了一个“疯狂”的解决方案,我怀疑它为什么会起作用。我仍然想就我的把戏获得专家意见。

    基本上,如果我按以下方式修改 for 循环,每 1000 个循环添加一个“重置 mcmc”,采样就会再次启动:

    for i in np.arange(1,n_samples):
        mcmc.sample(1, progress_bar=False)
        bar.update(i)
        for var in mcmc.stochastics:
            traces[str(var)][i] = mcmc.trace(var)[-1]
        if mcmc.trace('switch_model')[-1] == 0: # Gemetric wins
            traces['mu'][i] = traces['mu'][i-1] # One step back for the sampler of the Poisson parameter
            mu.value = traces['mu'][i-1]
    
        elif mcmc.trace('switch_model')[-1] == 1: # Poisson wins
            traces['p'][i] = traces['p'][i-1] # One step back for the sampler of the Geometric parameter
            p.value = traces['p'][i-1]
    
        if i%1000 == 0:
            mcmc = pm.MCMC(model)
    

    在实践中,此技巧每 1000 步擦除采样器的轨迹和数据库。看起来采样器不喜欢长数据库,虽然我不太明白为什么。 (当然1000步是任意的,太短会增加太多开销,太长会导致trace和数据库太长)。

    我觉得这个 hack 有点疯狂,而且绝对不优雅。有任何专家或开发人员对此发表评论吗?谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-23
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多