Membiasakan diri mencatat setiap eksperimen: logging metric dan artifact dengan MLflow, perbandingan dengan Weights & Biases, pengendalian seed dan hashing untuk reproducibility, serta eksperimen berbasis konfigurasi sehingga setiap hasil bisa diulang kapan pun.

Setelah di episode 10 kita melakukan tuning dengan cross-validation dan Optuna, mungkin kalian berpikir pekerjaan sudah selesai. Kenyataannya justru di sinilah masalah dimulai: berapa banyak eksperimen yang sudah kalian jalankan? Mana yang terbaik? Bisa kalian ulangi hasilnya tiga bulan lagi?
Di dunia nyata, ML bukan sekali jalan — ia iterasi puluhan kali dengan parameter, fitur, dan data berbeda. Tanpa experiment tracking, kalian akan tersesat: file model_final_v2_akhir_BENAR.ipynb menumpuk, dan tidak ada yang tahu konfigurasi mana yang menghasilkan skor terbaik. Episode ini mengajarkan cara keluar dari kekacauan itu.
Bayangkan dua minggu lalu kalian mendapat ROC-AUC 0.91. Hari ini skornya turun jadi 0.88, padahal "kodenya sama". Apa yang berubah? Tanpa pencatatan, jawabannya hilang — bisa jadi library ter-update, random state berubah, atau data bergeser.
Track record yang baik mencatat tiga hal untuk setiap eksperimen:
| Yang dicatat | Contoh |
|---|---|
| Konfigurasi (input) | Parameter, fitur, versi data, seed |
| Hasil (output) | Metric, artifact model, plot |
| Konteks (environment) | Versi library, commit kode, tanggal |
Dengan catatan ini, perbandingan antar eksperimen jadi objektif, dan hasil yang bagus bisa diulang (atau "diproduksi") kapan saja.
MLflow adalah tool tracking paling populer untuk memulai. Konsep intinya:
Install dan mulai dengan mudah:
pip install mlflow
mlflow ui --port 5000Lalu log eksperimen kalian langsung dari script:
import mlflow
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
mlflow.set_experiment("churn-v1")
with mlflow.start_run():
params = {"n_estimators": 300, "max_depth": 8}
model = RandomForestClassifier(**params, random_state=42)
score = cross_val_score(model, X_train, y_train,
cv=5, scoring="roc_auc").mean()
mlflow.log_params(params)
mlflow.log_metric("cv_roc_auc", score)
model.fit(X_train, y_train)
mlflow.sklearn.log_model(model, "model")Setelah beberapa run, buka http://localhost:5000 — kalian melihat tabel perbandingan semua run, bisa menyortir berdasarkan metric, dan mengunduh model terbaik. Tanpa tabel ini, perbandingan eksperimen hanya mengandalkan ingatan.
Tip
Gunakan mlflow.autolog() jika ingin hemat waktu — ia mencatat parameter, metric, dan model secara otomatis untuk framework populer (sklearn, XGBoost, LightGBM). Untuk eksperimen serius, kombinasikan autolog dengan logging manual untuk konteks tambahan seperti komentar atau versi data.
Weights & Biases (W&B) adalah alternatif cloud yang unggul di visualisasi dan kolaborasi tim. Kelebihannya dibanding MLflow lokal:
import wandb
wandb.init(project="churn", config={"n_estimators": 300})
model = RandomForestClassifier(
n_estimators=wandb.config.n_estimators,
random_state=42,
)Perbedaan utamanya: MLflow self-hosted (data di infrastruktur kalian), W&B SaaS (data di cloud pihak ketiga). Pilihan bergantung pada kebutuhan privasi data dan anggaran.
| Fitur | MLflow | Weights & Biases |
|---|---|---|
| Hosting | Self-hosted / lokal | SaaS (ada opsi cloud) |
| Setup | Ringan, langsung jalan | Butuh akun & API key |
| Kolaborasi tim | Perlu setup server | Bawaan |
| Integrasi tuning | Bagus dengan Optuna | Sweep bawaan |
Tracking hanya membantu jika eksperimen bisa diulang. Tiga sumber ketidak-reproducible-an paling umum:
Set seed di semua lapisan acak — bukan hanya di satu model:
import random
import numpy as np
import xgboost as xgb
def set_seed(seed=42):
random.seed(seed)
np.random.seed(seed)
set_seed(42)
model = xgb.XGBClassifier(random_state=42)Jika ada satu lapisan acak yang tidak diset (misalnya SMOTE), hasil bisa berbeda di tiap run.
Library yang di-update bisa mengubah hasil training. Catat versinya di setiap run:
import sklearn, xgboost, pandas
mlflow.log_params({
"sklearn_version": sklearn.__version__,
"xgboost_version": xgboost.__version__,
"pandas_version": pandas.__version__,
})Jika data bisa berubah (seseorang menambah baris), beri hash dataset sebagai sidik jari. Dengan begini kalian tahu persis data apa yang dipakai run itu.
import hashlib
def data_hash(df):
raw = df.to_csv(index=False).encode()
return hashlib.sha256(raw).hexdigest()[:12]
mlflow.log_param("data_hash", data_hash(X_train))Sidik jari yang sama → data sama. Berbeda → data berubah, dan membandingkan skor jadi tidak valid.
Trick agar eksperimen rapi: pisahkan konfigurasi dari kode. Simpan parameter dalam file YAML, bukan diketik keras di script:
experiment:
name: churn-v1
data_hash_check: true
model:
name: xgboost
n_estimators: 300
max_depth: 8
learning_rate: 0.05
random_state: 42
training:
cv_folds: 5
scoring: roc_aucimport yaml
with open("config/experiment.yaml") as f:
config = yaml.safe_load(f)
model_cfg = config["model"]
model = xgb.XGBClassifier(**model_cfg)
mlflow.set_experiment(config["experiment"]["name"])
mlflow.log_params(model_cfg)Kelebihannya: percobaan baru cukup dengan mengubah satu file YAML — dan setiap run otomatis mencatat konfigurasi yang dipakainya. Ini fondasi untuk otomasi pipeline di episode 17.
Membiasakan alur ini sejak sekarang akan terbayar besar saat proyek ML kalian berkembang dari notebook tunggal menjadi sistem produksi.
Pada episode 11 ini, kalian telah membiasakan diri dengan eksperimen yang tercatat dan reproduksibel.
Inti yang harus dibawa pulang:
Di episode 12 selanjutnya kita akan membahas time series forecasting — trend, seasonality, dan stationarity, rolling features, backtesting, model ARIMA/SARIMA dan Prophet, plus pendekatan ML modern dengan lag features dan LightGBM untuk peramalan penjualan. Sampai jumpa di episode 12!