funcyflows 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/samplers/latent_pcn.py +81 -86
- {funcyflows-0.2.0 → funcyflows-0.2.1}/PKG-INFO +1 -1
- {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/PKG-INFO +1 -1
- {funcyflows-0.2.0 → funcyflows-0.2.1}/pyproject.toml +1 -1
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/abstract_reference_measure.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/bases.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/gaussian_reference_measure.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/diagnostics/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/diagnostics/coverage.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/diagnostics/importance.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/__main__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/_common.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/bimodal_posterior.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/cloud_inpainting.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/nonstationary.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/phase_inpainting.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/positivity.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/ring_inpainting.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/alpha_divergence.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/flow_matching.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/negative_logl.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/reverse_kl.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/samplers/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/abstract_transformation.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/base_continuous.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/conditioners.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/grid_fields.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/vector_fields.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/layers/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/layers/base_discrete.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/layers/layer_classes.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/utils/__init__.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/utils/gaussian_misfit.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/utils/train.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/LICENSE +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/README.md +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/SOURCES.txt +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/dependency_links.txt +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/requires.txt +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/top_level.txt +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/setup.cfg +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/tests/test_basis.py +0 -0
- {funcyflows-0.2.0 → funcyflows-0.2.1}/tests/test_measures.py +0 -0
|
@@ -1,86 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
What problem this solves
|
|
4
|
-
------------------------
|
|
5
|
-
You have a posterior on coefficients,
|
|
6
|
-
|
|
7
|
-
pi(dv) proportional to exp(-Phi(v)) rho(dv),
|
|
8
|
-
|
|
9
|
-
with Phi the misfit (minus log likelihood) and rho a prior. Sampling it directly with a random-walk
|
|
10
|
-
Metropolis proposal fails as the number of modes M grows: to keep the acceptance rate away from
|
|
11
|
-
zero the step size has to shrink like M^(-1/2), so the chain needs O(M) steps to move anywhere.
|
|
12
|
-
|
|
13
|
-
pCN (Cotter, Roberts, Stuart & White, Statistical Science 2013, arXiv:1202.0709) fixes that for a
|
|
14
|
-
GAUSSIAN reference measure mu0. Its proposal is
|
|
15
|
-
|
|
16
|
-
z' = sqrt(1 - beta^2) z + beta xi, xi ~ mu0,
|
|
17
|
-
|
|
18
|
-
which leaves mu0 exactly invariant -- if z ~ mu0 then (z, z') is jointly Gaussian and exchangeable,
|
|
19
|
-
so the pair is reversible. Because the proposal already carries the reference measure, the
|
|
20
|
-
Metropolis ratio keeps only the likelihood:
|
|
21
|
-
|
|
22
|
-
accept with probability min(1, exp(Phi(z) - Phi(z'))).
|
|
23
|
-
|
|
24
|
-
No prior density appears, nothing scales with M, and beta can stay O(1) at any truncation.
|
|
25
|
-
|
|
26
|
-
What the "latent" part adds
|
|
27
|
-
---------------------------
|
|
28
|
-
pCN needs the reference measure to be Gaussian, which is a real restriction: it means the geometry
|
|
29
|
-
the sampler assumes is the geometry of mu0. If the posterior is curved, multimodal or far from the
|
|
30
|
-
prior, a Gaussian-geometry sampler crawls.
|
|
31
|
-
|
|
32
|
-
So run pCN not on v but on the flow's latent variable z, where v = T(z) and T is the trained
|
|
33
|
-
transport. The reference measure there IS Gaussian by construction -- it is the flow's base measure
|
|
34
|
-
-- and the flow has already absorbed the awkward geometry. This is transport-map preconditioning
|
|
35
|
-
(Parno & Marzouk, arXiv:1412.5492; the neural version, with HMC rather than pCN, is NeuTra,
|
|
36
|
-
arXiv:1903.03704).
|
|
37
|
-
|
|
38
|
-
The potential to hand it
|
|
39
|
-
------------------------
|
|
40
|
-
The chain targets nu(dz) proportional to exp(-Psi(z)) mu0(dz), and v = T(z) is then distributed as
|
|
41
|
-
|
|
42
|
-
exp(-Psi(T^-1 v)) q(dv), q = T_# mu0 (the flow's pushforward).
|
|
43
|
-
|
|
44
|
-
Setting that equal to pi gives the rule, once and for all:
|
|
45
|
-
|
|
46
|
-
Psi(z) = Phi(T z) + log (dq/dmu0)(T z) - log (drho/dmu0)(T z).
|
|
47
|
-
|
|
48
|
-
Two cases cover everything in this package, and they are NOT the same call:
|
|
49
|
-
|
|
50
|
-
* T is a learned PRIOR, so rho = q. The two log terms cancel:
|
|
51
|
-
|
|
52
|
-
Psi = Phi . T potential = misfit
|
|
53
|
-
|
|
54
|
-
The flow's Jacobian never enters, so ANY trained prior flow works and the trace need not even
|
|
55
|
-
be available. This is what the inpainting examples used.
|
|
56
|
-
|
|
57
|
-
* T approximates the POSTERIOR and the prior is the base measure, rho = mu0. Then:
|
|
58
|
-
|
|
59
|
-
Psi = Phi . T + log_rn_at . T potential = lambda v: misfit(v) + flow.log_rn_at(v)
|
|
60
|
-
|
|
61
|
-
Here the trace does enter, exactly. An estimated (Hutchinson) trace makes the chain converge to
|
|
62
|
-
the wrong measure, not to a noisy version of the right one. See bimodal_posterior.py.
|
|
63
|
-
|
|
64
|
-
`potential` is called on COEFFICIENTS v, never on z; this function does the transport for you.
|
|
65
|
-
|
|
66
|
-
When it works and when it does not
|
|
67
|
-
----------------------------------
|
|
68
|
-
If the flow is good, q is close to pi, Psi is nearly constant, and almost every proposal is accepted
|
|
69
|
-
even at beta close to 1 -- the chain returns near-independent samples. If the flow is poor, or the
|
|
70
|
-
likelihood is much sharper than anything the flow has seen, the adapted beta collapses and the
|
|
71
|
-
chain barely moves. That failure is quiet: the chains sit on their initialisation and the output
|
|
72
|
-
looks like a posterior. `info["moved"]` is reported for exactly this reason -- see its description
|
|
73
|
-
in the Returns section, and prefer an amortised conditional flow when it is small.
|
|
74
|
-
"""
|
|
75
|
-
import math
|
|
76
|
-
|
|
77
|
-
import torch
|
|
78
|
-
|
|
79
|
-
try: # progress bar is optional
|
|
80
|
-
from tqdm.auto import trange
|
|
81
|
-
except ImportError: # pragma: no cover
|
|
82
|
-
def trange(n, **kwargs):
|
|
83
|
-
return range(n)
|
|
1
|
+
import math, torch
|
|
2
|
+
from tqdm.auto import trange
|
|
84
3
|
|
|
85
4
|
|
|
86
5
|
def _as_coefficients(result):
|
|
@@ -93,7 +12,10 @@ def _as_coefficients(result):
|
|
|
93
12
|
@torch.no_grad()
|
|
94
13
|
def latent_pcn(flow, potential, num_chains=64, num_steps=2000, beta=0.2, init=None, burn=None,
|
|
95
14
|
thin=1, adapt_to=None, context=None, progress=True, generator=None):
|
|
96
|
-
r"""Sample a posterior by running pCN in the latent space of `flow`.
|
|
15
|
+
r"""Sample a posterior by running pCN in the latent space of `flow`. If unfamiliar with pCN,
|
|
16
|
+
it's an MCMC method that makes proposals by scaling the current MCMC sample and adding
|
|
17
|
+
an adjusted sample from the prior. Scales better with dimension than standard MCMC because
|
|
18
|
+
of the implicit geometry added along with the prior samples.
|
|
97
19
|
|
|
98
20
|
Parameters
|
|
99
21
|
----------
|
|
@@ -104,8 +26,8 @@ def latent_pcn(flow, potential, num_chains=64, num_steps=2000, beta=0.2, init=No
|
|
|
104
26
|
training, and every chain step costs one solve.
|
|
105
27
|
potential : callable
|
|
106
28
|
``potential(v) -> [batch]``, the NEGATIVE log of the target's density relative to the
|
|
107
|
-
flow's pushforward, as a function of COEFFICIENTS. See
|
|
108
|
-
|
|
29
|
+
flow's pushforward, as a function of COEFFICIENTS. See explanation further down
|
|
30
|
+
in this docstring for which of the two forms you want.
|
|
109
31
|
num_chains : int
|
|
110
32
|
Chains advanced in lockstep. They share one ``transport`` call per step, so more chains are
|
|
111
33
|
nearly free up to the batch the ODE can hold.
|
|
@@ -148,6 +70,79 @@ def latent_pcn(flow, potential, num_chains=64, num_steps=2000, beta=0.2, init=No
|
|
|
148
70
|
norm. Below ~0.1 the chain never left its initialisation and the "posterior"
|
|
149
71
|
you are looking at is whatever you passed as ``init``. Reported only when
|
|
150
72
|
``init`` is given.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
Preconditioned Crank-Nicolson MCMC in the latent space of a trained flow.
|
|
76
|
+
|
|
77
|
+
What we're doing
|
|
78
|
+
------------------------
|
|
79
|
+
You have a posterior on coefficients,
|
|
80
|
+
|
|
81
|
+
pi(dv) proportional to exp(-Phi(v)) rho(dv),
|
|
82
|
+
|
|
83
|
+
with Phi the misfit (minus log likelihood) and rho a prior. Sampling it directly with a random-walk
|
|
84
|
+
Metropolis proposal fails as the number of modes M grows: to keep the acceptance rate away from
|
|
85
|
+
zero the step size has to shrink like M^(-1/2), so the chain needs O(M) steps to move anywhere.
|
|
86
|
+
|
|
87
|
+
pCN (Cotter, Roberts, Stuart & White, Statistical Science 2013, arXiv:1202.0709) fixes that for a
|
|
88
|
+
GAUSSIAN reference measure mu0. Its proposal is
|
|
89
|
+
|
|
90
|
+
z' = sqrt(1 - beta^2) z + beta xi, xi ~ mu0,
|
|
91
|
+
|
|
92
|
+
which leaves mu0 exactly invariant -- if z ~ mu0 then (z, z') is jointly Gaussian and exchangeable,
|
|
93
|
+
so the pair is reversible. Because the proposal already carries the reference measure, the
|
|
94
|
+
Metropolis ratio keeps only the likelihood:
|
|
95
|
+
|
|
96
|
+
accept with probability min(1, exp(Phi(z) - Phi(z'))).
|
|
97
|
+
|
|
98
|
+
No prior density appears, nothing scales with M, and beta can stay O(1) at any truncation.
|
|
99
|
+
|
|
100
|
+
What the "latent" part adds
|
|
101
|
+
---------------------------
|
|
102
|
+
pCN needs the reference measure to be Gaussian, because the Gaussian family is closed under this operation
|
|
103
|
+
and almost nothing else is: with v and xi independent N(0,C), the combination has covariance
|
|
104
|
+
|
|
105
|
+
(1-beta^2)C + beta^2 C = C,
|
|
106
|
+
|
|
107
|
+
and a mean-zero Gaussian is determined by its covariance, so v' is N(0,C) again.
|
|
108
|
+
|
|
109
|
+
If the posterior is curved, multimodal or far from the prior, a Gaussian-geometry sampler does not do very well.
|
|
110
|
+
|
|
111
|
+
The constraint is on the REFERENCE measure, not the prior. An arbitrary prior rho enters through -log(drho/dmu0)
|
|
112
|
+
in the potential (formula above) with no change to the algorithm, or gets absorbed into the transport, which is what a learned prior flow is.
|
|
113
|
+
What must be closed under the proposal is the reference: Gaussian is the only finite-variance choice,
|
|
114
|
+
though alpha-stable references work with rebalanced coefficients.
|
|
115
|
+
|
|
116
|
+
But, we run pCN not on v but on the flow's latent variable z, where v = T(z) and T is the trained
|
|
117
|
+
transport. The reference measure there *IS* Gaussian by construction -- it is the flow's base measure
|
|
118
|
+
-- and the flow has already absorbed the awkward geometry. This is transport-map preconditioning
|
|
119
|
+
(Parno & Marzouk, arXiv:1412.5492; the neural version, with HMC rather than pCN, is NeuTra,arXiv:1903.03704).
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
Which potential to pass
|
|
124
|
+
-----------------------
|
|
125
|
+
The chain targets exp(-Psi(z)) mu0(dz), so v = T(z) comes out distributed as
|
|
126
|
+
|
|
127
|
+
Psi(z) = Phi(Tz) + log (dq/dmu0)(Tz) - log (drho/dmu0)(Tz), q = T_# mu0
|
|
128
|
+
|
|
129
|
+
Two cases cover the below, they are not the same call :grimace: :
|
|
130
|
+
|
|
131
|
+
* T is a learned PRIOR, so rho = q and the log terms cancel:
|
|
132
|
+
|
|
133
|
+
potential = misfit
|
|
134
|
+
|
|
135
|
+
The flow's Jacobian never enters, so any trained prior flow works and the trace
|
|
136
|
+
need not even be computable.
|
|
137
|
+
|
|
138
|
+
* T approximates the POSTERIOR and the prior is the base measure, rho = mu0:
|
|
139
|
+
|
|
140
|
+
potential = lambda v: misfit(v) + flow.log_rn_at(v)
|
|
141
|
+
|
|
142
|
+
Here the trace DOES enter, and it unfortunately has to be exact.
|
|
143
|
+
A Hutchinson estimate doesn't give a noisy version of the 'correct' chain:
|
|
144
|
+
- the randomness lands in the accept test
|
|
145
|
+
- so the chain has a different invariant measure.
|
|
151
146
|
"""
|
|
152
147
|
if not 0 < beta <= 1:
|
|
153
148
|
raise ValueError(f"beta must be in (0, 1]; got {beta}")
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "funcyflows"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Normalizing flows and flow matching on function spaces, with exact-trace vector fields"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
File without changes
|
|
File without changes
|
{funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/abstract_reference_measure.py
RENAMED
|
File without changes
|
|
File without changes
|
{funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/gaussian_reference_measure.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|