Redes Neurais Artificiais e Deep Learning · Insper

Diffusion Transformers

Um ViT onde estava a U-Net — e o que isso comprou

Uma peça do pipeline muda

Stable Diffusion = VAE + encoder de texto + U-Net + amostrador + guidance. Você tem 20× mais compute. Qual peça você troca?

  • O removedor de ruído. Todo o resto fica: VAE, encoder de texto, amostrador, classifier-free guidance.
  • Peebles e Xie (2023): cortar o latente ruidoso em patches, rodar um ViT comum, transformar os tokens de volta num latente.
  • Superou as melhores U-Nets da época no ImageNet — e mostrou algo mais útil: a qualidade acompanha o compute, de forma previsível.
  • Desde 2024: SD3, FLUX, Qwen-Image, HunyuanVideo, Wan, LTX-2 — os principais modelos abertos de imagem e vídeo descendem dele.

Simulador · U-Net, DiT, MMDiT

Patchify e o caminho de volta

C × H × W = canais × altura × largura do latente (o VAE reduz cada lado por 8: 256/8 = 32) · p = lado do patch · d = largura do modelo · E = a projeção aprendida

modelo latente tokens token
DiT-XL/2, 256² 2
FLUX.1-dev, 1024² 2
o nosso lab, 28² pixels 4
  • Entrada: uma Conv2d com kernel = passo = — o patch embedding do ViT.
  • Saída: uma camada linear para números por token e depois o unpatchify — um reshape e um permute, sem parâmetros.

Exercício · siga o tensor pelo DiT do lab

Entrada (B, 1, 28, 28) = (imagens, canais, altura, largura): um lote de imagens cinza do Fashion-MNIST. Ignore o e preencha antes de virar o slide.

passo saída
Conv2d(1, 96, 4, stride=4) ?
flatten(2).transpose(1, 2) ?
+ posições, 4 blocos adaLN-Zero ?
Linear(96, 16) ?
unpatchify ?

Conv2d(canais que entram, nº de filtros, lado do kernel, passo)

Com kernel = passo = , a grade de saída é .

flatten(2) junta altura e largura num eixo só; transpose(1, 2) põe esse eixo antes dos canais.

Responda em canais × altura × largura ou em tokens × largura.

Siga o tensor · resposta

1×28×28patchifyconv 4×4, s = 496×7×7flatten7 · 7 = 4949×964 blocosadaLN-Zero49×96saídaLinear(96, 16)49×16unpatchifyreshape1×28×28

passo saída de onde vem
Conv2d(1, 96, 4, stride=4) 96 × 7 × 7 96 filtros = · 28/4 = 7 por lado
flatten(2).transpose(1, 2) 49 × 96 7 · 7 = 49 tokens, cada um com números
+ posições, 4 blocos adaLN-Zero 49 × 96 cada bloco soma ao resíduo: mantém o formato
Linear(96, 16) 49 × 16 números por token = um patch 4 × 4
unpatchify 1 × 28 × 28 os 49 patches de volta na grade 7 × 7: 7 · 4 = 28 por lado

Simulador · tokens e custo

Mesmos parâmetros, mais tokens

DiT-XL (675M de parâmetros), ImageNet 256² (latente 32 × 32), 400K passos de treino:

patch tokens Gflops FID-50K ↓
8 16 7,4 106,4
4 64 29,1 43,0
2 256 118,6 19,5

Gflops = bilhões de operações numa passada pela rede · FID-50K = distância de Fréchet, nas features da Inception, entre 50 mil amostras e as imagens reais (menor é melhor) · DiT-XL/2 = tamanho XL, patch 2

  • Só e a camada de saída dependem de : o número de parâmetros não se mexe. Metade de , 4× os tokens, ~4× os Gflops.
  • Os parâmetros sozinhos preveem mal: o DiT-S/2 (33M) e o DiT-B/4 (130M) custam ~6 Gflops cada — FID 68,40 e 68,38.

A qualidade acompanha o compute por passada — venha ele da largura, da profundidade ou dos tokens.

Doze modelos, uma curva

