Автоматизация цикла переобучения
Преврати один деплой в воспроизводимый цикл: инструкция по запуску, скриптовая проверка допуска, автоматический выпуск с возможностью отката и еженедельный обзор.
Первый деплой — это проект; все последующие — процесс. Команды, автоматизировавшие цикл, переобучают модель за день, когда срабатывает оповещение об ухудшении результатов на отложенной выборке; команды без автоматизации в стрессовой ситуации восстанавливают процесс по памяти и выпускают регрессии. В этом уроке весь цикл проходит от начала до конца на модели таблеток: дообучение, проверка допуска и выпуск; в итоге ты составишь инструкцию, которая превратит следующий запуск в рутину.
Практические занятия
Цикл с ответственным за каждый шаг#
Если ты прошёл предыдущие уроки, вся информация о происхождении модели уже доступна: карточка Run Information указывает родительскую модель и закреплённую версию датасета, вкладка Models датасета содержит список всех моделей, обученных на каждой версии, а страница развёртывания ссылается на обслуживающую модель. Если точность снизилась, начни с развёртывания и проследи цепочку в обратном порядке.

Agents автоматизирует сбор данных. Функция Collect Uncertain Detections выполняет предсказания через твоё развёртывание и копирует изображения с детекциями в заданном диапазоне уверенности в датасет для проверки; функция Capture and Alert сохраняет подходящие изображения и отправляет сообщение в Slack. Рабочие процессы запускаются по нажатию Run, поэтому включи запуск в еженедельную проверку.

Пример: полный цикл для модели таблеток#
1. Дообучи развёрнутую модель. На Platform выбери развёрнутую модель в разделе My Models, включи Save Dataset Version и явно укажи оптимизатор. Локально этот шаг выглядит так:
from ultralytics import YOLO
model = YOLO("pills-v1.pt") # лучшая модель развёрнутой модели — best.pt
model.train(data="medical-pills.yaml", epochs=5, imgsz=320, optimizer="SGD", lr0=0.001, name="v2-finetune")Это дообучение из урока Обучение, просмотр и дообучение запусков: mAP50-95 вырос с 0.659 до 0.687.
2. Сравни её с развёрнутой моделью. Повторно используй gate.py из урока 6 с отложенной выборкой и двумя контрольными точками:
DATA = "medical-pills.yaml" # YAML-файл датасета отложенной выборки или URI ul://
BASELINE, CANDIDATE = "pills-v1.pt", "pills-v2.pt" # развёрнутая модель и переобученный кандидат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 candidateПроверка завершается с кодом 0, поэтому CI может перейти к выпуску. (В этом примере валидационная выборка medical-pills используется вместо отложенной; в рабочей среде используй версию отложенной выборки, которую модель никогда не видела.)
3. Выпусти модель. Загрузи или обучи кандидата в той же рабочей области, затем позволь CI вызвать Replace model через SDK ultralytics-platform и убедись, какая модель обслуживает запросы:
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")При тестировании с имитацией API, который сначала сообщает deploying, а затем ready, вывод будет таким:
deploying - Replacement model is deploying
status=ready model=v2-finetunedeployments.update отправляет PATCH /api/deployments/{owner}/{deployment} вместе с action: "replace"; старая модель продолжает обслуживать запросы, пока новая не будет готова. Цикл опрашивает retrieve, пока статус не сменится с deploying, а затем проверяет обслуживающую модель: неудачное развёртывание тоже завершается со статусом ready, но при этом остаётся старая модель. Для отката используй тот же скрипт, установив NEW_MODEL в предыдущую версию. Утилита командной строки ul cloud, входящая в состав ultralytics, использует тот же API, а в справочнике API описаны все вызовы.
4. Сбрось базовый уровень. Запусти holdout_check.py из урока 8 с новой контрольной точкой и новым файлом истории.
Составь инструкцию по эксплуатации#
# 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.Запланируй еженедельную 15-минутную проверку и ответь на два вопроса: есть ли проблемы (проверка конечной точки, отложенная выборка, доля правок) и изменилось ли что-нибудь в развёртывании — и почему? В большинстве недель ответ на оба вопроса — нет, и встреча занимает пять минут. Типичный квартал выглядит так:
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.Подводные камни#
Симптом: релиз прошёл неудачно, а предыдущая модель исчезла. Решение: храни в проекте как минимум две последние модели, использовавшиеся в продакшене. При удалении модель перемещается в корзину, а окончательное удаление модели также удаляет любое развёртывание, которое продолжает её использовать.
Симптом: ты запланировал канареечное развёртывание с долями 10%/50%/100%, но при замене модели весь трафик переключается сразу. Решение: каждый эндпоинт обслуживает одну модель. Для канареечного развёртывания размести кандидата на втором эндпоинте и разделяй трафик в собственном маршрутизаторе, а затем замени модель и удали второй эндпоинт.
Симптом: каждый кандидат проходит проверку, но в продакшене качество всё равно падает. Решение: проверка объективна только на отложенной версии, на которой не обучался ни один запуск. Храни отложенную выборку в отдельном приватном датасете и никогда не объединяй её с обучающими данными.
Показать решение
Пример цикла для линии таблеток. Триггер: результат проверки отложенной выборки за ночную смену снизился на 0.05. Сбор данных: 180 примеров из Monitoring за вечернюю смену сохранены в pill-review, ещё 120 получены от агента Collect Uncertain Detections; Batch Annotation при пороге 0.35 с развёрнутой моделью v2-finetune, доля правок — 18%; данные проверены и объединены; аудит пройден; версия — v6: +300 night-shift frames. Дообучи v3-night на основе v2-finetune, SGD, lr0 0.001, 20 эпох. Проверка на отложенной выборке из 300 изображений, включая 100 ночных: mAP50-95 вырос с 0.66 до 0.71, слабых классов нет, 4 мс: PASS. release.py с NEW_MODEL = "v3-night" сообщает status=ready model=v3-night; holdout_check.py записывает новый базовый уровень — 0.71. v2-finetune остаётся в проекте как модель для отката, а инструкция по эксплуатации, проверка и скрипт выпуска зафиксированы одним коммитом.