Evaluasi angka pada bagian sebelumnya perlu ditutup dengan satu pertanyaan praktis: seperti apa teks yang benar-benar dihasilkan model. Bagian penutup ini menjalankan inference generatif — melanjutkan tiga prompt pendek sebanyak 40 karakter — pada dua model sekaligus: model dasar beku dan model yang telah diberi adapter LoRA. Decoding dipilih greedy (selalu mengambil karakter dengan logit tertinggi), sehingga keluaran deterministik untuk model yang sama; strategi decoding lain seperti sampling dengan temperature dibahas pada chapter Inference dan Decoding dan bisa Anda tambahkan sendiri sebagai latihan.

Mesin Generasi Karakter demi Karakter #

Fungsi generate_greedy di src/inference.py bekerja dalam dua fase:

python src/inference.py — inti generate_greedy
def generate_greedy(model: ModelBahasa, teks_awal: str, sto: dict,
                    huruf: list, jumlah: int = JUMLAH_KARAKTER) -> str:
    """Lanjutkan teks_awal dengan decoding greedy sebanyak `jumlah` karakter."""
    with torch.no_grad():
        h = torch.zeros(1, model.lstm.d_sembunyi)
        c = torch.zeros(1, model.lstm.d_sembunyi)
        token = enkode(teks_awal, sto)
        for t in token:  # panaskan state LSTM dengan teks awal
            h, c = model.lstm.langkah(
                model.embed.weight[t].view(1, -1), (h, c))
        hasil = list(token)
        for _ in range(jumlah):
            logit = model.kepala(h)                  # (1, V)
            berikutnya = int(logit.argmax(dim=1))    # greedy: argmax
            hasil.append(berikutnya)
            h, c = model.lstm.langkah(
                model.embed.weight[berikutnya].view(1, -1), (h, c))
        return dekode(hasil, huruf)

Mari kita telaah fungsi di atas baris per baris:

  1. torch.no_grad(): seluruh generasi berjalan tanpa pelacakan gradient — inference memang tidak butuh backward pass.
  2. Fase pemanasan: setiap karakter prompt dilewatkan ke sel LSTM satu per satu untuk membawa state (h, c) ke konteks akhir prompt; karakter pertama hasil generasi diprediksi dari state ini.
  3. logit.argmax(dim=1): pilihan greedy — karakter dengan skor tertinggi, tanpa unsur acak.
  4. Umpan balik: karakter yang baru dipilih langsung menjadi masukan langkah berikutnya, sehingga kesalahan kecil bisa terbawa — inilah sebabnya teks generatif level karakter mudah berulang.

Tiga Prompt, Dua Model #

Skrip menyiapkan ulang kedua model dengan benih yang sama seperti pelatihan (pra-latih 150 epoch, LoRA 60 epoch), lalu membandingkan keduanya:

bash
python3 src/inference.py

Output yang Dihasilkan:

text
== persiapan ==
pra-latih  : 150 epoch pada subset umum
fine-tune  : 60 epoch LoRA r=4 pada subset kopi, loss 2.598 -> 1.721
generasi   : greedy, 40 karakter per prompt

prompt     : 'kopi '
model beku : 'kopi di derangan malam.sikore dengu laman mal'
model lora : 'kopi dingi kopi dingi kopi dingi kopi dingi k'

prompt     : 'barista '
model beku : 'barista semerananang memanak man malam.siti dera'
model lora : 'barista sepanga kopi dingi kopi dingi kopi dingi'

prompt     : 'sore '
model beku : 'sore dituku daman setama kama berjalan ketu m'
model lora : 'sore dingi kopi kopi dingi kopi dingi kopi di'

Pola yang muncul konsisten pada ketiga prompt. Model beku merangkai potongan kalimat umum (“berjalan”, “malam.”, “siti”) dengan ejaan yang sering melenceng — perilaku wajar untuk model 27 ribu parameter yang hanya dilatih 20 kalimat. Model ber-LoRA hampir sepenuhnya terseret ke domain kopi: kata “kopi” dan “dingin” (yang terpotong menjadi “dingi”) berulang tanpa henti. Pengulangan ini adalah wujud langsung dari ppl umum yang naik di Bagian 4 — adapter menajamkan prediksi pada domain kopi sampai model nyaris hanya bisa mengulang frasa domainnya.

Ada dua latihan yang pas ditutup di sini karena semuanya tinggal mengganti beberapa baris. Pertama, ganti logit.argmax(dim=1) dengan sampling bertemperature: bangkitkan distribusi probabilitas = torch.softmax(logit / suhu, dim=1) lalu tarik karakter lewat torch.multinomial — suhu rendah mempertahankan greedy, suhu tinggi melonggarkan pengulangan. Kedua, tambahkan argumen jumlah pada CLI sehingga prompt bisa dilanjutkan 100 karakter sekaligus; amati pada titik keberapa teks mulai berputar. Keduanya memperdalam pemahaman decoding yang dibahas chapter Inference dan Decoding .

Proyek ini menuntaskan satu siklus LLM mini: pra-latih, fine-tune dengan LoRA, evaluasi dua domain, inferensi generatif. Proyek berikutnya, Deteksi Objek pada Gambar , berpindah ranah dari teks ke gambar — keluaran model bukan lagi satu token, melainkan kelas objek beserta kotak posisinya di dalam citra.