能否在不加载原始模型到内存中的情况下,加载PyMC3跟踪并访问其值?

12

我仍在学习如何使用PyMC3,希望文档中已经涵盖了这些基础知识。基本思路是组合模型、采样生成后验分布并保存链。如果我按照Backends页面的建议来读取链(如trace = pm.backends.text.load('test_txt')),则会出现TypeError: No context on context stack的错误。我期望的是,通过指定保存好的数据库文件,text.load方法可以返回包含所有跟踪数值的numpy数组,也就是说,数据库应该包含访问链数值所需的所有信息。

经过一番搜索,我在PyMC3中只找到一个加载跟踪的示例,可以在这里找到,该示例显示使用与创建跟踪时相同的模型变量来加载跟踪。如果我想要编写一个脚本来运行我的链,并编写另一个脚本来加载和分析跟踪,则似乎唯一的方法是在两个文件中都使用相同的命令初始化模型。然而,这样做可能会在文件之间创建不一致的情况,因为我必须手动保持模型相同。

以下是从PyMC入门页面中获取的示例,其中演示了如何保存链。我将下面的代码保存在一个简短的脚本中:

import numpy as np
import pymc3 as pm
from scipy import optimize

# Initialize random number generator
np.random.seed(123)

# True parameter values
alpha, sigma = 1, 1
beta = [1, 2.5]

# Size of dataset
size = 100

# Predictor variable
X1 = np.random.randn(size)
X2 = np.random.randn(size) * 0.2

# Simulate outcome variable
Y = alpha + beta[0]*X1 + beta[1]*X2 + np.random.randn(size)*sigma

basic_model = pm.Model()

with basic_model:
    # Priors for unknown model parameters
    alpha = pm.Normal('alpha', mu=0, sd=10)
    beta = pm.Normal('beta', mu=0, sd=10, shape=2)
    sigma = pm.HalfNormal('sigma', sd=1)

    # Expected value of outcome
    mu = alpha + beta[0]*X1 + beta[1]*X2

    # Likelihood (sampling distribution) of observations
    Y_obs = pm.Normal('Y_obs', mu=mu, sd=sigma, observed=Y)

    # obtain starting values via MAP
    start = pm.find_MAP(fmin=optimize.fmin_powell)

    # instantiate sampler
    step = pm.Slice(vars=[sigma])

    # instantiate database
    db = pm.backends.Text('so_save')

    # draw 5000 posterior samples
    trace = pm.sample(5000, step=step, start=start, trace=db)

然后运行这些下一行(在Python CLI中或在单独的脚本中)会得到:

trace = pm.backends.text.load('so_save')
# TypeError: No context on context stack

trace = pm.backends.text.load('so_save', model=pm.Model())
print trace
print trace.varnames
# <MultiTrace: 1 chains, 5000 iterations, 0 variables>
# []

# run same first 36 lines from the big code block above
trace = pm.backends.text.load('so_save', model=basic_model)
print trace
print trace.varnames
# <MultiTrace: 1 chains, 5000 iterations, 4 variables>
# ['alpha', 'beta', 'sigma_log_', 'sigma']

为了更好的动力/背景,我正在尝试用几种略微不同的方式建模相同的数据。我希望在磁盘上为每个模型生成漂亮的长链,只需要生成一次就可以了。然后我可以玩弄比较它们的方法,并考虑我想分析轨迹的方式。

2个回答

16

简短回答:

使用此代码保存跟踪信息

import pickle # python3
import cPickle as pickle # python 2

with open('my_model.pkl', 'wb') as buff:
    pickle.dump({'model': basic_model, 'trace': trace}, buff)

然后这样重新加载:

with open('my_model.pkl', 'rb') as buff:
    data = pickle.load(buff)  

basic_model, trace = data['model'], data['trace']

长答案:

关于弃用后端的讨论已经有一段时间了——在存储需要长时间运行并且可能超出内存限制的跟踪上下文中,它们非常有用。使用持久性后端可以恢复已经完成的工作。哈密顿采样器更加高效,因此较短的跟踪就足够了,因此自2016年以来,磁盘上的后端没有得到太多开发时间。

加载不受信任的pickle文件存在一定的危险(如果您正在本地运行事物,则不是问题),因此重新思考PyMC3的持久性变得越来越重要,但是以上内容现在应该还有效。


你的意思是需要重新审视PyMC3项目或Python pickling的持久性吗? - nbrunett

0

为了在pymc3中保存和重新加载跟踪,您可以使用以下方法:pymc3.save_trace()pymc3.load_trace()。或者,您也可以使用“pickle”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接