SenseiTeoría desde cero0/21

2 · Números y estadística para producciónLección 7 de 7

Matrices, FLOPs y qué tan rápido calcula una GPU

Matrices, FLOPs and how fast a GPU computes

Cómo se cuenta el trabajo de un modelo en multiplicaciones y sumas, cuánto tarda una GPU en hacerlo y por qué casi nunca llega a la velocidad que promete su hoja de datos.

⏱ 57 min lo esencial · 82 min todo10 conceptos nuevos3 calculadoras10 ejerciciosModelo
Secciones14
  1. 01Matrices y cómo se multiplican
  2. 02Contar el trabajo: MACs y FLOPs
  3. 03FLOPS: qué tan rápido calcula una GPU
  4. 04La memoria también tiene velocidad
  5. 05El roofline: ¿cálculo o memoria? extra
  6. 06El batching: usar cada byte muchas veces extra
  7. 07Por dentro de una multiplicación: tiles, caché y fusión extra
  8. 08Menos bits, más velocidad extra
  9. 09Errores comunes
  10. 10En la vida real extra
  11. 11Ejercicios
  12. 12Lo que sigue
  13. 13Palabras que vas a oír
  14. 14Chequeo
La pregunta

Si una GPU hace más de cien billones de operaciones por segundo, ¿por qué un LLM escribe en ella apenas unos 20 tokens por segundo?

Antes de esta lección: Cómo guarda números una computadora.
01

Matrices y cómo se multiplican

Esencial

Matrices and how to multiply them

En la lección de embeddings viste que un vector es una lista ordenada de números, como (2, 1, 3). Esta lección sube un escalón: de la lista a la tabla. Casi todo lo que calcula un modelo, al entrenar y al responder, son cuentas con tablas de números.

Qué es una matriz

Una matriz (matrix) es una tabla de números ordenada en filas y columnas, todas del mismo largo. Esta tiene 2 filas y 3 columnas:

Fila ↓ · columna →123
1213
2102

Su tamaño se dice filas × columnas: es una matriz de 2 × 3, y se lee «dos por tres». Para señalar un número das su fila y su columna, en ese orden. El de la fila 1 y la columna 3 es 3; el de la fila 2 y la columna 1 es 1. Si la matriz se llama A, se escribe A₁₃ = 3. En Python se cuenta desde 0, así que el mismo número es A[0][2].

Un vector es una matriz con una sola fila (1 × 3) o una sola columna (3 × 1). Y una matriz es un tensor de dos dimensiones: su shape en PyTorch sería [2, 3].

Dónde hay matrices en ML

En todas partes. Cuatro que ya conoces:

  • Los pesos de una capa densa. La última capa de la ResNet-50 de C01 recibe 2,048 números y saca 500 logits, uno por categoría. Sus pesos forman una matriz de 2,048 × 500: una fila por cada número que entra y una columna por categoría.
  • Un batch. Si entran 32 fotos a la vez (un batch), los 2,048 números de cada una se apilan en una matriz de 32 × 2,048: una fila por foto.
  • Una tabla de datos. Una fila por ejemplo y una columna por feature.
  • Una foto en blanco y negro. Una de 224 × 224 píxeles es una matriz de 224 × 224. A color son tres, una por canal, y juntas forman el tensor de 3 × 224 × 224 que recibe la ResNet-50: 150,528 números.

Cuánto ocupa

Una matriz ocupa filas × columnas × los bytes de cada número. En la lección anterior viste cuántos bytes ocupa cada dtype: 4 en float32, 2 en FP16 y BF16, 1 en INT8.

Los pesos de la última capa de C01 son 2,048 × 500 = 1,024,000 números. En FP16 ocupan 1,024,000 × 2 = 2,048,000 bytes, ≈ 2 MB. Guarda esta idea para la segunda mitad de la lección: los bytes van a importar tanto como las cuentas, porque cada byte tiene que viajar desde la memoria hasta el lugar donde se calcula.

Multiplicar: filas por columnas

Recuerda el producto punto de la lección de embeddings: multiplicas dos vectores coordenada por coordenada y sumas todo. Si compras 2 playeras de $50, 1 gorra de $120 y 3 pares de calcetines de $15, pagas (2, 1, 3) · (50, 120, 15) = 100 + 120 + 45 = $265.

Una multiplicación de matrices (matrix multiplication, o matmul) son muchos productos punto de un jalón. Para multiplicar A por B, la casilla de la fila i y la columna j del resultado es el producto punto de la fila i de A con la columna j de B.

Multiplicación de una matriz de 2 por 3 por una de 3 por 2. A tiene las cantidades que compran Sofía (2, 1 y 3) y Luis (1, 0 y 2) de playeras, gorras y calcetines. B tiene el precio y los gramos de cada producto: playera 50 pesos y 200 gramos, gorra 120 y 100, calcetines 15 y 50. El resultado C es de 2 por 2: Sofía paga 265 y su paquete pesa 650 gramos; Luis paga 80 y pesa 300 gramos. La casilla marcada sale de la fila de Sofía por la columna del precio: 2 por 50 más 1 por 120 más 3 por 15, igual a 265. Cada casilla son 3 MACs; las 4 casillas, 12 MACs, que son 24 FLOPs. MULTIPLICAR (2 × 3) · (3 × 2) A: cantidades · B: precio y gramos · C = A · B B precio gramos playera 50 200 gorra 120 100 calcetines 15 50 A Sofía 2 1 3 Luis 1 0 2 265 650 80 300 C LA CASILLA MARCADA la fila de Sofía por la columna del precio: 2 × 50 + 1 × 120 + 3 × 15 = 265 Cada casilla son 3 MACs, y hay 4 casillas: 2 × 2 × 3 = 12 MACs = 24 FLOPs (n × k) · (k × m) da n × m: las de adentro deben ser iguales; las de afuera dan el tamaño.
B va arriba y A a la izquierda, para que cada casilla de C quede justo donde se cruzan su fila de A y su columna de B. La casilla marcada sale de la fila de Sofía por la columna del precio.

La regla de los tamaños

Para multiplicar, la fila de A y la columna de B tienen que medir lo mismo, o el producto punto no tiene pareja para cada número. En tamaños:

(n × k) · (k × m) da n × m

Las dos dimensiones de adentro (las k) deben ser iguales; las de afuera dicen el tamaño del resultado. Tres casos:

  • (2 × 3) · (3 × 2) da 2 × 2: el ejemplo de las compras.
  • (32 × 2,048) · (2,048 × 500) da 32 × 500: un batch de 32 fotos por los pesos de la última capa de C01 da 500 logits por foto.
  • (2 × 3) · (2 × 3) no se puede: las filas de A tienen 3 números y las columnas de B, 2.

El orden importa. B · A sí se puede, porque (3 × 2) · (2 × 3) cuadra por dentro, pero da una tabla de 3 × 3 que no significa nada para la tienda: su primera casilla suma el precio de una playera por las playeras de Sofía con los gramos de una playera por las playeras de Luis. En general, A · B ≠ B · A.

Una capa densa es una multiplicación de matrices

En la lección de redes, una neurona multiplicaba cada entrada por su peso y sumaba: un producto punto, más su sesgo. Una capa de 500 neuronas son 500 productos punto. Si llegan 32 fotos, son 32 × 500. Todo eso es una sola multiplicación de matrices: el batch X, de 32 × 2,048, por los pesos W, de 2,048 × 500, da los logits, de 32 × 500. Después se le suma a cada columna el sesgo de su categoría.

Una capa densa sobre un batch, como multiplicación de matrices (no a escala). A la izquierda, X, el batch: 32 fotos por 2,048 números, una fila por foto. Arriba, W, los pesos: 2,048 por 500, una columna por categoría. Donde se cruzan la fila de una foto y la columna de una categoría queda su logit: el resultado mide 32 por 500. Cada logit es un producto punto de 2,048 números, 2,048 MACs. Todo el batch: 32 por 500 por 2,048, 32,768,000 MACs, unos 65.5 millones de FLOPs. UNA CAPA DENSA SOBRE UN BATCH tenis W: los pesos 2,048 × 500 una columna por categoría foto 1 X: el batch 32 × 2,048 · una fila por foto logits 32 × 500 UN LOGIT la fila de una foto por la columna de una categoría: 2,048 MACs, un producto punto Todo el batch: 32 × 500 × 2,048 = 32,768,000 MACs ≈ 65.5 millones de FLOPs
La misma idea con números de verdad. Cada logit es la fila de una foto por la columna de una categoría: un producto punto de 2,048 números.

Por eso se dice que el deep learning es «multiplicar matrices». Una capa densa es una; una convolución se reorganiza como una (lo ves en una sección extra); la atención de un transformer usa dos. Las GPUs modernas tienen hasta circuitos que solo saben hacer esto.

02

Contar el trabajo: MACs y FLOPs

Esencial

Counting the work: MACs and FLOPs

Antes de preguntar cuánto tarda una GPU, hay que saber cuánto trabajo le pides. Ese trabajo se cuenta igual en cualquier máquina, como los kilómetros de un viaje no dependen del coche.

Dos unidades

Cada casilla del resultado es un producto punto de k números: k multiplicaciones, cada una sumada a lo que llevas. Ese par «multiplica y acumula» es una MAC (multiply-accumulate), la unidad que ya usaste en la lección de redes. El resultado tiene n × m casillas, así que:

MACs = n × m × k

Un FLOP (floating-point operation) es una sola operación con números decimales, es decir, de punto flotante: una multiplicación o una suma. Una MAC son dos FLOPs:

FLOPs = 2 × n × m × k

En las compras de Sofía y Luis: 2 × 2 × 3 = 12 MACs, que son 24 FLOPs. Las dos unidades miden lo mismo, contando el par o cada pieza; mezclarlas es uno de los errores más comunes (lo ves al final).

Los prefijos

Los números crecen rápido, así que se usan los prefijos que viste en la lección de unidades, con su notación científica:

PrefijoValeEjemplo de esta lección
M (mega)10⁶, un millón65.5 MFLOPs: la última capa de C01 con 32 fotos
G (giga)10⁹, mil millones8.2 GFLOPs: la ResNet-50 con una foto
T (tera)10¹², un billón65 TFLOPS: lo que hace una T4 por segundo, como máximo
P (peta)10¹⁵, mil billones82 PFLOPs: las ≈ 10 millones de fotos de un día de C01

Una capa densa

Una capa densa con e entradas y s salidas, aplicada a un batch de b ejemplos, es una matmul de (b × e) · (e × s): b × e × s MACs. Con b = 1 queda la regla de la lección de redes: entradas × salidas.

La última capa de C01, con un batch de 32La cuenta
Tamaño del resultado32 fotos de 2,048 números, por 2,048 × 500 pesos
(32 × 2,048) · (2,048 × 500)
32 × 500
MACs
32 × 500 × 2,048
32,768,000
FLOPs
2 × 32,768,000
65,536,000 ≈ 65.5 MFLOPs
Por foto
65,536,000 ÷ 32
2,048,000 ≈ 2 MFLOPs
Resultado
Cada foto pide ≈ 2 millones de FLOPs en esta capa. Es muy poco: la red completa pide ≈ 4,000 veces más.
FLOPs de una multiplicación de matricesCalculadora

Escribe los tamaños: A mide n × k y B mide k × m. La calculadora cuenta las MACs y los FLOPs, y el tiempo mínimo si la GPU fuera a su pico.

Tamaño del resultadon × m casillas, cada una un producto punto de k números16,000
MACsn × m × k32,768,000
FLOPs2 × n × m × k65,536,000
En GFLOPsmiles de millones0.066
Tiempo mínimo a ese picoFLOPs ÷ FLOPS0.0010 ms
Multiplicaciones así por segundo, como techo991,821

