Automatiser la boucle de réentraînement
Transforme un déploiement en une boucle reproductible : un guide opérationnel, une étape de validation avant promotion scriptée, une publication automatisée avec retour arrière et une revue hebdomadaire.
Le premier déploiement est un projet ; tous les suivants relèvent d’un processus. Les équipes qui scriptent la boucle réentraînent le modèle en un après-midi lorsque l’alerte du jeu de validation se déclenche ; les autres reconstruisent le processus de mémoire sous pression et mettent en production des régressions. Cette leçon exécute la boucle de bout en bout une fois sur le modèle de pilules — ajustement fin, validation et publication — puis rédige le guide opérationnel qui rendra la prochaine exécution routinière.
Pratique
La boucle, avec un responsable à chaque étape#
La traçabilité est automatique si tu as suivi les leçons précédentes : la fiche Run Information d'un modèle indique son modèle parent et la version épinglée du jeu de données, l'onglet Models du jeu de données répertorie chaque modèle entraîné sur chaque version, et la page de déploiement renvoie au modèle qu'elle sert. Quand la précision baisse, pars du déploiement et remonte la chaîne.

Agents automatise l'étape de collecte. Collect Uncertain Detections effectue des prédictions avec ton déploiement et copie dans un jeu de données de révision les images comportant des détections dont le niveau de confiance se situe dans une plage donnée ; Capture and Alert enregistre les images correspondantes et publie un message dans Slack. Les workflows s'exécutent quand tu cliques sur Run : ajoute donc une exécution à ta revue hebdomadaire.

