Elegir una pregunta antes de abrir una traza
Una traza responde mejor a una pregunta precisa: ¿el cálculo espera a los datos, se repite una copia o se llama demasiado a menudo a un operador pequeño? Define la entrada, la salida y las fronteras de tu etapa. Para el entrenamiento, precisa si incluye el backward, la actualización del optimizador y la lectura del batch. Para la inferencia, separa la carga del modelo y la consulta.
Mantén un escenario corto cuya corrección conozcas. Anota formas, batch, precisión, modo del modelo, compilación eventual y origen de los datos. Una entrada simplificada puede ayudar a aislar un comportamiento, pero ya no representa necesariamente la carga completa. Menciona esa diferencia en el informe.
Fija la unidad final: milisegundos por etapa o ejemplos procesados por segundo. Las sumas de eventos no sustituyen al tiempo transcurrido. Compara ventanas que tengan las mismas fronteras de lectura y transferencia.
Distinguir tiempo de CPU, trabajo de GPU y espera
La CPU prepara y lanza operaciones; la GPU puede ejecutarlas más tarde. Un intervalo de Python puede contener, por tanto, lanzamiento, espera o ambos. La documentación CUDA de PyTorch indica que las mediciones precisas deben tener en cuenta este asincronismo, en particular mediante sincronización o eventos adaptados al alcance.
Para una medición de duración de GPU concreta, los eventos CUDA pueden ser adecuados. Para una latencia de extremo a extremo, espera a que termine el trabajo incluido en esa latencia y mide el conjunto de la solicitud. No mezcles estas dos unidades. Una sincronización añadida entre cada operación puede eliminar un solapamiento real y transformar el programa que intentas comprender.
En el perfilador, los tiempos propios de un operador y sus tiempos que incluyen suboperaciones también responden a preguntas distintas. Mira la cronología antes de sumar las filas de la tabla. Actividades simultáneas o anidadas no representan porciones de tiempo transcurrido disjuntas.
Reservar una fase de arranque y una ventana activa
El primer paso puede incluir inicialización, carga o compilación. Decide si tu pregunta se refiere a ese arranque o a una fase ya estabilizada. Conserva ambas observaciones cuando importen para el uso, en lugar de borrar el coste inicial con una media presentada como global.
La función schedule permite distinguir espera, preparación de la recogida y ventana activa. El calentamiento del perfilador no es una prueba de que tu modelo haya alcanzado su régimen estable. Verifica también las formas encontradas y el estado de las cachés. Una aplicación con entradas variables puede encontrar nuevas rutas tras varias iteraciones.
El planning didáctico propuesto más abajo espera una etapa, prepara una y captura dos. Cuatro etapas bastan para explicar el mecanismo, no para establecer una distribución de rendimiento. En una campaña real, elige una ventana justificada y repite la medición fuera del perfilador después del análisis.
Ejemplo propuesto: cuatro etapas con fronteras legibles
El siguiente fragmento no se ha ejecutado. Supone que model, optimizer, loss_fn, loader y device existen, que el modelo está en device y que el cargador proporciona al menos cuatro batches de pares x, y. Realiza actualizaciones: usa un estado experimental previsto para ello, no una sesión cuyos pesos debas preservar.
Las etiquetas separan lectura CPU, transferencia y entrenamiento. El iterador se crea antes de la ventana, lo que excluye parte de su arranque del alcance. El archivo se elige nuevo para evitar sobrescribir una traza. El ejemplo rechaza una recolección GPU no disponible en lugar de presentar discretamente una traza CPU como un análisis GPU.
La señal step() avanza la planificación tras cada etapa. La receta oficial describe este vínculo entre iteraciones y recolección. En una pila ROCm, el dispositivo de PyTorch sigue llamándose cuda; la disponibilidad de la recolección del acelerador depende, no obstante, del build y de sus herramientas. Verifica las actividades realmente presentes en el 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,
))Convertir una observación en una hipótesis verificable
Empieza por la ventana activa y comprueba que aparecen las etiquetas esperadas. Examina después los espacios entre actividades, las copias y las repeticiones. Una larga espera en lectura_batch_cpu orienta hacia el pipeline de entrada; no mide directamente el almacenamiento. Una copia frecuente invita a examinar la ubicación de los tensores, sin probar que sea inútil.
Formula una sola hipótesis y luego propón una modificación controlada. Por ejemplo, si una constante se reconstruye y se transfiere en cada etapa, comprueba si su tiempo de vida puede abarcar varias etapas sin cambiar el resultado. Si un operador parece dominante, inspecciona sus formas y el número de llamadas antes de buscar un reemplazo.
Las líneas de abajo son lecturas posibles, no constataciones extraídas de una traza ejecutada. No se anuncia ninguna duración ni aceleración. La conclusión útil es un experimento siguiente que pueda confirmar o refutar la causa propuesta.
Desplaza la tabla para leer todas las columnas.| Observación posible | Hipótesis | Comprobación siguiente |
|---|---|---|
| GPU sin actividad durante la lectura | El pipeline de entrada no sigue el ritmo | Mismo cálculo con batch ya preparado |
| Copias recurrentes de una constante | Ubicación o tiempo de vida inadecuados | Mover una vez, verificar las salidas |
| Muchos lanzamientos pequeños | Trabajo fragmentado | Examinar agrupación y coste global |
| Un operador largo | Forma o algoritmo determinantes | Comparar el mismo operador y sus entradas |
Limitar el coste y la información de la instrumentación
Empieza con una recolección corta y pocas opciones. Activa las formas, las pilas o la memoria solo si una pregunta lo requiere. La API de PyTorch precisa que esta información añade un coste; la recolección de las formas puede incluso retener referencias a los tensores. Un perfil detallado puede, por tanto, cambiar las duraciones o el uso de memoria del programa.
Una traza puede contener nombres de operadores, formas y, según las opciones, rutas de código. Inspecciónala antes de compartirla. Una etiqueta de zona debe describir la etapa sin incluir correos, tokens, rutas privadas ni contenido de entrada. Elige un visor de trazas adecuado para tu entorno y mantén la recolección bajo tu control.
Si los eventos GPU esperados están ausentes, no rellenes sus tiempos con cero. Indica que no se observaron y revisa el soporte de la recolección. Una ausencia de evento en la herramienta no es prueba de ausencia de cálculo.
Validar la optimización fuera del perfilador
Parte del mismo estado relevante y compara la corrección antes y después de la modificación. En entrenamiento, un paso adicional cambia los pesos; dos capturas lanzadas sucesivamente no constituyen necesariamente una comparación equivalente. Conserva el código, los parámetros y el punto de partida para poder explicar la diferencia.
Mide después el escenario sin recolección detallada, con el mismo calentamiento y varias pasadas. Reporta el alcance, los valores brutos y su dispersión. Una mejora local puede desaparecer en el bucle completo o degradar la calidad: ambas deben permanecer en la decisión.
Por último, usa las observaciones para precisar los recursos realmente necesarios. Una traza de tu equipo no clasifica las ofertas de Kernodeck ni prueba el procesador anfitrión ni la red de un servidor alquilado. La comparación de GPU exige una carga, unas condiciones y unos resultados comparables en los recursos en cuestión.