- Moteur d’inférence LLM basé sur C++/CUDA permettant d’exécuter le modèle Llama 70B sur une RTX 3090 (24 Go de VRAM) grâce au streaming de la mémoire GPU et aux E/S directes NVMe
- Utilise une structure de cache adaptative à 3 niveaux qui répartit automatiquement les données entre la VRAM, la RAM épinglée et NVMe/mmap, avec une accélération allant jusqu’à 83x par rapport à mmap
- Le backend gpu-nvme-direct transfère les données directement du NVMe vers le GPU en contournant totalement le CPU, afin d’exploiter au maximum la bande passante PCIe
- Les fonctions Layer skip et self-speculative decoding réduisent les calculs inutiles et augmentent le débit sans perte de qualité
- Rend possible l’exécution efficace de très grands modèles sur du matériel grand public, ouvrant la voie à une meilleure accessibilité de l’inférence LLM haute performance
Présentation de NTransformer
- Moteur d’inférence LLM C++/CUDA à haut rendement, capable d’exécuter le modèle Llama 70B sur une RTX 3090 (24 Go de VRAM)
- Streame les couches du modèle via la mémoire GPU et peut, en option, utiliser les E/S directes NVMe pour contourner complètement le CPU
- Aucune dépendance externe en dehors du CUDA Toolkit, sans besoin de PyTorch ni de cuBLAS
- Prend en charge le format de modèle GGUF avec les formats de quantification Q4_0, Q8_0, Q4_K_M, Q5_K, Q6_K, F16 et F32
Performances et structure de cache
- Cache adaptatif à 3 niveaux (3-Tier Adaptive Caching)
- Couches résidentes en VRAM (0 E/S)
- RAM épinglée (dédiée aux transferts H2D)
- Repli sur NVMe/mmap
- Dans un environnement RTX 3090 + 48 Go de RAM, jusqu’à 83x plus rapide que mmap
- La bande passante PCIe Gen3 x8 (environ 6,5 Go/s) constitue le goulot d’étranglement
- La quantification Q4_K_M permet de charger 10 couches supplémentaires en VRAM (36 contre 26), réduisant ainsi le volume des transferts
- Le Layer skip (basé sur la similarité cosinus) saute 20 couches sur 80 avec une perte de qualité minimale
Fonctionnalités principales
- Streaming SLEP : superposition des lectures NVMe, du DMA PCIe et des calculs GPU avec double buffering
- Backend gpu-nvme-direct : lecture directe des données NVMe dans une mémoire épinglée accessible au GPU
- Self-speculative decoding : réutilise les couches résidentes en VRAM comme modèle brouillon, sans modèle supplémentaire
- Sélection automatique du chemin de données : résident en VRAM > H2D via RAM épinglée > mmap épinglé >
memcpy CPU
- Prise en charge de l’architecture Llama : RoPE, GQA, SwiGLU, RMSNorm et cache KV
Exigences système
- Linux (Ubuntu, kernel 6.17+), CUDA Toolkit 13.1, gcc/g++ 14, CMake 3.24+
- GPU Compute Capability 8.0+ (RTX 3090 testée)
- Pour les E/S directes NVMe, un SSD NVMe sur un slot PCIe distinct et la bibliothèque gpu-nvme-direct sont nécessaires
Streaming direct NVMe
- Si le modèle ne tient pas en VRAM, le chemin direct NVMe → GPU élimine totalement le CPU
- Flux de données : SSD NVMe → DMA → mémoire de staging épinglée → PCIe H2D → tampon GPU → calcul
- Le NVMe est lié à VFIO pour un accès direct en espace utilisateur
- Chaque couche (environ 670 Mo pour 70B Q6_K) est lue en environ 202 ms via 670 commandes NVMe
- Les lectures NVMe, le DMA H2D et les calculs GPU sont traités en parallèle dans un pipeline à double buffer
Configuration système et avertissements sur les risques
- Le script de configuration automatique (
setup_system.sh) configure successivement GRUB, NVIDIA DKMS, les en-têtes CUDA, VFIO et le binding NVMe
- Comprend des opérations à haut risque comme la désactivation de l’IOMMU, le patch de modules noyau et le binding NVMe à VFIO
- Une mauvaise configuration peut entraîner un échec de démarrage, une perte de données NVMe ou une instabilité du système
- Ne jamais utiliser le disque de démarrage, un périphérique NVMe dédié distinct est requis
- Des scripts de sauvegarde et de restauration sont fournis pour tous les changements
Architecture et structure du code
- Composants principaux dans le répertoire
src/
core/ : tenseurs, allocation mémoire, gestion des périphériques GPU
cuda/ : noyaux GEMV, RMSNorm, RoPE, SwiGLU, softmax
memory/ : moteur de streaming SLEP basé sur NVMe et mmap
model/ : composition du Transformer, chargeur GGUF, attention, FFN, normalisation
inference/ : tokenizer, sampler, moteur
scripts/ : comprend les scripts de configuration système, de binding NVMe et de restauration
Feuille de route du développement
- Étape 1 : Llama 8B Q8_0, noyaux CUDA personnalisés, 48,9 tok/s (terminé)
- Étape 2 : streaming SLEP, exécution de 70B sur un seul GPU, accélération 33x (terminé)
- Étape 3 : prise en charge de Q4_K_M/Q5_K, Layer skip, self-speculative decoding, cache KV F16 (terminé)
- Étape 4 : backend NVMe Direct, lecture NVMe pilotée par le GPU à 3,35 Go/s (terminé)
- Étape 5 : optimisation de l’inférence et API C publique (prévu)
Licence
- Sous licence BSD-2-Clause
1 commentaires
Commentaires Hacker News
Je trouve vraiment ingénieuse l’idée de transférer directement de la NVMe vers le GPU en contournant le CPU
Pour faire tourner de gros modèles en local, le goulot d’étranglement a toujours été la hiérarchie mémoire ; ici, c’est comme traiter la NVMe comme une VRAM étendue via un accès DMA direct
Je me demande comment cela se comparerait à l’approche mémoire unifiée (unified memory) des Apple M series. Le M4 Max peut charger entièrement un modèle 70B en mémoire, mais son débit reste inférieur à celui d’une 3090
Ce serait intéressant d’avoir un benchmark comparant les performances natives d’une 3090 avec approche NVMe et d’un M4 Max en inférence par lots (batch inference)
Avec GPUdirect, on peut faire du DMA direct vers le périphérique de stockage
Je me demande ce qui se passerait si le stockage m.2 était en réalité de la DRAM. Lorsqu’on fait du spilling de modèle depuis le GPU, on n’a pas besoin de persistance, ce qui permettrait de garder la RAM système pour le CPU
Une vitesse de 0,2 token/s est lente pour du chat, mais suffisante pour des tâches par lots / asynchrones
Je fais tourner un pipeline de génération automatique de contenu, avec plusieurs appels LLM en parallèle. La génération d’images est le goulot d’étranglement, donc l’ensemble prend de toute façon environ 20 minutes
Si je pouvais faire tourner un modèle 70B en local, j’économiserais le coût des tokens API, ce qui représenterait une grosse réduction de coûts
0,2 tok/s, c’est acceptable pour de l’expérimentation, mais insuffisant pour un usage interactif
Dans la plupart des cas, un modèle 8B ou 13B bien quantifié offre un meilleur compromis latence-qualité
C’est une expérience vraiment intéressante. J’aurais dû essayer ça en premier moi aussi
Je suis curieux de connaître les chiffres réels de throughput par rapport à la bande passante théorique du PCIe. J’aimerais savoir si le problème vient de la latence ou de la bande passante
C’est un hack impressionnant, mais 0,5 tok/s sur un modèle 70B reste lent comparé aux 30+ tok/s qu’on obtient sur la même carte avec un modèle 7B
Selon la recherche de NVIDIA, des modèles de 10B ou moins peuvent déjà traiter 40 à 70 % des tâches d’agent, et l’écart de qualité se réduit rapidement
Ce domaine vaut vraiment la peine d’être exploré davantage
À long terme, l’essentiel sera sans doute l’optimisation des modèles, c’est-à-dire la recherche des parties du modèle qu’on peut omettre sans impact sur les performances. Après tout, un modèle est aussi une forme de compression avec perte (lossy compression). Cette direction pourrait aussi aider à la démocratisation de l’IA
Projet vraiment très cool. Je me demande quel bagage en systèmes / matériel il faut pour avoir ce genre d’idée
Je travaille dans des environnements où le matériel est très abstrait, donc il m’est difficile d’imaginer ce type d’approche. Cela semble demander non seulement de la créativité, mais aussi une compréhension au niveau système
En essayant d’exécuter un LLM sur PS2, je me suis heurté aux limites de 32 Mo de RAM et 4 Mo de VRAM, ce qui m’a conduit à concevoir une approche de streaming des couches. La PS2 pouvait traiter directement des adresses 32 bits en VRAM, ce qui la rendait très rapide, et j’ai essayé de reproduire cela sur PC
J’essaie quelque chose de similaire moi aussi. Je teste l’exécution d’un modèle 1T avec moins de la moitié de la VRAM
En modifiant la couche de routage de SGLang, je pense pouvoir implémenter un swap d’experts basé sur une prédiction JIT entre une NVMe Gen5 et la mémoire GPU. J’utilise NVIDIA Dynamo et les primitives NIXL
Je me demande si quelqu’un l’a déjà tenté
Super projet. J’aimerais avoir plus de détails sur le processus de patch DKMS avec une carte GPU grand public. J’aimerais essayer moi aussi
Liens associés : RTX4090 P2P Unlock, vGPU Unlock