Chapter sebelumnya menutup dengan tabel keputusan: PSI di atas 0,25 berarti penyelidikan dan evaluasi ulang model. Sekarang kita bahas tahap berikutnya — bagaimana model diperbarui ketika bukti memang menuntutnya. Retraining terdengar seperti sekadar memanggil fit() lagi, tetapi di lingkungan produksi retraining adalah keputusan sistem: kapan dipicu, data apa yang boleh masuk, bagaimana model baru diadu dengan model lama sebelum menyentuh trafik, dan bagaimana kembali ke model sebelumnya dalam hitungan menit bila hasilnya menurun. Chapter ini merakit siklus lengkap tersebut — pemicu, pola champion/challenger, strategi warm start, disiplin rollback, dan syarat kesiapan data — lalu mendemonstrasikannya pada satu skenario drift yang sama dengan chapter sebelumnya.

Tiga Pemicu Retraining #

Setiap siklus pembaruan dimulai dari satu pertanyaan: apa yang memicunya? Tiga jawaban yang umum dipakai industri:

PemicuSinyal yang dipakaiKelebihanKekurangan
Terjadwal (scheduled)Kalender: mingguan/bulananTerencana, mudah diaudit dan diuji cobaBisa sia-sia (belum perlu) atau terlambat (sudah parah)
Kinerja (performance-triggered)Metrik berlabel turun di bawah ambangBereaksi langsung ke masalah nyataMenunggu label — yang datang terlambat
Drift (drift-triggered)PSI/KS data atau prediksi melewati ambangBekerja tanpa label, reaksi paling awalDrift tidak selalu berarti kinerja turun

Ketiganya bukan pilihan tunggal. Praktik yang matang menjadwalkan retraining secara rutin sebagai dasar (kolom pertama), lalu memakai ambang drift dan kinerja sebagai tombol darurat yang mempercepat jadwal. Bagian “kekurangan” pada tabel juga bukan formalitas: pemicu kinerja menunggu label yang baru matang berbulan-bulan, sedangkan pemicu drift sesekali berbunyi hanya karena campuran data berubah sementara hubungan fitur–label sebenarnya tetap — itulah mengapa keputusan akhir selalu dikembalikan ke evaluasi berlabel.

Pola Champion dan Challenger #

Struktur dasar pembaruan yang aman memakai dua peran. Champion adalah model yang sedang melayani produksi; model tersebut tidak disentuh selama evaluasi berjalan. Challenger adalah kandidat pengganti yang dilatih dari data baru (atau gabungan data lama dan baru), lalu diadu dengan champion pada himpunan uji yang sama dan terbaru — periode data paling recent yang representatif terhadap kondisi saat ini. Promosi hanya terjadi bila challenger mengungguli champion melewati margin yang ditetapkan di muka, bukan sekadar lebih tinggi seperseribu.

Margin tersebut disengaja. Selisih kecil bisa berasal dari fluktuasi sampel, dan setiap promosi membawa biaya: artefak baru harus diuji, dibawa ke strategi rilis bertahap, dan diawasi lebih ketat di minggu pertamanya. Tanpa margin, tim akan sibuk mempromosikan model yang secara praktis tidak berbeda.

Cold Start dan Warm Start #

Dari sisi komputasi ada dua cara memulai pelatihan model baru. Cold start melatih dari bobot nol seperti biasa — fit() penuh atas gabungan data. Warm start melanjutkan dari bobot model lama sehingga pelatihan hanya menyesuaikan sedikit:

python
from sklearn.linear_model import SGDClassifier

model_hangat = SGDClassifier(warm_start=True, random_state=42)
model_hangat.fit(X_periode_a, y_periode_a)   # bobot periode A terbentuk
model_hangat.fit(X_periode_b, y_periode_b)   # melanjutkan, bukan dari nol

Paramater warm_start=True tersedia pada estimator berbasis iterasi seperti SGDClassifier dan HistGradientBoostingClassifier. Kombinasi cold start + warm start juga menjadi dasar pembagian lain yang sering disebut di industri: melatih ulang seluruh model (retraining) versus melanjutkan pelatihan model yang sama (fine-tuning terhadap data baru). Trade-off-nya lurus: warm start murah dan cepat, tetapi membawa jejak bobot lama yang bisa memperlambat adaptasi penuh terhadap konsep baru; cold start membersihkan jejak tersebut dengan biaya komputasi penuh. Untuk model seukuran Course ini perbedaannya nyaris tidak terasa — keputusan baru terasa pada model besar dan data raksasa.

Praktikum: Drift, Penurunan Skor, dan Pemulihan #

Skrip berikut memainkan satu siklus utuh dalam dua periode data. Periode A memuat konsep lama: kelas 1 berpusat di kanan. Periode B memuat konsep baru: kelas 1 berpindah ke atas. Champion dilatih hanya pada A — persis seperti model produksi yang dibekukan saat pelatihan — lalu dihadapkan pada B untuk melihat penurunannya. Challenger kemudian dilatih pada gabungan A+B dan kedua model diadu pada himpunan uji yang sama.

