Le dernier modèle d’IA open-source de Google, Gemma 3, publié en mars 2025, offre des performances impressionnantes qui égalent celles de nombreux LLM propriétaires, tout en fonctionnant efficacement sur du matériel aux ressources limitées. Cette avancée dans le domaine de l’IA open-source fonctionne sur différentes plateformes, offrant aux développeurs du monde entier de puissantes capacités dans un format accessible.
Dans ce guide, nous allons vous aider à affiner Gemma 3 sur un ensemble de données de réponses aux questions personnalisé, dérivé des commentaires de Trustpilot. Nous utiliserons Bright Data pour récupérer les commentaires des clients, les traiter en paires d’AQ structurées et exploiter Unsloth pour un réglage fin efficace avec un minimum de calcul. À la fin, vous aurez créé un assistant IA spécialisé qui comprend les questions spécifiques à un domaine et qui est prêt à être hébergé sur Hugging Face Hub.
Plongeons dans l’aventure !
Comprendre Gemma 3
La famille Gemma 3 de Google a été lancée en mars 2025 avec quatre paramètres de poids libre – 1B, 4B, 12B et 27B – tous conçus pour fonctionner sur un seul GPU.
- Le modèle 1B est un modèle texte uniquement avec une fenêtre contextuelle de 32K tokens.
- Les modèles 4B, 12B et 27B ajoutent une entrée multimodale (texte + image) et prennent en charge une fenêtre de 128K jetons.
Dans le classement LMArena des préférences humaines, Gemma 3-27B-IT devance des modèles beaucoup plus grands tels que Llama 3 405B et DeepSeek-V3, offrant une qualité de pointe sans nécessiter une empreinte multi-GPU.
Source de l’image : Présentation de Gemma 3
Caractéristiques principales des modèles Gemma 3
Voici quelques caractéristiques notables des modèles Gemma 3 :
- Lasaisie multimodale (texte + image) est disponible sur les modèles 4B, 12B et 27B.
- Contexte long –jusqu’à 128K jetons (32K sur le modèle 1B).
- Capacités multilingues – plus de 35 langues prises en charge dès le départ ; plus de 140 langues formées au préalable.
- Quantization-Aware Training – Les versions officielles de QAT réduisent considérablement l’utilisation de la mémoire (d’environ 3x) tout en maintenant une qualité élevée.
- Appel de fonction et sortie structurée – Comprend un support intégré pour l’automatisation des appels et la réception de réponses structurées.
- Efficacité – Conçue pour fonctionner sur un seul GPU/TPU ou même sur des appareils grand public, qu’il s’agisse de téléphones, d’ordinateurs portables ou de stations de travail.
- Sécurité (ShieldGemma) – Comprend un cadre de filtrage de contenu intégré.
Pourquoi affiner Gemma 3 ?
Le réglage fin prend un modèle pré-entraîné comme Gemma 3 et lui enseigne de nouveaux comportements pour votre domaine ou tâche spécifique, sans le temps et le coût d’un entraînement à partir de zéro. Avec sa conception compacte et, sur les variantes 4B+, le support multimodal, Gemma 3 est léger, abordable, et il est possible de l’affiner même sur du matériel aux ressources limitées.
Les avantages de la mise au point sont les suivants
- Spécialisation par domaine – Aide le modèle à comprendre le langage propre à l’industrie et à mieux exécuter les tâches spécialisées dans votre domaine.
- Amélioration des connaissances – Ajout de faits et de contextes importants qui ne faisaient pas partie des données d’apprentissage initiales du modèle.
- Raffinement du comportement – Ajuste la façon dont le modèle répond, afin qu’il corresponde au ton de votre marque ou au format de sortie préféré.
- Optimisation des ressources – Permet d’obtenir des résultats de haute qualité tout en utilisant beaucoup moins de ressources de calcul que si l’on formait un nouveau modèle à partir de zéro.
Conditions préalables
Avant de commencer ce tutoriel, assurez-vous que vous disposez des éléments suivants :
- Python 3.9 ou supérieur est installé sur votre système.
- Connaissance de base de la programmation Python.
- Accès à un environnement informatique avec support GPU (par exemple, Google Colab, Jupyter Notebook ou Kaggle Notebooks).
- Compréhension des principes fondamentaux de l’apprentissage automatique et des grands modèles linguistiques (LLM).
- Expérience de l’utilisation d’un IDE tel que VS Code ou un IDE similaire.
Vous aurez également besoin d’informations d’identification pour accéder à des services externes :
- Un compte Hugging Face et un jeton avec accès en écriture.
👉 Créer un token ici - Un compte Bright Data et une clé API.
👉 Inscrivez-vous et suivez les instructions pour générer un jeton. - Un compte OpenAI et une clé API.
👉 O btenez votre clé API ici
💡 Assurez-vous que votre compte OpenAI dispose d’un crédit suffisant. Gérez la facturation ici et suivez l’utilisation ici.
Création d’un ensemble de données personnalisé pour un réglage fin
Le réglage fin fonctionne mieux lorsque votre ensemble de données reflète étroitement le comportement que vous souhaitez que le modèle apprenne. En créant un ensemble de données personnalisé adapté à votre cas d’utilisation spécifique, vous pouvez améliorer considérablement les performances du modèle. Rappelez-vous la règle classique : “Garbage in, garbage out”. C’est pourquoi il est si important d’investir du temps dans la préparation du jeu de données.
Un ensemble de données de haute qualité doit
- Correspondre à votre cas d’utilisation spécifique – Plus votre ensemble de données correspondra à votre application cible, plus les résultats de votre modèle seront pertinents.
- Maintenir une mise en forme cohérente – Une structure uniforme (comme des paires question-réponse) permet au modèle d’apprendre des modèles plus efficacement.
- Inclure divers exemples – Une variété de scénarios aide le modèle à se généraliser pour différentes entrées.
- Être propre et sans erreur – L’élimination des incohérences et des bruits empêche le modèle d’enregistrer des comportements indésirables.
Nous commencerons par des commentaires bruts comme celui-ci :
Et transformez-les en paires de questions-réponses structurées comme ceci :
Cet ensemble de données permettra à Gemma 3 d’apprendre à extraire des informations des commentaires des clients, à identifier des modèles de sentiments et à fournir des recommandations exploitables.
Étapes de l’installation
#1 Installer les bibliothèques : Ouvrez l’environnement de votre projet et installez toutes les bibliothèques Python nécessaires listées dans le fichier requirements.txt. Vous pouvez le faire en lançant la commande suivante dans votre terminal ou notebook :
pip install -r requirements.txt
#2 Configurer les variables d’environnement : Créez un fichier .env
dans le répertoire racine de votre projet et stockez vos clés API en toute sécurité.
OPENAI_API_KEY="your_openai_key_here"
HF_TOKEN="your_hugging_face_token_here"
Étape 1 : Collecte de données avec Bright Data
La première étape cruciale est la recherche de données. Pour construire notre ensemble de données d’affinage, nous collecterons des données d’évaluation brutes auprès de Trustpilot. En raison des mesures anti-bots robustes de Trustpilot, nous utiliserons l ‘API Trustpilot Scraper de Bright Data. Cette API gère efficacement la rotation des adresses IP, la résolution des CAPTCHA et la gestion des contenus dynamiques, ce qui permet de collecter efficacement des avis structurés à grande échelle, en évitant les complexités liées à la mise en place de votre propre solution de scraping.
Voici un script Python qui montre comment utiliser l’API de Bright Data pour collecter des avis, étape par étape :
import time
import json
import requests
from typing import Optional
# --- Configuration ---
API_KEY = "YOUR_API_KEY" # Replace with your Bright Data API key
DATASET_ID = "gd_lm5zmhwd2sni130p" # Replace with your Dataset ID
TARGET_URL = "https://www.trustpilot.com/review/hubspot.com" # Target company page
OUTPUT_FILE = "trustpilot_reviews.json" # Output file name
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
TIMEOUT = 30 # Request timeout in seconds
# --- Functions ---
def trigger_snapshot() -> Optional[str]:
"""Triggers a Bright Data snapshot collection job."""
print(f"Triggering snapshot for: {TARGET_URL}")
try:
resp = requests.post(
"https://api.brightdata.com/datasets/v3/trigger",
headers=HEADERS,
params={"dataset_id": DATASET_ID},
json=[{"url": TARGET_URL}],
timeout=TIMEOUT,
)
resp.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
snapshot_id = resp.json().get("snapshot_id")
print(f"Snapshot triggered successfully. ID: {snapshot_id}")
return snapshot_id
except requests.RequestException as e:
print(f"Error triggering snapshot: {e}")
except json.JSONDecodeError:
print(f"Error decoding trigger response: {resp.text}")
return None
def wait_for_snapshot(snapshot_id: str) -> Optional[list]:
"""Polls the API until snapshot data is ready and returns it."""
check_url = f"https://api.brightdata.com/datasets/v3/snapshot/{snapshot_id}"
print(f"Waiting for snapshot {snapshot_id} to complete...")
while True:
try:
resp = requests.get(
check_url,
headers=HEADERS,
params={"format": "json"},
timeout=TIMEOUT,
)
resp.raise_for_status()
# Check if response is the final data (list) or status info (dict)
if isinstance(resp.json(), list):
print("Snapshot data is ready.")
return resp.json()
else:
pass
except requests.RequestException as e:
print(f"Error checking snapshot status: {e}")
return None # Stop polling on error
except json.JSONDecodeError:
print(f"Error decoding snapshot status response: {resp.text}")
return None # Stop polling on error
print("Data not ready yet. Waiting 30 seconds...")
time.sleep(30)
def save_reviews(reviews: list, output_file: str) -> bool:
"""Saves the collected reviews list to a JSON file."""
try:
with open(output_file, "w", encoding="utf-8") as f:
json.dump(reviews, f, indent=2, ensure_ascii=False)
print(f"Successfully saved {len(reviews)} reviews to {output_file}")
return True
except (IOError, TypeError) as e:
print(f"Error saving reviews to file: {e}")
return False
except Exception as e:
print(f"An unexpected error occurred during saving: {e}")
return False
def main():
"""Main execution flow for collecting Trustpilot reviews."""
print("Starting Trustpilot review collection process...")
snapshot_id = trigger_snapshot()
if not snapshot_id:
print("Failed to trigger snapshot. Exiting.")
return
reviews = wait_for_snapshot(snapshot_id)
if not reviews:
print("Failed to retrieve reviews from snapshot. Exiting.")
return
if not save_reviews(reviews, OUTPUT_FILE):
print("Failed to save the collected reviews.")
else:
print("Review collection process completed.")
if __name__ == "__main__":
main()
Ce script exécute les étapes suivantes :
- Authentification : Il utilise votre
API_KEY
pour s’authentifier auprès de l’API Bright Data via l’en-têteAuthorization
. - Déclencher la collecte: Il envoie une requête POST pour déclencher une collecte de données pour l’
URL cible
spécifiée (la page Trustpilot de HubSpot dans ce cas), associée à votreDATASET_ID.
- Wait for Completion (Attendre l’achèvement) : Il interroge périodiquement l’API à l’aide de l’
identifiant de cliché
renvoyé pour vérifier si la collecte de données est terminée. - Récupérer les données: Lorsque l’API indique que les données sont prêtes, le script récupère les données d’examen au format JSON.
- Enregistrer la sortie : Il enregistre la liste des objets d’évaluation collectés dans un fichier JSON structuré
(trustpilot_reviews.json
).
Chaque examen dans le fichier JSON qui en résulte fournit des informations détaillées, telles que
{
"review_id": "680af52fb0bab688237f75c5",
"review_date": "2025-04-25T04:36:31.000Z",
"review_rating": 1,
"review_title": "Cancel Auto Renewal Doesn't Work",
"review_content": "I was with Hubspot for almost 3 years...",
"reviewer_name": "Steven Barrett",
"reviewer_location": "AU",
"is_verified_review": false,
"review_date_of_experience": "2025-04-19T00:00:00.000Z",
// Additional fields omitted for brevity
}
Apprenez à trouver les meilleures données pour la formation LLM grâce à notre guide : Les meilleures sources de données pour les formations LLM.
Étape 2 : Conversion de JSON en Markdown
Après avoir collecté les données d’examen brutes, l’étape suivante consiste à les convertir dans un format propre et lisible, adapté au traitement. Nous utiliserons le format Markdown, qui offre une structure de texte brut légère qui réduit le bruit lors de la tokenisation, améliore potentiellement les performances de réglage fin et garantit une séparation cohérente entre les différentes sections du contenu.
Pour effectuer la conversion, il suffit d’exécuter ce script 👉 convert-trustpilot-json-to-markdown.py
Ce script lit les données JSON à partir du résultat de l’étape 1 et génère un fichier Markdown contenant un résumé structuré et les avis individuels des clients.
Voici un exemple de la structure de sortie Markdown :
# HubSpot Review Summary
[Visit Website](https://www.hubspot.com/)
**Overall Rating**: 2.3
**Total Reviews**: 873
**Location**: United States
**Industry**: Electronics & Technology
> HubSpot is a leading growth platform... Grow Better.
---
### Review by Steven Barrett (AU)
- **Posted on**: April 25, 2025
- **Experience Date**: April 19, 2025
- **Rating**: 1
- **Title**: *Cancel Auto Renewal Doesn't Work*
I was with Hubspot for almost 3 years... Avoid.
[View Full Review](https://www.trustpilot.com/reviews/680af52fb0bab688237f75c5)
---
Découvrez pourquoi les agents d’intelligence artificielle préfèrent Markdown à HTML en lisant notre guide.
Étape 3 : Regroupement et traitement du document
Une fois le document Markdown prêt, la prochaine étape cruciale consiste à le diviser en morceaux plus petits et plus faciles à gérer. Cette étape est importante car les grands modèles de langage (LLM) sont limités en nombre de jetons d’entrée, et le réglage fin fonctionne souvent mieux avec des exemples d’une longueur appropriée. En outre, le traitement de ces morceaux peut améliorer leur clarté et leur cohérence pour le modèle.
Nous utilisons RecursiveCharacterTextSplitter
de LangChain pour diviser le fichier Markdown. Cette méthode décompose le texte de manière récursive sur la base d’une liste de séparateurs, ce qui permet de conserver ensemble les morceaux de texte apparentés. Pour préserver le contexte qui pourrait s’étendre entre les points de séparation, nous appliquons un chevauchement entre les morceaux consécutifs. Pour ce processus, nous utilisons une taille de bloc de 1 024 caractères avec un chevauchement de 256 caractères.
Après la division, chaque morceau est éventuellement transmis à un LLM (comme GPT-4o) pour améliorer sa clarté et sa cohérence globales tout en conservant strictement le sens original du texte d’examen. Cette étape d’amélioration vise à rendre la structure des données et le contenu de chaque morceau parfaitement clairs pour le processus d’ajustement ultérieur.
Chaque élément traité se voit attribuer un identifiant unique et est stocké dans un fichier au format JSON Lines (.jsonl
), ce qui le prépare à l’étape suivante du pipeline.
Voici la fonction Python utilisant le LLM pour plus de clarté :
def improve_review_chunk(text: str, client: OpenAI, model: str = "gpt-4o") -> str:
prompt = """Improve this review's clarity while preserving its meaning:
{text}
Return only the improved text without additional commentary."""
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": text}
]
)
return response.choices[0].message.content
Vous trouverez le code complet de cette étape ici 👉 split-markdown-into-chunks.py
Le résultat est un fichier JSON Lines où chaque ligne représente une partie de l’examen avec un identifiant unique et le contenu de l’examen potentiellement amélioré :
[
{
"id": "f8a3b1c9-e4d5-4f6a-8b7c-2d9e0a1b3c4d", // Unique chunk ID
"review": "# HubSpot Review Summary\\n\\n[Visit Website](https://www.hubspot.com/)...\\n---\\n\\n### Review by Steven Barrett (AU)\\n- **Posted on**: April 25, 2024...\\n- **Rating**: 1\\n- **Title**: *Cancel Auto Renewal Doesn't Work*\\n\\nI was with Hubspot for almost 3 years... [Text continues - may be improved]" // Chunk content (potentially refined)
},
// ... more chunk objects
]
Étape 4 : Générer des paires d’AQ
L’étape finale de préparation des données transforme les morceaux d’examen traités en paires structurées de questions-réponses (QA) adaptées à l’affinement d’un modèle linguistique. Nous utilisons GPT-4o d’OpenAI pour générer une paire de QA pour chaque élément du fichier .jsonl
créé à l’étape 3.
Pour chaque morceau, le script appelle l’API OpenAI à l’aide d’une invite système soigneusement conçue :
SYSTEM_PROMPT = """
You are an expert at transforming customer reviews into insightful question–answer pairs. For each review, generate exactly 1 high-quality QA pair.
PURPOSE:
These QA pairs will train a customer service AI to understand feedback patterns about HubSpot products and identify actionable insights.
GUIDELINES FOR QUESTIONS:
- Make questions general and applicable to similar situations
- Phrase from a stakeholder perspective (e.g., "What feature gaps are causing customer frustration?")
- Focus on product features, usability, pricing, or service impact
GUIDELINES FOR ANSWERS:
- Provide analytical responses (3–5 sentences)
- Extract insights without quoting verbatim
- Offer actionable recommendations
- Maintain objectivity and clarity
FORMAT REQUIREMENTS:
- Start with "Q: " followed by your question
- Then "A: " followed by a plain-text answer
"""
Le script comprend des mécanismes intégrés de limitation de la vitesse et de réessai pour gérer les interruptions temporaires de l’API et garantir une exécution stable. Vous pouvez trouver l’implémentation complète dans generate-qa-pairs.py.
Le résultat est enregistré sous la forme d’un tableau JSON, où chaque objet contient une paire de questions et de réponses générées, liées par l’identifiant de la partie originale :
[
{
"id": "82d53a10-9f37-4d03-8d3b-38812e39ecdc",
"question": "How can pricing and customer support issues impact customer satisfaction and retention for HubSpot?",
"answer": "Pricing concerns, particularly when customers feel they are overpaying for services they find unusable or unsupported, can significantly impact customer satisfaction and retention..."
}
// ... more QA pairs
]
Une fois généré, il est fortement recommandé de pousser l’ensemble de données d’assurance qualité résultant vers le Hugging Face Hub. Cela le rend facilement accessible pour l’affiner et le partager. Vous pouvez voir un exemple de l’ensemble de données publié ici : trustpilot-reviews-qa-dataset.
Mise au point de Gemma 3 avec Unsloth : Pas à pas
Maintenant que nous avons préparé notre ensemble de données Q&A personnalisé, affinons le modèle Gemma 3. Nous utiliserons Unsloth, une bibliothèque open-source qui offre des améliorations significatives en termes de mémoire et de vitesse pour l’entraînement LoRA/QLoRA par rapport aux implémentations standard de Hugging Face. Ces optimisations permettent d’affiner des modèles tels que Gemma 3 sur des configurations à GPU unique, à condition que le GPU dispose d’une VRAM suffisante.
Gemma 3 Taille | VRAM approximative requise* | Plates-formes adaptées |
---|---|---|
4B | ~15 GB | Gratuit Google Colab (T4), Kaggle (P100 16 GB) |
12B | ≥24 GB | Colab Pro+ (A100/A10), RTX 4090, A40 |
27B | 22-24 GB (avec QLoRA 4-bit, taille du lot = 1) ; ~40 GB autrement | A100 40 GB, H100, Configurations multi-GPU |
Remarque : les besoins en VRAM peuvent varier en fonction de la taille du lot, de la longueur de la séquence et des techniques de quantification spécifiques. La configuration requise pour le modèle 27B est celle d’un QLoRA 4 bits et d’une petite taille de lot (par exemple, 1 ou 2) ; des tailles de lot plus importantes ou une quantification moins agressive nécessiteront beaucoup plus de VRAM (~40 Go+).
Pour les débutants, il est recommandé de commencer avec le modèle 4B sur un ordinateur portable Colab gratuit, car il supporte confortablement le chargement, la formation et le déploiement avec Unsloth. La mise à niveau vers les modèles 12B ou 27B ne devrait être envisagée que lorsque l’accès à des GPU à plus grande mémoire vive ou à des niveaux de cloud payants est disponible.
Pour modifier le type d’exécution dans Google Colab et sélectionner un GPU T4, procédez comme suit :
- Cliquez sur le menu Runtime en haut.
- Sélectionnez Modifier le type d’exécution.
- Dans la boîte de dialogue qui s’affiche, sous Accélérateur matériel, choisissez GPU.
- Cliquez sur Enregistrer pour appliquer les modifications.
Étape 1 : Mise en place de l’environnement
Tout d’abord, installez les bibliothèques nécessaires. Si vous êtes dans un environnement Colab ou Jupyter, vous pouvez exécuter ces commandes directement dans une cellule de code.
%%capture
!pip install --no-deps unsloth vllm
import sys, re, requests; modules = list(sys.modules.keys())
for x in modules: sys.modules.pop(x) if "PIL" in x or "google" in x else None
!pip install --no-deps bitsandbytes accelerate xformers==0.0.29.post3 peft "trl==0.15.2" triton cut_cross_entropy unsloth_zoo
!pip install sentencepiece protobuf datasets huggingface_hub hf_transfer
# vLLM requirements - vLLM breaks Colab due to reinstalling numpy
f = requests.get("https://raw.githubusercontent.com/vllm-project/vllm/refs/heads/main/requirements/common.txt").content
with open("vllm_requirements.txt", "wb") as file:
file.write(re.sub(rb"(transformers|numpy|xformers)[^\n]{1,}\n", b"", f))
!pip install -r vllm_requirements.txt
Voici une brève explication des principaux paquets installés :
unsloth
: Fournit les optimisations de base pour une formation et un chargement LLM plus rapides et plus efficaces en termes de mémoire, en utilisant des techniques telles que les noyaux fusionnés.peft
: Méthodes de mise au point efficace en fonction des paramètres (comme LoRA). Elles permettent de n’entraîner qu’un petit nombre de paramètres supplémentaires au lieu du modèle complet.trl
: Transformer Reinforcement Learning (apprentissage par renforcement). Inclut leSFTTrainer
qui simplifie le processus de réglage fin supervisé.bitsandbytes
: Permet la quantification sur k bits (4 bits et 8 bits), ce qui réduit considérablement l’empreinte mémoire du modèle.accélérer
: Bibliothèque Hugging Face pour exécuter de manière transparente l’entraînement PyTorch sur différentes configurations matérielles (simple GPU, multi-GPU, etc.).datasets
: Bibliothèque Hugging Face pour le chargement, le traitement et la gestion efficace des ensembles de données.transformers
: la bibliothèque principale de Hugging Face pour les modèles pré-entraînés, les tokenizers et les utilitaires.huggingface_hub
: Utilitaires permettant d’interagir avec le Hugging Face Hub (connexion, téléchargement, chargement).vllm
(optionnel) : Un moteur d’inférence LLM rapide. Il peut être installé séparément si cela est nécessaire pour le déploiement.
Étape 2 : Authentification par le visage
Vous devrez vous connecter au Hugging Face Hub à partir de votre environnement pour télécharger le modèle et éventuellement télécharger le résultat affiné plus tard.
import os
from huggingface_hub import login
from google.colab import userdata
hf_token = userdata.get('HF_TOKEN')
if not hf_token:
raise ValueError("Please set your HF_TOKEN environment variable before running.")
try:
login(hf_token)
print("Successfully logged in to Hugging Face Hub.")
except Exception as e:
print(f"Error logging in to Hugging Face Hub: {e}")
Dans Google Colab, la façon la plus sûre de gérer votre jeton Hugging Face est d’utiliser l’onglet “Secrets” :
Étape 3 : Chargement du modèle et du tokenizer
Pour commencer le réglage fin, nous chargerons efficacement le modèle Gemma 3 réglé sur les instructions à l’aide de FastModel
d’Unsloth. Pour cet exemple, nous utiliserons le modèle unsloth/gemma-3-4b-it
, qui est une version quantifiée de 4 bits optimisée par Unsloth pour s’adapter aux contraintes de mémoire des GPU Colab typiques.
Découvrez la collection Gemma 3 d’Unsloth sur Hugging Face. Elle comprend des modèles de taille 1B, 4B, 12B et 27B, disponibles aux formats GGUF, 4-bit et 16-bit.
from unsloth import FastModel
from unsloth.chat_templates import get_chat_template
import torch # Import torch for checking CUDA
# Ensure CUDA is available
if not torch.cuda.is_available():
raise RuntimeError("CUDA is not available. A GPU is required for this tutorial.")
print(f"CUDA available: {torch.cuda.is_available()}")
print(f"CUDA device name: {torch.cuda.get_device_name(0)}")
model, tokenizer = FastModel.from_pretrained(
model_name="unsloth/gemma-3-4b-it", # Using the 4B instruction-tuned model optimized by Unsloth
max_seq_length=2048, # Set max context length
load_in_4bit=True, # Enable 4-bit quantization
full_finetuning=False, # Use PEFT (LoRA)
token=hf_token, # Pass your Hugging Face token
)
# Apply the correct chat template for Gemma 3
tokenizer = get_chat_template(tokenizer, chat_template="gemma-3")
print("Model and Tokenizer loaded successfully.")
Ce qui se passe dans ce code :
FastModel.from_pretrained()
: Le chargeur de modèle optimisé d’Unsloth.model_name="unsloth/gemma-3-4b-it"
: Spécifie la variante du modèle à charger. Nous choisissons la version 4B instruction-tuned(it)
, pré-optimisée par Unsloth.max_seq_length=2048
: définit le nombre maximum de tokens que le modèle peut traiter en une seule fois. Ajustez cette valeur en fonction de la longueur de vos morceaux de données et de la fenêtre contextuelle souhaitée, en équilibrant l’utilisation de la mémoire et la capacité à traiter des entrées plus longues.load_in_4bit=True
: essentiel pour l’entraînement avec une VRAM limitée. Cela permet de charger les poids du modèle avec une précision de 4 bits à l’aide debits et d'octets
.full_finetuning=False
: Indique à Unsloth de préparer le modèle pour l’ajustement PEFT/LoRA, ce qui signifie que seules les couches d’adaptation seront entraînées, et non tous les paramètres du modèle.get_chat_template(tokenizer, chat_template="gemma-3")
: Enveloppe le tokenizer pour formater automatiquement les invites dans le format de chat attendu de Gemma 3(<start_of_turn>user\n...\n<end_of_turn><start_of_turn>model\n...\n<end_of_turn>
). Cet aspect est essentiel pour affiner les modèles de suivi des instructions et s’assurer que le modèle apprend à générer des réponses dans les tournures conversationnelles attendues.
Étape 4 : Chargement et préparation de l’ensemble de données pour la formation
Nous chargeons l’ensemble de données que nous avons précédemment téléchargé sur le Hugging Face Hub, puis nous le transformons dans le format basé sur le chat attendu par le tokenizer et le trainer.
from datasets import load_dataset
from unsloth.chat_templates import standardize_data_formats, train_on_responses_only # train_on_responses_only imported earlier
# 1. Load the dataset from Hugging Face Hub
dataset_name = "triposatt/trustpilot-reviews-qa-dataset" # Replace with your dataset name
dataset = load_dataset(dataset_name, split="train")
print(f"Dataset '{dataset_name}' loaded.")
print(dataset)
# 2. Normalize any odd formats (ensure 'question' and 'answer' fields exist)
dataset = standardize_data_formats(dataset)
print("Dataset standardized.")
# 3. Define a function to format examples into chat template
def formatting_prompts_func(examples):
"""Formats question-answer pairs into Gemma 3 chat template."""
questions = examples["question"]
answers = examples["answer"]
texts = []
for q, a in zip(questions, answers):
# Structure the conversation as a list of roles and content
conv = [
{"role": "user", "content": q},
{"role": "assistant", "content": a},
]
# Apply the chat template
txt = tokenizer.apply_chat_template(
conv,
tokenize=False, # Return string, not token IDs
add_generation_prompt=False # Don't add the model's start tag at the end yet
)
# Gemma 3 tokenizer adds <bos> by default, which the trainer will re-add
# We remove it here to avoid double <bos> tokens
txt = txt.removeprefix(tokenizer.bos_token)
texts.append(txt)
return {"text": texts}
# 4. Apply the formatting function to the dataset
dataset = dataset.map(formatting_prompts_func, batched=True, remove_columns=["question", "answer"])
print("Dataset formatted with chat template.")
print(dataset) # Inspect the new 'text' column
Dans ce code :
load_dataset()
: Récupère notre jeu de données Q&A du Hugging Face Hub.standardize_data_formats()
: Assure la cohérence des noms de champs entre les différents ensembles de données, en recherchant spécifiquement “question” et “réponse” dans ce cas.formatting_prompts_func()
: Cette fonction critique traite les lots de nos paires de questions-réponses. Elle utilise la méthodetokenizer.apply_chat_template()
pour les convertir en chaînes formatées correctement pour le réglage fin des instructions de Gemma 3. Ce format inclut des jetons de tour spéciaux comme<start_of_turn>user\n
et<start_of_turn>model\n
, qui sont essentiels pour que le modèle comprenne la structure conversationnelle. Nous supprimons le symbole<bos>
initial car leSFTTrainer
ajoute le sien.dataset.map(...)
: Applique efficacement lafonction formatting_prompts_func
à l’ensemble du jeu de données, en créant une nouvelle colonne ‘text’ contenant les chaînes formatées et en supprimant les colonnes d’origine.
Étape 5 : Configuration de LoRA et du formateur
Nous allons maintenant configurer les paramètres PEFT (LoRA) et le SFTTrainer
de la bibliothèque trl
. LoRA fonctionne en injectant de petites matrices entraînables dans les couches clés du modèle pré-entraîné. Seules ces petites matrices d’adaptation sont mises à jour lors du réglage fin, ce qui réduit considérablement le nombre de paramètres à entraîner et minimise ainsi l’utilisation de la mémoire.
from trl import SFTTrainer, SFTConfig
import torch
# 1. Configure LoRA
model = FastModel.get_peft_model(
model,
r=8, # LoRA rank (a common value) - lower rank means fewer parameters, higher means more expressive
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj", # Attention layers
"gate_proj", "up_proj", "down_proj" # MLP layers
],
# Set True if you want to fine-tune language layers (recommended for text tasks)
# and Attention/MLP modules (where LoRA is applied)
finetune_language_layers=True,
finetune_attention_modules=True,
finetune_mlp_modules=True,
# finetune_vision_layers=False, # Only relevant for multimodal models (12B/27B)
lora_alpha=8, # LoRA scaling factor (often set equal to r)
lora_dropout=0, # Dropout for LoRA layers
bias="none", # Don't train bias terms
use_gradient_checkpointing="unsloth", # Memory optimization
random_state=1000, # Seed for reproducibility
use_rslora=False, # Rank-Stabilized LoRA (optional alternative)
# modules_to_save=["embed_tokens", "lm_head"], # Optional: train embedding/output layers
)
print("Model configured for PEFT (LoRA).")
# 2. Configure the SFTTrainer
# Determine a reasonable max_steps based on dataset size and epochs
# For demonstration, a small number of steps is used (e.g., 30)
# For a real use case, calculate steps = (dataset_size / batch_size / grad_accum) * num_epochs
dataset_size = len(dataset)
per_device_train_batch_size = 2 # Adjust based on your GPU VRAM
gradient_accumulation_steps = 4 # Accumulate gradients to simulate larger batch size (batch_size * grad_accum = 8)
num_train_epochs = 3 # Example: 3 epochs
# Calculate total training steps
total_steps = int((dataset_size / per_device_train_batch_size / gradient_accumulation_steps) * num_train_epochs)
# Ensure max_steps is not 0 if dataset is small or calculation results in < 1 step
max_steps = max(30, total_steps) # Set a minimum or calculate properly
print(f"Calculated total training steps for {num_train_epochs} epochs: {total_steps}. Using max_steps={max_steps}")
sft_config = SFTConfig(
dataset_text_field="text", # The column in our dataset containing the formatted chat text
per_device_train_batch_size=per_device_train_batch_size,
gradient_accumulation_steps=gradient_accumulation_steps,
warmup_steps=max(5, int(max_steps * 0.03)), # Warmup for first few steps (e.g., 3% of total steps)
max_steps=max_steps, # Total number of training steps
learning_rate=2e-4, # Learning rate
logging_steps=max(1, int(max_steps * 0.01)), # Log every 1% of total steps (min 1)
optim="adamw_8bit", # 8-bit AdamW optimizer (memory efficient)
weight_decay=0.01, # L2 regularization
lr_scheduler_type="linear", # Linear learning rate decay
seed=3407, # Random seed
report_to="none", # Disable reporting to platforms like W&B unless needed
output_dir="./results", # Directory to save checkpoints and logs
)
# 3. Build the SFTTrainer instance
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
eval_dataset=None, # Optional: provide a validation dataset
args=sft_config,
)
print("SFTTrainer built.")
# 4. Mask out the input portion for training
# This teaches the model to only generate the assistant’s response
# It prevents the model from just copying the user’s prompt
# Pass the literal prefixes for instruction and response turns from the chat template
trainer = train_on_responses_only(
trainer,
instruction_part="<start_of_turn>user\n", # Literal string before user content
response_part="<start_of_turn>model\n", # Literal string before model content
)
print("Trainer configured to train only on responses.")
Dans ce code :
FastModel.get_peft_model()
: Configure le modèle chargé pour le réglage fin LoRA avec les paramètres spécifiés.r
est le rang LoRA, contrôlant la taille des matrices d’adaptation.target_modules
spécifie les couches du modèle (comme l’attention et les projections MLP) qui recevront ces adaptateurs.lora_alpha
est un facteur d’échelle.use_gradient_checkpointing
est une technique d’économie de mémoire fournie par Unsloth.SFTConfig()
: Définit les hyperparamètres d’apprentissage pour leSFTTrainer
.per_device_train_batch_size
etgradient_accumulation_steps
travaillent ensemble pour déterminer la taille effective du lot utilisé pour calculer les gradients.max_steps
définit le nombre total d’itérations d’apprentissage.learning_rate
,optim
,weight_decay
, etlr_scheduler_type
contrôlent le processus d’optimisation.dataset_text_field
indique au trainer quelle colonne du dataset contient les exemples d’apprentissage formatés.SFTTrainer()
: Instancie l’entraîneur, en rassemblant le modèle configuré par LoRA, le jeu de données préparé, le tokenizer, et les arguments d’entraînement définis dansSFTConfig
.train_on_responses_only()
: Une fonction utilitaire (faisant partie detrl
et compatible avec Unsloth) qui modifie le calcul de la perte de l’entraîneur. Elle règle la perte pour qu’elle soit calculée uniquement sur les tokens correspondant à la réponse attendue du modèle(<start_of_turn>model\n..
.), en ignorant les tokens de l’invite de l’utilisateur(<start_of_turn>user\n.
..). Ceci est essentiel pour apprendre au modèle à générer des réponses pertinentes plutôt que de simplement répéter ou compléter l’invite d’entrée. Nous fournissons les préfixes exacts utilisés dans le modèle de discussion pour délimiter ces sections.
Étape 6 : Formation du modèle
Une fois que tout est en place, nous pouvons lancer le processus de réglage fin. La méthode trainer.train()
gère la boucle d’apprentissage en se basant sur les configurations fournies dans la SFTConfig
.
# Optional: clear CUDA cache before training
torch.cuda.empty_cache()
print("Starting training...")
# Use mixed precision training for efficiency
# Unsloth automatically handles float16/bf16 based on GPU capabilities and model
with torch.amp.autocast(device_type="cuda", dtype=torch.float16): # Or torch.bfloat16 if supported
trainer.train()
print("Training finished.")
L’unité didactique émettra des mises à jour sur la progression, y compris la perte d’apprentissage. Vous devriez observer que la perte diminue au fil des étapes, ce qui indique que le modèle apprend à partir des données. La durée totale de l’apprentissage dépend de la taille de l’ensemble de données, de la taille du modèle, des hyperparamètres et du GPU utilisé. Pour notre exemple de jeu de données et le modèle 4B sur un GPU T4, l’entraînement pour 200 étapes devrait se terminer relativement rapidement (par exemple, moins de 15 à 30 minutes, en fonction de la configuration exacte et de la longueur des données).
Étape 7 : Test du modèle affiné (inférence)
Après l’entraînement, testons notre modèle affiné pour voir s’il répond bien aux questions basées sur les données d’évaluation de Trustpilot sur lesquelles il a été entraîné. Nous utiliserons la méthode model.generate
avec un TextStreamer
pour obtenir un résultat plus interactif.
from transformers import TextStreamer
# Define some test questions related to the dataset content
questions = [
"What are common issues or complaints mentioned in the reviews?",
"What do customers like most about the product/service?",
"How is the customer support perceived?",
"Are there any recurring themes regarding pricing or value?"
# Add more questions here based on your dataset content
]
# Set up a streamer for real-time output
# skip_prompt=True prevents printing the input prompt again
# skip_special_tokens=True removes chat template tokens from output
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
print("\n--- Testing Fine-Tuned Model ---")
# Iterate through questions and generate answers
for idx, q in enumerate(questions, start=1):
# Build the conversation prompt in the correct Gemma 3 chat format
conv = [{"role": "user", "content": q}]
# Apply the chat template and add the generation prompt token
# add_generation_prompt=True includes the <start_of_turn>model tag
prompt = tokenizer.apply_chat_template(
conv,
add_generation_prompt=True,
tokenize=False
)
# Tokenize the prompt and move to GPU
inputs = tokenizer([prompt], return_tensors="pt", padding=True).to("cuda")
# Display the question
print(f"\n=== Question {idx}: {q}\n")
# Generate the response with streaming
# Pass the tokenized inputs directly to model.generate
_ = model.generate(
**inputs,
streamer=streamer, # Use the streamer for token-by-token output
max_new_tokens=256, # Limit the response length
temperature=0.7, # Control randomness (lower=more deterministic)
top_p=0.95, # Nucleus sampling
top_k=64, # Top-k sampling
use_cache=True, # Use cache for faster generation
# Add stopping criteria if needed, e.g., stopping after <end_of_turn>
# eos_token_id=tokenizer.eos_token_id,
)
# Add a separator after each answer
print("\n" + "="*40)
print("\n--- Testing Complete ---")
Voir les réponses du modèle dans l’image ci-dessous :
🔥 Super, ça marche bien !
Un processus d’affinage réussi signifie que le modèle génère des réponses plus analytiques et directement dérivées du contenu de l’examen sur lequel il a été affiné, reflétant le style et les idées présentes dans votre ensemble de données personnalisé, plutôt que des réponses génériques.
Étape 8 : Sauvegarder et pousser votre modèle affiné
Enfin, sauvegardez vos adaptateurs LoRA et votre tokenizer. Vous pouvez les sauvegarder localement et les pousser vers le Hugging Face Hub pour faciliter le partage, la gestion des versions et le déploiement.
# Define local path and Hub repository ID
new_model_local = "gemma-3-4b-trustpilot-qa-adapter" # Local directory name
new_model_online = "YOUR_HF_USERNAME/gemma-3-4b-trustpilot-qa" # Hub repo name
# 1. Save locally
print(f"Saving model adapter and tokenizer locally to '{new_model_local}'...")
model.save_pretrained(new_model_local)
tokenizer.save_pretrained(new_model_local)
print("Saved locally.")
# 2. Push to Hugging Face Hub
print(f"Pushing model adapter and tokenizer to Hugging Face Hub '{new_model_online}'...")
model.push_to_hub(new_model_online, token=hf_token)
tokenizer.push_to_hub(new_model_online, token=hf_token)
Le modèle peaufiné est maintenant disponible sur Hugging Face Hub :
Conclusion
Ce guide présente une approche de bout en bout pour affiner Gemma 3 de Google dans le cadre d’un cas d’utilisation pratique : la génération de réponses analytiques à partir d’avis de clients. Nous avons couvert l’ensemble du flux de travail, de la collecte de données de haute qualité et spécifiques au domaine via l’API web scraper de Bright Data, à la structuration dans un format d’assurance qualité à l’aide d’un traitement alimenté par LLM, en passant par le réglage fin du modèle Gemma 3 4B à l’aide de la bibliothèque Unsloth sur un matériel aux ressources limitées.
Le résultat est un LLM spécialisé, capable d’extraire des informations et d’interpréter des sentiments à partir de données d’évaluation brutes, et de les transformer en réponses structurées et exploitables. Cette méthode est très adaptable : vous pouvez appliquer ce même flux de travail pour affiner Gemma 3 (ou d’autres LLM appropriés) sur divers ensembles de données spécifiques à un domaine afin de créer des assistants d’IA adaptés à différents besoins.
Pour en savoir plus sur les stratégies d’extraction de données pilotées par l’IA, consultez ces ressources supplémentaires :
- Scraping Web avec LLaMA 3
- Scraping Web avec les serveurs MCP
- Scraping alimenté par l’IA avec LLM-Scraper
- ScrapeGraphAI pour le scraping Web LLM
Pour plus d’optimisations et d’exemples d’utilisation d’Unsloth, consultez la collection de carnets d’Unsloth (Unsloth Notebooks Collection).
Aucune carte de crédit requise