Skip to content

Build autoguide in unconstrained space and add full and low rank multivariate guides - #701

Merged
jessegrabowski merged 2 commits into
pymc-devs:mainfrom
ricardoV94:mvn_autogide
Jul 10, 2026
Merged

Build autoguide in unconstrained space and add full and low rank multivariate guides#701
jessegrabowski merged 2 commits into
pymc-devs:mainfrom
ricardoV94:mvn_autogide

Conversation

@ricardoV94

@ricardoV94 ricardoV94 commented Jun 26, 2026

Copy link
Copy Markdown
Member

Took the unconstrain fix from #635 and added some multivariate guides for fun

@codecov-commenter

codecov-commenter commented Jun 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.75325% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.40%. Comparing base (86fac3c) to head (76e4dff).
⚠️ Report is 18 commits behind head on main.

Files with missing lines Patch % Lines
pymc_extras/inference/advi/autoguide.py 96.85% 4 Missing ⚠️
pymc_extras/inference/advi/training.py 0.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main     #701       +/-   ##
===========================================
+ Coverage   51.60%   91.40%   +39.80%     
===========================================
  Files          73       92       +19     
  Lines        8003     8543      +540     
===========================================
+ Hits         4130     7809     +3679     
+ Misses       3873      734     -3139     
Files with missing lines Coverage Δ
pymc_extras/inference/advi/__init__.py 100.00% <100.00%> (ø)
pymc_extras/inference/advi/compile.py 100.00% <100.00%> (ø)
pymc_extras/inference/advi/objective.py 84.61% <100.00%> (+84.61%) ⬆️
pymc_extras/inference/advi/pytensorf.py 100.00% <100.00%> (+100.00%) ⬆️
pymc_extras/inference/advi/training.py 0.00% <0.00%> (ø)
pymc_extras/inference/advi/autoguide.py 97.48% <96.85%> (+97.48%) ⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ricardoV94
ricardoV94 force-pushed the mvn_autogide branch 2 times, most recently from b65846b to 559e951 Compare June 27, 2026 13:13
@ricardoV94 ricardoV94 changed the title Multivariate autoguide Build autoguide in unconstrained space and add full and low rank guides Jun 28, 2026
Comment thread pymc_extras/inference/advi/compile.py Outdated
Comment on lines +31 to +32
if "trust_input" not in compile_kwargs:
compile_kwargs["trust_input"] = True

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

use set_default

@ricardoV94 ricardoV94 changed the title Build autoguide in unconstrained space and add full and low rank guides Build autoguide in unconstrained space and add full and low rank multivariate guides Jun 28, 2026
@ricardoV94 ricardoV94 added bug Something isn't working enhancements New feature or request inference labels Jun 28, 2026

@zaxtax zaxtax left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I love this

Comment thread pymc_extras/inference/advi/autoguide.py Outdated
preserves_shape = (
transform is None
or transform.ndim_supp == 0
or equal_computations([value_shape], [rv_shape])

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this is a stop gag until we have transform.ndim_supp in: pymc-devs/pymc#8331

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is anything blocking that? I approved it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

pytensor being broken, will likely only ship with next release

"""Returns a graph representing the logp of the guide model, evaluated under draws from its random variables."""
@property
def latent(self) -> Variable:
"""The whole unconstrained draw, before it is split into per-variable values.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

probably makes sense for the regular Normal to also do it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this be a private or public method?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think it matters? I have no strong preference, let me know if you do

@jessegrabowski jessegrabowski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks nice, gave suggestions

Comment thread pymc_extras/inference/advi/autoguide.py Outdated
Comment on lines +230 to +233
lower-triangular Cholesky factor. The guide's logq is obtained by logprob inference over the
un-split draw (see :meth:`AutoFullRankGuideModel.stochastic_logq`); ``L`` is annotated
lower-triangular via :func:`pytensor.assumptions.assume` so the internal ``solve``/``slogdet``
lower to the triangular fast path.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Internal computation details not important to end-user, this is a public facing function so I'd rather the docstring be usage focused

Comment thread pymc_extras/inference/advi/autoguide.py Outdated
value_shapes, value_dims = get_value_shapes_and_dims(model)

# DictToArrayBijection flattens the unconstrained initial point into the guide mean init;
# point_map_info gives the per-RV layout (hence the order) of that flat vector.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
# point_map_info gives the per-RV layout (hence the order) of that flat vector.
# point_map_info gives the per-RV layout (thus the order) of that flat vector.

Comment thread pymc_extras/inference/advi/autoguide.py
Comment thread pymc_extras/inference/advi/autoguide.py
Comment thread pymc_extras/inference/advi/autoguide.py
Comment thread pymc_extras/inference/advi/autoguide.py Outdated
# cholesky outputs are auto-recognized as lower-triangular by pytensor's linalg rewrites
chol_cap = cholesky(capacitance, lower=True)
rhs = W.T @ (delta * d_inv)
sol = solve_triangular(chol_cap, rhs, lower=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should maybe be cho_solve, need to benchmark it but it's always been close when i tried it (or check that we rewrite this case. I know it would end up as cho_solve if this was a basic solve, not sure about solve_triangular)

Comment thread pymc_extras/inference/advi/autoguide.py Outdated

delta = u - loc
d_inv = 1.0 / d**2
capacitance = pt.eye(rank) + (W * d_inv[:, None]).T @ W # K x K, symmetric PD

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"Capacitance is the ability of an object to store electric charge when a voltage is applied across it. It is measured in farads (F) and depends on factors like the size of the conductive plates, the distance between them, and the type of dielectric material used."

Why this name?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Due to a manifold collapse in high dimensional next token prediction that we'll never be able to fully phantom and yet must respect if not enjoy.

@ricardoV94 ricardoV94 Jul 6, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is what the bot had to say in its defense

It traces back to the "capacitance matrix method" for solving elliptic PDEs on irregular domains (Buzbee–Dorr–George–Golub, 1971), by analogy to capacitance in circuit network theory — the low-rank correction plays the role of a boundary/capacitance term. It carried into general Woodbury usage. Concretely, PyTorch's LowRankMultivariateNormal uses this exact name (_capacitance_tril), so it's the conventional term for precisely this distribution.

Comment on lines +371 to +373
if rank is None:
rank = round(n_dim**0.5)
rank = max(1, min(rank, n_dim))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure I like this. I'd rather force users to think about it than give a random default with no real motivation

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

the motivation is that numpyro uses this default. hard against?

Comment thread pymc_extras/inference/advi/autoguide.py Outdated
@review-notebook-app

Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@ricardoV94
ricardoV94 force-pushed the mvn_autogide branch 3 times, most recently from 30b0c3f to f4b17e2 Compare July 6, 2026 09:51
Construct AutoDiagonalNormal guides over the model's unconstrained value
variables, matching the standard-normal parameter dtype to the value dtype
to avoid a per-element cast in the numba RV core loop.
@jessegrabowski
jessegrabowski merged commit f4f46ab into pymc-devs:main Jul 10, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancements New feature or request inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants