Exemples de code pour exécuter des LLM sur HPC
Find a file
François Pelletier 3e9d7be76f Première version
2025-08-24 20:00:05 -04:00
images Première version 2025-08-24 20:00:05 -04:00
.gitignore Première version 2025-08-24 20:00:05 -04:00
LICENSE Initial commit 2025-08-24 18:28:56 +00:00
llm-hpc.pdf Première version 2025-08-24 20:00:05 -04:00
llm-hpc.py Première version 2025-08-24 20:00:05 -04:00
README-EN.md Première version 2025-08-24 20:00:05 -04:00
README.md Première version 2025-08-24 20:00:05 -04:00
setup_llm_hpc.sh Première version 2025-08-24 20:00:05 -04:00

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

  1. Connectez-vous à l'interface web de votre cluster HPC
  2. Naviguez vers la section JupyterLab
  3. 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)

Illustration montrant le téléchargement d'un modèle de langage depuis un terminal, avec des barres de progression indiquant le téléchargement des différents composants du modèle

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).

Interface JupyterLab montrant le menu des modules avec une flèche pointant vers la gauche pour restaurer une collection de modules

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).

Interface de sélection de modules montrant la liste des collections disponibles avec la collection 'llm-sur-hpc' sélectionnée

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.

Interface de création de notebook montrant la liste des noyaux disponibles avec le kernel 'llm-sur-hpc' sélectionné

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.

Interface JupyterLab montrant le kernel actif 'llm-sur-hpc' en haut à droite de la fenêtre

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 :

  1. Charger le modèle Qwen2.5-7B-Instruct sur le GPU
  2. Générer plusieurs menus nutritionnels détaillés
  3. Sauvegarder chaque menu au format JSON
  4. 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 :

  1. Crée une conversation structurée avec le modèle en utilisant des rôles (system/user)
  2. Génère un menu à la fois avec un prompt détaillé pour obtenir un format JSON précis
  3. Encode le message pour le modèle en utilisant le tokenizer
  4. 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ération
    • do_sample=True : Active l'échantillonnage pour plus de créativité
    • temperature=0.8 : Contrôle la créativité (0.8 = équilibré)
  5. Extrait le JSON généré en nettoyant le texte de sortie
  6. Gère les erreurs de parsing JSON avec try/except
  7. 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 */ }
}

Exemple d'affichage de menu de cafétéria généré au format JSON

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.