3 points par GN⁺ 2026-03-25 | 1 commentaires | Partager sur WhatsApp
  • Optimise le placement des tenseurs entre GPU, RAM et NVMe pour exécuter de grands modèles de langage grâce à un ordonnanceur d’inférence conscient de la hiérarchie de stockage
  • Permet d’exécuter sur un Mac Mini 32 Go le modèle Mixtral 8x7B (31GB) à 2.2 tok/s et le modèle Llama 70B (40GB) à 0.3 tok/s
  • Analyse les schémas d’accès et la bande passante matérielle pour faire tourner de manière stable même des modèles dépassant la mémoire physique, y compris des modèles que llama.cpp ne pouvait pas traiter à cause d’un OOM
  • Grâce au routage des experts pour l’architecture MoE, au cache de neurones et au prefetch, réduit les E/S jusqu’à 75 % et atteint un taux de cache hit de 99.5 %
  • Sélectionne automatiquement les modes Full-resident, Expert-streaming et Dense FFN-streaming selon la taille du modèle et le matériel afin de maintenir les meilleures performances
  • Fournit une API HTTP compatible Ollama, intégrable avec OpenClaw et autres outils, et utilise le SSD en lecture seule pour permettre une inférence sur NVMe sans dégradation de durée de vie

Vue d’ensemble

  • Hypura est un ordonnanceur d’inférence LLM conscient de la hiérarchie de stockage pour Apple Silicon, un outil qui effectue une optimisation du placement des tenseurs entre GPU, RAM et NVMe
  • En répartissant les tenseurs selon les schémas d’accès, le coût en bande passante et les performances matérielles, il permet d’exécuter de façon stable de grands modèles dépassant la mémoire physique
  • Sur un Mac Mini 32 Go, il permet d’exécuter Mixtral 8x7B (31GB) à 2.2 tok/s et Llama 70B (40GB) à 0.3 tok/s
  • Dans le même environnement, llama.cpp ne peut pas s’exécuter à cause d’un OOM (Out of Memory)

Contexte du problème

  • Les Mac grand public disposent d’une mémoire unifiée rapide et d’un stockage NVMe, mais leur capacité mémoire reste limitée
  • Par exemple, un M1 Max 32 Go ne peut pas charger directement un modèle de 40 Go, ce qui provoque un swap excessif et une fin d’exécution par OOM
  • Hypura résout ce problème en analysant la structure du modèle pour effectuer un placement optimal par couche

Placement par couche fondé sur la structure du modèle

  • Norms et Embeddings : petits, mais consultés à chaque token, donc fixés sur le GPU
  • Routage des experts MoE : exploite la parcimonie, avec seulement 2 experts actifs sur 8 par token
    • Intercepte le routeur pour identifier les experts actifs, puis charge depuis le NVMe uniquement les parties nécessaires
    • Réduction des E/S de 75 % et taux de hit du cache de neurones de 99.5 %
    • Effectue un prefetch anticipé des prochains experts actifs via le suivi de co-activation (co-activation tracking)
  • Poids FFN denses : représentent environ 60 % de la taille du modèle
    • Streaming depuis le NVMe via un pool de buffers dynamique
    • La profondeur d’anticipation du prefetch (prefetch lookahead depth) est ajustée automatiquement selon la mémoire disponible
  • Résultat : des modèles qui plantaient avec l’approche mmap classique peuvent désormais être exécutés, tandis que les modèles tenant en mémoire fonctionnent à la vitesse du GPU Metal sans surcoût

Fonctionnement

  • Hypura lit les fichiers GGUF et profile la bande passante GPU, RAM et NVMe
  • Chaque tenseur est placé dans l’une des trois couches suivantes
    • GPU (Metal) : couches Attention, Norm et Embedding
    • RAM : couches de débordement qui ne peuvent pas être chargées sur le GPU
    • NVMe : couches restantes, avec E/S directes via F_NOCACHE + pread
  • Sélectionne automatiquement le mode d’inférence selon la taille du modèle et le matériel
    • Full-resident : charge l’ensemble du modèle en GPU+RAM, sans E/S NVMe
    • Expert-streaming : pour les modèles MoE, seuls les tenseurs non experts résident sur le GPU, les tenseurs experts sont streamés depuis le NVMe
    • Dense FFN-streaming : pour les grands modèles non-MoE, Attention+Norm sur le GPU, FFN streamé depuis le NVMe
  • La taille du pool de buffers, la profondeur de prefetch et le budget mémoire sont calculés automatiquement selon le profil matériel

