AI/ML Physics Flow Matching Diffusion Transformers PyTorch

Flow Matching & Diffusion Transformers (DiT): Continuous-Time Generative Physics


Viewed through statistical mechanics, generative modeling is a boundary-value transport problem: how do we construct a time-dependent velocity field $v_t : \mathbb{R}^d \to \mathbb{R}^d$ that continuously transports a simple Gaussian prior $p_0 = \mathcal{N}(0, I)$ at $t = 0$ into an intricate empirical data distribution $p_1 = p_{\text{data}}$ at $t = 1$?

Classical Denoising Diffusion Probabilistic Models (DDPM; Ho et al., 2020) solved this via discrete-time stochastic differential equations (SDEs) with curved variance-preserving schedules, requiring dozens of solver steps to integrate accurately. Modern frontier visual, audio, and protein generators – including Stable Diffusion 3, Flux, and Sora-class Diffusion Transformers (DiT) – have converged on a cleaner geometric framework: Optimal Transport Conditional Flow Matching (CFM) (Lipman et al., 2023; Liu et al., 2023) paired with adaLN-Zero Transformer backbones (Peebles & Xie, 2023).


0. Fluid Mechanics of Probability: The Continuity Equation & Flow ODE

Suppose a particle starts at $x_0 \sim p_0$ and evolves deterministically along an ordinary differential equation (ODE) governed by a smooth velocity field $u_t(x)$:

Probability Flow ODE & Liouville Continuity Equation
$$\frac{d x_t}{d t} = u_t(x_t), \qquad \frac{\partial p_t(x)}{\partial t} + \nabla_x \cdot \bigl(p_t(x)\, u_t(x)\bigr) = 0$$

The second equation is the exact conservation of probability mass (the continuity equation from fluid dynamics): the rate of density increase $\partial_t p_t$ inside any infinitesimal volume equals the negative divergence of the probability flux $J_t = p_t u_t$.

Why Marginal Flow Matching Seems Intractable – and Why Conditional Flow Matching Works

To train a neural velocity field $v_\theta(x_t, t)$ to match the marginal velocity $u_t(x_t)$, the naive objective $\mathcal{L}_{\text{FM}}(\theta) = \mathbb{E}_{t, x_t \sim p_t}\bigl[\|v_\theta(x_t, t) - u_t(x_t)\|^2\bigr]$ appears intractable because we do not have a closed-form expression for the marginal $u_t(x)$ integrated over all data points $x_1 \sim p_{\text{data}}$.

Lipman et al. (2023) proved a remarkable identity: if we define a simple conditional trajectory $x_t = \psi_t(x_0 \mid x_1)$ conditioned on a single data sample $x_1 \sim p_1$ with known conditional velocity $u_t(x_t \mid x_1) = \frac{d}{dt}\psi_t(x_0 \mid x_1)$, then the conditional loss $\mathcal{L}_{\text{CFM}}(\theta)$ has the exact same parameter gradient as the intractable marginal loss $\mathcal{L}_{\text{FM}}(\theta)$!

Conditional Flow Matching Gradient Equivalence Theorem
$$\nabla_\theta \, \mathbb{E}_{t, x_t \sim p_t}\!\left[\bigl\|v_\theta(x_t, t) - u_t(x_t)\bigr\|^2\right] \equiv \nabla_\theta \, \mathbb{E}_{t, x_0 \sim p_0, x_1 \sim p_1}\!\left[\bigl\|v_\theta(x_t, t) - u_t(x_t \mid x_1)\bigr\|^2\right]$$

Proof sketch: expanding the squared norm and applying the definition of the marginal velocity $u_t(x) = \int u_t(x \mid x_1) \frac{p_t(x \mid x_1) p_1(x_1)}{p_t(x)} dx_1$ causes the cross-term $\langle v_\theta(x_t, t), u_t(x_t) \rangle$ to collapse into the conditional expectation via Bayes' rule, while the $u_t$-only squared terms are independent of $\theta$.


1. Optimal Transport Paths (Rectified Flow) vs. Curved DDPM Schedules

In a general linear Gaussian interpolation $x_t = \alpha_t x_1 + \sigma_t x_0$ (with $x_0 \sim \mathcal{N}(0, I)$), choosing $\alpha_t = \sqrt{\bar{\alpha}_t}$ and $\sigma_t = \sqrt{1 - \bar{\alpha}_t}$ recovers the curved Variance-Preserving (VP-SDE / DDPM) path. Because $\frac{d^2 x_t}{dt^2} \neq 0$, the conditional trajectories curve through space, forcing numerical ODE solvers to take tiny steps ($\Delta t \ll 1$) to avoid truncation error.

Optimal Transport Flow Matching / Rectified Flow (Liu et al., 2023; Lipman et al., 2023) chooses the simplest possible displacement interpolant – a straight line in Euclidean space with constant velocity:

Optimal Transport (Rectified Flow) Interpolant & Velocity Objective
$$x_t = (1 - t)\, x_0 + t\, x_1, \qquad u_t(x_t \mid x_0, x_1) = \frac{d x_t}{d t} = x_1 - x_0$$ $$\mathcal{L}_{\text{RF}}(\theta) = \mathbb{E}_{t \sim \pi(t),\, x_0 \sim \mathcal{N}(0,I),\, x_1 \sim p_{\text{data}}} \left[ \bigl\| v_\theta\bigl((1-t)x_0 + t x_1,\; t\bigr) - (x_1 - x_0) \bigr\|_2^2 \right]$$

Exact Algebraic Equivalence Between Velocity $v_\theta$ and Score $\nabla_x \log p_t(x)$

Even when training with Flow Matching, we can recover the exact Stein score function $s_\theta(x_t, t) \approx \nabla_{x_t} \log p_t(x_t)$ (needed for stochastic SDE sampling or likelihood evaluation) at any $t \in (0, 1)$ via Tweedie's formula:

Velocity-to-Score Conversion Identity (for $x_t = \alpha_t x_1 + \sigma_t x_0$)
$$\nabla_{x_t} \log p_t(x_t) = \frac{\alpha_t \, v_\theta(x_t, t) - \dot{\alpha}_t \, x_t}{\sigma_t^2 \dot{\alpha}_t - \alpha_t \sigma_t \dot{\sigma}_t} \;\xrightarrow{\alpha_t = t,\, \sigma_t = 1-t}\; \frac{t \, v_\theta(x_t, t) - x_t}{1 - t}$$
1. Classical Diffusion (VP-SDE / DDIM) x_t = √ᾱ_t x₁ + √(1−ᾱ_t) x₀ (Curved Trajectories) p₀(x₀) Mode A Mode B Large Euler step overshoots curved path → needs 50+ NFE 2. Optimal Transport Flow Matching (SD3 / Flux) x_t = (1−t)x₀ + t x₁, u_t = x₁ − x₀ (Constant Velocity) p₀(x₀) Mode A Mode B d²x_t / dt² = 0 along conditional paths Straight trajectories → High-fidelity generation in 8–20 NFE
Figure 1: Classical curved diffusion trajectories vs. Straight Optimal Transport Flow Matching paths. Constant conditional velocity $u_t = x_1 - x_0$ minimizes ODE curvature and numerical integration error.

Logit-Normal Timestep Sampling & Resolution Shift (SD3)

When training Flow Matching with uniform timesteps $t \sim \mathcal{U}(0, 1)$, the network wastes capacity near $t \to 0$ (where the optimal prediction is simply the dataset mean $\mathbb{E}[x_1] - x_0$) and $t \to 1$ (where reconstructing $x_1$ from $x_{0.99}$ is trivial). Esser et al. (2024) demonstrated that sampling $t$ from a Logit-Normal distribution concentrates training updates at the critical perceptual transition around $t = 0.5$:

