Belajar ML Engineer - Efficient Fine-tuning (LoRA/QLoRA)
Episode 14 of 28

Belajar ML Engineer - Efficient Fine-tuning (LoRA/QLoRA)

Fine-tuning model besar tanpa biaya meledak: parameter-efficient fine-tuning dengan LoRA dan QLoRA, kuantisasi untuk hemat memori, langkah praktis fine-tune LoRA di GPU consumer, serta gambaran RLHF dan DPO untuk menyelaraskan perilaku model

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Setelah di episode 13 kita memahami arsitektur transformer dan fine-tuning dasar, muncul kenyataan pahit: fine-tuning penuh model 7B+ membutuhkan GPU kelas server — berpuluh GB VRAM, biaya puluhan juta per bulan, dan memakan waktu berhari-hari. Pada 2026, hampir tidak ada tim yang melakukan full fine-tuning untuk produksi; hampir semuanya memakai parameter-efficient fine-tuning (PEFT).

PEFT mengubah permainan: alih-alih melatih miliaran parameter, kalian melatih sebagian kecil parameter tambahan (kadang kurang dari 1%) dan memperoleh hasil yang sebanding. Episode ini membangun keterampilan LoRA/QLoRA yang akan kalian pakai hampir setiap hari sebagai MLE modern — termasuk memilih GPU yang tepat dan memahami kapan RLHF/DPO diperlukan.

Mengapa Full Fine-tuning Boros

Full fine-tuning memperbarui semua bobot model. Dampaknya:

  • Memori: optimizer (Adam) menyimpan 2x ukuran model dalam state; 7B parameter → sekitar 30-60GB VRAM hanya untuk training.
  • Storage: setiap adapter hasil training = ukuran model penuh.
  • Risiko overfitting: dengan ribuan parameter yang bergerak, model kecil akan meniru dataset kecil terlalu kuat (catastrophic forgetting).

Inilah alasan teknik PEFT lahir dan langsung menjadi standar industri.

LoRA: Low-Rank Adaptation

LoRA (Hu et al., 2021) berangkat dari observasi penting: perubahan bobot saat fine-tuning memiliki rank rendah — hanya sedikit arah yang benar-benar berguna. Alih-alih memperbarui matriks bobot W (misal 4096×4096), LoRA menambahkan dua matriks kecil A dan B yang hasil kalinya B×A mendekati perubahan W:

text
h = W·x + (B·A)·x
       └─────┘
      adaptasi LoRA, rank r

Matriks A (r×k) dan B (d×r) berukuran kecil — dengan r=8..64, jumlah parameter terlatih turun drastis. Bobot asli W dibekukan (tidak dilatih), hanya A dan B yang berubah.

LoRA dengan PEFT
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
 
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-1.5B")
 
lora_config = LoraConfig(
    r=16,                 # rank adaptasi
    lora_alpha=32,        # skala: alpha/r
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
)
peft_model = get_peft_model(model, lora_config)
print(f"trainable: {peft_model.num_parameters(only_trainable=True):,} parameter")

Kelebihan terbesar LoRA: adapter yang dihasilkan kecil (ratusan KB hingga beberapa MB, bukan puluhan GB). Model dasar yang sama bisa dipakai untuk banyak tugas — cukup tukar adapter — tanpa duplikasi bobot.

QLoRA: LoRA + Kuantisasi

QLoRA menggabungkan LoRA dengan kuantisasi 4-bit: bobot model dasar dikompresi ke 4-bit, sementara adapter LoRA tetap dilatih dalam presisi normal. Ini menurunkan kebutuhan memori hingga ~4x, sehingga model 7B bisa di-fine-tune di GPU consumer 16-24GB:

QLoRA: quantisasi + LoRA
from transformers import BitsAndBytesConfig, AutoModelForCausalLM
 
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype="bfloat16",
)
 
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-7B",
    quantization_config=bnb_config,
    device_map="auto",
)
peft_model = get_peft_model(model, lora_config)
TeknikVRAM dibutuhkan (7B)Hasil
Full fine-tune~60GB+Kualitas maksimal, mahal
LoRA~20-30GBMendekati full, adapter kecil
QLoRA~8-12GBHampir setara LoRA, GPU consumer OK

Praktik: LoRA Fine-tune Selesai

Berikut alur utuh yang bisa kalian jalankan — dari dataset ke adapter:

LoRA fine-tune (ringkas)
from datasets import load_dataset
from transformers import AutoTokenizer, TrainingArguments
from trl import SFTTrainer
 
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B")
dataset = load_dataset("json", data_files="data/support_tickets.json")["train"]
 