Performances

  • Environnement de test : M1 Max, 32 Go de mémoire unifiée, NVMe 5.1GB/s
  • Principaux résultats de benchmark
    • Qwen 2.5 14B Q4_K_M (8.4GB) : entièrement chargé sur le GPU, 21 tok/s
    • Mixtral 8x7B Q5_K_M (30.9GB) : mode Expert-streaming, 2.2 tok/s, 99.5 % de taux de hit du cache
    • Llama 3.3 70B Q4_K_M (39.6GB) : mode Dense FFN-streaming, pool de 24 slots, prefetch sur 7 couches, 0.3 tok/s
  • Les modèles qui tiennent en mémoire ont 0 surcoût, et les modèles plus volumineux restent exécutables grâce à Hypura

Installation et exécution

  • Rust 1.75+ et CMake requis
  • Procédure d’installation
    git clone --recurse-submodules https://github.com/hypura/hypura.git  
    cd hypura  
    cargo build --release  
    
  • Exemples d’exécution
    hypura profile  
    hypura run ./model.gguf --prompt "Hello, world"  
    hypura run ./model.gguf --interactive  
    hypura bench ./model.gguf  
    hypura inspect ./model.gguf  
    
  • Pour les modèles non vérifiés, il est recommandé de tester avec --max-tokens 10

Serveur compatible Ollama

  • Hypura fournit une API HTTP compatible Ollama, entièrement compatible avec OpenClaw et les autres outils basés sur Ollama
    hypura serve ./model.gguf  
    
    Endpoint: http://127.0.0.1:8080  
    
    API: /api/generate, /api/chat, /api/tags  
    
  • Principaux endpoints
    Endpoint Fonction
    GET / Vérification de l’état
    GET /api/tags Liste des modèles chargés
    GET /api/version Version du serveur
    POST /api/show Métadonnées du modèle
    POST /api/generate Génération de texte
    POST /api/chat Génération conversationnelle
  • Pour l’intégration avec OpenClaw, définissez l’URL de base Ollama sur Hypura dans ~/.openclaw/openclaw.json
  • Options du serveur
    hypura serve  [OPTIONS]  
    --host    défaut 127.0.0.1  
    --port    défaut 8080  
    --context    défaut 4096  
    

Architecture

  • Structure en workspace Cargo, composée de deux crates
    • hypura : binaire principal et bibliothèque
    • hypura-sys : bindings FFI pour llama.cpp (build CMake)
  • Principaux modules
    Module Rôle
    scheduler/placement.rs Optimisation du placement des tenseurs entre GPU/RAM/NVMe
    compute/inference.rs Moteur d’inférence et fonctions de chargement/génération pour le serveur
    compute/nvme_backend.rs Streaming NVMe, cache de neurones, callback d’évaluation
    server/routes.rs Handlers HTTP compatibles Ollama
    profiler/ Profilage matériel
    cli/bench.rs Outil de benchmark
    model/tensor_role.rs Classification du rôle des tenseurs

FAQ

  • Aucun problème de durée de vie du SSD

    • Hypura ne fait que lire sur le SSD, sans écriture
    • Les E/S NVMe sont effectuées en lecture seule via pread() + F_NOCACHE
    • Le SSD ne sert que de stockage à froid, les calculs étant réalisés en RAM/GPU
    • Les écritures se limitent à un niveau négligeable de quelques Ko, comme les résultats JSON des benchmarks ou les fichiers de statistiques

Consignes de sécurité

  • Si le modèle dépasse la limite de RAM (avec 4 Go de marge), bench --baseline est bloqué
  • Pour les modèles non vérifiés, tester avec --max-tokens 10
  • Les modèles de test sont stockés dans le répertoire ./test-models/

Licence

  • MIT License

Avis éthique

  • Le code du dépôt n’a pas été entièrement écrit directement par son auteur
  • Il a été produit dans le cadre d’une expérience de génération de code guidée par instructions avec un LLM
  • Il s’agit d’un projet visant à explorer le potentiel de l’inférence fondée sur le NVMe