Os 12 modelos do artigo do DiT, tamanhos S, B, L e XL com patches 8, 4 e 2: FID-50K depois de 400K passos de treino, em escala log, contra os Gflops de uma passada ou contra o número de parâmetros. Contra os Gflops, os pontos caem numa faixa só; contra os parâmetros, cada tamanho é uma linha vertical. FID-50K, menor é melhor (escala log) TAMANHO DO MODELO S · 12 blocos, d = 384 B · 12 blocos, d = 768 L · 24 blocos, d = 1024 XL · 28 blocos, d = 1152 TAMANHO DO PATCH p (LATENTE 32 × 32) p = 8 · 16 tokens p = 4 · 64 tokens p = 2 · 256 tokens PONTO

O bloco lê a condição pelas suas normalizações

t = nível de ruído (timestep) · y = classe · c, β, γ, α: vetores de tamanho d — β desloca, γ escala, α é o portão · W leva d a 6d · emb = senos e cossenos para t, uma tabela aprendida para y · SiLU(z) = z·σ(z) · LN = LayerNorm sem parâmetros · ⊙ = produto elemento a elemento

  • A LayerNorm perde a escala e o deslocamento aprendidos; uma camada linear os prevê a partir de (adaLN).
  • O adaLN-Zero acrescenta um portão por ramo residual — e inicializa , .

Para onde vai c, num bloco

adaLN-Zero. À esquerda, calculado uma vez por imagem: o timestep t e a classe y viram um vetor c; uma camada linear W de cada bloco transforma SiLU de c em seis vetores. À direita, um bloco aplicado a todo token: LayerNorm, escala por um mais gama 1 e deslocamento por beta 1, atenção, portão alfa 1, soma residual; depois o mesmo em volta do MLP com gama 2, beta 2 e alfa 2. Com W igual a zero, os portões valem zero e o bloco é a identidade. CONDIÇÃO · UMA VEZ POR IMAGEM UM BLOCO · EM TODO TOKEN x h Timestep tsenos e cossenos → MLP Classe ylinha de tabela aprendida c: d númerosMLP(emb(t)) + emb(y) W SiLU(c) + bW: d → 6dum W próprio por bloco seis vetores de d γ₁, β₁ α₁ γ₂, β₂ α₂ Tokens x: N × d LN (sem γ, β) (1 + γ₁) ⊙ · + β₁ Atenção ⊙ α₁ LN (sem γ, β) (1 + γ₂) ⊙ · + β₂ MLP ⊙ α₂ x′: N × d, próximo bloco

Por que zero?

Na inicialização, quanto vale ? Não "pequeno" — que número?

  • Exatamente 0: e dão , então — e o mesmo no MLP. Todo bloco começa como identidade.
  • A camada de saída também começa em zero: a rede começa prevendo zero e cada bloco aprende a acrescentar alguma coisa.
  • O mesmo truque das conexões residuais, das convoluções zeradas do ControlNet e do do LoRA.
  • O lab mede (seção 2): 0.0 na inicialização, 0,224 assim que se mexe.

Simulador · o bloco, linha a linha

x · latente 1×4×4 (uma cor por patch)
c · t e a classe (d = 4)

Simulador · quatro jeitos de dar a condição ao bloco

Medido no lab: o condicionamento

Fashion-MNIST, , , 4 blocos, 1500 passos, guidance :

desenho parâmetros loss de validação acurácia de classe FD ↓
tokens no contexto 470 224 0,2891 0,850 26,62
adaLN 636 304 0,2733 0,893 19,97
adaLN-Zero 710 800 0,2618 0,900 17,11

acurácia de classe = fração das 1000 amostras que um classificador pequeno põe na classe pedida · FD = distância de Fréchet nas features desse classificador (piso de 1,55 para imagens reais) · w = escala do classifier-free guidance

  • A ordem do artigo sobrevive em 28 × 28: FD 26,62 → 19,97 → 17,11.
  • Os parâmetros a mais são a modulação: os portões do adaLN-Zero são ; o modelo no contexto não tem modulação nenhuma. Mas o que pesa é como chega aos tokens: um token de classe disputa a atenção com 49 tokens de imagem.

