Intelligence artificielle
Le cadre d’inférence de Microsoft amène les modèles de langage à grande échelle 1-bit sur les appareils locaux

Le 17 octobre 2024, Microsoft a annoncé BitNet.cpp, un cadre d’inférence conçu pour exécuter des modèles de langage à grande échelle (LLM) quantifiés à 1 bit. BitNet.cpp constitue une avancée significative dans le domaine de l’IA générative, permettant le déploiement efficace de LLM 1 bit sur des CPU standard, sans nécessiter de GPU coûteux. Ce développement démocratise l’accès aux LLM, les rendant disponibles sur une large gamme d’appareils et offrant de nouvelles possibilités pour les applications d’IA sur appareil.
Comprendre les modèles de langage à grande échelle 1-bit
Les modèles de langage à grande échelle (LLM) nécessitaient traditionnellement des ressources computationnelles importantes en raison de l’utilisation de nombres à virgule flottante à haute précision (généralement FP16 ou BF16) pour les poids du modèle. Cette nécessité a rendu le déploiement des LLM coûteux et gourmand en énergie.
À leur core, les LLM 1 bit utilisent des techniques de quantification extrêmes pour représenter les poids du modèle à l’aide de trois valeurs possibles seulement : -1, 0 et 1, d’où le terme « 1,58 bit » (car il faut légèrement plus d’un bit pour encoder trois états).
Système de poids ternaire
Le concept
La quantification à 1 bit dans BitNet.cpp est un système de poids ternaire. BitNet fonctionne avec seulement trois valeurs possibles pour chaque paramètre :
- -1 (négatif)
- 0 (neutre)
- 1 (positif)
Cela entraîne une exigence de stockage d’environ 1,58 bit par paramètre, d’où le nom BitNet b1.58. Cette réduction drastique de la largeur de bit des paramètres conduit à une réduction impressionnante de l’utilisation de la mémoire et de la complexité computationnelle, car la plupart des multiplications à virgule flottante sont remplacées par des additions et des soustractions simples.
Fondement mathématique
La quantification à 1 bit implique la transformation des poids et des activations en leur représentation ternaire à l’aide des étapes suivantes :
1. Binarisation des poids
La binarisation des poids implique de les recentrer autour de la moyenne (α), aboutissant à une représentation ternaire. La transformation est exprimée mathématiquement comme :
Wf=Sign(W−α)
Où :
- W est la matrice de poids d’origine.
- α est la moyenne des poids.
- Sign(x) renvoie +1 si x > 0 et -1 sinon.
2. Quantification des activations
La quantification des activations garantit que les entrées sont limitées à une largeur de bit spécifiée :
Où :
- Qb = 2(b−1)2^{(b-1)} est le niveau de quantification maximum pour une largeur de bit b.
- γ est la valeur absolue maximale de x (notée ∣∣x∣∣∞).
- ε est un petit nombre pour éviter les débordements pendant les calculs.
3. Opération BitLinear
La couche BitLinear remplace les multiplications matricielles traditionnelles par une opération simplifiée :
y=Wf×x^e×(Qbβγ)
Où :
- β est un facteur d’échelle utilisé pour minimiser les erreurs d’approximation.
- γ met à l’échelle les activations.
- Q_b est le facteur de quantification.
Cette transformation permet des calculs efficaces tout en préservant les performances du modèle.
Implications de performance
Efficacité de la mémoire
Le système de poids ternaire réduit considérablement les exigences de mémoire :
- LLM traditionnels : 16 bits par poids
- BitNet.cpp : 1,58 bit par poids
Cette réduction se traduit par une économie de mémoire d’environ 90% par rapport aux modèles traditionnels à 16 bits, permettant ainsi à des modèles plus importants de tenir dans les mêmes contraintes matérielles.
1. Vitesse d’inférence : plus rapide sur les deux CPU
La vitesse d’inférence est représentée par le nombre de jetons traités par seconde. Voici un résumé des observations :
- Sur Apple M2 Ultra : BitNet.cpp atteint une accélération allant jusqu’à 5,07x pour les modèles plus importants (30B) par rapport à Llama.cpp, avec un pic de vitesse de 593,43 jetons par seconde pour un modèle de 125M, ce qui constitue une accélération de 1,37x. Pour les modèles plus importants comme le 3,8B et le 7B, BitNet.cpp maintient une vitesse supérieure à 84,77 jetons par seconde, montrant son efficacité à toutes les échelles.
- Sur Intel i7-13700H : BitNet.cpp atteint des améliorations de vitesse encore plus spectaculaires. À la taille de modèle de 7B, BitNet.cpp offre une accélération incroyable de 5,68x par rapport à Llama.cpp. Pour les modèles plus petits comme le 125M, il traite 389,08 jetons par seconde, ce qui est 2,37x plus rapide que Llama.cpp.
2. Efficacité énergétique : un facteur de changement pour les appareils périphériques
Les graphiques fournis comprennent également des comparaisons de coût énergétique, montrant une réduction significative de la consommation d’énergie par jeton traité :
- Sur Apple M2 Ultra : Les économies d’énergie de BitNet.cpp sont substantielles. Pour le modèle de 700M, il consomme 55,4% moins d’énergie par jeton par rapport à Llama.cpp, passant de 0,314 à 0,140. Cette tendance se poursuit pour les modèles plus importants, le modèle de 70B montrant une réduction de 70,0% de la consommation d’énergie.
- Sur Intel i7-13700H : BitNet.cpp offre 71,9% d’économie d’énergie pour le modèle de 700M, avec une consommation passant de 1,367 à 0,384. Bien que les données énergétiques pour le modèle de 70B dans Llama.cpp soient indisponibles, BitNet.cpp reste efficace, avec une consommation d’énergie à 17,33 pour le modèle de 70B.
3. Franchir le seuil de vitesse de lecture humaine
L’une des observations les plus intéressantes de ces graphiques est la référence à la vitesse de lecture humaine, indiquée à 5-7 jetons par seconde. Cette ligne rouge montre que les deux implémentations, en particulier BitNet.cpp, peuvent dépasser facilement les vitesses de lecture humaines même pour les modèles les plus importants :
- Sur Apple M2 Ultra, BitNet.cpp dépasse la vitesse de lecture humaine pour toutes les tailles de modèles, la vitesse la plus basse étant de 8,67 jetons par seconde pour un modèle de 70B.
- Sur Intel i7-13700H, le modèle de 100B atteint 1,70 jeton par seconde, touchant presque la plage inférieure de la vitesse de lecture humaine, tandis que tous les modèles plus petits dépassent ce seuil.
Considérations de formation
Estimateur de passage direct (STE)
Puisque la quantification à 1 bit introduit des fonctions non différentiables, la formation implique une technique spécialisée appelée Estimateur de passage direct (STE). Dans cette approche, les gradients s’écoulent sans altération à travers les points non différentiables. Voici une mise en œuvre simplifiée en Python :
class StraightThroughEstimator(Function): @staticmethod def forward(ctx, input): return input.sign() @staticmethod def backward(ctx, grad_output): return grad_output
Formation à précision mixte
Pour maintenir la stabilité pendant la formation, la précision mixte est employée :
- Poids et activations : Quantifiés à une précision de 1 bit.
- Gradients et états de l’optimiseur : Stockés dans une précision plus élevée.
- Poids latents : Maintenus dans une précision élevée pour faciliter les mises à jour précises pendant la formation.
Stratégie de taux d’apprentissage élevé
Un défi unique avec les modèles à 1 bit est que de petites mises à jour peuvent ne pas affecter les poids binarisés. Pour atténuer cela, le taux d’apprentissage est augmenté, garantissant ainsi une convergence plus rapide et de meilleures performances d’optimisation par rapport aux approches traditionnelles.
Quantification et normalisation de groupe
BitNet.cpp introduit la quantification et la normalisation de groupe pour améliorer le parallélisme du modèle. Au lieu de calculer les paramètres pour l’ensemble de la matrice de poids, BitNet divise les poids et les activations en plusieurs groupes (G).
Cette regroupation permet un traitement parallèle efficace sans communication intergroupe supplémentaire, permettant ainsi la formation et l’inférence de modèles à grande échelle.
Notes et optimisations d’implémentation
Optimisation CPU
BitNet.cpp exploite plusieurs optimisations de bas niveau pour atteindre les performances CPU maximales :
- Opérations vectorisées : Utilise les instructions SIMD pour effectuer des manipulations de bits de manière efficace.
- Accès à la mémoire adapté au cache : Structure les données pour minimiser les erreurs de cache.
- Traitement parallèle : Répartit la charge de travail de manière efficace sur plusieurs cœurs CPU.
Voici un exemple d’une fonction clé qui met en œuvre la quantification et l’inférence dans BitNet :
Modèles pris en charge
La version actuelle de BitNet.cpp prend en charge les modèles de langage à grande échelle 1 bit suivants disponibles sur Hugging Face :
- bitnet_b1_58-large (0,7 milliard de paramètres)
- bitnet_b1_58-3B (3,3 milliards de paramètres)
- Llama3-8B-1.58-100B-tokens (8,0 milliards de paramètres)
Ces modèles sont disponibles publiquement pour démontrer les capacités d’inférence du cadre. Bien qu’ils n’aient pas été formés ou publiés officiellement par Microsoft, ils illustrent la polyvalence du cadre.
Guide d’installation
Pour commencer avec BitNet.cpp, suivez les étapes ci-dessous :
Prérequis
- Python >= 3.9
- CMake >= 3.22
- Clang >= 18
- Conda (hautement recommandé)
Pour les utilisateurs Windows, Visual Studio doit être installé avec les composants suivants activés :
- Développement de bureau avec C++
- Outils C++-CMake pour Windows
- Git pour Windows
- Compilateur C++-Clang pour Windows
- Prise en charge de MS-Build pour l’ensemble d’outils LLVM (Clang)
Pour les utilisateurs Debian/Ubuntu, un script d’installation automatique est disponible :
Étapes d’installation détaillées
- Cloner le référentiel :
- Installer les dépendances :
- Construire et préparer le projet : Vous pouvez télécharger directement un modèle depuis Hugging Face et le convertir en format quantifié :
Alternativement, vous pouvez télécharger et convertir manuellement le modèle :
Exécution de l’inférence avec BitNet.cpp
Pour exécuter l’inférence en utilisant le cadre, utilisez la commande suivante :
Explication :
-mspécifie le chemin du fichier du modèle.-pdéfinit le texte de l’invite.-ndéfinit le nombre de jetons à prédire.-tempajuste l’aléatoire de l’échantillonnage (température) pendant l’inférence.
Exemple de sortie
Détails techniques de BitNet.cpp
Couche BitLinear
BitNet.cpp met en œuvre une architecture de transformateur modifiée, remplaçant les multiplications matricielles standard par des opérations BitLinear. Cette approche recentre les poids sur zéro avant la quantification et les met à l’échelle pour réduire les erreurs d’approximation. La fonction de transformation clé ressemble à ceci :
# Fonction de binarisation pour les poids à 1 bit def binarize_weights(W): alpha = W.mean() W_binarized = np.sign(W - alpha) return W_binarized
La combinaison de poids recentrés et de mise à l’échelle garantit que l’erreur de quantification reste minime, préservant ainsi les performances.
Impact sur l’industrie
BitNet.cpp pourrait avoir des implications considérables pour le déploiement des modèles de langage à grande échelle :
- Accessibilité : Permet aux modèles de langage à grande échelle de fonctionner sur des appareils standard, démocratisant ainsi l’accès à un puissant IA.
- Rentabilité : Réduit le besoin de GPU coûteux, abaissant ainsi la barrière à l’adoption.
- Efficacité énergétique : Économise de l’énergie en exploitant l’inférence basée sur le CPU.
- Innovation : Ouvre de nouvelles possibilités pour les applications d’IA sur appareil, comme la traduction en temps réel, les assistants vocaux et les applications axées sur la confidentialité sans dépendance du cloud.
Défis et orientations futures
Bien que les modèles de langage à grande échelle 1 bit montrent des promesses, plusieurs défis restent. Ceux-ci incluent le développement de modèles robustes à 1 bit pour diverses tâches, l’optimisation du matériel pour le calcul à 1 bit et l’encouragement des développeurs à adopter ce nouveau paradigme. De plus, l’exploration de la quantification à 1 bit pour les tâches de vision par ordinateur ou audio représente une direction passionnante pour l’avenir.
Conclusion
Le lancement de BitNet.cpp par Microsoft constitue une avancée significative. En permettant une inférence efficace à 1 bit sur les CPU standard, BitNet.cpp crée l’accessibilité et la durabilité de l’IA. Ce cadre ouvre la voie à des modèles de langage à grande échelle plus portables et plus rentables, repoussant les limites de ce qui est possible avec l’IA sur appareil.














