Comment exécuter localement un LLM (1/2)?

Ces deux billets proposent une shortlist non-exhaustive et tout à fait personnelle des outils et librairies open source à disposition permettent d'exploiter les LLM en local (sur son PC ou sur son serveur) afin de s'abstraire des UI disponibles en ligne type ChatGPT, Gemini, Claude ou LeChat, plus ou moins gratuites et plus ou moins utilisables si l'on veut faire de l'inférence sur des données non publiques par exemple.

Voici donc quelques solutions retenues à l'usage pour se débrouiller sans GPT et se donner les moyens d'explorer l'univers des possibilités avec les LLM : celles-ci sont classées par degré croissant d'abstraction, c'est-à dire de la bibliothèque de bas niveau avec du code "au plus près" du modèle jusqu'aux frameworks dotés de classes et méthodes facilitant l'inférence et orientés développement applicatif. L'étape ultime de ce processus d'abstraction (c'est-à dire de couches de plus en plus élaborées et complètes autour des LLM) comprend naturellement les nombreux outils low-code et no-code (concurrents de ChatGPT donc) qui émergent de plus en plus, mais non traitées dans ces billets.

Quelques remarques

CPU, GPU, local, cloud ?

Autant il est tout à fait jouable de faire tourner un algorithme de Machine Learning classique sur son laptop (hors contexte de big Data), autant par construction les LLM ont un coût élevé en RAM du fait des calculs parallélisés que leur exécution met en oeuvre. La plupart du temps le LLM ne tient pas sur la mémoire GPU d'un PC grand public et la version quantizée du modèle doit être utilisée sur la mémoire CPU, ce qui nécessite généralement d'implémenter en plus des stratégies d'accéleration d'inférence en s'aidant de bibliothèques diverses. Pour résumer donc, sans vRAM de compétition sur sa machine ou même avec une RAM CPU un peu limitée (moins de 16G) et sans serveur à dispo, cela peut être un peu la galère de bidouiller soi-même sur des LLM car même des tâches d'inférence de base (même en s'appuyant sur les petits modèles ou des modèles fortement compressés) ont parfois des vitesses d'exécution très lente, sans parler d'opérations de fine-tuning ou de quantization qui deviennent quasi impossibles.

enter image description here

Source : https://code.pieces.app/blog/how-to-run-an-llm-locally-with-pieces

Cela dit, une des évolutions principales des développements technologiques autour de l'IA générative tient justement dans la mise à disposition à la fois de solutions locales et d'environnements cloud qui lèvent certaines barrières d'infrastructure pour le quidam moyen souhaitant réaliser ses tests et développements. Plusieurs outils existent, plus ou moins compliqués à installer selon son hardware et avec des résultats plus ou moins satisfaisants, l'environnement souhaitable dépend évidemment fortement du projet et des modèles utilisés, et de plus toutes les solutions ne sont pas exclusives les unes des autres, mais au final et à l'usage, voici les solutions que personnellement j'utilise le plus couramment :


  • en local (depuis des notebooks, ou des applications conteneurisées ou pas) :
    • sans télécharger de modèle : les appels à l'API d'inférence d'HuggingFace
    • sans télécharger de modèle : les appels à l'API d'inférence de Groq. Groq est une startup venant concurrencer Nvidia sur le marché des puces dédiées à l'IA en développant une nouvelle architecture de puces nommée LPU capable de processer plus de 400 tokens/seconde. Moralité : le moteur LPU fournit une rapidité d'exécution d'opérations d'inférence assez impressionante, qu'il est possible de tester via une UI grand public, un playground, une API Rest et un client Python. Pour le moment tout cela est gratuit dans une limite trrrrrès large de 14400 requêtes à l'API par jour...
    • sans télécharger de modèle : les appels à l'API d'inférence du cloud Nvidia pour éviter tout problème de latence via un compte gratuit sur https://www.nvidia.com/en-us/ai-data-science/foundation-models/. L'ouverture du compte donne droit à un crédit de 1000 requêtes sur les principaux modèles de fondation (via leurs endpoints) hebergés sur l'infrastructure Nviadia, ce qui est pas mal...
    • impliquant le téléchargement de modèles : la librairie Ollama (cf plus bas)
    • impliquant le téléchargement de modèles : les Llamafiles (cf plus bas)
  • solutions cloud
    • Les Colab Notebooks : quand j'ai besoin de GPU à la demande et gratuitement pour faire tourner des scripts et quand je ne veux pas télécharger de modèles en local
    • Intel® Developer Cloud: idem car en plus de pouvoir louer à la demande des instances sur des machines avec processeurs Intel, un compte sur le developer cloud permet de bénéficier gratuitement d'un environnement JupyterLab dimensionné pour les calculs intensifs. A noter qu'Intel propose aussi les packages python open source pour accélerer l'inférence et la quantization sur CPU installables via pip comme n'importe quelle autre librairie (exemple : https://towardsdatascience.com/improving-llm-inference-latency-on-cpus-with-model-quantization-28aefb495657)
    • Tensordock : quand j'ai besoin de faire tourner une application conteneurisée (ou une stack d'applications conteneurisées) sur un serveur GPU puissant et ouvert. Tensordock est une plateforme permettant de louer à la demande n'importe quelle infrastructure sur un serveur localisé n'importe où dans le monde, payant (mais très modéré) et super pratique pour déployer une app sans latence et accessible sur le web

Serveur d'inférence

Un niveau central d'abstraction pour simplifier l'accès programmatique aux LLM est la notion de serveur d'inférence qui désigne le fait de passer les bibliothèques de bas niveau en backend et de proposer un front sous forme de CLI, d'API ou encore de Client (voire les trois) pour l'interaction avec les modèles. Concernant l'accès aux LLM via des API d'inférence, un standard s'installe petit à petit concernant la mise à disposition de serveur d'inférence qui n'est autre que celui d'OpenAI, et l'on retrouve cette homogénéisation des pratiques dans les mentions "OpenAI-compatible API" ou "OpenAI-like server" dans la documentation de plus en plus d'outils. Cette compatibilité consiste à fournir des endpoints similaires à ceux qu'OpenAI a mis en place pour ses API, et/ou à pouvoir utiliser le client d'OpenAI avec d'autres modèles en en ajustant les paramètres. Concrètement, le routage désormais standard pour faire de la complétion est /v1/chat/completions et, pour Ollama qui par exemple fournit désormais un endpoint compatible avec le format OpenAI, le code basique avec le client OpenAI sur un LLM ouvert servi par un Ollama local s'écrit :

import os
import openai

client = openai.OpenAI(
    api_key="whatever",
    base_url="http://localhost:11434/v1",
    )
chat_completion = client.chat.completions.create(
    model="<any_ollama_model>",
    messages=[
        {"role": "system", "content": "<system_content>"},
        {"role": "user", "content": "<user_content>"},
    ],
)
response = chat_completion.choices[0].message.content

De la même manière, l'endpoint standard pour générer des embeddings est /v1/embeddings, pour lister les modèles accessibles /v1/models etc.... (voir la doc de l'API d'OpenAI https://platform.openai.com/docs/api-reference)

Librairie Transformers

La librairie open-source Transformers d'HuggingFace est un package d'API de bas niveau décliné en plusieurs langages (python, js, go...) basé sur PyTorch et TensorFlow qui permet en quelques lignes de code d'exécuter toutes les tâches pour lesquelles les modèles de NLP ont été pré-entraînés, ainsi que les manipulations associées (téléchargement, tokenization, quantization, pipeline d'inférence...)

