PyMC3将随机协方差矩阵传递给pm.MvNormal()

时间:2018-11-09 09:05:01

标签: python theano bayesian normal-distribution pymc3

我尝试通过使用PyMC3将简单的2D高斯模型拟合到观测数据。

import numpy as np
import pymc3 as pm

n = 10000;
np.random.seed(0)
X = np.random.multivariate_normal([0,0], [[1,0],[0,1]], n);

with pm.Model() as model:
    # PRIORS
    mu = [pm.Uniform('mux', lower=-1, upper=1), 
          pm.Uniform('muy', lower=-1, upper=1)]
    cov = np.array([[pm.Uniform('a11', lower=0.1, upper=2), 0],
                    [0, pm.Uniform('a22', lower=0.1, upper=2)]])

    # LIKELIHOOD
    likelihood = pm.MvNormal('likelihood', mu=mu, cov=cov, observed=X)

with model:
    trace = pm.sample(draws=1000, chains=2, tune=1000)

虽然我可以通过将sd传递到pm.Normal来在一维中完成此操作,但是在将协方差矩阵传递给pm.MvNormal时遇到了一些麻烦。

我要去哪里错了?

1 个答案:

答案 0 :(得分:1)

PyMC3分发对象不是简单的数字对象或numpy数组。相反,它们是theano计算图中的节点,通常需要来自pymc3.maththeano.tensor的运算来对其进行操作。此外,由于PyMC3对象已经是多维的,因此不必将它们放置在numpy数组中。

原始模型

按照您的代码意图,工作版本会像这样

import numpy as np
import pymc3 as pm
import theano.tensor as tt

N = 10000
np.random.seed(0)
X = np.random.multivariate_normal(np.zeros(2), np.eye(2), size=N)

with pm.Model() as model:
    # use `shape` argument to define tensor dimensions
    mu = pm.Uniform('mu', lower=-1, upper=1, shape=2)

    # diagonal values on covariance matrix
    a = pm.Uniform('a', lower=0.1, upper=2, shape=2)

    # convert vector to a 2x2 matrix with `a` on the diagonal
    cov = tt.diag(a)

    likelihood = pm.MvNormal('likelihood', mu=mu, cov=cov, observed=X)

替代模型

我假设您提供的示例只是一个用来传达问题的玩具。但是以防万一,我要提到的是,当将协方差矩阵限制为对角线时,将失去使用多元法线(参数之间的建模协方差)的主要优势。此外,协方差矩阵的先验理论已经得到了很好的发展,因此考虑现有的解决方案值得花时间。特别是,有a PyMC3 example using the LKJ prior for covariance matrices

在这种情况下,以下是该示例的简单应用:

with pm.Model() as model_lkj:
    # use `shape` argument to define tensor dimensions
    mu = pm.Uniform('mu', lower=-1, upper=1, shape=2)

    # LKJ prior for covariance matrix (see example)
    packed_L = pm.LKJCholeskyCov('packed_L', n=2,
                                 eta=2., sd_dist=pm.HalfCauchy.dist(2.5))
    # convert to (2,2)
    L = pm.expand_packed_triangular(2, packed_L)

    likelihood = pm.MvNormal('likelihood', mu=mu, chol=L, observed=X)