python
# Retraining setelah drift: champion dilatih pada periode A, dievaluasi pada
# periode B yang konsepnya bergeser (skor turun), lalu challenger dilatih pada
# gabungan A+B dan dievaluasi ulang (skor pulih). Ditutup tabel keputusan.

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

rng = np.random.default_rng(42)
N_PER_KELAS = 400


def buat_blok(pusat, jumlah):
    """Satu klaster berlabel dengan sebaran normal baku di dua dimensi."""
    return rng.normal(pusat, 1.0, size=(jumlah, 2))


# 1) Periode A: kelas 1 berpusat di kanan -> batas keputusan vertikal x1.
X_a = np.vstack([buat_blok((0.0, 0.0), N_PER_KELAS),
                 buat_blok((2.5, 0.0), N_PER_KELAS)])
y_a = np.array([0] * N_PER_KELAS + [1] * N_PER_KELAS)

# 2) Periode B: kelas 1 berpindah ke atas -> batas optimal menjadi horizontal.
X_b = np.vstack([buat_blok((0.0, 0.0), N_PER_KELAS),
                 buat_blok((0.0, 2.5), N_PER_KELAS)])
y_b = np.array([0] * N_PER_KELAS + [1] * N_PER_KELAS)

X_a_latih, X_a_uji, y_a_latih, y_a_uji = train_test_split(
    X_a, y_a, test_size=0.3, random_state=42, stratify=y_a)
X_b_latih, X_b_uji, y_b_latih, y_b_uji = train_test_split(
    X_b, y_b, test_size=0.3, random_state=42, stratify=y_b)

# 3) Champion: dilatih hanya pada periode A, lalu dihadapkan pada periode B.
champion = LogisticRegression(random_state=42)
champion.fit(X_a_latih, y_a_latih)
skor_a_champion = accuracy_score(y_a_uji, champion.predict(X_a_uji))
skor_b_champion = accuracy_score(y_b_uji, champion.predict(X_b_uji))

print("champion (data latih: periode A saja)")
print(f"  akurasi pada A-uji: {skor_a_champion:.3f}")
print(f"  akurasi pada B-uji: {skor_b_champion:.3f} "
      f"(turun {skor_a_champion - skor_b_champion:.3f})")

# 4) Challenger: retraining atas gabungan data periode A dan periode B.
X_gabungan = np.vstack([X_a_latih, X_b_latih])
y_gabungan = np.concatenate([y_a_latih, y_b_latih])
challenger = LogisticRegression(random_state=42)
challenger.fit(X_gabungan, y_gabungan)
skor_a_challenger = accuracy_score(y_a_uji, challenger.predict(X_a_uji))
skor_b_challenger = accuracy_score(y_b_uji, challenger.predict(X_b_uji))

# 5) Tabel keputusan champion vs challenger.
AMBANG_PROMOSI = 0.05
delta_b = skor_b_challenger - skor_b_champion
keputusan = ("promosikan challenger" if delta_b >= AMBANG_PROMOSI
             else "pertahankan champion")

print()
print(f"{'model':<12} {'data latih':<12} {'A-uji':>6} {'B-uji':>6} {'delta B':>8}")
print("-" * 52)
print(f"{'champion':<12} {'A saja':<12} {skor_a_champion:>6.3f} "
      f"{skor_b_champion:>6.3f} {'-':>8}")
print(f"{'challenger':<12} {'A + B':<12} {skor_a_challenger:>6.3f} "
      f"{skor_b_challenger:>6.3f} {delta_b:>+8.3f}")
print()
print(f"ambang promosi: delta B >= {AMBANG_PROMOSI:.2f}")
print(f"keputusan      : {keputusan}")

# 6) Disiplin rollback: champion tidak dibuang, koefisiennya tetap bisa diaudit.
print()
print("disiplin rollback: champion tetap tersedia sebagai artefak")
print(f"  koefisien champion   : x1={champion.coef_[0, 0]:+.3f} "
      f"x2={champion.coef_[0, 1]:+.3f}")
print(f"  koefisien challenger : x1={challenger.coef_[0, 0]:+.3f} "
      f"x2={challenger.coef_[0, 1]:+.3f}")

Output yang Dihasilkan:

text
champion (data latih: periode A saja)
  akurasi pada A-uji: 0.908
  akurasi pada B-uji: 0.504 (turun 0.404)

model        data latih    A-uji  B-uji  delta B
----------------------------------------------------
champion     A saja        0.908  0.504        -
challenger   A + B         0.817  0.800   +0.296

ambang promosi: delta B >= 0.05
keputusan      : promosikan challenger

disiplin rollback: champion tetap tersedia sebagai artefak
  koefisien champion   : x1=+2.258 x2=-0.093
  koefisien challenger : x1=+1.301 x2=+1.258

