Llama CPP est un nouvel outil conçu pour exécuter des modèles de langage directement en C/C++. Cet outil est spécialement optimisé pour les processeurs Apple Silicon grâce à l'utilisation de la technologie ARM NEON et du framework Accelerate. Il offre également une compatibilité AVX2 pour les systèmes basés sur des architectures x86. Fonctionnant principalement sur le CPU, Llama CPP intègre aussi la capacité de quantification 4 bits, renforçant ainsi son efficacité.

Son avantage est qu'il permet d'exécuter un modèle de langage directement sur son ordinateur personnel sans requérir de GPU avec une importante quantité de VRAM. Pour simplifier, pas besoin de vendre votre voiture pour tester les derniers modèles en vogue.

Soyons clairs, même si l'outil vous permet de plonger tête baissée à moindre coût dans le monde des LLMs, il faudra vous armer de patience. Car les temps de traitement sont parfois monstrueux. On fait le test ensemble ? Vous verrez, il n'est pas rare d'attendre 5 minutes pour obtenir une réponse. Et ce n'est pas grave, l'idée ici est de faire tourner le système sur son poste de travail. Vous comprendrez pourquoi les stars de l'hébergement vous demandent quelques centaines/milliers d'euros pour faire tourner vos modèles dans le cloud.

À date, voici la liste des modèles compatibles :

  • LLaMA 🦙
  • LLaMA 2 🦙🦙
  • Falcon
  • Alpaca
  • GPT4All
  • Chinese LLaMA / Alpaca and Chinese LLaMA-2 / Alpaca-2
  • Vigogne (French)
  • Vicuna
  • Koala
  • OpenBuddy 🐶 (Multilingual)
  • Pygmalion/Metharme
  • WizardLM
  • Baichuan 1 & 2 + derivations
  • Aquila 1 & 2
  • Starcoder models
  • Mistral AI v0.1
  • Refact
  • Persimmon 8B
  • MPT
  • Bloom
  • StableLM-3b-4e1t

La première étape sera donc d'installer et de compiler Llama cpp. On part du principe que vous êtes développeur, et comme tout bon développeur, vous utilisez Linux. Ce n'est pas le cas ? Ce n'est pas grave, utilisez Docker pour simuler une machine tournant sous le même OS que cet article, à savoir Ubuntu 22.04. Vous pouvez utiliser ce docker-compose.yml par exemple :

version: '3.8'
services:
  ubuntu:
    image: ubuntu:22.04
    command: /bin/bash
    stdin_open: true
    tty: true
    working_dir: /workspace
Docker compose up
Docker compose exec ubuntu bash

Ça y est, nous y sommes ? Poursuivons.

Prérequis : installer les outils nécessaires à l'exécution du programme. Vous aurez besoin des outils de compilation, mais aussi des outils vous permettant de cloner les projets GitHub ainsi qu'un token vous donnant accès à Hugingface, le fameux dépôt des LLMs open source.

apt-get update
apt-get install -y git  cmake g++ make curl gh python3-pip

curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 

sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg 
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.g
pg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null 


pip install numpy
pip install sentencepiece
pip install -U "huggingface_hub[cli]"

Pour créer un token d'accès Hugging Face, voici le lien (il peut être un peu compliqué à retrouver dans l'interface) : https://huggingface.co/settings/tokens

Si vous n'avez pas encore de token sur GitHub, voici également un lien : https://github.com/settings/tokens/new

À présent, nous allons cloner et compiler llama.cpp.

# Cloner le dépôt Git de llama-cpp
gh repo clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp

# Compiler le projet
mkdir build
cd build
cmake ..
cmake --build . --config Release

À présent, nous allons télécharger le dernier modèle confectionné par MistralAi.

Vous trouverez le modèle sur Huggingface ici : https://huggingface.co/mistralai

