一句话,五个直觉,四个互动演示

你看不见的那一层高维球壳
正是 Flow Matching 学的东西

"Flow-matching 倾向于让网络学习噪声的流动方向(的集合),对应就是有偏置的高维球壳上一段在固定条件控制下的运动轨迹。"

如果你第一次读这句话觉得"每个字都认识、合起来像谜语"——这正常。
它把训练目标、高维几何、条件生成这三件互相纠缠的事情压缩成了一句话。
我们用 5 个停靠站一一拆开,每个站都配一个能拖动、能播放的小演示。

阅读时间 · ~15 分钟 需要的背景 · 基本机器学习、基本微积分 更新于 · 2026

第 0 站

这句话到底说了什么?

这句话其实是把三件不同的事叠加在一起讲:

1 · 训练目标

"噪声的流动方向(的集合)"

网络要学的不是一张图、不是一个噪声,而是一个速度场 $u_\theta(x, t)$:在每个时间、每个空间点上,告诉粒子"你下一步往哪走"。

2 · 几何形状

"高维球壳"

高维标准正态分布 $N(0, I_d)$ 的几乎所有样本都集中在半径 $\sqrt{d}$ 的一层薄壳上——这是个反直觉但精确的事实。

3 · 条件控制

"固定条件控制下的轨迹"

你给一个 prompt / class / mask(这就是"条件"),同一个噪声会被推向不同的目的地。条件就是"偏置",决定了流的方向。

本文路线:第 1 站讲清"流匹配在学什么";第 2 站揭示"高维噪声是一层壳"这个反直觉事实;第 3 站把前两站拼起来,看流匹配是怎么"在壳上走路"的;第 4 站加入条件,看"偏置"到底偏置了什么;第 5 站把原句重读一遍,每个词都有了形象的画面;最后给一段最小可运行代码和论文索引。

第 1 站

流匹配在学什么?—— 把噪声"运输"到数据

所有生成模型本质上都在做一件事:把一个简单分布(例如 $N(0, I)$)变成一个复杂分布(例如所有自然图像的分布)。

不同的生成模型只是用不同的方式去做"运输":

  • GAN:一步把噪声变成图(生成器是一个大函数 $G: z \mapsto x$)
  • Diffusion:分很多步,每步去掉一点噪声
  • Flow Matching:把整个过程看成一个连续时间的常微分方程(ODE),学这个 ODE 的速度场

具体来说,定义一族中间分布 $p_t$,从 $p_0 = N(0, I)$(纯噪声)连续过渡到 $p_1 = $ 数据分布。每个粒子 $x_t$ 在每个时刻有一个速度 $\frac{dx}{dt}$,所有这些速度合起来就是一个向量场 / 速度场

$$\frac{d x_t}{dt} = u_\theta(x_t, t)$$

网络 $u_\theta$ 输入"位置 + 时间",输出"该往哪个方向走多快"。

最简单也最常用的一种设计,叫 Rectified Flow / Conditional Flow Matching with optimal-transport-style coupling:让粒子走直线。

$$x_t = (1-t)\,x_0 + t\,x_1$$ $$\text{真值速度} = \frac{d x_t}{dt} = x_1 - x_0$$ $$\mathcal{L}(\theta) = \mathbb{E}_{x_0 \sim N(0,I),\,x_1 \sim \text{data},\,t \sim U[0,1]} \big\| u_\theta(x_t, t) - (x_1 - x_0) \big\|^2$$

训练 = 让网络预测"从此刻 $x_t$ 出发,走到目标 $x_1$ 的方向是什么"。这就是"学习噪声的流动方向"的精确含义。

互动演示 A

看噪声变成"两弯月亮"

下面这个 2D 演示里,蓝色点是 $N(0, I_2)$ 噪声,橙色点是目标"双月"分布。拖动时间滑块,你会看到每个粒子沿直线从蓝点滑到对应的橙点——这就是 rectified flow 学的轨迹族。背景的小箭头是平均速度场。