Par exemple en python d'analyse de sentiments :

from transformers import pipeline
pipe = pipeline("text-classification")
pipe(["the XSLT language is the most convenient for handling xml", "Angular 2 is a purge"])

# returns [{'label': 'POSITIVE', 'score': 0.8357490301132202},{'label': 'NEGATIVE', 'score': 0.9920245409011841}]

Depuis l'interface d'HuggingFace, le code à utiliser avec la librairie Transformers pour chaque modèle est illustré depuis le bouton "Use in Transformers" de la carte du modèle

enter image description here

Toute la doc est disponible ici. Voir aussi cette page sur Kaggle spéficique sur les pipelines. Voir aussi ce billet précédent pour l'aspect tokenisation et embeddings.

A noter que la librairie Transformers télécharge et met en cache le modèle à la première utilisation, puis l'appelle depuis le cache pour les requêtes suivantes, il faut donc prévoir l'espace nécessaire pour les gros modèles. Il est également possible de choisir l'emplacement de stockage du modèle

from huggingface_hub import snapshot_download
from transformers import AutoTokenizer, AutoModelForCausalLM

PROJECT_PATH_DIR = ""E:/huggingface/models"

# Download et mise en cache du modèle
snapshot_download(repo_id="ibm-granite/granite-3b-code-base", cache_dir=f"{PROJECT_PATH_DIR}/granite-3b-code-base", local_dir=f"{PROJECT_PATH_DIR}/granite-3b-code-base")