A modulação é barata em compute, não em parâmetros

  • leva : por bloco, contra da atenção (: Q, K, V e a saída) + MLP (: ).
  • DiT-XL, 28 blocos de : 223M dos seus 675M parâmetros — um terço do modelo para ler um vetor.
quem o que fez
PixArt-α (2023) calcula uma vez a partir de , um deslocamento aprendido por bloco — 833M → 611M
Wan (2025) um MLP de modulação compartilhado por todos os blocos
FLUX.2 (2025) um conjunto por tipo de bloco, reaproveitado em todo bloco

E o vetor de texto agregado saiu de : o timestep passa pela modulação; o prompt, pela atenção.

Como o prompt entra: três desenhos

desenho como texto atualizado? conjuntos de pesos usado em
cross-attention as consultas da imagem leem o texto numa segunda atenção não 1 U-Net do SD, PixArt-α, Wan, Movie Gen
conjunta, dois fluxos (MMDiT) uma atenção sobre [imagem; texto], pesos separados por modalidade sim 2 SD3, Qwen-Image
conjunta, um fluxo um bloco Transformer comum sobre [imagem; texto] sim 1 Z-Image

img, txt = tokens da imagem e do texto · [ · ; · ] = concatenar na sequência · dh = canais por cabeça

Dentro de um bloco MMDiT

Um bloco MMDiT. Os tokens de imagem à esquerda e os de texto à direita passam cada um pela sua própria modulação, pelas suas próprias projeções Q, K, V, pela sua própria projeção de saída e pelo seu próprio MLP; as duas sequências só se encontram numa atenção sobre a sequência concatenada. A condição c, timestep mais texto agregado, alimenta as duas modulações. Num bloco de um fluxo só, os mesmos passos usam um único conjunto de pesos para todos os tokens. PESOS DA IMAGEMPESOS DO TEXTO UM CONJUNTO DE PESOS PARA TODOS OS TOKENS Tokens de imagem: N × dpatches do latente ruidoso Tokens de texto, largura dvindos do encoder de texto c: timestep + texto agregadoum vetor por imagem adaLN: LN, (1 + γ) ⊙ · + β adaLN: LN, (1 + γ) ⊙ · + β Q, K, V Q, K, V Uma atençãoconcatenar, atenção, separarsobre todos os tokens juntos proj. de saída, ⊙ α, + resíduo proj. de saída, ⊙ α, + resíduo adaLN, MLP, ⊙ α, + resíduo adaLN, MLP, ⊙ α, + resíduo um adaLN para todos os tokens: LN, (1 + γ) ⊙ · + β um Q, K, V para todos os tokens uma projeção de saída, ⊙ α, + resíduo um MLP para todos os tokens (o FLUX o roda ao lado da atenção) Tokens de imagem, atualizadosapós o último bloco: unpatchify Tokens de texto, reescritosapós o último bloco: descartados

Simulador · quem faz atenção a quem

Dois fluxos, depois um

modelo dois fluxos um fluxo
FLUX.1 19 38
HunyuanVideo 20 40
FLUX.2 8 48
Z-Image 0 30

Alinhar as modalidades com pesos separados e depois compartilhá-los.

De onde veio o texto legível. A ablação do SD3: tire o encoder T5 (um modelo de linguagem; o SD3 tem também dois CLIPs) e a aderência ao prompt quase não se mexe (46% de vitórias contra o modelo completo; 50% seria empate), mas a tipografia cai (38%).

  • Foi o encoder que é modelo de linguagem, antes de tudo.
  • Desde então: um LLM multimodal (HunyuanVideo), Qwen2.5-VL (Qwen-Image), Mistral de 24B (FLUX.2).

Posições: RoPE, um eixo por vez

  • DiT: uma tabela fixa de senos e cossenos 2-D somada aos tokens — presa à grade de treino.
  • Desde o FLUX.1: embeddings rotativos por eixo — os canais da cabeça divididos em grupos, cada um girado por uma coordenada.