Exemple détaillé : un cycle complet sur le modèle de pilules#
1. Affine le modèle déployé. Sur Platform, sélectionne le modèle déployé sous My Models, active Save Dataset Version et définis explicitement l'optimiseur. En local, l'étape est identique :
from ultralytics import YOLO
model = YOLO("pills-v1.pt") # le best.pt du modèle déployé
model.train(data="medical-pills.yaml", epochs=5, imgsz=320, optimizer="SGD", lr0=0.001, name="v2-finetune")Il s'agit de l'affinage présenté dans Entraîner, consulter et affiner des exécutions : mAP50-95 passe de 0.659 à 0.687.
2. Évalue-le par rapport au modèle déployé. Réutilise gate.py de la leçon 6 avec le jeu de validation réservé et les deux checkpoints :
DATA = "medical-pills.yaml" # le fichier YAML de ton jeu de validation réservé ou son URI ul://
BASELINE, CANDIDATE = "pills-v1.pt", "pills-v2.pt" # modèle déployé par rapport au candidat réentraîné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
verdict: ship the candidateLe contrôle se termine avec le code 0 ; la CI peut donc passer à l'étape de publication. (Dans cette démo, la partition val de medical-pills sert de jeu de validation réservé ; en production, utilise une version de jeu de validation que le modèle n'a jamais vue.)
3. Publie-le. Envoie le candidat ou entraîne-le dans le même espace de travail, puis laisse la CI appeler Replace model via le SDK ultralytics-platform et vérifie quel modèle est en service :
import time
from ultralytics_platform import Platform
OWNER, DEPLOYMENT = "your-username", "pill-detector-st-ghislain"
PROJECT, NEW_MODEL = "pill-inspection", "v2-finetune"
with Platform() as client: # reads ULTRALYTICS_API_KEY
body = {"action": "replace", "project": PROJECT, "model": NEW_MODEL}
reply = client.deployments.update(OWNER, DEPLOYMENT, body=body)
print(reply["status"], "-", reply["message"]) # "deploying" while the new model starts
while (deployment := client.deployments.retrieve(OWNER, DEPLOYMENT)["deployment"])["status"] == "deploying":
time.sleep(15)
print(f"status={deployment['status']} model={deployment.get('model')}")
if deployment.get("model") != NEW_MODEL: # a failed rollout leaves the previous model serving
raise SystemExit("Replacement failed; the previous model is still live")Avec une API simulée qui renvoie deploying une fois, puis ready, le script affiche :
deploying - Replacement model is deploying
status=ready model=v2-finetunedeployments.update envoie PATCH /api/deployments/{owner}/{deployment} avec action: "replace" ; l'ancien modèle reste en service jusqu'à ce que le nouveau soit prêt. La boucle interroge retrieve jusqu'à ce que le statut ne soit plus deploying, puis vérifie le modèle en service, car un déploiement ayant échoué se termine également par ready, mais avec l'ancien modèle. Pour revenir en arrière, utilise le même script en définissant NEW_MODEL sur la version précédente. L'outil en ligne de commande ul cloud, fourni avec ultralytics, utilise la même API, et la référence de l'API documente chaque appel.
4. Réinitialise la référence. Exécute holdout_check.py de la leçon 8 avec le nouveau checkpoint et un fichier d'historique vierge.
Rédige le runbook#
# Retraining runbook: pill-detector
## Trigger
- Holdout mAP50-95 more than 1 point below baseline for 2 consecutive weeks, OR
- Batch Annotation edit rate above 25% on a new batch.
## Steps
1. Collect: Save to dataset from Monitoring, plus the "Collect Uncertain Detections" agent into pill-review.
2. Label: Batch Annotation with the deployed model at the swept threshold; review every image; record the edit rate.
3. Merge into the training dataset; rerun the duplicate check, class audit, and Clustering.
4. Create dataset version v(n+1) with a description of what changed.
5. Fine-tune from the deployed model with Save Dataset Version on; optimizer SGD, lr0 0.001.
6. Run gate.py against the deployed model on the holdout. Stop here on any FAIL.
7. ML lead approves; CI runs release.py.
8. Watch endpoint_check.py for 24 hours; start a new holdout baseline.
## Rollback
- Run release.py with NEW_MODEL set to the previous version. Never delete that model while it's the rollback target.
## Owner
- ML lead approves step 7. On-call runs steps 1-6 and 8.Réserve 15 minutes chaque semaine dans ton calendrier pour répondre à deux questions : y a-t-il quelque chose en rouge (vérification du point de terminaison, jeu de validation réservé, taux de modification) et quelque chose a-t-il changé dans le déploiement, et pourquoi ? La plupart des semaines, la réponse aux deux questions est non et la réunion dure cinq minutes. Voici à quoi ressemble un trimestre type :
Week 1 : Holdout alert. Collect, label, retrain, gate, release v(n+1).
Week 2-3 : Quiet. Checks green.
Week 4 : New defect class requested. Label, new version, retrain v(n+2).
Week 5-7 : Quiet.
Week 8 : Second plant in Poland. Check regions; add an endpoint in europe-central2.
Week 9-11: Quiet.
Week 12 : Quarterly holdout refresh and review.Pièges#
Symptôme : une mise en production se passe mal et le modèle précédent a disparu. Correctif : conserve au moins les deux derniers modèles de production dans le projet. La suppression d’un modèle le place dans la corbeille ; sa suppression définitive supprime aussi tout déploiement qui le sert encore.
Symptôme : tu as prévu un déploiement canari à 10 %/50 %/100 %, mais Remplacer le modèle bascule tout le trafic d’un coup. Correctif : chaque point de terminaison sert un seul modèle. Pour un déploiement canari, déploie le modèle candidat sur un deuxième point de terminaison et répartis le trafic dans ton propre routeur, puis remplace le modèle et supprime le deuxième point de terminaison.
Symptôme : tous les candidats franchissent le seuil, mais les performances en production régressent quand même. Correctif : l’évaluation n’est fiable que sur une version de réserve utilisée par aucun entraînement. Conserve le jeu de réserve dans son propre jeu de données privé et ne le fusionne jamais avec les données d’entraînement.
Afficher la solution
Cycle détaillé pour la chaîne de pilules. Déclencheur : le contrôle du jeu de validation réservé de nuit a baissé de 0.05. Collecte : 180 exemples du suivi de l'équipe du soir enregistrés dans pill-review, plus 120 exemples de l'agent Collect Uncertain Detections ; annotation par lots à 0.35 avec le v2-finetune déployé, taux de modification de 18 % ; révision et fusion ; audits sans anomalie ; version v6: +300 night-shift frames. Affine v3-night à partir de v2-finetune, avec SGD, lr0 à 0.001 et 20 époques. Évaluation sur les 300 images du jeu de validation réservé, dont 100 images de nuit : mAP50-95 passe de 0.66 à 0.71, aucune classe faible, 4 ms : RÉUSSITE. release.py avec NEW_MODEL = "v3-night" indique status=ready model=v3-night ; holdout_check.py enregistre une nouvelle référence de 0.71. v2-finetune reste dans le projet comme cible de retour arrière, et le runbook, le contrôle et le script de publication sont validés ensemble.