tokenizer = AutoTokenizer.from_pretrained(f"{PROJECT_PATH_DIR}/granite-3b-code-base")
model = AutoModelForCausalLM.from_pretrained(f"{PROJECT_PATH_DIR}/granite-3b-code-base")

Client d'inference de HuggingFace

HuggingFace met aussi à disposition un client d’inférence construit sur sa librairie Transformers qui peut pointer sur 2 types de services :

  • une API d'inférence : un service gratuit qui permet de requêter un LLM hébergé sur les serveurs d’HF. Tous les modèles ne sont pas accessibles de cette manière, notamment en fonction de leur taille et/ou de leur licence d’utilisation. Pour savoir si l'on peut requêter un modèle avec cette API, il fait se référer à l'information correspondante sur sa notice

enter image description here

enter image description here

  • des endpoints d'inférence pour des modèles déployés sur l’infrastructure d’HuggingFace ou sur un fournisseur de cloud. Ce service est payant de manière variable selon l’infrastructure sur laquelle est déployée l’endpoint. A noter que cette fonctionnalité revient à louer facilement du GPU via la plateforme d’HuggingFace, ce qui peut se révéler bien pratique pour faire tourner de gros modèles nécessitant de la RAM GPU (mais par contre ce n'est plus gratuit ;))

enter image description here

Client d'API

Comme le montre le 2ème screenshot, le serveur d'API d'un LLM est requêtable comme n'importe quelle autre API (avec Curl, avec la librarie requests ou le client urlib3 en python par exemple, avec l'API fetch ou la librarie axios en JS...). On peut également recourir au client d’inférence d'HuggingFace pour se simplifier la vie avec un wrapper qui permet de simplifier la requête. L'exemple suivant labelise une image avec pour chaque label un certain degré de confiance déterminé par le modèle

from huggingface_hub import InferenceClient
HF_TOKEN = "your_huggingface_token"

client = InferenceClient(token=HF_TOKEN)
client.image_classification("https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Zermatt_Marathon_2017_Riffelberg.jpg/640px-Zermatt_Marathon_2017_Riffelberg.jpg")

#returns [ImageClassificationOutputElement(label='alp', score=0.9645039439201355),
 ImageClassificationOutputElement(label='valley, vale', score=0.01940244808793068),
 ImageClassificationOutputElement(label='mountain bike, all-terrain bike, off-roader', score=0.00558288162574172),
 ImageClassificationOutputElement(label='ski', score=0.00039877466042526066),
 ImageClassificationOutputElement(label='cowboy boot', score=0.00036375492345541716)]

Le même appel au client en précisant explicitement un modèle :

client = InferenceClient(model="facebook/deit-small-distilled-patch16-224",token=HF_TOKEN)

Bonus

Vous pouvez tester l'inférence sur le LLM de votre choix en fonction de plusieurs types de tâches dans cette application développé vite fait pour illustrer ce post : https://huggingface.co/spaces/Geraldine/hf_inference_client_demo enter image description here

  • Le code de l'application est disponible sur ce dépôt Github
  • A noter que la version déployée sur HF génère un message d'errreur lors de la récupération d'un fichier image en ligne, mais que le bug ne se produit pas en local...*

A noter :

  • il faut se créer un compte sur HuggingFace et générer ensuite un API token dans les paramètres du compte pour requêter l'API d'inférence. En théorie l'authentification n'est pas obligatoire pour utiliser l'API sur un modèle public mais préférable pour garantir un accès "préférentiel" sur la masse des requêtes
  • dans son paramétrage le plus simple, il n’est même pas besoin de préciser le modèle à utiliser, le client choisissant lui-même le plus pertinent en fonction, mais il est possible de passer le modèle de son choix en argument
  • la limite d’usage de l’API n’est pas clairement explicitée mais elle existe, ce type d’accès est donc très intéressant pour tester des modèles mais non recommandé en production.

Comment s'y retrouver dans l'interface d'HuggingFace ?

Pas facile en effet de s'orienter dans ce catalogue de plus de 300 000 modèles ! Le point d'entrée par tâches peut aider de ce point de vue : https://huggingface.co/tasks, ou en s''aidant des filtres depuis la page d'accès par modèles https://huggingface.co/models

enter image description here

La suite ici...

"> ');