Ultralytics YOLO27 : Inscris-toi sur la liste d’attente.
Get Started
Développer avec Ultralytics Platform·Entraîner et évaluer·Leçon 6/10
Leçonintermédiaire

Comparer des exécutions et choisir la meilleure

Compare des exécutions dans un projet Platform, consigne la raison d’être de chacune et détermine si un candidat doit être déployé à l’aide d’un script de validation avant promotion.

Les modèles plus grands obtiennent généralement une meilleure métrique principale, puis échouent sur une classe que personne n’a vérifiée. Sans règle définie à l’avance, l’exécution déployée est simplement celle que quelqu’un préfère. Cette leçon consigne chaque exécution pour qu’on puisse retrouver son raisonnement plus tard, et transforme « est-ce mieux ? » en un script de validation qui renvoie PASS ou FAIL.

Résultat

Tu peux comparer des exécutions dans un projet Platform, documenter chacune d’elles et exécuter une validation avant promotion qui vérifie la métrique globale, chaque classe et la latence avant le déploiement d’un candidat.

Parcours accéléré
Si tu connais déjà les bases, voici la version courte.
  1. Regroupe les exécutions associées dans un même projet ; utilise la vue Table avec Diff pour voir les changements.

  2. Nomme les exécutions <dataset-version>_<change> et enregistre l’hypothèse et le résultat comme Custom Metadata.

  3. Définis les critères avant de consulter les résultats : dépasser le bruit sur mAP50-95, conserver 90 % de l’AP de chaque classe et respecter le budget de latence.

  4. Confirme les finalistes sur des données mises de côté à l’aide du script de validation ; n’utilise la partition de test qu’une seule fois, à la fin.

Pratique

Comparer des exécutions dans un projet#

Projet logistique d’Ultralytics Platform en vue Table, avec les modèles listés dans une barre latérale et leurs paramètres d’entraînement et métriques finales affichés côte à côte

Un projet répertorie ses modèles avec des cases à cocher. Les modèles sélectionnés se superposent dans le tableau de bord Charts ; la vue Table aligne les paramètres d’entraînement et les métriques finales, et Diff masque les colonnes identiques pour que tu voies immédiatement que deux exécutions ne diffèrent que par imgsz. La comparaison s’effectue au sein d’un même projet : regroupe donc les expériences associées (les modèles peuvent être coupés et collés d’un projet à l’autre). Pour analyser les courbes, compare la valeur finale, la vitesse à laquelle chaque exécution l’a atteinte et la régularité de son évolution.

Vue Charts du projet logistique d’Ultralytics Platform, avec les courbes de précision et de rappel de plusieurs modèles superposées et le panneau Ask AI comparant les modèles terminés dans un tableau

Avec au moins deux modèles terminés, Compare with AI demande à Ask AI de résumer les différences et de proposer l’expérience suivante. Considère sa proposition comme une hypothèse pour ta prochaine exécution, pas comme une conclusion.

Rendre chaque exécution explicable#

Les noms portent le sens : run_5 ne dit rien, tandis que v3_pallets_added et v4_imgsz1024 indiquent la version du jeu de données et la modification apportée. Pour consigner le raisonnement, ouvre More actions > Information sur la page du modèle et enregistre une note JSON dans Custom Metadata :

{
  "hypothesis": "Pallet AP is low because val holds only 7 pallets",
  "change": "Dataset v3: +80 pallet images from cam03 and cam07; fine-tuned from v2",
  "result": "Pallet AP 0.31 -> 0.58, overall mAP50-95 0.51 -> 0.59",
  "next": "Forklift recall drops at night; collect dawn and dusk footage"
}

Platform consigne le reste : la carte Run Information affiche le GPU, le tarif horaire, le coût total, la version ultralytics, l’hôte, le modèle parent, la version épinglée du jeu de données, le commit Git lorsqu’il est disponible et une commande yolo train que tu peux copier. Les comparaisons ne sont équitables qu’entre des exécutions utilisant la même version de jeu de données : chaque exécution doit donc en avoir une d’épinglée.

Choisir la métrique et les critères avant d’examiner les résultats#

Vue Validation du modèle dans Ultralytics Platform avec les courbes Precision-Recall, F1-Confidence, Precision-Confidence et Recall-Confidence, une ligne par classe

IndicateurQuand l’utiliser
mAP50-95Valeur par défaut pour detect, segment, pose et OBB : récompense les boîtes bien ajustées et reste assez stable pour permettre les comparaisons
mAP50Objets volumineux et bien séparés pour lesquels l’ajustement des boîtes importe peu
AP par classe pour une seule classeUne classe représente l’essentiel de la valeur commerciale
Rappel à précision fixeSystèmes de sécurité et d’alarme
Latence d’inférence sur la cibleToujours, comme limite stricte

Le guide des métriques de performance YOLO explique chacune d’elles. Un candidat n’est déployé que s’il satisfait tous les critères :

Exemple pratique : un script de validation avant promotion#

Télécharge les fichiers best.pt des finalistes et évalue-les sur des données identiques avec le même code. Cet exemple utilise deux checkpoints officiels pour pouvoir être exécuté partout :

from ultralytics import YOLO

DATA = "coco8.yaml"  # identical held-out data for both runs; use your test split for the final call
BASELINE, CANDIDATE = "yolo26n.pt", "yolo26s.pt"  # e.g. best.pt from two Platform runs
NOISE, CLASS_FLOOR, LATENCY_BUDGET_MS = 0.005, 0.90, 100.0

def evaluate(weights):
    m = YOLO(weights).val(data=DATA, plots=False, verbose=False)
    per_class = {m.names[int(c)]: ap for c, ap in zip(m.box.ap_class_index, m.box.ap)}
    return m.box.map, per_class, m.speed["inference"]