Pour plus de clarté, vous pouvez directement ajouter llama.cpp à votre environnement. Cela nous permettra de nous concentrer sur les commandes sans polluer notre console de chemins qui ne nous apporteront rien.

Par exemple :

export PATH="/Data/Projets/Llm/src/Llama-cpp/llama.cpp/build/bin:$PATH"

Téléchargement du Modèle : remplacez $HUGGINGFACE_TOKEN par votre token.

mkdir /Data/Projets/Llm/Models/mistralai 

huggingface-cli login --token $HUGGINGFACE_TOKEN
huggingface-cli download mistralai/Mistral-7B-v0.1 --local-dir /Data/Projets/Llm/Models/mistralai 

Servez-vous un café, il y en a pour 15 gigas.

Certains gros fichiers ne seront que des liens symboliques vers le répertoire de cache. Vous pouvez préciser --cache-dir afin de les écrire sur une autre partition si besoin.

Ce qui pourrait nous donner quelque chose comme ceci :

huggingface-cli download mistralai/Mistral-7B-v0.1 --local-dir /Data/Projets/Llm/Models/mistralai --cache-dir /Data/Projets/Llm/Models/huggingface_cache/

Une fois que nous avons téléchargé nos fichiers au format PyTorch, nous allons devoir procéder à une petite conversion.

On retourne dans notre répertoire llama.cpp et on exécute la commande suivante :

python3 llama.cpp/convert.py /Data/Projets/Llm/Models/mistralai 
  --outfile /Data/Projets/Llm/Models/mistralai/Mistral-7B-v0.1.gguf 
  --outtype f16

Quel est donc ce paramètre --outtype q8_0 ?? C'est la Quantification (quantization en anglais).

La quantification est un processus qui vise à réduire la taille et la complexité des modèles. Imaginez un sculpteur qui commence avec un énorme bloc de marbre et qui le taille pour créer une statue. La quantification, c'est un peu comme retirer des morceaux du bloc pour le rendre plus léger et plus facile à déplacer, tout en veillant à ce que la statue conserve sa beauté et sa forme.

Dans le contexte des LLMs, la quantification implique de simplifier la représentation des poids du modèle. Les poids dans un LLM sont des valeurs numériques qui déterminent comment le modèle réagit à différentes entrées. En réduisant la précision de ces poids (par exemple, en passant de valeurs flottantes 32 bits à des valeurs 8 bits), on réduit la taille globale du modèle et la quantité de calcul nécessaire pour l'exécuter.

Cela a plusieurs avantages. Premièrement, cela rend le modèle plus rapide et moins gourmand en énergie, ce qui est crucial pour les applications sur des appareils mobiles ou des serveurs à faible capacité. Deuxièmement, cela rend l'IA plus accessible, car elle peut fonctionner sur une gamme plus large d'appareils, y compris ceux qui n'ont pas de matériel de calcul de pointe.

