batchCooking/services/tech-step-intent-service/tests/test_training_data_balance.py
Nicolas 0dadadfa24 feat(recipes): equilibre le corpus d'entrainement du textcat a 20 phrases par technique
Chaque technique n'avait que 3 a 7 utterances par locale (moyenne ~3.8),
un desequilibre reel entre classes qui contribue directement a des
classifications confiantes mais fausses sur une formulation jamais vue
(constate concretement dans la PR precedente : une phrase inedite pour
melt classee comme caramelize avec une confiance elevee).

Porte chaque technique a exactement 20 utterances par locale (fr et en) :
- Les utterances existantes sont conservees telles quelles, jamais
  reecrites.
- Le complement vient d'augment_utterances.py (nouveau script maintainer,
  reutilisable pour une future technique sous-alimentee) : enveloppe
  chaque utterance deja a l'imperatif/infinitif dans une tournure modale
  grammaticalement valide (il faut/veillez a/make sure to...) plutot que
  de dupliquer ou d'inventer du texte generique - vraie diversite de
  surface, vocabulaire distinctif de la technique intact.
- tests/test_training_data_balance.py fait respecter l'invariant en CI
  (20 minimum, meme nombre fr/en) pour toute future modification.

_TRAINING_ITERATIONS recalibre de 25 a 10 (locale_pipeline.py) pour
compenser les ~2.6x d'exemples par epoque : temps d'entrainement mesure
quasi identique a avant (~687s fr+en combines contre ~670s), confiance
egale ou meilleure sur les cas deja suivis (simmer 0.31 -> 0.48).

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

38 lines
1.7 KiB
Python

"""Garde-fou de non-régression pour l'équilibrage du corpus (voir
`training_data.py`'s propre commentaire de tête) : un textcat entraîné sur
des classes très inégales en nombre d'exemples 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). Chaque technique doit
avoir *au moins* 20 `utterances` par locale, et — pour rester vraiment
équilibré plutôt que juste "assez" — le même nombre pour les deux locales
d'une même technique."""
from intent_service.training_data import TECH_STEP_TRAINING_DATA
_MIN_UTTERANCES_PER_LOCALE = 20
def test_every_technique_has_at_least_the_minimum_utterances_per_locale():
short = [
(entry.uid, locale, len(getattr(entry, locale).utterances))
for entry in TECH_STEP_TRAINING_DATA
for locale in ("fr", "en")
if len(getattr(entry, locale).utterances) < _MIN_UTTERANCES_PER_LOCALE
]
assert short == [], (
f"{len(short)} (uid, locale) pair(s) below the {_MIN_UTTERANCES_PER_LOCALE}-utterance "
f"floor — run augment_utterances.py: {short}"
)
def test_every_technique_has_the_same_utterance_count_in_both_locales():
# Not just "both above the floor" — a technique whose fr/en counts drift
# apart re-introduces the same per-class imbalance this test file exists
# to catch, just between locales of the same technique instead of across
# techniques.
mismatched = [
(entry.uid, len(entry.fr.utterances), len(entry.en.utterances))
for entry in TECH_STEP_TRAINING_DATA
if len(entry.fr.utterances) != len(entry.en.utterances)
]
assert mismatched == [], f"fr/en utterance count mismatch: {mismatched}"