Truss: Cara Package, Serve, dan Deploy Model ML dengan Rapi
Halo temen-temen, ketemu lagi sama aku, Ruby. Kali ini aku pengen ngobrolin satu tool yang menurutku sering banget kelewat sama praktisi ML, padahal manfaatnya gede banget waktu kita udah masuk fase "model udah jadi, terus gimana cara nyajiinnya ke dunia luar?". Tool itu namanya Truss, dibikin sama tim di Baseten.
Kalau temen-temen pernah ngerasain sakitnya bikin model machine learning yang jalan mulus di notebook, tapi begitu mau di-deploy jadi API malah berantakan karena beda versi library, dependency sistem yang kurang, atlas GPU yang salah konfigurasi, atau Dockerfile yang bikin pusing, nah Truss ini jawaban buat kebanyakan masalah itu. Truss ngasih kita satu cara standar buat membungkus model beserta semua kebutuhannya, lalu nge-serve-nya secara lokal maupun ke cloud tanpa harus jadi ahli DevOps dulu.
Di tutorial ini aku bakal ajak temen-temen dari nol: install, bikin struktur Truss pertama, ngerti isi file yang di-generate, nyoba serve lokal, nambahin dependency Python dan sistem, atur GPU, sampai akhirnya deploy ke Baseten. Aku juga bakal kasih contoh konkret pakai model dari HuggingFace biar kebayang. Yuk kita mulai.
Introduction
Apa itu Truss sebenarnya
Truss itu framework open-source buat packaging, serving, dan deployment model ML. Ide dasarnya sederhana tapi powerful: setiap model dibungkus dalam sebuah struktur folder yang standar, yang disebut sebuah "Truss". Di dalamnya ada dua hal utama yang perlu temen-temen isi, yaitu kode buat load dan predict model (model/model.py), plus konfigurasi lingkungan (config.yaml) yang mendeskripsikan dependency, resource, dan setting lainnya.
Yang bikin Truss enak dipakai adalah dia ngurusin bagian yang biasanya bikin frustrasi. Temen-temen nggak perlu nulis Dockerfile manual, nggak perlu setup server FastAPI/Flask sendiri, nggak perlu mikirin gimana caranya request masuk lalu diteruskan ke fungsi predict. Semua itu di-handle sama Truss lewat konvensi yang jelas.
Kenapa aku suka pola ini
Menurut aku kekuatan terbesar Truss ada di pemisahan yang bersih antara kode model dan konfigurasi environment. Waktu kita ngoding, kita cukup fokus di model.py: gimana model di-load ke memori sekali di awal, dan gimana tiap request diproses. Sementara urusan versi Python, package, dependency sistem, dan berapa banyak CPU/GPU yang dibutuhin semua ditulis deklaratif di config.yaml. Pemisahan ini bikin model kita jauh lebih gampang direproduksi di mesin lain, dan jauh lebih gampang di-review sama temen tim.
Selain itu, Truss ini portable. Truss yang sama bisa temen-temen jalanin lokal buat testing, bisa di-build jadi Docker image, dan bisa di-deploy ke Baseten buat produksi. Jadi nggak ada momen "kok di lokal jalan tapi di server nggak" yang biasanya bikin kita begadang.
Kapan sebaiknya pakai Truss
Truss paling cocok buat temen-temen yang punya model, entah itu model HuggingFace, model custom PyTorch/TensorFlow, atau bahkan pipeline gabungan, dan pengen nyajiinnya sebagai layanan inference yang bisa dipanggil lewat HTTP. Kalau kebutuhan temen-temen cuma nge-run script sekali doang, mungkin Truss overkill. Tapi begitu temen-temen butuh model yang standby, siap nerima request kapan aja, dengan konfigurasi resource yang jelas, di situlah Truss bersinar.
Instalasi
Prasyarat
Sebelum mulai, pastikan temen-temen udah punya Python versi 3.8 ke atas. Aku saranin bikin virtual environment dulu biar bersih dan nggak nabrak dependency proyek lain. Kalau temen-temen mau serve lewat Docker (dan ini yang paling mendekati kondisi produksi), pastiin Docker juga udah keinstall dan jalan di mesin.
Pertama kita bikin virtual environment dan aktifin:
python3 -m venv venv
source venv/bin/activate
Kalau temen-temen di Windows, aktivasinya beda dikit:
python -m venv venv
venv\Scripts\activate
Install Truss
Install Truss gampang banget, cukup satu perintah pip:
pip install truss
Setelah selesai, kita bisa cek versinya buat mastiin instalasi sukses:
truss version
Kalau keluar nomor versi, berarti Truss udah siap dipakai. Truss ini menyediakan command-line tool bernama truss yang bakal sering kita pakai buat inisialisasi, serve lokal, dan deploy.
Login ke Baseten (opsional untuk sekarang)
Kalau temen-temen udah punya rencana deploy ke Baseten, temen-temen bisa siapin API key dari dashboard Baseten. Tapi ini belum wajib di tahap awal, karena serve lokal nggak butuh akun sama sekali. Nanti di bagian deployment kita bahas lebih detail. Buat sekarang cukup pastiin Truss udah keinstall dan command truss bisa dipanggil.
Basic Usage
Inisialisasi Truss pertama
Sekarang kita bikin Truss pertama. Command-nya truss init diikuti nama folder yang mau kita buat. Misalnya aku mau bikin model klasifikasi teks sentimen:
truss init sentiment-classifier
Waktu dijalankan, Truss bakal generate struktur folder standar buat kita. Kadang di versi tertentu dia nanya beberapa hal interaktif, tapi intinya dia bikinin scaffold yang siap kita isi. Setelah selesai, coba masuk ke folder itu dan lihat isinya:
cd sentiment-classifier
ls -la
Ngerti struktur yang di-generate
Struktur dasar sebuah Truss kira-kira begini:
sentiment-classifier/
├── config.yaml
├── model/
│ └── model.py
├── data/
└── packages/
Aku jelasin satu-satu ya biar temen-temen paham fungsinya:
Folder model/ isinya model.py, dan ini jantungnya. Di sinilah kita nulis logika load dan predict. File config.yaml adalah tempat kita deklarasiin semua konfigurasi environment: dependency Python, dependency sistem, resource (CPU/GPU/memori), nama model, dan lain-lain. Folder data/ dipakai buat naruh file bobot model atau aset lain yang perlu ikut dibundel. Folder packages/ buat kode Python tambahan yang mau kita import di model.py, misalnya modul utilitas custom.
Isi file model.py
Isi default model/model.py biasanya berupa sebuah class Model dengan dua method penting: load() dan predict(). Konsepnya penting banget buat dimengerti:
Method load() dipanggil sekali waktu server pertama kali nyala. Di sinilah kita muat model ke memori. Karena cuma dipanggil sekali, operasi berat kayak download bobot dan inisialisasi model ditaruh di sini biar nggak diulang tiap request.
Method predict() dipanggil tiap kali ada request masuk. Fungsinya nerima input (biasanya dictionary hasil parse JSON dari request), lalu mengembalikan output yang bakal dikirim balik sebagai response.
Sekarang mari kita isi model/model.py dengan contoh nyata pakai model sentimen dari HuggingFace:
from transformers import pipeline
class Model:
def init(self, kwargs):
# kwargs berisi config, datadir, secrets, dsb dari Truss
self.model = None
def load(self):
# Dipanggil sekali saat server start. Muat model ke memori di sini.
self.model = pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
)
def predict(self, modelinput):
# Dipanggil tiap request. modelinput adalah dict hasil parse JSON.
text = modelinput.get("text", "")
result = self.model(text)
return {"predictions": result}
Perhatiin polanya: model di-load di load(), dan predict() cuma ambil teks dari input lalu jalanin inference. Bersih banget kan? Kita nggak usah mikirin server, routing, atau serialization. Truss yang ngurusin semua itu.
Konfigurasi config.yaml dasar
Sekarang kita atur config.yaml biar dependency-nya jelas. Untuk model sentimen di atas, kita butuh transformers dan torch. Isi minimalnya kira-kira begini:
modelname: sentiment-classifier
pythonversion: py311
requirements:
- torch==2.3.0
- transformers==4.44.0
resources:
cpu: "1"
memory: 2Gi
usegpu: false
Field modelname ini nama model kita. pythonversion menentukan versi Python di dalam container. requirements isinya list package Python persis kayak isi requirements.txt. resources mendeklarasiin berapa CPU, memori, dan apakah butuh GPU.
Serve model secara lokal
Nah ini bagian yang paling seru: nyoba model kita jalan tanpa deploy ke mana-mana. Truss punya command truss predict yang bisa nge-serve lokal lalu ngirim request buat kita. Dari dalam folder Truss, jalankan:
truss predict --target-directory . -d '{"text": "Aku suka banget sama tool ini"}'
Perintah di atas bakal ngebangun environment, muat model lewat load(), terus ngirim input JSON kita ke predict(), dan nampilin hasilnya di terminal. Pertama kali dijalankan mungkin agak lama karena harus download model dan setup, tapi setelah itu jauh lebih cepat.
Kalau temen-temen mau nyoba pakai Docker yang lebih mirip produksi, kita bisa jalanin server-nya dulu lalu kirim request via HTTP. Pertama build dan run image-nya:
truss image build .
truss run-image .
Setelah server nyala, biasanya dia dengerin di port tertentu (misal 8080). Kita bisa tembak pakai curl:
curl -X POST http://localhost:8080/v1/models/model:predict \
-H "Content-Type: application/json" \
-d '{"text": "Deploy model jadi gampang banget"}'
Responnya bakal berupa JSON hasil dari predict() kita tadi. Di titik ini temen-temen udah punya model yang jalan sebagai layanan HTTP, cuma dari beberapa file doang. Keren kan?
Advanced Usage
Setelah paham dasarnya, sekarang kita naik level. Di bagian ini aku bahas hal-hal yang bakal temen-temen butuhin waktu model makin serius: nambah dependency sistem, atur GPU, muat model dari file lokal, sampai preprocessing yang lebih kompleks.
Nambahin dependency Python
Nambah dependency Python gampang, cukup tambahin di list requirements di config.yaml. Misalnya kita butuh numpy dan pillow buat model image:
requirements:
- torch==2.3.0
- transformers==4.44.0
- pillow==10.4.0
- numpy==1.26.4
Aku selalu saranin pin versi (pakai ==) biar hasilnya deterministik. Bayangin kalau temen-temen nggak pin versi, terus dua minggu kemudian ada update besar di salah satu library, bisa-bisa model yang tadinya jalan malah error. Pin versi ini best practice yang bakal nyelametin temen-temen dari banyak drama.
Nambahin dependency sistem
Kadang model kita butuh library level sistem operasi, bukan cuma package Python. Contoh klasik: model computer vision yang butuh ffmpeg buat proses video, atau libgl1 buat OpenCV. Nah untuk ini Truss punya field systempackages di config.yaml:
systempackages:
- ffmpeg
- libgl1-mesa-glx
- libglib2.0-0
Package di sini bakal di-install pakai apt-get di dalam container. Jadi kalau temen-temen pernah dapet error aneh macam "libGL.so.1 not found" waktu pakai OpenCV, biasanya jawabannya nambahin libgl1-mesa-glx di sini.
Konfigurasi GPU
Buat model besar kayak LLM atau model image generation, kita jelas butuh GPU. Truss ngasih cara deklaratif buat minta GPU lewat field resources. Contohnya:
resources:
cpu: "4"
memory: 16Gi
usegpu: true
accelerator: A10G
Field usegpu di-set true, dan accelerator menentukan tipe GPU yang mau dipakai. Baseten mendukung berbagai tipe akselerator seperti T4, A10G, A100, dan lainnya. Buat model yang lebih besar, temen-temen bisa minta GPU yang lebih kuat, atau bahkan multi-GPU dengan format seperti A100:2 yang artinya dua kartu A100.
Waktu pakai GPU, pastiin juga versi torch yang temen-temen pilih kompatibel sama CUDA. Truss biasanya udah nyediain base image yang sesuai, tapi kalau temen-temen pakai versi torch spesifik, cek dulu kompatibilitasnya biar nggak boncos waktu inference.
Contoh lengkap: model image dari HuggingFace
Biar makin kebayang, aku kasih contoh model yang lebih berat, yaitu image classification pakai model Vision Transformer dari HuggingFace. Model ini nerima gambar dalam bentuk base64, decode, lalu klasifikasiin. Pertama model/model.py:
import base64
import io
from PIL import Image
from transformers import pipeline
class Model:
def init(self, kwargs):
self.model = None
def load(self):
self.model = pipeline(
"image-classification",
model="google/vit-base-patch16-224",
)
def predict(self, modelinput):
# Terima gambar sebagai string base64
imageb64 = modelinput.get("imagebase64", "")
imagebytes = base64.b64decode(imageb64)
image = Image.open(io.BytesIO(imagebytes)).convert("RGB")
results = self.model(image)
# Ambil top-3 prediksi
top = results[:3]
return {"predictions": top}
Lalu config.yaml-nya kita sesuaikan buat model image dengan GPU:
modelname: vit-image-classifier
python
version: py311
requirements:
- torch==2.3.0
- transformers==4.44.0
- pillow==10.4.0
systempackages:
- libgl1-mesa-glx
resources:
cpu: "2"
memory: 8Gi
use
gpu: true
accelerator: T4
Dengan setup ini, temen-temen udah punya model image classification yang siap jalan di GPU. Buat testing lokal, temen-temen bisa encode gambar ke base64 dulu lewat Python kecil, lalu kirim ke truss predict.
Muat model dari file lokal (bundled weights)
Kadang kita nggak mau download model dari internet tiap kali deploy, entah karena modelnya custom hasil training sendiri, atau biar startup lebih cepat. Nah kita bisa naruh file bobot di folder data/ dan muatnya dari sana. Truss bakal nge-bundle isi folder data/ ke dalam image, dan menyediakan path-nya lewat argumen datadir:
import os
import joblib
class Model:
def init(self, kwargs):
self.datadir = kwargs["datadir"]
self.model = None
def load(self):
modelpath = os.path.join(self.datadir, "model.joblib")
self.model = joblib.load(modelpath)
def predict(self, modelinput):
features = modelinput.get("features", [])
prediction = self.model.predict([features])
return {"prediction": prediction.tolist()}
Pola ini cocok banget buat model scikit-learn atau XGBoost yang udah kita training dan simpan sebagai file. Tinggal taruh model.joblib di folder data/, dan Truss otomatis nyertain dalam bundle.
Pakai secrets dengan aman
Kalau model temen-temen butuh akses ke API eksternal atau butuh token HuggingFace buat model private, jangan pernah hardcode token di kode. Truss punya mekanisme secrets. Kita deklarasiin nama secret di config.yaml:
secrets:
hfaccesstoken: null
Nilai null di sini artinya secret ini bakal diisi belakangan (di lokal lewat file secrets, di Baseten lewat dashboard). Lalu di model.py kita akses lewat kwargs:
class Model:
def init(self, kwargs):
self.secrets = kwargs["secrets"]
self.model = None
def load(self):
token = self.secrets["hfaccesstoken"]
# gunakan token buat muat model private
self.model = pipeline(
"text-generation",
model="my-org/private-model",
token=token,
)
def predict(self, modelinput):
return {"output": self.model(modelinput.get("prompt", ""))}
Dengan cara ini token sensitif temen-temen nggak pernah kesimpan di kode atau di git. Ini penting banget buat keamanan.
Deploy ke Baseten
Sekarang bagian puncaknya: deploy ke Baseten biar model kita bisa diakses dari mana aja lewat endpoint produksi. Pertama, temen-temen perlu login pakai API key dari dashboard Baseten:
truss login
Command ini bakal minta API key temen-temen. Setelah login sukses, deploy cukup satu perintah dari dalam folder Truss:
truss push
Truss bakal ngemas seluruh model, build image di infrastruktur Baseten, lalu deploy sebagai model yang di-serve. Prosesnya bakal nampilin progress dan di akhir ngasih tahu endpoint model kita. Setelah live, kita bisa panggil lewat HTTP dengan menyertakan API key Baseten di header:
curl -X POST https://model-xxxxx.api.baseten.co/development/predict \
-H "Authorization: Api-Key YOURBASETENAPI_KEY" \
-d '{"text": "Model sudah live di produksi"}'
Baseten juga punya konsep environment development dan production. Waktu development, tiap truss push langsung update model biar iterasi cepat. Kalau udah mantap, temen-temen bisa promote ke production environment yang lebih stabil dan nggak berubah tiap push.
Publish ke production
Kalau mau langsung deploy ke production environment, temen-temen bisa tambahin flag:
truss push --publish
Dengan flag --publish, Truss bakal bikin deployment yang di-tag sebagai production, bukan sekadar development yang berubah-ubah. Ini yang temen-temen pakai kalau model udah siap dipakai user beneran.
Best Practices
Setelah cukup lama main sama Truss, ada beberapa kebiasaan yang menurut aku bakal bikin hidup temen-temen jauh lebih tenang. Aku rangkum di sini.
Selalu pin versi dependency
Aku udah singgung tadi, tapi ini penting banget sampai aku ulangi. Selalu pin versi package di requirements pakai ==. Model yang reproducible itu emas. Kalau versi nggak dikunci, temen-temen bakal ketemu bug yang muncul random cuma karena ada library yang update di belakang layar. Kunci semua versi, termasuk torch, transformers, dan library lain yang kritikal.
Uji lokal sebelum push
Jangan langsung truss push tanpa nyoba lokal dulu. Selalu jalanin truss predict atau serve via Docker di lokal buat mastiin load() dan predict() jalan seperti harusnya. Deploy ke cloud itu makan waktu dan resource, jadi nangkep error di lokal jauh lebih murah dan cepat daripada nunggu build cloud gagal baru sadar ada typo.
Taruh operasi berat di load(), bukan predict()
Ini kesalahan yang sering aku lihat: orang naruh loading model atau setup berat di dalam predict(). Akibatnya tiap request jadi lambat banget karena model di-load ulang terus. Ingat, load() cuma dipanggil sekali, predict() dipanggil tiap request. Semua yang berat dan cuma perlu sekali, taruh di load().
Sesuaikan resource dengan kebutuhan nyata
Jangan asal minta GPU A100 kalau model kecil temen-temen sebenarnya cukup jalan di CPU. Resource itu ada biayanya, apalagi GPU. Mulai dari resource kecil, ukur performa dan latensi, baru naikkan kalau memang perlu. Sebaliknya, jangan pelit sampai model kehabisan memori dan crash. Ukur kebutuhan nyata lewat testing.
Rapikan preprocessing dan validasi input
Karena predict() nerima input mentah dari user, selalu validasi dan kasih default yang aman. Kalau field text nggak ada, jangan sampai server crash. Kasih penanganan yang rapi biar API kita tahan banting terhadap input yang aneh. Ini bikin layanan temen-temen jauh lebih profesional dan stabil.
Manfaatkan folder packages untuk kode reusable
Kalau model.py temen-temen mulai gendut, pindahin logika yang bisa dipisah ke folder packages/. Misalnya fungsi preprocessing, postprocessing, atau utilitas lain. Ini bikin kode lebih rapi dan gampang di-test secara terpisah.
Kelola secret dengan benar
Sekali lagi, jangan pernah hardcode token atau kredensial di kode. Pakai mekanisme secrets Truss. Selain lebih aman, ini juga bikin model temen-temen gampang dipindah antar environment tanpa harus ngedit kode.
Conclusion
Oke temen-temen, kita udah keliling cukup jauh soal Truss dari Baseten. Kita mulai dari install lewat pip install truss, bikin struktur pertama dengan truss init, ngerti peran model/model.py dengan method load() dan predict()-nya, plus config.yaml buat ngatur dependency dan resource. Lalu kita nyoba serve lokal lewat truss predict dan Docker, nambahin dependency Python maupun sistem, atur GPU buat model berat, sampai akhirnya deploy ke Baseten pakai truss push.
Yang aku suka dari Truss adalah dia ngasih struktur yang jelas dan konsisten buat sesuatu yang biasanya berantakan. Pemisahan antara kode model dan konfigurasi environment bikin model kita reproducible dan gampang di-maintain. Dan karena Truss yang sama jalan dari lokal sampai produksi, kita nggak lagi dihantui momen "kok di lokal jalan doang".
Saranku, coba langsung praktik. Ambil satu model favorit temen-temen dari HuggingFace, bungkus jadi Truss, serve lokal, lalu kalau berani deploy ke Baseten. Sekali temen-temen ngerasain betapa mulusnya alurnya, aku yakin bakal ketagihan. Selamat nyoba, dan sampai ketemu di tutorial berikutnya. Semangat terus belajarnya ya temen-temen.