Cependant, la quantification doit être gérée avec soin. Une réduction excessive de la précision peut entraîner une perte de performance, où le modèle devient moins précis ou moins fiable. Il s'agit donc de trouver le juste équilibre entre efficacité et performance.

  1. Quantification 2 bits (2-Bit Quantization)

    • q2_k: Utilise Q4_K pour les tenseurs attention.vw et feed_forward.w2, et Q2_K pour les autres tenseurs. Ceci signifie que certains tenseurs clés ont une précision légèrement supérieure (4 bits) pour maintenir la performance, tandis que les autres sont plus compressés (2 bits).
  2. Quantification 3 bits (3-Bit Quantization)

    • q3_k_l: Emploie Q5_K pour attention.wv, attention.wo, et feed_forward.w2, et Q3_K pour les autres. Cela indique une précision plus élevée (5 bits) pour certains tenseurs importants, tandis que les autres sont à 3 bits.
    • q3_k_m: Utilise Q4_K pour les mêmes tenseurs que q3_k_l, mais avec une précision légèrement inférieure (4 bits), et Q3_K pour les autres.
    • q3_k_s: Applique une quantification Q3_K à tous les tenseurs, offrant une uniformité mais avec une précision moindre.
  3. Quantification 4 bits (4-Bit Quantization)

    • q4_0: Méthode originale de quantification à 4 bits.
    • q4_1: Offre une précision plus élevée que q4_0, mais inférieure à q5_0, avec une inférence plus rapide que les modèles q5.
    • q4_k_m: Utilise Q6_K pour la moitié des tenseurs attention.wv et feed_forward.w2, et Q4_K pour les autres.
    • q4_k_s: Applique Q4_K à tous les tenseurs.
  4. Quantification 5 bits (5-Bit Quantization)

    • q5_0: Fournit une précision plus élevée mais nécessite plus de ressources et ralentit l'inférence.
    • q5_1: Offre une précision encore plus élevée au prix d'une utilisation accrue des ressources et d'une inférence plus lente.
    • q5_k_m: Comme q4_k_m, mais avec Q6_K pour certains tenseurs et Q5_K pour les autres.
    • q5_k_s: Utilise Q5_K pour tous les tenseurs.
  5. Quantification 6 bits (6-Bit Quantization)

    • q6_k: Emploie une quantification Q8_K pour tous les tenseurs, offrant une précision relativement élevée.
  6. Quantification 8 bits (8-Bit Quantization)

    • q8_0: Cette méthode atteint une quantification presque indiscernable du format float16, mais nécessite beaucoup de ressources et ralentit l'inférence.

La précision d'une méthode de quantification dépend donc de la quantité de bits utilisée pour représenter les poids du modèle.

  1. La plus précise : La méthode q6_k (Quantification 6 bits), qui utilise Q8_K pour tous les tenseurs, serait probablement la plus précise parmi notre liste. Elle utilise 8 bits pour chaque poids, ce qui permet une représentation plus détaillée et plus proche des valeurs d'origine. Cela se traduit par une meilleure préservation des nuances et des détails du modèle, mais au prix d'une plus grande utilisation des ressources et d'un temps d'inférence potentiellement plus long.

  2. La moins précise : La méthode q2_k (Quantification 2 bits) serait la moins précise. Cette méthode utilise seulement 2 bits pour la majorité des tenseurs, avec quelques exceptions à 4 bits (Q4_K) pour les tenseurs attention.vw et feed_forward.w2. La représentation à 2 bits est très compacte, mais elle est aussi beaucoup plus susceptible de perdre des informations importantes, car elle ne peut représenter que quatre valeurs différentes par poids, comparée à 256 valeurs dans une quantification à 8 bits.

Cela est la théorie, notre outil nous propose trois types de conversions : --outtype {f32,f16,q8_0}

  1. f32 (Float 32-bit) : C'est la représentation standard de haute précision pour les nombres à virgule flottante dans de nombreux calculs informatiques, y compris dans les LLMs. Chaque poids est stocké avec une précision de 32 bits, ce qui offre une grande précision mais aussi une grande taille de modèle et une utilisation des ressources. Cette option n'est pas une forme de quantification mais plutôt le format standard sans quantification.

  2. f16 (Float 16-bit) : Il s'agit d'une version plus compacte de f32, où chaque poids est stocké avec une précision de 16 bits. Cela réduit la taille du modèle et la quantité de calcul nécessaire, avec une légère perte de précision par rapport à f32. Bien que ce soit une forme de compression, ce n'est pas techniquement de la quantification au sens où nous l'avons discuté précédemment.

  3. q8_0 (8-Bit Quantization) :

Ceci se rapporte directement à la méthode de quantification à 8 bits mentionnée précédemment. Dans cette méthode, chaque poids est représenté avec 8 bits. C'est la quantification la plus élevée parmi les options que vous avez données et est presque comparable à f16 en termes de précision. Elle offre un bon équilibre entre la réduction de la taille du modèle et la préservation de la précision.

