# Dataset SFT synthetique — builder deterministe, 227 paires, 6 familles.
# Le point pedagogique : 20 exemples ne pouvaient transmettre qu'un FORMAT ;
# 227 exemples de formulations variees transmettent le MAPPING formulation -> fond,
# qui est ce qu'un SFT peut apprendre a cette echelle. Graine fixee : deux
# executions donnent exactement le meme dataset.
DEFS = {
"la gravite": "La gravite est une force fondamentale qui attire deux corps massifs l'un vers l'autre. Sur Terre, elle nous maintient au sol et donne leur poids aux objets. Newton a formule la loi de la gravitation universelle, puis Einstein l'a reformulee comme une deformation de l'espace-temps.",
"l'intelligence artificielle": "L'intelligence artificielle (IA) est un domaine de l'informatique qui vise a creer des systemes capables de realiser des taches necessitant normalement l'intelligence humaine : reconnaissance d'images, comprehension du langage, prise de decision. L'apprentissage profond en est la technique la plus performante actuellement.",
"le machine learning": "Le machine learning (apprentissage automatique) est une branche de l'IA ou les systemes apprennent a partir de donnees sans etre explicitement programmes. Les trois types principaux sont l'apprentissage supervise (avec labels), non supervise (sans labels) et par renforcement (recompenses).",
"un neurone artificiel": "Un neurone artificiel est l'unite de base d'un reseau de neurones. Il recoit des entrees numeriques, les multiplie par des poids, additionne les resultats, puis applique une fonction d'activation comme ReLU ou sigmoid pour produire une sortie.",
"un reseau de neurones": "Un reseau de neurones est un ensemble de neurones artificiels organises en couches. Chaque couche transforme sa sortie vers la suivante ; l'apprentissage ajuste les poids par retropropagation du gradient pour minimiser une fonction de perte.",
"Python": "Python est un langage de programmation de haut niveau, cree par Guido van Rossum en 1991. Il est connu pour sa syntaxe lisible et sa polyvalence : science des donnees, intelligence artificielle, developpement web, automatisation.",
"une API": "Une API (Application Programming Interface) est un ensemble de definitions qui permet a deux programmes de communiquer. Le client envoie une requete selon un contrat documente, le serveur renvoie une reponse structuree, souvent en JSON via HTTP.",
"un token (NLP)": "Un token est l'unite de texte manipulee par un modele de langage : un mot, une partie de mot ou un signe de ponctuation. La tokenisation decoupe le texte brut en ces unites avant de les convertir en identifiants numeriques.",
"une epoch": "Une epoch est un passage complet du modele sur l'ensemble du dataset d'entrainement. Plusieurs epochs font voir chaque exemple plusieurs fois, ce qui permet la convergence mais expose au surapprentissage si leur nombre est trop eleve.",
"un checkpoint": "Un checkpoint est un instantane des poids d'un modele sauvegarde pendant ou apres l'entrainement. Il permet de reprendre l'entrainement, de comparer des variants, ou de revenir a un meilleur etat.",
"la VRAM": "La VRAM (Video Random Access Memory) est la memoire dediee du GPU. Un modele et ses activations y resident pendant l'entrainement ; sa capacite borne la taille du modele, la longueur des sequences et la taille de batch.",
"le fine-tuning": "Le fine-tuning consiste a ajuster les poids d'un modele deja entraine sur une nouvelle tache. C'est moins couteux que l'entrainement depuis zero et le modele conserve les connaissances de son pre-entrainement.",
"LoRA": "LoRA (Low-Rank Adaptation) fige les poids du modele et entraine de petites matrices de rang faible inserees dans les couches. Le nombre de parametres entrainables chute d'un facteur mille, rendant le fine-tuning de grands modeles abordable.",
"la quantization 4-bit": "La quantization 4-bit code chaque poids sur 4 bits au lieu de 16, divisant la memoire des poids par quatre avec une perte de precision limitee. Combinnee a LoRA (QLoRA), elle permet d'entrainer de grands modeles sur un seul GPU.",
"un embedding": "Un embedding est la representation vectorielle dense d'un objet (mot, phrase, image) dans un espace ou la distance entre vecteurs traduit une similarite semantique. Les modeles de langage produisent des embeddings en sortie de chaque couche.",
"l'attention": "L'attention est le mecanisme qui, pour chaque token, calcule des poids sur tous les autres tokens puis en fait la moyenne ponderee des representations. Chaque mot peut ainsi se lier aux mots qui l'eclairent, quelle que soit leur distance.",
"un prompt": "Un prompt est le texte soumis a un modele de langage pour obtenir une reponse. Sa formulation, son contexte et son format influencent fortement la reponse : c'est l'ingenierie de prompt.",
"le surapprentissage": "Le surapprentissage (overfitting) survient quand un modele memorise les exemples d'entrainement au lieu d'en extraire des regularites. Il se manifeste par une perte d'entrainement qui descend pendant que la perte d'evaluation remonte.",
"un benchmark": "Un benchmark est un jeu d'evaluation standardise qui permet de comparer des modeles sur une tache donnee. Un bon benchmark est public, reproductible et disjoint des donnees d'entrainement.",
"la temperature (generation)": "La temperature est le parametre de generation qui regle l'aleatoire de l'echantillonnage. Basse, elle rend les sorties deterministes et conservatrices ; haute, elle les diversifie au prix d'incoherences.",
}
CONCEPT_PAIRS = [
("CPU et GPU", "Le CPU execute des taches complexes en serie avec peu de coeurs puissants ; le GPU execute des taches simples en parallele avec des milliers de coeurs. L'entrainement des reseaux de neurones, massivement parallele, profite au GPU."),
("apprentissage supervise et non supervise", "L'apprentissage supervise apprend depuis des exemples labels (entree vers sortie attendue) : classification, regression. Le non supervise cherche des structures dans des donnees non labels : clustering, reduction de dimension."),
("une liste et un tuple en Python", "Une liste est mutable : on peut ajouter, retirer ou modifier ses elements apres creation. Un tuple est immuable : cree une fois, jamais modifie. La liste sert aux collections qui evoluent, le tuple aux enregistrements fixes et aux cles de dictionnaire."),
("classification et regression", "La classification predit une categorie discrete (spam ou non, chat ou chien) ; la regression predit une valeur continue (un prix, une temperature). Les deux sont supervisees mais leur metrique differe : exactitude ou F1 contre erreur quadratique."),
("precision et rappel", "La precision mesure la part de vrais positifs parmi les positifs predits ; le rappel mesure la part de vrais positifs parmi les positifs reels. Precision haute : peu de fausses alertes. Rappel haut : peu d'oublis. Le F1 en est la moyenne harmonique."),
("batch training et stochastic gradient descent", "Le batch gradient descent calcule le gradient sur tout le dataset avant chaque mise a jour : stable mais couteux. La version stochastique (ou mini-batch) met a jour sur de petits lots : plus bruitee mais plus rapide et meilleure en generalisation."),
("un modele de base et un modele instruct", "Un modele de base complete du texte de maniere plausible mais ignore les conventions de dialogue. Un modele instruct a subi un ajustement par instructions (SFT, RLHF) qui lui apprend a repondre aux requetes : arret, format, refus."),
("pre-entrainement et fine-tuning", "Le pre-entrainement apprend les regularites du langage sur des corpus massifs non labels ; le fine-tuning specialise ensuite le modele sur une tache avec peu de donnees etiquetees. Le second herite des representations du premier."),
("un parametre et un hyperparametre", "Un parametre est appris par le modele pendant l'entrainement (poids, biais). Un hyperparametre est fixe avant l'entrainement par l'ingenieur (taux d'apprentissage, taille de batch, nombre de couches)."),
("dropout et weight decay", "Le dropout desactive aleatoirement des neurones pendant l'entrainement pour eviter la co-adaptation ; le weight decay penalise les grands poids en ajoutant leur norme a la perte. Les deux combattent le surapprentissage, l'un sur la structure, l'autre sur l'amplitude."),
("une fonction d'activation ReLU et sigmoid", "ReLU laisse passer les valeurs positives et met les negatives a zero : simple, rapide, sans saturation du cote positif. La sigmoid comprime toute valeur dans (0, 1), utile en sortie binaire mais sujette a l'evanescence du gradient en profondeur."),
("tokenisation par mot et par sous-mot (BPE)", "La tokenisation par mot decoupe sur les espaces : vocabulaire enorme, mots inconnus intraitables. La tokenisation par sous-mot (BPE) decoupe en fragments frequents : vocabulaire borne, les mots rares se recomposent de fragments connus."),
]
RESUME_TEXTS = {
"Le machine learning permet aux ordinateurs d'apprendre a partir de donnees": "L'apprentissage automatique fait emerger des regularites depuis des donnees, sans regles explicites.",
"Les transformers sont une architecture de reseau de neurones": "Les transformers traitent les sequences par attention, sans recurrence ni convolution.",
"Le fine-tuning consiste a ajuster les poids d'un modele": "Le fine-tuning specialise un modele existant plutot que d'en entrainer un nouveau.",
"Un GPU accelere les calculs matriciels": "Le GPU met en parallele les operations qui dominent l'entrainement des reseaux.",
"Un modele de langage predit le token suivant": "Un LM est un predicteur statistique du prochain token, conditionne par tout le contexte precedent.",
"Le surapprentissage degrade la generalisation": "Memoriser l'entrainement nuit aux donnees nouvelles : c'est le surapprentissage.",
"La quantization reduit l'empreinte memoire des modeles": "Coder les poids sur moins de bits reduit la memoire au prix d'une precision limitee.",
"Un benchmark compare des modeles sur une tache standard": "Les benchmarks rendent les comparaisons publiques et reproductibles.",
"L'attention pondere l'importance des tokens": "Chaque token pondere les autres avant d'agreger leurs representations.",
"La tokenisation precede toute inference": "Tout texte devient des identifiants numeriques avant d'entrer dans le modele.",
"Un embedding encode un objet en vecteur": "Les representations vectorielles rendent la similarite calculable.",
"Le RLHF aligne les modeles sur des preferences humaines": "Le RLHF ajuste un modele par recompense depuis des comparaisons humaines.",
}
WHY_TOPICS = {
"le deep learning a-t-il connu un essor recent": "Trois facteurs convergent : des corpus massifs numerises, des GPU qui mettent le calcul matriciel en parallele, et des architectures (transformers) qui passent a l'echelle. Les idees des annees 80 n'attendaient que ces trois leviers.",
"les modeles de langage utilisent-ils des sous-mots": "Parce qu'un vocabulaire de mots entiers laisse les mots rares intraitables, alors qu'un vocabulaire de sous-mots borne la taille tout en recomposant n'importe quel mot. Le BPE construit ce vocabulaire par frequences.",
"faut-il fixer la graine aleatoire en experimentation": "Sans graine fixee, deux executions donnent deux resultats et aucune comparaison n'est possible. Fixer la graine rend l'experience reproductible ; c'est le socle de toute mesure de difference entre deux configurations.",
"les GPU dominent-ils l'entrainement": "Parce que l'entrainement se reduit a des produits matriciels massivement paralleles, exactement ce pour quoi le GPU est concu. Le CPU excelle en serie complexe, le GPU en parallele simple.",
"mesure-t-on la loss d'evaluation en plus de la loss d'entrainement": "Parce que la loss d'entrainement peut descendre par memorisation pure. La loss d'evaluation, calculee sur des donnees jamais vues, est la seule qui temoigne de la generalisation.",
"la VRAM limite-t-elle la taille des modeles entrainables": "Parce que poids, gradients, etats d'optimiseur et activations doivent tous resider en memoire simultanement. La quantization et le gradient checkpointing sont les deux leviers pour y loger davantage.",
"peut-on juger un fine-tuning sur ses generations": "Sur un petit dataset, une generation plausible peut n'etre que la memorisation d'un exemple. Les pertes train/eval disjointes et les generations sur instructions jamais vues arbitrent mieux qu'une lecture a l'oeil.",
"les modeles instruct refusent-ils certaines requetes": "Parce que l'alignement (SFT puis RLHF) leur apprend des conventions de comportement, incluant le refus. Le modele de base n'a pas ce reflexe : il complete du texte, il ne decide pas.",
"faut-il plusieurs epochs de fine-tuning": "Une epoch unique peut sous-apprendre ; dix epochs sur un petit dataset memorisent. Le bon point d'arret se lit sur la courbe de perte d'evaluation : on s'arrete quand elle cesse de descendre.",
"un petit modele peut-il battre un grand sur une tache etroite": "Oui, apres fine-tuning sur une tache precise : le grand modele dilue sa capacite sur tout, le petit la concentre. C'est l'argument economique du fine-tuning face a l'echelle brute.",
}
LIST_TEMPLATES = [
("Donnez {n} conseils pour ameliorer sa productivite au travail", [
"Commencez par la tache la plus difficile", "Groupez les taches similaires en blocs", "Coupez les notifications pendant les taches profondes",
"Planifiez la journee la veille au soir", "Accordez des pauses regulieres", "Notez les idees des qu'elles surviennent",
"Fixez une limite de temps par reunion", "Relisez vos objectifs chaque matin", "Automatisez les taches repetitives", "Dites non aux demandes hors priorites",
]),
("Listez {n} avantages du langage Python pour la data science", [
"Syntaxe lisible qui raccourcit le prototypage", "Ecosysteme scientifique complet (NumPy, pandas)", "Communaute et documentation abondantes",
"Portable sur tous les systemes", "Interactif via notebooks", "Integre au C pour les parties critiques",
"Nombreuses bibliotheques de ML pretes a l'emploi", "Gratuit et open source", "Outillage de test mature", "Standard de fait dans l'industrie",
]),
("Quelles sont les {n} etapes d'un projet de machine learning", [
"Cadrer le probleme et la metrique", "Collecter les donnees", "Nettoyer et explorer", "Construire une baseline simple",
"Entrainer des modeles candidats", "Evaluer sur un jeu disjoint", "Deployer", "Surveiller la derive en production",
]),
("Donnez {n} bonnes pratiques d'un notebook pedagogique", [
"Une cellule = une idee", "Annoncer la question avant le code", "Interpreter la sortie juste apres la cellule", "Fixer toutes les graines",
"Limiter la duree de chaque cellule", "Garder un fil narratif du debut a la fin", "Citer les sources des donnees", "Relire comme un etudiant novice",
]),
("Citez {n} risques d'un fine-tuning sur petit dataset", [
"Memorisation mot a mot", "Perte des competences generales", "Reponses confiantes mais fausses", "Sensibilite a la graine",
"Sur-ajustement au format plutot qu'au fond", "Metriques d'entrainement trompeuses", "Evaluation impossible faute de donnees disjointes",
]),
("Donnez {n} leviers pour economiser la VRAM pendant l'entrainement", [
"Quantization 4-bit des poids", "LoRA plutot que full fine-tuning", "Gradient checkpointing", "Reduire la taille de batch",
"Raccourcir les sequences", "Optimizer en 8 bits", "Liberer les caches entre phases", "Basculer la precision mixte",
]),
]
HOWTO_STEPS = [
("Comment creer une liste vide en Python", ["ma_liste = []", "ou via le constructeur : ma_liste = list()"]),
("Comment ajouter un element a une liste Python", ["ma_liste.append(element)", "pour concatener une autre liste : ma_liste.extend(autre)"]),
("Comment creer un dictionnaire en Python", ["mon_dict = {}", "puis alimentation par cle : mon_dict['cle'] = valeur"]),
("Comment lire un fichier texte en Python", ["with open('chemin.txt', encoding='utf-8') as f:", " contenu = f.read()"]),
("Comment ecrire un fichier texte en Python", ["with open('sortie.txt', 'w', encoding='utf-8') as f:", " f.write(contenu)"]),
("Comment trier une liste en Python", ["triee = sorted(ma_liste)", "ou en place : ma_liste.sort() ; les deux acceptent key= pour un critere"]),
("Comment verifier la presence d'un element dans une liste", ["if element in ma_liste:", "le test in parcourt la liste ; pour un test frequent, preferer un set"]),
("Comment mesurer le temps d'execution d'une fonction Python", ["import time", "debut = time.perf_counter()", "ma_fonction()", "print(time.perf_counter() - debut)"]),
("Comment fixer la graine aleatoire de NumPy", ["import numpy as np", "np.random.seed(42)", "pour la nouvelle API : rng = np.random.default_rng(42)"]),
("Comment charger un modele HuggingFace en local", ["from transformers import AutoModelForCausalLM", "modele = AutoModelForCausalLM.from_pretrained('nom_du_modele')"]),
("Comment compter les parametres entrainables d'un modele PyTorch", ["n = sum(p.numel() for p in modele.parameters() if p.requires_grad)", "print(n)"]),
("Comment liberer la memoire GPU sous PyTorch", ["del modele", "import torch ; import gc", "gc.collect() ; torch.cuda.empty_cache()"]),
]
def build_sft_dataset(seed=42):
"""Genere le dataset SFT deterministe : familles x grilles x reformulations."""
import random as _random
r = _random.Random(seed)
data, seen = [], set()
def add(instruction, response):
key = instruction.strip().lower()
if key not in seen:
seen.add(key)
data.append({"instruction": instruction, "response": response})
for sujet, rep in DEFS.items():
add(f"Qu'est-ce que {sujet} ?", rep)
for paire, rep in CONCEPT_PAIRS:
add(f"Quelle est la difference entre {paire} ?", rep)
for texte, rep in RESUME_TEXTS.items():
add(f"Resumez en une phrase : {texte}...", rep)
for q, rep in WHY_TOPICS.items():
add(f"Pourquoi {q} ?", rep)
for tpl, items in LIST_TEMPLATES:
for n in [3, 4, 5, 6, 7, 8]:
if n > len(items):
break
add(tpl.format(n=n), "\n".join(f"{i+1}. {p}" for i, p in enumerate(items[:n])))
for q, lines in HOWTO_STEPS:
add(q, "\n".join(lines))
forms = [
("Pouvez-vous expliquer {sujet} ?", lambda s: DEFS[s]),
("Expliquez-moi {sujet}.", lambda s: DEFS[s]),
("J'aimerais comprendre {sujet}.", lambda s: DEFS[s]),
]
for tpl, fn in forms:
for sujet in DEFS:
add(tpl.format(sujet=sujet), fn(sujet))
for paire, rep in CONCEPT_PAIRS:
add(f"Comparez {paire}.", rep)
add(f"{paire} : que choisir et quand ?", rep)
for q, rep in WHY_TOPICS.items():
add(f"Pour quelle raison {q} ?", rep)
add(f"Dites-moi pourquoi {q}.", rep)
list_alts = {"Donnez": "Enumerez", "Listez": "Donnez-moi", "Citez": "Listez pour moi"}
for tpl, items in LIST_TEMPLATES:
mot = tpl.split(" ")[0]
alt_mot = list_alts.get(mot)
if alt_mot is None:
continue
alt_tpl = tpl.replace(mot, alt_mot, 1)
for n in [3, 5]:
if n > len(items):
break
add(alt_tpl.format(n=n), "\n".join(f"{i+1}. {p}" for i, p in enumerate(items[:n])))
for q, lines in HOWTO_STEPS:
add(f"Comment faire pour : {q.replace('Comment ', '')} ?", "\n".join(lines))
r.shuffle(data)
return data
def famille(q):
q = q.lower()
if q.startswith("qu'est-ce que") or "expliquez" in q or q.startswith("j'aimerais") or q.startswith("pouvez-vous"):
return "definitions"
if "difference" in q or q.startswith("comparez") or "que choisir" in q:
return "comparaisons"
if q.startswith("resumez"):
return "resumes"
if q.startswith("pourquoi") or q.startswith("pour quelle") or q.startswith("dites-moi pourquoi"):
return "pourquois"
if any(x in q for x in ["conseils", "avantages", "etapes", "bonnes pratiques", "risques", "leviers", "listez", "citez", "donnez", "enumerez", "quelles sont"]):
return "listes"
return "howto/code"
# ---- Instanciation et controles ----
sft_data = build_sft_dataset(seed=42)
print(f"Dataset SFT : {len(sft_data)} paires (deterministe, graine 42)")
from collections import Counter
cats = Counter(famille(d["instruction"]) for d in sft_data)
print("\nRepartition par famille :")
for cat, count in cats.most_common():
print(f" {cat:14s} {count}")
assert sft_data == build_sft_dataset(seed=42), "builder non deterministe !"
assert len({d["instruction"] for d in sft_data}) == len(sft_data), "instructions en double !"
lens_words = [len((d["instruction"] + " " + d["response"]).split()) for d in sft_data]
print(f"\nLongueur (mots, instruction + reponse) : min {min(lens_words)}, max {max(lens_words)}, moyenne {sum(lens_words)/len(lens_words):.0f}")
reps = Counter(d["response"] for d in sft_data)
print(f"Reponses partagees par plusieurs formulations : {sum(1 for v in reps.values() if v > 1)} (fonds distincts : {len(reps)})")
print("Determinisme et unicite verifies par assertion.")