Local AI

Optimiser Ollama pour l'inférence concurrentielle multi-utilisateurs : Gestion des fenêtres de contexte et de l'allocation VRAM

Le déploiement de grands modèles de langage locaux (LLM) est devenu une pratique standard pour les développeurs recherchant confidentialité, faible latence et efficacité des coûts. Bien qu'Ollama simplifie l'exécution de ces modèles, le passage d'un environnement de développement mono-utilisateur à un environnement de production multi-utilisateurs introduit des défis complexes de gestion des ressources. Les principaux goulets d'étranglement sont la fragmentation de la mémoire vidéo (VRAM) et l'épuisement des fenêtres de contexte. Ce guide explore les stratégies pour maximiser la concurrence sans compromettre la qualité ou la stabilité de l'inférence.

Le problème de la concurrence VRAM

Contrairement aux API cloud où l'inférence est distribuée sur d'immenses clusters, l'inférence locale repose sur la mémoire GPU discrète de votre matériel. Par défaut, Ollama charge les poids du modèle dans la VRAM. Lorsque plusieurs utilisateurs demandent une inférence simultanément, le système doit décider s'il doit maintenir les modèles existants en mémoire ou les évincer pour charger de nouveaux modèles. Ce "thrashing" entraîne des pics de latence significatifs car les poids sont constamment échangés entre la RAM CPU et la VRAM GPU.

Une gestion efficace de la VRAM nécessite de comprendre l'empreinte mémoire d'un modèle. La formule pour l'utilisation approximative de la VRAM est :

Utilisation VRAM ≈ (Paramètres du modèle × Octets par poids) + (Longueur du contexte × Têtes d'attention × Taille du Dtype)

Pour un modèle de 7 milliards de paramètres quantifié en 4 bits (Q4_K_M), la taille de base des poids est d'environ 4 Go. Cependant, la fenêtre de contexte ajoute une surcharge dynamique. Une fenêtre de contexte de 4 096 jetons sur une couche d'attention FP16 peut ajouter plusieurs centaines de Mo. Pour atténuer ce problème, vous devriez standardiser les tailles de contexte dans votre déploiement pour éviter des pics de mémoire imprévisibles.

Stratégies pour l'inférence concurrentielle

Il existe trois approches principales pour gérer les charges multi-utilisateurs dans Ollama :

  1. Épinglage de modèle : Maintenir les modèles populaires en mémoire. C'est idéal pour les scénarios à haut débit avec un ensemble fixe de modèles.
  2. Offloading agressif : Utiliser le drapeau `num_gpu` d'Ollama pour contrôler combien de couches restent sur le GPU. Cela permet à de plus petits modèles de coexister, mais augmente le temps d'inférence CPU.
  3. Mise en file d'attente des requêtes : Mettre en place une file d'attente au niveau de l'application pour sérialiser les requêtes si votre matériel ne peut pas gérer un parallélisme réel.

Configuration d'Ollama pour la stabilité

Bien qu'Ollama gère la planification en interne, vous pouvez influencer son comportement via des variables d'environnement et des paramètres API. D'abord, définissez explicitement vos limites de VRAM. Si vous avez un GPU NVIDIA, assurez-vous d'utiliser les derniers pilotes pour prendre en charge CUDA 12.0+ pour une meilleure gestion de la mémoire.

Lors du démarrage de votre instance Ollama, envisagez de définir la variable d'environnement `OLLAMA_MAX_LOADED_MODELS`. Cela limite le nombre de modèles qui peuvent être chargés simultanément, empêchant les erreurs OOM (Out of Memory) sous forte charge.

export OLLAMA_MAX_LOADED_MODELS=2
export OLLAMA_GPU_OVERHEAD=1024 # Mo
docker run -d \
  -e OLLAMA_MAX_LOADED_MODELS=$OLLAMA_MAX_LOADED_MODELS \
  -e OLLAMA_GPU_OVERHEAD=$OLLAMA_GPU_OVERHEAD \
  -p 11434:11434 \
  ollama/ollama:latest

Gestion dynamique des fenêtres de contexte

Toutes les requêtes n'exigent pas la même longueur de contexte. L'assistance au codage bénéficie souvent de contextes longs, tandis que les tâches simples de résumation non. Pour optimiser la VRAM, vous devriez imposer des limites de contexte dynamiques au niveau de l'API.

Voici un exemple en Python utilisant `requests` pour démontrer comment spécifier une fenêtre de contexte plus stricte (`num_ctx`) pour une tâche spécifique, garantissant que le modèle n'alloue pas de VRAM inutile pour les tampons d'attention :

import requests

def generate_response(prompt, num_ctx=2048):
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={
            "model": "llama3:8b",
            "prompt": prompt,
            "stream": False,
            "options": {
                "num_ctx": num_ctx,
                "temperature": 0.7
            }
        }
    )
    return response.json().get("response")

# Exemple : Court contexte pour des Q&R rapides
quick_answer = generate_response("Qu'est-ce que Python ?", num_ctx=512)
print(quick_answer)

Surveillance et alertes

L'optimisation est un processus itératif. Vous devez surveiller l'utilisation de votre GPU en temps réel. Des outils comme `nvidia-smi` ou `nvtop` sont essentiels. Recherchez les métriques suivantes :

  • Utilisation de la mémoire GPU : Devrait rester en dessous de 90 % de la VRAM totale pour permettre la surcharge du système d'exploitation.
  • Utilisation du GPU : Une forte utilisation avec une faible latence indique un bon batch processing. Une forte utilisation avec une forte latence peut indiquer un thrashing mémoire.

Intégrez ces métriques dans votre pile de surveillance (par exemple, Prometheus avec `node_exporter`) pour déclencher des alertes lorsque l'utilisation de la VRAM dépasse les seuils de sécurité.

Conclusion

L'optimisation d'Ollama pour l'inférence concurrentielle multi-utilisateurs ne consiste pas à forcer le matériel, mais à une allocation intelligente des ressources. En limitant le nombre de modèles chargés, en standardisant les fenêtres de contexte et en surveillant l'utilisation de la VRAM, vous pouvez obtenir des services IA locaux stables et à faible latence. Commencez par des paramètres conservateurs, profilez votre charge de travail et ajustez les paramètres en fonction de données empiriques. À mesure que les modèles IA locaux continuent de diminuer et de devenir plus efficaces, ces stratégies resteront critiques pour construire des applications évolutives et axées sur la confidentialité.

Share: