Causal mask
Model bahasa seperti GPT dilatih untuk menebak token berikutnya, jadi token ke-i tidak boleh melihat token sesudahnya. Implementasikan attention dengan causal mask: skor untuk pasangan (i, j) dengan j > i diganti -inf sebelum softmax.
Q = K = 0 (semua skor sama), V = [[3], [6], [9]]
→ token 0 melihat {3}: 3
→ token 1 melihat {3, 6}: 4.5
→ token 2 melihat {3, 6, 9}: 6
| query ↓ / key → | kucing | itu | tidur | di | atas | kasur |
|---|---|---|---|---|---|---|
| kucing | 0.20 | 0.16 | 0.17 | 0.15 | 0.15 | 0.16 |
| itu | 0.12 | 0.12 | 0.12 | 0.16 | 0.21 | 0.27 |
| tidur | 0.35 | 0.14 | 0.17 | 0.11 | 0.11 | 0.12 |
| di | 0.11 | 0.11 | 0.11 | 0.16 | 0.22 | 0.29 |
| atas | 0.12 | 0.13 | 0.13 | 0.17 | 0.20 | 0.25 |
| kasur | 0.17 | 0.15 | 0.15 | 0.16 | 0.17 | 0.19 |
Baris “tidur”: paling memperhatikan kucing (35%). Outputnya adalah rata-rata berbobot dari vektor V semua token dengan bobot di baris ini.
Attention(Q, K, V) = softmax(QKᵀ / √d) V. Setiap baris dijumlahkan menjadi 1. Matikan "bagi √d" dan lihat baris menjadi lebih "tajam". Nyalakan causal mask: token hanya boleh melihat dirinya dan token sebelumnya (dipakai GPT).
Kenapa mask
Saat training, kita memasukkan seluruh kalimat sekaligus dan meminta model menebak token berikutnya di setiap posisi secara paralel. Kalau posisi ke-3 bisa melihat posisi ke-4, tugasnya menjadi menyalin, bukan menebak: loss cepat turun ke nol tapi model tidak belajar apa-apa yang berguna. Mask menutup “masa depan”, sehingga satu kalimat sepanjang T memberi T contoh latihan sekaligus.
Kenapa -inf, bukan 0
Skor 0 tetap mendapat bobot e0/∑, jadi tidak sama dengan diabaikan. Dengan −∞, e−∞=0 tepat. Baris mana pun selalu punya minimal satu posisi yang diizinkan (dirinya sendiri), jadi penyebut softmax tidak pernah 0.
Di PyTorch
mask = torch.tril(torch.ones(T, T))
att = att.masked_fill(mask == 0, float("-inf"))minitorch punya tril dan masked_fill yang sama. Kamu akan memakainya di proyek tiny GPT.
Penjelasan
Yang diminta. Attention seperti soal sebelumnya, tetapi token i hanya boleh melihat token 0..i.
Langkah di kode:
scores = Q @ K.T / np.sqrt(d), berbentuk(T, T).future = np.triu(np.ones((T, T), dtype=bool), k=1).triudengank=1mengambil segitiga atas tanpa diagonal, yaitu tepat posisij > i(“masa depan”).scores = np.where(future, -np.inf, scores)menutup masa depan.- Softmax stabil per baris.
maxsetiap baris selalu berhingga karena diagonal tidak pernah ditutup, dan e−∞=0, sehingga posisi masa depan mendapat bobot tepat 0. w @ V.
Kenapa −∞ dan bukan 0. Skor 0 tetap ikut softmax dengan bobot e0/∑, jadi token masih “mengintip” masa depan. Hanya −∞ yang memberi bobot nol.
Cek case 2. Semua skor sama, jadi setiap token merata-ratakan semua yang boleh ia lihat: token 0 → 3, token 1 → (3+6)/2 = 4.5, token 2 → (3+6+9)/3 = 6.
Yang dikembalikan: array (T, dv). Baris pertama selalu sama dengan V[0].
Topik
Petunjuk 1
np.triu(np.ones((T, T)), k=1) bernilai 1 tepat di posisi j > i, yaitu posisi yang dilarang.
Petunjuk 2
Isi skor di posisi terlarang dengan -inf sebelum softmax. exp(-inf) = 0, jadi bobotnya nol. Baris pertama selalu hanya melihat dirinya sendiri.
Nilai ditulis sebagai JSON. Output yang diharapkan dihitung dari solusi referensi.