En résumé, f32 offre la plus grande précision mais à la plus grande taille, f16 réduit cette taille de moitié avec une légère perte de précision, et q8_0 réduit encore davantage la taille tout en offrant une précision qui est généralement suffisante pour de nombreuses applications. Ces options reflètent différents compromis entre la précision et l'efficacité en termes de taille et de calcul.

  • f32: vous donnera un fichier de 27 gigaoctets. Il faudra vous assurer d'avoir suffisamment de RAM pour cela. En effet, Llama.cpp chargera tout le fichier en RAM. L'exécution a tout simplement planté sur mon poste.
  • f16: vous donnera un fichier de 14 gigaoctets.

L'exécution d'une instruction donnera ceci :

main -m  /Data/Projets/Llm/Models/mistralai/Mistral-7B-v0.1.gguf -i --interactive-first -r "### Human:" --temp 0 -c 2048 -n -1 --ignore-eos --repeat_penalty 1.2 --instruct

Vous avez la possibilité de directement utiliser un serveur. La commande suivante vous permet d'installer llama-cpp ainsi qu'un serveur compatible avec OpenAPI.

pip install llama-cpp-python[server]
python3 -m llama_cpp.server --model  /Data/Projets/Llm/Models/mistralai/Mistral-7B-v0.1.gguf  --host 0.0.0.0 --port 8000

53f749c772a10b3f17be12bcf1389ef2f9a316ce.png

39b0388cde190ffbae906d2e630c74e9e147ff91.png

Nous allons à présent installer une interface client qui conversera avec notre API.

gh repo clone https://github.com/mckaywrigley/chatbot-ui.git
cd chatbot-ui/
docker compose up

J'ai un peu modifié le docker-compose afin de le calibrer avec ma configuration.

version: '3.6'

services:
  chatgpt:
    build: .
    ports:
      - 3000:3000
    restart: on-failure
    environment:
      - 'OPENAI_API_KEY=sk-XXXXXXXXXXXXXXXXXXXX'
      - 'OPENAI_API_HOST=http://host.docker.internal:8000'
      - 'DEFAULT_MODEL=/Data/Projets/Llm/Models/mistralai/Mistral-7B-v0.1.gguf'
      - 'NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=You are a helpful and friendly AI assistant. Respond very concisely.'
      - 'WAIT_HOSTS=http://host.docker.internal:8000/'
      - 'WAIT_TIMEOUT=${WAIT_TIMEOUT:-3600}'
    extra_hosts:
      - "host.docker.internal:host-gateway"

Le programme n'est pas vraiment conçu pour interagir directement avec MistralAi. Je n'ai pas forcément choisi l'exemple le plus simple.

Sachez qu'avec les modèles spécifiés comme compatibles sur le dépôt officiel, l'intégration est meilleure.

Voici un aperçu de ce que donne ma petite question sur la recette de la mayonnaise via Chat-ui.

Nous allons maintenant regarder ce que ça donne en poussant la quantification à 8 bits avec le type à q8_0.

python3 llama.cpp/convert.py /Data/Projets/Llm/Models/mistralai  --outfile /Data/Projets/Llm/Models/mistralai/Mistral-7B-v0.1_q8.gguf  --outtype q8_0


main -m  /Data/Projets/Llm/Models/mistralai/Mistral-7B-v0.1_q8.gguf -i --interactive-first -r "### Human:" --temp 0 -c 2048 -n -1 --ignore-eos --repeat_penalty 1.2 --instruct

Comme vous le voyez, c'est nettement plus rapide ! Et tout à fait exploitable.

Ainsi s'achève cette petite présentation d'une stack auto-hébergée. Comme vous le voyez, avec très peu de moyens, ça fonctionne. Imaginez avec du matériel conçu pour !

Sachez que MistralAi est une entreprise française. En dehors de l'utilisation sur un ordinateur portable bon marché, sachez que l'ensemble de la suite d'outils pour entreprises est disponible pour ce modèle.