Ajuster finement Laya sur tes propres décisions
Sur le benchmark typed-decisions, les checkpoints de base obtiennent près du hasard sans exemples — 0.36 et 0.35 contre une référence aléatoire de 0.318 — tandis que le checkpoint ajusté atteint 0.766 sur les mêmes 2,000 décisions, au-dessus du 0.727 publié de TypeSafe Jev et au-dessus du plafond d’auto-accord de 0.735 de l’enseignant. L’ajustement fin est là où se trouve l’essentiel de la valeur, et le public notebook d’ajustement fin exécute toute la boucle sur les GPU 2xT4 gratuits de Kaggle : construire le jeu de données, entraîner avec RLCD, ajuster les températures de calibration, évaluer et pousser le résultat vers le Hub. Cette page parcourt ce notebook et pointe les parties qui restent porteuses quand tu remplaces les données par les tiennes.
L’autre exemple travaillé — une tête de décision d’agent de navigation sur un seul GPU de 16 GB sans API payante — est à Ajuster finement Laya comme tête de décision d’un agent de navigation.
Ce que fait le notebook, dans l’ordre
| # | étape | ce qui se passe |
|---|---|---|
| 1 | Environnement | vérifie que les deux GPU T4 sont visibles et alloués |
| 2 | Installation | laya, transformers, datasets et les dépendances d’entraînement |
| 3 | Prétraitement | les 1,200 cas d’entraînement (6,000 décisions typées) deviennent des éléments tokenisés avec cibles souples, écrits sur disque pour les deux rangs DDP |
| 4 | Entraînement | train_ddp.py sous torchrun --nproc_per_node=2, quatre époques |
| 5 | Calibration | une température par type, ajustée sur une tranche mise de côté avant l’entraînement (dans le script d’entraînement, après la dernière époque) |
| 6 | Évaluation | la partition test officielle répondue par le checkpoint ajusté — 400 cas, 2,000 décisions — avec latence par cas |
| 7 | Métriques | exactitude, exactitude souple, Brier, ECE, MAE de score, à-un-niveau, KL/TV et percentiles de latence ; un tableau comparatif contre Jev et le plafond de l’enseignant |
| 8 | Publication | (optionnel) une fiche de modèle construite à partir des nombres de l’exécution elle-même, dossier téléversé vers le Hub |
| 9 | Rapport | benchmark_report.json avec le tableau de métriques et l’exactitude par workflow |
Réglages Kaggle : Accelerator GPU T4 x2, Internet On. Les sorties atterrissent dans
/kaggle/working/laya_finetuned_typed_decisions.
La recette d’entraînement
RLCD s’entraîne sur les distributions gold du benchmark, pas sur des étiquettes dures : chaque élément porte la probabilité que l’enseignant a attribuée à chaque option, et les deux moitiés de la perte lisent cette cible —
- un terme de gradient de politique sur des projections de logits bruitées échantillonnées (style GRPO : quatre échantillons par élément, bruit d’exploration amorti 0.4 → 0.1), récompensé par des règles de score propres (sphérique 0.75, probabilité classée 1.0) ;
- un terme d’entropie croisée souple à plein poids contre la même distribution.
Les réglages que le notebook fixe pour une carte de 16 GB :
| époques | 4 |
| lot effectif | 64 séquences (8 par micro-lot, 2 GPU, 4 étapes d’accumulation) |
| taux d’apprentissage | encodeur 2.5e-5, tête 1e-4 — AdamW, plan cosinus |
| mémoire | autocast fp16, gradient checkpointing sur l’encodeur et la tête, clip de norme de gradient 1.0 |
| budget de séquence | max_len 1024, head_max_len 256, max_tokens_per_batch 4096 |
Le temps d’exécution sur 2xT4 est de quelques minutes pour la démo et d’heures pour de vraies données : environ 4–6 minutes pour les 6,000 décisions de la démo, et environ 4–5 heures pour quatre époques sur ~30k questions.
Pour le pointer sur tes données, remplace les deux appels load_dataset et garde le schéma de lignes :
chaque cas porte state, questions et gold (les probabilités de l’enseignant par question), et le
préprocesseur les transforme en éléments. Les types de question sont choice, score et noul ; tout ce
que tu peux exprimer avec eux sur un état est permis.
La calibration fait partie de l’exécution
C’est l’étape la plus susceptible d’être abandonnée quand on copie la boucle, et elle est porteuse dès que quelqu’un conditionne sur la confiance.
Le notebook prélève une tranche de calibration hors des données d’entraînement avant de les répartir entre les rangs (jusqu’à 400 éléments, ou 10 %, à graine fixe, identique sur chaque rang). Ajuster les températures sur des éléments que l’exécution a déjà entraînés mesure l’ajustement plutôt que la calibration — le modèle est quasi certain et quasi correct sur eux, donc l’optimiseur n’a rien à assouplir et renvoie une échelle dégénérée.
Après la dernière époque, le rang 0 ajuste une température par type de question (choice, score,
noul) par LBFGS sur le logarithme de la température, écrêtée à [0.1, 10] (1.0 pour une tranche de
moins de dix éléments, 1.2 si l’ajustement lève une erreur). Les valeurs vont dans rl_agent_config.json
comme temperature, et le notebook supprime toute temperature_by_options héritée dans la même
écriture : ces vieilles valeurs par compartiment prennent le pas à l’inférence et masqueraient
silencieusement le nouvel ajustement.
L’échelonnage de température laisse l’argmax — et l’exactitude — inchangés ; ce qui bouge, c’est la confiance. Les checkpoints tels quels sont trop confiants, alors ajuste avant de te fier à un seuil, et évalue le résultat sur des données mises de côté avant de revendiquer une amélioration. Le test de régression de persistance de configuration tourne sans téléchargements ni entraînement :
python tests/test_calibration_persistence.py
Évaluer avant de s’y fier
L’évaluation est une passe complète sur la partition de test officielle : 400 cas, 2,000 décisions couvrant
Agent Trace Observability, Customer Service, Invoice Processing et Security Incidents. Elle calcule
l’exactitude, l’exactitude souple, Brier, ECE (via laya.common.ece_score), la MAE de score, à-un-niveau
et les percentiles de latence, puis construit un tableau comparatif dont les lignes de référence sont fixes :
| modèle | type | exactitude | ECE |
|---|---|---|---|
| TypeSafe Jev 1.13.0 | général | 0.727 | 0.144 |
| ModernBERT-base (149M) | spécialiste | 0.646 | 0.179 |
| Teacher Self-Agreement | plafond | 0.735 | — |
| Laya (checkpoint publié) | ajusté | 0.766 | — |
La ligne Laya de ta propre exécution est calculée de la même façon — le notebook reconstruit le tableau à
partir des nombres de l’exécution elle-même. Deux habitudes à copier : garde les tranches qui t’intéressent
(une langue, un workflow) dans des données mises de côté, et rapporte la calibration à côté de l’exactitude,
parce que le signal d’entraînement est une distribution, pas seulement une étiquette. Quand tu as des
nombres, un post dans les Discussions du dépôt est
l’endroit pour les partager ; les benchmarks et les limites connues vivent dans BENCHMARKS.md à la racine
du dépôt.
Pousser vers le Hub
La cellule de publication est le dernier kilomètre de la boucle, et elle est délibérément ennuyeuse :
- Mets un
HF_TOKENen écriture dans Kaggle (Add-ons → Secrets). La cellule lève une erreur avec les instructions exactes s’il manque. - Définis le dépôt de destination — la cellule livrée pointe par défaut vers un nom dans l’espace de noms du projet, alors change-le avant d’exécuter.
- Exécute-la. Elle écrit une fiche de modèle dont les nombres viennent du tableau de comparaison de cette
exécution, puis téléverse
model.safetensors,encoder/,tokenizer/,rl_agent_config.json, la fiche et le rapport de benchmark.
Le résultat se charge comme n’importe quel autre checkpoint — il n’y a pas d’API spécifique à l’ajustement fin :
import laya
agent = laya.load("your-org/your-checkpoint") # the repo you just pushed
result = agent.predict(state, questions)
Un checkpoint_latest/ roulant est écrasé après chaque époque, donc un timeout Kaggle ou un OOM coûte une
époque plutôt que l’exécution.
Ce qu’il faut surveiller
- La boucle ne vaut que par ses cibles. RLCD imite la distribution d’un enseignant sur tes questions ; collecte les confiances de l’enseignant avant (ou pendant) l’entraînement, et traite leur qualité comme le plafond.
- La tranche de calibration est petite exprès. Jusqu’à 400 éléments ou 10 % — assez pour trois scalaires par type, pas assez pour valider contre. Mets de côté tes propres données d’évaluation.
- Tes étiquettes doivent rentrer dans les trois primitives. Si ta décision n’est pas un choice, une échelle ou une probabilité oui/non, façonne-la d’abord en l’une d’elles. Deux arêtes vives sont déjà documentées : les nombres d’options élevés dégradent la sélection par confiance (#394), et la négation en choix forcé peut suivre la question plutôt que l’état (#377).
- Livre la config, pas seulement les poids. La
temperature_by_optionssupprimée est la partie qui dé-ajuste silencieusement une calibration si elle survit dans une config copiée.