label-quality-audit

Par mkurman · zorai

Auditez la qualité des labels à l'aide du confident learning (Northcutt et al.), de la détection de bruit par validation croisée et de l'analyse des erreurs par classe. Identifie les exemples mal étiquetés pour révision.

npx skills add https://github.com/mkurman/zorai --skill label-quality-audit

Audit de qualité des étiquettes

Vue d'ensemble

Le bruit dans les étiquettes est le problème de qualité des données le plus insidieux — il reste invisible jusqu'à ce que le modèle apprenne la mauvaise chose. Le confident learning (Northcutt et al., 2021) identifie les exemples probablement mal étiquetés en utilisant des probabilités prédites hors-échantillon.

Quand l'utiliser

Utilisez-le quand : les étiquettes des données d'entraînement proviennent de travailleurs crowdsourcés, de systèmes automatisés ou de supervision faible. Ne l'utilisez pas sur des données de référence validées par des experts sauf pour auditer une dérive.

Pipeline de Confident Learning

import numpy as np
from sklearn.model_selection import cross_val_predict
from sklearn.ensemble import RandomForestClassifier

def confident_learning_audit(X, y, n_folds=5):
    """
    Returns indices of likely mislabeled examples.
    Based on Northcutt et al. "Confident Learning: Estimating
    Uncertainty in Dataset Labels" (JMLR 2021).
    """
    n_classes = len(np.unique(y))

    # 1. Out-of-sample predicted probabilities
    proba = cross_val_predict(
        RandomForestClassifier(n_estimators=100, random_state=42),
        X, y, cv=n_folds, method="predict_proba"
    )

    # 2. Compute confident joint
    # Estimated joint distribution of noisy labels × true labels
    confident_joint = np.zeros((n_classes, n_classes))
    for i in range(len(y)):
        true_class = y[i]
        pred_class = np.argmax(proba[i])
        confidence = proba[i][pred_class]

        # Count if predicted class has confidence above per-class threshold
        class_threshold = np.percentile(proba[:, pred_class], 70)
        if confidence > class_threshold:
            confident_joint[true_class][pred_class] += 1

    # 3. Find label issues: examples where predicted ≠ given AND confident
    issues = []
    per_class_thresholds = {
        k: np.percentile(proba[:, k], 70) for k in range(n_classes)
    }

    for i in range(len(y)):
        pred_class = np.argmax(proba[i])
        if (pred_class != y[i] and 
            proba[i][pred_class] > per_class_thresholds[pred_class]):
            issues.append(i)

    # 4. Per-class noise estimates
    noise_rates = {}
    for k in range(n_classes):
        n_in_class = np.sum(y == k)
        n_noisy = np.sum((np.array(issues) != y[np.array(issues)]) & 
                         (y[np.array(issues) == k]))
        noise_rates[k] = n_noisy / n_in_class if n_in_class > 0 else 0

    return {
        "issue_indices": issues,
        "n_issues": len(issues),
        "issue_fraction": len(issues) / len(y),
        "noise_rates": noise_rates,
        "confident_joint": confident_joint,
    }

Analyse par classe

Classe Total Mal étiquetée Taux de bruit Action
Classe bruit élevé N M > 0,10 Vérifier les directives d'annotation
Bruit moyen N M 0,05-0,10 Vérifier 50 exemples
Bruit faible N M < 0,05 OK

Que faire avec les problèmes détectés

  1. Ne jamais corriger automatiquement en fonction des prédictions du modèle — cela renforce le biais du modèle.
  2. Marquer pour révision humaine. Si impossible, supprimer de l'entraînement (pas du test).
  3. Ré-annoter un échantillon stratifié pour estimer le vrai taux de bruit.
  4. Si le taux de bruit > 20 %, envisager une ré-annotation plutôt qu'un nettoyage.

Skills similaires