191 lines
9.4 KiB
Markdown
191 lines
9.4 KiB
Markdown
|
||
---
|
||
|
||
je sais utiliser ollama.py, j'ai un ordi avec 32G de RAM,
|
||
Je voudrais me mettre au Hugging Face Hub, avec des petits modèles : Qwen 2.5 0.5B pour le français, SmolLM2 360M pour l’anglais. Phi-3 Mini Gemma 2 2B, etc...
|
||
tu peux m'expliquer comment faire ? faut-il utiliser transformer.py de hugging face ?
|
||
|
||
---
|
||
|
||
Oui, utiliser `transformers.py` de Hugging Face est exactement la bonne approche pour charger et utiliser ces modèles. C'est la bibliothèque principale de la plateforme.
|
||
|
||
Pour te lancer avec tes modèles (Qwen 2.5 0.5B, SmolLM2 360M, etc.), voici les clés à retenir, en partant de ce que tu connais avec Ollama.
|
||
|
||
### Le cœur de la méthode : `AutoModelForCausalLM` et `AutoTokenizer`
|
||
|
||
La manière standard et la plus simple est d'utiliser les classes `AutoModelForCausalLM` et `AutoTokenizer` . Le préfixe `Auto` est pratique car il permet de charger n'importe quel modèle sans avoir à connaître sa classe exacte .
|
||
|
||
```python
|
||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||
|
||
nom_du_modele = "Qwen/Qwen2.5-0.5B-Instruct" # Par exemple
|
||
|
||
tokenizer = AutoTokenizer.from_pretrained(nom_du_modele)
|
||
modele = AutoModelForCausalLM.from_pretrained(
|
||
nom_du_modele,
|
||
device_map="auto", # Laisse transformers gérer l'emplacement (CPU/GPU)
|
||
torch_dtype="auto" # Laisse le modèle choisir le type de données (float16, bfloat16...)
|
||
)
|
||
```
|
||
|
||
Pour un modèle comme **SmolLM2**, ce serait `"HuggingFaceTB/SmolLM2-360M-Instruct"` .
|
||
|
||
### Le rôle crucial du tokenizer
|
||
|
||
Le tokenizer ne se contente pas de découper le texte. Pour les modèles de type "Instruct" (comme ceux que tu as listés), il **doit** appliquer un *chat template*. Ce template ajoute les tokens spéciaux (comme `<|im_start|>` pour Qwen ou `<start_of_turn>` pour Gemma) qui indiquent au modèle où commence le rôle de l'utilisateur, celui de l'assistant, etc. .
|
||
|
||
C'est la méthode `apply_chat_template()` qui s'en charge :
|
||
|
||
```python
|
||
messages = [
|
||
{"role": "user", "content": "Quelle est la capitale de la France ?"}
|
||
]
|
||
|
||
# Générer le prompt formaté
|
||
prompt_formate = tokenizer.apply_chat_template(
|
||
messages,
|
||
tokenize=False, # On veut le texte, pas les IDs pour l'instant
|
||
add_generation_prompt=True # Ajoute le token pour que le modèle commence à répondre
|
||
)
|
||
|
||
# Tokenizer le prompt pour le modèle
|
||
inputs = tokenizer(prompt_formate, return_tensors="pt").to(modele.device)
|
||
```
|
||
|
||
### Générer la réponse
|
||
|
||
Enfin, on utilise la méthode `generate()` du modèle, en veillant à ne garder que la nouvelle partie générée (sans le prompt).
|
||
|
||
```python
|
||
outputs = modele.generate(**inputs, max_new_tokens=500)
|
||
|
||
# Décoder uniquement la nouvelle partie
|
||
reponse = tokenizer.decode(outputs[0][inputs['input_ids'].shape[-1]:], skip_special_tokens=True)
|
||
print(reponse)
|
||
```
|
||
|
||
### Conseils pour ton ordinateur de 32 Go de RAM
|
||
|
||
Tes choix de modèles sont parfaits pour une machine comme la tienne.
|
||
|
||
* **Les modèles très légers (0.5B, 360M)** : Ils sont conçus pour tourner sur des appareils avec des ressources limitées. Par exemple, un modèle SmolLM2 360M n'utilise qu'environ **700 Mo** de mémoire pour l'inférence . Le Qwen 2.5 0.5B est un excellent choix pour le français .
|
||
* **Optimisation pour les modèles plus gros** : Pour des modèles comme Phi-3 Mini (3.8B) ou Gemma 2 2B, tu peux utiliser la quantification (par exemple, des modèles en `4-bit` comme ceux trouvés sur le Hub) pour réduire drastiquement leur empreinte mémoire. Avec 32 Go de RAM, tu as de la marge.
|
||
* **Stabilité sur Mac (MPS)** : Si tu es sur un Mac récent avec puce M, tu pourras utiliser l'accélération GPU (`device_map="mps"`). Attention : pour un entraînement (fine-tuning), il est parfois plus stable d'utiliser le type `torch.float32` plutôt que `float16` pour éviter des erreurs de calcul (NaN) . Pour la simple inférence, ce ne sera pas un problème.
|
||
|
||
### L'alternative : `pipeline()`
|
||
|
||
Pour une prise en main encore plus rapide, la fonction `pipeline()` de Transformers est idéale . Elle gère automatiquement la tokenisation et la génération.
|
||
|
||
```python
|
||
from transformers import pipeline
|
||
|
||
generateur = pipeline("text-generation", model="Qwen/Qwen2.5-0.5B-Instruct")
|
||
resultat = generateur([{"role": "user", "content": "Bonjour !"}], max_new_tokens=100)
|
||
print(resultat[0]['generated_text'])
|
||
```
|
||
|
||
En résumé, `transformers.py` est l'outil par excellence pour tes besoins. Commence par charger un modèle, joue avec `apply_chat_template()` et `generate()`, et tu maîtriseras vite le fonctionnement.
|
||
|
||
N'hésite pas si tu as d'autres questions, par exemple sur le chargement d'un modèle quantifié pour économiser encore plus de mémoire !
|
||
|
||
---
|
||
|
||
ok et comment je fais pour être vraiment en local, c'est-à-dire avec ollama je fais un ollama pull <mon_modèle>, là je fais comment pour récupérer le modèle ?
|
||
|
||
---
|
||
|
||
Avec Hugging Face, le processus est un peu différent d'`ollama pull`. Tu ne télécharges pas un seul fichier `.gguf` comme avec Ollama, mais un dossier complet contenant le modèle, son tokenizer et sa configuration. Tu as plusieurs options, du plus automatique au plus manuel.
|
||
|
||
### 💡 Méthode 1 : Le téléchargement automatique avec `transformers`
|
||
|
||
C'est la méthode que tu as déjà vue, mais avec l'assurance que tout reste local.
|
||
|
||
Quand tu utilises `AutoModelForCausalLM.from_pretrained("nom_du_modele")`, le code va automatiquement :
|
||
1. **Vérifier le cache** : Par défaut, les modèles sont stockés dans `~/.cache/huggingface/transformers/` .
|
||
2. **Télécharger** : Si le modèle n'est pas trouvé, il sera téléchargé depuis le Hub de Hugging Face.
|
||
|
||
Pour garantir qu'il ne cherche **jamais** à se connecter à internet (même si le modèle est manquant), tu peux utiliser l'option `local_files_only=True` .
|
||
|
||
```python
|
||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||
|
||
nom_du_modele = "Qwen/Qwen2.5-0.5B-Instruct"
|
||
|
||
# La première exécution va télécharger le modèle.
|
||
# Les suivantes le chargeront depuis le cache.
|
||
tokenizer = AutoTokenizer.from_pretrained(nom_du_modele)
|
||
modele = AutoModelForCausalLM.from_pretrained(
|
||
nom_du_modele,
|
||
device_map="auto",
|
||
torch_dtype="auto"
|
||
)
|
||
|
||
# Pour être sûr de ne jamais utiliser Internet (mode hors-ligne) :
|
||
# tokenizer = AutoTokenizer.from_pretrained(nom_du_modele, local_files_only=True)
|
||
# modele = AutoModelForCausalLM.from_pretrained(nom_du_modele, local_files_only=True)
|
||
```
|
||
|
||
Tu peux aussi personnaliser l'emplacement du cache avec le paramètre `cache_dir` ou la variable d'environnement `HF_HOME` .
|
||
|
||
### 🧩 Méthode 2 : Téléchargement via `huggingface_hub` (équivalent de `pull`)
|
||
|
||
Cette approche te donne un contrôle plus granulaire. Elle est idéale pour pré-télécharger un modèle ou pour gérer des cas particuliers comme les modèles au format GGUF .
|
||
|
||
```python
|
||
from huggingface_hub import snapshot_download
|
||
|
||
# Télécharge tout le modèle dans le dossier "./mon_dossier_qwen"
|
||
snapshot_download(
|
||
repo_id="Qwen/Qwen2.5-0.5B-Instruct",
|
||
local_dir="./mon_dossier_qwen",
|
||
local_dir_use_symlinks=False # Désactive les liens symboliques pour avoir une copie réelle
|
||
)
|
||
```
|
||
|
||
Une fois téléchargé, tu peux charger le modèle depuis ce dossier local :
|
||
```python
|
||
tokenizer = AutoTokenizer.from_pretrained("./mon_dossier_qwen")
|
||
modele = AutoModelForCausalLM.from_pretrained("./mon_dossier_qwen")
|
||
```
|
||
|
||
### 📁 Pour mémoire : La structure d'un modèle Hugging Face
|
||
|
||
Pour que `transformers` reconnaisse un modèle, son dossier doit contenir des fichiers précis :
|
||
* `config.json` : La configuration du modèle (nombre de couches, etc.) .
|
||
* `pytorch_model.bin` ou `*.safetensors` : Les poids du modèle. C'est l'équivalent du fichier `.gguf` d'Ollama .
|
||
* `tokenizer_config.json`, `vocab.json`, `merges.txt` : Les fichiers nécessaires au tokenizer .
|
||
|
||
### ⚙️ Gérer le mode hors-ligne (comme un pro)
|
||
|
||
L'option `local_files_only=True` est efficace, mais la manière standard est d'utiliser des variables d'environnement, surtout si tu prévois de travailler souvent hors-ligne .
|
||
|
||
Avant d'exécuter ton script, tu peux définir ces variables pour que **tous** les appels à la bibliothèque Hugging Face soient forcés à utiliser le cache local :
|
||
|
||
```bash
|
||
# Dans ton terminal
|
||
export HF_HUB_OFFLINE=1
|
||
export TRANSFORMERS_OFFLINE=1
|
||
```
|
||
Ou en Python :
|
||
```python
|
||
import os
|
||
os.environ["HF_HUB_OFFLINE"] = "1"
|
||
os.environ["TRANSFORMERS_OFFLINE"] = "1"
|
||
```
|
||
|
||
La différence est importante :
|
||
* `local_files_only=True` à l'appel : fonctionne bien, mais doit être passé à chaque fonction.
|
||
* `HF_HUB_OFFLINE=1` : agit comme un "kill switch" global. Même si une bibliothèque tente un téléchargement, elle échouera en levant une erreur, ce qui est parfait pour un environnement de production ou air-gappé .
|
||
|
||
### 📝 En résumé
|
||
|
||
| Action | Avec Ollama | Avec Hugging Face (transformers) |
|
||
| :--- | :--- | :--- |
|
||
| **Télécharger un modèle** | `ollama pull <modèle>` | `AutoModel.from_pretrained("<modèle>")` (télécharge et charge) OU `snapshot_download` (télécharge seulement) |
|
||
| **Charger un modèle** | `ollama run <modèle>` | `AutoModel.from_pretrained("./mon_dossier")` (si déjà téléchargé) |
|
||
| **Stockage** | `~/.ollama/models` (fichiers `.gguf`) | `~/.cache/huggingface/transformers/` |
|
||
| **Garantir le hors-ligne** | (Implicite, pas de téléchargement sans `pull`) | `local_files_only=True` ou `HF_HUB_OFFLINE=1` |
|
||
|
||
La grande force de Hugging Face est sa flexibilité : une fois que tu as téléchargé le dossier d'un modèle, il est totalement autonome. Tu peux le déplacer, le copier, et le charger sans jamais avoir à refaire de requête réseau.
|
||
|
||
|