Arsitektur fine-tuning lokal menentukan apakah pipeline pelatihan Anda akan terasa sederhana dan stabil, atau justru cepat menjadi sulit dioperasikan. Untuk tim kecil yang ingin melakukan fine-tuning model kecil/menengah secara lokal atau on-prem, tiga pola yang paling masuk akal biasanya adalah monolit tunggal, worker terpisah berbasis queue, dan hybrid.
Jawaban singkatnya: pilih monolit jika volume job rendah, tim kecil, dan Anda ingin bergerak cepat dengan kompleksitas minimal. Pilih worker terpisah jika job mulai banyak, durasinya panjang, GPU perlu dipakai efisien, dan Anda butuh retry serta isolasi dependensi. Pilih hybrid jika Anda ingin mulai kecil seperti monolit, tetapi tidak ingin migrasi mahal saat beban bertambah.
Konteksnya mirip dengan workflow lokal yang sering dipakai saat bereksperimen menggunakan trainer untuk model terbuka seperti Gemma: ada tahap unggah dataset, validasi, preprocessing, memulai training, memantau log, menyimpan checkpoint, lalu mengevaluasi hasil. Yang berubah bukan konsep training-nya, melainkan bagaimana komponen-komponen itu diorkestrasi.
Mengapa pemilihan arsitektur fine-tuning lokal penting?
Fine-tuning lokal berbeda dari request API biasa. Bebannya cenderung panjang, berat, dan stateful. Satu job bisa menghabiskan waktu menit hingga jam, memakai GPU intensif, menghasilkan file besar, serta bergantung pada lingkungan Python, CUDA, driver, dan library ML yang sensitif.
Karena itu, arsitektur yang cocok bukan hanya soal "bisa jalan", tetapi juga:
- Utilisasi CPU/GPU: apakah GPU sering idle menunggu preprocessing, download model, atau upload artefak?
- Isolasi dependensi: apakah runtime aplikasi web bercampur dengan stack training yang berat?
- Throughput: berapa banyak job yang bisa diantrikan dan diproses tanpa saling mengganggu?
- Retry: bagaimana jika proses mati di tengah epoch atau host restart?
- Observabilitas: apakah status job, log, error, dan artefak mudah dilihat?
- Biaya infrastruktur: apakah harus menyiapkan service tambahan, queue, object storage, atau host terpisah?
- Biaya operasional: siapa yang akan merawat worker, membersihkan checkpoint lama, dan menangani job macet?
- Bottleneck storage: apakah disk lokal, NFS, atau object storage menjadi titik lemah saat dataset dan checkpoint membesar?
- Maintainability tim kecil: apakah arsitektur terlalu rumit untuk tim 2-4 engineer?
Opsi 1: Monolit tunggal
Pada pola ini, satu aplikasi menangani semuanya: UI atau API, validasi dataset, penjadwalan job, eksekusi training, penyimpanan metadata, dan streaming log. Secara praktik, aplikasi web memanggil proses training lokal, misalnya lewat subprocess, background task, atau internal scheduler.
Diagram alur sederhana
User/API
-> App Monolith
-> Validasi dataset
-> Simpan config job
-> Jalankan trainer lokal
-> Tulis log/status
-> Simpan checkpoint/artefakKapan monolit layak dipilih?
- Anda baru mulai dengan 1 mesin, 1 GPU, dan volume job rendah.
- Training dijalankan oleh tim internal, bukan banyak tenant eksternal.
- Fokus utama adalah time to first working system.
- Tim kecil belum ingin mengelola queue broker, worker fleet, atau scheduler terpisah.
- Kegagalan sesekali masih bisa ditangani manual.
Kelebihan monolit
- Paling cepat dibangun: lebih sedikit komponen, lebih sedikit titik gagal.
- Debug awal lebih mudah: log aplikasi dan log training dekat satu sama lain.
- Biaya infra rendah: cukup satu host atau satu stack.
- Deploy sederhana: cocok untuk proof-of-concept dan tahap validasi produk.
Kekurangan monolit
- CPU/GPU sering tidak optimal: proses non-training bisa berbagi resource dengan aplikasi web.
- Isolasi dependensi buruk: library training dapat bentrok dengan dependency backend utama.
- Throughput terbatas: saat beberapa job masuk, Anda cepat bertemu bottleneck.
- Retry dan recovery sering ad-hoc: jika proses mati, status job mudah tidak sinkron.
- Observabilitas bercampur: log web, log queue internal, dan log trainer saling menimpa konteks.
Contoh implementasi praktis
Monolit masih bisa dibuat cukup rapi jika Anda memisahkan job state dari eksekusi proses. Minimal, simpan status job di database dan jangan mengandalkan memory aplikasi.
jobs/
id: string
status: queued | running | succeeded | failed | canceled
dataset_path: string
base_model: string
output_dir: string
created_at: timestamp
started_at: timestamp
finished_at: timestamp
error_message: text
pid: integer nullableAlur minimal yang sehat:
- User membuat job lewat API.
- Aplikasi menyimpan metadata job dengan status
queued. - Runner internal mengambil job yang belum jalan.
- Runner mengeksekusi trainer sebagai proses terpisah.
- Stdout/stderr ditulis ke file log dan sebagian dipush ke UI.
- Saat proses selesai, status diubah ke
succeededataufailed.
Anti-pattern monolit yang sering terjadi
- Menjalankan training langsung di request HTTP. Request akan timeout, sulit dibatalkan, dan menyandera worker web.
- Menyimpan status job hanya di memory. Begitu aplikasi restart, job menjadi "hilang".
- Menggabungkan environment web dan training dalam satu image besar tanpa kontrol. Upgrade satu library bisa merusak keduanya.
- Menyimpan checkpoint di disk sementara tanpa lifecycle. Disk cepat penuh dan job berikutnya gagal.
Opsi 2: Worker terpisah berbasis queue
Pada pola ini, aplikasi utama hanya menerima request, memvalidasi input, dan mengirim job ke queue. Proses training dijalankan oleh worker terpisah yang bisa hidup di host berbeda, idealnya dekat dengan GPU.
Diagram alur sederhana
User/API
-> App/API Server
-> Simpan metadata job
-> Push ke Queue
-> Training Worker
-> Ambil dataset/model
-> Jalankan trainer
-> Simpan log/checkpoint
-> Update status jobKapan worker terpisah layak dipilih?
- Anda memiliki beberapa job per hari atau antrean yang mulai menumpuk.
- GPU perlu digunakan lebih disiplin dan tidak boleh terganggu oleh traffic aplikasi.
- Lingkungan training berbeda jauh dari runtime backend.
- Anda perlu retry, timeout, prioritas job, atau concurrency control.
- Mulai ada kebutuhan multi-tenant atau pemisahan workload eksperimen vs produksi.
Kelebihan worker berbasis queue
- Isolasi dependensi jauh lebih baik: app server dan worker bisa memakai image/container berbeda.
- Utilisasi GPU lebih terkontrol: scheduler worker dapat membatasi satu GPU satu job, atau policy lain sesuai kebutuhan.
- Retry lebih rapi: kegagalan karena OOM, file corrupt, atau host restart lebih mudah ditangani.
- Throughput lebih baik: app server tetap responsif walau ada banyak job panjang.
- Observabilitas lebih jelas: metrik antrean, durasi job, rasio gagal, dan utilisasi resource bisa dipisah.
Kekurangan worker berbasis queue
- Infra lebih kompleks: perlu queue broker, mekanisme ack, dead-letter, dan worker lifecycle.
- Biaya operasional naik: monitoring worker, restart policy, cleanup artefak, dan sinkronisasi status perlu disiplin.
- Debug lintas komponen lebih sulit: masalah bisa terjadi di app, queue, worker, storage, atau jaringan.
- Storage menjadi titik krusial: jika dataset/checkpoint lewat network storage yang lambat, GPU bisa menunggu I/O.
Struktur job yang aman untuk worker
Jangan kirim payload besar langsung ke queue. Kirim referensi ke dataset, config, dan lokasi output. Queue sebaiknya membawa pesan kecil dan idempoten.
{
"job_id": "ft_20260708_001",
"dataset_ref": "datasets/customer-support-v3.jsonl",
"base_model": "gemma-small-it",
"train_config_ref": "configs/ft_20260708_001.yaml",
"output_ref": "artifacts/ft_20260708_001/"
}Praktik implementasi yang penting
- Gunakan status job eksplisit:
queued,claimed,running,succeeded,failed,canceled. - Pastikan job idempoten: worker yang memproses ulang job tidak boleh merusak state.
- Simpan heartbeat: jika worker mati, job bisa dideteksi sebagai stale dan dijadwalkan ulang dengan aman.
- Pisahkan log event dan status akhir: log streaming tidak boleh menjadi satu-satunya sumber kebenaran.
- Batasi retry otomatis: retry buta pada error konfigurasi hanya menghabiskan GPU.
Contoh state machine sederhana
queued
-> claimed
-> running
-> succeeded
-> failed
-> canceled
Jika worker mati saat claimed/running:
-> stale detection
-> requeue atau mark failed sesuai kebijakanAnti-pattern worker yang sering terjadi
- Menganggap queue menyelesaikan semua masalah reliability. Tanpa idempotensi dan status yang rapi, job duplikat tetap terjadi.
- Mendorong file dataset besar lewat broker. Broker bukan object storage.
- Retry otomatis tanpa klasifikasi error. Error OOM, path salah, dan permission issue perlu respons berbeda.
- Satu storage bersama tanpa pengendalian I/O. Checkpoint besar dari beberapa job bisa melumpuhkan throughput.
Opsi 3: Hybrid
Pola hybrid menggabungkan kesederhanaan monolit dengan isolasi worker untuk bagian yang berat. Umumnya, aplikasi utama tetap menangani CRUD job, validasi ringan, metadata, UI, dan observabilitas dasar. Training yang benar-benar memakai GPU dijalankan oleh worker terpisah atau runner khusus.
Diagram alur sederhana
User/API
-> App Utama
-> Validasi metadata & dataset ringan
-> Simpan job
-> Jika job ringan: jalankan lokal
-> Jika job training/GPU: kirim ke Queue
-> GPU Worker
-> Training
-> Upload artefak
-> Update statusMengapa hybrid sering paling masuk akal?
Untuk tim kecil, hybrid sering menjadi titik tengah terbaik. Anda tidak perlu memecah semua komponen terlalu cepat, tetapi Anda juga tidak memaksa aplikasi utama menanggung beban training. Dengan kata lain, kompleksitas ditambahkan hanya pada bagian yang memang membutuhkannya.
Kapan hybrid layak dipilih?
- Anda ingin mulai seperti monolit, tetapi sudah melihat tanda beban akan naik.
- Task preprocessing, evaluasi ringan, atau export model masih nyaman di app utama.
- Task training utama perlu lingkungan yang lebih terisolasi dan dapat diskalakan.
- Anda ingin transisi bertahap tanpa memecah seluruh sistem sekaligus.
Kelebihan hybrid
- Jalur migrasi paling halus dari sistem kecil ke sistem yang lebih tahan beban.
- Biaya infra masih terkontrol: Anda hanya menambah worker untuk jalur kritis.
- Maintainability lebih baik untuk tim kecil dibanding worker penuh untuk semua hal.
- Observabilitas tetap terpusat di app utama, sementara eksekusi berat diisolasi.
Kekurangan hybrid
- Batas tanggung jawab harus jelas, kalau tidak Anda mendapatkan kerumitan dua dunia sekaligus.
- Risiko inkonsistensi operasional jika sebagian task jalan lokal, sebagian lewat queue, tetapi aturan statusnya berbeda.
- Dokumentasi internal wajib rapi agar tim paham job mana yang dieksekusi di mana.
Pola hybrid yang praktis
Pola yang sering berhasil adalah:
- App utama: autentikasi, upload dataset, validasi format, metadata eksperimen, dashboard, audit log.
- Worker GPU: training, resume dari checkpoint, evaluasi berat, export artefak final.
- Shared storage: lokasi terpusat untuk dataset, checkpoint, dan hasil.
Dengan pola ini, Anda bisa menambah worker GPU tanpa mengubah API publik atau skema job secara besar-besaran.
Perbandingan teknis: monolit vs worker vs hybrid
1. Utilisasi CPU/GPU
- Monolit: cocok untuk 1 mesin sederhana, tetapi GPU lebih mudah idle saat proses lain mengganggu alur.
- Worker: paling baik untuk mengalokasikan GPU secara eksplisit dan menjaga app server tetap ringan.
- Hybrid: mendekati worker untuk task berat, tanpa memindahkan seluruh sistem.
2. Isolasi dependensi
- Monolit: paling berisiko bentrok antara dependency backend dan stack ML.
- Worker: isolasi terbaik karena image/runtime dapat dipisah total.
- Hybrid: baik jika aturan pemisahan tegas.
3. Throughput
- Monolit: terbatas, terutama bila ada beberapa job panjang atau banyak operasi file.
- Worker: lebih baik karena job diantrikan dan diproses sesuai kapasitas worker.
- Hybrid: cukup baik untuk skala kecil-menengah yang bertumbuh.
4. Retry dan recovery
- Monolit: sering paling lemah jika tidak dirancang dari awal.
- Worker: unggul bila state machine, heartbeat, dan idempotensi diterapkan dengan benar.
- Hybrid: bagus untuk jalur training, selama job lokal tidak dibiarkan tanpa mekanisme pemulihan.
5. Observabilitas
- Monolit: sederhana di awal, tetapi cepat berantakan jika semua log bercampur.
- Worker: paling kaya sinyal observabilitas, namun perlu setup monitoring lebih matang.
- Hybrid: paling seimbang untuk tim kecil yang ingin dashboard terpusat.
6. Biaya infrastruktur dan operasional
- Monolit: murah di awal, mahal saat harus ditambal untuk kebutuhan reliability.
- Worker: biaya awal dan biaya operasi lebih tinggi, tetapi lebih sehat untuk sistem sibuk.
- Hybrid: kompromi yang sering paling ekonomis dalam jangka menengah.
7. Risiko bottleneck storage
- Monolit: disk lokal mudah penuh, tetapi alurnya sederhana.
- Worker: storage network bisa menjadi bottleneck besar bila banyak checkpoint/dataset dipakai serentak.
- Hybrid: masih perlu desain storage yang disiplin, namun bisa dioptimalkan bertahap.
8. Maintainability untuk tim kecil
- Monolit: terbaik sampai kompleksitas job mulai naik.
- Worker: kuat, tapi menuntut disiplin DevOps dan observabilitas.
- Hybrid: sering paling realistis jika tim kecil ingin tumbuh tanpa menanggung semua kompleksitas sejak hari pertama.
Storage: bottleneck yang sering diremehkan
Banyak tim fokus ke GPU dan lupa bahwa fine-tuning lokal sering macet karena I/O. Dataset, cache model, checkpoint, tensorboard log, dan artefak evaluasi bisa membebani storage lebih cepat daripada yang diperkirakan.
Masalah umum
- Disk lokal penuh karena checkpoint lama tidak dibersihkan.
- Network storage lambat sehingga worker menunggu baca/tulis file besar.
- Kontensi I/O saat beberapa worker menyimpan checkpoint pada waktu hampir bersamaan.
- Model base diunduh berulang karena cache tidak dibagi dengan benar.
Praktik yang disarankan
- Simpan dataset dan artefak dengan struktur path yang konsisten.
- Tetapkan kebijakan retensi checkpoint sejak awal.
- Bedakan storage untuk cache model, dataset input, dan artefak output jika memungkinkan.
- Hindari menulis log berukuran besar secara sinkron ke database transaksional.
- Pastikan ada proses cleanup berkala yang aman dan terukur.
Observabilitas dan debugging yang benar-benar berguna
Untuk pipeline fine-tuning, observabilitas yang berguna bukan hanya "job gagal". Anda perlu tahu di tahap mana job gagal dan apakah penyebabnya berasal dari input, resource, atau kode training.
Minimum observability yang sebaiknya ada
- Status job dan transisinya.
- Waktu antre, waktu mulai, durasi jalan, waktu selesai.
- Lokasi dataset, model dasar, dan output artefak.
- Exit code proses training.
- Ringkasan error yang bisa dicari.
- Heartbeat worker untuk mendeteksi job macet.
Debugging tips
- Jika GPU sering idle, cek apakah bottleneck ada di preprocessing atau storage, bukan di trainer.
- Jika job sering gagal acak, cek permission path, ruang disk, dan cleanup process.
- Jika status job tidak sinkron, audit transisi state dan pastikan update bersifat atomik.
- Jika retry menimbulkan hasil aneh, evaluasi apakah output lama ditimpa atau dicampur dengan run baru.
Catatan praktis: jangan jadikan log console sebagai satu-satunya sumber diagnosis. Simpan metadata run secara terstruktur agar investigasi tidak bergantung pada grep file panjang.
Kapan memilih tiap arsitektur?
Pilih monolit jika:
- Anda baru memulai dan ingin validasi alur lokal secepat mungkin.
- Hanya ada satu-dua engineer yang memelihara sistem.
- Job sedikit dan bisa dipantau manual.
- Downtime ringan atau retry manual masih dapat diterima.
Pilih worker terpisah jika:
- Fine-tuning menjadi workflow rutin, bukan eksperimen sesekali.
- Anda punya lebih dari satu GPU atau lebih dari satu host.
- Traffic aplikasi dan workload training tidak boleh saling mengganggu.
- Reliability dan audit trail mulai penting.
Pilih hybrid jika:
- Anda ingin mulai kecil tetapi melihat kebutuhan scale-up dalam waktu dekat.
- Tim ingin menjaga app utama tetap sederhana sambil memisahkan jalur GPU.
- Anda ingin meminimalkan migrasi besar di kemudian hari.
Checklist keputusan: mulai kecil lalu scale up tanpa migrasi mahal
Gunakan checklist berikut sebelum memutuskan arsitektur fine-tuning lokal:
- Apakah job training berdurasi panjang?
Jika ya, jangan ikat eksekusi ke request HTTP atau proses web utama. - Apakah dependency training berbeda jauh dari app backend?
Jika ya, prioritaskan isolasi environment, minimal lewat runner terpisah. - Apakah satu job gagal perlu retry otomatis?
Jika ya, rancang state machine dan idempotensi sejak awal. - Apakah Anda memperkirakan beberapa job paralel?
Jika ya, queue/worker atau hybrid lebih aman daripada monolit murni. - Apakah storage saat ini cukup untuk dataset, cache model, dan checkpoint?
Jika belum, bottleneck akan muncul bahkan pada arsitektur yang bagus. - Apakah tim mampu mengoperasikan broker, worker, monitoring, dan cleanup?
Jika tidak, hybrid biasanya lebih realistis daripada worker penuh. - Apakah API job dan metadata sudah dipisahkan dari detail runtime?
Jika ya, Anda bisa migrasi dari monolit ke hybrid/worker dengan biaya jauh lebih rendah.
Prinsip desain agar migrasi murah
- Standarkan model data job sejak awal, terlepas dari siapa yang mengeksekusi.
- Gunakan kontrak job yang stabil: input, output, status, log, artefak.
- Pisahkan control plane dan execution plane sedini mungkin, meskipun masih dalam satu repo.
- Jangan hard-code path lokal yang menyulitkan perpindahan ke worker host lain.
- Bungkus trainer di satu entrypoint konsisten agar app tidak bergantung pada detail internal training script.
Rekomendasi praktis untuk tim kecil
Jika Anda sedang membangun sistem fine-tuning lokal untuk model kecil/menengah, pendekatan yang paling aman biasanya:
- Mulai dengan monolit yang disiplin: job state di database, trainer dijalankan sebagai proses terpisah, log disimpan, output terstruktur.
- Saat job mulai rutin atau GPU menjadi resource kritis, pindahkan jalur training ke worker berbasis queue.
- Pertahankan app utama sebagai pusat metadata, autentikasi, dashboard, dan audit.
- Jadikan storage dan lifecycle artefak sebagai prioritas, bukan tambahan belakangan.
Dengan cara itu, Anda mendapatkan manfaat terbesar dari arsitektur fine-tuning lokal tanpa memaksa tim kecil menelan kompleksitas berlebih terlalu dini. Monolit cocok untuk start cepat, worker cocok untuk throughput dan isolasi, sedangkan hybrid sering menjadi pilihan terbaik untuk tumbuh stabil tanpa migrasi mahal.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!