Duplica cualquiera de los tres tamaños y el trabajo se duplica; duplica los tres y se multiplica por 8. El tiempo es un piso: supone que la memoria entrega los números a tiempo, y eso lo decide la intensidad aritmética, que ves en la sección de la memoria.

Empieza con la última capa de C01 y un batch de 32: n = 32, k = 2048 y m = 500. Baja n a 1, una sola foto: el trabajo baja 32 veces. Después pon 4096 en los tres: la multiplicación grande que vas a ver más adelante.

La ResNet-50 completa

Sumando todas sus capas, la ResNet-50 de C01 hace ≈ 4,100 millones de MACs por foto (4,088 millones, contadas capa por capa): 4.1 GMACs, que son 8.2 GFLOPs. Es el número de la Ronda, y lo vas a usar en toda la lección.

Compáralo con sus 24.5 millones de parámetros: 4,088 millones de MACs ÷ 24.5 millones de pesos ≈ 167. Cada peso se usa, en promedio, unas 167 veces por foto. No es igual en todas partes: en una convolución sobre un mapa grande, cada peso se usa en miles de posiciones; en la capa final, una sola vez. Esa reutilización va a ser la clave de la segunda mitad de la lección.

Un LLM

En un LLM, escribir un token usa cada parámetro en una MAC: ≈ 2 FLOPs por parámetro. Llama 3 8B tiene 8.03 mil millones de parámetros, así que hace ≈ 2 × 8.03 × 10⁹ ≈ 16 GFLOPs por token, el doble que una foto de C01. Falta la atención sobre los tokens anteriores, que crece con el largo de la conversación, pero en conversaciones cortas es una parte chica.

03

FLOPS: qué tan rápido calcula una GPU

Esencial

FLOPS: how fast a GPU computes

Ya sabes contar el trabajo. Ahora, la velocidad.

FLOPs y FLOPS

Fíjate en la última letra. FLOPs, con s minúscula, es un plural: una cantidad de operaciones. FLOPS, con S mayúscula, es floating-point operations per second: una velocidad. La ResNet-50 pide 8.2 GFLOPs por foto; una T4 hace hasta 65 TFLOPS. Es la diferencia entre kilómetros y kilómetros por hora.

Los TFLOPS son billones (10¹²) de operaciones por segundo. Con el trabajo y la velocidad, el tiempo sale de una división, como el de un viaje:

tiempo mínimo = FLOPs ÷ FLOPS

Por qué una GPU es tan rápida

Una CPU tiene de 8 a unas decenas de núcleos muy capaces, que hacen cualquier cosa, una tras otra. Una GPU tiene miles de núcleos sencillos que hacen la misma operación sobre muchos números a la vez, y las multiplicaciones de matrices son justo eso: millones de productos punto que no dependen unos de otros.

Las GPUs modernas tienen además tensor cores: circuitos que multiplican un bloque pequeño de matrices completo en un solo paso. La T4 de C01 tiene 2,560 núcleos normales (los CUDA cores) y 320 tensor cores, como viste en la lección de cómo aprende un modelo.

Los tensor cores son rapidísimos, pero solo con ciertos tipos de dato, casi todos de pocos bits: FP16, BF16, FP8 o INT8, según la GPU. Los de la T4 no aceptan float32: con float32, la T4 usa sus núcleos normales y hace 8.1 TFLOPS; con FP16 y sus tensor cores, 65: ocho veces más. Por eso C01 sirve su modelo en FP16, convertido con TensorRT, el compilador de NVIDIA que prepara un modelo para correr rápido en una GPU concreta.

Las GPUs de la Ronda

Estas son las GPUs que más vas a oír, con los números de la Ronda (M04):

T4L4A100H100
Año2018202320202022
Memoria (VRAM)16 GB24 GB40 u 80 GB80 GB
FP16 con tensor cores, denso65 TFLOPS≈ 121 TFLOPS312 TFLOPS≈ 990 TFLOPS
FP8no tiene≈ 242 TFLOPSno tiene≈ 1,979 TFLOPS
INT8, denso130 TOPS≈ 242 TOPS624 TOPS≈ 1,979 TOPS
Ancho de banda de memoria320 GB/s300 GB/s1,555 GB/s (40 GB)
2,039 GB/s (80 GB)
3,350 GB/s
Precio en AWS, por GPU y hora≈ US$0.53≈ US$0.80≈ US$2.75 (40 GB)
≈ US$3.43 (80 GB)
≈ US$6.88

La H100 es la versión SXM, un módulo que va montado en la placa del servidor; la que viene en tarjeta (PCIe) es más lenta. Los precios son aproximados, de septiembre de 2026. Para leer la tabla:

  • Denso. NVIDIA suele publicar también el doble, with sparsity: supone un modelo podado con un patrón especial que casi ningún modelo cumple (lo ves en una sección extra). Divide entre 2. La T4 no tiene sparsity: sus números ya son densos.
  • TOPS. Con enteros como INT8 no son operaciones de punto flotante; se dice TOPS, tera operations per second.
  • La precisión manda. En los tensor cores, con la mitad de bytes por número el pico suele duplicarse: la L4 hace ≈ 121 TFLOPS en FP16 y ≈ 242 en FP8.
  • El ancho de banda es la otra mitad de la historia, la de la sección que sigue. Entre la T4 y la H100, los TFLOPS crecen ≈ 15 veces y el ancho de banda, ≈ 10.

El chequeo de cordura de C01

Con la tabla ya puedes hacer la cuenta que la Ronda llama chequeo de cordura (sanity check) en M03: ¿cuántas fotos por segundo podría responder una T4, como máximo?

Una T4 contra la ResNet-50La cuenta
FLOPs por foto≈ 4.1 GMACs × 2
4.1 × 10⁹ × 2
8.2 × 10⁹
Pico de la T4, por segundoFP16 con tensor cores
hoja de datos de NVIDIA
65 × 10¹²
Tiempo mínimo por foto
8.2 × 10⁹ ÷ (65 × 10¹²)
≈ 0.126 ms
Techo de fotos por segundo
65 × 10¹² ÷ (8.2 × 10⁹)
≈ 7,900
Lo medido en C01con perf_analyzer (la herramienta de Triton que mide cuántas peticiones por segundo aguanta un modelo), TensorRT en FP16 y batches de hasta 32
supuesto de la Ronda
≈ 1,200
Fracción del pico
1,200 ÷ 7,900
≈ 15 %
Resultado
La T4 llega a ≈ 15 % de su pico. Suena a poco, y es normal.

Utilización: cuánto del pico usas de verdad

Esa fracción tiene nombre: la utilización de la GPU, la parte de su velocidad de catálogo que de verdad aprovechas. Se calcula como FLOPS logrados ÷ FLOPS pico. En C01, 1,200 fotos por segundo × 8.2 GFLOPs = 9.84 TFLOPS logrados, contra 65 de pico: ≈ 15 %.

¿Por qué tan poco? La Ronda da cuatro razones:

  1. La T4 baja su velocidad cuando llega a su tope de consumo, 70 W, y bajo carga sostenida llega seguido.
  2. No todas las capas usan los tensor cores.
  3. Entre una operación y la siguiente hay tiempo muerto.
  4. Algunas capas usan muy poco cada byte que leen de la memoria, y se quedan esperando.

La cuarta razón es la idea más importante de esta lección, y es la sección que sigue.

La regla que deja el chequeo: el techo teórico dice qué es imposible, no qué vas a obtener. Si un benchmark te diera 10,000 fotos por segundo en una T4 con la misma ResNet-50 en FP16, serían 10,000 × 8.2 GFLOPs = 82 TFLOPS, más que el pico. El benchmark está midiendo mal.

04

La memoria también tiene velocidad

Esencial

Memory has a speed too

Hay una pregunta que la tabla de TFLOPS no contesta: ¿de dónde salen los números que la GPU multiplica?

El viaje de los números

Los pesos del modelo y las entradas viven en la memoria de la GPU, la VRAM. Los núcleos no calculan ahí: antes, cada número tiene que viajar de la VRAM al chip. Y ese viaje tiene su propio límite de velocidad, el ancho de banda de memoria (memory bandwidth): cuántos bytes por segundo puede entregar la VRAM. En una T4 son 320 GB/s; en una H100, 3,350 GB/s.

Dentro del chip hay una memoria pequeñita y muchísimo más rápida, una caché: 4 MB en la T4, unas decenas de MB en las GPUs más nuevas. Un buen programa trae un bloque de números una vez y lo usa muchas veces ahí antes de soltarlo. Cuántas veces logra usar cada byte que trae es la pregunta de toda esta sección.

Dónde se calcula y por dónde viajan los bytes · Sigue «Una multiplicación grande» y luego «Un token de un LLM»: la misma GPU, con dos historias opuestas. El tercer recorrido adelanta el remedio, el batching, que tiene su propia sección extra.
  • Pesos · los números del modelo
    Los parámetros del modelo. La ResNet-50 de C01 en FP16 ocupa ≈ 49 MB; Llama 3 8B en BF16, ≈ 16 GB. Viven en la VRAM, y para usarlos hay que traerlos al chip.
  • Entradas · el batch, el token
    Lo que entra a cada capa: la foto ya convertida en tensor, los mapas de la capa anterior o, en un LLM, el vector del token y el KV cache de la conversación. También viven en la VRAM y también viajan.
  • Salidas · el resultado de la capa
    Lo que calcula cada capa vuelve a la VRAM para que la siguiente lo lea. Escribirlo y releerlo también cuesta bytes: por eso conviene fusionar operaciones (lo ves en una sección extra).
  • Caché del chip · pocos MB, rapidísima
    Una memoria chiquita dentro del chip, mucho más rápida que la VRAM. Todo lo que sube de la VRAM pasa por el ancho de banda (320 GB/s en una T4). Un buen programa trae un bloque de números una vez y lo usa muchas veces aquí: cuántas veces logra usar cada byte que trae es la intensidad aritmética.
  • Tensor cores · 65 TFLOPS en FP16 (T4)
    Los circuitos que multiplican bloques de matrices en un solo paso, con ciertos tipos de dato, casi todos de pocos bits (FP16, BF16, FP8 o INT8, según la GPU). Son rapidísimos, pero solo trabajan con lo que ya llegó al chip: si la memoria no los alimenta, esperan.

Dos relojes

Cualquier cálculo en una GPU tiene dos tiempos mínimos, como dos relojes que corren a la vez:

  • El reloj del cálculo: FLOPs ÷ FLOPS pico.
  • El reloj de la memoria: bytes que hay que mover ÷ ancho de banda.

Los dos trabajos se enciman (mientras los núcleos calculan un bloque, ya viene el siguiente), así que el cálculo termina cuando termina el más lento:

tiempo ≥ el mayor de (FLOPs ÷ FLOPS, bytes ÷ ancho de banda)

Intensidad aritmética

La comparación entre los dos relojes depende de una sola propiedad del cálculo: cuántas operaciones hace por cada byte que mueve. Se llama intensidad aritmética (arithmetic intensity):

intensidad = FLOPs ÷ bytes movidos

Cálculo, en FP16IntensidadFLOPsBytes
Producto punto de dos vectores de 4,0960.58,19216,384
Matriz de 4,096 × 4,096 por un vector≈ 1≈ 33.6 millones≈ 33.6 MB
Dos matrices de 1,024 × 1,024≈ 341≈ 2.1 mil millones≈ 6.3 MB
Dos matrices de 4,096 × 4,096≈ 1,365≈ 137 mil millones≈ 101 MB

