Cuando tu GPU se queda sin VRAM: qué hacer
La VRAM de la GPU es el cuello de botella en cargas de IA y gráficos. Así funcionan la memoria unificada, el offloading de VRAM y el swap en NVMe.

El mensaje de error más común en machine learning no es un traceback de Python ni un error de dimensiones. Es CUDA out of memory. Tu modelo es demasiado grande, el batch size es excesivo o tus activaciones intermedias no caben en la VRAM de tu GPU. Una RTX 4090 tiene 24 GB. Un modelo de 70B parámetros en media precisión necesita unos 140 GB. Las cuentas no cuadran, y gastar más dinero en GPUs más grandes solo aplaza el problema: una H100 con 80 GB tampoco puede alojar los modelos más grandes en una sola tarjeta.
Pero ¿y si pudieras extender la memoria de la GPU de forma transparente usando la RAM del sistema o incluso almacenamiento NVMe? Herramientas como Greenboost de NVIDIA y proyectos similares hacen exactamente eso: usan la jerarquía de memoria (VRAM → RAM del sistema → SSD) para ejecutar cargas que no deberían caber en tu hardware. Los compromisos de rendimiento son reales, pero sorprendentemente manejables en muchos casos de uso. Para entender cómo funciona, primero hay que entender la jerarquía de memoria de la GPU.
Por qué la memoria de la GPU es diferente a la de la CPU
La memoria de la CPU y la de la GPU sirven para patrones de acceso fundamentalmente distintos. Las cargas de CPU son sensibles a la latencia: un solo hilo necesita un dato y se bloquea hasta que llega. Las cachés de la CPU están diseñadas para minimizar la latencia en accesos aleatorios.
Las cargas de GPU son sensibles al throughput: miles de hilos necesitan sus datos, y la GPU puede cambiar entre hilos para ocultar la latencia. La memoria de la GPU (HBM en GPUs de centro de datos, GDDR en tarjetas de consumo) está diseñada para ancho de banda: entregar enormes cantidades de datos por segundo, aunque cada acceso individual tarde más que un acierto en la caché de la CPU.
Memory bandwidth comparison (approximate):
RTX 4090 GDDR6X: 1,000 GB/s
H100 HBM3: 3,350 GB/s
DDR5 System RAM: 50 GB/s
PCIe 5.0 x16: 64 GB/s (theoretical max)
NVMe SSD: 7 GB/s
The bandwidth cliff between VRAM and system RAM is ~20x.
Between VRAM and NVMe it's ~140x.
This is why naive offloading to system RAM kills performance —
you're trying to feed a 1,000 GB/s appetite through a 50 GB/s straw.
Esta brecha de ancho de banda es la razón por la que no basta con hacer la memoria de la GPU 'virtual' (paginar datos a la RAM del sistema como la CPU hace con el disco). Una CPU tolera los fallos de página con quizás una ralentización de 10x. Una GPU que accede a la RAM del sistema en lugar de la VRAM sufre una reducción de ancho de banda de 20x, lo que en cargas limitadas por ancho de banda (la mayoría de la inferencia de ML) significa una ralentización de 20x.
Cómo funciona realmente el offloading de VRAM
El truco no es tratar la RAM del sistema como una VRAM lenta. Consiste en precargar datos de la RAM del sistema a la VRAM antes de que la GPU los necesite, ocultando la latencia detrás del cómputo. Esta es la idea clave detrás de todas las técnicas prácticas de extensión de VRAM.
Durante la inferencia de una red neuronal, el cálculo es secuencial por capas. Mientras la GPU procesa la capa 5, sabe que la capa 6 es la siguiente. Un sistema de offloading inteligente puede empezar a transferir los pesos de la capa 6 desde la RAM del sistema a la VRAM mientras la capa 5 se calcula. Si el cómputo tarda más que la transferencia (algo habitual en capas grandes), la transferencia queda completamente oculta y la GPU nunca se detiene.
# Conceptual overlap of compute and transfer
# (simplified pseudocode)
def inference_with_offloading(model, input_data):
# Only 2 layers fit in VRAM at a time
# Rest are in system RAM
for i, layer in enumerate(model.layers):
# Start async transfer of NEXT layer while computing current
if i + 1 < len(model.layers):
async_transfer_to_gpu(model.layers[i + 1])
# Compute on current layer (GPU is busy, transfer happens in parallel)
output = layer.forward(input_data)
# Evict current layer from VRAM (it's done)
transfer_to_ram(layer)
# Wait for next layer transfer to complete (usually already done)
sync_transfer()
input_data = output
return output
Este enfoque de pipeline funciona bien para la inferencia porque el grafo de cómputo es predecible: sabes exactamente qué pesos se necesitarán después. El entrenamiento es más difícil, porque los backward passes necesitan las activaciones del forward pass, lo que genera patrones de movimiento de datos más complejos.
Los enfoques en la práctica
CUDA Unified Memory
La CUDA Unified Memory de NVIDIA crea un único espacio de direcciones que abarca la VRAM de la GPU y la RAM del sistema. El runtime de CUDA migra páginas automáticamente entre ambas según los patrones de acceso. Cuando la GPU accede a una página en la RAM del sistema, se produce un fallo de página y la página se migra a la VRAM.
La ventaja: es transparente para la aplicación. Tu código CUDA no necesita gestionar la ubicación de los datos. La desventaja: los fallos de página son caros, y las heurísticas de migración del runtime no siempre coinciden con el patrón de acceso de la aplicación. En cargas predecibles, como la inferencia de redes neuronales, la gestión explícita supera a la migración automática.
Offloading capa por capa
Herramientas como Hugging Face Accelerate, DeepSpeed ZeRO-Inference y el flag --mmap de llama.cpp implementan offloading explícito por capas. Mantienen solo las capas activas en la VRAM y transmiten el resto desde la RAM del sistema o el disco. El modelo no necesita caber entero en la VRAM: solo necesita caber una o dos capas a la vez.
Así es como ejecutar modelos de 70B en hardware de consumo funciona realmente. Un modelo de 70B cuantizado a 4 bits necesita unos 40 GB en total, pero cualquier capa individual solo requiere unos 1-2 GB. Con 24 GB de VRAM y prefetching, puedes ejecutar el modelo con un impacto moderado en el rendimiento: quizás entre un 30 y un 50 % más lento que si cupiera entero en la VRAM.
NVMe como memoria extendida
El enfoque más agresivo usa SSDs NVMe como un tercer nivel de memoria para la GPU. El ancho de banda es pésimo comparado con la VRAM (~7 GB/s frente a ~1.000 GB/s), pero la capacidad es prácticamente ilimitada. Un disco NVMe de 4 TB cuesta unos 200 dólares y puede almacenar decenas de modelos grandes a la vez.
Proyectos como Greenboost de NVIDIA implementan esto de forma transparente: el sistema de memoria de la GPU se extiende a NVMe, con prefetching inteligente para minimizar el impacto de la limitación de ancho de banda. En cargas de inferencia donde la GPU dedica un tiempo considerable a calcular (no solo a mover datos), la latencia de NVMe puede ocultarse por completo gracias al solapamiento con el cómputo.
El rendimiento depende mucho de la carga. Las operaciones limitadas por cómputo (grandes multiplicaciones de matrices) ocultan bien la latencia de transferencia. Las operaciones limitadas por memoria (mecanismos de atención con contextos largos) no. En la práctica, el offloading a NVMe funciona mejor para la inferencia por lotes de modelos grandes con batch sizes pequeños, que es exactamente el caso de uso de la inferencia local de LLMs.
La ventaja de la memoria unificada de Apple
La arquitectura de memoria unificada de Apple Silicon toma un camino totalmente distinto: eliminar la distinción entre VRAM y RAM. La CPU y la GPU comparten el mismo pool de memoria física. No hay 'offloading' porque no hay separación: la GPU accede a la misma memoria que usa la CPU.
Esto no elimina el problema del ancho de banda: el de la memoria de los chips M (~400 GB/s en el M4 Max) es inferior al de una GPU dedicada, pero elimina el cuello de botella del PCIe que hace lento el offloading en GPUs discretas. Un Mac con 128 GB de memoria unificada puede alojar un modelo de 70B por completo en memoria accesible por la GPU, sin gastos de offloading.
El compromiso: menor throughput máximo en cargas que caben enteras en la VRAM de una GPU dedicada, pero un rendimiento muchísimo mejor en cargas que no caben. Para la inferencia de modelos grandes, cuando el modelo supera la VRAM de la GPU discreta, Apple Silicon suele ser más rápido que una GPU discreta con offloading, a pesar de tener menos potencia de cómputo bruta.
Qué significa esto para los desarrolladores
Si estás construyendo aplicaciones que usan GPUs (inferencia de ML, gráficos, computación científica), la restricción de VRAM afecta tus decisiones de arquitectura de forma muy concreta.
- Conoce el tamaño de tu working set. Perfila el uso de memoria de la GPU. No la asignación máxima, sino el working set en cada momento. Si tu pico es de 48 GB pero ninguna operación necesita más de 8 GB de datos activos, el offloading funcionará bien. Si una sola operación necesita de verdad 48 GB simultáneamente, necesitas una GPU más grande.
- Elige tu estrategia de offloading según el patrón de acceso. El acceso secuencial (inferencia capa por capa) funciona genial con prefetching. El acceso aleatorio (atención sobre contextos grandes) no. Sabe qué patrón sigue tu carga.
- La cuantización suele ser más barata que el offloading. Pasar tu modelo de FP16 a INT4 reduce la memoria 4 veces con un impacto moderado en la calidad. El offloading a la RAM del sistema añade latencia sin ningún impacto en la calidad, pero con un ahorro de memoria limitado. Primero cuantiza, y después haz offloading.
- El batch size es tu perilla de ajuste. Los lotes grandes necesitan más memoria, pero amortizan mejor la sobrecarga. Los lotes pequeños necesitan menos memoria, pero procesan menos elementos por segundo. Cuando estás cerca del límite de VRAM, reducir el batch size es la solución más sencilla.
- Vigila la fragmentación de memoria. La asignación de memoria de CUDA puede fragmentar la VRAM con el tiempo, sobre todo con entradas de longitud variable. Puede que tengas 8 GB libres en total pero ningún bloque contiguo de 2 GB.
torch.cuda.memory_stats()de PyTorch muestra la fragmentación.torch.cuda.empty_cache()puede ayudar, aunque no es la panacea.
La memoria de la GPU siempre será el cuello de botella en cargas de cómputo a gran escala. Los modelos crecen más rápido que la VRAM. Pero las herramientas para gestionar ese cuello de botella (memoria unificada, offloading inteligente, caché multinivel) están mejorando lo suficiente como para que 'no cabe en la VRAM' ya no sea una barrera infranqueable. Es un compromiso de rendimiento y, cada vez más, uno manejable.


