Aller au contenu principal

Module 5 — Décodage : température, top-k, top-p

Le modèle des modules précédents produit, à chaque étape, une distribution de probabilité sur son vocabulaire de jetons. Reste à choisir un jeton. Ce choix est le décodage, et c'est le levier que l'ingénieur ajuste le plus souvent en production — bien plus que les poids du modèle. Pour notre assistant de support, un décodage mal réglé transforme des réponses factuelles en variations créatives inutiles, ou des propositions naturelles en clones stériles. Ce module explique ce que chaque paramètre fait exactement à la distribution.

D'une distribution à un jeton : sept stratégies

Le modèle produit un vecteur de scores RV\ell \in \mathbb{R}^{|V|} appelés logits. La probabilité de chaque jeton est obtenue par un softmax : pi=exp(i)/jexp(j)p_i = \exp(\ell_i) / \sum_j \exp(\ell_j). Toutes les stratégies de décodage se distinguent par comment elles utilisent ces probabilités.

StratégieSélectionAléatoireUsage type
Argmax (glouton)argmaxipi\arg\max_i p_inontest, réponse ultra-courte
Recherche par faisceauxconserve les kk meilleures séquencesnontraduction courte
Échantillonnage bruttire selon ppouirarement utile
Températuretire selon pp modifiée par TTouitout usage général
Top-ktire parmi les kk meilleursouilimitation dure du bruit
Top-p (nucléus)tire parmi la plus petite masse cumulée p\geq pouiproduction de texte varié
Combiné top-k + top-p + TTapplique les trois filtresouiréglage fin

Argmax et recherche par faisceaux sont déterministes ; à même invite, elles produisent toujours la même sortie. Les autres sont stochastiques ; deux appels identiques peuvent donner des réponses différentes, à moins de fixer la graine aléatoire.

La température, ou comment aplatir la distribution

La température T>0T > 0 divise les logits avant le softmax :

pi(T)=exp(i/T)jexp(j/T).p_i(T) = \frac{\exp(\ell_i / T)}{\sum_j \exp(\ell_j / T)}.

Une température basse (T<1T < 1) accentue les différences entre logits et concentre la masse sur les meilleurs jetons. Une température haute (T>1T > 1) aplatit la distribution et rend les jetons rares plus probables. À la limite T0T \to 0, la distribution devient un point : c'est équivalent à l'argmax.

import numpy as np

logits = np.array([3.0, 2.0, 1.0, -1.0])

def softmax(x, T):
x = x / T
x = x - x.max()
e = np.exp(x)
return e / e.sum()

for T in [0.3, 1.0, 2.0]:
p = softmax(logits, T)
print(f"T = {T:>4} :", np.round(p, 3))

Sortie :

T =  0.3 : [0.955 0.045 0.    0.   ]
T = 1.0 : [0.643 0.236 0.087 0.032]
T = 2.0 : [0.502 0.305 0.185 0.008]

À T=0,3T = 0{,}3, le premier jeton capte 95 pour cent de la masse ; à T=2T = 2, les trois meilleurs se partagent la moitié presque également. Le comportement change complètement, et pourtant c'est la même paramétrisation d'une même distribution.

Top-k et top-p : couper la queue

La distribution du softmax garde toujours une masse non nulle sur les jetons les plus improbables — dans un vocabulaire de 32 000 jetons, cette « queue » peut représenter quelques pour cent au total. C'est peu, mais tirer dedans produit des mots aberrants qui font dérailler la génération.

Top-k garde uniquement les kk jetons de plus haute probabilité et renormalise. Le paramètre est simple mais rigide : à distribution très concentrée, k=40k = 40 garde 40 jetons dont 35 négligeables ; à distribution très plate, k=40k = 40 coupe trop tôt.

Top-p (aussi appelé nucleus sampling) garde la plus petite ensemble de jetons dont la masse cumulée dépasse pp, puis renormalise. Il s'adapte automatiquement à la forme de la distribution : sur une distribution concentrée, il garde peu de jetons ; sur une distribution plate, il en garde plus.

def top_p(logits, p=0.9, T=1.0):
proba = softmax(logits, T)
ordre = np.argsort(-proba)
cumule = np.cumsum(proba[ordre])
coupe = np.searchsorted(cumule, p) + 1
filtre = np.zeros_like(proba)
filtre[ordre[:coupe]] = proba[ordre[:coupe]]
return filtre / filtre.sum()

print(np.round(top_p(logits, p=0.9, T=1.0), 3))

