Transformer decoder yang kita kenal pada section Attention dan Transformer biasanya kita latih dengan puluhan ribu parameter pada korpus mainan, sehingga kemampuannya terbatas pada pola data latih. Large language model (LLM) menjalankan resep yang sama — memprediksi token berikutnya — pada skala yang jauh lebih besar: miliaran parameter, triliunan token teks, dan komputasi ribuan GPU selama berbulan-bulan. Hasilnya bukan sekadar model yang lebih akurat, melainkan model yang dapat mengerjakan tugas bahasa yang tidak pernah dilatih secara eksplisit. Chapter ini memetakan definisi LLM, kemampuan yang muncul dari skala, dan siklus hidupnya, disertai language model mainan yang benar-benar kita latih.

Apa itu Large Language Model #

Large language model adalah model neural network berbasis transformer dengan arsitektur decoder-only yang dilatih untuk satu tugas: memprediksi token berikutnya dari sebuah potongan teks. Token adalah satuan teks yang diproses model — potongan kata, kata utuh, atau karakter — sesuai pembahasan kita pada chapter Tokenization . Kata large pada LLM merujuk pada tiga besaran yang tumbuh bersamaan: jumlah parameter (miliaran), jumlah token data pelatihan (triliunan), dan jumlah komputasi. Ketiga besaran itu harus naik bersama agar biaya pelatihan optimal — hubungan kuantitatifnya kita bedah pada chapter Pretraining .

Arsitektur intinya sudah kita kuasai: blok multi-head attention dengan positional encoding disusun berlapis-lapis. Sebagai decoder-only, attention pada setiap posisi dibatasi masked self-attention — token hanya boleh menoleh ke kiri, karena itulah yang tersedia saat memprediksi token berikutnya. Keluarga LLM yang banyak dipakai antara lain GPT (OpenAI), Claude (Anthropic), Gemini (Google), dan Llama (Meta, dengan beberapa versi bobotnya dirilis terbuka). Semuanya memakai resep dasar yang sama; yang membedakan adalah data, skala, dan tahap penyesuaian setelah pretraining.

Kemampuan yang Muncul dari Skala #

Dua kemampuan menonjol muncul ketika skala mencapai titik tertentu, dan keduanya tidak diprogram secara eksplisit. Pertama, in-context learning: model menyelesaikan tugas baru hanya dari contoh yang ditulis di dalam prompt, tanpa satu pun bobot model diubah. Bentuk populernya adalah few-shot prompting — kita tuliskan dua-tiga pasangan contoh di prompt, lalu model melanjutkan pola untuk masukan baru. Kedua, generalisasi format: model yang dilatih hanya meneruskan teks ternyata juga dapat merangkum, menerjemahkan, atau menulis kode ketika instruksi dan contohnya tersusun rapi, meskipun tugas tersebut tidak ada daftarnya di data pretraining. Perlu dicatat bahwa kemampuan ini datang bersama keterbatasan — hal itu kita bahas tuntas pada chapter Keterbatasan dan Risiko LLM .

Siklus Hidup LLM #

Model yang kita pakai sehari-hari melewati empat tahap besar sebelum sampai ke pengguna:

Pretraining menghabiskan porsi komputasi terbesar: model belajar statistik bahasa dari korpus web bersihan selama berbulan-bulan. Instruction tuning lalu menyeting model agar mengikuti instruksi alih-alih sekadar melanjutkan kalimat. Alignment menyesuaikan perilaku lebih lanjut — respons yang berguna dan aman dipilih dengan preferensi manusia. Terakhir, inference adalah tahap pemakaian: model membangkitkan respons token demi token. Tiga tahap pertama dibedah pada chapter-chapter berikutnya di section ini; demo berikut memperlihatkan inti mekanismenya versi mainan.

Demo: LM Mainan Prediksi Karakter Berikutnya #

Kita latih sebuah language model mini berbasis MLP: diberi 24 karakter terakhir, model menebak karakter berikutnya pada korpus buatan berisi kalimat berulang tentang tiga hewan. Model ini jelas bukan transformer — tujuannya memperlihatkan bahwa mekanisme “belajar distribusi token berikutnya lalu membangkitkan teks” bisa dibangun dan diamati langsung dalam hitungan detik:

python
"""LM mainan: prediksi karakter berikutnya pada teks berpola sederhana.

Sebuah jaringan saraf kecil (embedding + MLP) dilatih sebagai language model
karakter-level: diberi 24 karakter terakhir, tebak karakter berikutnya.
Korpus buatan berisi kalimat berulang "kucing makan ikan." dan kawanannya
sehingga pola konteks->karakter berikutnya bisa dipelajari tuntas.
Setelah pelatihan, kita bangkitkan teks secara greedy (selalu ambil
karakter dengan probabilitas tertinggi) dan ukur akurasi prediksi
karakter pada potongan korpus yang tidak dipakai melatih.
Diuji di CPU dengan PyTorch 2.14, seed tetap, deterministik.
"""

