Escolher uma pergunta antes de abrir uma trace
Uma trace responde melhor a uma pergunta precisa: o cálculo espera pelos dados, uma cópia é repetida, ou um pequeno operador é chamado vezes demais? Defina a entrada, a saída e as fronteiras da sua etapa. Para treinamento, especifique se ela contém backward, atualização do otimizador e leitura do batch. Para inferência, separe carregamento do modelo e requisição.
Mantenha um cenário curto cuja correção você conhece. Anote formas, batch, precisão, modo do modelo, compilação eventual e fonte dos dados. Uma entrada simplificada pode ajudar a isolar um comportamento, mas já não representa necessariamente a carga completa. Mencione essa diferença no registro.
Fixe a unidade final: milissegundos por etapa ou exemplos processados por segundo. As somas de eventos não substituem o tempo decorrido. Compare janelas com as mesmas fronteiras de leitura e transferência.
Distinguir tempo de CPU, trabalho de GPU e espera
A CPU prepara e lança operações; a GPU pode executá-las mais tarde. Um intervalo do Python pode, portanto, conter lançamento, espera ou ambos. A documentação CUDA do PyTorch indica que as medições precisas devem levar em conta esse assincronismo, em particular por sincronização ou eventos adequados ao escopo.
Para uma medição de duração de GPU direcionada, os eventos CUDA podem servir. Para uma latência ponta a ponta, aguarde o fim do trabalho compreendido nessa latência e meça o conjunto da requisição. Não misture essas duas unidades. Uma sincronização adicionada entre cada operação pode suprimir uma sobreposição real e transformar o programa que você busca entender.
No profiler, os tempos próprios de um operador e seus tempos incluindo suboperações também respondem a perguntas diferentes. Olhe a linha do tempo antes de somar as linhas da tabela. Atividades simultâneas ou aninhadas não representam porções de tempo decorrido disjuntas.
Reservar uma fase de inicialização e uma janela ativa
A primeira passagem pode incluir inicialização, carregamento ou compilação. Decida se sua pergunta diz respeito a essa inicialização ou a uma fase já estabilizada. Mantenha as duas observações quando elas importam para o uso, em vez de apagar o custo inicial de uma média apresentada como global.
A função schedule permite distinguir espera, preparação da coleta e janela ativa. O aquecimento do profiler não é prova de que seu modelo atingiu seu regime estável. Verifique também as formas encontradas e o estado dos caches. Uma aplicação com entradas variáveis pode encontrar novos caminhos após várias iterações.
O planejamento didático proposto abaixo aguarda uma etapa, prepara uma e captura duas. Quatro etapas bastam para explicar o mecanismo, não para estabelecer uma distribuição de desempenho. Em uma campanha real, escolha uma janela justificada e repita a medição fora do profiler após a análise.
Exemplo proposto: quatro etapas com fronteiras legíveis
O trecho a seguir não foi executado. Ele pressupõe que model, optimizer, loss_fn, loader e device existem, que o modelo está em device e que o loader fornece pelo menos quatro batches de pares x, y. Ele realiza atualizações: use um estado experimental destinado a isso, não uma sessão cujos pesos você precisa preservar.
Os rótulos separam leitura da CPU, transferência e treinamento. O iterador é criado antes da janela, o que exclui parte da sua inicialização do escopo. O arquivo é escolhido novo para evitar sobrescrever um trace. O exemplo recusa uma coleta de GPU indisponível em vez de apresentar discretamente um trace de CPU como uma análise de GPU.
O sinal step() avança o planejamento após cada etapa. A receita oficial descreve essa ligação entre iterações e coleta. Em uma pilha ROCm, o dispositivo do PyTorch continua sendo chamado cuda; a disponibilidade da coleta do acelerador depende, no entanto, do build e das suas ferramentas. Verifique as atividades realmente presentes no resultado.
from pathlib import Path
import torch
from torch.profiler import (
profile, schedule, record_function,
ProfilerActivity, supported_activities,
)
trace = Path("trace-etape.json")
if trace.exists():
raise FileExistsError("Choisissez un nouveau nom de trace")
activities = [ProfilerActivity.CPU]
if device.type == "cuda":
if ProfilerActivity.CUDA not in supported_activities():
raise RuntimeError("Collecte GPU indisponible dans ce build")
activities.append(ProfilerActivity.CUDA)
iterator = iter(loader)
model.train()
with profile(
activities=activities,
schedule=schedule(wait=1, warmup=1, active=2, repeat=1),
record_shapes=False, profile_memory=False, with_stack=False,
on_trace_ready=lambda p: p.export_chrome_trace(str(trace)),
) as prof:
for _ in range(4):
with record_function("lecture_batch_cpu"):
x, y = next(iterator)
with record_function("transfert"):
x, y = x.to(device), y.to(device)
with record_function("entrainement"):
optimizer.zero_grad(set_to_none=True)
loss = loss_fn(model(x), y)
loss.backward()
optimizer.step()
prof.step()
print(prof.key_averages().table(
sort_by="self_cpu_time_total", row_limit=8,
))Transformar uma observação em hipótese verificável
Comece pela janela ativa e verifique se os rótulos esperados aparecem. Examine em seguida os espaços entre atividades, as cópias e as repetições. Uma longa espera em lecture_batch_cpu aponta para o pipeline de entrada; ela não mede diretamente o armazenamento. Uma cópia frequente convida a examinar o posicionamento dos tensores, sem provar que ela é inútil.
Formule uma única hipótese e proponha uma modificação controlada. Por exemplo, se uma constante é reconstruída e transferida a cada etapa, verifique se o tempo de vida dela pode abranger várias etapas sem alterar o resultado. Se um operador parece dominante, inspecione suas formas e o número de chamadas antes de procurar um substituto.
As linhas abaixo são leituras possíveis, não constatações tiradas de um trace executado. Nenhuma duração nem aceleração é anunciada. A conclusão útil é um próximo experimento que possa confirmar ou refutar a causa proposta.
Role a tabela para ler todas as colunas.| Observação possível | Hipótese | Verificação seguinte |
|---|---|---|
| GPU sem atividade durante a leitura | O pipeline de entrada não acompanha | Mesmo cálculo com batch já preparado |
| Cópias recorrentes de uma constante | Posicionamento ou tempo de vida inadequados | Mover uma vez, verificar as saídas |
| Muitos pequenos lançamentos | Trabalho fragmentado | Examinar agrupamento e custo global |
| Um operador longo | Forma ou algoritmo determinante | Comparar o mesmo operador e suas entradas |
Limitar o custo e as informações da instrumentação
Comece com uma coleta curta e poucas opções. Ative as formas, as pilhas ou a memória somente se uma pergunta exigir. A API do PyTorch especifica que essas informações adicionam um custo; a coleta das formas pode até reter referências aos tensores. Um perfil detalhado pode, portanto, alterar as durações ou a ocupação de memória do programa.
Um trace pode conter nomes de operadores, formas e, dependendo das opções, caminhos de código. Inspecione-o antes de compartilhá-lo. Um rótulo de zona deve descrever a etapa sem incluir email, token, caminho privado ou conteúdo de entrada. Escolha um leitor de trace adequado ao seu ambiente e mantenha a coleta sob seu controle.
Se os eventos de GPU esperados estiverem ausentes, não preencha seus tempos com zero. Indique que não foram observados e examine o suporte da coleta. A ausência de um evento na ferramenta não é prova da ausência de computação.
Validar a otimização fora do profiler
Parta do mesmo estado relevante e compare a correção antes e depois da modificação. Para o treinamento, uma etapa adicional altera os pesos; duas capturas executadas em sequência não constituem necessariamente uma comparação equivalente. Mantenha código, parâmetros e ponto de partida para poder explicar a diferença.
Em seguida, meça o cenário sem coleta detalhada, com o mesmo aquecimento e várias passagens. Relate o escopo, os valores brutos e sua dispersão. Uma melhoria local pode desaparecer no loop inteiro ou degradar a qualidade: ambas devem permanecer na decisão.
Por fim, use as observações para especificar os recursos realmente necessários. Um trace da sua máquina não classifica as ofertas da Kernodeck e não prova nem o processador host nem a rede de um servidor alugado. A comparação de GPU exige uma carga, condições e resultados comparáveis nos recursos em questão.