Model yang berakhir di notebook belum menyelesaikan masalah apa pun. Nilai machine learning baru terwujud ketika prediksi bisa diakses pengguna atau sistem lain, entah lewat API yang menerima request satu per satu atau lewat proses batch yang tiap malam memproses jutaan baris. Pada chapter penutup section ini kita membungkus model ke endpoint HTTP dengan FastAPI, memahami perbedaan batch dan real-time, serta merapikan fondasi produksi: reproducibility, registry, dan monitoring.
Dari Function ke HTTP Endpoint #
Prediksi pada dasarnya adalah function: input fitur, output hasil. Deployment real-time berarti membuka function tersebut lewat HTTP agar klien mana pun bisa memanggilnya. FastAPI membuat pekerjaan ini ringkas; kita pakai pipeline scaler plus k-NN dari chapter sebelumnya, dengan dua fitur kelopak sebagai input:
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
app = FastAPI()
iris = load_iris()
X = iris.data[:, 2:] # hanya fitur kelopak: panjang dan lebar
y = iris.target
pipeline = Pipeline([
("scaler", StandardScaler()),
("model", KNeighborsClassifier(n_neighbors=5)),
])
pipeline.fit(X, y)
class PermintaanPrediksi(BaseModel):
panjang_kelopak: float
lebar_kelopak: float
@app.post("/prediksi")
def prediksi(permintaan: PermintaanPrediksi):
fitur = [[permintaan.panjang_kelopak, permintaan.lebar_kelopak]]
indeks = pipeline.predict(fitur)[0]
return {"spesies": iris.target_names[indeks]}
client = TestClient(app)
respons = client.post("/prediksi", json={"panjang_kelopak": 5.1, "lebar_kelopak": 1.8})
print(respons.status_code)
print(respons.json())Output yang Dihasilkan:
200
{'spesies': 'virginica'}Mari kita bedah bagian-bagian penting kode di atas:
- Baris 15-19 (
class PermintaanPrediksi(BaseModel)): Pydantic memvalidasi request body. Request tanpapanjang_kelopak, atau dengan tipe string, otomatis ditolak dengan status 422 sebelum menyentuh model. - Baris 22 (
@app.post("/prediksi")): decorator FastAPI mendaftarkan functionprediksi()sebagai handler HTTP methodPOSTdi path/prediksi. - Baris 23-27 (
def prediksi(...)): handler menerima objek tervalidasi, membentuk input dua dimensi (pipeline mengharapkan bentuk(n_sampel, n_fitur)), lalu mengembalikan dictionary yang FastAPI serialisasi menjadi JSON. - Baris 30-33 (
TestClient(app)): classTestClientmemanggil endpoint tanpa menjalankan server sungguhan, cara yang benar untuk menguji aplikasi FastAPI seperti dibahas pada chapter Menulis Test dengan pytest.
Di produksi, aplikasi ini dijalankan dengan server ASGI: uvicorn app:app --reload memulai server development, dan hasil {'spesies': 'virginica'} tadi persis yang akan diterima klien yang mengirim request serupa.
Batch vs Real-Time #
Tidak semua prediksi harus live. Pilihan mode deployment bergantung pada seberapa segar hasil dibutuhkan:
| Aspek | Batch | Real-time API |
|---|---|---|
| Waktu hasil | Terjadwal (tiap malam, tiap jam) | Milidetik setelah request |
| Contoh kasus | Skor risiko kredit bulanan, rekomendasi mingguan | Deteksi fraud saat transaksi, autocomplete |
| Beban puncak | Rata, bisa dijadwalkan | Mengikuti trafik pengguna, perlu autoscaling |
| Biaya operasional | Rendah, satu cron job | Lebih tinggi, server harus selalu hidup |
| Kompleksitas | Skrip plus penjadwal | Validasi input, logging, monitoring |
Skema hibrida juga umum: skor berat dihitung batch tiap malam, lalu API hanya membaca hasilnya, sehingga request real-time tetap cepat tanpa memanggil model.
Latency, Throughput, dan Batching #
Dua angka menggambarkan performa layanan prediksi. Latency adalah waktu satu request dari masuk hingga jawaban keluar, biasanya dalam milidetik. Throughput adalah jumlah request per detik yang mampu dilayani. Keduanya saling tarik-menarik dengan satu senjata sederhana: batching. Memproses 1 request memakan hampir selama memproses 32 request sekaligus untuk model seperti k-NN, sehingga menumpuk request kecil menjadi batch besar menaikkan throughput total dengan mengorbankan latency individu:
| Strategi | Latency per request | Throughput | Cocok untuk |
|---|---|---|---|
| Satu-satu | Terendah | Rendah | Kebutuhan interaktif |
| Batching kecil (mis. 8-32) | Sedikit naik | Naik signifikan | Trafik tinggi |
| Batching besar (ratusan) | Tinggi | Tertinggi | Pekerjaan latar belakang |
Menentukan titik impasnya adalah pekerjaan pengukuran, bukan tebakan: ukur latency dan throughput pada trafik serupa produksi, lalu putuskan.
Reproducibility Sebelum Deploy #
Model yang dimuat di server harus identik dengan model yang tervalidasi. Dua kebiasaan menjaminnya:
- Virtual environment per proyek, dibahas pada chapter Membuat Virtual Environment, mengisolasi versi Python dan library server dari mesin pelatih.
- Pin semua dependensi, dibahas pada chapter Dependency Pinning:
requirements.txtdengan versi persis (scikit-learn==1.5.2) menjamin kombinasi Python dan scikit-learn yang sama dengan saat model dibuat, prasyarat file pickle dimuat tanpa kejutan sesuai chapter Model Serialization.
Tanpa keduanya, deployment baru bisa saja membawa versi library berbeda, dan prediksi produksi diam-diam bergeser dari hasil evaluasi tanpa satu pun error yang tercetak.
Setelah Deploy: Registry dan Monitoring #
Pekerjaan tidak selesai saat model online. Praktik industri menambahkan dua lapisan:
- Model registry: satu tempat terpusat (misalnya MLflow Model Registry atau layanan sejenis) yang mencatat setiap versi model, metadata, status (staging, produksi, diarsipkan), dan siapa yang melatihnya. Registry menjawab pertanyaan “model versi berapa yang sedang melayani trafik sekarang” dalam hitungan detik.
- Monitoring drift: performa dan sebaran input diawasi terus-menerus. Data drift terjadi ketika pola input berubah (pendapatan rata-rata pelanggan naik setahun kemudian); concept drift ketika hubungan input-output bergeser (selera berubah, penipuan menemukan celah baru). Deteksi drift umumnya membandingkan distribusi fitur dan tingkat error terhadap baseline saat model dirilis, dan drift yang terdeteksi adalah sinyal untuk melatih ulang model dengan data terbaru.
Dengan ini rangkaian section Machine Learning tertutup: dari memahami pola belajar dari data, menyiapkan dataset, merancang fitur, melatih model supervised dan unsupervised, mengevaluasi dengan jujur, merangkai pipeline, menyimpan model, hingga menyajikannya sebagai layanan. Langkah berikutnya di luar section ini adalah memperdalam satu domain nyata dan mengulang siklusnya pada data milik kita sendiri.