一句话总结:训练好的网络 = 把每一个 "(位置, 时间)" 对映射到 "(下一步该往哪)"。它学的不是一个方向,而是整个空间 × 整个时间区间上的方向——所以是"流动方向的集合"。

第 2 站

反直觉时刻:高维 Gaussian 根本不是"一团云"

问你一个问题:你脑海里的 $N(0, I_d)$(d 很大,比如 1024)长什么样?

大多数人的第一反应:"一团绕着原点的雾,大部分概率密度在原点附近,越远越稀疏"——这在 1 维、2 维、3 维都对,但到了高维,这个图像是错的

真相是:对于 $x \sim N(0, I_d)$,

$$\mathbb{E}\big[\|x\|^2\big] = d, \qquad \text{Var}\big[\|x\|^2\big] = 2d$$

用一阶展开可以得到 $\|x\| \approx \sqrt{d}$,并且波动大约是 $1/\sqrt{2}$,几乎不随 $d$ 改变

这意味着:维度越高,所有样本都被"挤"到半径 $\sqrt{d}$ 的一层薄壳上。

这是经典的 测度浓度 (concentration of measure) 现象。形象地说:

维度 $d$典型范数 $\sqrt{d}$相对厚度(壳厚 / 半径)视觉
21.41~50%胖团
103.16~22%稍微集中的云
10010.0~7%初见壳形
102432.0~2.2%明显的薄壳
409664.0~1.1%极薄的壳
16384128.0~0.55%几乎是个完美球面

SD3 / Flux / DiT 这类现代生成模型,工作维度通常是 latent 的 $4 \times 64 \times 64 = 16384$ 或更大。所谓"采样一个噪声 $x_0$",几何上就是在那层薄薄的 $\sqrt{d}$ 球壳上随机取一个点。

互动演示 B

亲眼看见"球壳"从云里浮现

拖动滑块改变维度 $d$。上图:原始范数 $\|x\|$ 的直方图,竖线标出 $\sqrt{d}$。下图:归一化范数 $\|x\| / \sqrt{d}$ 的直方图。维度越高,下图越收缩成一根针——所有样本都凑到了 1 附近。

μ = ..., σ = ...

一句话总结:当我们说"从高维 Gaussian 采样"时,几何上你不是在原点附近抓一把雾,而是在一个半径 $\sqrt{d}$ 的薄壳上随手一点。"高维球壳"——精确得不能再精确。

第 3 站

把两件事拼起来:流匹配 = 球壳上的散步

现在我们把第 1 站(速度场)和第 2 站(球壳)拼起来。

  1. 起点:$x_0 \sim N(0, I_d)$,几乎一定满足 $\|x_0\| \approx \sqrt{d}$——位于噪声壳上。
  2. 终点:$x_1 \sim p_{\text{data}}$。真实数据(图像 latent、speech token、3D 点云……)通常也有自己的典型范数 $\|x_1\| \approx R_{\text{data}}$,所以也大致活在某个"数据壳"上
  3. 中途:$x_t = (1-t) x_0 + t x_1$,它的范数会从 $\sqrt{d}$ 平滑过渡到 $R_{\text{data}}$。

所以一整条轨迹的形状是:

噪声壳出发 → 一段 带方向 的连续运动 → 到达数据流形
这就是原句里说的"球壳上一段运动轨迹"。

速度场 $u_\theta(x_t, t)$ 在每一点上其实可以分解为两个分量:

  • 径向分量 $u_r$:决定范数怎么变(壳半径的演化);
  • 切向分量 $u_\perp$:决定在壳上朝哪个方向转(这就是"瞄向哪个目标点")。

对早期 $t$(接近 0),$x_t$ 离 $x_0$ 很近、还在噪声壳附近,所以速度场主要在做切向调整——决定"这粒噪声将来要变成猫还是变成狗"。对后期 $t$(接近 1),径向分量才开始压缩范数,让样本落到数据流形上。

