b belajar.myudak

Embedding token + posisi

Lapisan pertama GPT: setiap token id diubah menjadi vektor dengan mengambil barisnya dari tok_table, lalu ditambah vektor posisi dari pos_table:

ht=Etok[idst]+Epos[t]h_t = E_\text{tok}[\text{ids}_t] + E_\text{pos}[t]

Kembalikan matriks (T, d).

ids = [2, 0, 2]  →  [tok[2] + pos[0], tok[0] + pos[1], tok[2] + pos[2]]
Positional encoding sinusoidal

PE(pos=10, i=0) = sin(10 / 10000^(0/32)) = -0.5440

Baris = posisi token (0 di atas), kolom = dimensi. Kolom kiri berosilasi cepat, kolom kanan sangat lambat, mirip jarum detik, menit, dan jam sebuah jam. Kombinasinya unik untuk tiap posisi.

Kemiripan PE(posisi 10) dengan posisi lain

Posisi yang berdekatan punya encoding yang mirip, dan kemiripan turun seiring jarak. Inilah yang membuat model bisa "merasakan" urutan.

Embedding = lookup

tok_table[ids] adalah perkalian onehot(ids) @ tok_table tanpa membuat matriks one-hot yang boros memori. Saat backward, hanya baris-baris yang dipakai yang menerima gradien. Token yang sama di dua posisi akan menjumlahkan gradien dari keduanya (lihat np.add.at di minitorch).

Kenapa butuh posisi

Attention memperlakukan input sebagai himpunan: kalau urutan token diacak, output setiap token tidak berubah (hanya ikut teracak). Tanpa informasi posisi, “anjing menggigit orang” dan “orang menggigit anjing” terlihat sama.

Ada dua cara umum:

  • Embedding posisi yang dipelajari (GPT-2, soal ini): tabel (block_size, d) yang dilatih seperti bobot lain. Sederhana, tapi tidak bisa dipakai melewati block_size.
  • Sinusoidal (Transformer asli, widget di atas): rumus tetap sin⁡/cos⁡\sin/\cos dengan frekuensi berbeda di setiap dimensi. Model LLM modern umumnya memakai RoPE, yang memutar vektor Q dan K sesuai posisinya.

Penjelasan

Yang diminta. Setiap token id diubah menjadi vektor, lalu ditambah vektor posisinya: tok_table[ids[t]] + pos_table[t].

Langkah di kode:

  1. tok_table[ids]: fancy indexing dengan array id mengambil satu baris per id. Bentuknya (T,) → (T, d). Id yang sama (case [1, 1, 1, 1]) mengambil baris yang sama berkali-kali.
  2. pos_table[np.arange(T)] (sama dengan pos_table[:T]) mengambil baris 0 sampai T−1, juga (T, d).
  3. Jumlahkan.

Kenapa ditambah, bukan digabung (concat)? Menambah menjaga dimensi tetap d dan ternyata cukup: model belajar memakai sebagian arah ruang vektor untuk “apa tokennya” dan sebagian lain untuk “di mana posisinya”.

Cek case 2. ids = [2, 0, 2]: [5,5]+[0,0], [1,0]+[0.1,0.1], [5,5]+[0.2,0.2]. Token yang sama di posisi berbeda (id 2) menghasilkan vektor yang berbeda. Itulah inti positional embedding.

Yang dikembalikan: array (T, d).

Topik
embeddingpositional encodingindexing
Petunjuk 1

Indexing dengan array: tok_table[ids] mengambil satu baris untuk setiap id, hasilnya (T, d).

Petunjuk 2

Posisi ke-t mengambil pos_table[t]. Untuk semua posisi sekaligus: pos_table[np.arange(T)], atau cukup pos_table[:T].

Python 3.14 · NumPy

Pengaturan editor

Ukuran font
Ukuran huruf di editor.
Ukuran tab
Lebar indentasi. Otomatis: 2 spasi untuk TypeScript, 4 untuk Python.
Key bindings
Ganti ke mode Vim.
Nomor baris relatif
Nomor baris dihitung dari posisi kursor (berguna untuk gerakan Vim).
Word wrap
Baris panjang dilipat agar muat di lebar editor.
IntelliSense
Saran kode otomatis saat mengetik (Ctrl+Spasi tetap bisa dipakai saat mati).

Nilai ditulis sebagai JSON. Output yang diharapkan dihitung dari solusi referensi.