Fíjate en el patrón. Una matriz por un vector usa cada peso una vez: 2 FLOPs por cada 2 bytes. Dos matrices cuadradas de lado n usan cada número n veces: 2n³ FLOPs para mover 3 × n² números de 2 bytes, así que la intensidad es ≈ n ÷ 3. Mientras más grandes las matrices, más se reusa cada byte.

La intensidad es una propiedad del cálculo: no depende de la GPU en que corra.

El punto de quiebre de la GPU

Del otro lado está la GPU. Si divides su pico de FLOPS entre su ancho de banda, sale cuántas operaciones tiene que hacer con cada byte para que la memoria alcance a alimentar a sus núcleos. Es su punto de quiebre (ridge point), y es una propiedad de la GPU:

Puntos de quiebre, en FP16La cuenta
T4
65 × 10¹² ÷ (320 × 10⁹)
≈ 203 FLOPs por byte
L4
121 × 10¹² ÷ (300 × 10⁹)
≈ 403
A100 de 80 GB
312 × 10¹² ÷ (2,039 × 10⁹)
≈ 153
H100
990 × 10¹² ÷ (3,350 × 10⁹)
≈ 295
Resultado
Para tener ocupados sus tensor cores, una T4 necesita usar cada byte que trae en ≈ 200 operaciones. La Ronda redondea los dos primeros a ≈ 200 y ≈ 400.

Con las dos cosas, la decisión es una comparación:

  • Si la intensidad del cálculo es menor que el punto de quiebre, los núcleos esperan a la memoria. El cálculo es memory-bound (limitado por la memoria): tarda bytes ÷ ancho de banda, y una GPU con más TFLOPS no lo acelera.
  • Si es mayor, la memoria alcanza y los núcleos van a su máximo. Es compute-bound (limitado por el cálculo): tarda FLOPs ÷ FLOPS, y una GPU con más ancho de banda no lo acelera.

El decode de un LLM: memory-bound

En la lección de LLMs viste que la respuesta sale de un token a la vez (el decode) y que cada token obliga a leer todos los pesos. Ahora puedes decir con números por qué eso es lento.

Un token de Llama 3 8B en una L4La cuenta
Pesos8.03 mil millones de parámetros en BF16, 2 bytes cada uno
8.03 × 10⁹ × 2 B
≈ 16.06 GB
FLOPs por tokenuna MAC por parámetro
2 × 8.03 × 10⁹
≈ 16 GFLOPs
Intensidad
16 GFLOPs ÷ 16 GB
≈ 1 FLOP por byte
Reloj del cálculo
16 × 10⁹ ÷ (121 × 10¹²)
≈ 0.13 ms
Reloj de la memoria
16.06 GB ÷ 300 GB/s
≈ 54 ms
Techo
1 token ÷ 54 ms
≈ 19 tokens por segundo
Resultado
El quiebre de la L4 es ≈ 400 y la intensidad es 1: memory-bound, unas 400 veces por debajo. Los núcleos trabajan 0.13 ms y esperan 54.

De ahí sale la regla más útil de la lección para los LLMs:

tokens por segundo ≤ ancho de banda ÷ bytes de los pesos

Por eso, para que un LLM escriba más rápido, no sirve una GPU con el doble de TFLOPS. Sirve una con más ancho de banda: en una H100, 3,350 ÷ 16 ≈ 210 tokens por segundo, como techo. O leer menos bytes por token: con los pesos en INT8, la misma L4 sube a ≈ 37 (lo ves en la sección extra de la precisión). O usar cada peso leído para varias conversaciones a la vez: el batching, en otra sección extra. Y fíjate en la trampa: la L4 tiene casi el doble de TFLOPS que la T4, pero un poco menos ancho de banda (300 contra 320 GB/s). Para el decode, la L4 no es más rápida; lo que sí tiene es más VRAM (24 GB, donde cabe un modelo de 8B en BF16, que en los 16 GB de la T4 no cabe) y soporte de BF16, que la T4 no tiene.

El prefill es lo contrario

Leer el prompt es otra historia. En el prefill, los 2,000 tokens de un prompt pasan juntos por el modelo, y cada peso que se lee se usa para los 2,000. La intensidad sube a ≈ 2,000 FLOPs por byte, muy por encima del quiebre de la L4, y manda el cálculo. Por eso la Ronda dice que el tiempo al primer token (TTFT) depende de los FLOPs, y el tiempo de cada token después (TPOT), de los bytes. Son el mismo modelo en la misma GPU, en los dos lados del punto de quiebre.

¿Qué te limita y qué palanca mueves? · El razonamiento completo para cualquier operación. Sigue los tres recorridos: una multiplicación grande, un token de un LLM y la última capa de C01.
  • FLOPs · 2 × n × m × k
    El trabajo de la operación, contado: 2 FLOPs por cada MAC. Para una multiplicación de matrices de n × k por k × m, 2 × n × m × k. Para un token de un LLM, ≈ 2 × parámetros.
  • Bytes · lo que entra y sale de la VRAM
    Todo lo que la operación tiene que leer de la VRAM o escribir en ella: pesos, entradas y salidas, cada número con los bytes de su dtype. En un LLM, también el KV cache de cada conversación.
  • La GPU · pico y ancho de banda
    Dos números de su hoja de datos, en la precisión que vas a usar: el pico de TFLOPS (denso, no with sparsity) y el ancho de banda de memoria en GB/s.
  • Intensidad · FLOPs ÷ bytes
    La intensidad aritmética: cuántas operaciones hace la operación con cada byte que mueve. Es propiedad de la operación, no de la máquina: sube con el tamaño de las matrices y con el batch.
  • Punto de quiebre · pico ÷ ancho de banda
    Cuántas operaciones por byte necesita la GPU para que la memoria alcance a alimentar a sus núcleos: ≈ 203 en una T4, ≈ 403 en una L4, ≈ 153 en una A100 de 80 GB y ≈ 295 en una H100, en FP16.
  • ¿Cuál es mayor? · intensidad o quiebre
    La comparación del roofline (el modelo del techo). El tiempo nunca baja del mayor de dos relojes: FLOPs ÷ pico y bytes ÷ ancho de banda. Cuál es el mayor lo decide justo esta comparación.
  • Memory-bound · manda la memoria
    Palancas: batching (una lectura de los pesos sirve para varias entradas), menos bytes (cuantizar los pesos a INT8 o INT4), fusionar operaciones para no escribir y releer resultados intermedios, o una GPU con más GB/s. Comprar más TFLOPS no mueve nada.
  • Compute-bound · manda el cálculo
    Palancas: menos FLOPs (menos resolución, un modelo más chico), tensor cores de menor precisión (FP16, luego INT8 o FP8) o una GPU con más TFLOPS. Más ancho de banda no lo acelera.
05

El roofline: ¿cálculo o memoria?

Extra

The roofline: compute or memory?

Todo lo anterior cabe en una sola gráfica, el roofline (el modelo del techo) (roofline model, «el modelo del techo»), que propusieron Samuel Williams, Andrew Waterman y David Patterson en 2009.

Cómo se lee

A lo ancho va la intensidad aritmética del cálculo; a lo alto, los TFLOPS que puede alcanzar. Las dos escalas son logarítmicas: cada marca vale 10 veces la anterior, para que quepan juntos 0.1 y 10,000. La línea de arriba es el máximo posible:

TFLOPS alcanzables = el menor de (pico, intensidad × ancho de banda)

Tiene dos partes:

  • La rampa. Con intensidad baja, lo que llega por la memoria limita: cada byte por segundo rinde «intensidad» FLOPs por segundo. En una T4, intensidad × 320 GB/s. Si duplicas la intensidad, duplicas la velocidad.
  • El techo. Con intensidad alta, la memoria ya alcanza y el límite es el pico: 65 TFLOPS en la T4. Subir más la intensidad ya no sirve.

Las dos partes se juntan en el punto de quiebre, ≈ 203 FLOPs por byte en la T4.

El roofline de una T4 en FP16, con las dos escalas logarítmicas. A lo ancho, la intensidad aritmética en FLOPs por byte, de 0.1 a 10,000; a lo alto, los TFLOPS alcanzables, de 0.01 a 100. La rampa sube como intensidad por 320 GB/s hasta el punto de quiebre, cerca de 203 FLOPs por byte, y desde ahí el techo es plano en 65 TFLOPS. A la izquierda del quiebre los cálculos son memory-bound; a la derecha, compute-bound. Tres puntos: el decode de un LLM, con intensidad 1, alcanza 0.32 TFLOPS; la capa final de C01 con batch 32, con intensidad cercana a 30, alcanza unos 9.5 TFLOPS; una multiplicación de dos matrices de 4,096, con intensidad cercana a 1,365, llega al techo de 65 TFLOPS. EL ROOFLINE DE UNA T4 · FP16 TFLOPS 0.1 1 10 100 1,000 10,000 0.01 0.1 1 10 100 intensidad aritmética: FLOPs por byte ← memory-bound compute-bound → pico: 65 TFLOPS quiebre ≈ 203 FLOPs por byte decode de un LLM ≈ 0.32 TFLOPS capa final de C01 batch 32: ≈ 9.5 matmul de 4,096 ≈ 1,365 FLOPs/B Quiebre: 65 TFLOPS ÷ 320 GB/s ≈ 203 FLOPs por byte. Rampa: intensidad × 320 GB/s. Techo: 65 TFLOPS.
El roofline de una T4. A la izquierda del quiebre, la rampa: manda la memoria y cada FLOP por byte de más rinde. A la derecha, el techo plano de 65 TFLOPS. Los tres puntos son cálculos de esta lección.

Lee los tres puntos. El decode de un LLM, con intensidad 1, alcanza a lo mucho 0.32 TFLOPS: el 0.5 % del pico. La última capa de C01 con 32 fotos, con intensidad ≈ 30, puede llegar a lo mucho a ≈ 9.5 TFLOPS. La multiplicación de dos matrices de 4,096 toca el techo.

El roofline de tu GPUCalculadora

Pon el pico y el ancho de banda de una GPU, y la intensidad aritmética de un cálculo. Sale cuántos TFLOPS puede alcanzar y qué lo limita.

Punto de quiebre de la GPUFLOPs por byte: pico ÷ ancho de banda203
Lo que la memoria alcanza a alimentarTFLOPS: intensidad × ancho de banda0.32
TFLOPS alcanzablesel menor de los dos: el techo del roofline0.32
Parte del pico que puedes usar0.5 %
Intensidad ÷ punto de quiebremenos de 1×: memory-bound · 1× o más: compute-bound0.005×

Con la T4 y una intensidad de 1 alcanzas 0.32 TFLOPS: el 0.5 % del pico. Pon la L4 (121 TFLOPS y 300 GB/s) con la misma intensidad: alcanzas un poco menos que con la T4, aunque tiene casi el doble de pico.

Empieza con la T4 y una intensidad de 1. Sube la intensidad hasta pasar 203 y mira cuándo deja de crecer lo alcanzable. Después pon los números de la H100: 990 TFLOPS y 3,350 GB/s.

Una multiplicación grande: compute-bound

Dos matrices de 4,096 × 4,096 son lo mismo que una capa de 4,096 entradas y 4,096 salidas aplicada a un batch de 4,096: la multiplicación grande y con batch por excelencia.

Dos matrices de 4,096 × 4,096 en FP16, en una T4La cuenta
FLOPs
2 × 4,096³
≈ 137.4 × 10⁹
Bytesleer A y B, escribir C: cada una de 4,096² números de 2 bytes
3 × 4,096² × 2
≈ 100.7 MB
Intensidad
137.4 × 10⁹ ÷ (100.7 × 10⁶)
≈ 1,365 FLOPs por byte
Reloj del cálculo
137.4 × 10⁹ ÷ (65 × 10¹²)
≈ 2.11 ms
Reloj de la memoria
100.7 MB ÷ 320 GB/s
≈ 0.31 ms
Resultado
1,365 es mucho más que 203: compute-bound. Tarda por lo menos ≈ 2.1 ms. Una GPU con más ancho de banda no la acelera; una con más TFLOPS, sí.

