ScoreSDEForImageGeneration
ImageGenerationModelScoreSDEForImageGeneration(config: ScoreSDEConfig)Score-SDE with its objective and the three samplers.
Parameters
configScoreSDEConfigNotes
Reference: Song et al., ICLR 2021 (arXiv:2011.13456).
Trained by denoising score matching, equation 7, in the form that weights each time by — which makes the loss the plain mean squared error between the predicted and the actual noise, since the in the score and the in the weight cancel to one. That is the same objective DDPM optimises, which is the paper's point.
Three ways to sample, all from one trained network:
"euler"
Integrate the reverse-time SDE, equation 6.
"pc"
The same, with Langevin corrector steps at fixed . The
paper's Predictor-Corrector.
"ode"
The probability-flow ODE, equation 13, handed to
lucid.diffeq.odeint.
Examples
>>> import lucid
>>> from lucid.models import score_sde_vp_gen
>>> model = score_sde_vp_gen(sample_size=8, base_channels=8,
... channel_mult=(1,), num_res_blocks=1, resnet_groups=4,
... attention_resolutions=()).eval()
>>> out = model(lucid.randn((2, 3, 8, 8)))
>>> bool(out.loss.ndim == 0)
TrueUsed by 2
Constructors
1Properties
1Instance methods
3forward(x: Tensor, t: Tensor | None = None)generate(n_samples: int = 1, method: str = 'pc', steps: int | None = None, device: str | None = None, guidance: _Guidance | None = None)Draw samples by integrating backwards from the prior.
Parameters
n_samplesint= 1method(pc, euler, ode)= "pc""euler" integrates the reverse SDE, "pc" adds Langevin
correction, "ode" solves the probability-flow ODE with
lucid.diffeq.odeint.stepsint or None= NoneNone uses num_scales. That this is a
sampling argument rather than a property of the trained model
is the framework's point.devicestr or None= NoneNone follows the parameters.guidancecallable or None= None(x, t) -> Tensor, returning
. Added to the score, which
is all conditional sampling is — the paper's controllable
generation needs no retraining and no conditional model.Returns
GenerationOutputsamples of shape (n_samples, C, H, W).
Raises
ValueErrormethod is not one of the three.Examples
>>> import lucid
>>> from lucid.models import score_sde_vp_gen
>>> model = score_sde_vp_gen(sample_size=8, base_channels=8,
... channel_mult=(1,), num_res_blocks=1, resnet_groups=4,
... attention_resolutions=()).eval()
>>> [model.generate(n_samples=2, method=m, steps=2).samples.shape
... for m in ("euler", "pc", "ode")]
[(2, 3, 8, 8), (2, 3, 8, 8), (2, 3, 8, 8)]
>>> model.generate(method="ddim")
Traceback (most recent call last):
...
ValueError: method must be 'pc', 'euler' or 'ode', got 'ddim'log_likelihood(x: Tensor, steps: int = 100, eps: Tensor | None = None)Exact log-likelihood of the data, in nats.
Parameters
Returns
Tensor(N,) log-densities.
Notes
Song et al. (2021), Appendix D.2. Because the probability-flow ODE is a neural ODE, the instantaneous change of variables gives
equation 39, where solves that ODE. The divergence is expensive, so it is estimated as the paper does — equation 40, the Skilling-Hutchinson trace estimator
with of zero mean and identity covariance. The vector-Jacobian product is one backward pass, so the whole estimate costs one extra gradient per solver step.
This is what the deterministic sampler buys that a stochastic one
cannot: an exact density, not a bound. It is also stochastic in
the estimator — two calls differ, and the variance falls with
the number of probes, not with steps.
Examples
>>> import lucid
>>> from lucid.models import score_sde_vp_gen
>>> model = score_sde_vp_gen(sample_size=8, base_channels=8,
... channel_mult=(1,), num_res_blocks=1, resnet_groups=4,
... attention_resolutions=()).eval()
>>> model.log_likelihood(lucid.randn((1, 3, 8, 8)), steps=3).shape
(1,)