Local AI

Optimiser llama.cpp sur Apple Silicon pour la vitesse

Apple Silicon a fondamentalement changé le paysage de l'inférence locale des grands modèles de langage (LLM). En exploitant l'architecture mémoire unifiée des puces M1, M2 et M3, les développeurs peuvent exécuter de grands modèles localement sans les pénalités de latence typiquement associées au transfert de données entre le CPU et le GPU. Cependant, atteindre des performances maximales nécessite plus que simplement compiler le code ; cela exige une approche stratégique pour le choix du backend et la gestion de la mémoire. Dans ce guide, nous explorerons comment optimiser llama.cpp pour tirer le meilleur parti de chaque cycle de votre matériel Mac.

Comprendre le backend Metal

Par défaut, llama.cpp est compilé avec le support Metal activé sur macOS. C'est crucial car les Metal Performance Shaders (MPS) fournissent des noyaux hautement optimisés pour les multiplications de matrices, qui constituent la base computationnelle des modèles Transformer. Contrairement à CUDA sur les GPU NVIDIA, qui dispose d'un écosystème mature de bibliothèques, le backend Metal d'Apple dans llama.cpp est conçu pour minimiser la surcharge des lancements de noyaux. Lors de l'exécution de l'inférence, les tenseurs sont stockés directement en mémoire GPU, permettant un accès rapide. La clé des performances ici est de s'assurer que votre compilation utilise bien le backend Metal et ne bascule pas sur une exécution CPU uniquement, ce qui réduirait considérablement le débit.

Exploiter l'architecture mémoire unifiée

Le système de mémoire unifiée d'Apple Silicon permet à la fois au CPU et au GPU d'accéder au même pool de mémoire sans copie explicite. Pour les LLM, c'est un changement majeur. Les configurations GPU discrètes traditionnelles nécessitent de décharger les poids du modèle de la RAM système vers la VRAM, un processus qui peut prendre des secondes voire des minutes pour les grands modèles. Sur Apple Silicon, les poids du modèle résident en mémoire unifiée, accessibles par le GPU via des interconnexions à haut débit. Cela élimine entièrement l'étape de "déchargement". Cependant, vous devez vous assurer que votre modèle est chargé correctement en mémoire GPU. Dans llama.cpp, cela est contrôlé par le paramètre -ngl (nombre de couches GPU).

Configuration pratique pour un débit maximal

Pour atteindre un haut débit, vous devez équilibrer le nombre de couches déchargées sur le GPU avec votre bande passante mémoire disponible. Voici un exemple pratique d'exécution d'un modèle LLaMA 2 quantifié avec des drapeaux optimaux pour une puce M2 Max :


# Charger le modèle avec toutes les couches sur le GPU
# -ngl 99 s'assure que toutes les couches possibles sont déplacées vers le GPU
# -c 4096 définit la taille de la fenêtre de contexte
# -b 512 définit la taille du lot (des lots plus grands donnent souvent un meilleur débit)
./llama-cli -m ./llama-2-13b-q4_K_M.gguf -ngl 99 -c 4096 -b 512

Notez l'utilisation de -b 512. Bien qu'une taille de lot plus grande consomme plus de mémoire, elle permet au GPU de traiter plusieurs jetons en parallèle, ce qui est crucial pour atteindre des taux élevés de jetons par seconde (TPS). Si vous êtes limité par la mémoire, vous pouvez réduire cette valeur, mais commencez haut et descendez jusqu'à observer une baisse de performance.

Astuces avancées : Quantification et Contexte

La quantification est le deuxième levier majeur pour les performances. L'utilisation d'un schéma de quantification 4 bits (tel que Q4_K_M ou Q4_0) réduit considérablement l'empreinte mémoire, laissant plus de place pour la fenêtre de contexte et la taille du lot. Sur Apple Silicon, la bande passante est souvent le facteur limitant plutôt que la puissance de calcul brute. En réduisant la quantité de données qui doivent être déplacées entre les unités de mémoire, la quantification a un impact direct sur la vitesse d'inférence. De plus, gardez votre fenêtre de contexte aussi petite que possible. Un contexte de 4096 jetons est généralement suffisant pour la plupart des applications de chat et produira une génération de jetons plus rapide qu'un contexte de 16k.

Surveillance des performances

Pour vérifier que vos optimisations fonctionnent, surveillez l'utilisation du GPU à l'aide du Moniteur d'activité dans macOS. Recherchez l'onglet "GPU" et assurez-vous que votre processus utilise activement les cœurs GPU. Si vous observez une faible utilisation du GPU malgré une forte utilisation du CPU, vous n'avez peut-être pas déchargé suffisamment de couches sur le GPU. L'augmentation du paramètre -ngl devrait déplacer la charge de travail vers le backend Metal.

Conclusion

L'optimisation de llama.cpp pour Apple Silicon est un mélange de compréhension de l'architecture matérielle et de réglage des paramètres logiciels. En exploitant le backend Metal et le système de mémoire unifiée, vous pouvez atteindre des vitesses d'inférence locale qui rivalisent avec les API basées sur le cloud pour de nombreux cas d'usage. Commencez avec un modèle quantifié en 4 bits, déchargez toutes les couches sur le GPU et réglez votre taille de lot pour trouver le point optimal pour votre configuration matérielle spécifique. Avec ces stratégies, votre Mac devient un outil puissant pour le développement d'IA privé et à haut débit.

Share: