O mesmo código, dois modos radicalmente diferentes
Se você implementou um modelo transformer em PyTorch, pode usar o mesmo código tanto para treinamento quanto para inferência — mas de maneiras completamente distintas. Entender essa diferença é essencial para quem está saindo dos tutoriais e colocando modelos em produção.
Durante o treinamento, você processa batches de sequências com comprimento fixo, calcula a loss e atualiza os pesos do modelo via backpropagation. O modelo vê tokens de entrada e saída simultaneamente, usando uma máscara causal para evitar que o token na posição i “veja” tokens futuros.
Durante a inferência, os pesos estão congelados. O modelo gera um token por vez, de forma autoregressiva, e usa KV caching para evitar recomputar estados intermediários a cada passo.
Treinamento: processamento em paralelo
No treinamento, o transformer processa toda a sequência de entrada de uma vez. O loop é simples:
# Treinamento
model.train()
for batch in dataloader:
optimizer.zero_grad()
input_ids = batch['input_ids'] # (batch, seq_len)
target_ids = batch['target_ids'] # (batch, seq_len)
logits = model(input_ids) # (batch, seq_len, vocab_size)
loss = criterion(
logits.view(-1, vocab_size),
target_ids.view(-1)
)
loss.backward()
optimizer.step()Cada batch processa centenas de tokens em paralelo. A máscara causal garante que o token na posição t só atenda às posições 0..t, preservando a propriedade autoregressiva mesmo com processamento paralelo.
Inferência: geração token a token
Na inferência, o paradigma muda completamente. Você não tem os tokens alvo — precisa gerá-los um a um:
# Inferência com KV cache
model.eval()
generated = [start_token]
past_key_values = None
for _ in range(max_new_tokens):
current_input = generated[-1:] # apenas o último token
with torch.no_grad():
logits, past_key_values = model(
current_input,
past_key_values=past_key_values,
use_cache=True
)
next_token = sample_token(logits[0, -1])
generated.append(next_token)
if next_token == eos_token:
breakO KV cache é a chave da eficiência: em vez de recomputar os estados de atenção para toda a sequência a cada novo token, o modelo reaproveita os valores de chave/valor já calculados dos tokens anteriores. Isso transforma a complexidade de O(n²) para O(n) por passo de geração.
Principais diferenças
| Aspecto | Treinamento | Inferência |
|---|---|---|
| Processamento | Paralelo (batch × seq_len) | Sequencial (token a token) |
| Pesos | Atualizados via backprop | Congelados |
| KV Cache | Não usado | Essencial para eficiência |
| Gradientes | Computados | Desabilitados (no_grad) |
| Modo do modelo | model.train() | model.eval() |
| Dropout / BatchNorm | Ativos | Desabilitados |
Decodificação: escolhendo o próximo token
Transformar logits em tokens não é trivial. As principais estratégias:
- Greedy: sempre escolhe o token de maior probabilidade. Determinístico, mas pode gerar texto repetitivo.
- Temperatura: divide os logits por um fator T antes do softmax. T > 1 aumenta a diversidade; T < 1 torna o modelo mais conservador.
- Top-k: restringe a escolha aos k tokens mais prováveis.
- Top-p (nucleus): escolhe entre os tokens cuja probabilidade acumulada atinge p.
A combinação típica em produção é temperatura + top-p, com valores como T=0.7 e p=0.9 para um balanço entre coerência e criatividade.
Do treinamento à produção
O ciclo completo de um transformer envolve três fases distintas:
- Pré-treinamento: o modelo aprende padrões gerais de linguagem em datasets massivos. É caro e feito uma única vez.
- Fine-tuning: adaptação a uma tarefa específica com dados rotulados. Muito mais rápido que o pré-treinamento.
- Inferência em produção: o modelo gera respostas. Aqui, eficiência é tudo — KV cache, quantização (INT8, INT4), e batch dinâmico fazem a diferença entre servir 10 ou 10.000 requisições.
Entender que treinar e servir são problemas de engenharia diferentes é o primeiro passo para colocar transformers em produção com eficiência.
Descubra mais sobre noticiAI
Assine para receber nossas notícias mais recentes por e-mail.