La misma cuenta, en Python

python
def roofline(nombre, flops, bytes_, pico_tflops, gb_s):
    t_calculo = flops / (pico_tflops * 1e12)        # segundos
    t_memoria = bytes_ / (gb_s * 1e9)
    intensidad = flops / bytes_                      # FLOPs por byte
    quiebre = pico_tflops * 1e12 / (gb_s * 1e9)
    manda = "compute-bound" if intensidad >= quiebre else "memory-bound"
    print(f"{nombre:26}{intensidad:8.1f}{t_calculo * 1e3:10.4f}{t_memoria * 1e3:10.4f}  {manda}")

def matmul(n, k, m, bytes_por_numero=2):            # FP16: 2 bytes por número
    flops = 2 * n * k * m
    bytes_ = bytes_por_numero * (n * k + k * m + n * m)   # leer A y B, escribir C
    return flops, bytes_

print(f"{'operación':26}{'FLOPs/B':>8}{'cálculo':>10}{'memoria':>10}  (ms)")
roofline("matmul 4096, T4", *matmul(4096, 4096, 4096), 65, 320)
roofline("matriz por vector, T4", *matmul(1, 4096, 4096), 65, 320)
roofline("capa final C01 x32, T4", *matmul(32, 2048, 500), 65, 320)
pesos = 8.03e9 * 2                                   # Llama 3 8B en BF16
roofline("token de Llama 3 8B, L4", 2 * 8.03e9, pesos, 121, 300)
roofline("prefill de 2,000, L4", 2 * 8.03e9 * 2000, pesos, 121, 300)
Salida
operación                  FLOPs/B   cálculo   memoria  (ms)
matmul 4096, T4             1365.3    2.1144    0.3146  compute-bound
matriz por vector, T4          1.0    0.0005    0.1049  memory-bound
capa final C01 x32, T4        29.6    0.0010    0.0069  memory-bound
token de Llama 3 8B, L4        1.0    0.1327   53.5333  memory-bound
prefill de 2,000, L4        2000.0  265.4545   53.5333  compute-bound

Las dos últimas filas son el mismo modelo en la misma GPU. Un token suelto no baja de ≈ 54 ms, por los bytes; el prefill de 2,000 tokens, de ≈ 265 ms, por las cuentas. Sueltos, esos 2,000 tokens serían 2,000 × 54 ms ≈ 107 segundos: la diferencia es cuántas veces se usa cada peso leído.

06

El batching: usar cada byte muchas veces

Extra

Batching: using each byte many times

Si el problema del decode es que cada peso se usa una sola vez, el remedio es usarlo varias veces por cada lectura. Eso hace el batching.

Una lectura, muchos usos

Con un batch de b entradas, la matriz de pesos se lee una vez y se multiplica por las b entradas. Los FLOPs se multiplican por b; los bytes de los pesos, no. Mientras los pesos sean casi todos los bytes, la intensidad queda ≈ b.

El batching, en una capa de 4,096 por 4,096 en FP16. Arriba, con una entrada, la matriz de pesos se lee una vez (33.6 MB) para hacer 33.6 millones de FLOPs: 1 FLOP por byte. Con 8 entradas se lee lo mismo, 33.7 MB, para 268 millones de FLOPs: casi 8 FLOPs por byte. Abajo, barras de la intensidad según el batch: 1 con batch 1, 8 con batch 8, 31.5 con batch 32, 228 con batch 256 y 410 con batch 512. Una línea marca el punto de quiebre de la T4, cerca de 203, y otra el de la L4, cerca de 403. UNA LECTURA DE LOS PESOS, MUCHOS USOS W PESOS × batch 1 lee 33.6 MB · 33.6 MFLOPs ≈ 1 FLOP por byte W PESOS × batch 8 lee 33.7 MB · 268 MFLOPs ≈ 8 FLOPs por byte Los FLOPs crecen 8 veces; los bytes, casi nada. INTENSIDAD SEGÚN EL BATCH batch 1 1 batch 8 8 batch 32 31.5 batch 256 228 batch 512 410 T4 ≈ 203 L4 ≈ 403 Con batch b, cada peso se usa b veces: la intensidad es ≈ b mientras los pesos sean casi todos los bytes.
Una capa de 4,096 × 4,096 en FP16. Arriba, con 1 entrada cada peso que se lee se usa una vez; con 8, ocho veces, casi por los mismos bytes. Abajo, la intensidad según el batch, contra los quiebres de la T4 y de la L4.

¿Por qué no es exactamente b? Porque las entradas y las salidas también son bytes, y crecen con el batch. Con la cuenta completa, la capa de 4,096 pasa el quiebre de la T4 con un batch de 226, no de 204; lo calculas en los ejercicios.

En C01: el dynamic batching

La ResNet-50 tiene su propia historia, capa por capa. En FP16, cada peso ocupa 2 bytes y cada uso suyo son 2 FLOPs, así que, si cuentas solo los pesos, la intensidad es igual al número de veces que se usa cada peso:

Usos por peso en la ResNet-50 de C01, a batch 1La cuenta
Etapa 1mapas de 56 × 56
668 M MACs ÷ 0.216 M pesos
≈ 3,100
Etapa 3mapas de 14 × 14
1,464 M ÷ 7.1 M
≈ 206
Etapa 4mapas de 7 × 7
809 M ÷ 15.0 M
≈ 54
Capa finaldensa: cada peso, una vez
1,024,000 ÷ 1,024,500
≈ 1
Resultado
Contando solo los pesos, y contra el quiebre de la T4 (≈ 203): la etapa 1 sobra, la etapa 3 está justo en el límite, y la etapa 4 y la capa final quedan debajo con una sola foto.

Con 4 fotos juntas, la etapa 4 sube a ≈ 54 × 4 = 216 y pasa el quiebre; con 32, a ≈ 1,730. Ojo: esta cuenta solo mira los pesos. Las activaciones (los mapas que cada capa lee y escribe) también viajan, así que la intensidad real es menor, sobre todo donde los mapas son grandes. Una convolución de 1 × 1 de la etapa 1, por ejemplo, mueve ≈ 2 MB de mapas por cada 32 KB de pesos: su intensidad real ronda 50, no 3,100. Y como los mapas crecen con el batch, juntar fotos no se la sube. La Ronda lo resume así: con batches de 32, la ResNet-50 tiende a ser compute-bound; con los batches de 1 a 3 que trae el tráfico real, parte de sus capas espera a la memoria o al costo de lanzar cada operación. Por eso la capacidad se mide, no se deduce de estas cuentas.

Por eso C01 usa el dynamic batching de Triton: junta las fotos que llegan casi juntas, hasta 32, y las calcula en un solo batch. El precio es la espera. La Ronda le pone un tope de 2 ms en la cola, para que juntar fotos no se coma el presupuesto de latencia (un p99 de 200 ms o menos, medido en la API).

En un LLM: varias conversaciones por paso

En el decode, el batch son varias conversaciones a la vez: en cada paso los pesos se leen una vez y sale un token para cada conversación. Pero cada conversación trae su propio KV cache, que se lee aparte y no se comparte. La Ronda lo calcula para Llama 3 8B en una L4 con 4 conversaciones de 8,192 tokens, con 1.07 GB de KV cache cada una (lo que cabe en sus 24 GB):

Cuatro conversaciones a la vez, en una L4La cuenta
Bytes por pasolos pesos una vez, más el KV cache de cada conversación
16.06 GB + 4 × 1.07 GB
≈ 20.3 GB
Tiempo por paso
20.3 GB ÷ 300 GB/s
≈ 68 ms
Tokens por segundo en total4 tokens por paso
4 ÷ 0.068 s
≈ 59
Tokens por segundo de cada conversación
59 ÷ 4
≈ 15
Resultado
Con una sola conversación eran ≈ 19 tokens por segundo. Con cuatro, cada una va un poco más lento (≈ 15), pero la GPU produce ≈ 3 veces más (≈ 59).

Los servidores de LLMs como vLLM hacen esto sin parar: su continuous batching mete y saca conversaciones del batch en cada paso. El límite ya no son los pesos, sino la memoria para los KV caches: cada conversación más ocupa más VRAM y agrega bytes a cada paso. Lo ves en la Ronda, en M14.

Tokens por segundo al decodificarCalculadora

En cada paso del decode, la GPU lee todos los pesos una vez y el KV cache de cada conversación. Mueve los números y mira el techo de tokens por segundo.

Bytes que se leen en cada pasolos pesos una vez, más el KV cache de cada conversación16.1 GB
Tiempo mínimo de cada pasobytes ÷ ancho de banda53.5 ms
Tokens por segundo de cada conversación, como techo18.7
Tokens por segundo en total, como techo18.7

Empieza con Llama 3 8B en BF16 (16.06 GB) en una L4 (300 GB/s): ≈ 19 tokens por segundo. Con los pesos en INT8 (8.03 GB) el techo sube a ≈ 37. Es una cota: no cuenta el cálculo ni el tiempo muerto, y lo real queda abajo.

Prueba 4 conversaciones con 1.07 GB de KV cache cada una: ≈ 59 tokens por segundo en total y ≈ 15 por conversación. Luego pon el ancho de banda de una H100, 3,350 GB/s.

Lo que cuesta el batching

El batching no es gratis:

  • Espera. Para juntar un batch hay que esperar a que lleguen las entradas. Por eso se le pone un tope de tiempo, como los 2 ms de C01.
  • Memoria. Más entradas a la vez son más activaciones, o más KV caches, en la VRAM.
  • La latencia de cada uno. En un LLM, cada conversación más hace un poco más lento el paso de todas: es el TPOT que ve cada persona.
  • Que haya a quién juntar. En un teléfono hay una sola persona escribiendo: batch 1, siempre.
07

Por dentro de una multiplicación: tiles, caché y fusión

Extra

Inside a multiplication: tiles, cache and fusion

La intensidad de una matmul que calculaste (≈ 1,365 para dos matrices de 4,096) supone que cada número viaja de la VRAM una sola vez. Lograrlo es trabajo de quien programa la GPU, y entender cómo explica varias cosas que vas a oír.

El programa más directo, en Python

Así se multiplica sin bibliotecas, contando cada multiplicación con su suma:

python
def matmul(A, B):
    n, k, m = len(A), len(B), len(B[0])
    assert len(A[0]) == k, "las dimensiones de adentro no coinciden"
    C = [[0] * m for _ in range(n)]
    macs = 0
    for i in range(n):              # cada fila de A
        for j in range(m):          # cada columna de B
            for t in range(k):      # el producto punto, número por número
                C[i][j] += A[i][t] * B[t][j]   # multiplica y acumula: 1 MAC
                macs += 1
    return C, macs

compras = [[2, 1, 3],               # Sofía: playeras, gorras, calcetines
           [1, 0, 2]]               # Luis
productos = [[50, 200],             # playera: precio y gramos
             [120, 100],            # gorra
             [15, 50]]              # calcetines
C, macs = matmul(compras, productos)
print("C =", C)
print("MACs =", macs, "  FLOPs =", 2 * macs)

for n, k, m in [(4, 8, 5), (1, 64, 10), (16, 16, 16)]:
    A = [[1] * k for _ in range(n)]
    B = [[1] * m for _ in range(k)]
    print(f"({n} x {k}) . ({k} x {m}): MACs = {matmul(A, B)[1]:5}  n*m*k = {n * m * k}")
