Definir la carga antes de elegir el contador
«Un modelo 7B» no especifica ni la representación de los pesos ni el trabajo que hay que realizar. Anota su revisión, el framework, las versiones de las extensiones, el formato realmente cargado y la operación: entrenamiento, adaptación o generación. Para el texto, anota las longitudes de entrada y de salida; para la visión, la resolución y el número de imágenes. Un modelo multimodal exige conservar estas dos dimensiones.
Prepara una entrada habitual, una larga pero esperada y una cercana a tu límite funcional. Consérvalas durante las comparaciones. Verifica las formas después de la tokenización, el padding, el agrupamiento o el redimensionamiento: el valor indicado en la configuración no prueba la forma realmente procesada.
Fija también lo que permanece simultáneamente en memoria: una secuencia, un microbatch, varias solicitudes o una evaluación lanzada después del entrenamiento. Tu pregunta se vuelve verificable: ¿esta carga completa cabe en cada dispositivo utilizado, incluso durante su etapa más exigente?
- Identidad del ensayo: modelo o código, revisión, conjunto de entradas y semilla cuando sea pertinente.
- Dimensiones: batch, contexto, tokens generados, resolución o número de solicitudes simultáneas.
- Entorno: GPU seleccionado, controlador, Python, PyTorch, backend CUDA o HIP/ROCm y ajustes del asignador.
- Alcance: carga, cálculo, transferencia, evaluación, exportación; primera pasada o pasada tras el calentamiento.
Calcular los pesos sin mezclar GB y GiB
Un GB corresponde a 1 000 000 000 bytes; un GiB a 1 073 741 824 bytes. Los contadores de PyTorch usados aquí devuelven bytes. Conserva ese valor bruto en el archivo de resultados y aplica una sola conversión para comparar las filas. La denominación comercial de una tarjeta no sustituye la capacidad declarada realmente por el dispositivo.
Para un conjunto denso de siete mil millones de parámetros almacenados en dos bytes cada uno, los pesos representan 14 000 000 000 bytes: 14 GB, o aproximadamente 13,04 GiB. Esta operación no incluye activaciones, gradientes, caché KV ni estados del optimizador. Añadir una reserva de 4 GiB da aproximadamente 17,04 GiB como hipótesis de preparación; eso no demuestra que una carga vaya a caber en ese margen.
La división teórica a cuatro bits supone un almacenamiento compacto uniforme. Una carga cuantizada real puede añadir escalas y otra información, y conservar algunos módulos en otra precisión. Por tanto, el formato de almacenamiento de los pesos y el formato de cálculo deben aparecer por separado en tu ficha.
| Hipótesis de almacenamiento | Bytes calculados | GiB aproximados |
|---|---|---|
| 32 bits uniformes | 28 000 000 000 | 26,08 |
| 16 bits uniformes | 14 000 000 000 | 13,04 |
| 4 bits compactos, sin metadatos | 3 500 000 000 | 3,26 |
Fuentes técnicas: NIST — prefijos binarios y comparación GB/GiB · Hugging Face — formatos y módulos cuantizados con bitsandbytes
En entrenamiento, medir un paso completo
Los pesos coexisten con otros objetos: gradientes, estados del optimizador, activaciones necesarias para la pasada hacia atrás y tensores temporales. Sus tamaños dependen del bucle, de la precisión y de las dimensiones de la carga. Una constante universal en bytes por parámetro ocultaría, en particular, el efecto del microbatch y de las entradas.
Instrumenta la pasada hacia delante, el cálculo de la pérdida, la retropropagación y la actualización. Para observar los estados realmente creados por tu optimizador, no te detengas en la carga del modelo. Conserva también una medición del primer paso completo: un calentamiento exitoso puede haber realizado ya una inicialización que debes poder financiar en memoria al arrancar.
Añade la evaluación y la exportación que necesite tu proyecto. Si el fallo ocurre durante la evaluación, reducir únicamente el batch de entrenamiento no corrige esa fase. Una adaptación que entrena pocos parámetros puede seguir conservando un modelo base y activaciones voluminosas.
Fuentes técnicas: Hugging Face — categorías de memoria durante el entrenamiento
En inferencia, seguir el contexto y la concurrencia
En una generación autorregresiva con atención, la caché KV guarda estados asociados a los tokens. Para una caché densa uniforme, su tamaño depende de las capas, de las cabezas KV, de su dimensión, de los tokens conservados y de las secuencias presentes a la vez. Usa las cabezas KV del modelo, no automáticamente sus cabezas de consulta.
Ejemplo aritmético: 32 capas, 8 cabezas KV, una dimensión de 128, 8 192 tokens, dos bytes por valor y una secuencia dan 1 073 741 824 bytes, es decir, 1 GiB para K y V juntos. Cuatro secuencias idénticas dan 4 GiB solo para esta partida. Este cálculo no mide ni el rendimiento ni la ocupación completa de la GPU.
Adapta la fórmula a la caché realmente empleada. Una ventana deslizante no conserva necesariamente todo el historial; una caché estática puede preasignar su capacidad máxima. Las cachés cuantizadas y deslocalizadas también cambian el problema. Mide por separado el procesamiento inicial de la entrada y la generación, sin atribuir automáticamente toda su diferencia a la caché.
Fuentes técnicas: Hugging Face — estrategias de caché, asignación estática y ventanas
Allocated y reserved: dos lecturas que no se suman
memory_allocated describe los bytes ocupados por los tensores seguidos por PyTorch en el dispositivo. memory_reserved describe la memoria gestionada por su asignador con caché, incluida la que ya sirve a esos tensores. Sumar ambas cuenta dos veces una parte de la memoria. Consérvalas en dos columnas distintas.
Sus variantes máximas registran cada una un pico desde el inicio del seguimiento o su último restablecimiento. Son picos absolutos del periodo, que incluyen las asignaciones ya presentes al inicio. El resultado no representa automáticamente solo los objetos creados por la fase.
Una lectura del sistema puede tener un alcance más amplio. Las asignaciones hechas directamente por una biblioteca CUDA, por ejemplo algunas comunicaciones NCCL, no todas son visibles en el asignador de PyTorch. Por lo tanto, una diferencia con una herramienta del sistema no establece por sí sola una fuga.
| Contador | Pregunta a la que responde | Error que hay que evitar |
|---|---|---|
| memory_allocated | ¿Cuánto ocupan los tensores en este punto de lectura? | Tomarlo por toda la ocupación de la tarjeta. |
| memory_reserved | ¿Cuánto gestiona el asignador en este punto de lectura? | Sumarlo a allocated. |
| max_memory_allocated | ¿Qué pico de los tensores se ha seguido durante el periodo? | Confundirlo con el valor al final de la fase. |
| max_memory_reserved | ¿Qué pico de reserva reporta el asignador? | Suponer que ocurre en el mismo instante que el otro pico. |
Fuentes técnicas: PyTorch — memory_allocated · PyTorch — memory_reserved · PyTorch — max_memory_allocated · PyTorch — asignaciones fuera de su asignador
Por qué la diferencia entre los dos picos no mide la caché
Consideremos únicamente los dos instantes ficticios de la tabla. El pico allocated vale 8 GiB y el pico reserved 12 GiB. Su diferencia, 4 GiB, no es la diferencia observada en ninguno de esos dos instantes: esta vale respectivamente 2 y 6 GiB. Dos máximos no describen forzosamente un mismo estado.
Para estudiar su desfase en un momento dado, registra allocated y reserved en el mismo punto de control, tras la sincronización y sin ninguna operación voluntaria nueva entre las lecturas. Obtienes una diferencia de contadores en ese instante, no una medida de la caché KV del modelo, ni una garantía de que toda esa diferencia pueda satisfacer la próxima asignación.
Guarda también el backend del asignador en el informe. La documentación de PyTorch 2.14 precisa que, con cudaMallocAsync, max_memory_reserved puede combinar los niveles más altos de dos pools y ofrecer una cota superior del pico simultáneo. Esto refuerza la necesidad de conservar el nombre y el alcance del contador.
| Instante ilustrativo | Allocated | Reserved | Reserved − allocated en ese instante |
|---|---|---|---|
| A | 8 GiB | 10 GiB | 2 GiB |
| B | 6 GiB | 12 GiB | 6 GiB |
Fuentes técnicas: PyTorch — definición y límite de max_memory_reserved
Delimitar cada fase antes de registrar su pico
Las operaciones de GPU pueden encolarse antes de terminar. Para una medición por fase, termina los trabajos anteriores antes de restablecer los picos a cero y, después, espera al final de la fase antes de la lectura. torch.cuda.synchronize espera a los kernels de todos los streams del dispositivo seleccionado; esta elección define una frontera explícita para este protocolo.
reset_peak_memory_stats reinicia el seguimiento de los picos a partir del estado actual; no libera los tensores del programa. Registra primero los niveles de partida. Al final, conserva los dos picos absolutos y los dos niveles actuales. No presentes la resta de un nivel de partida como el volumen exacto de todos los tensores temporales: también pueden haberse liberado objetos anteriores durante la fase.
Esta instrumentación puede modificar el solapamiento habitual de las fases. Úsala para localizar el problema y, después, verifica también el bucle completo con su planificación real. En multitarjeta, repite las lecturas para cada dispositivo; una medición en cuda:0 no describe las demás GPU.
- 1. Dar un nombre a la fase y anotar sus entradas exactas.
- 2. Sincronizar el dispositivo y, después, registrar allocated y reserved de partida.
- 3. Llamar a reset_peak_memory_stats en ese mismo dispositivo.
- 4. Ejecutar la fase definida conservando las salidas necesarias para lo siguiente.
- 5. Sincronizar, registrar los picos y los niveles finales y, después, guardar el éxito o el error.
- 6. Conservar el resultado bruto, las dimensiones y la configuración; no rellenar ninguna medición que falte con cero.
Fuentes técnicas: PyTorch — sincronización de un dispositivo · PyTorch — restablecimiento de las estadísticas de pico
Distinguir la primera pasada y las pasadas tras el calentamiento
La primera prueba y un bucle ya preparado no responden a la misma pregunta. Conserva un registro de la carga y del primer paso, y luego documenta el número de iteraciones de calentamiento antes de las repeticiones. No elimines un fallo de inicialización alegando que los pasos siguientes habrían sido más ligeros.
El script de IteraGPU distingue model_load, inputs, cold_forward, warmup y warm_forward. Su cold_forward es el primer paso del modelo pequeño tras inicializar el dispositivo. No mide todo el arranque de un servidor, un controlador o un servicio. Las repeticiones warm_forward permanecen en el mismo proceso y aprovechan su estado existente.
Para tu modelo, comienza una nueva serie en un proceso nuevo cuando cambies una condición que pueda dejar objetos o reservas anteriores. Anota el orden de las pruebas y la política de calentamiento. Relanzar cinco veces un mismo bucle y lanzar cinco procesos no constituyen el mismo protocolo.
Usar el notebook y el script IteraGPU Lab v1
Empieza por el README y luego descarga el notebook autónomo o el script Python. El cálculo estimate usa la biblioteca estándar. La medición exige PyTorch instalado con un backend GPU compatible y un dispositivo accesible; no descarga ningún modelo ni paquete. El notebook requiere un entorno capaz de leer archivos ipynb.
El ejercicio de medición usa una pequeña red densa original y entradas sintéticas. Las opciones batch, context y width describen sus tensores; context aquí no es la longitud de un verdadero LLM con caché KV. Este soporte sirve para examinar el método de medición y para variar una dimensión. No demuestra la capacidad de una tarjeta para tu modelo de investigación.
Ejecuta los comandos que aparecen a continuación desde la carpeta que contiene el script. Consulta primero el informe environment. Si falta PyTorch o la GPU, measure debe detenerse explícitamente con el código 2; ningún resultado de CPU debe interpretarse como una medición de GPU. El JSON de salida de una medición correcta se genera en tu entorno. Elige un nombre de archivo nuevo para cada serie: el script se niega a sobrescribir un resultado existente.
El primer comando rehace el cálculo de los pesos y de la reserva hipotética de 4 GiB. Para los siguientes, usa un dispositivo que estés autorizado a solicitar y mantén dimensiones modestas al principio. Anota la versión de PyTorch realmente utilizada: las referencias técnicas de esta página describen en particular la versión 2.14, sin imponer que esté instalada en tu equipo.
El funcionamiento del script se verificó en un caso pequeño: RTX 5070 local fuera de catálogo, controlador 610.62, Python 3.14.6 y PyTorch 2.11.0+cu128. La prueba usaba batch 1, contexto 16, ancho 64, float32, un calentamiento y dos repeticiones. Valida esta ruta de ejecución, sin calificar un LLM, un entrenamiento ni las GPU ofrecidas en alquiler. El notebook se entrega sin salidas y la tabla de comparación sin resultados; la protección de ausencia de PyTorch también se verificó en un entorno distinto.
python mesure_memoire.py estimate --parameters 7000000000 --bits 16 --reserve-gib 4
python mesure_memoire.py environment --device cuda:0
python mesure_memoire.py measure --device cuda:0 --batch 2 --context 128 --width 1024 --dtype float32 --warmup 3 --repeats 5 --output mesures.json- Notebook de cálculo y medición
Notebook autónomo para abrir, revisar y ejecutar en tu entorno.
- Script mesure_memoire.py
Cálculo sin dependencia externa, comprobación del entorno y medición explícita de GPU.
- Instrucciones de la carpeta
Requisitos previos, comandos, alcance de las fases y límites de interpretación.
- Archivo IteraGPU Lab v1
Todos los recursos versionados, con sus instrucciones y su licencia.
- Licencia de los recursos
Condiciones de reutilización de los archivos proporcionados.
Interpretar un fallo antes de cambiar de tarjeta
Una prueba incompleta sigue siendo una observación útil. Conserva la fase, las dimensiones solicitadas, el mensaje de error y los últimos valores disponibles. Un pico parcial antes de una saturación no constituye el requisito de memoria de una ejecución completa. Reduce una sola dimensión para construir un caso que finalice, y luego busca la frontera entre éxito y fallo.
empty_cache libera bloques no utilizados de la caché del asignador, sin liberar los tensores que siguen vivos. No es una corrección universal a una carga demasiado grande. Llamarlo entre cada repetición cambia las condiciones: documenta esa decisión en lugar de mezclar esos ensayos con los que conservan la caché.
Si los contadores simples no explican la situación, una traza de memoria puede ayudar a identificar las asignaciones a lo largo del tiempo. Su alcance sigue siendo el de las asignaciones visibles por PyTorch. Por lo tanto, un pico allocated bajo no excluye una asignación externa u otro usuario de la tarjeta.
| Observación | Verificación útil | Siguiente prueba |
|---|---|---|
| Fallo durante la carga | Formato cargado, colocación de los pesos y memoria ya ocupada. | Reproducir la carga sola en un proceso nuevo. |
| Carga exitosa, paso hacia atrás imposible | Microbatch, entradas, activaciones conservadas y estado del bucle. | Reducir una dimensión y luego rehacer el paso completo. |
| Evaluación sola en fallo | Batch de evaluación, salidas retenidas y contexto de cálculo. | Medir la evaluación con sus propios límites. |
| Allocated aumenta de una repetición a otra | Referencias conservadas en listas, cachés de la aplicación o grafos. | Verificar su tiempo de vida antes de culpar al asignador. |
| Reserved permanece alto tras el cálculo | Tensores aún vivos y política de caché. | Comparar los valores actuales, sin sumar los contadores. |
| Una herramienta del sistema indica más | Alcance de la herramienta, contexto de GPU, otros procesos y bibliotecas. | Aislar la carga y acercar lecturas tomadas en el mismo momento. |
Fuentes técnicas: PyTorch — qué libera empty_cache · PyTorch — trazas y límites de visibilidad de memoria
Construir un margen a partir de cargas comparables
Evita un porcentaje de margen presentado como universal. El margen debe cubrir variaciones identificadas: entrada más larga, batch autorizado, evaluación, exportación, versión de biblioteca u otra ocupación de la tarjeta. Prueba los casos límite esperados y luego registra lo que queda fuera del alcance. Una ejecución exitosa sobre una sola entrada pequeña no valida la carga máxima.
Cambia una variable a la vez: batch 1 y luego 2 con contexto constante, o contextos 2 048 y luego 4 096 con batch constante. Mantén el mismo contenido y las mismas reglas de preparación. Un truncamiento que elimina una información necesaria hace que la tarea sea diferente, aunque reduzca el pico.
Si los pesos dominan, estudia otro formato controlando la calidad. Si las activaciones dominan, el microbatch o el checkpointing de activaciones pueden ser pistas. Este último intercambia memoria por recálculo: mide también la duración y verifica los resultados. Si la caché KV domina, examina contexto, concurrencia y estrategia de caché. El expediente de comparación completa este enfoque con una regla de calidad común.
Fuentes técnicas: PyTorch — checkpointing de activaciones y recálculo
Pasar de la traza a una decisión de configuración
Tu salida esperada es una ficha breve: estimación de los pesos, carga máxima probada, fases exitosas o fallidas, cuatro contadores con unidades, entorno y elección adoptada. Adjunta el resultado bruto a esta ficha. Separa lo que has calculado, lo que has observado y lo que aún supones.
Compara luego la necesidad con la capacidad de cada tarjeta, manteniendo las restricciones de software. Varias GPU exigen un reparto del trabajo y de los datos; su presencia no crea automáticamente un único depósito de memoria para la aplicación. Un fallo en una tarjeta puede persistir a pesar de haber memoria libre en otra.
El protocolo PyTorch emplea la interfaz torch.cuda; una compilación HIP/ROCm de PyTorch reutiliza ese nombre. Identifica el backend realmente instalado antes de comparar dos familias de hardware. El uso de una misma función de Python no demuestra que los núcleos, las precisiones o los resultados sean equivalentes.
El dimensionador permite retomar la hipótesis inicial; las fichas de GPU permiten comparar las capacidades. Vuelve luego al mismo caso de trabajo para verificar la elección. La pequeña red de la descarga sigue siendo un ejercicio de instrumentación: solo la ejecución de tu carga, en su entorno documentado, puede validar tu propio margen.
Fuentes técnicas: NVIDIA — reparto del trabajo en varias GPU · PyTorch — interfaz torch.cuda en las compilaciones HIP/ROCm