import torch
import torch.nn as nn

torch.manual_seed(0)

# ---------- 1. Korpus buatan: pola kalimat berulang ----------
blok = "kucing makan ikan. anjing makan daging. burung makan biji. "
korpus = blok * 8
LATIH, UJI = korpus[: -len(blok)], korpus[-len(blok):]

karakter = sorted(set(korpus))
id_kar = {c: i for i, c in enumerate(karakter)}
V = len(karakter)
print(f"panjang korpus latih : {len(LATIH)} karakter")
print(f"panjang korpus uji   : {len(UJI)} karakter")
print(f"vocabulary karakter  : {V} -> {''.join(karakter)!r}")
print()

JENDELA = 24


def jendela(teks):
    """Semua pasangan (konteks 24 karakter, karakter berikutnya)."""
    X, y = [], []
    for i in range(len(teks) - JENDELA):
        X.append([id_kar[c] for c in teks[i : i + JENDELA]])
        y.append(id_kar[teks[i + JENDELA]])
    return torch.tensor(X), torch.tensor(y)


X_latih, y_latih = jendela(LATIH)
X_uji, y_uji = jendela(UJI)
print(f"contoh latih: {X_latih.shape[0]} jendela, uji: {X_uji.shape[0]} jendela")
print(f"konteks[0]  : {''.join(karakter[i] for i in X_latih[0])!r}")
print(f"target[0]   : {karakter[y_latih[0].item()]!r}")
print()

# ---------- 2. Model mainan: embedding + MLP ----------
D = 16


class LMMainan(nn.Module):
    """Language model karakter-level: 24 karakter -> 1 karakter berikutnya."""

    def __init__(self, vocab, jendela, dim):
        super().__init__()
        self.embed = nn.Embedding(vocab, dim)
        self.mlp = nn.Sequential(
            nn.Linear(jendela * dim, 96),
            nn.ReLU(),
            nn.Linear(96, vocab),
        )

    def forward(self, x):
        z = self.embed(x).flatten(1)          # (batch, jendela*dim)
        return self.mlp(z)                    # logits (batch, vocab)


model = LMMainan(V, JENDELA, D)
n_param = sum(p.numel() for p in model.parameters())
print(f"parameter model: {n_param}")
print()

# ---------- 3. Pelatihan: cross-entropy pada karakter berikutnya ----------
opt = torch.optim.Adam(model.parameters(), lr=0.005)
loss_fn = nn.CrossEntropyLoss()
EPOCH = 150
print("=== Pelatihan (loss cross-entropy tiap 25 epoch) ===")
for ep in range(EPOCH):
    logits = model(X_latih)
    loss = loss_fn(logits, y_latih)
    opt.zero_grad()
    loss.backward()
    opt.step()
    if ep % 25 == 0 or ep == EPOCH - 1:
        print(f"  epoch {ep:3d}  loss latih = {loss.item():.4f}")
print()

with torch.no_grad():
    loss_uji = loss_fn(model(X_uji), y_uji).item()
    benar = (model(X_uji).argmax(1) == y_uji).float().mean().item()
print(f"loss uji akhir    : {loss_uji:.4f}")
print(f"akurasi uji       : {benar:.3f} ({int(benar * X_uji.shape[0])}"
      f"/{X_uji.shape[0]} karakter)")
print()

# ---------- 4. Bangkitan greedy: karakter demi karakter ----------
def bangkit(model, benih, panjang):
    """Sampling autoregressive deterministik (greedy)."""
    teks = list(benih)
    model.eval()
    with torch.no_grad():
        for _ in range(panjang):
            konteks = torch.tensor(
                [[id_kar[c] for c in teks[-JENDELA:]]]
            )
            logits = model(konteks)[0]
            berikutnya = logits.argmax().item()
            teks.append(karakter[berikutnya])
    return "".join(teks)


benih = LATIH[:JENDELA]
hasil = bangkit(model, benih, 45)
harapan = korpus[JENDELA : JENDELA + 45]
print("=== Bangkitan greedy 45 karakter ===")
print(f"benih  : {benih!r}")
print(f"model  : {hasil[JENDELA:]!r}")
print(f"asli   : {harapan!r}")
print(f"sama persis dengan korpus asli: {hasil[JENDELA:] == harapan}")
print()

# ---------- 5. Distribusi probabilitas pada satu posisi ----------
with torch.no_grad():
    ujung = korpus.find("burung makan ") + len("burung makan ")
    konteks_str = korpus[ujung - JENDELA : ujung]
    konteks = torch.tensor([[id_kar[c] for c in konteks_str]])
    prob = model(konteks)[0].softmax(0)
