feat(phase3): CamemBERT v3 + détection villes + initiales + texte espacé + docs réglementaires

Intégration du modèle CamemBERT-bio-deid v3 (F1=0.96, Recall=0.97, 1112 docs)
et corrections qualité issues de l'audit approfondi sur 29 fichiers.

Détection des villes en texte libre :
- Automate Aho-Corasick sur 33K communes INSEE + 11.6K villes FINESS
- Stratégie contextuelle : exige un contexte géographique (à, de, vers,
  habite, urgences de, etc.) sauf pour les villes composées (Saint-Palais)
- Blacklist de ~80 communes homonymes de mots courants (charge, signes, plan...)
- Normalisation SAINT↔ST pour les variantes orthographiques
- De 18 fuites de villes à 2 cas résiduels atypiques

Masquage des initiales de prénom :
- Post-traitement regex : "Dr T. [NOM]" → "Dr [NOM] [NOM]"
- Références initiales : "Ref : JF/VA" → "Ref : [NOM]/[NOM]"

Détection texte espacé d'en-tête :
- "C E N T R E  H O S P I T A L I E R" → [ETABLISSEMENT]

Autres corrections :
- Fix regex RE_EXTRACT_MME_MR (Mr?.? → Mr.?, \s+ → [ \t]+, * → {0,4})
- Stop words médicaux : lever, coucher, services hospitaliers (viscérale, etc.)
- CamemBERT NER manager : version tracking, propriété version, log F1/Recall
- Script finetune : export ONNX automatique + mise à jour VERSION.json
- Évaluateur qualité : exclusion stop words médicaux des alertes INSEE

Documentation :
- Spécifications techniques CamemBERT-bio-deid v3
- Conformité RGPD + AI Act (caviardage PDF raster)
- AIPD (Analyse d'Impact Protection des Données)

Score qualité : 97.0/100 (Grade A), Leak score 100/100

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 12:16:13 +01:00
parent c9572c383a
commit eb14cd219d
8 changed files with 1957 additions and 9 deletions

View File

@@ -3,13 +3,16 @@
"""
CamemBERT-bio NER Manager — Inférence ONNX pour la désidentification clinique.
================================================================================
Modèle fine-tuné sur almanach/camembert-bio-base avec des annotations silver
issues de 29 documents cliniques français (F1=89% sur validation).
Modèle fine-tuné sur almanach/camembert-bio-base avec des annotations silver.
Versions:
v2 (2026-03-09): 29 docs, 7K exemples — F1=0.90, Recall=0.93
v3 (2026-03-11): 1112 docs, 198K exemples — F1=0.96, Recall=0.97
Utilisé comme signal NER supplémentaire dans le pipeline d'anonymisation,
en complément d'EDS-Pseudo et GLiNER (vote majoritaire).
Inférence ONNX Runtime CPU : ~20 ms pour 512 tokens.
Inférence ONNX Runtime CPU : ~10-20 ms pour 512 tokens.
"""
from __future__ import annotations
@@ -70,6 +73,10 @@ class CamembertNerManager:
def is_loaded(self) -> bool:
return self._loaded
@property
def version(self) -> str:
return getattr(self, "_version", "?")
def load(self) -> None:
"""Charge le modèle ONNX et le tokenizer."""
if not _ORT_AVAILABLE:
@@ -102,7 +109,23 @@ class CamembertNerManager:
# Tokenizer
self._tokenizer = AutoTokenizer.from_pretrained(str(self._model_dir))
self._loaded = True
log.info(f"CamemBERT-bio ONNX chargé: {self._model_dir} ({len(self._id2label)} labels)")
# Lire la version depuis VERSION.json (si disponible)
self._version = "?"
version_path = self._model_dir.parent / "VERSION.json"
if version_path.exists():
try:
with open(version_path, encoding="utf-8") as vf:
vinfo = json.load(vf)
self._version = vinfo.get("current_version", "?")
v_meta = vinfo.get("versions", {}).get(self._version, {})
f1 = v_meta.get("f1", "?")
recall = v_meta.get("recall", "?")
log.info(f"CamemBERT-bio ONNX {self._version} chargé (F1={f1}, R={recall}, {len(self._id2label)} labels)")
except Exception:
log.info(f"CamemBERT-bio ONNX chargé: {self._model_dir} ({len(self._id2label)} labels)")
else:
log.info(f"CamemBERT-bio ONNX chargé: {self._model_dir} ({len(self._id2label)} labels)")
def unload(self) -> None:
self._session = None