无掉头采样器 (NUTS) 的 PyMC3 性能问题:简单模型每秒少于 2 次迭代
PyMC3 performance issues with No U-Turn Sampler (NUTS): less than 2 iterations per second with simple model
我试图了解以下代码的问题所在:
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
中的模型更简单),性能同样糟糕:
与 pm.Model() 为 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
模型的非居中版本应该工作得更好:
β_raw = pm.Normal('β_raw', 0, sd=1, shape=X.get_value().shape[1])
β = pm.Deterministic('β', β_raw * σ)
通常情况下,如果有效样本量较小,您的第一个冲动不应该只是增加样本数量,而是尝试稍微调整一下参数化。
此外,您可以使用 tt.nnet.sigmoid
而不是自定义 invlogit,这可能 faster/more 稳定。
我试图了解以下代码的问题所在:
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
中的模型更简单),性能同样糟糕:与 pm.Model() 为 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
模型的非居中版本应该工作得更好:
β_raw = pm.Normal('β_raw', 0, sd=1, shape=X.get_value().shape[1])
β = pm.Deterministic('β', β_raw * σ)
通常情况下,如果有效样本量较小,您的第一个冲动不应该只是增加样本数量,而是尝试稍微调整一下参数化。
此外,您可以使用 tt.nnet.sigmoid
而不是自定义 invlogit,这可能 faster/more 稳定。