implementation

A diffusion model as a statistical game. The third of the three Implicit Learners families, and the only one whose Bayesian inversion is neither exact nor a root-find.

Sources: code: VariationalDiffusion.jl, factor.jl, lens.jl, predictor.jl, reddiff.jl, schedule.jl

Theory (CT-ML wiki): Bayesian Inversion · Statistical Game · Lens

The chain, in nine files

filenotesupplies
schedule.jlschedulethe VP-SDE: with
predictor.jlpredictor wrapping a Lux model; score and Tweedie
reddiff.jlreddiffthe proximal operator; Proposition 2; λ calibration
factor.jlfactorthe LenticulumFactor; from the polarity
analytic.jlanalyticclosed-form ε* of a Gaussian mixture: an exact-score relation (oracle)
implicit.jlimplicitdeterministic implicit inference and its adjoint backward pass
energy.jlenergyenergy-parametrised predictors: , a conservative score, an energy for the relation
implicit_factor.jlimplicit_factorDiffusionFactor with ImplicitProx: report and per-channel pullback
proxdm.jlproxdmproximal diffusion models: prox interface, exact oracle, sampler, proximal inference
ext/backendsthe network’s derivatives through any AD backend (DifferentiationInterface, Reactant)

Concept notes are in vault/Families/Diffusion/, entry point The Diffusion Family.

What LenticulumCore already had

Nothing in the core needed changing, which is the strongest evidence so far that its abstractions were the right ones:

  • ProximalInversion(prox) exists in lens.jl and its docstring already names this package and RED-Diff. It was written before there was an implementation.
  • Polarity with per-channel precisions is exactly , including default_precision(Observed()) = Inf.
  • GradedEnergySpace expresses the (clamp, score) split without a new type.
  • DiracBelief is what RED-Diff’s variational family actually produces.

One thing it did not have, and the gap is now confirmed from two directions: the energy(factor, x, a, y, ps, st) signature presumes a causal split. constraint.md §3 hit it from the acausal side; factor.md §4 hits it here. Two independent factor families means it is an interface bug rather than a quirk.

Two properties worth stating up front

No automatic-differentiation dependency. RED-Diff’s stop-gradient means the denoiser Jacobian is never formed, and the clamp’s gradient is in closed form. So the dependency list is LuxCore, Random, LinearAlgebra — and not Lux, since any Lux model is an AbstractLuxLayer. Where a learned network is differentiated (the implicit learner’s Newton steps and its backward pass), the user chooses the backend with NoisePredictor(…; ad = AutoZygote()) or any other ADTypes object, and a package extension supplies it (backends). Training the denoiser itself is ordinary Lux training.

The inversion returns a DiracBelief. That is the paper’s own variational family (), not a shortcut, and it is the source of most of what is awkward about putting this factor in a graph — see factor §5.

How it is tested

There is exactly one closed-form diffusion model, and the test suite is built on it: for Gaussian data ,

is a perfectly trained noise predictor. Against it:

  • Tweedie’s denoise reproduces the exact linear-Gaussian posterior mean to floating point;
  • the RED-Diff regulariser collapses to a linear shrinkage with known in closed form;
  • with the calibrated , the RED-Diff fixed point is the exact Gaussian posterior mean, to within Monte-Carlo noise that averages away over seeds;
  • and no single can do the same for a correlated prior — reddiff §4.2.

This is the same move GaussianFactor makes in the parent package: build the one case where everything is computable, and check the framework against arithmetic instead of against itself.

Related: Implicit Learners, The Diffusion Family, ImplicitREDDiff, Factors are Parameterized Statistical Games, Channels and Polarity