23. Autoregressive Generation
Geração Autorregressiva de Imagens
Modelos de difusão dominam a geração de imagens desde 2020 — mas existe uma abordagem radicalmente diferente que ganhou força: tratar imagens como sequências de tokens discretos e gerá-las da mesma forma que modelos de linguagem geram texto.
Essa é a abordagem por trás da geração de imagens nativa do Gemini, do GPT-4o e de modelos como Chameleon (Meta) e LlamaGen.
O Problema: Como Tokenizar uma Imagem?
Texto é naturalmente discreto (palavras, subpalavras). Imagens são contínuas — pixels em \([0,255]^3\). Para usar geração autorregressiva, precisamos de um vocabulário visual.
A solução: VQ-GAN (Vector Quantization GAN)1 aprende um codebook de \(K\) vetores. O encoder mapeia qualquer patch de imagem para o vetor mais próximo do codebook — convertendo a imagem em uma grade de índices inteiros.
Geração Autorregressiva de Tokens
Com um codebook treinado, podemos representar qualquer imagem como uma sequência de \(N\) índices inteiros. Geramos então essa sequência exatamente como um LLM gera texto:
Cada token é gerado um de cada vez, condicionado em todos os anteriores e no prompt de texto.
MaskGIT: Geração Paralela por Mascaramento
A geração puramente autorregressiva é lenta: 1024 tokens = 1024 passes de modelo. O MaskGIT2 acelera isso com geração paralela iterativa:
- Começa com todos os tokens mascarados
[MASK] - A cada iteração, prediz todos os tokens simultaneamente (bidirecional!)
- "Revela" apenas os tokens com maior confiança
- Repete com menos tokens mascarados
Em apenas 8–12 iterações, gera 1024 tokens — contra 1024 iterações do AR puro.
Any-to-Any: Gemini, GPT-4o e Chameleon
O passo final é remover a distinção entre tokens de texto e tokens de imagem. Modelos any-to-any tratam tudo como uma sequência de tokens:
O modelo Transformer padrão processa essa sequência misturada naturalmente.
Como Cada Modelo Implementa Isso
| Modelo | Tokenizador visual | Geração | Treinamento |
|---|---|---|---|
| Chameleon (Meta) | VQ-VAE (8192 códigos) | Autorregressivo puro | Texto + imagem juntos desde o início |
| Gemini 2.0 (Google) | Tokenizador proprietário | AR + decoder de difusão | Multimodal nativo |
| GPT-4o (OpenAI) | Tokens visuais discretos | AR + decoder de difusão | Multimodal nativo |
| LlamaGen | VQGAN (16384 códigos) | AR com LLaMA | Inicializa de LLaMA pré-treinado |
AR vs. Difusão: Quando Usar Cada Um?
- Unifica texto e imagem na mesma arquitetura
- Melhor para multimodal any-to-any
- Aproveita toda a infraestrutura de LLMs
- Escala bem com mais dados
- Lento: 1 token por vez
- Melhor qualidade de imagem isolada
- Geração global coerente
- Mais controle (guidance, cfg scale)
- Mais rápido por imagem que AR
- Não unifica com texto nativamente
A tendência atual: híbridos — um backbone LLM autorregressivo para entendimento e raciocínio, com um decoder de difusão para renderizar a imagem final com alta qualidade. É exatamente o que o GPT-4o faz.
Implementação: VQ-GAN + Transformer AR
import torch
import torch.nn as nn
# 1. Quantizador vetorial
class VectorQuantizer(nn.Module):
def __init__(self, n_codes, d_code):
super().__init__()
self.codebook = nn.Embedding(n_codes, d_code)
def forward(self, z):
# z: (B, H, W, d_code) — latentes do encoder
flat = z.view(-1, z.shape[-1])
# Distâncias ao codebook
dists = torch.cdist(flat, self.codebook.weight)
indices = dists.argmin(dim=-1) # índice do código mais próximo
quantized = self.codebook(indices).view_as(z)
# Straight-through estimator para backprop
quantized_st = z + (quantized - z).detach()
return quantized_st, indices.view(z.shape[:3])
# 2. Geração autorregressiva com modelo estilo GPT
class ImageGPT(nn.Module):
def __init__(self, n_codes, seq_len, d_model, n_heads, n_layers):
super().__init__()
self.tok_emb = nn.Embedding(n_codes + 1, d_model) # +1 para token BOS
self.pos_emb = nn.Embedding(seq_len + 1, d_model)
encoder_layer = nn.TransformerEncoderLayer(d_model, n_heads, d_model*4, batch_first=True)
self.transformer = nn.TransformerEncoder(encoder_layer, n_layers)
self.head = nn.Linear(d_model, n_codes)
def forward(self, tokens):
B, T = tokens.shape
pos = torch.arange(T, device=tokens.device).unsqueeze(0)
x = self.tok_emb(tokens) + self.pos_emb(pos)
# Máscara causal
mask = torch.triu(torch.ones(T, T, device=tokens.device), diagonal=1).bool()
x = self.transformer(x, mask=mask)
return self.head(x) # logits sobre n_codes
@torch.no_grad()
def generate(self, prompt_tokens, n_new, temperature=1.0, top_k=2048):
tokens = prompt_tokens.clone()
for _ in range(n_new):
logits = self(tokens)[:, -1, :] / temperature
if top_k: logits[logits < logits.topk(top_k)[0][:,-1:]] = -float('inf')
probs = logits.softmax(-1)
next_tok = torch.multinomial(probs, 1)
tokens = torch.cat([tokens, next_tok], dim=1)
return tokens
-
Esser, P. et al. (2021). Taming Transformers for High-Resolution Image Synthesis (VQ-GAN). ↩
-
Chang, H. et al. (2022). MaskGIT: Masked Generative Image Transformer. ↩
-
Yu, L. et al. (2023). LlamaGen: Autoregressive Image Generation without Vector Quantization. ↩
-
Team, C. et al. (2024). Chameleon: Mixed-Modal Early-Fusion Foundation Models. ↩
-
Li, J. et al. (2024). MAR: Autoregressive Image Generation without Vector Quantization. ↩