Salida
C = [[265, 650], [80, 300]]
MACs = 12   FLOPs = 24
(4 x 8) . (8 x 5): MACs =   160  n*m*k = 160
(1 x 64) . (64 x 10): MACs =   640  n*m*k = 640
(16 x 16) . (16 x 16): MACs =  4096  n*m*k = 4096

Son tres ciclos, uno dentro de otro: uno por cada fila de A (n vueltas), uno por cada columna de B (m vueltas) y uno por cada número del producto punto (k vueltas). Por eso el contador siempre da n × m × k. NumPy y PyTorch hacen exactamente las mismas cuentas, solo que muchísimo más rápido. Lo que cambia, además de repartir el trabajo entre muchos núcleos, es cuántas veces traen cada número de la memoria.

Si no se reusa nada

Ese programa, tal cual, traería de la VRAM los dos números de cada MAC: 4 bytes en FP16 para 2 FLOPs. Intensidad 0.5: memory-bound para siempre, sin importar el tamaño de las matrices. Las cuentas son las mismas; lo que cambia es cuántas veces viaja cada número.

Tiles

Los programas de verdad parten el resultado en bloques, llamados tiles (mosaicos). Para calcular un bloque de T × T casillas de C, traen al chip una franja de T filas de A y una de T columnas de B, y usan cada número T veces antes de soltarlo.

Cuánto rinde un tile de T × T, en FP16La cuenta
FLOPs del bloqueT × T casillas, cada una con k MACs
2 × T × T × k
2T²k
Bytes que se traenT filas de A y T columnas de B, de k números de 2 bytes
2 × (T × k + k × T)
4Tk
Intensidad
2T²k ÷ 4Tk
T ÷ 2
Con T = 64
64 ÷ 2
32 FLOPs por byte
Con T = 256
256 ÷ 2
128 FLOPs por byte
Resultado
Mientras más grande el tile, más se reusa cada número. El límite es la memoria rápida junto a los núcleos, de apenas decenas o cientos de KB por cada grupo de núcleos, así que los programas reales usan tiles dentro de tiles, uno por cada nivel de la jerarquía de memoria (de la VRAM a la caché, y de ahí a la memoria junto a los núcleos), y se acercan a la intensidad ideal.

Nadie escribe esto a mano para su modelo: lo traen las bibliotecas de NVIDIA (cuBLAS para matrices, cuDNN para convoluciones) y los compiladores como TensorRT, que prueban varios tamaños de tile en tu GPU y se quedan con el más rápido.

Una convolución, como matmul

En la lección de redes contaste las MACs de una convolución: posiciones de salida × filtros × pesos por filtro. Es una multiplicación de matrices disfrazada.

Toma la primera capa de la ResNet-50. Cada filtro mira una ventana de 7 × 7 píxeles en los 3 canales: 147 números. Si para cada una de las 112 × 112 = 12,544 posiciones pones en una fila los 147 números que mira el filtro, armas una matriz de 12,544 × 147. Los 64 filtros, uno por columna, forman otra de 147 × 64. Su producto mide 12,544 × 64: los 64 mapas de activaciones de 112 × 112, uno por columna.

La primera capa de la ResNet-50, como matmulLa cuenta
Matriz de ventanasuna fila por posición, con los 147 números que mira el filtro
12,544 × 147
1,843,968 números
Matriz de filtrosuna columna por filtro
147 × 64
9,408 pesos
MACs
12,544 × 64 × 147
118,013,952
Resultado
Las mismas 118 millones de MACs que contaste en la lección de redes. Las bibliotecas de las GPUs suelen calcular las convoluciones así, como multiplicaciones de matrices, para aprovechar el hardware que las multiplica.

Matrices chicas, GPU desperdiciada

Si la matriz es más chica que los tiles, no hay qué reusar ni con qué llenar los miles de núcleos. Además, cada operación es un kernel: un programita que la CPU le manda a la GPU, con un costo fijo de lanzamiento del orden de microsegundos. Una ResNet-50 son decenas de kernels por foto, y más de cien si no se fusionan. A batch 1, ese costo fijo y las matrices chicas pueden pesar más que el cálculo: la GPU parece ociosa sin estarlo. La Ronda (M08) lo arregla con un runtime compilado: TensorRT, que junta capas y deja menos kernels, o torch.compile con CUDA graphs, que lanza todos los kernels de un jalón.

Fusión

Las operaciones elemento a elemento, como sumar el sesgo o aplicar una ReLU, hacen una operación por número: leen 2 bytes, escriben 2 y hacen 1 FLOP. Intensidad 0.25, memory-bound al extremo.

Si cada una fuera un kernel aparte, el resultado de la convolución se escribiría en la VRAM, se volvería a leer para sumar el sesgo, se escribiría otra vez, se leería para la ReLU y se escribiría al final. La fusión de capas (layer fusion) junta la convolución, el sesgo y la ReLU en un solo kernel: la ReLU se aplica mientras el resultado sigue en el chip, y nunca viaja de más. Es de lo primero que hace TensorRT, junto con «plegar» la BatchNorm dentro de la convolución anterior, como viste en la lección de redes.

08

Menos bits, más velocidad

Extra

Fewer bits, more speed

En la lección anterior viste que un número puede guardarse en 4, 2, 1 o medio byte. En el roofline, bajar la precisión mueve las dos cosas a la vez.

Dos efectos

  1. Menos bytes por número. El mismo cálculo en FP16 mueve la mitad de bytes que en float32: la intensidad se duplica y el reloj de la memoria tarda la mitad.
  2. Un techo más alto. Los tensor cores hacen más operaciones por segundo con números más chicos: la T4 pasa de 8.1 TFLOPS en float32 a 65 en FP16 y a 130 TOPS en INT8; la H100, de ≈ 990 en FP16 a ≈ 1,979 en FP8.

Qué efecto te ayuda depende de qué te limita.

En una CNN: hasta 2×

La ResNet-50 con batches grandes tiende a ser compute-bound, así que lo que más la acelera es el techo. En la T4, pasar de FP16 a INT8 sube el techo de 65 a 130: 2× como máximo. Las capas que esperan a la memoria tampoco ganan más de 2×, porque sus bytes bajan a la mitad. Y solo si los pesos y las activaciones están en INT8, porque los tensor cores INT8 necesitan los dos números en INT8. En la práctica no todo se cuantiza y hay conversiones de por medio: la Ronda estima ≈ 1.5 a 2× sobre FP16 para C01. Además, cuantizar puede bajar la accuracy, así que se mide con el golden set antes de aceptarlo.

En el decode de un LLM: tanto como bajen los bytes

El decode es memory-bound: lo que lo acelera es leer menos bytes. Aquí basta cuantizar solo los pesos (weight-only): se guardan en INT8 o INT4 y se convierten de vuelta a 16 bits (BF16 o FP16) justo antes de multiplicar, ya dentro del chip. Esa conversión cuesta cálculo, pero el cálculo sobra.

Llama 3 8B en una L4, con menos bitsLa cuenta
BF162 bytes por peso
300 GB/s ÷ 16.06 GB
≈ 19 tokens por segundo
INT81 byte por peso
300 GB/s ÷ 8.03 GB
≈ 37
INT4medio byte por peso, más las escalas de cada grupo; muchos formatos dejan en BF16 la tabla de embeddings y la capa de salida, ≈ 1,000 millones de pesos
300 GB/s ÷ ≈ 5.73 GB
≈ 52
Resultado
Si los pesos pesan la mitad, el techo se duplica. INT4 no llega a 4× porque parte del modelo se queda en BF16. Más TFLOPS no habrían movido nada.

Servir en float32 sale caro

El otro lado de la moneda. En C01, PyTorch sin optimizar, en float32 y de una foto en una, responde del orden de 100 fotos por segundo: 100 × 8.2 GFLOPs = 0.82 TFLOPS, ≈ 10 % del pico float32 de la T4 y ≈ 1.3 % de su pico FP16. Así, la Ronda calcula que harían falta ≈ 5 GPUs solo para el pico de diseño de 500 fotos por segundo, contra 1 con TensorRT en FP16.

Sparsity

El último truco de las hojas de datos. Desde la generación de la A100, los tensor cores pueden saltarse ceros si en cada grupo de 4 pesos hay 2 en cero (sparsity 2:4). Eso duplica los TFLOPS anunciados, pero exige podar el modelo con ese patrón y reentrenarlo un poco para recuperar la calidad, y casi ningún modelo que te dan lo cumple. Por eso la Ronda usa siempre los números densos, y tú también deberías.

09

Errores comunes

Esencial

Common mistakes

Casi todos vienen de mirar un solo número, los FLOPs o los TFLOPS, y olvidar la memoria o las unidades.

Confundir FLOPs con FLOPS

Qué pasa: «la ResNet-50 hace 8.2 GFLOPS» mezcla una cantidad con una velocidad. Después se divide o se multiplica al revés y salen tiempos sin sentido.

Cómo evitarlo: di las unidades completas: «8.2 GFLOPs por foto» y «65 TFLOPS» (por segundo). Si al dividir no te quedan segundos, o algo por segundo, algo está al revés.

Olvidar el factor 2

Qué pasa: se mezclan MACs con FLOPs. Pasa más de lo que crees, porque muchos artículos llaman «FLOPs» a las MACs: el artículo original de las ResNet (He y otros, 2015) dice que su red de 34 capas hace «3.6 mil millones de FLOPs (multiply-adds)», es decir, de MACs. Si divides MACs entre los TFLOPS de una hoja de datos, que sí cuentan FLOPs, tu tiempo sale a la mitad.

Cómo evitarlo: pregunta siempre «¿MACs o FLOPs?». 1 MAC = 2 FLOPs, y los TFLOPS de los fabricantes cuentan FLOPs.

Creer que el pico se alcanza

Qué pasa: «8.2 GFLOPs por foto y 65 TFLOPS: ≈ 7,900 fotos por segundo por T4». C01 mide ≈ 1,200, el 15 %. Si dimensionas con el pico, compras varias veces menos GPUs de las que hacen falta.

Cómo evitarlo: usa el pico solo como chequeo de cordura, para saber qué es imposible. Dimensiona con lo medido (en la Ronda, con perf_analyzer y tráfico parecido al real). Y si tu medición pasa el pico, la medición está mal.

Ignorar el ancho de banda de memoria

Qué pasa: «el LLM va lento: compro una GPU con el doble de TFLOPS». El decode es memory-bound: la L4 tiene casi el doble de TFLOPS que la T4 y, aun así, menos GB/s.

Cómo evitarlo: antes de comprar, calcula la intensidad del cálculo y compárala con el quiebre de la GPU. Para el decode, la cuenta rápida es tokens por segundo ≤ GB/s ÷ GB de pesos.

Confundir cuánta memoria hay con qué tan rápido se lee

Qué pasa: «es memory-bound porque la T4 tiene poca VRAM». Es la respuesta junior que cita la Ronda. La capacidad (GB) decide qué cabe; el ancho de banda (GB/s), qué tan rápido se lee. Un modelo puede caber con espacio de sobra y ser memory-bound igual.

Cómo evitarlo: separa las dos preguntas: ¿cabe? (GB) y ¿qué tan rápido se lee? (GB/s). Se resuelven con palancas distintas.

Comparar TFLOPS de distinta precisión, o con sparsity

Qué pasa: comparar los ≈ 1,979 TFLOPS de la H100 en FP8 con los 312 de la A100 en FP16 y concluir que es 6 veces más rápida. En la misma precisión (FP16) son ≈ 990 contra 312: ≈ 3 veces. Y si la tabla dice with sparsity, es el doble de lo que tu modelo va a ver.

