U-Net denoiser shared by every DDPM variant.
Implements the architecture introduced by Ho, Jain, and Abbeel, 2020:
a symmetric U-Net augmented with sinusoidal-timestep conditioning,
GroupNorm-equipped residual blocks, and self-attention at low-resolution
feature maps. The encoder reduces spatial resolution by a factor of
over
stages; the middle block applies ResBlock → Attn → ResBlock at the
bottleneck; the decoder mirrors the encoder with concatenated skip
connections. The output convolution emits out_channels_effective
channels — equal to in_channels (or 2 * in_channels when
learn_sigma is enabled for variance prediction).
Spatial layout per stage :
* num_res_blocks ResBlocks (with optional attention at
attention_resolutions).
* Downsample → next stage (skipped for l == L - 1).
Decoder mirrors the encoder with concatenated skip features; the extra
ResBlock per stage (num_res_blocks + 1 total on the decoder side)
consumes the post-downsample skip.
Parameters
configDDPMConfigbase_channels, channel_mult,
num_res_blocks, attention_resolutions, num_heads,
dropout, resnet_groups, and learn_sigma.Attributes
time_mlpnn.TimestepEmbedding4 * base_channels.conv_innn.Conv2dbase_channels.down_res, down_attn, down_samplenn.ModuleListmid_block1, mid_attn, mid_block2nn.Moduleup_res, up_attn, up_samplenn.ModuleListnorm_outnn.GroupNormconv_outnn.Conv2dout_channels_effective.Notes
Reference: Ho, Jain, and Abbeel, "Denoising Diffusion Probabilistic Models", NeurIPS, 2020 (arXiv:2006.11239); architecture details in Appendix B. Improved-DDPM additions follow Nichol and Dhariwal, * "Improved Denoising Diffusion Probabilistic Models"*, ICML, 2021 (arXiv:2102.09672).
ResBlock conditioning recipe:
Examples
>>> import lucid
>>> from lucid.models.generative.ddpm import DDPMConfig
>>> from lucid.models.generative.ddpm._model import DDPMUNet
>>> cfg = DDPMConfig(sample_size=32, base_channels=32,
... channel_mult=(1, 2), num_res_blocks=1,
... attention_resolutions=(16,), resnet_groups=16)
>>> unet = DDPMUNet(cfg).eval()
>>> x = lucid.randn((1, 3, 32, 32))
>>> t = lucid.tensor([42]).long()
>>> out = unet(x, t)
>>> out.shape # (1, 3, 32, 32)
(1, 3, 32, 32)