trainer = SFTTrainer(
    model=peft_model,
    train_dataset=dataset,
    args=TrainingArguments(
        output_dir="./lora-out",
        per_device_train_batch_size=4,
        gradient_accumulation_steps=4,
        learning_rate=2e-4,
        num_train_epochs=3,
        logging_steps=50,
    ),
)
trainer.train()
peft_model.save_pretrained("./lora-adapter")   # simpan adapter saja

Menjalankan Inference dengan Adapter

Load model + adapter
from peft import PeftModel
 
base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-1.5B")
model = PeftModel.from_pretrained(base, "./lora-adapter")

Model dasar + adapter adalah kombinasi yang di-deploy — di episode 15 kita akan menyajikannya lewat vLLM.

Kuantisasi: Jangan Lupa Evaluasi

Kuantisasi menghemat memori dengan mengorbankan presisi. Aturan yang harus selalu dipakai: ukur dampaknya, jangan asumsikan. Sebelum mengadopsi QLoRA atau model 4-bit, bandingkan metrik (misal accuracy atau perplexity) model berkuantisasi vs presisi penuh pada eval set kalian. Untuk banyak tugas, perbedaannya kecil; untuk tugas presisi tinggi (misal matematika), bisa signifikan.

RLHF dan DPO: Menyelaraskan Perilaku

Fine-tuning supervised mengajarkan format & pengetahuan; alignment mengajarkan perilaku — menjawab sesuai preferensi manusia, tidak berbahaya, dan mengikuti instruksi.

  • RLHF (Reinforcement Learning from Human Feedback): melatih reward model dari preferensi manusia, lalu mengoptimalkan model terhadap reward model dengan PPO. Kuat tapi kompleks dan tidak stabil.
  • DPO (Direct Preference Optimization): menyederhanakan RLHF — langsung mengoptimalkan dari pasangan preferensi (preferred/rejected) tanpa reward model terpisah dan tanpa RL loop yang tidak stabil.
DPO dengan TRL
from trl import DPOTrainer, DPOConfig
 
dpo_dataset = load_dataset("json", data_files="data/preferences.json")["train"]
dpo_args = DPOConfig(output_dir="./dpo-out", beta=0.1, per_device_train_batch_size=2)
dpo_trainer = DPOTrainer(
    model=model, args=dpo_args, train_dataset=dpo_dataset, tokenizer=tokenizer
)
dpo_trainer.train()

Untuk tahun 2026, alur produksi yang umum: SFT → DPO. SFT memberi kemampuan tugas, DPO menyelaraskan jawaban dengan preferensi. RLHF penuh biasanya hanya untuk tim dengan resource besar.

Warning

Data alignment (preferensi manusia) adalah aset paling mahal dan paling mudah "bocor". Pastikan data preferensi di-review untuk bias, di-versioning ketat, dan tidak mengandung data pribadi. Model yang diselaraskan dengan data berkualitas buruk akan menghasilkan kebijakan yang buruk — dan kesalahan ini hampir mustahil diperbaiki dengan prompt.

Common Pitfalls

PitfallDampakPencegahan
Memilih rank LoRA terlalu besarOverfit, adapter membesarMulai r=8..32, naik bertahap
Lupa alpha scalingPerilaku adaptasi melencengalpha ≈ 2×r sebagai titik awal
Adapter & base mismatchInference errorSimpan model id base di adapter config
Kuantisasi tanpa evaluasiKualitas turun tak terdeteksiBandingkan metrik sebelum/sesudah
Data SFT jelek, lalu berharap DPO memperbaikiPerilaku tetap burukKualitas data sebelum alignment

Penutup

Pada episode 14 ini, kalian telah menguasai fine-tuning yang efisien:

  • LoRA melatih matriks kecil adaptasi, membekukan bobot utama — adapter berukuran MB.
  • QLoRA menambah kuantisasi 4-bit sehingga model 7B bisa di-fine-tune di GPU consumer.
  • Evaluasi kuantisasi — selalu ukur dampak, jangan asumsikan.
  • SFT → DPO adalah alur alignment standar 2026; RLHF untuk tim berresource besar.

Di episode 15 selanjutnya kita akan membahas Serving LLMs (vLLM/TGI) — PagedAttention, continuous batching, OpenAI-compatible API, dan cara menyajikan model LLM lokal dengan throughput dan memori yang efisien. Sampai jumpa di episode 15!

Belajar ML Engineer - Efficient Fine-tuning (LoRA/QLoRA) | Belajar ML Engineer