Cómo evitarlo: compara siempre en la misma precisión, densa, y la que de verdad vas a usar.

Leer la utilización de nvidia-smi como «qué tanto trabajan los núcleos»

Qué pasa: nvidia-smi marca 100 % y se concluye «la GPU está al máximo, hay que comprar otra». Ese número es el porcentaje del tiempo en que corrió algún kernel. Un decode memory-bound marca casi 100 % con los tensor cores casi ociosos; con batches de 1, la Ronda (M03) cuenta que puede marcar 30 % mientras usas el 5 % de lo que la GPU daría con batches grandes.

Cómo evitarlo: compara el throughput logrado contra el máximo medido, mira cómo cambia el throughput al subir el batch y, si hace falta el detalle, usa un perfilador como Nsight.

10

En la vida real

Extra

In real life

C01 · Una T4 que trabaja al 5 %. Cuando Ana sube la foto de sus tenis, la ResNet-50 hace 8.2 GFLOPs en una T4, que mide ≈ 1,200 fotos por segundo: el 15 % de su pico. Un día completo son 10 millones de fotos, 82 PFLOPs, que una sola T4 resolvería en ≈ 2.3 horas a su máximo medido (la cuenta va abajo). En promedio llegan ≈ 116 fotos por segundo para 2 GPUs: ≈ 58 cada una contra ≈ 1,200 posibles, ≈ 5 % de carga. Las dos T4 (≈ US$768 al mes) están ahí por disponibilidad, para que el servicio siga si se cae una, no por cálculo. Por eso cuantizar a INT8 (2× como máximo) no ahorra GPUs en C01: no es el cálculo lo que fija cuántas hay.

Todas las fotos de un día de C01La cuenta
Fotos al día≈ 2.5 M publicaciones con ≈ 3 fotos cada una, más las que mandan otros equipos
dato de la Ronda
10,000,000
FLOPs por foto
2 × 4.1 × 10⁹
8.2 × 10⁹
FLOPs al día
10,000,000 × 8.2 × 10⁹
8.2 × 10¹⁶ = 82 PFLOPs
Una T4 a lo medido≈ 1,200 fotos por segundo
10,000,000 ÷ 1,200
≈ 8,300 s ≈ 2.3 horas
Resultado
82 PFLOPs suena enorme, pero es menos de una décima parte del día de una sola T4.
Para ir más hondoCuánto cuesta entrenar

Entrenar suma la backpropagation, que cuesta unas dos veces el forward pass: calcula gradientes para las activaciones y para los pesos. Por eso un paso de entrenamiento cuesta ≈ 3 veces responder, como viste en la lección de cómo aprende un modelo.

En C01: 1,840,211 fotos × 8 épocas × 3 × 8.2 GFLOPs ≈ 3.6 × 10¹⁷ FLOPs por cada entrenamiento mensual.

Para los LLMs se usa la misma regla escrita de otra forma: entrenar cuesta ≈ 6 × parámetros × tokens de entrenamiento, 2 del forward y ≈ 4 de la backpropagation por cada parámetro y cada token. Es la cuenta que se usa para estimar cuántas GPUs y cuántas semanas pide un modelo nuevo.

C10 · Un LLM propio. C10 sirve un modelo de 70.6 mil millones de parámetros en FP8: ≈ 70.6 GB de pesos. Cada réplica usa 2 H100 y las dos se reparten los pesos (tensor parallelism), así que en cada paso de decode cada H100 lee su mitad: 35.3 GB ÷ 3,350 GB/s ≈ 10.5 ms, el piso del paso. Con 40 conversaciones a la vez, cada GPU lee además ≈ 13.9 GB de KV cache: el paso sube a ≈ 15 ms. El objetivo de C10 es un TPOT de 50 ms o menos en el p95 (≈ 20 tokens por segundo por persona), así que queda margen. El prefill, en cambio, es compute-bound: con ≈ 4.2 preguntas por segundo por réplica y ≈ 1,000 tokens nuevos en cada prompt (el resto es un principio que se repite entre preguntas, y su KV cache ya estaba calculado), son ≈ 593 TFLOPS, ≈ 15 % del pico FP8 de las dos H100 (≈ 3,958). Son cotas: la capacidad real de cada réplica sale de un barrido de carga.

Un teléfono con un modelo chico. Un teléfono atiende a una sola persona, así que siempre está a batch 1: el decode es memory-bound sin remedio. Su memoria es compartida por la CPU, la GPU y la NPU (el chip para redes neuronales), y entrega unas decenas de GB/s. Las NPUs anuncian decenas de TOPS, pero para escribir texto casi no importan: importan los bytes. Apple publicó en 2024 que su modelo para el iPhone, de ≈ 3,000 millones de parámetros comprimido a ≈ 3.5 bits por peso, genera ≈ 30 tokens por segundo en un iPhone 15 Pro. Haz la cuenta: 3 × 10⁹ × 3.5 ÷ 8 ≈ 1.3 GB de pesos. Apple no publica el ancho de banda de esa memoria; si es del orden de 50 GB/s, una estimación razonable, el techo es ≈ 38 tokens por segundo. Lo publicado queda cerca del techo (≈ 80 %), como debe ser en un cálculo memory-bound. Por eso los modelos de los teléfonos son chicos y van muy cuantizados: duplicar los TOPS de la NPU no movería nada, y bajar los bytes por token sí.

Fuera del ML: los videojuegos. Las GPUs nacieron para dibujar. Cada vértice de un modelo 3D se multiplica por una matriz de 4 × 4 para ponerlo en la pantalla, y una imagen de 1080p tiene 1920 × 1080 = 2,073,600 píxeles, cada uno con su propia cuenta, 60 veces por segundo: ≈ 124 millones de píxeles por segundo. Es el mismo tipo de trabajo que una red neuronal: muchísimas multiplicaciones iguales e independientes. En 2012, AlexNet ganó el concurso ImageNet entrenada en dos tarjetas de videojuegos (GTX 580), y desde entonces el deep learning vive en GPUs.

11

Ejercicios

Esencial

Exercises

