Em julho de 2026, otimizar transformers deixou de ser um luxo de laboratórios com clusters de GPUs. Com PyTorch 2.6+ e torch.profiler, qualquer desenvolvedor consegue identificar gargalos nos kernels de atenção que consomem até 70% do tempo de inferência de um modelo — e reduzi-los pela metade com duas linhas de código.
O que mudou: de 2024 para 2026
Há dois anos, perfilar atenção em PyTorch exigia compilar extensões CUDA manualmente e decifrar traces do NVIDIA Nsight. Hoje, o torch.profiler nativo expõe tabelas de tempo por operação, traces de GPU em timeline e recomendações automáticas de kernel no console. O PyTorch Profiler evoluiu de uma ferramenta de nicho para o painel de controle padrão de qualquer engenheiro que trabalha com LLMs.
Este tutorial é baseado na série Profiling in PyTorch do Hugging Face Blog (Parte 3), escrita por Aritra Roy Gosthipaty, Sergio Paniego, Sayak Paul e Rémi Ouazan Reboul. A Parte 1 cobriu operações básicas e a Parte 2 focou em camadas lineares e kernels fused. Agora, o alvo é o algoritmo mais caro de qualquer transformer: atenção.
✅ O que você ganha
- Ler traces do profiler como quem lê um log de terminal
- Identificar se seu modelo está gastando tempo em matmul, softmax ou máscara causal
- Substituir atenção ingênua por SDPA com uma única mudança de API
- Entender quando inplace ops aceleram e quando atrapalham
- Executar os scripts em qualquer GPU NVIDIA (local ou via Hugging Face Spaces)
⚠️ O que você NÃO ganha
- Este não é um tutorial de transformers do zero — você precisa saber o que é Q, K, V
- Não cobre FlashAttention 3 ou kernels customizados em Triton/CUDA (é foco da Parte 4)
- Os números absolutos de tempo dependem da sua GPU — uma A100 é bem diferente de uma T4
Tabela de requisitos
| Componente | Mínimo | Recomendado | Ideal |
|---|---|---|---|
| GPU | NVIDIA T4 (16 GB) | A10G (24 GB) | A100 80 GB |
| PyTorch | 2.0+ | 2.4+ | 2.6+ |
| RAM | 16 GB | 32 GB | 64 GB |
| Conhecimento | Python + atenção | Profiler básico | CUDA kernels |
| Tempo | 30 min | 1 hora | 2 horas |
Passo a passo: 4 maneiras de perfilar atenção
Os scripts completos estão disponíveis no post original do Hugging Face. Vamos analisar cada abordagem e o que o profiler revela.
1. Atenção ingênua (naive attention)
A implementação clássica executa 5 operações: matmul Q×Kᵀ, escala, máscara causal, softmax e matmul final com V. O profiler mostra essas operações como eventos sequenciais na timeline da GPU — cada uma espera a anterior terminar.
class NaiveCausalAttention(nn.Module):
def __init__(self, head_dim):
super().__init__()
self.scale = 1.0 / math.sqrt(head_dim)
def forward(self, q, k, v, mask):
scores = torch.matmul(q, k.transpose(-2, -1)) # O(n²)
scores = scores * self.scale
scores = scores.masked_fill(mask, float("-inf"))
attn = torch.softmax(scores, dim=-1)
return torch.matmul(attn, v)O que o profiler revela: o masked_fill cria um tensor intermediário desnecessário. Cada operação aloca memória nova, gerando picos de uso de VRAM que o profiler marca como memory hotspots. Em uma A100 com batch size 32 e 4096 tokens, essa implementação gasta ~45% do tempo em matmul e ~20% em alocações de memória.
2. Operações inplace (inplace ops)
Substituir operações que criam novos tensores por variantes inplace reduz alocações. O PyTorch oferece sufixos com underscore (_) para isso:
scores = torch.matmul(q, k.transpose(-2, -1))
scores.mul_(self.scale) # inplace multiply
scores.masked_fill_(mask, float("-inf")) # inplace masked fill
attn = torch.softmax(scores, dim=-1)
return torch.matmul(attn, v)Ganho: ~15% de redução no pico de VRAM e ~8% de aceleração no tempo total. Cuidado: operações inplace quebram o grafo de autograd se você precisar de gradientes — só use durante inferência ou se tiver certeza de que a backward pass não depende dos valores intermediários originais.
3. SDPA — Scaled Dot-Product Attention
Desde o PyTorch 2.0, torch.nn.functional.scaled_dot_product_attention (SDPA) unifica Flash Attention, Memory-Efficient Attention e a implementação padrão em uma única API. O PyTorch seleciona automaticamente o kernel mais rápido disponível na sua GPU:
attn_output = F.scaled_dot_product_attention(
q, k, v,
attn_mask=mask,
dropout_p=0.0,
is_causal=True
)O que o profiler revela: em vez de 5 kernels CUDA separados, o trace mostra um único bloco aten::scaled_dot_product_attention. O tempo total cai de ~12 ms para ~4 ms por forward pass (A100, 4096 tokens). A mágica está em fundir matmul + scale + softmax + matmul em um único kernel, evitando leituras/escritas redundantes na VRAM.
Ativação: se sua GPU for compatível (Ampere ou superior, i.e. A100, A10G, RTX 3090/4090), o SDPA usa Flash Attention automaticamente. Para verificar:
print(torch.backends.cuda.sdp_kernel())
# Output esperado: SDPBackend.FLASH_ATTENTION4. Kernels otimizados manualmente
O estágio final é usar kernels CUDA hand-tuned como flash_attn_func da biblioteca flash-attn (v2.7+ em julho/2026) ou implementações via torch.compile com mode="max-autotune". O profiler mostra kernels com nomes explícitos como flash_fwd_kernel, e o ganho sobre SDPA pode chegar a 10-15% adicionais em GPUs Hopper (H100).
Tabela comparativa das abordagens
| Abordagem | Tempo (ms) | VRAM (GB) | Complexidade | Suporte a grad |
|---|---|---|---|---|
| Ingênua | 12.0 | 8.2 | Trivial | ✅ |
| Inplace | 11.0 | 7.0 | Baixa | ⚠️ limitado |
| SDPA | 4.0 | 5.1 | Mínima (1 linha) | ✅ |
| Kernel manual | 3.5 | 4.8 | Alta | ✅ |
Casos de uso reais
- Fine-tuning de LLMs com LoRA: o SDPA reduz o tempo de cada epoch em ~40% sem alterar uma linha do código de treinamento
- Inferência em batch com vLLM: substituir atenção ingênua por SDPA nos kernels de prefill dobra o throughput em GPUs Ampere
- Prototipação de arquiteturas: ao testar variantes como Grouped Query Attention, o profiler mostra instantaneamente se o novo padrão de acesso à memória é eficiente
- Debugging de OOM: o trace de memória do profiler revela exatamente qual operação de atenção estoura a VRAM, permitindo ajustar batch size ou sequence length com precisão cirúrgica
- Portabilidade entre GPUs: o mesmo script com SDPA roda em T4, A10G e H100 — o PyTorch seleciona o kernel ótimo em cada uma automaticamente
Comparação de custo
| Ambiente | Custo/hora | GPUs | SDPA? | Ideal para |
|---|---|---|---|---|
| HF Spaces (Dev Mode) | US$ 0 (gratuito) | T4 16 GB | ✅ | Prototipação |
| Hugging Face Jobs | ~US$ 3,50/h | A10G 24 GB | ✅ | Treino médio |
| Lambda Labs | ~US$ 1,10/h | A100 80 GB | ✅ | Treino pesado |
| RunPod | ~US$ 0,79/h | RTX 4090 | ✅ | Inferência |
Troubleshooting: 5 erros comuns
- ❌
profiler.step()não mostra nada: o profiler precisa de umtorch.cuda.synchronize()explícito após o forward para capturar kernels assíncronos. Adicione antes deprof.step(). - ❌ SDPA cai para kernel padrão mesmo em A100: verifique se o
dtypeéfloat16oubfloat16— Flash Attention não suportafloat32. Usemodel.to(dtype=torch.bfloat16). - ❌ Trace truncado no Chrome: o profiler gera arquivos JSON grandes (>500 MB). Use
with_stack=Trueapenas para debugging pontual. Para visualização, filtre porrow_limitna tabela. - ❌
masked_fill_quebra gradientes: se precisar de autograd, eviteinplacena máscara. A perda de gradiente é silenciosa — o treino converge para NaN sem aviso. - ❌ Kernel memory bandwidth limitado: se a tabela do profiler mostra “memory-bound”, reduza
head_dimou aumente o batch size para saturar os compute units da GPU.
FAQ
Preciso de uma GPU NVIDIA para acompanhar? Sim. O torch.profiler funciona em CPU, mas os kernels de atenção otimizados (Flash Attention, SDPA) exigem GPU NVIDIA com arquitetura Ampere ou superior. No Hugging Face Spaces você consegue uma T4 gratuita.
Qual a diferença entre SDPA e Flash Attention? SDPA é a API do PyTorch que seleciona automaticamente o melhor backend — Flash Attention é um dos backends possíveis. Se sua GPU suportar Flash Attention, o SDPA o utiliza sem você precisar instalar nada extra.
Posso usar isso em produção? Sim. O SDPA é estável desde PyTorch 2.0 e é usado em produção por Hugging Face TGI, vLLM e Ollama. O ganho de 3x sobre atenção ingênua é real e reprodutível.
O que mudou com PyTorch 2.6? O torch.compile com mode="max-autotune" agora aplica fusão de kernels automaticamente ao SDPA, eliminando a necessidade de kernels manuais para a maioria dos casos.
Vale a pena aprender kernels CUDA manuais? Se você está publicando um modelo que será baixado milhões de vezes (LLaMA, Mistral), sim — cada ms conta. Para 95% dos projetos, SDPA + torch.compile entrega 90% do ganho com zero esforço adicional.
O futuro: o que esperar em 2027
O PyTorch está caminhando para tornar o profiler uma ferramenta prescritiva, não apenas descritiva. Em vez de mostrar uma tabela e deixar você interpretar, o profiler sugerirá automaticamente: “substitua esta atenção ingênua por SDPA e ganhe 3x”. O torch.compile com mode="max-autotune" já faz isso para kernels — em breve fará para arquiteturas inteiras. Enquanto isso, dominar o profiler de atenção é a habilidade que separa engenheiros que depuram crashes de OOM às 3h da manhã daqueles que dormem tranquilos.
Descubra mais sobre noticiAI
Assine para receber nossas notícias mais recentes por e-mail.



