Model yang dilatih hanya berguna jika bisa dipakai kembali tanpa mengulang training. Melatih ulang model setiap kali aplikasi start itu boros; lebih buruk lagi, hasil training ulang bisa berbeda dari model yang sudah tervalidasi. Solusinya adalah serialization: menyimpan objek model terlatih ke file, lalu memuatnya kembali di lingkungan produksi. Pada chapter ini kita melakukan round-trip nyata dengan pickle, memahami risiko kompatibilitas versi, dan menerapkan pola metadata sidecar agar model tersimpan tidak menjadi kotak hitam.

Round-Trip Model dengan pickle #

Modul pickle dari standard library bisa menyerialisasi hampir semua objek Python, termasuk model scikit-learn. Kita latih model k-NN pada dataset iris, simpan, muat kembali, lalu buktikan keduanya memprediksi hal yang sama:

python
import pickle

import numpy as np
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier

iris = load_iris()
X, y = iris.data, iris.target

model = KNeighborsClassifier(n_neighbors=5).fit(X, y)

with open("model_iris.pkl", "wb") as berkas:
    pickle.dump(model, berkas)

with open("model_iris.pkl", "rb") as berkas:
    model_dimuat = pickle.load(berkas)

prediksi_asli = model.predict(X[:5])
prediksi_dimuat = model_dimuat.predict(X[:5])
print("Prediksi model asli :", prediksi_asli)
print("Prediksi model muat :", prediksi_dimuat)
print("Identik:", np.array_equal(prediksi_asli, prediksi_dimuat))

Output yang Dihasilkan:

text
Prediksi model asli : [0 0 0 0 0]
Prediksi model muat : [0 0 0 0 0]
Identik: True

Mari kita bedah kode di atas:

  1. Baris 13 (model = KNeighborsClassifier(...).fit(X, y)): model dilatih sekali di sesi ini; pada praktik nyata, training bisa memakan menit hingga jam.
  2. Baris 15-16 (pickle.dump(model, berkas)): seluruh isi objek model, termasuk data latih yang disimpan k-NN, ditulis ke file model_iris.pkl dalam format biner. Mode "wb" wajib karena isinya biner, bukan teks.
  3. Baris 18-19 (pickle.load(berkas)): objek dibangun ulang dari file, siap dipakai tanpa memanggil fit() lagi. Prediksinya identik dengan model asli, dibuktikan np.array_equal() yang mengembalikan True.

Untuk model berukuran besar yang menampung array numpy banyak (misalnya random forest atau model dengan data latih besar), paket joblib yang terpasang bersama scikit-learn lebih efisien: joblib.dump(model, "model.joblib") dan joblib.load("model.joblib") memakai API yang sama tetapi menangani array besar lebih cepat dan hemat memori.

Bahaya Kompatibilitas Versi #

File pickle bukan format model portabel. File pickle adalah rekaman struktur objek Python secara harfiah; untuk dibuka, pemuat harus punya class yang sama persis di lokasi memori yang setara, dan versi scikit-learn yang berbeda bisa mengubah struktur internal model. Ketika model dibuat dengan scikit-learn 1.5 lalu dimuat di lingkungan scikit-learn 0.24, scikit-learn akan menampilkan InconsistentVersionWarning, dan pada kasus struktur yang jauh berbeda, pemuatan gagal dengan error AttributeError atau ModuleNotFoundError karena atribut atau module lama sudah tidak ada.

Konsekuensinya tegas: file .pkl hanya bisa dijamin tampil semestinya pada kombinasi Python dan scikit-learn yang sama dengan saat training. Pendekatan yang lebih portabel untuk pertukaran antar framework adalah format terbuka seperti ONNX, yang menyimpan komputasi model sebagai graf tanpa terikat struktur class Python; sayangnya tidak semua model scikit-learn didukung konversinya. Untuk kebutuhan section ini, aturan mainnya sederhana: simpan versi, jaga versi.

Pola Metadata Sidecar #

Karena file pickle tidak menyimpan konteks, kita buat sendiri konteksnya: file JSON kecil di samping file model yang mencatat versi library, daftar fitur, daftar kelas, dan tanggal training:

python
import json
import sklearn

metadata = {
    "file_model": "model_iris.pkl",
    "sklearn_version": sklearn.__version__,
    "fitur": list(iris.feature_names),
    "kelas": list(iris.target_names),
    "tanggal_training": "2025-06-15",
}
with open("model_iris.json", "w") as berkas:
    json.dump(metadata, berkas, indent=2)
print(json.dumps(metadata, indent=2))

Output yang Dihasilkan:

text
{
  "file_model": "model_iris.pkl",
  "sklearn_version": "1.5.2",
  "fitur": [
    "sepal length (cm)",
    "sepal width (cm)",
    "petal length (cm)",
    "petal width (cm)"
  ],
  "kelas": [
    "setosa",
    "versicolor",
    "virginica"
  ],
  "tanggal_training": "2025-06-15"
}

File JSON ini adalah sidecar: mudah dibaca manusia, mudah dibaca program, dan tidak terikat versi Python. Nilai "sklearn_version": "1.5.2" berasal dari atribut sklearn.__version__ pada mesin pelatih, jadi angka ini selalu jujur, bukan hasil ketikan manual. Daftar fitur menjadi kontrak input: skrip prediksi bisa memeriksa urutan dan nama kolom sebelum memanggil model.predict().

Skrip Load-and-Predict #

Gabungan keduanya menghasilkan skrip prediksi yang defensif dan bisa dijalankan utuh setiap kali dibutuhkan:

python
import json
import pickle

import numpy as np
import sklearn

with open("model_iris.json") as berkas:
    metadata = json.load(berkas)

if metadata["sklearn_version"] != sklearn.__version__:
    raise RuntimeError("Versi scikit-learn berbeda; latih ulang model")

with open("model_iris.pkl", "rb") as berkas:
    model = pickle.load(berkas)

contoh_baru = np.array([[5.1, 3.5, 1.4, 0.2]])
prediksi = model.predict(contoh_baru)[0]
print(f"Prediksi untuk contoh baru: {metadata['kelas'][prediksi]}")

Output yang Dihasilkan:

text
Prediksi untuk contoh baru: setosa

Skrip ini memuat metadata lebih dulu, memeriksa versi scikit-learn sebelum menyentuh file pickle, lalu menerjemahkan angka prediksi (0) menjadi nama kelas (setosa) memakai metadata. Jika lingkungan produksi kelak memakai versi berbeda, RuntimeError gagal cepat alih-alih menghasilkan prediksi senyap yang salah.

Keamanan: Jangan Unpickle Sembarang File #

Memuat file pickle berarti mengeksekusi kode arbitrer yang tertanam di dalamnya. Serangan umumnya: file .pkl jahat yang dipalsukan sebagai “model pretrained” di forum atau repositori publik. Batasi pemuatan pickle hanya pada file yang kita buat sendiri atau dari sumber yang benar-benar dipercaya; untuk file dari pihak ketiga, verifikasi checksum atau muat di sandbox terisolasi.

Dengan model yang bisa disimpan, dimuat, dan diverifikasi, fondasi terakhir sudah siap: membawa model tersebut ke hadapan pengguna lewat endpoint HTTP, yang kita kerjakan pada chapter Pengenalan Deployment Model.