21. Flow-Matching
A difusão funciona e é um jeito estranho de ter chegado a algo que funciona. Há uma equação diferencial estocástica, um limite variacional, um cronograma de ruído com nome próprio, uma cadeia discreta de mil passos e três parametrizações intercambiáveis. O método não é complicado — a dedução é.
O flow matching1 chega ao mesmo lugar pela outra direção e a montagem cabe em três linhas. Sorteie uma amostra de ruído e uma de dados. Trace a reta entre elas. Treine uma rede para prever a direção do deslocamento num ponto aleatório dessa reta. É o método inteiro.
Sem cronograma, sem limite, sem cadeia. E — esta é a parte que vale deixar clara — não é uma família diferente de modelo. Difusão é flow matching com um interpolante curvo. Assim que você vê isso, os últimos quatro capítulos colapsam numa ideia só.
Movendo partículas
Você tem partículas distribuídas como \(p_0 = \mathcal{N}(0, I)\). Você as quer distribuídas como seus dados no tempo \(t = 1\). Aprenda um campo de velocidade \(v_\theta(x, t)\) que diga para onde cada partícula deve se mover em cada instante e integre.
Há um problema óbvio em treinar isso e é aquele em que a área toda estava travada. O campo de velocidade de que você precisa é um marginal: na posição \(x\) e no tempo \(t\), ele precisa fazer média sobre todo ponto de dados que plausivelmente poderia ter produzido \(x\). Você não consegue calcular isso. Você nem consegue escrever.
O teorema que faz funcionar
Você não precisa. Regredir a velocidade condicional — a de um único par sorteado \((x_0, x_1)\), que é simplesmente \(x_1 - x_0\) — tem o mesmo gradiente que regredir a marginal intratável1. Então você treina sobre um alvo que cabe numa linha e a rede converge para o campo que você de fato queria.
É exatamente o movimento que o DDPM faz ao regredir \(\epsilon\) em vez do score. Mesmo truque, enunciado uma vez e em geral, em vez de uma vez por cronograma de ruído.
A difusão é um caso particular
Tome um par qualquer de funções \(a(t)\), \(b(t)\) e defina o interpolante
Todo método deste módulo é uma escolha de \(a\) e \(b\):
| Método | \(a(t)\) | \(b(t)\) | Formato do caminho |
|---|---|---|---|
| DDPM / difusão | \(\sqrt{\bar\alpha_t}\) | \(\sqrt{1 - \bar\alpha_t}\) | Curvo — um quarto de círculo |
| Flow matching (caminho OT) | \(t\) | \(1 - t\) | Reto, por par |
| Fluxo retificado3 | \(t\) | \(1 - t\) | Reto e reacoplado |
A velocidade condicional é \(a'(t)x_1 + b'(t)x_0\) em todos os casos e a marginal é a esperança condicional dela. Um framework, uma perda, um código. As diferenças restantes são a ponderação da perda ao longo de \(t\) e o formato da trajetória — que é o que o próximo painel mede.
O que "caminhos mais retos" de fato significa
A afirmação padrão é que o flow matching dá trajetórias retas e por isso precisa de menos passos de integração. É meio verdade e a metade que é falsa vale conhecer.
Tudo naquele painel é exato — o alvo é uma mistura de gaussianas, então as velocidades marginais dos dois interpolantes têm forma fechada e nada é treinado. Compare os dois e:
- O caminho condicional — a reta entre uma amostra de ruído e uma de dados — é reto por construção com o interpolante linear.
- O caminho marginal, que é o que o modelo de fato aprende, não é. Ele precisa fazer média sobre todo ponto de dados compatível com a posição atual e ruído e dados acoplados de forma independente se cruzam o tempo todo. Neste alvo, os caminhos aprendidos com o interpolante linear saem mais curvos que os de difusão.
- Passados uns 32 passos, os dois interpolantes convergem para o mesmo erro. O argumento inteiro é sobre o regime de poucos passos.
A vantagem real do flow matching não é a trajetória
É o objetivo: uma única regressão sem ponderação, sem cronograma a ajustar, com peso uniforme ao longo de \(t\) e sem a decisão \(\epsilon\)-versus-\(\mathbf{v}\) para errar em ruído alto. É por isso que SD3 e FLUX o adotaram. Afirmações de "2–10× menos passos" vindas só do interpolante não sobrevivem a uma medição cuidadosa; os ganhos de passos vêm de reflow e destilação, que é a próxima seção.
Fluxo retificado: endireitar de propósito
Se os caminhos não são retos, endireite-os3. O reflow são dois passos:
- Sorteie ruído \(z\), integre a ODE treinada com precisão, obtenha \(x = \text{ODE}(z)\).
- Retreine o modelo nos pares \((z, x)\) que ele mesmo produziu, na reta entre eles.
A distribuição marginal de \(x\) não muda — você não está alterando o que o modelo gera, apenas qual ruído é pareado com qual saída. Mas o acoplamento agora é um que o modelo consegue realizar com uma reta e uma reta é integrada exatamente por um passo de Euler.
Marque depois de um reflow no painel e a curvatura vai a zero e o erro vai a zero em qualquer número de passos. É esse o mecanismo por trás da geração de um passo e de poucos passos e é por isso que SD3 e FLUX são descritos como modelos de fluxo retificado e não meramente de flow matching.
| Para onde vai a partir dali | Ideia |
|---|---|
| Modelos de consistência4 | Treinar o mapa de qualquer ponto da trajetória direto para o ponto final. Autoconsistência é a perda. |
| Modelos de atalho5 | Condicionar a rede no próprio tamanho do passo, para que um modelo sirva a 1, 4 ou 128 passos. |
| MeanFlow6 | Aprender a velocidade média num intervalo em vez da instantânea — geração de um passo sem estágio separado de destilação. |
Onde é usado
Flow matching não é mais uma alternativa de nicho; é sobre ele que a geração atual de modelos está construída.
| Modelo | Para que usa |
|---|---|
| Stable Diffusion 37 | Fluxo retificado + MMDiT, com deslocamento de timestep dependente da resolução |
| FLUX.1 | Fluxo retificado + um DiT de 12B, dois encoders CLIP e T5-XXL |
| Modelos de vídeo e áudio | O mesmo objetivo, sem mudanças, sobre um latente temporal |
| Moléculas e proteínas | Flow matching em variedades — o framework não assume dados euclidianos |
| Políticas de robôs | Blocos de ações como um fluxo; o mesmo código, um \(p_1\) diferente |
flowchart LR
A["Texto<br/>(prompt)"] --> B["Encoders de texto<br/>CLIP + T5-XXL"]
N["Ruído<br/>z₀ ~ N(0,I)"] --> C
B --> C["Diffusion Transformer<br/>fluxo retificado"]
C -->|"ODE: 20–50 passos"| D["Latente z₁"]
D --> E["Decoder VAE"]
E --> F["Imagem 1024×1024"] Amostragem
O treino te dá um campo de velocidade. Transformá-lo numa amostra é integração de ODE e o solver é escolha sua — a mesma separação do capítulo 20.
import torch
@torch.no_grad()
def sample_euler(model, shape, n_steps=25, device='cuda'):
"""Primeira ordem. Uma avaliação do modelo por passo."""
x = torch.randn(shape, device=device) # x em t = 0 é ruído puro
dt = 1.0 / n_steps
for i in range(n_steps):
t = torch.full((shape[0],), i * dt, device=device)
x = x + dt * model(x, t)
return x
@torch.no_grad()
def sample_heun(model, shape, n_steps=15, device='cuda'):
"""Segunda ordem: duas avaliações por passo, mas muito menos erro por passo.
A custo igual, bate o Euler assim que o campo tem qualquer curvatura."""
x = torch.randn(shape, device=device)
dt = 1.0 / n_steps
for i in range(n_steps):
t = torch.full((shape[0],), i * dt, device=device)
t2 = torch.full((shape[0],), (i + 1) * dt, device=device)
v1 = model(x, t)
v2 = model(x + dt * v1, t2) # preditor, depois correção
x = x + dt * (v1 + v2) / 2
return x
Lendo um código de flow matching
Três convenções diferem entre artigos e custam uma tarde se você assumir: se \(t = 0\) é ruído ou dados (este capítulo usa ruído), se o modelo prevê velocidade, \(x_1\) ou \(\epsilon\) (todos interconversíveis, dados \(t\) e o interpolante) e se \(t\) é passado como número em \([0,1]\) ou como índice inteiro de timestep. Confira as três antes de depurar qualquer outra coisa.
Pontos principais
- O flow matching aprende um campo de velocidade e amostra integrando uma ODE. A perda é um único erro quadrático, sem cronograma e sem limite variacional.
- A velocidade marginal é intratável, mas regredir a condicional tem o mesmo gradiente. Esse teorema é o método inteiro.
- Difusão é flow matching com um interpolante curvo. \(a(t) = \sqrt{\bar\alpha_t}\) em vez de \(a(t) = t\). Um framework cobre os dois.
- "Caminhos retos" vale para o caminho condicional. O caminho marginal — o que o modelo aprende — não é reto e pode ser mais curvo que o da difusão.
- A vantagem real é o objetivo: mais simples, sem ponderação, sem cronograma para errar. É por isso que SD3 e FLUX o adotaram.
- O reflow entrega retidão de verdade, reacoplando cada amostra de ruído com a saída que ela já produz. É o que torna a geração de um passo possível.
- Modelos de consistência, de atalho e o MeanFlow atacam o mesmo alvo: colapsar a trajetória em menos avaliações.
- Passados ~32 passos o interpolante deixa de importar. Todo argumento aqui é sobre o regime de poucos passos.
-
Lipman, Y., Chen, R. T. Q., Ben-Hamu, H., Nickel, M., & Le, M. (2023). Flow Matching for Generative Modeling — ICLR. O teorema do flow matching condicional é a seção 3 e é curta. ↩↩
-
Liu, X., Gong, C., & Liu, Q. (2023). Flow Straight and Fast: Learning to Generate and Transfer Data with Rectified Flow — ICLR. Fluxo retificado e o procedimento de reflow. ↩↩
-
Song, Y., Dhariwal, P., Chen, M., & Sutskever, I. (2023). Consistency Models — ICML. ↩
-
Frans, K., Hafner, D., Levine, S., & Abbeel, P. (2025). One Step Diffusion via Shortcut Models — ICLR. Condicione no tamanho do passo e um modelo serve a qualquer orçamento de passos. ↩
-
Geng, Z., Deng, M., Bai, X., Kolter, J. Z., & He, K. (2025). Mean Flows for One-step Generative Modeling. Velocidade média em vez de instantânea e geração de um passo sem estágio de destilação. ↩
-
Esser, P., et al. (2024). Scaling Rectified Flow Transformers for High-Resolution Image Synthesis — ICML. SD3; a ablação de interpolantes e ponderações de timestep na seção 3 é a comparação publicada mais útil. ↩
-
Albergo, M. S., Boffi, N. M., & Vanden-Eijnden, E. (2023). Stochastic Interpolants: A Unifying Framework for Flows and Diffusions. A formulação geral \(a(t), b(t)\) usada na tabela acima. ↩