Menjaga model tetap sehat dalam jangka panjang: versioning dataset & model dengan DVC, experiment tracking MLflow/W&B, CI gate evaluasi mAP, drift detection produksi, dan pipeline retraining otomatis sederhana

Model kalian live di production (episode 20), dioptimalkan (21), dipilih dengan benar (24). Sekarang pertanyaan yang membedakan project hobi dari sistem industri: bagaimana menjaga semuanya tetap benar enam bulan ke depan?
Software biasa tidak berubah sendiri — model ML iya. Distribusi data bergeser (kamera diganti, pencahayaan berubah, perilaku user baru), dan akurasi tergerus diam-diam. MLOps adalah disiplin menjaga siklus data → training → evaluasi → deployment tetap terukur dan dapat diulang. Episode ini merangkai semua kebiasaan baik dari episode 14–17 menjadi satu sistem operasional.
| Pilar | Masalah yang Dipecahkan | Tool Pilihan |
|---|---|---|
| Data/Model versioning | "Dataset versi mana yang melatih model ini?" | DVC (+ Git) |
| Experiment tracking | "Run minggu lalu pakai config apa, hasilnya berapa?" | MLflow / W&B |
| CI untuk evaluasi | "Regressi mAP lolos tanpa disadari" | GitHub Actions + gate |
| Monitoring & drift | "Akurasi produksi turun diam-diam" | Evidently + metrik bisnis |
Perhatikan polanya: setiap pilar adalah jawaban atas pertanyaan post-mortem klasik. Tim tanpa MLOps menjawab pertanyaan itu dengan menebak; tim dengan MLOps membuka dashboard.
Git tidak sanggup menyimpan ribuan gambar — di situlah DVC masuk: file besar disimpan di storage remote (S3/GCS), sementara Git hanya menyimpan pointer hash-nya.
pip install dvc[s3]
dvc init
# lacak folder dataset sebagai satu unit versioned
dvc add datasets/proyek-helm
git add datasets/proyek-helm.dvc .gitignore && git commit -m "dataset v1"
# remote storage + push artefak
dvc remote add -d storage s3://bucket-ku/dvcstore
dvc pushKini setiap commit = kondisi dataset yang persis reproducible. Pasangkan dengan kebiasaan episode 10 (simpan args.yaml tiap run) dan pertanyaan "model ini dilatih pakai apa?" terjawab permanen.
Episode 17 sudah menyentuh callback W&B/MLflow — kini kita formalisasikan standarnya:
import mlflow
from ultralytics import YOLO
mlflow.set_tracking_uri("http://mlflow.internal:5000")
mlflow.set_experiment("proyek-helm")
with mlflow.start_run(run_name="v3-augmalam"):
mlflow.log_params({
"base_model": "yolo26n.pt",
"epochs": 60, "imgsz": 960,
"dataset": "helm-v3", # cocokkan tag DVC!
})
model = YOLO("yolo26n.pt")
model.add_callback("on_fit_epoch_end",
lambda t: mlflow.log_metrics(
{k: float(v) for k, v in t.metrics.items()}, step=t.epoch))
model.train(data="datasets/proyek-helm/data.yaml")
mlflow.log_artifact("runs/detect/train/weights/best.pt", "model")Aturan kontrak minimalnya: setiap run mencatat (versi dataset, config lengkap, metrik final, artefak best.pt). Empat item itu membuat run mana pun bisa direproduksi atau dibandingkan dalam hitungan menit.
Tip
Tag run dengan ID versi dataset DVC — menghubungkan dua dunia versioning. Tanpa itu, dashboard tracking dan repo data menjadi dua pulau yang saling tidak percaya.
Analogi langsung dari CI software: PR yang menurunkan test coverage ditolak — PR yang menurunkan mAP juga harus ditolak. Contoh job GitHub Actions:
name: Model Eval Gate
on:
pull_request:
paths: ["datasets/**", "training/**"]
jobs:
eval:
runs-on: [self-hosted, gpu]
steps:
- uses: actions/checkout@v4
- run: dvc pull datasets/proyek-helm
- name: Train kandidat singkat
run: python training/train.py --epochs 15
- name: Evaluasi vs baseline
run: python training/eval_gate.py --min-map5095 0.60from ultralytics import YOLO
MIN_MAP = 0.60 # ambang tim, tertulis eksplisit!
metrics = YOLO("runs/detect/candidate/weights/best.pt").val(
data="datasets/proyek-helm/data.yaml", verbose=False)
map_val = float(metrics.box.map)
print(f"kandidat mAP50-95 = {map_val:.4f} | ambang = {MIN_MAP}")
assert map_val >= MIN_MAP, f"REGRESI MODEL! {map_val:.4f} < {MIN_MAP}"
print("Gate lolos — aman untuk merge")Ambangnya bukan angka magis: ambil mAP baseline production dikurangi toleransi tim (misal −1%). Yang penting ia hidup di kode, dieksekusi otomatis — bukan di kepala senior engineer.
Drift = distribusi data produksi bergeser dari distribusi training. Tiga sinyal pemantauannya:
Ketika drift terkonfirmasi, jalankan lifecycle retraining yang sudah kalian siapkan sejak episode 14 (merge data lama+baru, val multi-generasi). Otomasi minimalnya:
from ultralytics import YOLO
# 1. dataset terbaru sudah ditarik via dvc pull
model = YOLO("models/current/best.pt") # warm start dari model hidup
model.train(data="datasets/proyek-helm/data.yaml",
epochs=40, patience=10, name=f"retrain-{TANGGAL}")
# 2. gate sama seperti CI — tak ada rilis tanpa bukti
metrics = YOLO("runs/detect/retrain-{}/weights/best.pt".format(TANGGAL)) \
.val(data="datasets/proyek-helm/data.yaml")
assert metrics.box.map >= AMBANG_TIM
# 3. promosi versi: shadow → canary → full (jangan langsung replace!)Langkah 3 adalah yang sering dilompati: model baru tidak langsung menggantikan yang lama. Jalankan paralel dulu (shadow mode), bandingkan pada trafik nyata, baru promosikan bertahap.
[x] Dataset di-DVC, setiap perubahan = commit + dvc push
[x] Tiap run training tercatat (params + metrics + best.pt)
[x] Run tagged dengan versi dataset
[x] CI gate mAP aktif di PR yang menyentuh model/data
[x] Monitoring produksi: volume deteksi + distribusi conf + alert anomali
[x] Prosedur retraining berkala terjadwal + protokol promosi amanRangkuman episode ini:
Di episode 26 — episode penutup teknis — kita pandang ke sekeliling: ekosistem & tren modern 2026, dari YOLO26 dan Ultralytics Platform sampai arah industri: attention, zero-shot, edge AI, dan auto-labeling. Sampai jumpa!