Belajar ML Engineer - Training & Validation Best Practices
Episode 5 of 28

Belajar ML Engineer - Training & Validation Best Practices

Menyusun proses training yang jujur dan terukur: train/val/test split yang benar, cross-validation yang menghormati waktu, hyperparameter tuning dengan search strategy, serta pipeline training terstruktur yang bisa dijalankan ulang dan dibandingkan antar eksperimen

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 4 kita membangun feature pipeline yang konsisten, sekarang tiba saatnya bagian yang paling sering disalahpahami pemula: cara training dan validasi yang benar. Kebanyakan orang langsung memanggil model.fit() dan melihat akurasi — padahal tanpa disiplin validasi, angka akurasi itu sering kali bohong.

Masalah terbesar di industri bukan model yang kurang pintar, melainkan model yang terlihat bagus di eksperimen tapi melorot di produksi. Sering kali penyebabnya bukan modelnya, tapi cara kita memisahkan data, cara kita tuning hyperparameter, dan cara kita mengevaluasi. Episode ini membangun fondasi yang akan menyelamatkan kalian dari mimpi buruk itu.

Train/Val/Test Split yang Benar

Tiga bagian data dengan tiga peran yang tidak boleh dicampur:

SplitPeranJangan dipakai untuk
TrainingMelatih parameter modelEvaluasi final, tuning
ValidationMemilih model & tuning hyperparameterEvaluasi final
TestEvaluasi final satu kali sajaTuning atau pemilihan model
Split sederhana
from sklearn.model_selection import train_test_split
 
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
X_train, X_val, y_train, y_val = train_test_split(
    X_train, y_train, test_size=0.2, random_state=42, stratify=y_train
)

stratify=y menjaga proporsi kelas agar sama di semua split — penting untuk data tidak seimbang. random_state membuat split reproducible.

Split untuk Data Bertempo Waktu

Jika data memiliki dimensi waktu (transaksi, log, clickstream), random split adalah kesalahan serius: model akan "mencontek" data masa depan. Gunakan temporal split — training hanya pada periode lalu, validasi/test pada periode berikutnya.

Temporal split
train = df[df["date"] < "2026-05-01"]
val   = df[(df["date"] >= "2026-05-01") & (df["date"] < "2026-06-01")]
test  = df[df["date"] >= "2026-06-01"]

Aturan emasnya: test set harus meniru kondisi produksi. Jika di produksi kalian memprediksi "hari ini" berdasarkan data "kemarin", maka test set harus disusun persis seperti itu.

Cross-Validation

K-fold cross-validation memakai seluruh data secara bergantian sebagai validation, sehingga estimasi performa lebih stabil dari satu split:

K-fold CV
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import GradientBoostingClassifier
 
scores = cross_val_score(GradientBoostingClassifier(), X_train, y_train, cv=5)
print(f"mean: {scores.mean():.4f} ± {scores.std():.4f}")

Dua varian penting:

  • StratifiedKFold: menjaga proporsi kelas di tiap fold — wajib untuk class imbalance.
  • TimeSeriesSplit: fold diurutkan waktu, training selalu sebelum validation — wajib untuk data temporal.

Untuk data temporal, jangan pernah memakai KFold biasa; gunakan TimeSeriesSplit.

Hyperparameter Tuning

Setelah baseline terlatih, kalian mengeksplorasi ruang hyperparameter. Dua pendekatan utama:

  • GridSearchCV: mencoba semua kombinasi — sederhana tapi boros untuk ruang besar.
  • RandomizedSearchCV: sampling acak kombinasi — jauh lebih efisien untuk ruang besar, sering lebih unggul.
Randomized search
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform, randint
 
param_dist = {
    "n_estimators": randint(100, 400),
    "max_depth": randint(3, 12),
    "learning_rate": uniform(0.01, 0.3),
}
search = RandomizedSearchCV(
    GradientBoostingClassifier(),
    param_distributions=param_dist,
    n_iter=50, cv=5, scoring="roc_auc", random_state=42,
)
search.fit(X_train, y_train)
print(search.best_params_)

Ada aturan penting yang sering dilanggar: tuning hanya menyentuh validation set. Jika kalian memilih hyperparameter berdasarkan performa di test set, test set sudah ter-bocor dan angka finalnya tidak bisa dipercaya lagi.

Pipeline Training Terstruktur

Training yang baik adalah proses yang bisa dijalankan ulang dan dibandingkan. Struktur yang umum:

Pipeline training end-to-end
from src.data import load_and_clean
from src.features import build_feature_pipeline
from src.config import TrainConfig
 
 
def run_training(config: TrainConfig):
    df = load_and_clean(config.raw_path)
    X_train, X_val, X_test, y_train, y_val, y_test = config.split(df)
    preprocessor = build_feature_pipeline(X_train)
    model = config.make_model()
    model.fit(preprocessor.transform(X_train), y_train)
    val_score = model.score(preprocessor.transform(X_val), y_val)
    return model, preprocessor, {"val_score": val_score}
 
 
if __name__ == "__main__":
    model, preprocessor, metrics = run_training(TrainConfig())
    print(metrics)

Praktik yang membuat pipeline ini production-grade:

  1. Setiap eksperimen tercatat — metric, hyperparameter, dan dataset hash masuk ke experiment tracker (episode 6).
  2. Seed dikontrol (random_state) agar hasil reproducible.
  3. Baseline selalu ada — bandingkan tiap model dengan baseline naif (misal memprediksi kelas mayoritas).

Tip

Aturan yang banyak dipelajari dengan pahit: evaluasi test set hanya satu kali. Jika kalian memakai test set berulang-ulang untuk mengambil keputusan, secara tidak sadar kalian sedang tuning terhadap test set — dan angka final kalian tidak mencerminkan performa di data baru.

Common Pitfalls

PitfallDampakPencegahan
Random split pada data temporalModel mencontek masa depanTimeSeriesSplit / temporal split
Tanpa stratify pada data imbalanceSplit tidak mewakili populasistratify=y
Tuning sampai menyentuh test setTest set ter-bocor, angka tidak jujurTest set hanya untuk evaluasi final
GridSearch pada ruang besarBoros waktu & computeRandomizedSearch
Tanpa baselineTidak tahu apakah model bergunaSelalu sediakan baseline naif

Penutup

Pada episode 5 ini, kalian telah membangun fondasi training yang sehat:

  • Split jujur: train/val/test dengan peran terpisah; temporal split untuk data berwaktu.
  • Cross-validation yang tepat jenisnya: StratifiedKFold atau TimeSeriesSplit.
  • Tuning dengan randomized search yang menyentuh validation, bukan test.
  • Pipeline training terstruktur, reproducible, dan selalu dibandingkan dengan baseline.

Di episode 6 selanjutnya kita akan membahas Experiment Tracking & Registry — mencatat setiap eksperimen dengan MLflow/W&B, membandingkan run secara sistematis, dan mengelola model registry untuk menjawab pertanyaan "model mana yang sedang live dan kenapa". Sampai jumpa di episode 6!