Skip to content

Mv cleanup #3008

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 11, 2018
Merged

Mv cleanup #3008

merged 8 commits into from
Jun 11, 2018

Conversation

gBokiau
Copy link
Contributor

@gBokiau gBokiau commented Jun 5, 2018

This picks up some of the most straight-forward edits from #2847. Guiding principle:

Whatever is implemented by the Mv distributions, is best delegated to Mv distributions

Aka DRY.

For review:
In GP it appeared that covariance matrices were being stabilised multiple times over. Perhaps this was a side-effect of not following the above principle, unless there was some ground for doing this, eg the _build_marginals() have some way of screwing up (rendering non-positive definite) the covs even after they have first been stabilised. Please review.

Copy link
Contributor Author

@gBokiau gBokiau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining doubts about stabilisation

pymc3/gp/gp.py Outdated
@@ -418,15 +417,15 @@ def marginal_likelihood(self, name, X, y, noise, is_observed=True, **kwargs):
if not isinstance(noise, Covariance):
noise = pm.gp.cov.WhiteNoise(noise)
mu, cov = self._build_marginal_likelihood(X, noise)
chol = cholesky(stabilize(cov))
cov = stabilize(cov)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the stabilisation is needed here since noise is already being added to the diagonal in _build_marginal_likelihood.

pymc3/gp/gp.py Outdated
@@ -959,7 +956,7 @@ def _build_conditional(self, Xnew, pred_noise, diag):
cov = Km - Asq
if pred_noise:
cov += sigma * np.eye(cov.shape)
return mu, cov
return mu, stabilize(cov)
Copy link
Contributor Author

@gBokiau gBokiau Jun 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, actually almost certain this is redundant. (Moved from line 999, BTW)
Maybe not redundant when pred_noise == False.

self.nu = nu = tt.as_tensor_variable(nu)
self.init = init
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice simplification!

@twiecki
Copy link
Member

twiecki commented Jun 6, 2018

@gBokiau Looks great, I think iterative changes are the way to go. Definitely want @aseyboldt and @bwengals to take a close look.

Copy link
Member

@aseyboldt aseyboldt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message would be nice, but looks good to me. Thanks!


self.mu = mu = tt.as_tensor_variable(mu)
self.init = init
self.mean = tt.as_tensor_variable(0.)
self.innovArgs = (self.mu, cov, tau, chol, lower)
self.innov = multivariate.MvNormal.dist(*self.innovArgs)

def logp(self, x):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works if x has rank 1, right? Maybe we should intercept the shape in __init__ (one of the kwargs) and throw an error if that doesn't have length 1, just to give people a better error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er, wait, I would hope not, wouldn't rank 1 defeat the purpose of Mv?
I'll run the demo to get a better grasp. More tests for the timeseries would be nice wrt shapes #2859 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked to be sure: this only accepts x and cov/chol with ndim 2, and correctly controls that the shapes are compatible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related observations:

  • To be more precise, it controls/catches any glitch between shape and cov upon sampling, not at declaration time. That is also the behaviour of MvN/MvT. While that could be improved, I think it should then happen in those classes.
  • Another question entirely (for later, perhaps) is wether we want to intercept any such errors here, as to make them more contextual for the timeseries classes.

However this is all probably not what your concern about the rank was?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have said rank 2, not 1. I didn't actually think about the fact that mvnormal doesn't support higher rank input either, but I still think we should check this in this class. If at some point in the future we extend mvnormal, people wouldn't get an error then, but I'm not sure the results are what we want. (eg which dimension is the one with the correlations? In mvnormal it is the last one....)
Here is the code in mvnormal that I have in mind:
https://github.com/pymc-devs/pymc3/blob/master/pymc3/distributions/multivariate.py#L37

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, gotcha. If my understanding is correct, in the case of a random walk, ndim=1 doesn't make sense either, right? So shape can only be two-dimensional for these distributions.

So, as it stands, I would simply add this control in __init__:

    if len(self.shape) != 2:
        raise ValueError("Only 2 dimensions are allowed.")

Perhaps for a separate PR — when given 3 dims, we could (I think?) diff the obs separately along the time axis, concatenate/stack the thus obtained innovations to two dims, and pass that on to Mv.

@pymc-devs pymc-devs deleted a comment from gBokiau Jun 6, 2018
@bwengals
Copy link
Contributor

bwengals commented Jun 8, 2018

these look good to me!

@twiecki twiecki merged commit 1ef580e into pymc-devs:master Jun 11, 2018
@twiecki
Copy link
Member

twiecki commented Jun 11, 2018

Thanks @gBokiau!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants