batchCooking/services/tech-step-intent-service/tests/test_training_data_balance.py
Nicolas c7116d4a29 fix(recipes): reequilibre le corpus via substitution de synonyme plutot que du remplissage generique
Trois tentatives precedentes d'egaliser chaque technique a 20 utterances
ont toutes degrade le F1 agrege sous 0.8 (voir le commit revert
precedent). Nouvelle strategie, beaucoup plus conservatrice : egalise
chaque technique vers le maximum DEJA present dans le corpus (7 en fr,
5 en en, portes par cook/preheat), pas vers un nombre choisi dans
l'absolu - +3-4 utterances en moyenne par technique au lieu de +13-17.

augment_utterances.py (nouveau, reutilisable) genere le complement en
priorite par substitution de synonyme (un des synonyms propres a la
technique, en tete d'une utterance existante, remplace par un autre) -
avec un garde-fou supplementaire par rapport aux tentatives precedentes :
le synonyme de remplacement doit lui aussi etre a l'imperatif/infinitif,
pas juste le synonyme d'origine, pour eviter de substituer un groupe
nominal/adjectif ("a petit feu", "gros bouillons") a la place d'un
verbe et produire une phrase grammaticalement cassee. Tournures modales
uniquement en dernier recours pour les techniques dont le vocabulaire
n'apparait qu'en milieu de phrase (julienne, brunoise...).

Resultat : chaque technique a exactement 7 utterances en fr et 5 en en,
sans exception (tests/test_training_data_balance.py fait respecter cet
invariant). _TRAINING_ITERATIONS reste a 25 (inchange). start_period/
timeout d'attente /health releves de 900s a 1200s (temps d'entrainement
mesure ~930s contre ~670s avant, la marge de securite existante etait
devenue trop juste).

Suite complete locale : 35/35 verts (14m41s).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 19:08:33 +02:00

22 lines
1.2 KiB
Python

"""Garde-fou de non-régression pour l'équilibrage du corpus (voir
`training_data.py`'s propre commentaire de tête) : chaque technique doit
avoir exactement le même nombre d'`utterances` que chaque autre, par
locale — un déséquilibre entre classes est une source réelle de
classifications confiantes mais fausses sur une phrase jamais vue (constaté
en pratique — voir l'historique Git de ce fichier, trois tentatives
d'équilibrer vers un nombre plus élevé ont toutes dégradé le F1 agrégé de
`test/recipe-matching/tech-step-eval.test.ts` avant que la stratégie
actuelle — équilibrer vers le maximum déjà présent dans le corpus, pas un
nombre choisi dans l'absolu — ne passe cette même gate)."""
from intent_service.training_data import TECH_STEP_TRAINING_DATA
def test_every_technique_has_the_same_utterance_count_per_locale():
for locale in ("fr", "en"):
counts = {entry.uid: len(getattr(entry, locale).utterances) for entry in TECH_STEP_TRAINING_DATA}
distinct = set(counts.values())
assert len(distinct) == 1, (
f"utterance counts for locale {locale!r} aren't uniform across techniques "
f"(run augment_utterances.py to re-equalize): {counts}"
)