Mengamankan reproduktibilitas eksperimen ML: dependency pinning dengan lockfile, container Docker untuk training dengan base image yang konsisten, pinning image berdasarkan digest, dan best practice environment agar hasil training identik di semua mesin.

Setelah di episode 3 kode ML kalian sudah terstruktur dan ter-package, sekarang muncul masalah berikutnya: environment. Model yang akurat di laptop kalian bisa mengeluarkan hasil berbeda di mesin CI atau server produksi — bukan karena kodenya, tapi karena dependency dan system library yang berbeda.
Mengapa reproduktibilitas adalah fondasi MLOps? Karena tanpa environment yang identik, kalian tidak bisa: (1) mereproduksi hasil eksperimen lama saat direview, (2) membuktikan bahwa peningkatan akurasi berasal dari kode, bukan kebetulan versi library, dan (3) mempercayai hasil A/B test di produksi. Episode ini membangun lapisan pertama dari triple reproducibility: code, environment, data (data menyusul di episode 6).
Mulai dari hal paling dasar: jangan menulis dependency dengan versi "kabur". numpy>=1.0 akan menarik versi terbaru yang mungkin mengubah hasil numerik.
[project]
name = "churn-predictor"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"numpy==2.1.3",
"pandas==2.2.3",
"scikit-learn==1.6.1",
"mlflow==2.20.2",
]Versi tepat (==) menjamin dependency yang sama di semua mesin. Namun pinning manual tidak cukup — library lain yang dipasang transitif juga harus terkunci. Solusinya lockfile: daftar lengkap semua paket beserta versi dan hash-nya.
uv pip compile pyproject.toml -o requirements.lock
uv pip install -r requirements.lockuv pip compile menghitung seluruh dependency transitif dan mengunci versinya. Yang menarik di sini: numpy dan scikit-learn pernah mengubah hasil floating point antar versi minor — satu angka saja bergeser di urutan desimal kedelapan, hasil evaluasi model bisa berbeda di digit yang sama. Lockfile menghilangkan drama ini.
Lockfile mengunci versi Python package, tetapi belum mengunci sistem operasi, system library (BLAS, OpenMP), dan versi Python. Untuk itu kita butuh container. Docker image adalah snapshot lengkap environment — inilah kenapa MLOps Engineer hampir selalu bekerja dengan Docker.
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
COPY requirements.lock .
RUN pip install --no-cache-dir -r requirements.lock
COPY src ./src
COPY pyproject.toml .
RUN pip install --no-cache-dir -e .
ENTRYPOINT ["python", "-m", "churn.train"]Catatan penting pada Dockerfile di atas:
python:3.12-slim — versi Python dan sistem dasar identik di mana pun.PYTHONDONTWRITEBYTECODE — mencegah file .pyc yang tidak diinginkan.ENTRYPOINT — container langsung menjalankan training, bukan shell interaktif.Build dan jalankan:
docker build -t churn-train:0.1.0 .
docker run --rm -v "$PWD/artifacts:/app/artifacts" churn-train:0.1.0Dengan -v (bind mount), artifact model yang dihasilkan container muncul di direktori artifacts mesin lokal — pola mount untuk output yang akan kita pakai terus di series ini.
Tip
Untuk training yang butuh GPU, jangan mulai dari python:3.12-slim. Gunakan base image GPU resmi seperti nvidia/cuda:12.x-cudnn-runtime-ubuntu22.04 atau image ML siap pakai (misal pytorch/pytorch, nvcr.io NGC) lalu pasang dependency di atasnya. Diskusi GPU lanjutan ada di episode 17 dan 22.
python:3.12-slim adalah tag yang bisa berpindah — besok image yang sama bisa berisi patch baru. Untuk reproducibility ketat, pin image berdasarkan digest (hash konten image):
docker inspect --format='{{index .RepoDigests 0}}' python:3.12-slimFROM python:3.12-slim@sha256:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0Sekarang image dasar tidak akan pernah berubah. Efek sampingnya, kalian tidak dapat patch keamanan otomatis — jadi kombinasi yang sehat: pin digest untuk environment deterministik, dan perbarui dengan sengaja saat ada update keamanan (dibahas lebih lanjut di episode 20 tentang supply chain).
Urutan lapisan yang harus kalian kuasai, dari yang paling longgar ke paling ketat:
| Lapisan | Tool | Fungsi |
|---|---|---|
| Python package | requirements.txt | Daftar dependency dasar |
| Version exact | pyproject.toml + lockfile | Kunci versi, termasuk transitif |
| Sistem & Python | Docker | Snapshot OS + library + Python |
| Image immutable | Docker digest | Base image tidak berubah |
| Data | DVC (episode 6) | Kunci versi dataset |
Jika kalian memakai semua lapisan, hasil training kalian bisa direproduksi oleh siapa pun, di mesin mana pun — bahkan dua tahun kemudian. Inilah yang disebut reproducibility di dunia MLOps.
pip install di dalam container tanpa lockfile → build "berhasil hari ini", error besok.latest tag → dependency berubah diam-diam; pin dengan == atau digest.COPY . .) → cache pecah, image membengkak; copy spesifik.python:3.12 vs python:3.13 bisa mengubah hasil library numerik.Pada episode 4 ini, kalian telah mengunci environment training.
Inti yang harus dibawa pulang:
Di episode 5 selanjutnya kita akan membahas experiment tracking — MLflow dan Weights & Biases untuk mencatat parameter, metrik, dan artifact setiap percobaan, sehingga perbandingan model tidak lagi bergantung pada ingatan. Sampai jumpa di episode 5!