modelo eixos canais da cabeça por eixo
FLUX.1 índice, linha, coluna 16 + 56 + 56 = 128
HunyuanVideo tempo, linha, coluna 16 + 56 + 56 = 128
CogVideoX tempo, linha, coluna 2/8, 3/8, 3/8 dos canais
FLUX.2 quatro eixos 32 · 4 = 128

(a consulta de um token vezes a chave de outro) depende só de diferenças de posição: resolução, proporção e duração viram uma questão de comprimento de sequência.

A curva que pagou os modelos seguintes

modelo ano parâmetros blocos texto entra por tokens em 1024²
DiT-XL/2 2023 675M 28 1152 classe, adaLN 256 em 256²
SD3 medium 2024 2B 24 1536 dois fluxos 4096
FLUX.1-dev 2024 12B 19 + 38 3072 dois, depois um 4096
Qwen-Image 2025 20B 60 3072 dois fluxos 4096
Z-Image 2025 6B 30 3840 um fluxo 4096
FLUX.2-dev 2025 32B 8 + 48 6144 dois, depois um 4096
  • Os modelos ficaram mais largos e mais profundos; a sequência ficou em 4096: VAE de 8× e dão .
  • O SD3 repetiu o estudo até 8B: a loss de validação cai de forma suave e acompanha o GenEval e a preferência humana.

19 + 38 = blocos de dois fluxos + blocos de um fluxo · d = largura do modelo · GenEval = um benchmark automático de aderência ao prompt

Vídeo: o mesmo bloco sobre patches de espaço-tempo

VAE 3-D (4× no tempo, 8 × 8 no espaço, 16 canais), patches (tempo × altura × largura):

modelo clipe (largura × altura) tokens
CogVideoX-5B 720 × 480, 49 quadros 13 · 30 · 45 17 550
Mochi 1 848 × 480, 163 quadros 28 · 30 · 53 44 520
Movie Gen 768 × 768, 256 quadros 32 · 48 · 48 73 728
Wan 2.1 14B 1280 × 720, 81 quadros 21 · 45 · 80 75 600
HunyuanVideo 1280 × 720, 129 quadros 33 · 45 · 80 118 800
  • No espaço, 8 do VAE × 2 do patch = 16 pixels por lado de token: .
  • No tempo, : no HunyuanVideo, . O Mochi comprime por 6 (); o Movie Gen, por 8 ().

Atenção 3-D completa

Os primeiros modelos de vídeo faziam atenção dentro de cada quadro e depois ao longo de cada pixel no tempo. Mais barato. Por que o CogVideoX, o HunyuanVideo e o Wan abandonaram isso?

  • Uma cabeça que se move não está no mesmo pixel no quadro seguinte.
  • Com atenção fatorada, os seus tokens no quadro não fazem atenção direto aos seus tokens no quadro — só passando por outros patches.
  • A consistência sofre (o argumento do CogVideoX). Então: uma atenção sobre todos os tokens.
  • Também novo: o LTX-2 gera vídeo e áudio juntos (fluxos de 14B e 5B); o Wan 2.2 divide os passos entre um especialista de muito ruído e um de pouco ruído (27B, 14B ativos).

Para onde vai o compute

çõçãçã

multiplicações-adições por bloco, com N tokens de largura d · 12Nd² = 4Nd² (Q, K, V e a saída, matrizes d × d) + 8Nd² (MLP d → 4d → d) · 2N²d = QKᵀ (N × N escores de d termos) + a soma ponderada dos V

FLUX em 1024²: (imagem + texto), . Ele é limitado pela atenção?

  • Não: . Projeções e MLPs fazem 80% do trabalho.
  • O termo só vence quando passa de : 18 432 tokens no FLUX. Uma imagem fica abaixo; um vídeo, não.

Imagem × vídeo: a parte da atenção