互动演示 C

看高维轨迹的"范数轮廓"

这里我们模拟一个 $d$ 维(可调)的 rectified flow,画出 20 条轨迹的 $\|x_t\|$ 随 $t$ 的变化。你会看到:起点都在 $\sqrt{d}$ 附近抱成一束,中途各自滑行,终点落到一个较小的"数据壳"上。每一条曲线 = 一条"球壳上的运动轨迹"。

一句话总结:训练流匹配 = 教网络在两个球壳之间画出一束有方向的曲线。每一条曲线就是一个"$x_0 \to x_1$"的故事。

第 4 站

"偏置"是什么?—— 条件信息决定壳上选哪条路

现在最后一块拼图:原句里的"有偏置的"和"固定条件控制下"到底什么意思?

同一个噪声出发点 $x_0$,不能同时变成猫、变成狗、变成宇航员。要让它确定地变成"猫",必须告诉网络一个条件 $c$("猫"这个 prompt / class / image / mask)。

训练时改成条件流匹配

$$\mathcal{L}(\theta) = \mathbb{E}_{x_0, x_1, t, c}\big\| u_\theta(x_t, t, c) - (x_1 - x_0) \big\|^2$$

速度场多了一个输入 $c$。同一个 $(x, t)$ 在不同 $c$ 下,速度方向不一样

几何上:原本"无条件速度场"会把每个噪声粒子推向"所有可能数据的某种平均"(图像里就是模糊的平均脸)。一旦你给了条件 $c$,速度场就被偏置(biased)到指向"$c$ 对应的那一小块数据流形"。

这就是为什么 Classifier-Free Guidance(CFG)work:

$$u_{\text{guided}}(x, t) \;=\; u(x, t \mid c) \;+\; w \cdot \big[u(x, t \mid c) - u(x, t \mid \varnothing)\big]$$

$u(x, t \mid c) - u(x, t \mid \varnothing)$ 就是条件特有的"偏置方向",乘上系数 $w$ 再加回去,等于"让方向更偏向条件一点"。

互动演示 D

同一束噪声,三种条件,三套轨迹

三个目标聚类(红 / 绿 / 蓝)放在一个圆上。同一批噪声粒子作为起点。点击不同的"条件"按钮,看同一组粒子被推向完全不同的目的地。这就是"偏置"在做的事。

一句话总结:"偏置"不是模型有 bug,而是条件信号偏置了速度场。同一个噪声壳上的同一个点,在不同条件下走向不同未来——这就是"固定条件控制下的运动轨迹"。

第 5 站

重读那句话

现在你有了 4 个停靠站、4 个互动演示作为锚点,再读一次原句:

flow-matching 倾向于让网络学习噪声的流动方向(的集合) 第 1 站:网络学的是速度场 $u_\theta(x, t)$,覆盖整个空间×时间,所以是"方向的集合"。

,对应就是 → 这个速度场对应一族 ODE 轨迹。

有偏置的高维球壳 第 2 + 4 站:起点在 $\sqrt{d}$ 的噪声壳上;偏置由条件 $c$ 给出,决定壳上"哪一片"被选中。

上一段 第 3 站:一段从噪声壳 → 数据流形的连续曲线,参数化在 $t \in [0, 1]$ 上。

在固定条件控制下的运动轨迹 第 4 站:条件 $c$ 一旦固定,从同一个 $x_0$ 出发的轨迹就被唯一决定(ODE 是确定性的)。

一句话翻译:训练 Flow Matching = 教一个神经网络速度场,让它能把"$\sqrt{d}$ 球壳上一个随机点"通过一段连续的、被条件信号偏置的轨迹,送到"数据流形上某个具体的点"。

第 6 站

实践中的样子 —— 一段最小可读代码 + 论文索引