Dans la pratique, on combine les trois : température modérée (T0,7T \approx 0{,}7), top-p de 0,90{,}9 et top-k élevé (k=40k = 40) comme filet de sécurité. Cette combinaison est le réglage par défaut de la plupart des interfaces publiques.

Réglages recommandés par usage

Il n'existe pas un « bon » décodage universel. Le tableau ci-dessous donne les valeurs qui fonctionnent, avec la raison.

UsageTempératureTop-pTop-kPourquoi
Support client, faits vérifiables0,2 - 0,30,940déterminisme perçu, moins d'errance
Génération de code0,0 - 0,21,040correction syntaxique prioritaire
Rédaction commerciale0,70,940style vivant, variations utiles
Brainstorming0,9 - 1,20,95100diversité recherchée
Extraction structurée0,01,01argmax pur, aucune variation

Pour notre assistant de support, une température autour de 0,3 avec top-p à 0,9 donne des réponses stables sans les rendre robotiques. Passer à 0,7 rend les mêmes réponses subtilement différentes d'un appel à l'autre, ce qui déroute les opérateurs qui les relisent.

Pénalités de répétition, l'outil du dernier recours

Les modèles ont tendance à répéter, surtout quand l'invite est mal construite ou que la température est basse. Deux pénalités existent.

  • Pénalité de répétition : divise le logit d'un jeton déjà présent par un facteur r>1r > 1 (souvent 1,05 à 1,2).
  • Pénalité de fréquence ou de présence (interface OpenAI) : soustrait un terme proportionnel au compte du jeton dans l'historique.

Ces pénalités règlent le symptôme, jamais la cause. Une répétition persistante signale presque toujours un problème de gabarit de conversation (module 3), une invite trop répétitive elle-même, ou un modèle mal adapté à la langue. Augmenter la pénalité au-delà de 1,3 est un mauvais signe : le modèle finit par éviter les jetons qu'il doit utiliser, ce qui produit un texte artificiellement bariolé.

Déterminisme et graine aléatoire

Pour tester ou pour tracer un bogue, on veut souvent des sorties reproductibles. Trois conditions doivent être remplies simultanément.

  1. Décodage glouton ou faisceau, ou échantillonnage avec une graine fixée.
  2. Précision numérique stable : torch.use_deterministic_algorithms(True) et parfois torch.backends.cudnn.deterministic = True.
  3. Aucune opération dépendante du matériel qui varie entre GPU.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, set_seed

set_seed(42)
tok = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")
modele = AutoModelForCausalLM.from_pretrained(
"meta-llama/Meta-Llama-3-8B-Instruct",
torch_dtype=torch.bfloat16,
device_map="auto",
)

entree = tok("Bonjour, comment puis-je vous aider ?", return_tensors="pt").to(modele.device)
sortie = modele.generate(
**entree,
do_sample=True,
temperature=0.3,
top_p=0.9,
max_new_tokens=64,
)

Même avec ces précautions, la reproductibilité stricte n'est pas garantie sur GPU : les additions en virgule flottante ne sont pas associatives, et l'ordre dépend du parallélisme. On accepte un écart au niveau du bruit numérique.

La température zéro n'est pas la sécurité

Il est tentant de mettre T=0T = 0 pour « avoir la vérité ». En réalité, l'argmax choisit toujours le même jeton, ce qui verrouille aussi les erreurs : si le modèle a une petite probabilité d'halluciner à cette position, il hallucinera à chaque appel. Un décodage à température modérée avec échantillonnage donne parfois une réponse fausse, mais échoue plus rarement de la même manière, ce qui permet à un contrôle de détecter l'incohérence.

Fixer le décodage avant de comparer deux modèles

Une erreur classique en évaluation est de comparer deux modèles avec des réglages de décodage différents, hérités d'exemples publics. Une baisse de température de 0,7 à 0,3 change la performance sur MMLU de plusieurs points. Toujours fixer explicitement le décodage avant toute comparaison, et le documenter à côté du chiffre.

En résumé

  • Le décodage transforme une distribution en un jeton ; température, top-k et top-p modifient la distribution avant tirage, tandis qu'argmax et faisceaux la déterminisent.
  • La température aplatit ou concentre la distribution ; abaisser TT n'améliore pas la factualité, mais verrouille le comportement, y compris les erreurs.
  • Top-p s'adapte à la forme de la distribution alors que top-k est rigide ; les combiner avec une température modérée est le réglage par défaut le plus robuste.
  • Les pénalités de répétition traitent un symptôme et jamais la cause ; au-delà de 1,3, elles dégradent le texte plus qu'elles ne l'améliorent.

Module suivant : ce que le modèle peut réellement voir en une seule invocation — la fenêtre de contexte et ses limites.