I’m running into a linalg.cholesky error (due to non-positive definite input) caused by issues with the CorrMatrixCholeskyTransform seemingly not being bijective (even though it has bijective = True
?).
For context… I’m trying to transform a vector (a sample from a multivariate normal) into a correlation matrix in a custom guide. The corr_matrix constraint is enforced by (internally in Pyro through biject_to
registration) using the transforms:
ComposeTransform[CorrCholeskyTransform, Inverse(CorrMatrixCholeskyTransform)]
where the input to output chain goes like:
real vector → lower cholesky factor → correlation matrix
The inverse of this (invoked when using the log_abs_det_jacobian()
method) is thus just the reverse direction with inverses:
ComposeTransform[CorrMatrixCholeskyTransform, Inverse(CorrCholesky)]
where the input to output goes like:
correlation matrix → lower cholesky factor → real vector
The problem I’m running into is that the original transform chain produces a correlation matrix, but when I then use the inverse transform chain (which it does when using log_abs_det_jacobian()
), this correlation matrix is input into CorrMatrixCholeskyTransform first, which is basically doing cholesky(correlation matrix)
and this can produce the error below (that the correlation matrix isn’t positive definite, so it can’t do a cholesky decomp on it):
torch._C._LinAlgError: linalg.cholesky: The factorization could not be completed because the input is not positive-definite
Thus, does this mean CorrMatrixCholeskyTransform isn’t actually bijective, since the inverse of this transform can output correlation matrices that the original transform can’t always accept as input? And is there some way to get around this?
As a code example and proof, I did some logging during optimization, and this recreates the error:
from torch.distributions.transforms import CorrCholeskyTransform
from pyro.distributions.transforms import CorrMatrixCholeskyTransform
trans1 = CorrCholeskyTransform()
trans2 = CorrMatrixCholeskyTransform()
real_vect = torch.tensor([-0.2894, -1.0836, -0.4998, 1.6825, 0.1669, 1.0653, -1.2977, 1.1127,
-2.8873, 2.3409, 3.4971, 2.0659, -0.2017, 2.7351, 1.2209, -0.6655,
1.5769, 2.1106, -0.8692, -1.5110, -0.4753, -0.4464, 1.0486, 1.8616,
-0.3846, -0.4477, -0.0422, -1.5995, -0.2185, -3.7241, -0.1611, -3.0001,
-1.0150, 2.5573, 3.0970, -1.6133])
# Forward
lower_cholesky = trans1(real_vect) # from real vector to lower triangular cholesky correlation factor
corr_mat = trans2.inv(lower_cholesky) # from corr factor to correlation matrix
# Inverse.
lower_cholesky = trans2(corr_mat) # <-- error (corr_mat isn't positive definite... must be positive semidefinite?)
trans1.inv(lower_cholesky)