LLM et IA Générative
Small Language Models (SLM)
Modèles compacts pour l'edge AI - Phi, Gemma, Qwen et l'inférence on-device
Small Language Models (SLM)
Les Small Language Models sont des modèles de langage compacts (1-7B paramètres) optimisés pour fonctionner sur des appareils avec des ressources limitées : smartphones, ordinateurs portables, objets connectés.
Pourquoi les SLM ?
┌─────────────────────────────────────────────────────────────────┐
│ LLM vs SLM : COMPROMIS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ LARGE LANGUAGE MODELS (70B+) SMALL LANGUAGE MODELS (1-7B) │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ ✓ Capacités maximales │ │ ✓ Fonctionne localement │ │
│ │ ✓ Raisonnement complexe │ │ ✓ Latence < 100ms │ │
│ │ ✓ Multilingue complet │ │ ✓ Vie privée totale │ │
│ │ ✗ Cloud obligatoire │ │ ✓ Gratuit à l'usage │ │
│ │ ✗ Latence réseau │ │ ✓ Fonctionne hors-ligne │ │
│ │ ✗ Coût par requête │ │ ✗ Capacités réduites │ │
│ │ ✗ Données envoyées │ │ ✗ Contexte limité │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
│ │
│ GPU REQUIS: GPU REQUIS: │
│ A100/H100 (80GB VRAM) RTX 3060 ou M1/M2/M3 │
│ ~$2-4/heure cloud Gratuit (votre matériel) │
│ │
└─────────────────────────────────────────────────────────────────┘Panorama des SLM en 2024
Microsoft Phi
┌─────────────────────────────────────────────────────────────────┐
│ FAMILLE MICROSOFT PHI │
├─────────────────────────────────────────────────────────────────┤
│ │
│ PHI-1 (1.3B) ─────► PHI-2 (2.7B) ─────► PHI-3 (3.8B) │
│ │ │ │ │
│ │ │ ├── Phi-3-mini │
│ Juin 2023 Déc 2023 ├── Phi-3-small │
│ Code only General └── Phi-3-medium │
│ │
│ INNOVATION CLÉ: "Textbooks Are All You Need" │
│ - Données synthétiques de haute qualité │
│ - Filtrage agressif du contenu web │
│ - Curriculum learning (simple → complexe) │
│ │
│ PERFORMANCES (Phi-3-mini 3.8B): │
│ - MMLU: 69% (vs GPT-3.5: 70%) │
│ - HumanEval: 58.5% │
│ - Fonctionne sur iPhone │
│ │
└─────────────────────────────────────────────────────────────────┘Google Gemma
# Gemma 2 - Modèle open source de Google
# Disponible en 2B, 9B et 27B paramètres
from transformers import AutoModelForCausalLM, AutoTokenizer
# Gemma 2B - fonctionne sur CPU
model = AutoModelForCausalLM.from_pretrained(
"google/gemma-2-2b-it", # "it" = instruction-tuned
device_map="auto",
torch_dtype="auto",
)
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b-it")
messages = [
{"role": "user", "content": "Explique la photosynthèse en 3 phrases."}
]
prompt = tokenizer.apply_chat_template(messages, tokenize=False)
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))Qwen (Alibaba)
┌─────────────────────────────────────────────────────────────────┐
│ FAMILLE QWEN 2.5 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Qwen2.5-0.5B Qwen2.5-1.5B Qwen2.5-3B Qwen2.5-7B │
│ │ │ │ │ │
│ 500M params 1.5B params 3B params 7B params │
│ ~300MB ~900MB ~2GB ~4GB │
│ │
│ SPÉCIALISATIONS: │
│ ├── Qwen2.5-Coder (code, 6 langages) │
│ ├── Qwen2.5-Math (mathématiques) │
│ └── Qwen2.5-VL (vision-langage) │
│ │
│ ATOUTS: │
│ ✓ Excellent support multilingue (29 langues) │
│ ✓ Contexte jusqu'à 128K tokens │
│ ✓ Licence Apache 2.0 (commercial OK) │
│ │
└─────────────────────────────────────────────────────────────────┘Llama 3.2 (Meta)
# Llama 3.2 - Versions légères pour mobile
# 1B et 3B paramètres optimisés pour l'edge
import torch
from transformers import pipeline
# Llama 3.2 1B - Ultra léger
pipe = pipeline(
"text-generation",
model="meta-llama/Llama-3.2-1B-Instruct",
torch_dtype=torch.bfloat16,
device_map="auto",
)
response = pipe(
"Écris une fonction Python pour trier une liste.",
max_new_tokens=200,
do_sample=True,
temperature=0.7,
)
print(response[0]["generated_text"])Comparatif des SLM
| Modèle | Taille | MMLU | HumanEval | Contexte | Licence |
|---|---|---|---|---|---|
| Phi-3-mini | 3.8B | 69% | 58.5% | 128K | MIT |
| Gemma-2-2B | 2B | 51% | 26% | 8K | Gemma |
| Qwen2.5-3B | 3B | 65% | 45% | 128K | Apache 2.0 |
| Llama-3.2-3B | 3B | 63% | 48% | 128K | Llama 3.2 |
| Mistral-7B | 7B | 62% | 30% | 32K | Apache 2.0 |
Edge AI et inférence on-device
Architecture Edge
┌─────────────────────────────────────────────────────────────────┐
│ ARCHITECTURE EDGE AI │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ CLOUD │ ← Modèles 70B+, entraînement │
│ │ (backup) │ Fallback pour tâches complexes │
│ └──────┬───────┘ │
│ │ API (si nécessaire) │
│ │ │
│ ┌──────▼───────┐ │
│ │ EDGE │ ← Serveur local, NAS, Raspberry Pi │
│ │ SERVER │ Modèles 7-13B, cache partagé │
│ └──────┬───────┘ │
│ │ LAN │
│ │ │
│ ┌──────▼───────┐ │
│ │ DEVICE │ ← Smartphone, laptop, IoT │
│ │ (on-chip) │ Modèles 1-3B, temps réel │
│ └──────────────┘ │
│ │
│ CRITÈRES DE ROUTAGE: │
│ - Complexité de la tâche │
│ - Sensibilité des données │
│ - Latence requise │
│ - Disponibilité réseau │
│ │
└─────────────────────────────────────────────────────────────────┘Runtimes pour l'edge
# 1. LLAMA.CPP - C++ ultra-optimisé
# Installation: brew install llama.cpp (macOS)
# Depuis le terminal:
# ./llama-cli -m phi-3-mini-4k-instruct-q4_K_M.gguf \
# -p "Explique le machine learning" \
# -n 200
# 2. OLLAMA - Simplifié pour développeurs
"""
# Installation et utilisation Ollama
ollama pull phi3
ollama run phi3 "Qu'est-ce que l'edge computing?"
# API REST
curl http://localhost:11434/api/generate -d '{
"model": "phi3",
"prompt": "Hello!"
}'
"""
# 3. MLX (Apple Silicon)
import mlx.core as mx
from mlx_lm import load, generate
model, tokenizer = load("mlx-community/Phi-3-mini-4k-instruct-4bit")
response = generate(
model,
tokenizer,
prompt="Écris un haiku sur l'IA",
max_tokens=50
)
print(response)Optimisations pour mobile
┌─────────────────────────────────────────────────────────────────┐
│ OPTIMISATIONS POUR MOBILE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. QUANTIZATION │
│ ├── FP32 → FP16 (÷2 mémoire) │
│ ├── FP16 → INT8 (÷2 mémoire) │
│ └── INT8 → INT4 (÷2 mémoire) │
│ │
│ Phi-3 3.8B: │
│ - FP32: 15.2 GB ❌ │
│ - FP16: 7.6 GB ❌ │
│ - INT8: 3.8 GB ⚠️ │
│ - INT4: 1.9 GB ✓ (iPhone 15 Pro) │
│ │
│ 2. PRUNING (élagage) │
│ Suppression des poids proches de zéro │
│ → 50-90% de sparsité possible │
│ │
│ 3. DISTILLATION │
│ Grand modèle → Petit modèle │
│ → Transfère les connaissances │
│ │
│ 4. SPECULATIVE DECODING │
│ Petit modèle génère drafts │
│ Grand modèle valide en batch │
│ → 2-3x speedup │
│ │
└─────────────────────────────────────────────────────────────────┘Cas d'usage edge
Assistant hors-ligne
import ollama
class OfflineAssistant:
"""Assistant fonctionnant entièrement hors-ligne"""
def __init__(self, model="phi3"):
self.model = model
self.conversation = []
def chat(self, message: str) -> str:
self.conversation.append({
"role": "user",
"content": message
})
response = ollama.chat(
model=self.model,
messages=self.conversation,
options={
"num_ctx": 4096, # Contexte limité pour la vitesse
"temperature": 0.7,
}
)
assistant_message = response["message"]["content"]
self.conversation.append({
"role": "assistant",
"content": assistant_message
})
return assistant_message
# Utilisation
assistant = OfflineAssistant()
print(assistant.chat("Bonjour! Peux-tu m'aider avec Python?"))
# Fonctionne sans internet, données restent localesClassification locale de documents
from transformers import pipeline
import torch
# Modèle léger pour classification
classifier = pipeline(
"zero-shot-classification",
model="MoritzLaworski/mDeBERTa-v3-base-mnli-xnli", # 278M params
device="mps" if torch.backends.mps.is_available() else "cpu"
)
def classify_document(text: str, labels: list[str]) -> dict:
"""Classifie un document localement"""
result = classifier(
text,
candidate_labels=labels,
multi_label=True
)
return {
label: score
for label, score in zip(result["labels"], result["scores"])
if score > 0.3
}
# Exemple
doc = "Le nouveau modèle Tesla atteint 600km d'autonomie"
categories = ["automobile", "technologie", "finance", "sport"]
print(classify_document(doc, categories))
# {'automobile': 0.92, 'technologie': 0.45}IoT et capteurs intelligents
# Modèle minuscule pour microcontrôleurs
# TinyML avec TensorFlow Lite
"""
Exemple conceptuel pour ESP32 ou Raspberry Pi Pico
"""
class TinyPredictor:
"""Prédicteur ultra-léger pour microcontrôleur"""
def __init__(self, model_path: str):
# Modèle TFLite quantifié INT8 (~100KB)
import tflite_runtime.interpreter as tflite
self.interpreter = tflite.Interpreter(model_path=model_path)
self.interpreter.allocate_tensors()
def predict_anomaly(self, sensor_data: list[float]) -> bool:
"""Détecte anomalies sur données capteur"""
input_details = self.interpreter.get_input_details()
output_details = self.interpreter.get_output_details()
# Préparer l'entrée
import numpy as np
input_data = np.array([sensor_data], dtype=np.float32)
self.interpreter.set_tensor(input_details[0]['index'], input_data)
# Inférence (~10ms sur ESP32)
self.interpreter.invoke()
# Résultat
output = self.interpreter.get_tensor(output_details[0]['index'])
return output[0][0] > 0.5 # Anomalie si > 0.5
# Déploiement sur device
predictor = TinyPredictor("anomaly_detector.tflite")
is_anomaly = predictor.predict_anomaly([23.5, 45.2, 1.02])Déploiement d'un SLM
Application mobile avec Llama.cpp
// iOS - Utilisation de llama.cpp via Swift
import Foundation
class LocalLLM {
private var context: OpaquePointer?
init(modelPath: String) {
// Initialiser llama.cpp
var params = llama_model_default_params()
params.n_gpu_layers = 1 // Utiliser le GPU si disponible
let model = llama_load_model_from_file(modelPath, params)
self.context = llama_new_context_with_model(model, llama_context_default_params())
}
func generate(prompt: String, maxTokens: Int = 100) -> String {
// Tokenize et génère
// ... implémentation llama.cpp
return generatedText
}
}
// Utilisation dans une app iOS
let llm = LocalLLM(modelPath: Bundle.main.path(forResource: "phi-3-mini", ofType: "gguf")!)
let response = llm.generate(prompt: "Bonjour!")Serveur edge avec Ollama
# docker-compose.yml pour serveur edge
"""
version: '3.8'
services:
ollama:
image: ollama/ollama
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- capabilities: [gpu]
volumes:
ollama_data:
"""
# Client Python
import httpx
class EdgeLLMClient:
def __init__(self, base_url="http://localhost:11434"):
self.base_url = base_url
self.client = httpx.Client(timeout=60.0)
def generate(self, prompt: str, model: str = "phi3") -> str:
response = self.client.post(
f"{self.base_url}/api/generate",
json={
"model": model,
"prompt": prompt,
"stream": False,
}
)
return response.json()["response"]
def available_models(self) -> list[str]:
response = self.client.get(f"{self.base_url}/api/tags")
return [m["name"] for m in response.json()["models"]]
# Utilisation
client = EdgeLLMClient()
print(client.generate("Résume cet article: ..."))Benchmarks edge
┌─────────────────────────────────────────────────────────────────┐
│ PERFORMANCES EDGE RÉELLES │
├─────────────────────────────────────────────────────────────────┤
│ │
│ DEVICE: MacBook Air M2 (8GB RAM) │
│ MODEL: Phi-3-mini-4k-instruct (Q4_K_M) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Métrique │ Valeur │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ Tokens/seconde │ 35-40 tok/s │ │
│ │ Time to first token │ ~200ms │ │
│ │ Mémoire utilisée │ 2.1 GB │ │
│ │ Taille modèle │ 2.2 GB (GGUF Q4) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ DEVICE: iPhone 15 Pro (8GB RAM) │
│ MODEL: Phi-3-mini (CoreML INT4) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Métrique │ Valeur │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ Tokens/seconde │ 15-20 tok/s │ │
│ │ Time to first token │ ~500ms │ │
│ │ Impact batterie │ Modéré │ │
│ │ Taille app │ ~2 GB avec modèle │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ DEVICE: Raspberry Pi 5 (8GB) │
│ MODEL: Gemma-2B (GGUF Q4) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Métrique │ Valeur │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ Tokens/seconde │ 5-8 tok/s │ │
│ │ Time to first token │ ~2s │ │
│ │ Utilisable │ Oui (tâches simples) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘Limites et considérations
┌─────────────────────────────────────────────────────────────────┐
│ LIMITES DES SLM │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ⚠ Capacités réduites vs grands modèles │
│ - Raisonnement multi-étapes limité │
│ - Moins fiable sur tâches complexes │
│ - Connaissances moins étendues │
│ │
│ ⚠ Trade-offs de la quantization │
│ - Légère perte de qualité (1-3%) │
│ - Certaines tâches sensibles à la précision │
│ │
│ ⚠ Maintenance │
│ - Mises à jour manuelles du modèle │
│ - Pas de correction automatique des bugs │
│ │
│ BONNES PRATIQUES: │
│ ✓ Choisir le modèle adapté à la tâche │
│ ✓ Prévoir un fallback cloud pour cas complexes │
│ ✓ Tester sur le hardware cible avant déploiement │
│ ✓ Monitorer la qualité des réponses │
│ │
└─────────────────────────────────────────────────────────────────┘