Type at least 2 letters. Enter opens the first result, Esc closes.

    learn.mohebi.ai

    Diffusion and flow matching in 2D

    Watch noise turn into data on small 2D examples. Add noise to a data set, see the score field that points back to the data, and sample with the reverse SDE, the probability-flow ODE and flow matching. Everything is computed exactly in your browser; nothing is trained.

    A diffusion model creates new data (images, sounds, molecules) from pure noise. It learns to undo a fixed process that destroys data by adding noise step by step. On this page you see the whole idea on points in the plane:

    A real model learns the score with a neural network. Here the data distribution is a mixture of small Gaussians around the data points, so the noised density and its score have a closed form. The score in every figure is exact, not learned. This lets you see the sampling methods themselves, without training errors, and see clearly why few sampling steps give blurry results.

    1. The playground #

    Interactive figure: loading…

    Move the time slider, or press Play. The blue dots are the data x0x_0; the noised points xt=atx0+σtεx_t = a_t x_0 + \sigma_t \varepsilon turn from blue to aqua as tt goes from 0 to 1. The blue shading is the noised density ptp_t, and the violet arrows show the exact score, scaled as σt∇log⁡pt\sigma_t \nabla \log p_t so that all arrows have a similar size (arrow length grows with the size, up to a cap). Then choose Reverse: sample. Particles start as noise at t=1t = 1 and move along magenta paths to samples at t=0t = 0. Change the sampler and the number of steps NN; the panel reports the distance of the samples to the data. Choose draw to click your own data set.

    2. Paths through time #

    Interactive figure: loading…

    Pick a process and change the number of steps. Here the data are one-dimensional, so we can draw time on the horizontal axis: data at t=0t = 0 on the left, noise at t=1t = 1 on the right. The shading is the exact density pt(x)p_t(x), scaled in each column. Magenta: particle paths. For N≤12N \le 12 the yellow dashed lines show where each step aims: the denoiser's guess x^0=D(xt)\hat x_0 = D(x_t) on the left axis. On the far left, the orange histogram of 4000 final samples is compared with the data density. Compare DDIM and Flow matching with the same NN: the shading of flow matching spreads along straight lines.

    3. Few steps or many #

    Interactive figure: loading…

    Choose a sampler and a data set. The six panels show the final samples of the same noise points for N=1,2,4,8,16,64N = 1, 2, 4, 8, 16, 64 steps, over the data. The chart shows the distance dd to the data (sliced Wasserstein-2, explained below) against NN for all four samplers; the chosen one is orange. The grey band is the distance between two sets of true samples of the same size: inside or below the band, the samples are as good as we can measure.

    4. Try this #

    1. When is the shape gone? In the playground, choose two moons and Forward, and move tt slowly from 0 to 1. Question: at which tt can you no longer see two moons, and where do the arrows point at t=1t = 1? What to see: the schedule destroys the shape fast. At t=0.1t = 0.1 the signal scale is at=0.95a_t = 0.95 and the moons are clear; at t=0.3t = 0.3, at=0.63a_t = 0.63 and σt=0.78\sigma_t = 0.78, and the moons have merged into one cloud. At t=1t = 1, p1≈N(0,I)p_1 \approx \mathcal N(0, I), so the score is about −x-x: every arrow points to the origin.
    2. One step gives the average. Choose Reverse, the sampler DDIM and N=1N = 1, then N=2,4,8,16N = 2, 4, 8, 16. Question: where do the samples land with one step? What to see: with N=1N = 1 all samples land on one point, the mean of the data (here the origin). With 2 and 4 steps the samples form a blurry cloud between the moons. With 16 steps they lie on the moons (the badge says close to the data). In Figure 2, choose 80 / 20, DDIM and N=1N = 1: every path ends at x≈−0.72x \approx -0.72, which is the mean 0.8⋅(−1.2)+0.2⋅1.20.8 \cdot (-1.2) + 0.2 \cdot 1.2.
    3. Same start, same end? Set DDIM with N=40N = 40 and press Sample again twice. Then do the same with DDPM. Question: which sampler is a fixed map from noise to data? What to see: DDIM draws exactly the same paths and samples again; DDPM draws new paths every time from the same starting noise, because it adds fresh noise at every step. In Figure 2 the ODE paths never cross; the SDE paths cross often.
    4. Too much noise. Choose Euler–Maruyama with N=2N = 2, then N=10N = 10, then N=40N = 40, and compare with DDPM at the same NN. Question: both methods sample the same reverse SDE; why do they fail in different ways with few steps? What to see: at N=2N = 2 the Euler–Maruyama points fly out of the frame: the first step has β(1)Δt=10\beta(1)\Delta t = 10, far too large for an explicit method. DDPM stays in the frame, because each step draws from an exact Gaussian; its error with few steps is blur. At N=10N = 10 the Euler–Maruyama samples are a noisy band around the moons, and the DDPM samples are still too smooth. At N=40N = 40 both are close to the data: the distance is near that of true samples. Figure 3 shows that Euler–Maruyama needs the most steps of the four samplers.
    5. Straight lines in training, curves in sampling. Choose Flow matching, turn on training pairs and sample with N=40N = 40. Question: do the paths follow the grey dashed lines from noise to data? What to see: no. Each training pair (x0,ε)(x_0, \varepsilon) is joined by a straight line, but these lines cross. The model learns the average velocity of all lines through a point, so the sampling paths bend and never cross. They are still straighter than the DDIM paths: compare both samplers at N=4N = 4 in Figure 3.
    6. The exact score copies the data. Choose draw and click five separate points. Set the kernel width ss to 0.030.03 and sample with DDIM and N=64N = 64. Question: does the model create new points? What to see: every sample lands on one of your five points. The exact score of a small data set reproduces the training data; this is memorization. Increase ss and the five points become five blobs. A trained network does not learn this exact score, and that is one reason why real diffusion models can create new data.

    5. The math in short #

    The forward process and DDPM #

    DDPM (denoising diffusion probabilistic models, Ho et al. 2020) adds a little Gaussian noise in each of TT steps:

    q(xt∣xt−1)=N ⁣(1−βt xt−1, βtI).q(x_t \mid x_{t-1}) = \mathcal N\!\big(\sqrt{1 - \beta_t}\, x_{t-1},\ \beta_t I\big).

    A sum of independent Gaussians is Gaussian, so we can jump to any step at once: xt=αˉt x0+1−αˉt εx_t = \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\, \varepsilon with αˉt=∏s≤t(1−βs)\bar\alpha_t = \prod_{s \le t} (1 - \beta_s) and ε∼N(0,I)\varepsilon \sim \mathcal N(0, I). With many small steps this becomes the variance-preserving (VP) SDE of Song et al. (2021), with continuous time t∈[0,1]t \in [0, 1]:

    dx=−12β(t) x dt+β(t) dw,xt=atx0+σtε,at=e−12∫0tβ(s) ds,σt2=1−at2.dx = -\tfrac12 \beta(t)\, x\, dt + \sqrt{\beta(t)}\, dw, \qquad x_t = a_t x_0 + \sigma_t \varepsilon, \quad a_t = e^{-\frac12 \int_0^t \beta(s)\, ds}, \quad \sigma_t^2 = 1 - a_t^2 .

    Here ww is Brownian motion. The figures use β(t)=0.1+19.9 t\beta(t) = 0.1 + 19.9\, t, so a1≈0.007a_1 \approx 0.007: at t=1t = 1 almost no signal is left. "Variance preserving" means that data with unit variance keep unit variance. The signal-to-noise ratio is SNR(t)=at2/σt2\mathrm{SNR}(t) = a_t^2 / \sigma_t^2.

    DDPM trains a network ε^θ(xt,t)\hat\varepsilon_\theta(x_t, t) to predict the noise that was added, with the loss E ∥ε−ε^θ(xt,t)∥2\mathbb E\, \|\varepsilon - \hat\varepsilon_\theta(x_t, t)\|^2. The best possible prediction is the conditional mean E[ε∣xt]\mathbb E[\varepsilon \mid x_t], and the next section shows that this is the score up to a factor.

    The score and the denoiser #

    The score of the noised density ptp_t is ∇xlog⁡pt(x)\nabla_x \log p_t(x). The denoiser D(x)=E[x0∣xt=x]D(x) = \mathbb E[x_0 \mid x_t = x] is the best guess of the clean point (best in mean squared error). Tweedie's formula connects the two:

    D(x)=x+σt2 ∇xlog⁡pt(x)at,E[ε∣xt=x]=−σt ∇xlog⁡pt(x).D(x) = \frac{x + \sigma_t^2\, \nabla_x \log p_t(x)}{a_t}, \qquad \mathbb E[\varepsilon \mid x_t = x] = -\sigma_t\, \nabla_x \log p_t(x).

    So "predict the noise", "predict the clean point" and "learn the score" are the same task.

    The exact score of these figures. Each data set is a mixture pdata=∑kπk N(μk,s2I)p_{\text{data}} = \sum_k \pi_k\, \mathcal N(\mu_k, s^2 I): one small Gaussian of width ss (the kernel width) around each data point μk\mu_k. Noising maps N(μk,s2I)\mathcal N(\mu_k, s^2 I) to N(atμk,vtI)\mathcal N(a_t \mu_k, v_t I) with vt=at2s2+σt2v_t = a_t^2 s^2 + \sigma_t^2. With the responsibilities wk(x)∝πk N(x; atμk, vtI)w_k(x) \propto \pi_k\, \mathcal N(x;\ a_t \mu_k,\ v_t I) and their weighted mean m(x)=∑kwk(x) μkm(x) = \sum_k w_k(x)\, \mu_k:

    ∇xlog⁡pt(x)=−x−at m(x)vt,D(x)=σt2vt m(x)+ats2vt x.\nabla_x \log p_t(x) = -\frac{x - a_t\, m(x)}{v_t}, \qquad D(x) = \frac{\sigma_t^2}{v_t}\, m(x) + \frac{a_t s^2}{v_t}\, x .

    Near the data (small tt) one weight wkw_k is close to 1, so the score points to the nearest data point. When the noise is large, all wkw_k are about equal, m(x)m(x) is the mean of the data, and the score points toward atma_t m, the scaled mean.

    Quick check

    At t=1t = 1 the noised density is almost N(0,I)\mathcal N(0, I). What is the denoiser's guess D(x1)D(x_1) for a point x1x_1 drawn there?

    The reverse SDE and the probability-flow ODE #

    For a forward SDE dx=f(x,t) dt+g(t) dwdx = f(x, t)\, dt + g(t)\, dw, the process run backward in time is again an SDE (Anderson 1982):

    dx=[f(x,t)−g(t)2 ∇xlog⁡pt(x)] dt+g(t) dwˉ(t from 1 to 0),dx = \big[f(x, t) - g(t)^2\, \nabla_x \log p_t(x)\big]\, dt + g(t)\, d\bar w \qquad (t \text{ from } 1 \text{ to } 0),

    where wˉ\bar w is a Brownian motion in reverse time. Song et al. (2021) showed that the deterministic probability-flow ODE

    dxdt=f(x,t)−12 g(t)2 ∇xlog⁡pt(x)\frac{dx}{dt} = f(x, t) - \tfrac12\, g(t)^2\, \nabla_x \log p_t(x)

    has the same marginal densities ptp_t for every tt. Both start from p1≈N(0,I)p_1 \approx \mathcal N(0, I) and end at p0=pdatap_0 = p_{\text{data}}. The SDE paths are random and cross each other; the ODE paths are smooth, never cross, and define a fixed, invertible map from noise to data. For the VP SDE, f=−12βxf = -\tfrac12\beta x and g=βg = \sqrt\beta.

    The four samplers use the time grid ti=1−i/Nt_i = 1 - i/N and take NN steps, one score evaluation per step:

    Quick check

    You start DDIM and DDPM twice each from the same noise x1x_1, with 50 steps. What do you get?

    Flow matching #

    Flow matching (Lipman et al. 2023; also called rectified flow, Liu et al. 2023) uses the straight line between a data point and a noise point:

    xt=(1−t) x0+t ε,dxtdt=ε−x0.x_t = (1 - t)\, x_0 + t\, \varepsilon, \qquad \frac{d x_t}{dt} = \varepsilon - x_0 .

    A network vθ(x,t)v_\theta(x, t) is trained with E ∥vθ(xt,t)−(ε−x0)∥2\mathbb E\, \|v_\theta(x_t, t) - (\varepsilon - x_0)\|^2. The best solution is the average velocity of all pairs whose line passes through xx:

    v(x,t)=E[ε−x0∣xt=x]=x−D(x)t.v(x, t) = \mathbb E[\varepsilon - x_0 \mid x_t = x] = \frac{x - D(x)}{t}.

    Sampling solves dx/dt=v(x,t)dx/dt = v(x, t) from t=1t = 1 to t=0t = 0. The figures use the convention t=0t = 0 for data and t=1t = 1 for noise, as in DDPM and in Stable Diffusion 3; Lipman et al. use the opposite direction.

    Two facts are useful. First, an Euler step xt′=D(xt)+t′t(xt−D(xt))x_{t'} = D(x_t) + \tfrac{t'}{t}\big(x_t - D(x_t)\big) moves on the straight line from xtx_t toward the current guess x^0=D(xt)\hat x_0 = D(x_t), as the yellow lines in Figure 2 show. Second, this path is also a Gaussian path xt=atx0+σtεx_t = a_t x_0 + \sigma_t \varepsilon (with at=1−ta_t = 1 - t, σt=t\sigma_t = t). With the exact score, its ODE and the probability-flow ODE of the VP SDE send the same noise point to (almost exactly) the same data point; only the path in between differs. The flow-matching path bends less, so Euler steps make smaller errors.

    Quick check

    Flow matching is trained on straight lines from x0x_0 to ε\varepsilon. Are the sampling paths of the trained model straight?

    Why few steps blur the result #

    Every DDPM, DDIM and flow-matching step moves toward the guess x^0=D(xt)=E[x0∣xt]\hat x_0 = D(x_t) = \mathbb E[x_0 \mid x_t]. This guess is an average over all clean points that could have produced xtx_t. When the noise is large, many very different clean points are possible, so their average lies between them: between the two moons, or in the middle of the ring.

    This is why fast samplers follow straighter paths (flow matching, rectified flow), use higher-order ODE solvers, or train a model to jump along the ODE in one step (distillation and consistency models).

    Distances between point clouds

    The panels report the sliced Wasserstein-2 distance between the samples {yi}\{y_i\} and true samples {xi}\{x_i\} of the same size nn. Project both sets onto a direction uu; in one dimension the Wasserstein-2 distance pairs the sorted values: W22=1n∑i(u⊤x(i)−u⊤y(i))2W_2^2 = \frac1n \sum_i \big(u^\top x_{(i)} - u^\top y_{(i)}\big)^2. The sliced distance averages W22W_2^2 over 24 evenly spaced directions and takes the square root. It sees both errors: samples that are too concentrated (blur) and samples that are too spread (noise). With a finite nn even two sets of true samples have a distance above 0; this is the grey band in Figure 3.

    6. Learn more on this site #