images | ||
.gitignore | ||
LICENSE | ||
llm-hpc.pdf | ||
llm-hpc.py | ||
README-EN.md | ||
README.md | ||
setup_llm_hpc.sh |
Utiliser des LLM avec Transformers sur un cluster HPC
🚀 Prérequis
- Accès à un cluster HPC (comme VALERIA)
- Connaissances de base en Python
- Compréhension des concepts d'apprentissage automatique
- Accès à une session JupyterLab sur le cluster
💻 Démarrer une session Jupyter avec un GPU
Pour commencer, vous devez lancer une session JupyterLab qui vous donnera accès aux ressources GPU du cluster.
Étape 1 : Accéder à l'interface Jupyter
- Connectez-vous à l'interface web de votre cluster HPC
- Naviguez vers la section JupyterLab
- Cliquez sur "Démarrer un nouveau serveur" pour créer une nouvelle session
Conseil : Assurez-vous d'avoir une connexion internet stable pendant toute la durée de votre session.
Étape 2 : Configurer les ressources de la session
Lorsque vous configurez votre session Jupyter, choisissez les paramètres suivants :
- RAM : Minimum 32 Go (pour les modèles 7B sans quantization)
- CPU : 2 coeurs suffisent (le GPU sera le principal accélérateur)
- GPU : Sélectionnez un GPU disponible sur le cluster
Pourquoi 32 Go de RAM ? Même si le modèle tournera principalement sur GPU, vous avez besoin de RAM locale pour charger les bibliothèques Python et les données initiales.
🛠️ Préparer votre environnement personnalisé
Ces instructions, inspirées de la documentation VALERIA, vous guideront dans la création d'un environnement Python optimisé pour l'exécution de LLM.
Étape 1 : Se connecter à un noeud frontal
Depuis votre session JupyterLab, ouvrez un terminal et connectez-vous à un noeud frontal :
ssh ${IDUL}@login.valeria.science
Qu'est-ce qu'un noeud frontal ? Les noeuds frontaux sont des machines d'accès au cluster que vous utilisez pour préparer votre environnement, compiler du code et lancer des tâches. Ils ne sont pas conçus pour les calculs intensifs.
Les noeuds frontaux se terminent généralement par ul-val-pr-sshXX
.
Étape 2 : Naviguer vers votre espace de travail
Utilisez les commandes cd
pour vous rendre dans votre projet et créez un dossier dédié :
cd /home/ulaval.ca/${IDUL}/projects/${COMPTE_CHERCHEUR}/${PROJET}
mkdir llm-sur-hpc
cd llm-sur-hpc
Étape 3 : Créer une collection de modules
Les modules système vous permettent de gérer facilement les dépendances logicielles. Créez votre propre collection :
export NAME=llm-sur-hpc
module reset
module load python/3.12 cuda/12.6 scipy-stack/2025a
module save $NAME
Comment ça marche ? Cette commande charge les versions spécifiques de Python, CUDA et la stack scientifique, puis sauvegarde cette configuration dans une collection nommée
llm-sur-hpc
.
Étape 4 : Vérifier votre environnement Python
Confirmez que vous avez la bonne version de Python :
python --version
Vous devriez voir Python 3.12.x
ou une version compatible.
Étape 5 : Créer un environnement virtuel
Un environnement virtuel isole vos dépendances du système global :
virtualenv --no-download ~/venvs/$NAME
source ~/venvs/$NAME/bin/activate
Astuce : Une fois activé, vous verrez le nom de votre environnement entre parenthèses sur chaque ligne de votre terminal, comme ceci :
(llm-sur-hpc) ~$
Étape 6 : Installer les dépendances
L'installation des bibliothèques deep learning peut prendre quelques minutes :
pip install --no-index --upgrade pip
pip install --no-index transformers torch accelerate
Pourquoi
--no-index
? Cette option force pip à utiliser uniquement les packages déjà disponibles dans l'environnement module, ce qui est plus rapide et plus fiable sur les clusters HPC.
Étape 7 : Créer un kernel Jupyter
Pour pouvoir utiliser cet environnement dans JupyterLab, installez-le comme un kernel :
python -m ipykernel install --name ${NAME} --user
Étape 8 : Télécharger les modèles pré-entraînés
Maintenant, téléchargeons les fichiers du modèle directement depuis le noeud frontal. Ouvrez une session Python :
python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
# Spécifiez le modèle que vous souhaitez utiliser
modele_nom = "Qwen/Qwen2.5-7B-Instruct"
# Téléchargez le tokenizer
tokenizer = AutoTokenizer.from_pretrained(modele_nom)
# Téléchargez le modèle
modele = AutoModelForCausalLM.from_pretrained(modele_nom)
Important : Ce processus peut échouer à cause de la mémoire limitée sur les noeuds frontaux (généralement 12-16 Go). Ne vous inquiétez pas ! L'objectif ici est simplement de télécharger tous les fichiers du modèle sur le système de fichiers. Une fois les fichiers téléchargés, vous pourrez les utiliser efficacement sur les noeuds GPU.
Quand vous avez terminé, quittez la session Python :
exit()
Vous pouvez maintenant fermer votre terminal frontal et retourner à votre session JupyterLab.
🧪 Utiliser notre environnement dans JupyterLab
Maintenant que votre environnement est prêt, retournons à JupyterLab pour l'utiliser.
Étape 1 : Restaurer votre collection de modules
Dans la barre latérale gauche de JupyterLab, trouvez le menu des modules (généralement représenté par des icônes de configuration).
Cliquez sur la flèche qui pointe vers la gauche pour restaurer vos modules personnalisés.
Étape 2 : Sélectionner votre collection
Dans la liste des collections, choisissez celle que vous avez créée précédemment (normalement nommée llm-sur-hpc
).
Comment savoir si c'est chargé ? La liste Loaded Modules en bas de la fenêtre changera pour afficher les modules que vous venez de charger (Python 3.12, CUDA 12.6, etc.).
Étape 3 : Créer un nouveau notebook
Cliquez sur le bouton +
pour créer un nouveau notebook. Vous devriez voir votre kernel personnalisé dans la liste des noyaux disponibles.
Sélectionnez votre kernel llm-sur-hpc
et créez le notebook.
Étape 4 : Vérifier le kernel actif
Assurez-vous que vous travaillez bien avec le bon kernel en vérifiant le nom affiché en haut à droite de la fenêtre Jupyter.
Si vous voyez (llm-sur-hpc)
là, vous êtes prêt à commencer !
🚀 Démarrer votre projet dans Jupyter
Félicitations ! Vous avez maintenant un environnement complètement configuré pour exécuter des LLM sur GPU.
Étape 1 : Lancer le script principal
Vous pouvez maintenant exécuter l'ensemble du script llm-hpc.py
dans votre notebook Jupyter. Ce script démontre comment :
- Charger un modèle de langage pré-entraîné
- Générer du contenu structuré en utilisant le GPU
- Sauvegarder les résultats dans un fichier JSON propre
Étape 2 : Comprendre ce qui se passe
Le script va :
- Charger le modèle Qwen2.5-7B-Instruct sur le GPU
- Générer plusieurs menus nutritionnels détaillés
- Sauvegarder chaque menu au format JSON
- Afficher les résultats pour vérification
Conseil pédagogique : Prenez le temps de lire les commentaires dans le script. Chaque section est expliquée en détail pour vous aider à comprendre les concepts clés de l'exécution de LLM sur HPC.
📚 Documentation détaillée du script llm-hpc.py
Pour maximiser votre apprentissage, examinons chaque étape du script en détail.
Étape 1 : Importation des bibliothèques nécessaires
import json
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from tqdm import tqdm
- json : Pour manipuler les données au format JSON
- torch : Pour le calcul tensoriel et l'utilisation du GPU
- transformers : Pour charger le modèle de langage et le tokenizer
- tqdm : Pour afficher une barre de progression pendant l'exécution
Étape 2 : Configuration des paramètres du projet
modele_nom = "Qwen/Qwen2.5-7B-Instruct"
nombre_de_menus = 5
- modele_nom : Spécifie le modèle de langage à utiliser (ici Qwen2.5-7B-Instruct avec 7 milliards de paramètres)
- nombre_de_menus : Définit combien de menus nutritionnels générer
Étape 3 : Chargement du modèle et du tokenizer
device = "cuda"
tokenizer = AutoTokenizer.from_pretrained(modele_nom)
modele = AutoModelForCausalLM.from_pretrained(modele_nom).to(device)
- device : Configure l'utilisation du GPU (cuda) pour les calculs
- tokenizer : Charge le tokenizer qui convertit le texte en tokens compréhensibles par le modèle
- modele : Charge le modèle de langage et le déplace sur le GPU pour un traitement accéléré
Étape 4 : Fonction de génération des menus au format JSON
La fonction generer_menus_json()
effectue les opérations suivantes :
- Crée une conversation structurée avec le modèle en utilisant des rôles (system/user)
- Génère un menu à la fois avec un prompt détaillé pour obtenir un format JSON précis
- Encode le message pour le modèle en utilisant le tokenizer
- Génère la réponse du modèle avec des paramètres contrôlés :
max_new_tokens=500
: Limite la longueur de la générationdo_sample=True
: Active l'échantillonnage pour plus de créativitétemperature=0.8
: Contrôle la créativité (0.8 = équilibré)
- Extrait le JSON généré en nettoyant le texte de sortie
- Gère les erreurs de parsing JSON avec try/except
- Ajoute un identifiant à chaque menu généré
Étape 5 : Exécution de la génération des menus
dataset_menus = generer_menus_json(nombre_de_menus)
- Appelle la fonction principale avec le nombre de menus défini
- Stocke tous les menus générés dans la variable
dataset_menus
Étape 6 : Affichage des résultats pour vérification
if dataset_menus:
print("\n--- Les premiers menus générés ---")
for i, menu in enumerate(dataset_menus[:5]):
print(f"Menu {i + 1}:\n{json.dumps(menu, indent=2)}\n")
else:
print("Aucun menu n'a pu être généré.")
- Affiche jusqu'à 5 premiers menus générés pour vérification
- Utilise
json.dumps()
pour une mise en forme lisible avec indentation - Gère le cas où aucun menu n'a été généré
Étape 7 : Sauvegarde des données dans un fichier
if dataset_menus:
nom_fichier = "menus_canadiens.json"
with open(nom_fichier, "w", encoding="utf-8") as f:
json.dump(dataset_menus, f, ensure_ascii=False, indent=2)
print(f"Les {len(dataset_menus)} menus ont été sauvegardés dans le fichier '{nom_fichier}'.")
else:
print("La génération de menus a échoué. Aucun fichier n'a été créé.")
- Crée un fichier JSON nommé "menus_canadiens.json"
- Utilise
ensure_ascii=False
pour supporter les caractères français - Applique une indentation de 2 pour une lecture humaine facile
- Confirme la sauvegarde ou informe d'un échec
📊 Structure des données générées
Chaque menu généré suit cette structure JSON :
{
"menu_id": 1,
"plat_principal": {
"nom": "Nom du plat",
"ingredients": ["liste d'ingrédients"],
"quantite": "poids en grammes",
"valeurs_nutritives": {"calories": valeur, "proteines": valeur}
},
"accompagnement": { /* même structure */ },
"dessert": { /* même structure */ },
"boisson": { /* même structure */ }
}
Ce script démontre comment utiliser un grand modèle de langage sur HPC pour générer des données structurées en JSON, avec une gestion robuste des erreurs et une sortie formatée pour une utilisation ultérieure.