urut = prob.argsort(descending=True)[:3]
print(f"=== Distribusi karakter berikutnya setelah ...{konteks_str[12:]!r} ===")
for i in urut:
    print(f"  {karakter[i.item()]!r}: {prob[i].item():.3f}")

Output yang Dihasilkan:

text
panjang korpus latih : 413 karakter
panjang korpus uji   : 59 karakter
vocabulary karakter  : 14 -> ' .abcdgijkmnru'

contoh latih: 389 jendela, uji: 35 jendela
konteks[0]  : 'kucing makan ikan. anjin'
target[0]   : 'g'

parameter model: 38542

=== Pelatihan (loss cross-entropy tiap 25 epoch) ===
  epoch   0  loss latih = 2.6626
  epoch  25  loss latih = 0.0001
  epoch  50  loss latih = 0.0000
  epoch  75  loss latih = 0.0000
  epoch 100  loss latih = 0.0000
  epoch 125  loss latih = 0.0000
  epoch 149  loss latih = 0.0000

loss uji akhir    : 0.0000
akurasi uji       : 1.000 (35/35 karakter)

=== Bangkitan greedy 45 karakter ===
benih  : 'kucing makan ikan. anjin'
model  : 'g makan daging. burung makan biji. kucing mak'
asli   : 'g makan daging. burung makan biji. kucing mak'
sama persis dengan korpus asli: True

=== Distribusi karakter berikutnya setelah ...'urung makan ' ===
  'b': 1.000
  'i': 0.000
  'u': 0.000

Mari kita telaah kode di atas baris per baris:

  1. Baris 16-21: torch.manual_seed(0) menjamin hasil identik antar eksekusi. Korpus dibangun dari satu blok kalimat dikali delapan; blok terakhir dipisahkan sebagai data uji yang tidak pernah dilihat model saat pelatihan.
  2. Baris 34-40: fungsi jendela menggeser sebuah jendela selebar 24 karakter di sepanjang teks — setiap posisi menghasilkan satu pasangan (konteks, karakter berikutnya). Seluruh korpus diubah menjadi ratusan pasangan target inilah bentuk konkret data language model.
  3. Baris 54-68: class LMMainan memetakan token ke vektor embedding berdimensi 16, meratakannya menjadi satu vektor panjang, lalu dua lapis Linear menghasilkan logits — satu skor mentah per karakter vocabulary.
  4. Baris 81-88: training loop standar PyTorch: hitung logits, ukur CrossEntropyLoss terhadap karakter benar, mundurkan gradien, dan perbarui bobot. Loss turun dari 2,66 ke mendekati nol — pola konteks menuju karakter berikutnya berhasil dipelajari tuntas.
  5. Baris 91-96: evaluasi pada data uji. Akurasi 1,000 pada 35 jendela menunjukkan pola yang dipelajari bukan hafalan posisi, karena posisi-posisi itu tidak pernah dilatih.
  6. Baris 100-112: fungsi bangkit adalah loop autoregressive: teks dibangkitkan satu karakter per langkah, dan setiap langkah mengambil karakter berprobabilitas tertinggi (greedy) lalu menyusulkannya ke konteks.
  7. Baris 125-134: satu konteks dievaluasi lebih dekat — logits diubah menjadi distribusi probabilitas lewat softmax. Setelah “burung makan “, model memberi probabilitas 1,000 untuk huruf b (awalan “biji”).

Keluaran terpenting ada di bagian bangkitan: teks buatan model sama persis dengan kelanjutan korpus asli. Model 38 ribu parameter ini mengulang pola kalimat dengan struktur yang benar — bukti sederhana bahwa prediksi token berikutnya, ketika dipelajari dari data berpola, menghasilkan kemampuan membangkitkan teks. LLM melakukan hal yang sama pada skala miliaran parameter dan korpus internet, sehingga pola yang dipelajari mencakup tata bahasa, fakta dunia, sampai gaya penulisan kode.

Istilah Kunci #

IstilahArti singkat
TokenSatuan teks yang diproses model: potongan kata, kata, atau karakter
ParameterBobot yang dipelajari model; skala LLM diukur dari jumlahnya
Context windowJumlah token maksimum yang dilihat model sekali maju (demo: 24 karakter)
PretrainingPelatihan awal pada korpus masif dengan next-token prediction
Instruction tuningPenyetelan agar model mengikuti instruksi, bukan sekadar melanjutkan teks
AlignmentPenyesuaian perilaku model dengan preferensi manusia
InferenceTahap pemakaian model untuk membangkitkan keluaran token demi token

Seluruh rangkaian istilah di atas menggantung pada satu keputusan paling awal dan paling berdampak: teks dipecah menjadi token seperti apa. Vocabulary yang dipilih menentukan ukuran model, panjang sekuens, dan cara model melihat kata yang belum pernah ditemuinya. Chapter berikutnya membahas tokenization dari sisi LLM: algoritma BPE sampai ke baris-baris penggabungannya.