- Motor de inferencia LLM basado en C++/CUDA que puede ejecutar el modelo Llama 70B en una RTX 3090 (24 GB de VRAM) mediante streaming de memoria de GPU y E/S directa desde NVMe
- Usa una estructura de caché adaptativa de 3 niveles para dividir automáticamente entre VRAM, RAM fijada y NVMe/mmap, logrando una mejora de velocidad de hasta 83 veces frente a mmap
- El backend gpu-nvme-direct omite por completo la CPU y transfiere datos directamente de NVMe a la GPU, aprovechando al máximo el ancho de banda de PCIe
- Las funciones Layer skip y self-speculative decoding reducen cálculos innecesarios y aumentan la velocidad de procesamiento sin pérdida de calidad
- Permite ejecutar de forma eficiente modelos enormes en hardware de consumo, mostrando el potencial de ampliar el acceso a la inferencia LLM de alto rendimiento
Descripción general de NTransformer
- Motor de inferencia LLM C++/CUDA de alta eficiencia que ejecuta el modelo Llama 70B en una RTX 3090 (24 GB de VRAM)
- Hace streaming de las capas del modelo a través de la memoria de GPU y, opcionalmente, usa E/S directa desde NVMe para omitir por completo la CPU
- Sin dependencias externas aparte de CUDA Toolkit; no requiere PyTorch ni cuBLAS
- Compatible con el formato de modelos GGUF y con las cuantizaciones Q4_0, Q8_0, Q4_K_M, Q5_K, Q6_K, F16 y F32
Rendimiento y estructura de caché
- Caché adaptativa de 3 niveles (3-Tier Adaptive Caching)
- Capas residentes en VRAM (0 E/S)
- RAM fijada (solo para transferencia H2D)
- Respaldo en NVMe/mmap
- En un entorno con RTX 3090 + 48 GB de RAM, logra una mejora de velocidad de 83 veces frente a mmap
- El ancho de banda de PCIe Gen3 x8 (aprox. 6.5 GB/s) actúa como cuello de botella
- La cuantización Q4_K_M carga 10 capas más en VRAM (36 vs 26), reduciendo el volumen de transferencia
- Con Layer skip (basado en similitud coseno), omite 20 de 80 capas con una pérdida mínima de calidad
Funciones principales
- Streaming SLEP: superpone lecturas NVMe, DMA por PCIe y cómputo en GPU con doble búfer
- Backend gpu-nvme-direct: lee datos de NVMe directamente a memoria fijada accesible para la GPU
- Self-speculative decoding: usa las capas residentes en VRAM como modelo borrador, sin necesidad de un modelo adicional
- Selección automática de ruta de datos: residente en VRAM > RAM fijada H2D > mmap fijado > memcpy de CPU
- Compatibilidad con la arquitectura Llama: incluye RoPE, GQA, SwiGLU, RMSNorm y caché KV
Requisitos del sistema
- Linux (Ubuntu, kernel 6.17+), CUDA Toolkit 13.1, gcc/g++ 14, CMake 3.24+
- GPU con Compute Capability 8.0+ (probado en RTX 3090)
- Para usar E/S directa desde NVMe, se requiere un SSD NVMe en una ranura PCIe separada y la biblioteca gpu-nvme-direct
Streaming directo desde NVMe
- Si el modelo no cabe en VRAM, utiliza una ruta directa NVMe → GPU que excluye por completo a la CPU
- Flujo de datos: SSD NVMe → DMA → memoria de staging fijada → PCIe H2D → búfer de GPU → cómputo
- Vincula el NVMe a VFIO para acceso directo desde espacio de usuario
- Cada capa (aprox. 670 MB en 70B Q6_K) se lee en unos 202 ms mediante 670 comandos NVMe
- La lectura NVMe, el DMA H2D y el cómputo en GPU se procesan en paralelo en una tubería de doble búfer
Configuración del sistema y advertencias de riesgo
- El script de configuración automática (
setup_system.sh) configura en secuencia GRUB, NVIDIA DKMS, encabezados de CUDA, VFIO y el binding de NVMe
- Incluye tareas de alto riesgo como desactivar IOMMU, parchear módulos del kernel y vincular NVMe a VFIO
- Una configuración incorrecta puede causar fallos de arranque, pérdida de datos en NVMe e inestabilidad del sistema
- Nunca usar la unidad de arranque; se requiere un dispositivo NVMe dedicado aparte
- Se proporcionan scripts de respaldo y restauración para todos los cambios
Arquitectura y estructura del código
- Componentes principales dentro del directorio
src/
core/: tensores, asignación de memoria y gestión de dispositivos GPU
cuda/: kernels de GEMV, RMSNorm, RoPE, SwiGLU y softmax
memory/: motor de streaming SLEP basado en NVMe y mmap
model/: configuración del Transformer, cargador GGUF, attention, FFN y normalization
inference/: tokenizador, sampler y motor
scripts/: incluye scripts de configuración del sistema, binding de NVMe y restauración
Hoja de ruta de desarrollo
- Fase 1: Llama 8B Q8_0, kernels CUDA personalizados, 48.9 tok/s (completado)
- Fase 2: streaming SLEP, ejecución de 70B en una sola GPU, mejora de velocidad de 33 veces (completado)
- Fase 3: compatibilidad con Q4_K_M/Q5_K, Layer skip, self-speculative decoding, caché KV en F16 (completado)
- Fase 4: backend NVMe Direct, lectura NVMe dirigida por GPU a 3.35 GB/s (completado)
- Fase 5: optimización de inferencia y API C pública (pendiente)
Licencia
1 comentarios
Comentarios en Hacker News
Me parece muy ingeniosa la forma de transferir directamente de NVMe al GPU evitando la CPU
Al ejecutar modelos grandes en local, el cuello de botella siempre ha sido la jerarquía de memoria, y esto equivale a tratar el NVMe como si fuera VRAM extendida mediante DMA directo
Me pregunto cómo se compararía con el enfoque de memoria unificada (unified memory) de los Apple M series. El M4 Max puede cargar por completo un modelo de 70B en memoria, pero su rendimiento es menor que el de una 3090
Sería interesante ver benchmarks comparando el rendimiento nativo de una 3090 usando este enfoque con NVMe frente a un M4 Max, tomando como base la inferencia por lotes (batch inference)
Con GPUdirect es posible hacer transferencia DMA directa hacia dispositivos de almacenamiento
Me hizo pensar: ¿y si el almacenamiento m.2 fuera realmente DRAM? Como al hacer spill del modelo desde el GPU no hace falta persistencia, se podría dejar la RAM del sistema para la CPU
Una velocidad de 0.2 tokens por segundo es lenta para chat, pero suficiente para trabajos por lotes/asíncronos
Yo ejecuto pipelines automáticos de generación de contenido, con varias llamadas a LLM en paralelo. La generación de imágenes es el cuello de botella, así que de todos modos el trabajo completo tarda como 20 minutos
Si pudiera ejecutar un modelo de 70B en local, me ahorraría el costo de los tokens de API, así que sería un gran ahorro de costos
0.2 tok/s está bien para experimentar, pero no alcanza para un uso interactivo
En la mayoría de los casos, un modelo 8B o 13B bien cuantizado ofrece un mejor equilibrio entre latencia y calidad
Es un experimento realmente interesante. Yo también debí haber intentado algo así antes
Me da curiosidad el valor real de throughput frente al ancho de banda teórico de PCIe. Quisiera saber si es un problema de latencia o de ancho de banda
Es un hack genial, pero 0.5 tok/s con un modelo 70B es lento comparado con los 30+ tok/s que da un modelo 7B en la misma tarjeta
Según investigaciones de NVIDIA, incluso los modelos de 10B o menos pueden encargarse de 40 a 70% de las tareas de agentes, y la brecha de calidad también se está reduciendo rápidamente
Este campo vale mucho la pena para seguir experimentando
A largo plazo, parece que lo clave será la optimización de modelos, es decir, investigar qué partes del modelo pueden omitirse sin afectar el rendimiento. Después de todo, un modelo también es una especie de estructura de compresión con pérdida (lossy compression). Ir en esa dirección también ayudaría a la democratización de la IA
Es un proyecto realmente genial. Me pregunto qué tipo de conocimientos de sistemas/hardware se necesitan para concebir una idea así
Yo trabajo en entornos donde el hardware está muy abstraído, así que me cuesta imaginar este tipo de enfoque. Parece que no solo hace falta creatividad, sino también comprensión a nivel de sistema
Intenté ejecutar un LLM en una PS2, pero choqué con los límites de 32 MB de RAM y 4 MB de VRAM, así que ideé un método de streaming de capas. La PS2 podía manejar direcciones de 32 bits directamente en la VRAM, así que era muy rápida, y quise intentar reproducir eso en PC
Yo también estoy intentando algo parecido. Estoy experimentando con ejecutar un modelo 1T usando menos de la mitad de la VRAM
Creo que, modificando la capa de enrutamiento de SGLang, se podría implementar expert swap basado en predicción JIT desde Gen5 NVMe hacia la memoria del GPU. Usaría primitivas de NVIDIA Dynamo y NIXL
Me pregunto si alguien ya intentó algo así
Gran proyecto. Me gustaría saber un poco más sobre el proceso de parcheo DKMS en GPU comunes. Yo también quiero intentarlo
Enlaces relacionados: RTX4090 P2P Unlock, vGPU Unlock