Aller au contenu

Pipeline qualité

Avant que les données d'entraînement n'atteignent l'étape de fine-tuning, elles passent par un pipeline qualité en trois étapes : déduplication, filtrage et ordonnancement curriculaire.

Pourquoi la qualité compte

Les données brutes de honeypot sont bruitées. Le même script bot frappe des milliers de honeypots avec des commandes identiques. Sans déduplication, un modèle fine-tuné mémoriserait uname -a → discovery mais échouerait sur les commandes nouvelles. Sans ordonnancement curriculaire, l'entraînement serait instable.

Étape 1 — Déduplication

Méthode : hachage basé sur les trigrammes.

Pour chaque entrée d'entraînement, le pipeline extrait le texte de sortie, génère tous les trigrammes (séquences de 3 mots) des 80 premiers mots, et les hache en MD5. Si deux entrées partagent le même hash de trigrammes, le doublon est supprimé.

Seuil : configurable, défaut 0.85 de similarité.

Étape 2 — Filtrage qualité

Critère Min Max Justification
Nombre de tokens 50 2 000 Trop court = pas de signal. Trop long = bruit.
Score qualité 0.3 Calculé à partir du poids du verdict et du statut de validation

Pondération des verdicts

Le score qualité intègre la validation humaine quand disponible :

Statut de validation Facteur de poids
Non validé 0.3× poids de base
Humain d'accord 1.5× poids de base (plafonné à 1.0)
Humain en désaccord 2.0× poids de base (cas limite important)
Humain incertain 0.1× poids de base

Les entrées où l'humain est en désaccord reçoivent le poids le plus élevé car elles représentent les cas où le modèle s'est trompé — exactement ce qu'on veut que le modèle apprenne.

Étape 3 — Ordonnancement curriculaire

Les entrées sont triées par difficulté :

  1. Patterns simples d'abord — observations à commande unique, verdicts clairs
  2. Séquences multi-étapes — sessions avec 3–5 commandes
  3. Kill chains complexes — séquences de 5+ commandes couvrant plusieurs tactiques MITRE
  4. Cas limites en dernier — faux positifs, verdicts incertains, tentatives d'injection de prompt

Cela suit le principe d'apprentissage curriculaire : les modèles s'entraînent plus stablement quand ils voient les exemples faciles avant les difficiles.

Moteur de décroissance

Les observations plus anciennes perdent du poids au fil du temps via une fonction de décroissance à demi-vie :

poids = 0.5 ^ (temps_écoulé / demi_vie)

Demi-vie de base : 90 jours. Les modificateurs de décroissance négatifs augmentent le poids au fil du temps — utilisés pour les observations rares et à haute valeur (comme l'injection de prompt GLaDOS) qui deviennent plus importantes à mesure que le dataset grandit.

Exécution

from pdx.training.quality.pipeline import QualityPipeline

qp = QualityPipeline(
    min_quality=0.3,
    dedup_threshold=0.85,
    min_tokens=50,
    max_tokens=2000
)

clean_entries = qp.run(
    entries=raw_entries,
    dedup=True,
    quality_filter=True,
    curriculum=True
)

print(qp.stats)
# {"dedup_removed": 142, "quality_filtered": 38, "total_output": 820}