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>
38 lines
1.7 KiB
Python
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}"
|