KVSplit - exécuter un contexte 2 à 3 fois plus long sur Apple Silicon
(github.com/dipampaul17)- KVSplit est un projet open source qui permet d’exécuter de grands LLM et de longues fenêtres de contexte sur Apple Silicon
- Grâce à une allocation de précision séparée pour les clés et les valeurs, il atteint jusqu’à 72 % de réduction mémoire avec moins de 1 % de dégradation de qualité
- Il est optimisé pour les puces M1/M2/M3 et le framework Metal
- Il démontre des améliorations de vitesse d’exécution et des économies mémoire au moyen de benchmarks mesurés et d’outils de visualisation
- Il propose une installation simple, une comparaison en une commande, ainsi que divers outils de benchmark et d’analyse
Introduction : pourquoi KVSplit est important
KVSplit est un outil open source qui permet d’exécuter de grands LLM et des fenêtres de contexte bien plus longues sur Apple Silicon (M1/M2/M3) en appliquant une quantification avec des précisions différentes aux clés et aux valeurs à l’intérieur du cache KV. Il dépasse la limite des projets existants, qui quantifient les clés et les valeurs de la même manière, en réduisant drastiquement l’utilisation mémoire tout en maintenant la dégradation de qualité à un niveau presque imperceptible. Les benchmarks réels, les performances et les métriques de qualité sont tous publiés, ce qui le rend crédible, et la prise en charge de Metal ainsi que des outils intuitifs de comparaison et de visualisation améliorent l’efficacité de développement.
Ses principaux avantages par rapport aux projets comparables sont les suivants :
- Séparation de la précision clé/valeur pour une gestion mémoire plus efficace
- Spécialisation Apple Silicon et prise en charge d’une optimisation complète pour le framework Metal
- Intégration de benchmarks, perplexité, mesures mémoire/vitesse/qualité et visualisation
- Installation en une commande, compatibilité avec les modèles, intégration à llama.cpp
- Visualisation en temps réel des économies mémoire et divers outils de tests comparatifs
Caractéristiques principales et points clés
Vue d’ensemble
- Avec KVSplit, il devient possible d’exécuter sur Apple Silicon des LLM bien plus grands et des longueurs de contexte plus importantes qu’auparavant
- En attribuant une précision de quantification différente aux clés et aux valeurs, il obtient à la fois des économies mémoire et des gains de vitesse
- Jusqu’à 72 % d’économie mémoire, amélioration de vitesse (5 à 15 %↑) et moins de 1 % de dégradation de qualité ont été confirmés
- Prise en charge complète de Metal, avec accélération optimale sur Apple Silicon
Principaux résultats de benchmark
- Dans la configuration K8V4 (clés 8 bits, valeurs 4 bits)
- 59 % d’économie mémoire et 0,86 % de dégradation de qualité (sur la base de la perplexité)
- Gain de vitesse de 5,7 % par rapport à FP16
- Dans la configuration K4V4 (clés/valeurs toutes deux en 4 bits)
- Jusqu’à 72 % d’économie mémoire
- Environ 6 % de perte de qualité. Recommandé pour des usages moins sensibles à la qualité
Comparaison des effets de réduction mémoire
- Par rapport à FP16 à 176 MB (8K tokens)
- K8V8 (clés/valeurs 8 bits) : 93.5MB (47%)
- K8V4 (clés 8 bits, valeurs 4 bits) : 71.5MB (41%)
- K4V4 (clés/valeurs 4 bits) : 49.5MB (28%)
Fonctionnalités principales
- Quantification individuelle des clés et des valeurs du cache KV
- Optimisation complète pour Apple Silicon et Metal
- Scripts d’analyse de benchmark/qualité (perplexité)/utilisation mémoire
- Outils de visualisation et génération de graphiques de qualité publication
- Configuration en une commande et comparaison en temps réel
Structure des dossiers du projet
- llama.cpp : inclut un build optimisé pour Metal
- models : stockage des fichiers de modèles
- scripts : inclut les scripts de benchmark/installation/comparaison/visualisation
- results, plots : stockage des résultats de benchmark et des fichiers de visualisation
- README.md
Enseignements scientifiques et résultats expérimentaux
Phénomène clé du cache KV
- Les vecteurs de clés ont une sensibilité à la quantification bien plus élevée que les vecteurs de valeurs → il faut attribuer une précision plus élevée aux clés pour préserver la qualité
- K8V4 est le sweet spot : la répartition clés 8 bits / valeurs 4 bits offre le meilleur compromis qualité-mémoire
- 59 % d’économie mémoire, seulement 0,86 % de dégradation de la perplexité, et une vitesse supérieure à FP16
- K4V8, malgré le même nombre total de bits que K8V4, provoque une dégradation de qualité plus de 7 fois plus importante → preuve de l’importance de la précision côté clés
Implications globales
- Il permet à la fois l’efficacité mémoire et la préservation de la qualité du modèle → il devient possible d’exécuter des contextes bien plus longs et des modèles plus grands sur du matériel grand public
Exemples d’utilisation et recommandations de configuration
Exemples d’exécution avec différentes précisions de quantification
- Par défaut (FP16) : ./llama.cpp/build/bin/llama-cli -m models/your-model.gguf -p "prompt" -t 8 --flash-attn
- K8V4 recommandé : --kvq 8
- K4V8 (DÉMO) : --kvq-key 4 --kvq-val 8
- K4V4 (réduction maximale) : --kvq 4
Exemple de contexte long
- Contexte 32K : FP16 nécessite ~1.4GB, mais K8V4 peut fonctionner avec ~400MB
Explication des flags en ligne de commande
-t 8: nombre de threads, 8 recommandé pour M1/M2/M3--flash-attn: optimisation pour Apple Silicon--kvq N: définit les clés/valeurs toutes deux sur N bits--kvq-key,--kvq-val: prise en charge d’un réglage individuel-c N: nombre de tokens de contexte (plus il est élevé, plus l’effet de KVSplit est important)-n N: nombre de tokens générés-f FILE: fichier document en entrée-m MODEL: chemin du modèle
Benchmark avancé et visualisation
- benchmark_kvsplit.py mesure, selon la configuration et la longueur de séquence, la mémoire/la vitesse/la perplexité/les caractéristiques de mise à l’échelle
- visualize_results.py génère des graphiques de niveau publication scientifique
- Les résultats sont automatiquement enregistrés en CSV/JSON et un résumé est fourni
Optimisation Apple Silicon et visualisation mémoire
- Utilisation complète du framework Metal
- Effet décisif sur les modèles M1/M2/M3 à forte contrainte mémoire
- capture_memory.sh permet de visualiser en temps réel les économies mémoire
- En raison d’un alignement de pages personnalisé, la réduction réelle peut légèrement différer de la valeur théorique
Récapitulatif des fonctionnalités
- Précision en bits indépendante pour les clés/valeurs et quantification personnalisée
- Optimisation complète pour Apple Silicon et Metal
- Benchmarks complets mémoire/vitesse/qualité
- Visualisation de qualité publication, comparaison en temps réel et prise en charge de la capture mémoire
- Interface d’installation et d’utilisation ultra-simple
Citations et recherches de référence
- "More for Keys, Less for Values: Adaptive KV Cache Quantization" (2024)
- "Unifying KV Cache Compression for Large Language Models with LeanKV" (2025)
- Implémentation de base : [llama.cpp], modèle de test : [TinyLlama]
Recommandations de configuration et plans futurs
- K8V4 (clés 8 bits / valeurs 4 bits) : perte de qualité de 0,86 %, réduction mémoire de 59 %, vitesse +5,7 %, soit le meilleur équilibre
- K4V4 : réduction mémoire maximale (72 %), baisse de qualité d’environ 6 %. Adapté aux usages où la mémoire est la priorité absolue
- Particulièrement performant pour l’exécution de contextes longs, avec des contextes 2 à 3 fois plus longs possibles
Feuille de route
- Précision adaptative fondée sur l’importance des tokens
- Quantification individuelle par couche
- Optimisation sur mesure selon le modèle (Mistral, Phi-3, etc.)
- Démo web et prise en charge mobile (iOS/iPadOS) prévues
Licence et contribution
- Licence MIT
- Tout développeur ou chercheur en IA peut contribuer via une Issue ou une PR
1 commentaires
Avis Hacker News
Expression d’intérêt trouvant cela intéressant, question sur l’intuition expliquant pourquoi ce phénomène apparaît et sur le cheminement qui a mené à cette découverte, suggestion d’améliorations orientées utilisateur comme le fait que l’étape d’application du patch dans le script d’installation n’est pas finalisée et l’usage de
git submodule, ainsi que proposition de séparerllama.cppet les dépendances Python pour mieux prendre en compte divers environnements Pythonllama.cpp, que le code d’analyse des arguments a déjà été déplacé dansarg.cpp, ce qui rend le patch sans effet, et que les options de quantification K/V ont déjà été ajoutées àllama.cppen 2023 ; doute sur l’utilité même du patch, qui semble simplement modifier les arguments en ligne de commande, et forte recommandation d’éviter d’exécuter uninstall.shd’un nouveau dépôt pour appliquer un patch aussi simpleQuestion sur la possibilité de faire cela aussi avec MLX, avec l’idée que MLX est plus rapide et que cette approche pourrait aider les utilisateurs Mac à bénéficier en pratique de conversations longues à bonne vitesse
Question sur l’existence d’une différence réelle avec les options
--cache-type-k,--cache-type-vbf16n’a été ajoutée que récemment ; par le passé, sur les GPU Apple, l’approchetype_k/vsemblait limitée au minimum à 16 bits (f16/bf16), donc sans bien connaître l’intérieur dellama.cpp, cela pourrait être légèrement différentAprès lecture du code, conclusion que le patch est inutile, avec confirmation via un lien de PR que la fonctionnalité a déjà été intégrée à
llama.cppen 2023 ; mise en garde contre le fait d’inciter à exécuterinstall.shpour appliquer un patch au lieu d’utiliser simplement un fork du dépôt ; critique d’une structure confuse du dépôt avec plusieurs fichiers de patch, du code dupliqué et des patches qui s’écrasent les uns les autres ; en pratique, le dépôt ne ferait qu’ajouter l’option--kvq, alors qu’il existe déjà des options séparées de quantification K/V ; soupçon que l’auteur ne pouvait pas ignorer cette fonctionnalité existante ; recommandation de ne pas exécuter les scripts d’un dépôt fournissant des scripts complexes ; critique supplémentaire expliquant que le post HN et le nombre d’étoiles GitHub sont élevés, mais que le contenu est trompeur, et inquiétude face au fait que l’auteur continue d’éviter les questions ; conclusion ajoutant que le dépôt et les scripts mélangent du code ancien dellama.cppavec la structure récente, ce qui accroît encore la confusionQuestion sur la possibilité d’appliquer une quantification KV différenciée (
K8V4, etc.) à des modèles déjà convertis au format.gguf, et sur d’éventuelles limitations selon le type de modèle ou la configuration du tokenizer.ggufexistants, sans conversion spéciale ; la quantification ne s’applique qu’au cache KV à l’exécution et est indépendante des poids du modèle ; les drapeaux--kvq-keyet--kvq-valservent seulement à définir le format de stockage mémoire ; l’auteur dit avoir testé avec succès divers modèles comme LLama-3, Mistral, Phi-2/Phi-3, TinyLlama, Qwen, etc. ; en revanche, cela reste limité au backend Metal dellama.cpp, et comme Flash Attention contourne actuellement les formats personnalisés de cache KV, l’option-fa 0est nécessaire ; sinon, cela devrait fonctionner avec toute architecture Transformer utilisant l’attentionQuestion demandant si ce patch est plus rapide ou meilleur sur des Apple Silicon à grande capacité mémoire, comme 64 Go ou 128 Go, avec mention de rumeurs selon lesquelles l’extension de la fenêtre de contexte est en pratique lente sur Apple Silicon, et interrogation sur l’intérêt concret avec beaucoup de mémoire
K8V4, mais cela serait dû à l’efficacité des accès mémoire ; pour les gros modèles, la lenteur vient surtout des limites de calcul, indépendamment de la RAM ou de l’optimisation du cache KV ; autrement dit, KVSplit est utile lorsqu’on bute sur une limite mémoire, et en pratique il est préférable d’attribuer de plus grandes fenêtres de contexte à des modèles plus petits, comme les 7B à 13B ; si l’on veut à la fois de très gros modèles et des fenêtres extrêmement longues, des GPU de classe serveur restent plus adaptés, mais cette approche repousse tout de même les limites possibles sur matériel AppleExpression d’intérêt et demande d’une explication un peu plus haut niveau : possibilité d’utiliser un modèle 2048 tokens avec une fenêtre étendue à 4–6k, ou un modèle 128k avec une fenêtre 256k+, ainsi que question sur les cas d’usage idéaux des modèles locaux
K8V4permet une réduction mémoire de 59 %, ce qui peut augmenter la longueur maximale de contexte jusqu’à 2,4× ; un modèle 2048 tokens peut ainsi monter à environ 5000 tokens, et un modèle 8K à environ 19,5K ; exemples d’usage réels sur MacBook : traiter un livre entier d’un coup, analyser une grande base de code ou conserver de longs historiques de conversation dans une application interactive ; l’économie de mémoire croît linéairement avec la longueur de contexte ; d’après l’expérience rapportée, à 8K de contexte, le cache KV passe de 176 Mo à 72 Mo, et à 128k le gain se chiffre en gigaoctets ; solution particulièrement utile lorsqu’on rencontre des erreurs OOM dues à la longueur d’entréeÉloge disant que c’est une très bonne idée et une tentative intéressante, avec question supplémentaire sur l’applicabilité aux GPU et sur la possibilité de la combiner avec d’autres techniques de quantification
llama.cppprend déjà en charge des réglages séparés via--cache-type-ket--cache-type-v; le patch actuel est spécialisé pour Metal, mais le principe est transposable tel quel ; cela peut aussi être combiné avec d’autres techniques de quantification, car la quantification du cache KV n’intervient qu’à l’exécution et n’entre pas en conflit avec la quantification des poids ; il s’agit d’une étape distincte du pipeline de conversion ; en revanche, des moteurs commevLLMouTensorRT-LLM, qui utilisent une autre structure de cache, nécessiteraient une implémentation spécifique ; sur GPU, le plus grand effet viendrait d’une intégration directe dans une architecture FlashAttention, où les gains mémoire pourraient se traduire directement en gains de vitesseMessage indiquant ne pas bien comprendre certains points, percevoir quelque chose d’étrange, recommander de ne pas exécuter le script et signaler l’avoir dénoncé
Question sur l’évolution des performances : même si l’on peut placer un contexte plus long en mémoire, la vitesse de calcul ne devrait-elle pas rester la même ?
fp16,q8etq4, la vitesse d’itération semble similaire ; l’auteur n’a pas vérifié le fonctionnement interne, mais s’attendait à ce que les vecteurs soient packés pour un traitement SIMD en bloc en 4 ou 8 bits, alors qu’il a plutôt eu l’impression que ce n’était pas le cas