spec: Architecture complète avec VLM (5 couches détection)
- Ajout documentation VLM (Ollama qwen2.5vl:7b) - Pipeline complet: Regex → VLM → EDS-Pseudo → CamemBERT → Contextuel - Nouvelles exigences REQ-013/REQ-014 pour optimisation VLM - Tâches Phase 2.5: amélioration prompt, validation croisée, perf - Document ARCHITECTURE_REELLE.md avec détails complets - Matériel: AMD Ryzen 9 9950X, 128GB RAM, RTX 5070 12GB - Objectifs: Rappel ≥99.5%, Précision ≥97%, F1 ≥0.98
This commit is contained in:
571
.kiro/specs/anonymization-quality-optimization/QUICKSTART.md
Normal file
571
.kiro/specs/anonymization-quality-optimization/QUICKSTART.md
Normal file
@@ -0,0 +1,571 @@
|
||||
# Guide de Démarrage Rapide
|
||||
|
||||
## Installation des Dépendances
|
||||
|
||||
```bash
|
||||
# Installer les nouvelles dépendances
|
||||
pip install pytest pytest-cov pydantic structlog jinja2 matplotlib
|
||||
|
||||
# Vérifier l'installation
|
||||
python -c "import pytest, pydantic, structlog, jinja2, matplotlib; print('✅ Toutes les dépendances sont installées')"
|
||||
|
||||
# Vérifier la disponibilité CUDA
|
||||
python -c "import torch; print(f'CUDA disponible: {torch.cuda.is_available()}'); print(f'GPU: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else \"N/A\"}')"
|
||||
```
|
||||
|
||||
## Préparation de l'Environnement
|
||||
|
||||
```bash
|
||||
# Créer les répertoires nécessaires
|
||||
mkdir -p tests/ground_truth
|
||||
mkdir -p tests/unit
|
||||
mkdir -p tests/regression
|
||||
mkdir -p reports/quality
|
||||
mkdir -p evaluation
|
||||
mkdir -p detectors
|
||||
mkdir -p tools
|
||||
mkdir -p docs
|
||||
mkdir -p config
|
||||
|
||||
# Vérifier la structure
|
||||
tree -L 2 tests/ evaluation/ detectors/ tools/
|
||||
```
|
||||
|
||||
## Phase 1 : Création du Dataset de Test
|
||||
|
||||
### Étape 1.1 : Sélectionner les Documents
|
||||
|
||||
```bash
|
||||
# Aller dans le répertoire source
|
||||
cd "/home/dom/Téléchargements/II-1 Ctrl_T2A_2025_CHCB_DocJustificatifs (1)/"
|
||||
|
||||
# Lister tous les PDFs
|
||||
find . -name "*.pdf" -type f > /tmp/all_pdfs.txt
|
||||
wc -l /tmp/all_pdfs.txt # Compter le nombre total
|
||||
|
||||
# Analyser la répartition par dossier OGC
|
||||
for dir in */; do
|
||||
count=$(find "$dir" -name "*.pdf" -type f | wc -l)
|
||||
echo "$dir: $count PDFs"
|
||||
done | sort -t: -k2 -n
|
||||
|
||||
# Sélectionner manuellement 30 documents :
|
||||
# - 10 simples (1-2 pages, peu de PII)
|
||||
# - 15 moyens (3-5 pages, PII variés)
|
||||
# - 5 complexes (>5 pages, nombreux PII)
|
||||
|
||||
# Copier les documents sélectionnés
|
||||
# Exemple :
|
||||
cp "257_23209962/FC14.pdf" ~/path/to/project/tests/ground_truth/ogc_257_fc14.pdf
|
||||
cp "257_23209962/FC16.pdf" ~/path/to/project/tests/ground_truth/ogc_257_fc16.pdf
|
||||
# ... répéter pour les 30 documents
|
||||
```
|
||||
|
||||
### Étape 1.2 : Créer l'Outil d'Annotation
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > tools/annotation_tool.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Outil d'annotation CLI pour créer le dataset de test.
|
||||
Usage: python tools/annotation_tool.py tests/ground_truth/
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
# TODO: Implémenter l'outil d'annotation
|
||||
# Voir design.md section 2.1.2 pour les spécifications
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python tools/annotation_tool.py <ground_truth_dir>")
|
||||
sys.exit(1)
|
||||
|
||||
ground_truth_dir = Path(sys.argv[1])
|
||||
print(f"Annotation des documents dans : {ground_truth_dir}")
|
||||
# TODO: Implémenter la logique d'annotation
|
||||
EOF
|
||||
|
||||
chmod +x tools/annotation_tool.py
|
||||
```
|
||||
|
||||
### Étape 1.3 : Annoter les Documents
|
||||
|
||||
```bash
|
||||
# Lancer l'outil d'annotation
|
||||
python tools/annotation_tool.py tests/ground_truth/
|
||||
|
||||
# Pour chaque PDF, l'outil doit :
|
||||
# 1. Extraire et afficher le texte
|
||||
# 2. Demander de saisir les PII (type, texte, page, contexte)
|
||||
# 3. Demander les termes médicaux à préserver
|
||||
# 4. Sauvegarder en JSON
|
||||
|
||||
# Format de sortie attendu :
|
||||
# tests/ground_truth/ogc_257_fc14.pdf
|
||||
# tests/ground_truth/ogc_257_fc14.annotations.json
|
||||
```
|
||||
|
||||
## Phase 2 : Implémentation de l'Évaluation
|
||||
|
||||
### Étape 2.1 : Créer l'Évaluateur de Qualité
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > evaluation/quality_evaluator.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Évaluateur de qualité d'anonymisation.
|
||||
Compare les détections avec les annotations manuelles.
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List, Dict
|
||||
import json
|
||||
|
||||
@dataclass
|
||||
class EvaluationResult:
|
||||
true_positives: int
|
||||
false_positives: int
|
||||
false_negatives: int
|
||||
precision: float
|
||||
recall: float
|
||||
f1_score: float
|
||||
missed_pii: List[Dict]
|
||||
false_detections: List[Dict]
|
||||
|
||||
class QualityEvaluator:
|
||||
def __init__(self, ground_truth_dir: Path):
|
||||
self.ground_truth_dir = ground_truth_dir
|
||||
|
||||
def evaluate(self, pdf_path: Path, audit_path: Path) -> EvaluationResult:
|
||||
# TODO: Implémenter l'évaluation
|
||||
# Voir design.md section 2.2.1 pour les spécifications
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
# TODO: Ajouter CLI
|
||||
pass
|
||||
EOF
|
||||
|
||||
chmod +x evaluation/quality_evaluator.py
|
||||
```
|
||||
|
||||
### Étape 2.2 : Créer le Scanner de Fuite
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > evaluation/leak_scanner.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Scanner de fuite de PII dans les documents anonymisés.
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List, Dict
|
||||
|
||||
@dataclass
|
||||
class LeakReport:
|
||||
is_safe: bool
|
||||
leak_count: int
|
||||
leaks: List[Dict]
|
||||
|
||||
class LeakScanner:
|
||||
def scan(self, anonymized_pdf: Path, original_audit: Path) -> LeakReport:
|
||||
# TODO: Implémenter le scan
|
||||
# Voir design.md section 2.2.2 pour les spécifications
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
# TODO: Ajouter CLI
|
||||
pass
|
||||
EOF
|
||||
|
||||
chmod +x evaluation/leak_scanner.py
|
||||
```
|
||||
|
||||
### Étape 2.3 : Créer le Benchmark
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > evaluation/benchmark.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Benchmark de performance du système d'anonymisation.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import time
|
||||
import json
|
||||
|
||||
class Benchmark:
|
||||
def __init__(self, test_data_dir: Path):
|
||||
self.test_data_dir = test_data_dir
|
||||
|
||||
def run(self) -> Dict:
|
||||
# TODO: Implémenter le benchmark
|
||||
# Voir design.md section 2.2.3 pour les spécifications
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
# TODO: Ajouter CLI
|
||||
pass
|
||||
EOF
|
||||
|
||||
chmod +x evaluation/benchmark.py
|
||||
```
|
||||
|
||||
## Phase 3 : Mesure de la Baseline
|
||||
|
||||
### Étape 3.1 : Anonymiser les Documents de Test
|
||||
|
||||
```bash
|
||||
# Option 1 : Via GUI
|
||||
python Pseudonymisation_Gui_V5.py
|
||||
# Sélectionner le dossier tests/ground_truth/
|
||||
# Lancer l'anonymisation
|
||||
|
||||
# Option 2 : Via CLI (si disponible)
|
||||
python anonymizer_core_refactored_onnx.py \
|
||||
tests/ground_truth/*.pdf \
|
||||
--output tests/ground_truth/anonymized/ \
|
||||
--hf \
|
||||
--raster
|
||||
```
|
||||
|
||||
### Étape 3.2 : Évaluer la Baseline
|
||||
|
||||
```bash
|
||||
# Évaluer chaque document
|
||||
python evaluation/quality_evaluator.py \
|
||||
--ground-truth tests/ground_truth/ \
|
||||
--anonymized tests/ground_truth/anonymized/ \
|
||||
--output reports/baseline_evaluation.json
|
||||
|
||||
# Générer le rapport HTML
|
||||
python evaluation/quality_evaluator.py \
|
||||
--ground-truth tests/ground_truth/ \
|
||||
--anonymized tests/ground_truth/anonymized/ \
|
||||
--output reports/baseline_report.html \
|
||||
--format html
|
||||
```
|
||||
|
||||
### Étape 3.3 : Scanner les Fuites
|
||||
|
||||
```bash
|
||||
# Scanner tous les documents anonymisés
|
||||
for pdf in tests/ground_truth/anonymized/*.pdf; do
|
||||
audit="${pdf%.pdf}.audit.jsonl"
|
||||
python evaluation/leak_scanner.py \
|
||||
--anonymized "$pdf" \
|
||||
--audit "$audit" \
|
||||
--output "reports/leak_$(basename $pdf .pdf).json"
|
||||
done
|
||||
|
||||
# Générer un rapport consolidé
|
||||
python evaluation/leak_scanner.py \
|
||||
--batch tests/ground_truth/anonymized/ \
|
||||
--output reports/leak_report.html
|
||||
```
|
||||
|
||||
### Étape 3.4 : Benchmarker les Performances
|
||||
|
||||
```bash
|
||||
# Exécuter le benchmark
|
||||
python evaluation/benchmark.py \
|
||||
--test-dir tests/ground_truth/ \
|
||||
--iterations 3 \
|
||||
--output reports/baseline_benchmark.json
|
||||
|
||||
# Afficher les résultats
|
||||
python evaluation/benchmark.py \
|
||||
--show reports/baseline_benchmark.json
|
||||
```
|
||||
|
||||
## Phase 4 : Amélioration des Détecteurs
|
||||
|
||||
### Étape 4.1 : Créer les Regex Améliorées
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > detectors/improved_regex.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Regex améliorées pour la détection de PII.
|
||||
"""
|
||||
import re
|
||||
|
||||
# Téléphone amélioré (formats fragmentés)
|
||||
RE_TEL_IMPROVED = re.compile(
|
||||
r"(?<!\d)"
|
||||
r"(?:"
|
||||
r"(?:\+33|0033)\s*[1-9](?:[\s.\-]?\d){8}"
|
||||
r"|"
|
||||
r"0[1-9](?:[\s.\-]?\d){8}"
|
||||
r"|"
|
||||
r"0[1-9][\s.\-]?\d{1,2}[\s.\-]?\d{1,2}[\s\n]{1,3}\d{1,2}[\s.\-]?\d{1,2}[\s.\-]?\d{1,2}"
|
||||
r")"
|
||||
r"(?!\d)",
|
||||
re.MULTILINE
|
||||
)
|
||||
|
||||
# Email amélioré (domaines médicaux)
|
||||
RE_EMAIL_IMPROVED = re.compile(
|
||||
r"\b[A-Za-z0-9._%+-]+"
|
||||
r"@"
|
||||
r"(?:"
|
||||
r"(?:chu|ch|aphp|ap-hm|hospices-civils|clinique|hopital|ehpad)"
|
||||
r"[\w\-]*\.[a-z]{2,}"
|
||||
r"|"
|
||||
r"[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
|
||||
r")\b",
|
||||
re.IGNORECASE
|
||||
)
|
||||
|
||||
# TODO: Ajouter les autres regex améliorées
|
||||
# Voir design.md section 2.3.1 pour les spécifications
|
||||
EOF
|
||||
```
|
||||
|
||||
### Étape 4.2 : Créer le Détecteur Contextuel
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > detectors/contextual.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Détecteur contextuel pour les noms de personnes.
|
||||
"""
|
||||
import re
|
||||
from typing import List, Dict
|
||||
|
||||
class ContextualDetector:
|
||||
def __init__(self):
|
||||
self.strong_contexts = [
|
||||
r"(?:Dr\.?|Docteur|Pr\.?|Professeur)\s+{name}",
|
||||
r"(?:Mme|Madame|M\.|Monsieur)\s+{name}",
|
||||
r"Patient(?:e)?\s*:\s*{name}",
|
||||
]
|
||||
|
||||
def detect(self, text: str, page: int) -> List[Dict]:
|
||||
# TODO: Implémenter la détection contextuelle
|
||||
# Voir design.md section 2.3.2 pour les spécifications
|
||||
pass
|
||||
EOF
|
||||
```
|
||||
|
||||
### Étape 4.3 : Créer le Détecteur Hybride
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > detectors/hybrid.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Détecteur hybride combinant plusieurs méthodes.
|
||||
"""
|
||||
from typing import List, Dict
|
||||
|
||||
class HybridDetector:
|
||||
def __init__(self):
|
||||
# TODO: Initialiser les détecteurs
|
||||
pass
|
||||
|
||||
def detect(self, text: str, page: int) -> List[Dict]:
|
||||
# TODO: Implémenter le pipeline hybride
|
||||
# Voir design.md section 2.3.3 pour les spécifications
|
||||
pass
|
||||
EOF
|
||||
```
|
||||
|
||||
## Phase 5 : Tests et Validation
|
||||
|
||||
### Étape 5.1 : Créer les Tests Unitaires
|
||||
|
||||
```bash
|
||||
# Créer les fichiers de test
|
||||
mkdir -p tests/unit
|
||||
|
||||
# Tests des regex
|
||||
cat > tests/unit/test_improved_regex.py << 'EOF'
|
||||
import pytest
|
||||
from detectors.improved_regex import RE_TEL_IMPROVED, RE_EMAIL_IMPROVED
|
||||
|
||||
class TestImprovedRegex:
|
||||
@pytest.mark.parametrize("phone,should_match", [
|
||||
("06 12 34 56 78", True),
|
||||
("0612345678", True),
|
||||
("06 12 34\n56 78", True),
|
||||
("12345678901", False),
|
||||
])
|
||||
def test_phone_detection(self, phone, should_match):
|
||||
match = RE_TEL_IMPROVED.search(phone)
|
||||
assert (match is not None) == should_match
|
||||
|
||||
# TODO: Ajouter plus de tests
|
||||
EOF
|
||||
|
||||
# Exécuter les tests
|
||||
pytest tests/unit/ -v --cov=detectors
|
||||
```
|
||||
|
||||
### Étape 5.2 : Créer les Tests de Régression
|
||||
|
||||
```bash
|
||||
# Créer le fichier
|
||||
cat > tests/regression/test_regression.py << 'EOF'
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from evaluation.quality_evaluator import QualityEvaluator
|
||||
|
||||
class TestRegression:
|
||||
def test_quality_metrics(self):
|
||||
"""Vérifie que les métriques de qualité sont atteintes"""
|
||||
evaluator = QualityEvaluator(Path("tests/ground_truth"))
|
||||
# TODO: Implémenter le test
|
||||
# Vérifier Rappel >= 99.5%, Précision >= 97%
|
||||
pass
|
||||
|
||||
def test_no_performance_degradation(self):
|
||||
"""Vérifie qu'il n'y a pas de dégradation de performance"""
|
||||
# TODO: Implémenter le test
|
||||
# Vérifier temps < 30s par PDF
|
||||
pass
|
||||
EOF
|
||||
|
||||
# Exécuter les tests de régression
|
||||
pytest tests/regression/ -v
|
||||
```
|
||||
|
||||
### Étape 5.3 : Valider sur le Corpus Complet
|
||||
|
||||
```bash
|
||||
# Anonymiser tous les documents
|
||||
python Pseudonymisation_Gui_V5.py
|
||||
# Sélectionner : /home/dom/Téléchargements/II-1 Ctrl_T2A_2025_CHCB_DocJustificatifs (1)/
|
||||
# Lancer l'anonymisation
|
||||
|
||||
# Scanner toutes les fuites
|
||||
python evaluation/leak_scanner.py \
|
||||
--batch "/home/dom/Téléchargements/II-1 Ctrl_T2A_2025_CHCB_DocJustificatifs (1)/anonymise/" \
|
||||
--output reports/full_corpus_leak_report.html
|
||||
|
||||
# Vérifier qu'aucune fuite critique n'est détectée
|
||||
grep -i "CRITIQUE" reports/full_corpus_leak_report.html
|
||||
```
|
||||
|
||||
## Commandes Utiles
|
||||
|
||||
### Vérifier la Qualité du Code
|
||||
|
||||
```bash
|
||||
# Linter
|
||||
pylint detectors/ evaluation/ tools/
|
||||
|
||||
# Formatter
|
||||
black detectors/ evaluation/ tools/
|
||||
|
||||
# Type checker
|
||||
mypy detectors/ evaluation/ tools/
|
||||
|
||||
# Tout en une fois
|
||||
pylint detectors/ && black --check detectors/ && mypy detectors/
|
||||
```
|
||||
|
||||
### Générer la Documentation
|
||||
|
||||
```bash
|
||||
# Générer la doc API avec Sphinx (optionnel)
|
||||
sphinx-apidoc -o docs/api detectors/ evaluation/ tools/
|
||||
sphinx-build -b html docs/ docs/_build/
|
||||
|
||||
# Ou simplement documenter avec des docstrings
|
||||
python -m pydoc detectors.hybrid
|
||||
```
|
||||
|
||||
### Exporter les Résultats
|
||||
|
||||
```bash
|
||||
# Exporter les métriques en CSV
|
||||
python evaluation/quality_evaluator.py \
|
||||
--ground-truth tests/ground_truth/ \
|
||||
--output reports/metrics.csv \
|
||||
--format csv
|
||||
|
||||
# Exporter les graphiques
|
||||
python evaluation/quality_evaluator.py \
|
||||
--ground-truth tests/ground_truth/ \
|
||||
--output reports/charts/ \
|
||||
--format charts
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problème : Annotation trop longue
|
||||
|
||||
**Solution** : Paralléliser avec 2 annotateurs
|
||||
```bash
|
||||
# Annotateur 1 : documents 1-15
|
||||
python tools/annotation_tool.py tests/ground_truth/ --range 1-15
|
||||
|
||||
# Annotateur 2 : documents 16-30
|
||||
python tools/annotation_tool.py tests/ground_truth/ --range 16-30
|
||||
```
|
||||
|
||||
### Problème : GPU non détecté
|
||||
|
||||
**Solution** : Vérifier l'installation CUDA
|
||||
```bash
|
||||
# Vérifier CUDA
|
||||
nvidia-smi
|
||||
|
||||
# Vérifier PyTorch CUDA
|
||||
python -c "import torch; print(torch.cuda.is_available())"
|
||||
|
||||
# Réinstaller PyTorch avec CUDA si nécessaire
|
||||
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
||||
```
|
||||
|
||||
### Problème : VRAM insuffisante
|
||||
|
||||
**Solution** : Réduire la taille du batch
|
||||
```yaml
|
||||
# Dans config/quality_config.yml
|
||||
gpu:
|
||||
batch_size: 8 # Réduire de 16 à 8
|
||||
max_vram_gb: 8 # Réduire la limite
|
||||
```
|
||||
|
||||
### Problème : Traitement trop lent même avec GPU
|
||||
|
||||
**Solution** : Vérifier que le GPU est bien utilisé
|
||||
```python
|
||||
# Ajouter du logging dans le code
|
||||
import torch
|
||||
print(f"Device utilisé: {torch.cuda.get_device_name(0)}")
|
||||
print(f"VRAM utilisée: {torch.cuda.memory_allocated() / 1e9:.2f} GB")
|
||||
```
|
||||
|
||||
### Problème : Mémoire RAM insuffisante (peu probable avec 128 GB)
|
||||
|
||||
**Solution** : Réduire le nombre de workers
|
||||
```yaml
|
||||
# Dans config/quality_config.yml
|
||||
performance:
|
||||
max_workers: 4 # Réduire de 8 à 4
|
||||
```
|
||||
|
||||
## Ressources
|
||||
|
||||
- **Documentation** : `docs/`
|
||||
- **Spécifications** : `.kiro/specs/anonymization-quality-optimization/`
|
||||
- **Tests** : `tests/`
|
||||
- **Rapports** : `reports/`
|
||||
|
||||
## Support
|
||||
|
||||
Pour toute question :
|
||||
1. Consulter `requirements.md` pour les exigences
|
||||
2. Consulter `design.md` pour l'architecture
|
||||
3. Consulter `tasks.md` pour le plan détaillé
|
||||
4. Consulter `SUMMARY.md` pour le résumé exécutif
|
||||
Reference in New Issue
Block a user