modelo atenção
DiT-XL/2, 256² 256 1152 256 / 7 168 4%
FLUX.1, 1024² 4608 3072 4608 / 23 040 20%
Wan 2.1, 720p 75 600 5120 75 600 / 106 320 ≈ 71%
HunyuanVideo, 720p 118 800 3072 118 800 / 137 232 ≈ 87%
  • Os de vídeo são os do slide do VAE 3-D; os de imagem, os do patchify.
  • Medido: um clipe de 5 segundos em 720p do HunyuanVideo levou 945 s, 800 na atenção — 85%, perto dos 87% da fórmula.

Então os truques de eficiência se dividem

alavanca exemplos importa para
menos passos LADD / SD3-Turbo (4 passos), FLUX.1 schnell (1–4), destilação de guidance imagens e vídeo
menos tokens o autoencoder de 32× do SANA, fusão de tokens os dois
atenção mais barata SANA (linear), sliding-tile: 945 → 685 s sem treino vídeo
reaproveitar entre passos TeaCache, até 4,4× vídeo
menos parâmetros ativos Wan 2.2: dois especialistas por nível de ruído modelos grandes

DiTs de imagem são limitados pelo MLP; DiTs de vídeo, pela atenção. Por isso atenção esparsa é uma história de vídeo.

Medido no lab: o tamanho do patch

Mesmo , 4 blocos, 1500 passos, — só muda:

parâmetros tokens M mult.-adições acurácia de classe FD ↓
14 745 540 4 1,8 0,319 341,97
7 717 169 16 7,3 0,908 27,58
4 710 800 49 23,5 0,900 17,11
  • Só e a saída dependem de : — 37 924 com , 3 184 com . O resto é igual.
  • Compute : com , M — 13× o de e o FD cai junto.
  • Com cada token tem números espremidos em e a atenção só move informação entre tokens.
  • ( tokens): 116M, 4,94× o — é a tarefa aberta.

Onde é usado, outubro de 2026

domínio sistemas
texto para imagem (abertos) SD3/3.5, FLUX.1, Qwen-Image, Z-Image, FLUX.2, Qwen-Image-2.1 MMDiT, dois fluxos e depois um ou um fluxo só, rectified flow, encoders LLM/VLM
texto para vídeo (abertos) CogVideoX, HunyuanVideo (1.5), Wan 2.1/2.2, LTX-2 VAE 3-D, RoPE 3-D, atenção 3-D completa ou esparsa
áudio LTX-2 um fluxo de áudio do mesmo DiT
objetos 3-D TRELLIS Transformers de rectified flow sobre um latente 3-D
robótica GR00T N1 um módulo de ação DiT, flow matching
fechados Sora, Sora 2, Veo 3, Midjourney Sora: um DiT sobre patches de espaço-tempo; os outros não publicam

rectified flow = flow matching com caminhos retos, a loss do lab · MMDiT = DiT multimodal, dois fluxos

O que substituiu a U-Net, onde

  • Texto para imagem: entre o SDXL (2023, U-Net) e o SD3 (2024, MMDiT).
  • Vídeo: em 2024 — o Stable Video Diffusion (2023) não teve sucessor em U-Net.
  • Continua convolucional: o VAE em volta de cada um desses modelos, muitas etapas de super-resolução.

A U-Net não morreu. EDM2 (uma U-Net, 2024): FID 1,81 no ImageNet 512², melhor que os 3,04 do DiT-XL/2. O argumento do DiT nunca foi "vence uma convolução com orçamento fixo" — é que ele continua rendendo à medida que o orçamento cresce e compartilha tudo com os LLMs.

Para onde o desenho está indo

desenvolvimento o que muda
REPA alinhar uma camada do DiT com um DINOv2 congelado: treino até 17,5× mais rápido
RAE fazer difusão num latente DINOv2 congelado em vez do latente de um VAE: FID 1,13 no ImageNet
um fluxo + encoder de texto grande menos pesos separados no gerador, mais linguagem no encoder
modelos unificados um Transformer lê e gera texto e imagens — próxima aula

REPA = alinhamento de representações · RAE = autoencoder de representações · DINOv2 = um ViT treinado sem rótulos (auto-supervisionado)

Laboratório · um DiT, construído e medido

