El problema fundamental que Hypura aborda es la limitación de memoria en hardware de consumo para la inferencia de modelos de lenguaje grandes (LLMs), especialmente en plataformas con memoria unificada y NVMe rápido pero de capacidad limitada, como Apple Silicon. Tradicionalmente, cuando un modelo excede la RAM física, el sistema operativo recurre al swapping, lo que degrada drásticamente el rendimiento y a menudo conduce a fallos por Out-Of-Memory (OOM). Hypura resuelve esto al tratar el almacenamiento NVMe no como un simple disco de swap, sino como un nivel de memoria explícitamente gestionado, permitiendo la ejecución de modelos que de otro modo serían inviables.
La relevancia de esta solución radica en la democratización del acceso a LLMs de gran escala. Al permitir que modelos de decenas de gigabytes se ejecuten en máquinas de consumo con 32GB o 64GB de RAM, Hypura reduce la barrera de entrada para desarrolladores e investigadores que no tienen acceso a hardware de servidor con grandes cantidades de VRAM. Esto es particularmente importante en un contexto donde los LLMs continúan creciendo en tamaño y complejidad, y la inferencia en el 'edge' o en dispositivos personales se vuelve cada vez más deseable.
Arquitectura del Sistema
Hypura opera como un scheduler de inferencia que realiza un perfilado inicial del hardware (GPU, RAM, ancho de banda NVMe) y luego resuelve un problema de optimización para asignar cada tensor del modelo a un nivel de memoria específico: GPU (Metal), RAM o NVMe. Los tensores críticos para la latencia, como las capas de atención, normas y embeddings, se fijan en la GPU. Las capas que no caben en el 'working set' de la GPU se desbordan a la RAM vía mmap. Los tensores restantes se cargan bajo demanda desde NVMe utilizando I/O directo (F_NOCACHE + pread) y prefetching.
Para modelos MoE (Mixtral), Hypura implementa un modo 'expert-streaming'. Solo los tensores no-expertos (~1GB) residen en la GPU. Los tensores de los expertos se transmiten desde NVMe a través de un 'pool buffer' dinámico. Un 'neuron cache' rastrea las porciones de expertos cargadas, logrando una tasa de aciertos del 99.5% debido a la localidad temporal. La intercepción del router identifica los expertos seleccionados en el 'eval callback', cargando solo los 'strides' necesarios de NVMe, lo que resulta en una reducción del 75% de I/O. Para modelos densos grandes (Llama 70B), se utiliza el modo 'dense FFN-streaming', donde las capas de atención y normas permanecen en la GPU (~8GB), mientras que los tensores FFN (~32GB) se transmiten desde NVMe a través de un 'pool buffer' con 'prefetch lookahead' escalado automáticamente. El tamaño del 'pool buffer', la profundidad del 'prefetch' y los presupuestos de memoria se calculan automáticamente a partir del perfil de hardware.
Flujo de Inferencia con Expert-Streaming (MoE)
- 1 Carga Inicial Tensores no-expertos (normas, embeddings) se cargan y fijan en la GPU.
- 2 Generación de Token Se inicia el proceso de inferencia para un nuevo token.
- 3 Intercepción de Router El 'eval callback' identifica los expertos MoE seleccionados por el router.
- 4 Consulta Neuron Cache Se verifica si los 'strides' de los expertos necesarios están en el cache de ...
- 5 Carga de NVMe (Miss) Si no están en cache, los 'strides' de expertos se cargan bajo demanda desde ...
- 6 Prefetch Especulativo Se predicen y precargan expertos para el siguiente token basándose en co-acti...
- 7 Cálculo en GPU Los tensores cargados y residentes se utilizan para el cálculo en la GPU.
- 8 Actualización Cache Los expertos utilizados se añaden/actualizan en el cache de neuronas.
| Capa | Tecnología | Justificación |
|---|---|---|
| compute | Apple Metal | Framework de bajo nivel para acceso directo a la GPU y memoria unificada, crucial para el rendimiento de inferencia. recommendedMaxWorkingSetSize para determinar la capacidad de GPU. |
| storage | NVMe (Direct I/O) | Utilizado como un nivel de memoria de 'cold storage' para tensores que no caben en RAM/GPU, con acceso directo (F_NOCACHE + pread) para evitar el cache del OS. Uso de F_NOCACHE y pread para I/O sin cache. |
| storage | mmap | Para mapear tensores a la RAM, permitiendo acceso eficiente a datos que desbordan la GPU pero aún caben en la memoria principal. |
| orchestration | Rust | Lenguaje de programación principal para la lógica del scheduler, gestión de memoria y bindings FFI, elegido por su seguridad de memoria y rendimiento. Rust 1.75+ |
| compute | llama.cpp (vendored) | Backend de inferencia subyacente, modificado con un tipo de buffer GGML personalizado para la gestión de tensores en Hypura. |
| messaging | Ollama-compatible HTTP API | Proporciona una interfaz estándar para la interacción con LLMs, permitiendo a Hypura actuar como un reemplazo directo para herramientas existentes. /api/generate, /api/chat con streaming NDJSON. |
Trade-offs
Ganancias
- ▲ Capacidad de ejecutar modelos LLM grandes
- ▲▲ Estabilidad del sistema (evita OOM)
- ▲ Eficiencia de I/O para MoE
Costes
- ▲ Rendimiento (tok/s) para modelos que no caben en RAM/GPU
- △ Complejidad de la gestión de memoria
hypura-sys — FFI bindings to llama.cpp (vendored at vendor/llama.cpp/, built via CMake).compute/nvme_backend.rs — Custom GGML buffer type, pool-based expert/FFN streaming, neuron cache, eval callbackFundamentos Teóricos
El concepto de tiering de memoria y la gestión explícita de la jerarquía de memoria no es nuevo, y tiene raíces en la investigación de sistemas operativos y bases de datos. Principios como la 'localidad de referencia' (temporal y espacial) son fundamentales para el diseño de cachés y la optimización del rendimiento de la memoria, como se describe en trabajos clásicos sobre jerarquías de memoria y algoritmos de reemplazo de caché. La idea de mover datos entre diferentes niveles de almacenamiento basándose en patrones de acceso y costos de ancho de banda se asemeja a las estrategias de gestión de memoria virtual y paginación, pero con una capa de aplicación consciente del contenido (la arquitectura del LLM).
La optimización de la colocación de tensores puede verse como una instancia del problema de 'bin packing' o 'knapsack problem' con restricciones de rendimiento, un área bien estudiada en optimización combinatoria. La explotación de la escasez en modelos MoE para reducir I/O y el uso de un 'neuron cache' son aplicaciones directas de principios de caché y prefetching, similares a los utilizados en sistemas de archivos y bases de datos para mejorar el rendimiento de I/O, como se detalla en trabajos sobre 'buffer management' y 'query optimization' en sistemas de bases de datos (ej., 'The Five-Minute Rule for Trading Memory for Disk Accesses' de Gray y Putzolu, 1987, aunque en un contexto diferente, ilustra la lógica de costo-beneficio).