Hi all,
Long time Stan user giving PyMC3 a shot. I’m trying to wrap my head around implementing a custom log likelihood that involves matrix operations with observed data and latent variables. Specifically, I don’t understand how to do math with random variables and TensorVariables
.
Here’s an dumb model that illustrates my confusion (this is not the model I actually want to implement but illustrates where I’m getting tripped up). The generative model is
vg, ve ~ priors
b | vg ~ MVN(0, C*vg)
y | b, ve ~ MVN(Xb, I * ve)
where C
is a known m-by-m matrix and b
is a vector of latent effects. I simulate these data via:
import numpy as np
import pymc3 as pm
from pymc3 import math as pmm
n=200
m=100
vg=.4
ve=.6
X = np.random.multivariate_normal(np.zeros(m), np.eye(m), size=n)
u = .1
C = (np.eye(m) + np.outer(u,u))
S = C*vg/m
beta = np.random.multivariate_normal(np.zeros(m), S)
e = np.random.multivariate_normal(np.zeros(n), np.eye(n)*ve, size=1)
y = X @ beta + e
I have no trouble implementing this using the built-in MVN functions. Here’s a working PyMC3 implementation:
with pm.Model() as lmm:
## theta
vg = pm.HalfCauchy(name='vg', beta=1.0);
ve = pm.HalfCauchy(name='ve', beta=1.0);
## b | theta
b = pm.MvNormal(name='b',mu=np.zeros(m),cov=C*vg/m,shape=(1,m))
linpred = b @ X.T
## y | Xb, theta
loglik = pm.Normal(name="loglik", mu=linpred, sigma=ve, observed=y, shape =n)
Even though b
is a latent vector and X
is some observed data, there’s no problem computing linpred
. However, when I try to implement the MVN lpdf manually, I run into TypeError: unsupported operand type(s) for @: 'TensorVariable' and 'MultiObservedRV'
. Here’s my broken attempt to implement this manually:
with pm.Model() as lmm2:
## theta
vg = pm.HalfCauchy(name='vg', beta=1.0);
ve = pm.HalfCauchy(name='ve', beta=1.0);
## b | theta
def mvn_lpdf(C):
cov=C*vg/m
return -(pmm.logdet(cov)+ pmm.dot(pmm.matrix_inverse(cov) @ b,b))
b = pm.DensityDist(name='b',logp=mvn_lpdf,observed={"C":C})
linpred = b @ X.T
## y | Xb, theta
loglik = pm.Normal(name="loglik", mu=linpred, sigma=ve, observed=y, shape =n)
What’s causing the type errors in the return -(pmm.logdet(cov)+ pmm.dot(pmm.matrix_inverse(cov) @ b,b))
line?
Thanks,
Richard