Resuélvelos con lápiz (y calculadora para los números grandes) antes de abrir la solución. Los cuatro primeros son directos; los dos últimos juntan varias ideas.

  1. 1Fácil

    ¿Se puede multiplicar una matriz de 3 × 4 por una de 4 × 2? ¿Y una de 3 × 4 por una de 2 × 4? Si se puede, ¿de qué tamaño sale y cuántas MACs y FLOPs cuesta?

    Ver la solución paso a paso

    3 × 4 por 4 × 2: sí, porque las de adentro coinciden (4 y 4). Sale de 3 × 2. MACs: 3 × 2 × 4 = 24; FLOPs: 48.

    3 × 4 por 2 × 4: no. Las filas de la primera tienen 4 números y las columnas de la segunda, 2. Con la transpuesta de la segunda, que mide 4 × 2, sí se podría.

  2. 2Fácil

    Calcula A · B y B · A, con A = [[1, 2], [3, 4]] y B = [[5, 6], [7, 8]] (cada corchete de adentro es una fila). ¿Cuántas MACs hiciste en cada una?

    Ver la solución paso a paso

    A · B, fila por columna:

    • Fila 1: 1 × 5 + 2 × 7 = 19 y 1 × 6 + 2 × 8 = 22.
    • Fila 2: 3 × 5 + 4 × 7 = 43 y 3 × 6 + 4 × 8 = 50.

    A · B = [[19, 22], [43, 50]].

    B · A: 5 × 1 + 6 × 3 = 23, 5 × 2 + 6 × 4 = 34, 7 × 1 + 8 × 3 = 31 y 7 × 2 + 8 × 4 = 46. B · A = [[23, 34], [31, 46]]: otro resultado, aunque las dos midan 2 × 2.

    Cada una cuesta 2 × 2 × 2 = 8 MACs, 16 FLOPs.

  3. 3Fácil

    Un MLP para dígitos tiene una capa de 784 entradas y 128 salidas. ¿Cuántas MACs y FLOPs hace con un batch de 64 imágenes? ¿Cuánto tardaría, como mínimo, en una T4 a 65 TFLOPS?

    Ver la solución paso a paso

    Es una matmul de (64 × 784) · (784 × 128):

    • MACs: 64 × 784 × 128 = 6,422,528.
    • FLOPs: el doble, 12,845,056, unos 12.8 millones.
    • Tiempo mínimo: 12,845,056 ÷ (65 × 10¹²) ≈ 2 × 10⁻⁷ s = 0.2 µs.

    Es tan poco que pesan más otras cosas: el costo fijo de lanzar la operación en la GPU, del orden de microsegundos, y hasta leer sus ≈ 0.32 MB de entradas, pesos y salidas en FP16, ≈ 1 µs a 320 GB/s.

  4. 4Fácil

    Un detector pide 20 GFLOPs por imagen y una GPU anuncia 100 TFLOPS en la precisión que usas. ¿Cuál es el tiempo mínimo por imagen y el techo de imágenes por segundo? Si mides 900 por segundo, ¿qué utilización tienes?

    Ver la solución paso a paso
    • Tiempo mínimo: 20 × 10⁹ ÷ (100 × 10¹²) = 0.0002 s = 0.2 ms.
    • Techo: 100 × 10¹² ÷ (20 × 10⁹) = 5,000 imágenes por segundo.
    • Utilización: 900 ÷ 5,000 = 18 %. Un número normal, como el 15 % de C01.
  5. 5Medio

    Multiplicas dos matrices de 1,024 × 1,024 en FP16. Calcula sus FLOPs, los bytes mínimos (leer las dos y escribir el resultado) y su intensidad. ¿Es compute-bound en una T4? ¿Y en una L4?

    Ver la solución paso a paso
    • FLOPs: 2 × 1,024³ = 2,147,483,648 ≈ 2.15 × 10⁹.
    • Bytes: 3 × 1,024² × 2 = 6,291,456 ≈ 6.3 MB.
    • Intensidad: 2.15 × 10⁹ ÷ (6.3 × 10⁶) ≈ 341 FLOPs por byte.

    En la T4 (quiebre ≈ 203) es compute-bound. En la L4 (quiebre ≈ 403) es memory-bound, por poco. Ahí los dos relojes quedan cerca: el cálculo, 2.15 × 10⁹ ÷ (121 × 10¹²) ≈ 0.018 ms; la memoria, 6.3 MB ÷ 300 GB/s ≈ 0.021 ms. La misma operación cambia de lado según la GPU: la intensidad es del cálculo, el quiebre es de la máquina.

  6. 6Medio

    ¿Cuántos tokens por segundo, como techo, da Llama 3 8B en BF16 (≈ 16.06 GB) en una A100 de 80 GB y en una H100? ¿Y un modelo de 70.6 mil millones de parámetros en FP8, en una sola H100, si cupiera con su KV cache?

    Ver la solución paso a paso

    Techo = ancho de banda ÷ bytes de los pesos:

    • A100 de 80 GB: 2,039 ÷ 16.06 ≈ 127 tokens por segundo.
    • H100: 3,350 ÷ 16.06 ≈ 209 (la Ronda redondea a ≈ 210).
    • El de 70.6 mil millones en FP8 pesa ≈ 70.6 GB: 3,350 ÷ 70.6 ≈ 47.

    En C10 ese modelo va repartido en dos H100 que leen su mitad cada una, a la vez: el piso baja a ≈ 10.5 ms por paso, ≈ 95 tokens por segundo como techo para una sola conversación.

  7. 7Medio

    (La aproximación «intensidad ≈ b» viene de la sección extra del batching.) Una capa de 4,096 × 4,096 en FP16 recibe un batch de b vectores. Escribe su intensidad y encuentra el batch más chico con el que pasa el quiebre de la T4 (≈ 203.1). Compáralo con la aproximación «intensidad ≈ b».

    Ver la solución paso a paso

    FLOPs: 2 × b × 4,096 × 4,096. Bytes: 2 × (b × 4,096 + 4,096 × 4,096 + b × 4,096), las entradas, los pesos y las salidas. Dividiendo y simplificando:

    intensidad = 4,096 × b ÷ (2b + 4,096)

    Para que pase 203.1: 4,096 b ≥ 203.1 × (2b + 4,096), o sea b × (4,096 − 406.2) ≥ 203.1 × 4,096, y b ≥ 831,898 ÷ 3,689.8 ≈ 225.5. El batch más chico es 226 (comprobación: 4,096 × 226 ÷ 4,548 ≈ 203.5).

    La aproximación «intensidad ≈ b» diría 204, un 10 % menos. Con batches chicos casi no importa; cerca del quiebre, las entradas y salidas ya pesan.

  8. 8Medio

    (a) Si C01 pasara su modelo a INT8 y midiera 2,000 fotos por segundo por T4, ¿qué parte del pico INT8 de la T4 (130 TOPS) usaría? (b) Un proveedor jura que con la misma T4 y la misma ResNet-50 en FP16 llega a 10,000 fotos por segundo. ¿Le crees?

    Ver la solución paso a paso

    (a) 2,000 × 8.2 × 10⁹ = 16.4 × 10¹² operaciones por segundo, contra 130 × 10¹²: ≈ 13 %. Más fotos por segundo que en FP16, pero una utilización parecida: la misma T4, con las mismas esperas.

    (b) No: 10,000 × 8.2 × 10⁹ = 82 TFLOPS, más que el pico de 65. En FP16 es imposible. Algo cambió sin decirlo (un modelo más chico, menos resolución, INT8) o midió mal. Pide ver cómo midió.

  9. 9Reto

    (Las partes c y d usan la sección extra del batching.) La ResNet-50 de C01 tiene 24.5 millones de parámetros y hace 4.1 GMACs por foto. (a) En FP16 y contando solo los pesos, ¿cuál es su intensidad a batch 1? (b) Su etapa 4 tiene 15.0 millones de pesos y hace 809 millones de MACs: ¿cuál es su intensidad a batch 1? (c) ¿Desde qué batch pasa la etapa 4 el quiebre de la T4? (d) ¿Por qué la intensidad real es menor que estas cuentas?

    Ver la solución paso a paso

    (a) FLOPs: 8.2 × 10⁹. Bytes de pesos: 24.5 × 10⁶ × 2 = 49 MB. Intensidad: 8.2 × 10⁹ ÷ (49 × 10⁶) ≈ 167 FLOPs por byte, un poco debajo de los ≈ 203 de la T4. Es lo mismo que «cada peso se usa ≈ 167 veces»: en FP16, 2 FLOPs por uso y 2 bytes por peso se cancelan.

    (b) 809 ÷ 15.0 ≈ 54: casi todos los pesos de la etapa 4 se usan en las 7 × 7 = 49 posiciones de sus mapas (el promedio sube un poco porque su primera convolución todavía trabaja con mapas de 14 × 14). Memory-bound a batch 1.

    (c) Con batch b, la intensidad por los pesos es ≈ 54 × b. Para pasar 203: b ≥ 203 ÷ 54 ≈ 3.8, así que batch 4 (54 × 4 = 216).

    (d) Porque las activaciones también viajan: la entrada de cada capa se lee y su salida se escribe en la VRAM. Esos bytes suman al denominador y bajan la intensidad. En las primeras etapas, con mapas de 56 × 56, las activaciones pesan mucho más que los pesos.

  10. 10Reto

    En C10, una réplica sirve un modelo de 70.6 mil millones de parámetros en FP8 (1 byte por peso) con 2 H100, cada una con la mitad de los pesos. (a) ¿Cuál es el piso de un paso de decode por leer los pesos? (b) Con 40 conversaciones, cada GPU lee además ≈ 13.9 GB de KV cache por paso: ¿cuánto tarda el paso y cuántos tokens por segundo salen en total? (c) Para el prefill de un prompt de 2,000 tokens, ¿cuántos FLOPs son, qué intensidad tiene y cuál es su piso en FP8 (≈ 1,979 TFLOPS por H100)? ¿Por qué no tarda 2,000 pasos de decode?

    Ver la solución paso a paso

    (a) Cada H100 lee 35.3 GB a 3,350 GB/s: 35.3 ÷ 3,350 ≈ 10.5 ms.

    (b) (35.3 + 13.9) GB ÷ 3,350 GB/s ≈ 14.7 ms ≈ 15 ms por paso. Salen 40 tokens por paso: 40 ÷ 0.0147 s ≈ 2,700 tokens por segundo en total, ≈ 68 por conversación. El TPOT no puede bajar de ≈ 15 ms, y el objetivo de 50 ms deja margen.

    (c) FLOPs: 2 × 70.6 × 10⁹ × 2,000 ≈ 2.8 × 10¹⁴. Cada peso de 1 byte se usa para los 2,000 tokens, 2 FLOPs cada vez: intensidad ≈ 4,000 FLOPs por byte, contra un quiebre de la H100 en FP8 de ≈ 1,979 ÷ 3.35 ≈ 591. Compute-bound. Piso: 2.8 × 10¹⁴ ÷ (2 × 1,979 × 10¹²) ≈ 71 ms.

    2,000 pasos de decode tardarían ≈ 2,000 × 10.5 ms = 21 s, porque leerían los pesos 2,000 veces. El prefill los lee una vez y usa cada byte miles de veces: ahí manda el cálculo, que la H100 tiene de sobra.

12

Lo que sigue

Esencial

What comes next

En la Ronda:

  • M03 · Latencia y capacidad hace el chequeo de cordura de esta lección: 8.2 GFLOPs por foto contra 65 TFLOPS, un techo de ≈ 7,900 fotos por segundo, y lo medido, ≈ 1,200 (≈ 15 %). Ahí también está la trampa de planear con la utilización de nvidia-smi.
  • M04 · Hardware para inferencia trae la tabla de las GPUs (T4, L4, A10G, A100 y H100), la sección del roofline con sus puntos de quiebre y los techos de decode de Llama 3 8B: ≲ 19 tokens por segundo en una L4 y ≲ 210 en una H100.
  • M08 · Optimización de modelos usa el roofline para elegir: INT8 da como máximo 2× en una CNN (130 TOPS contra 65 TFLOPS en la T4), INT4 weight-only sube el decode de la L4 de ≈ 19 a ≈ 52 tokens por segundo, la fusión de capas evita releer la memoria, y bajar la resolución de 224 a 160 píxeles deja (160 ÷ 224)² ≈ 51 % de los FLOPs.
  • M14 · Sistemas con LLMs separa el prefill (compute-bound, manda el TTFT) del decode (memory-bound, manda el TPOT), calcula los pisos de una réplica de C10 y explica el speculative decoding.
  • C01 y C10 hacen estas cuentas en grande: 2 T4 que trabajan al ≈ 5 % en promedio, y 16 réplicas de 2 H100 con un piso de ≈ 15 ms por paso de decode.

En el Dojo: cuando abra la estación 5 (Export, engine y paridad), vas a convertir el modelo de C01 en un engine de TensorRT. Ese engine es lo de las secciones extra «Menos bits, más velocidad» y «Por dentro de una multiplicación» hecho archivo: corre en FP16 en los tensor cores y trae las capas fusionadas.

En Sensei: sigue el módulo «La computadora por dentro», que abre con «Programa, proceso e hilo». «Memoria, caché y disco» explica por qué hay memorias de distinta velocidad y qué es una caché; «CPU y GPU» muestra cómo se reparten el trabajo sus núcleos. Más adelante, «Qué tan rápido y cuánto: latencia y throughput» junta estos tiempos mínimos con las colas, y «Máquinas, GPUs y cómo se cobran» les pone precio.

13

Palabras que vas a oír

Esencial

Words you will hear

Estos son los conceptos que presentó esta lección. Cada uno tiene su tarjeta con la definición completa.

MatrizmatrixUna tabla de números ordenada en filas y columnas, todas del mismo largo. Su tamaño se dice «filas × columnas»: una matriz de 2 × 3 tiene 2 filas y 3 columnas.Más

Es el paso que sigue al vector: un vector es una sola fila (o una sola columna) de números; una matriz, varias filas del mismo largo. Cada número se ubica por su fila y su columna. En ML casi todo es una matriz o se guarda como una: los pesos de una capa densa (una fila por número que entra y una columna por salida), un batch de embeddings (una fila por foto) o una tabla de datos (una fila por ejemplo y una columna por feature). Una matriz es un tensor de dos dimensiones, y su shape es [filas, columnas]. Lo que ocupa en memoria es filas × columnas × los bytes de su dtype.

Ejemplo. Los pesos de la última capa de la ResNet-50 de C01 forman una matriz de 2,048 × 500: una fila por cada número que sale del backbone y una columna por categoría. Son 1,024,000 números: ≈ 2 MB en FP16 y ≈ 4.1 MB en float32.

Ver en el glosario →

Multiplicación de matricesmatrix multiplication (matmul)Combinar una matriz de n × k con una de k × m para obtener una de n × m: cada casilla del resultado es el producto punto de una fila de la primera con una columna de la segunda.Más

Solo se puede si las dimensiones de adentro coinciden (las dos k); las de afuera dan el tamaño del resultado. El orden importa: A · B casi nunca es igual a B · A, y a veces ni siquiera se puede. Cada casilla pide k MACs, así que el total es n × m × k MACs, o 2 × n × m × k FLOPs. Es la operación central del deep learning: una capa densa sobre un batch es una sola multiplicación de matrices, una convolución se reorganiza como una, y la atención de un transformer usa dos. Las GPUs tienen circuitos, los tensor cores, que solo hacen esto.

Ejemplo. Las cantidades de dos compras, (2, 1, 3) y (1, 0, 2), por una tabla de 3 × 2 con el precio y los gramos de cada producto (playera: $50 y 200 g; gorra: $120 y 100 g; calcetines: $15 y 50 g). Sale una tabla de 2 × 2: la primera compra cuesta $265 y pesa 650 g; la segunda, $80 y 300 g. Fueron 2 × 2 × 3 = 12 MACs.

Ver en el glosario →

FLOPfloating-point operationUna operación con números decimales: una suma o una multiplicación en punto flotante. Contar FLOPs dice cuánto trabajo pide un cálculo, sin importar en qué máquina corra.Más

El plural se escribe FLOPs, con s minúscula, y es una cantidad. No lo confundas con FLOPS, con S mayúscula, que es una velocidad: FLOPs por segundo (ver TFLOPS). Una multiplicación con su suma, una MAC, son 2 FLOPs, así que multiplicar una matriz de n × k por una de k × m cuesta 2 × n × m × k FLOPs. Se usan los prefijos de siempre: MFLOPs (millones), GFLOPs (miles de millones), TFLOPs (billones, 10¹²). Ojo: muchos artículos y tablas llaman «FLOPs» a lo que en realidad son MACs; antes de comparar dos números, revisa cuál cuenta cada uno.

Ejemplo. La ResNet-50 de C01 hace ≈ 4.1 mil millones de MACs por foto: ≈ 8.2 GFLOPs. Un LLM hace ≈ 2 FLOPs por parámetro por cada token: Llama 3 8B, con 8.03 mil millones de parámetros, ≈ 16 GFLOPs por token.

Ver en el glosario →

