No U-Turn采样器(NUTS)的PyMC3性能问题:使用简单模型每秒少于2次迭代

时间:2017-10-27 14:26:07

标签: python theano pymc3

我试图了解以下代码的问题:

import pymc3 as pm
import theano as t

X = t.shared(train_new)
features = list(map(str, range(train_new.shape[1])))
with pm.Model() as logistic_model:
    glm = pm.glm.GLM(X, targets, labels=features,
                     intercept=False, family='binomial')
    trace = pm.sample(3000, tune=3000, jobs=-1)

数据集并不重要:它的形状为(891, 13)。以下是我自己总结的结论:

  • 问题肯定不是硬件,因为我的笔记本电脑和c4.2xlarge AWS实例的性能相同;
  • 它不能是theano.shared,因为如果我删除它,性能又是一样的;
  • 问题似乎不在pymc3.glm.GLM中,因为当我手动构建模型时(可能比GLM中的模型更简单),性能同样糟糕:

    with pm.Model() as logistic_model:
        invlogit = lambda x: 1 / (1 + pm.math.exp(-x))
        σ = pm.HalfCauchy('σ', beta=2)
        β = pm.Normal('β', 0, sd=σ, shape=X.get_value().shape[1])
        π = invlogit(tt.dot(X, β))
        likelihood = pm.Bernoulli('likelihood', π, observed=targets)
    

从约200 it/s开始,很快就会降至5 it/s。半采样后,它进一步减少到2 it/s左右。这是一个严重的问题,因为该模型几乎没有收集成千上万的样本。我需要执行比这种情况目前更多的样本。

这是日志:

Auto-assigning NUTS sampler...
Initializing NUTS using jitter+adapt_diag...
 99%|█████████▊| 5923/6000 [50:00<00:39,  1.97it/s]

我尝试使用pm.Metropolis()作为步骤,它有点快,但它并没有收敛。

MWE :一个显示问题的最小工作示例的文件,数据在此处: https://gist.github.com/rubik/74ddad91317b4d366d3879e031e03396

1 个答案:

答案 0 :(得分:4)

模型的非居中版本应该可以更好地运作:

β_raw = pm.Normal('β_raw', 0, sd=1, shape=X.get_value().shape[1])
β = pm.Deterministic('β', β_raw * σ)

如果有效样本量很小,通常你的第一个冲动不应该只是增加样本数量,而是尝试稍微使用参数化。

此外,您可以使用tt.nnet.sigmoid代替您的自定义invlogit,它可能更快/更稳定。