Mari kita telaah bagian-bagian yang memikul beban utama:

  1. Baris 14–16 (def buat_blok): pembangkit klaster dua dimensi; rng berseed 42 memastikan kedua periode dapat direproduksi persis.
  2. Baris 19–27 (dua periode): satu-satunya perbedaan A dan B adalah pusat klaster kelas 1 — dari (2.5, 0) ke (0, 2.5). Ini concept drift dalam bentuknya yang paling murni: fitur sama, label sama, tetapi hubungan keduanya berputar 90 derajat.
  3. Baris 29–32 (pemisahan data): train_test_split dengan random_state=42 dan stratify menghasilkan himpunan latih dan uji terpisah untuk tiap periode — challenger dilatih hanya pada *_latih, dan promosi diputuskan pada *_uji yang tidak pernah dilihat pelatihan.
  4. Baris 34–43 (diagnosis champion): champion menunjukkan pola klasik model yang tertinggal drift — 0,908 pada periode asal, tetapi 0,504 pada periode baru, nyaris setara tebakan acak.
  5. Baris 45–51 (challenger): np.vstack menggabungkan data latih kedua periode sebelum fit() — model belajar konsep lama dan konsep baru bersamaan.
  6. Baris 53–68 (tabel keputusan): AMBANG_PROMOSI = 0.05 ditetapkan sebelum melihat hasil — kebiasaan yang menjaga keputusan tetap objektif. Delta +0,296 pada B-uji melewati ambang, sehingga keputusan tercetak: promosikan challenger.
  7. Baris 70–76 (audit koefisien): perbandingan koefisien merangkum perubahan konsep: champion hanya mengandalkan x1 (+2,258; x2 nyaris nol), sedangkan challenger mengandalkan x1 dan x2 hampir seimbang (+1,301 dan +1,258) — model baru memang belajar aturan yang berbeda, bukan sekadar angka yang digeser.

Dua detail pada keluaran layak dibaca pelan. Pertama, akurasi challenger pada A-uji turun menjadi 0,817 dari 0,908 milik champion — pembaruan model hampir selalu merupakan pertukaran, bukan kemenangan mutlak; bila periode lama tetap penting, pembobotan sampel (sample_weight) dapat menyeimbangkan keduanya. Kedua, angka 0,504 champion pada B-uji menegaskan mengapa drift pada chapter sebelumnya tidak boleh diabaikan: model tidak sekadar “sedikit meleset”, melainkan kehilangan seluruh daya pisahnya.

Disiplin Rollback #

Promosi bukan akhir siklus — sistem harus siap mundur. Praktik baku menempatkan challenger melalui strategi rilis bertahap dari Chapter Strategi Deployment Model (shadow atau canary), sementara artefak champion tetap tersimpan lengkap dengan metadatanya. Bila metrik pasca-rilis menurun, pemulihan berarti mengarahkan trafik kembali ke artefak lama dalam hitungan menit, bukan melatih ulang dalam hitungan jam. Baris 70–76 pada skrip menunjukkan prinsip auditnya: koefisien champion tetap dapat diperiksa setelah challenger diangkat, karena objek — dan di produksi, artefak — model lama tidak pernah dibuang begitu promosi terjadi.

Kesiapan Data: Label yang Datang Terlambat #

Satu prasyarat senyap pada seluruh siklus di atas: label periode B dianggap sudah tersedia saat challenger dilatih. Di dunia nyata, asumsi tersebut sering tidak berlaku — nasabah yang gagal bayar baru diketahui berbulan-bulan kemudian, dan label yang belum matang bisa berubah nilainya seiring waktu. Melatih ulang dengan label setengah jadi berarti menanam galat sistematis ke model baru, yang kemudian dipromosikan justru karena evaluasinya tampak baik. Karena itu siklus pembaruan yang sehat menambahkan satu gerbang: kesiapan label — retraining hanya berjalan setelah cakupan label periode terbaru melewati ambang yang ditetapkan, atau setelah umur data minimal tercapai. Umpan baluk yang terlambat adalah sifat masalah, bukan kegagalan tim; desain sikluslah yang harus menoleransinya.

Dengan ini siklus operasional menutup penuh: strategi penyajian, API serving, batch, monitoring drift, hingga pembaruan model yang terkontrol. Namun seluruh rantai tersebut berdiri di satu asumsi yang belum kita uji: bahwa data yang mengalir ke sistem adalah data yang jujur. Model yang terus belajar dari data produksi — persis siklus yang baru kita bangun — membuka kategori risiko baru: masukan yang dirancang untuk menyesatkan, data yang dicemari, dan model yang dibocorkan lewat pertanyaan-prediksi. Kategori risiko tersebut adalah pembuka Section Keamanan, Etika, dan Keandalan, dimulai dari Chapter Ancaman Keamanan Model Machine Learning.

Referensi Resmi #