下面是最小化的条件 rectified flow 训练 + 采样片段。50 行内就能跑通,可以一对一对应到上面五站的概念:

# PyTorch 风格伪代码 —— 条件 Rectified Flow,最小版本
import torch
import torch.nn.functional as F

def train_step(model, x1, c, optimizer):
    # x1: 一个 batch 的真实数据 (B, D);c: 条件 (B, ...)
    x0 = torch.randn_like(x1)                # ← 高维球壳上的样本(第 2 站)
    t  = torch.rand(x1.size(0), 1, device=x1.device)

    xt     = (1 - t) * x0 + t * x1           # ← 一段轨迹(第 3 站)
    target = x1 - x0                         # ← "噪声的流动方向"(第 1 站)
    pred   = model(xt, t.squeeze(-1), c)     # ← u_θ(x, t, c) 学到的速度

    loss = F.mse_loss(pred, target)          # ← 条件流匹配损失(第 4 站)
    optimizer.zero_grad(); loss.backward(); optimizer.step()
    return loss.item()


@torch.no_grad()
def sample(model, c, D, steps=50, cfg_scale=0.0):
    # 推理:从噪声壳上一点出发,沿 ODE 积分到 t=1
    x = torch.randn(c.size(0), D)            # ← 起点:随机一个噪声壳上的点
    dt = 1.0 / steps
    for k in range(steps):
        t = torch.full((c.size(0),), k * dt, device=x.device)
        v_c   = model(x, t, c)               # ← 条件方向
        if cfg_scale > 0:
            v_u = model(x, t, torch.zeros_like(c))  # ← 无条件方向
            v = v_c + cfg_scale * (v_c - v_u)        # ← CFG 偏置(第 4 站公式)
        else:
            v = v_c
        x = x + v * dt                       # ← 欧拉法走一小步
    return x

每一行代码都对应到原句的某个词:x0 = torch.randn_like(x1) 在视觉化层面就是选了高维球壳上一个点target = x1 - x0 就是这一粒噪声的"流动方向";模型的输入 $c$ 就是那个"偏置";从 $t=0$ 走到 $t=1$ 的循环就是那"一段运动轨迹"

进一步阅读

从入门到现代实践的推荐顺序:

  • 入门读物:"An Introduction to Flow Matching" — Cambridge MLG blog (https://mlg.eng.cam.ac.uk/blog/2024/01/20/flow-matching.html)。如果你只读一篇,读这个。
  • 原始论文:Lipman et al., Flow Matching for Generative Modeling, ICLR 2023.
  • 等价/同期工作:Liu et al., Flow Straight and Fast: Learning to Generate and Transfer Data with Rectified Flow, 2022/23.
    Albergo & Vanden-Eijnden, Building Normalizing Flows with Stochastic Interpolants, 2023.
  • OT 耦合改进:Tong et al., Improving and Generalizing Flow-Based Generative Models with Minibatch Optimal Transport, TMLR 2024.
  • 大规模实践:Esser et al. (Stability AI), Scaling Rectified Flow Transformers for High-Resolution Image Synthesis, 2024 (SD3 paper)。
    Black Forest Labs, Flux, 2024。
  • 高维几何/浓度测度(理解"球壳"那部分的数学):Vershynin, High-Dimensional Probability, 2018。看第 3 章就够了。
  • 蒸馏与一步采样:Liu et al., InstaFlow; Yin et al., One-Step Diffusion Distillation。这些工作都是在尝试"把那段球壳上的轨迹拉直成一步跳"。

留给你的最后一个图像:下次当你看到训练日志上流过的 loss 数字时,记住——网络正在干一件几何上非常优雅的事:它在学怎么在一层维度为几千的薄薄球壳上画地图,每一张地图对应一个 prompt。你看到的每一张 Flux 出图,都是从那层壳上随手摸的一个点,沿着这张地图、走过一段轨迹、最终来到你眼前的图像分布上。