Logit-Normal Timestep Density & Resolution-Dependent Shift
$$u \sim \mathcal{N}(\mu_t, \sigma_t^2), \qquad t = \sigma(u) = \frac{1}{1 + e^{-u}}, \qquad t_{\text{shifted}} = \frac{s_{\text{res}} \cdot t}{1 + (s_{\text{res}} - 1) t}$$

where $s_{\text{res}} = \sqrt{M_{\text{tokens}} / M_{\text{base}}}$ shifts timesteps toward higher noise levels as image/video resolution $M_{\text{tokens}}$ increases (since higher spatial resolution has greater redundancy against equal-variance pixel noise).


2. Diffusion Transformers (DiT) & `adaLN-Zero` Conditioning

Replacing the convolutional U-Net with an isotropic Vision Transformer (Peebles & Xie, 2023) unlocks clean scaling laws with compute $\mathcal{C} = N_{\text{params}} \cdot M_{\text{patches}}$. How should timestep $t$ and class/text conditioning $c$ modulate each Transformer block? Peebles & Xie discovered that Adaptive LayerNorm initialized to Zero (adaLN-Zero) significantly outperforms cross-attention and in-context token conditioning at every FLOP budget:

DiT Block with adaLN-Zero Modulation ($6 \times d_{\text{model}}$ Regressors)
$$(\gamma_1, \beta_1, \alpha_1, \gamma_2, \beta_2, \alpha_2) = W_{\text{ada}}\, \text{SiLU}(t_{\text{emb}} + c_{\text{emb}})$$ $$h' = h + \alpha_1 \odot \text{Attention}\!\Bigl((1 + \gamma_1) \odot \text{LN}(h) + \beta_1\Bigr)$$ $$h_{\text{out}} = h' + \alpha_2 \odot \text{MLP}\!\Bigl((1 + \gamma_2) \odot \text{LN}(h') + \beta_2\Bigr)$$

Initializing $W_{\text{ada}} = 0$ and $b_{\text{ada}} = 0$ sets $\alpha_1 = \alpha_2 = 0$ at step $0$, making every DiT block an exact identity function ($h_{\text{out}} = h$) at initialization and stabilizing deep 40-layer training without warmup instabilities.

Latent h adaLN (γ₁, β₁) (1+γ₁)·LN(h) + β₁ Multi-Head Attn × α₁=0 adaLN + MLP (1+γ₂)·LN(h') + β₂ × α₂=0 Conditioning MLP: W_ada(SiLU(t_emb + c_emb)) → (γ₁, β₁, α₁, γ₂, β₂, α₂) W_ada and b_ada initialized to ZERO so block acts as exact identity at step 0
Figure 2: Diffusion Transformer (DiT) block with `adaLN-Zero` conditioning. Regressing $(\gamma_1, \beta_1, \alpha_1, \gamma_2, \beta_2, \alpha_2)$ from a zero-initialized linear layer ensures stable identity initialization across arbitrary depth.
PyTorch Implementation: DiT Block with adaLN-Zero & Logit-Normal CFM LossPure PyTorch
import math
import torch
import torch.nn as nn
import torch.nn.functional as F

def modulate(x: torch.Tensor, shift: torch.Tensor, scale: torch.Tensor) -> torch.Tensor:
    # x: [B, N_tokens, D], shift: [B, D], scale: [B, D]
    return x * (1.0 + scale.unsqueeze(1)) + shift.unsqueeze(1)

class DiTBlockAdaLNZero(nn.Module):
    """Diffusion Transformer Block with adaLN-Zero conditioning (Peebles & Xie, 2023)."""
    def __init__(self, d_model: int = 128, n_heads: int = 4, mlp_ratio: int = 4):
        super().__init__()
        self.norm1 = nn.LayerNorm(d_model, elementwise_affine=False, eps=1e-6)
        self.attn = nn.MultiheadAttention(d_model, n_heads, batch_first=True)
        self.norm2 = nn.LayerNorm(d_model, elementwise_affine=False, eps=1e-6)
        self.mlp = nn.Sequential(
            nn.Linear(d_model, d_model * mlp_ratio),
            nn.GELU(approximate="tanh"),
            nn.Linear(d_model * mlp_ratio, d_model)
        )
        self.adaLN_modulation = nn.Sequential(
            nn.SiLU(),
            nn.Linear(d_model, 6 * d_model, bias=True)
        )
        # Zero-initialize the modulation linear layer so alpha_1 = alpha_2 = 0 at step 0!
        nn.init.zeros_(self.adaLN_modulation[1].weight)
        nn.init.zeros_(self.adaLN_modulation[1].bias)

    def forward(self, x: torch.Tensor, cond: torch.Tensor) -> torch.Tensor:
        # x: [B, N_tokens, D], cond: [B, D] (sum of timestep and class/text embeddings)
        shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = (
            self.adaLN_modulation(cond).chunk(6, dim=-1)
        )
        h = modulate(self.norm1(x), shift_msa, scale_msa)
        attn_out, _ = self.attn(h, h, h, need_weights=False)  # [B, N_tokens, D]
        x = x + gate_msa.unsqueeze(1) * attn_out
        x = x + gate_mlp.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift_mlp, scale_mlp))
        return x

def sample_logit_normal_timesteps(
    batch_size: int,
    mu: float = 0.0,
    sigma: float = 1.0,
    res_shift: float = 1.0,
    device: str = "cpu"
) -> torch.Tensor:
    u = torch.randn(batch_size, device=device) * sigma + mu
    t = torch.sigmoid(u)
    if res_shift != 1.0:
        t = (res_shift * t) / (1.0 + (res_shift - 1.0) * t)
    return t  # [B]

def rectified_flow_loss(model_fn, x_1: torch.Tensor, cond: torch.Tensor) -> torch.Tensor:
    """Optimal Transport Conditional Flow Matching loss: E[||v_theta(x_t, t, c) - (x_1 - x_0)||^2]."""
    B = x_1.size(0)
    x_0 = torch.randn_like(x_1)  # [B, ...]
    t = sample_logit_normal_timesteps(B, device=x_1.device)
    t_broadcast = t.view(B, *([1] * (x_1.ndim - 1)))  # [B, 1, ...]

    x_t = (1.0 - t_broadcast) * x_0 + t_broadcast * x_1
    target_velocity = x_1 - x_0
    pred_velocity = model_fn(x_t, t, cond)
    return F.mse_loss(pred_velocity, target_velocity)

3. Classifier-Free Guidance (CFG) & 2nd-Order Heun ODE Integration

At inference time, we integrate $\frac{dx_t}{dt} = \hat{v}_\theta(x_t, t, c)$ from $t = 0$ ($x_0 \sim \mathcal{N}(0, I)$) to $t = 1$, where the guided velocity $\hat{v}_\theta$ linearly extrapolates from the unconditional velocity $v_\theta(x_t, t, \varnothing)$ toward the conditional velocity $v_\theta(x_t, t, c)$ with guidance scale $w \ge 1.0$:

Velocity-Space Classifier-Free Guidance & 2nd-Order Heun Step
$$\hat{v}_\theta(x_t, t, c) = v_\theta(x_t, t, \varnothing) + w \cdot \bigl(v_\theta(x_t, t, c) - v_\theta(x_t, t, \varnothing)\bigr)$$ $$\tilde{x}_{t + \Delta t} = x_t + \Delta t \, \hat{v}_\theta(x_t, t, c), \qquad x_{t + \Delta t} = x_t + \frac{\Delta t}{2}\Bigl(\hat{v}_\theta(x_t, t, c) + \hat{v}_\theta(\tilde{x}_{t + \Delta t}, t + \Delta t, c)\Bigr)$$

While 1st-order Euler integration has global truncation error $\mathcal{O}(\Delta t)$, the 2nd-order Heun predictor-corrector achieves $\mathcal{O}(\Delta t^2)$ accuracy, halving the required Number of Function Evaluations (NFE) for curved regions near $t \to 1$.

PyTorch Implementation: Euler & 2nd-Order Heun Flow ODE Solver with CFGPure PyTorch
import torch

@torch.no_grad()
def solve_flow_ode(
    velocity_fn,             # Callable(x_t, t_tensor, cond) -> velocity tensor
    x_0: torch.Tensor,       # Initial Gaussian noise [B, ...]
    cond: torch.Tensor,      # Conditioning tensor [B, ...]
    uncond: torch.Tensor,    # Null conditioning tensor [B, ...]
    num_steps: int = 20,
    cfg_scale: float = 4.5,
    solver: str = "heun"     # 'euler' (1st order) or 'heun' (2nd order predictor-corrector)
) -> torch.Tensor:
    B = x_0.size(0)
    ts = torch.linspace(0.0, 1.0, num_steps + 1, device=x_0.device)
    x_t = x_0.clone()

    def guided_v(x: torch.Tensor, t_scalar: float) -> torch.Tensor:
        t_vec = torch.full((B,), t_scalar, device=x.device, dtype=x.dtype)
        if cfg_scale == 1.0:
            return velocity_fn(x, t_vec, cond)
        v_u = velocity_fn(x, t_vec, uncond)
        v_c = velocity_fn(x, t_vec, cond)
        return v_u + cfg_scale * (v_c - v_u)

    for i in range(num_steps):
        t_cur = ts[i].item()
        t_next = ts[i + 1].item()
        dt = t_next - t_cur

        v_cur = guided_v(x_t, t_cur)
        x_euler = x_t + dt * v_cur

        if solver == "heun":
            v_next = guided_v(x_euler, t_next)
            x_t = x_t + 0.5 * dt * (v_cur + v_next)
        else:
            x_t = x_euler

    return x_t

4. Failure Modes & Generative Diagnostics

1. High-Guidance Color Saturation & Overshoot ($w \gt 7.5$): Large CFG scales amplify the orthogonal component $(v_c - v_u)$ perpendicular to the data manifold, pushing trajectories outside the support of $p_t(x)$ and producing burnt, neon-saturated artifacts.
Fix: Apply CFG Interval Clamping (Kynkäänniemi et al., 2024) – disable CFG ($w = 1.0$) for early global-layout steps $t \in [0, 0.2]$ and final high-frequency steps $t \in [0.85, 1.0]$, applying $w \gt 1$ strictly inside the middle perceptual window $t \in [0.2, 0.85]$.
2. Patchification Grid Artifacts on Final DiT Layer: If the final linear un-patching layer (Linear(d_model, p * p * C)) is initialized with standard Kaiming weights, early steps suffer massive velocity variance spikes across patch boundaries.
Fix: Always zero-initialize the final linear layer and its modulation MLP in the DiT head so the initial predicted velocity field is identically $v_\theta(x_t, t) = 0$ everywhere at step $0$.
Training Objective
Rectified Flow velocity prediction $v_\theta \approx x_1 - x_0$ with Logit-Normal $(\mu=0.0, \sigma=1.0)$ timestep sampling.
Resolution Shift $s_{\text{res}}$
$s_{\text{res}} = 1.0$ at $256^2$, $s_{\text{res}} = 3.0$ at $1024^2$ ($4096$ latent patches at $16\times$ VAE compression).
Inference Solver
20–28 Euler steps or 12–16 Heun steps with QK-Norm enabled inside all DiT attention layers.

5. Runnable End-to-End Verification: DiT Identity Init & Flow ODE Transport

The self-contained script below verifies: (1) `DiTBlockAdaLNZero` acts as an exact identity mapping at initialization ($\|f(x, c) - x\|_\infty = 0.0$), (2) training a lightweight velocity network with `rectified_flow_loss` for 200 steps transports $\mathcal{N}(0, I)$ to a target bimodal distribution, and (3) `solve_flow_ode` with 2nd-order Heun integration accurately lands on the target modes.

Runnable Verification Script: adaLN-Zero Identity, Rectified Flow Training & Heun ODEVerified PyTorch
import torch
import torch.nn as nn

def verify_flow_matching_dit():
    torch.manual_seed(42)

    # 1. Verify DiTBlockAdaLNZero exact identity at step 0
    B, N, D = 4, 16, 64
    x_lat = torch.randn(B, N, D)
    cond = torch.randn(B, D)
    dit_block = DiTBlockAdaLNZero(d_model=D, n_heads=4)
    out_init = dit_block(x_lat, cond)
    identity_diff = (out_init - x_lat).abs().max().item()
    assert identity_diff == 0.0, f"adaLN-Zero failed identity init: {identity_diff}"

    # 2. Train a tiny Conditional Rectified Flow velocity network on 2D conditional target modes
    # Class c=+1 -> target mode at (+3.0, +3.0); Class c=-1 -> target mode at (-3.0, -3.0)
    net = nn.Sequential(
        nn.Linear(2 + 1 + 1, 64),
        nn.SiLU(),
        nn.Linear(64, 64),
        nn.SiLU(),
        nn.Linear(64, 2)
    )
    opt = torch.optim.AdamW(net.parameters(), lr=1e-2)

    def model_fn(x_t: torch.Tensor, t: torch.Tensor, c: torch.Tensor) -> torch.Tensor:
        inp = torch.cat([x_t, t.unsqueeze(-1), c.unsqueeze(-1)], dim=-1)
        return net(inp)

    for _ in range(200):
        c_batch = torch.randint(0, 2, (128,)).float() * 2.0 - 1.0  # {-1, +1}
        x1_batch = c_batch.unsqueeze(-1) * 3.0 + 0.1 * torch.randn(128, 2)
        loss = rectified_flow_loss(model_fn, x1_batch, c_batch)
        opt.zero_grad()
        loss.backward()
        opt.step()

    # 3. Integrate Probability Flow ODE using 2nd-order Heun solver for class c=+1
    x0_test = torch.randn(64, 2)
    c_pos = torch.ones(64)
    c_null = torch.zeros(64)
    x1_gen = solve_flow_ode(model_fn, x0_test, c_pos, c_null, num_steps=16, cfg_scale=1.0, solver="heun")
    gen_mean = x1_gen.mean(dim=0)
    dist_to_target = (gen_mean - torch.tensor([3.0, 3.0])).norm().item()
    assert dist_to_target < 0.35, f"Flow ODE transport error too high: {dist_to_target}"

    print(f"[PASS] DiT adaLN-Zero Step-0 Identity Diff : {identity_diff:.1e} (Exact Identity!)")
    print(f"[PASS] Final Rectified Flow Training Loss  : {loss.item():.4f}")
    print(f"[PASS] Heun ODE Generated Mode Mean        : ({gen_mean[0]:.2f}, {gen_mean[1]:.2f}) vs Target (3.00, 3.00)")

if __name__ == "__main__":
    verify_flow_matching_dit()

6. Generative Transport Frameworks: Head-to-Head

Dimension DDPM (VP-SDE) Score SDE / EDM OT Flow Matching (Rectified Flow)
Forward Path $x_t$ $\sqrt{\bar{\alpha}_t} x_1 + \sqrt{1 - \bar{\alpha}_t} x_0$ $x_1 + \sigma(t) x_0$ $(1 - t) x_0 + t x_1$
Network Target Noise $\epsilon_\theta \approx x_0$ Preconditioned Denoiser $D_\theta \approx x_1$ Velocity $v_\theta \approx x_1 - x_0$
Trajectory Geometry Curved (high $\frac{d^2 x_t}{dt^2}$) Curved variance-exploding Straight Euclidean line ($\frac{d^2 x_t}{dt^2} = 0$)
Timestep Sampling Discrete uniform $t \in \{1..1000\}$ Log-Normal $\ln \sigma \sim \mathcal{N}(P_{\text{mean}}, P_{\text{std}}^2)$ Logit-Normal $t = \sigma(\mathcal{N}(\mu, \sigma^2))$ + Res Shift
Typical Sampling NFE $50$ – $1000$ steps $25$ – $50$ steps (Heun) $8$ – $25$ steps (Euler / Heun)