MACmultiply-accumulateMultiplicar dos números y sumar el resultado a lo que ya llevas acumulado. Es la unidad de trabajo de una red neuronal: 1 MAC son 2 FLOPs, una multiplicación y una suma.Más

Un producto punto de k números son k MACs: multiplicas cada par y lo vas sumando a un acumulador. Una capa densa hace entradas × salidas MACs por ejemplo; una convolución, posiciones × filtros × pesos por filtro; una multiplicación de matrices de n × k por k × m, n × m × k. El hardware la hace en una sola instrucción (la FMA, fused multiply-add), pero se cuenta como 2 FLOPs. Las MACs dicen cuánto cálculo pide un modelo; los parámetros, cuánta memoria.

Ejemplo. La primera capa de la ResNet-50 tiene 9,408 pesos y hace 118,013,952 MACs por foto: cada peso se usa en 12,544 posiciones. La red completa hace ≈ 4.1 GMACs (4,100 millones) por foto, que son ≈ 8.2 GFLOPs.

Ver en el glosario →

TFLOPSteraFLOPSBillones (10¹²) de operaciones de punto flotante por segundo: la velocidad de cálculo de un chip. Una T4 anuncia 65 TFLOPS en FP16; una H100, ≈ 990.Más

La S mayúscula es «por segundo»: FLOPS es una velocidad y FLOPs, con s minúscula, una cantidad. Lo que publica el fabricante es el pico teórico: todos los núcleos trabajando sin parar con un tipo de dato concreto. Depende mucho de la precisión: la T4 hace 8.1 TFLOPS en float32 y 65 en FP16 con sus tensor cores. Con enteros se dice TOPS (operaciones, no de punto flotante): 130 TOPS en INT8 en la T4. Si la hoja de datos dice with sparsity, divide entre 2: supone un modelo podado con un patrón especial. El tiempo mínimo de un cálculo es sus FLOPs ÷ los FLOPS; en la práctica se logra una fracción, porque a menudo manda el ancho de banda de memoria (ver roofline (el modelo del techo)).

Ejemplo. La ResNet-50 hace 8.2 GFLOPs por foto. En una T4, a 65 TFLOPS: 8.2 × 10⁹ ÷ (65 × 10¹²) ≈ 0.126 ms por foto, un techo de ≈ 7,900 fotos por segundo. Lo que se mide en C01 es ≈ 1,200: ≈ 15 % del pico.

Ver en el glosario →

Intensidad aritméticaarithmetic intensityCuántas operaciones hace un cálculo por cada byte que lee o escribe en la memoria: FLOPs ÷ bytes. Si es baja, manda la memoria; si es alta, manda el cálculo.Más

Es una propiedad del cálculo, no de la máquina: depende de cuántas veces se reutiliza cada número que se trae de la VRAM. Una matriz por un vector usa cada peso una sola vez (≈ 1 FLOP por byte en FP16); dos matrices cuadradas de lado n, cada número n veces (≈ n ÷ 3 FLOPs por byte en FP16). Se compara con el punto de quiebre de la GPU, su pico de FLOPS ÷ su ancho de banda de memoria: por debajo, el cálculo es memory-bound; por encima, compute-bound. El batching la sube: un peso que se lee una vez se usa para todo el batch.

Analogía. Un cocinero cuyos ingredientes llegan de una bodega: la intensidad es cuántos platillos saca de cada viaje. Si saca uno, espera al ayudante; si saca cien, el ayudante le sobra. Se rompe en que la comida se gasta y un número no: se puede usar las veces que quieras mientras siga en el chip.

Ejemplo. Generar un token de un LLM en BF16: cada peso de 2 bytes se usa en una MAC, 2 FLOPs, así que la intensidad es ≈ 1 FLOP por byte. Multiplicar dos matrices de 4,096 × 4,096 en FP16 son ≈ 137 GFLOPs con ≈ 101 MB de lecturas y escrituras: ≈ 1,365 FLOPs por byte.

Ver en el glosario →

Compute-boundcompute-boundCuando lo que frena un cálculo es la velocidad de los núcleos y no la memoria: los datos llegan a tiempo y el chip calcula a su máximo. Se acelera con menos FLOPs o con más FLOPS.Más

En español, «limitado por el cálculo». Pasa cuando la intensidad aritmética del cálculo es mayor que el punto de quiebre de la GPU: cada byte que llega se usa en tantas operaciones que la memoria alcanza a alimentar a los núcleos. Lo son las multiplicaciones de matrices grandes, el prefill de un LLM, que procesa todo el prompt de una vez, y, en buena parte de sus capas, una CNN con batches moderados. Palancas: menos FLOPs (menos resolución, un modelo más chico), tensor cores de menor precisión (FP16, INT8, FP8) o una GPU con más TFLOPS. Una GPU con más ancho de banda no lo acelera.

Ejemplo. Dos matrices de 4,096 × 4,096 en FP16 en una T4: calcular toma al menos ≈ 2.1 ms (137 GFLOPs ÷ 65 TFLOPS) y mover sus ≈ 101 MB, ≈ 0.3 ms (a 320 GB/s). Manda el cálculo.

Ver en el glosario →

Memory-boundmemory-boundCuando lo que frena un cálculo es cuántos bytes por segundo entrega la memoria: los núcleos esperan datos. Más TFLOPS no lo aceleran; menos bytes o más ancho de banda, sí.Más

En español, «limitado por la memoria». Pasa cuando la intensidad aritmética es menor que el punto de quiebre de la GPU: cada byte se usa en muy pocas operaciones. Es el caso del decode de un LLM con pocas conversaciones (cada token relee todos los pesos), de las operaciones elemento a elemento (una ReLU, sumar un sesgo) y de las capas densas con batch chico. El tiempo mínimo es bytes ÷ ancho de banda de memoria. Palancas: batching (una lectura sirve para varios), menos bytes (cuantizar a INT8 o INT4), fusionar operaciones para no escribir y releer resultados intermedios, o una GPU con más GB/s.

Ejemplo. Un token de Llama 3 8B en una L4: leer sus ≈ 16 GB de pesos a 300 GB/s toma ≈ 54 ms; calcular sus ≈ 16 GFLOPs a 121 TFLOPS, ≈ 0.13 ms. Los núcleos esperan ≈ 400 veces más de lo que trabajan, y el techo es ≈ 19 tokens por segundo.

Ver en el glosario →

Roofline (el modelo del techo)roofline modelUna gráfica que dice qué tan rápido puede ir, como máximo, un cálculo en un chip: el menor entre su pico de FLOPS y su intensidad aritmética × el ancho de banda de memoria.Más

A lo ancho va la intensidad aritmética y a lo alto los FLOPS alcanzables, las dos en escala logarítmica. Tiene dos partes: una rampa, donde lo alcanzable es intensidad × ancho de banda (el cálculo es memory-bound), y un techo plano en el pico de TFLOPS (el cálculo es compute-bound). Se juntan en el punto de quiebre (ridge point): pico ÷ ancho de banda, ≈ 203 FLOPs por byte en una T4. Es una cota: lo real queda debajo. Sirve para saber qué recurso te limita y, por lo tanto, cuál vale la pena comprar o ahorrar. Lo propusieron Williams, Waterman y Patterson en 2009.

Ejemplo. En una T4 (65 TFLOPS y 320 GB/s), un cálculo con intensidad 1 alcanza a lo mucho 1 × 320 GB/s = 0.32 TFLOPS, el 0.5 % del pico; uno con intensidad 1,365 llega al techo de 65 TFLOPS.

Ver en el glosario →

Ancho de banda de memoriamemory bandwidthCuántos bytes por segundo puede mover la memoria de un chip hacia sus núcleos y de regreso. En una GPU se mide en GB/s: 320 en una T4, 300 en una L4 y 3,350 en una H100 SXM.Más

Es la velocidad de la VRAM, no su tamaño: la capacidad dice qué cabe; el ancho de banda, qué tan rápido se lee. Ojo con las unidades: GB/s son gigabytes por segundo, mientras que el ancho de banda de una red se suele dar en Gb/s, gigabits, 8 veces menos. El tiempo mínimo para leer algo es bytes ÷ ancho de banda, y en un cálculo memory-bound ese es el tiempo que manda. Las memorias HBM de las GPUs grandes dan de ≈ 1,555 GB/s (A100 de 40 GB) a 3,350 GB/s (H100 SXM); las GDDR6 de la T4 y la L4, ≈ 300.

Ejemplo. Llama 3 8B en BF16 pesa ≈ 16 GB, y para generar cada token hay que leerlo entero. A 300 GB/s (L4) son ≈ 54 ms por token, un techo de ≈ 19 tokens por segundo; a 3,350 GB/s (H100 SXM), ≈ 210.

Ver en el glosario →

14

Chequeo

Esencial

Check

Intenta responder en tu cabeza antes de abrir cada respuesta.

  1. 1¿Cuántas MACs y cuántos FLOPs cuesta multiplicar una matriz de n × k por una de k × m?Ver respuesta

    n × m × k MACs, porque cada una de las n × m casillas del resultado es un producto punto de k números. Cada MAC es una multiplicación y una suma: 2 × n × m × k FLOPs.

  2. 2¿Qué diferencia hay entre 8.2 GFLOPs y 65 TFLOPS?Ver respuesta

    El primero es una cantidad de trabajo (FLOPs, con s minúscula): lo que pide una foto a la ResNet-50. El segundo es una velocidad (FLOPS, por segundo): lo que hace una T4 como máximo. El primero entre el segundo da el tiempo mínimo, ≈ 0.126 ms.

  3. 3¿Qué es la intensidad aritmética y contra qué se compara?Ver respuesta

    Los FLOPs que hace un cálculo por cada byte que mueve de la memoria. Se compara con el punto de quiebre de la GPU, su pico de FLOPS ÷ su ancho de banda (≈ 203 en una T4): por debajo, memory-bound; por encima, compute-bound.

  4. 4¿Por qué el decode de un LLM es memory-bound, y cuál es su techo de tokens por segundo?Ver respuesta

    Porque cada token usa cada peso una sola vez: 2 FLOPs por cada 2 bytes, intensidad ≈ 1, cientos de veces debajo del quiebre. El techo es ancho de banda ÷ bytes de los pesos: 300 GB/s ÷ 16 GB ≈ 19 tokens por segundo para Llama 3 8B en una L4.

  5. 5¿Por qué el batching sube la intensidad?Ver respuesta

    Porque los pesos se leen una vez y se usan para todo el batch: los FLOPs crecen con el batch y los bytes de los pesos no. Con un batch de b, la intensidad de una capa queda ≈ b, mientras los pesos sean casi todos los bytes.

  6. 6Una T4 anuncia 65 TFLOPS. ¿Por qué C01 usa solo ≈ 15 %, y por qué no es un problema?Ver respuesta

    El pico supone todos los núcleos trabajando sin parar; en la práctica la T4 baja su velocidad a 70 W, no todas las capas usan tensor cores, hay tiempo muerto y algunas capas esperan a la memoria. No es un problema: C01 se dimensiona con lo medido, y aun así sus GPUs trabajan al ≈ 5 % en promedio.

  7. 7¿Una L4 genera tokens más rápido que una T4 porque tiene casi el doble de TFLOPS?Ver respuesta

    No. El decode depende del ancho de banda, y la L4 tiene 300 GB/s contra 320 de la T4. Lo que la L4 sí tiene es más VRAM (24 GB, donde cabe un modelo de 8B en BF16) y BF16, que la T4 no tiene.

Sigue · 16Programa, proceso e hiloLa computadora por dentro Léelo en la RondaM04 · Hardware para inferenciaLo que acabas de leer, con el ojo del entrevistador. ← 14 · Cómo guarda números una computadora