Notebook no Colab, ~2 h, GPU T4 (nível gratuito), Fashion-MNIST. Cada seção termina num checkpoint.

  1. patchify e unpatchify, à mão
  2. o bloco adaLN-Zero: identidade, medida
  3. o DiT inteiro e o seu custo contra o relógio
  4. flow matching, guidance e um juiz
  1. no contexto × adaLN × adaLN-Zero
  2. : tokens, tempo, qualidade
  3. o seu DiT com orçamento: a tabela é sua

abrir no Colab →

Pontos principais

  1. Um DiT é um ViT sobre patches latentes ruidosos; o unpatchify devolve uma velocidade do formato da entrada.
  2. O tamanho do patch é um botão de compute: mesmos parâmetros, 16× os Gflops (118,6/7,4), FID 106 → 19,5.
  3. adaLN-Zero: normalizações moduladas por , portões em zero, todo bloco começa como identidade — o melhor e o mais barato; os seus parâmetros explicam por que os modelos seguintes o compartilham.
  4. Texto: cross-attention, conjunta com dois fluxos ou um fluxo só. A atenção conjunta é quase de graça; o que custa são os pesos.
  5. RoPE por eixo faz da resolução e da duração um comprimento de sequência.
  6. Imagens são limitadas pelo MLP; vídeo, pela atenção: .

Roteiro: (1) a troca e o patchify; (2) adaLN-Zero e a ablação do condicionamento; (3) como o prompt entra: cross-attention, atenção conjunta, um fluxo só; (4) posições e a curva de escala; (5) vídeo e para onde vai o compute; (6) onde é usado em 2026. Fecha com o laboratório no Colab.

U-Net: a resolução desce e sobe, blocos de atenção entre as convoluções. DiT: uma resolução, todo bloco vê todos os tokens, t e a classe entram em todo bloco. MMDiT: o texto ganha o seu próprio fluxo.

É a seção 1 do laboratório: patchify e unpatchify à mão, com a ida e volta exata.

Comece no DiT-XL com p = 2: 256 tokens, 118 G multiplicações-adições — os 118,6 Gflops do artigo. Mova p para 4 e 8. Depois o FLUX com p = 1: 16 384 tokens e a atenção com quase metade do custo.

Os 12 modelos da tabela 4 do artigo. Contra os Gflops: uma faixa só, S/2 e B/4 no mesmo lugar. Clique em "Contra os parâmetros": cada tamanho vira uma linha vertical, FID de 153,6 a 68,4 com os mesmos 33M. Pergunte antes de clicar: o que os pontos S vão fazer?

Sete passos: t e y viram c; um W por bloco faz seis vetores, compartilhados por todos os tokens; a metade da atenção; a metade do MLP; W = 0 (os vetores viram 0 e só o caminho residual fica aceso — o próximo slide pede o número); o custo: 0,2% do compute, um terço dos parâmetros.

Caso inicial "um bloco treinado": avance linha a linha. A linha 3 são os seis vetores, só de c e iguais para os 4 tokens; a linha 4 é a LN (média 0, variância 1); a linha 5 é onde t entra. Depois escolha "na inicialização: W = 0": os seis vetores são 0, a atenção ainda calcula (linha 6) mas α1 = 0 não deixa nada passar; max |bloco(z) − z| = 0 e out = 0 — a resposta do slide anterior. "o mesmo bloco, outro t": mesmo x, outro c, outra saída. "um patch plano": a LN zera o token 1.

A ablação do artigo no DiT-XL/2. Peça a ordem antes de clicar. O adaLN-Zero é o melhor e, junto com o adaLN, o mais barato: a modulação é por imagem, não por token.

Avance passo a passo: entram duas sequências; um c, duas modulações; Q, K, V próprios; concatenar, uma atenção, separar; saída e MLP próprios — o texto sai reescrito; último passo: o bloco de um fluxo só, um conjunto de pesos, o mesmo trabalho por token.

Cross-attention: as linhas do texto nunca são calculadas. Conjunta: os quatro blocos num único softmax. Troque para o FLUX e para o Wan: a atenção conjunta custa 12,5% e 0,7% a mais de escores. A diferença entre dois fluxos e um está nos pesos, não no compute.