1 commentaires

 
GN⁺ 2026-03-25
Commentaires sur Hacker News
  • J’aimerais le suggérer au mainteneur. Le tableau comparatif inclut actuellement des modèles anciens comme Qwen 2.5 14B, Mixtral 8x7B et Llama 3.3 70B
    Récemment, de nombreux retours indiquent que les modèles Qwen 3.5 MoE affichent des performances remarquables sur le matériel Apple
    Il serait utile de consulter l’article de Simon Willison
    Si possible, ce serait bien d’ajouter aussi au tableau le modèle Kimi K2.5 (1T paramètres)
    Tweets associés : seikixtc, danpacary

    • Merci pour le partage. Si jamais vous êtes prêt à lancer directement des benchmarks avec Hypura, j’agrégerai les résultats dans les statistiques. Sinon, je l’ajouterai à ma todo list
    • Simon, c’est un peu hors sujet, mais votre site a été down pendant un moment
      Un message d’erreur lié à Heroku s’affichait, mais tout fonctionne de nouveau maintenant
      J’y étais allé pour lire cet article, et j’ai vu que vous aviez déjà publié aussi un billet sur litellm. Lecture très intéressante
    • C’est dommage que la métrique de vitesse des tokens manque dans l’exemple Kimi
  • En local, même une vitesse inférieure à 1 token par seconde peut être tout à fait exploitable s’il s’agit d’un travail en arrière-plan
    La différence entre « terminé immédiatement » et « terminé dans la nuit » reste malgré tout un saut de performance significatif

  • En pratique, ce qui compte, c’est à quel point le schéma de lecture est séquentiel
    Le NVMe atteint 5 à 7 Go/s en lecture séquentielle, mais tombe autour de 500 Mo/s en lecture aléatoire
    Pour un modèle 1T, il faut streamer 2 To par forward pass en fp16, donc en théorie cela prend plus de 300 secondes par token
    Ce n’est pas adapté à l’interactif, mais cela peut avoir du potentiel pour la batch inference

    • Sur un M1 Max, la lecture aléatoire 4K (QD=1) tourne autour de 65 Mo/s
    • D’accord. C’est plus proche d’une POC (Proof of Concept) que de quelque chose de pratique
      Mais avec de petits modèles MoE, on peut générer plusieurs tokens par seconde, ce qui le rend réellement exploitable
    • L’essentiel des modèles MoE, c’est l’activation sparse
      On ne lit pas la totalité des 2 To, on n’accède qu’à une partie des couches d’experts
      Chaque couche ne fait que quelques Mio, donc l’efficacité d’accès NVMe n’est pas si mauvaise
  • Je me demandais d’où sortait ce « modèle à 1T paramètres ». Dans le dépôt, je ne vois que des modèles de 70B ou moins

    • C’était mentionné pour illustrer une possibilité. Mais les performances sont trop lentes pour être pratiques en dehors de tâches longues très spécifiques
      Les modèles réalistes sont plutôt de petits MoE capables de générer plusieurs tokens par seconde
    • Le titre semble un peu exagéré. Au final, ce qui compte, c’est la vitesse, et il n’y a aucune information là-dessus
  • Le point clé du MoE, c’est justement qu’avec l’activation sparse, on ne lit pas les 2 To entiers
    Mais le schéma d’accès devient randomisé, ce qui est la pire condition possible pour du NVMe
    Pour des tâches où la latence est importante, comme l’inférence d’agents, c’est l’élément central

  • On dirait qu’Intel Optane s’agite dans sa tombe

    • Les memristors aussi donnaient l’impression d’être sur le point d’arriver en production il y a 10 ans, et aujourd’hui ils ont complètement disparu
    • J’ai encore quatre Optane neufs en réserve. C’est une blague, mais c’est vrai
      En pratique, ce n’est toutefois pas plus rapide que du NVMe. Avec des logiciels prenant en charge la lecture/écriture parallèle, il n’y a presque aucune différence
    • Intel qui fabrique quelque chose de bien puis abandonne en cours de route, on a l’habitude maintenant
      Cela dit, en en mettant 4 en RAID 0, on pourrait probablement saturer la bande passante d’un PCIe 16x
    • mention de pmem
  • Le matériel Mac grand public offre une mémoire unifiée rapide et du NVMe, mais avec une capacité limitée
    Si on charge un modèle de 40 Go sur un M1 Max de 32 Go, le swap s’emballe puis le système finit en panic
    macOS n’a pas d’OOM killer comme Linux, il manque simplement d’espace de swap

  • Avoir « le plus de mémoire possible » est important, mais la bande passante est encore plus déterminante
    Le M4 Pro offre 273 Go/s, le M4 Max 546 Go/s, le M4 Ultra 819 Go/s
    Une fois le modèle chargé en mémoire, c’est la bande passante qui détermine la vitesse des tokens
    Selon Hypura, le M4 Max est le sweet spot. Avec 64 Go, il peut faire tourner confortablement un modèle 70B (Q4), et générer à une vitesse double de celle du Pro

  • Ce projet fonctionne en pratique un peu comme une mémoire swap intelligente
    Il est intéressant de voir qu’il régule l’usage du NVMe pour éviter de trop le solliciter
    Mais si le NVMe est réellement très chargé, on peut craindre une réduction de durée de vie

    • La formulation « solliciter le NVMe » me paraît étrange
      Les SSD voient bien la durée de vie de leurs cellules diminuer selon le nombre d’écritures, mais il est extrêmement rare qu’une charge de lecture endommage le contrôleur
      Si c’était le cas, cela indiquerait un autre problème dans le système
  • Il serait intéressant de comparer ce projet à des expériences précédentes, une autre tentative
    Cette fois-ci, c’est basé sur mmap, et certains retours indiquaient un surcoût important

    • Ce code a été écrit par un LLM, donc sa fiabilité est limitée
    • En plus, cette implémentation n’utilise pas de quantization agressive, donc elle dégrade moins la qualité