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.
Files changed (49) hide show
  1. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/samplers/latent_pcn.py +81 -86
  2. {funcyflows-0.2.0 → funcyflows-0.2.1}/PKG-INFO +1 -1
  3. {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/PKG-INFO +1 -1
  4. {funcyflows-0.2.0 → funcyflows-0.2.1}/pyproject.toml +1 -1
  5. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/__init__.py +0 -0
  6. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/__init__.py +0 -0
  7. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/abstract_reference_measure.py +0 -0
  8. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/bases.py +0 -0
  9. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/base_measures/gaussian_reference_measure.py +0 -0
  10. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/diagnostics/__init__.py +0 -0
  11. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/diagnostics/coverage.py +0 -0
  12. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/diagnostics/importance.py +0 -0
  13. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/__init__.py +0 -0
  14. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/__main__.py +0 -0
  15. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/_common.py +0 -0
  16. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/bimodal_posterior.py +0 -0
  17. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/cloud_inpainting.py +0 -0
  18. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/nonstationary.py +0 -0
  19. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/phase_inpainting.py +0 -0
  20. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/positivity.py +0 -0
  21. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/examples/ring_inpainting.py +0 -0
  22. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/__init__.py +0 -0
  23. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/alpha_divergence.py +0 -0
  24. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/flow_matching.py +0 -0
  25. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/negative_logl.py +0 -0
  26. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/objectives/reverse_kl.py +0 -0
  27. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/samplers/__init__.py +0 -0
  28. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/__init__.py +0 -0
  29. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/abstract_transformation.py +0 -0
  30. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/__init__.py +0 -0
  31. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/base_continuous.py +0 -0
  32. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/conditioners.py +0 -0
  33. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/grid_fields.py +0 -0
  34. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/continuous/vector_fields.py +0 -0
  35. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/layers/__init__.py +0 -0
  36. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/layers/base_discrete.py +0 -0
  37. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/transports/layers/layer_classes.py +0 -0
  38. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/utils/__init__.py +0 -0
  39. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/utils/gaussian_misfit.py +0 -0
  40. {funcyflows-0.2.0 → funcyflows-0.2.1}/FuncyFlows/utils/train.py +0 -0
  41. {funcyflows-0.2.0 → funcyflows-0.2.1}/LICENSE +0 -0
  42. {funcyflows-0.2.0 → funcyflows-0.2.1}/README.md +0 -0
  43. {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/SOURCES.txt +0 -0
  44. {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/dependency_links.txt +0 -0
  45. {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/requires.txt +0 -0
  46. {funcyflows-0.2.0 → funcyflows-0.2.1}/funcyflows.egg-info/top_level.txt +0 -0
  47. {funcyflows-0.2.0 → funcyflows-0.2.1}/setup.cfg +0 -0
  48. {funcyflows-0.2.0 → funcyflows-0.2.1}/tests/test_basis.py +0 -0
  49. {funcyflows-0.2.0 → funcyflows-0.2.1}/tests/test_measures.py +0 -0
@@ -1,86 +1,5 @@
1
- r"""Preconditioned Crank-Nicolson MCMC in the latent space of a trained flow.
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 the module docstring for which of
108
- the two forms you want; getting this wrong is silent.
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}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: funcyflows
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Normalizing flows and flow matching on function spaces, with exact-trace vector fields
5
5
  Author: Liam Pinchbeck
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: funcyflows
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Normalizing flows and flow matching on function spaces, with exact-trace vector fields
5
5
  Author: Liam Pinchbeck
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "funcyflows"
7
- version = "0.2.0"
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
File without changes