Model deep learning mengharapkan masa depan yang menyerupai masa lalinya — secara teknis, data uji harus berasal dari distribusi yang sama dengan data latih. Syarat itu nyaris tidak pernah terpenuhi lama setelah deployment: kamera berganti sudut, pengguna baru datang dari segmen lain, definisi target berubah mengikuti kebijakan baru. Perbedaan antara distribusi latih dan distribusi lapangan disebut distribution shift, dan menjelaskan sebagian besar kegagalan model produksi yang tidak disebabkan penyerang. Chapter ini memetakan tiga jenis shift, mendemonstrasikan keruntuhannya dengan angka nyata, lalu menguji dua mitigasi — augmentasi aturan dan batas kapasitas model.
Tiga Jenis Shift dan Gejalanya #
| Jenis shift | Yang berubah | Contoh konkret | Gejala | Mitigasi |
|---|---|---|---|---|
| Covariate | distribusi fitur P(x) | basis pengguna meluas ke wilayah fitur yang tak tersampel saat latih | prediksi salah sistematis di wilayah baru | augmentasi luas, domain randomization, monitoring drift |
| Label | proporsi kelas P(y) | rasio transaksi menyalahi aturan naik dari 2% ke 20% | presisi runtuh, confusion matrix miring | kalibrasi ulang threshold, sampling ulang data |
| Concept | relasi P(y|x) | makna “akun aktif” berubah setelah kebijakan baru | akurasi turun merata di semua segmen | pelabelan ulang, retraining berkala |
Ketiganya membagi satu akar: keputusan model hanya sah pada wilayah data yang pernah diamatinya, prinsip yang dibahas sebagai generalisasi pada Generalisasi Model . Terdapat pula natural adversarial examples — input alami yang jujur namun kebetulan jatuh di wilayah rentan model — sehingga pengujian robustness perlu dipandang bagian dari evaluasi, bukan opsional.
Demo: Negasi yang Tak Pernah Diajarkan #
Skenario fiktif kita klasik di NLP: sentimen ulasan. Fitur x1 adalah skor polaritas kata, fitur x2 penanda negasi (+1 tanpa negasi, -1 dengan negasi). Kebenaran sejatinya berbentuk XOR: “bagus” positif, “tidak bagus” negatif. Data latih berasal dari periode ketika ulasan belum memakai negasi — x2 selalu +1 — sehingga model hanya perlu aturan sederhana. Deployment bertemu Dist B: ulasan dengan negasi, wilayah fitur yang tak pernah dilihat. Berkas distribution_shift.py mengukur keruntuhannya, menyembuhkan dengan augmentasi aturan negasi, lalu membuktikan bahwa model linear tidak dapat disembuhkan dengan data apa pun:
"""Distribution shift: akurasi runtuh saat data uji berasal dari
wilayah fitur yang tak pernah dilihat saat training, lalu pulih
lewat augmentasi aturan (negasi) — dengan syarat kapasitas model
cukup untuk merepresentasikan interaksinya.
Skenario fiktif: klasifikasi sentimen ulasan.
x1 = skor polaritas kata (negatif..positif), x2 = penanda negasi
(+1 tanpa negasi, -1 dengan negasi). Kalimat "tidak bagus" (x1 > 0,
x2 = -1) bersentimen negatif: kebenaran berbentuk XOR.
"""
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.neural_network import MLPClassifier
rng = np.random.default_rng(5)
def buat_data(n, negasi):
x1 = rng.uniform(-3, 3, n)
x2 = np.full(n, -1.0 if negasi else 1.0)
y = ((x1 > 0) == (x2 > 0)).astype(int)
return np.column_stack([x1, x2]), y
# Dist A: tanpa negasi (data latih + uji i.i.d.)
X_latih, y_latih = buat_data(600, negasi=False)
X_uji_A, y_uji_A = buat_data(300, negasi=False)
# Dist B: ulasan dengan negasi (wilayah fitur yang tak pernah dilihat)
X_uji_B, y_uji_B = buat_data(300, negasi=True)
# Dist C: derau pengukuran pada skor polaritas (gangguan alami)
X_uji_C = X_uji_A.copy()
X_uji_C[:, 0] += rng.normal(0, 0.8, len(y_uji_A))
def uji(m, Xd, yd, nama):
print(f"akurasi {nama:34s}: {m.score(Xd, yd):.3f}")
# ---------- 1. Model dilatih hanya pada Dist A ----------
mlp = MLPClassifier(hidden_layer_sizes=(16, 16), alpha=1e-4,
max_iter=3000, random_state=5)
mlp.fit(X_latih, y_latih)
print("===== MLP DILATIH HANYA PADA DIST A (tanpa negasi) =====")
uji(mlp, X_uji_A, y_uji_A, "Dist A (i.i.d.)")
uji(mlp, X_uji_B, y_uji_B, "Dist B (dengan negasi)")
uji(mlp, X_uji_C, y_uji_A, "Dist C (derau polaritas)")
# contoh konkret: "tidak bagus" vs "bagus"
contoh = np.array([[2.0, 1.0], [2.0, -1.0]])
print("prediksi untuk 'bagus' [x1=2, x2=+1] :",
mlp.predict(contoh[:1])[0], "(benar: 1 = positif)")
print("prediksi untuk 'tidak bagus' [x1=2, x2=-1]:",
mlp.predict(contoh[1:])[0], "(benar: 0 = negatif)")
# ---------- 2. Mitigasi: augmentasi aturan negasi ----------
X_aug = np.vstack([X_latih, X_latih.copy()])
X_aug[len(X_latih):, 1] = -1.0
y_aug = np.concatenate([y_latih, 1 - y_latih])
mlp_aug = MLPClassifier(hidden_layer_sizes=(16, 16), alpha=1e-4,
max_iter=3000, random_state=5)
mlp_aug.fit(X_aug, y_aug)
print()
print("===== MLP DILATIH DENGAN AUGMENTASI NEGASI =====")
print(f"data latih membesar dari {len(y_latih)} menjadi {len(y_aug)} baris")
uji(mlp_aug, X_uji_A, y_uji_A, "Dist A (i.i.d.)")
uji(mlp_aug, X_uji_B, y_uji_B, "Dist B (dengan negasi)")
uji(mlp_aug, X_uji_C, y_uji_A, "Dist C (derau polaritas)")
print("prediksi 'tidak bagus' [x1=2, x2=-1] :",
mlp_aug.predict(contoh[1:])[0], "(benar: 0 = negatif)")
# ---------- 3. Augmentasi tanpa kapasitas: model linear ----------
logreg_aug = LogisticRegression().fit(X_aug, y_aug)
print()
print("===== REGRESI LOGISTIK + AUGMENTASI YANG SAMA =====")
uji(logreg_aug, X_uji_A, y_uji_A, "Dist A (i.i.d.)")
uji(logreg_aug, X_uji_B, y_uji_B, "Dist B (dengan negasi)")
print("model linear tak bisa merepresentasikan XOR,")
print("augmentasi data saja tidak menolong")Output yang Dihasilkan:
===== MLP DILATIH HANYA PADA DIST A (tanpa negasi) =====
akurasi Dist A (i.i.d.) : 1.000
akurasi Dist B (dengan negasi) : 0.000
akurasi Dist C (derau polaritas) : 0.903
prediksi untuk 'bagus' [x1=2, x2=+1] : 1 (benar: 1 = positif)
prediksi untuk 'tidak bagus' [x1=2, x2=-1]: 1 (benar: 0 = negatif)
===== MLP DILATIH DENGAN AUGMENTASI NEGASI =====
data latih membesar dari 600 menjadi 1200 baris
akurasi Dist A (i.i.d.) : 1.000
akurasi Dist B (dengan negasi) : 1.000
akurasi Dist C (derau polaritas) : 0.903
prediksi 'tidak bagus' [x1=2, x2=-1] : 0 (benar: 0 = negatif)
===== REGRESI LOGISTIK + AUGMENTASI YANG SAMA =====
akurasi Dist A (i.i.d.) : 0.517
akurasi Dist B (dengan negasi) : 0.497
model linear tak bisa merepresentasikan XOR,
augmentasi data saja tidak menolongContoh di atas diuji nyata dengan scikit-learn 1.5.2 pada CPU dan selesai dalam waktu di bawah lima detik dengan seed tetap. Mari kita telaah kode di atas baris per baris:
- Baris 18-22 (fungsi
buat_data):x1diambil acak,x2seragam per skenario, dan label dihitung sebagai kesamaan tanda — sentimen positif jika tanda polaritas dan tanda negasi searah; inilah XOR yang menjadi kebenaran sejati tugas. - Baris 25-31 (tiga himpunan uji): Dist A i.i.d. tanpa negasi, Dist B dengan negasi (wilayah fitur baru), dan Dist C berupa derau tambahan pada skor polaritas — mewakili gangguan alami sensor.
- Baris 38-40 (model dist A): MLP kecil 16 unit; akurasi 1,000 pada Dist A menunjukkan model sehat menurut evaluasi standar — persis kondisi yang lolos review internal sebelum runtuh di lapangan.
- Baris 47-51 (contoh konkret): “bagus” diprediksi 1 (benar), tetapi “tidak bagus” juga diprediksi 1 — kata tidak tidak pernah muncul pada data latih sehingga modelnya buta terhadapnya.
- Baris 54-56 (augmentasi aturan): salinan data latih dibuat dengan
x2dibalik dan label dibalik mengikutinya — augmentasi yang benar karena meniru invariansi tugas, bukan sekadar menambah derau acak. - Baris 70-75 (uji kapasitas): logistic regression dilatih pada data yang sudah diaugmentasi tetap mentok di sekitar 50% — XOR tidak dapat direpresentasikan model linear; data tidak menolong model yang strukturnya salah.
Membaca Angka dan Mitigasi Sistemik #
Tiga angka pada output meringkas seluruh chapter. Akurasi Dist B bukan 50% melainkan 0,000: model tidak sekadar bingung, melainkan salah secara sistematis dan sempurna — seluruh prediksi terbalik karena bobot fitur negasi aktif dengan tanda yang keliru. Kegagalan sistematis semacam ini lebih berbahaya daripada tebakan acak karena kelihatannya meyakinkan. Setelah augmentasi, akurasi Dist B pulih ke 1,000 tanpa menurunkan Dist A — bukti bahwa augmentasi yang meniru invariansi tugas nyaris gratis, tema yang diperluas pada Data Augmentation Strategies . Sementara itu Dist C tetap 0,903 sebelum dan sesudah mitigasi: derau pengukuran menuntut teknik lain (fitur yang lebih tahan, kompresi input), bukan augmentasi aturan.
Pada sistem produksi, shift tidak berhenti sekali: ia merambat pelan setiap minggu. Deteksi dini menjadi tanggung jawab monitoring — statistik input dan keluaran dilacak, penyimpangan menyalakan peringatan sebelum akurasi runtuh, dibahas rinci pada Monitoring Model Produksi . Untuk domain robotik dan simulasi, teknik domain randomization mengacak parameter lingkungan saat training agar model menyerap variasi yang mungkin muncul di dunia nyata.
Mengetahui model gagal adalah satu masalah; mengetahui mengapa ia memutuskan demikian adalah masalah berikutnya — dan menjadi syarat bagi perbaikan. Chapter selanjutnya membuka kotak hitam itu dengan teknik interpretabilitas.