(base_map, base_ap, _), (cand_map, cand_ap, cand_ms) = evaluate(BASELINE), evaluate(CANDIDATE)
weak = [n for n, ap in base_ap.items() if cand_ap.get(n, 0) < CLASS_FLOOR * ap]
gates = {
    f"mAP50-95 {base_map:.3f} -> {cand_map:.3f} beats noise": cand_map - base_map > NOISE,
    f"every class keeps {CLASS_FLOOR:.0%} of its AP (weak: {', '.join(weak) or 'none'})": not weak,
    f"inference {cand_ms:.1f} ms within {LATENCY_BUDGET_MS:.0f} ms": cand_ms <= LATENCY_BUDGET_MS,
}
for name, ok in gates.items():
    print("PASS" if ok else "FAIL", name)
print("verdict:", "ship the candidate" if all(gates.values()) else "keep the baseline, run more experiments")
raise SystemExit(0 if all(gates.values()) else 1)  # non-zero exit blocks a CI release step
PASS mAP50-95 0.669 -> 0.693 beats noise
FAIL every class keeps 90% of its AP (weak: elephant, potted plant)
PASS inference 44.1 ms within 100 ms
verdict: keep the baseline, run more experiments

Résultat : le modèle le plus grand l’emporte au classement général avec 2,4 points d’avance, mais deux classes perdent plus de 10 % de leur AP ; il échoue donc. C’est la régression que masque une comparaison limitée à la métrique principale. Le dictionnaire par classe provient de ap_class_index et de ap, qui ne couvrent que les classes présentes dans les données ; la latence est mesurée sur la machine qui exécute le script. Exécute donc la validation sur du matériel similaire à ta cible de déploiement. COCO8 ne comporte que 8 images de validation, bien trop peu pour prendre une véritable décision. Utilise un jeu de données de validation mis de côté d’au moins quelques centaines d’images et transmets split="test" une seule fois, pour la décision finale.

Examiner les images problématiques#

Pour les exécutions de détection entraînées avec une version de jeu de données enregistrée, la vue Validation ajoute Validation insights : les images les plus et les moins performantes selon le F1 par image, affichées avec la vérité terrain ; un explorateur de caractéristiques qui corrèle le F1 à la taille de l’image, au rapport hauteur/largeur et au nombre d’instances ; et les classes les plus associées aux échecs. L’option Find similar sur les images les moins performantes ajoute des images similaires au jeu d’entraînement en tant qu’images non étiquetées, transformant un échec de validation en tâche concrète sur les données.

Pièges#

La partition de test est devenue un jeu de réglage

Symptôme : le mAP de test annoncé est excellent, mais les résultats en production sont moins bons. Correctif : règle le modèle sur la partition de validation. Si tu as comparé dix exécutions sur la partition de test, tu l’as utilisée pour le réglage et son score est optimiste. Évalue les finalistes sur la partition de test une seule fois, tout à la fin.

Comparer des exécutions sur différentes versions du jeu de données

Symptôme : une exécution « gagne » de 4 points, et personne ne peut expliquer pourquoi. Correctif : vérifie la version épinglée du jeu de données dans la fiche Run Information de chaque exécution. Si les versions diffèrent, relance l’évaluation de référence sur la nouvelle version avant toute comparaison.

Prendre le bruit pour une victoire

Symptôme : le gagnant change à chaque réentraînement avec une nouvelle graine. Correctif : sur la plupart des jeux de données, les écarts inférieurs à environ 0,5 point de mAP relèvent du bruit d’une exécution à l’autre. Garde le seuil de bruit dans le critère de validation et utilise un jeu de réserve plus grand lorsque les résultats sont aussi proches.

Essayer

Entraîne deux modèles qui ne diffèrent que par un seul paramètre (taille d’image, taille du modèle ou version du jeu de données), vérifie dans la vue Table avec Diff que seul ce paramètre diffère, puis enregistre une note Custom Metadata pour chaque modèle. Exécute ensuite gate.py avec tes deux fichiers best.pt, tes données mises de côté et un budget de latence adapté à ta cible, puis consigne la décision.

Terminé lorsque
Tu as terminé la leçon lorsque tous les éléments suivants sont réunis.
  • Les deux exécutions figurent dans un même projet, et Diff affiche un seul paramètre modifié.

  • Chaque exécution comprend une note Custom Metadata indiquant l’hypothèse, la modification et le résultat.

  • gate.py a affiché PASS ou FAIL pour les trois critères, et tu as consigné la suite à donner.

Afficher la solution

Exemple de réponse pour le modèle de pilules : comparaison de la référence v1-baseline (10 époques) au candidat v2-finetune (5 époques supplémentaires, SGD, lr0 0.001). Définis DATA = "medical-pills.yaml" et les deux poids dans gate.py. Résultat : PASS mAP50-95 0.659 -> 0.687 beats noise, PASS every class keeps 90% of its AP (weak: none), PASS inference 4.0 ms within 100 ms ; décision : « déployer le candidat ». Custom Metadata sur v2 : hypothèse « v1 s’améliorait encore à l’époque 10 », modification « ajustement fin de 5 époques, SGD lr0 0.001 », résultat « mAP50-95 0.659 -> 0.687 ». À noter dans les métadonnées : la validation de medical-pills a également guidé l’entraînement ; confirme donc le résultat sur un jeu de données distinct mis de côté avant la mise en production.

Et ensuite ?

Tu as choisi un gagnant. Ensuite, tu le placeras derrière un point de terminaison dédié et l’appelleras depuis du code capable de gérer les démarrages à froid.