Informasi posisi

Mengapa urutan token harus disuntikkan dan bentuk positional encoding.

Daftar isi

Self-attention memperlakukan masukan sebagai himpunan tanpa urutan, sehingga informasi posisi harus disuntikkan secara terpisah dan inilah peran positional encoding. Topik ini membuktikan simetri yang menuntut suntikan itu, menurunkan encoding sinusoidal beserta sifat relatifnya, dan memeragakan bentuk learnable yang dipakai model modern. Setelah selesai, baris penjumlahan embedding plus posisi pada kode transformer terbaca sebagai kebutuhan struktural, bukan kebiasaan.

Bukti bahwa urutan tidak dilihat oleh attention#

Formula scaled dot-product tidak memuat posisi di mana pun. Kecocokan dihitung dari isi vektor, softmax menormalkan bobot, dan campuran value hanya memakai bobot itu, sehingga mengacak urutan baris masukan mengacak urutan keluaran dengan cara yang persis sama, dan relasi antar barisnya tidak berubah. Akibatnya, kalimat anjing menggigit orang dan orang menggigit anjing diperlakukan identik, padahal keduanya berbeda makna.

Sifat ini dapat diverifikasi dengan eksperimen kecil yang menukar dua baris masukan dan membandingkan keluaran per barisnya.

python Contoh: mengacak baris masukan hanya mengacak keluaran
import torch
import torch.nn as nn

torch.manual_seed(0)
mha = nn.MultiheadAttention(embed_dim=8, num_heads=2, batch_first=True)
x = torch.randn(1, 4, 8)
permutasi = torch.tensor([2, 0, 3, 1])
keluar, _ = mha(x, x, x)
keluar_acak, _ = mha(x[:, permutasi], x[:, permutasi], x[:, permutasi])
kembali = keluar_acak[:, torch.argsort(permutasi)]
print("keluaran identik setelah acak dan urut ulang:", torch.allclose(keluar, kembali, atol=1e-6))
text Keluaran
keluaran identik setelah acak dan urut ulang: True

Keluaran yang sudah diurutkan kembali identik dengan keluaran aslinya, dan itulah bukti bahwa self-attention tidak menyimpan urutan apa pun. Konsekuensinya langsung, yaitu token embedding yang sama akan mendapat representasi yang sama di posisi mana pun, sehingga satu sumber informasi urutan harus ditambahkan, dan penambahannya berupa vektor posisi yang dijumlahkan ke embedding sebelum masuk blok pertama.

Encoding sinusoidal dan sifat relatifnya#

Makalah transformer asli menyuntikkan posisi dengan kombinasi gelombang sinus dan kosinus yang frekuensinya menurun secara geometris sepanjang dimensi, dan untuk posisi p p serta dimensi ganjil-genap 2i,2i+1 2i, 2i+1 :

PE(p, 2i)=sin⁡(p100002i/d),PE(p, 2i+1)=cos⁡(p100002i/d) PE_{(p,\,2i)} = \sin\left(\frac{p}{10000^{2i/d}}\right), \qquad PE_{(p,\,2i+1)} = \cos\left(\frac{p}{10000^{2i/d}}\right)

Tiga sifat menjelaskan pilihan ini. Pertama, setiap posisi memperoleh pola yang unik, karena frekuensi berbeda membuat pasangan nilai sinus-kosinusnya berbeda. Kedua, nilainya terikat pada rentang −1-1 sampai 1 pada posisi berapa pun, sehingga skala embedding tidak perlu diubah untuk sekuens panjang. Ketiga, dan paling sering dirujuk, pergeseran posisi tetap dapat dinyatakan sebagai rotasi tetap terhadap dimensi-dimensinya, sehingga selisih antar posisi memiliki wujud linier yang mudah dikenali oleh layer berikutnya.

Sifat ketiga ini diukur langsung pada tabel encoding yang dibangun dari formula di atas, dengan membandingkan kecocokan posisi yang berjarak tetap.

python Contoh: kecocokan encoding untuk jarak yang sama
import torch

def encoding(posisi, d):
    k = torch.arange(d // 2, dtype=torch.float32)
    frekuensi = 10000 ** (-2 * k / d)
    sudut = posisi * frekuensi
    return torch.stack([torch.sin(sudut), torch.cos(sudut)], dim=1).flatten()

d = 32
p0 = torch.arange(d, dtype=torch.float32) / d
e0, e2, e2tengah = encoding(0, d), encoding(2, d), encoding(200, d)
print("cos(0 vs posisi 2)   :", round(float(torch.cosine_similarity(e0, e2, dim=0)), 3))
print("cos(0 vs posisi 200) :", round(float(torch.cosine_similarity(e0, e2tengah, dim=0)), 3))
print("cos(2 vs posisi 4)   :", round(float(torch.cosine_similarity(e2, encoding(4, d), dim=0)), 3))
print("rentang nilai        :", round(float(e2tengah.min()), 3), "sampai", round(float(e2tengah.max()), 3))
text Keluaran
cos(0 vs posisi 2)   : 0.858
cos(0 vs posisi 200) : 0.509
cos(2 vs posisi 4)   : 0.858
rentang nilai        : -0.969 sampai 0.999

Kecocokan posisi berjarak dua tetap sama apapun letaknya di sekuens, yaitu posisi 0 terhadap 2 sebanding dengan posisi 200 terhadap 202, sedangkan kecocokan terhadap posisi yang jauh menyusut. Pola ini persis sifat relatif yang dijanjikan, yaitu encoding menyatakan posisi absolut tetapi kecocokannya mengukur jarak, dan rentang nilainya tetap terkendali pada posisi 200 sekalipun.

Learnable dan embedding yang digabung#

Alternatif yang dipakai banyak model modern adalah vektor posisi learnable, yaitu tabel berukuran panjang maksimum kali dimensi yang dipelajari seperti parameter lain, dan nn.Embedding yang sama dengan topik Embedding mewujudkannya dalam satu baris. Kedua bentuk unggul pada hal yang berbeda, karena sinusoidal tidak menuntut panjang maksimum yang tetap dan tetap bermakna pada posisi yang melebihi pelatihan, sedangkan learnable menyesuaikan diri pada panjang yang memang dipakai dan sering unggul bila panjangnya terbatas.

Kode berikut memeragakan gabungan keduanya pada masukan transformer mini, yaitu embedding token ditambah vektor posisi, lalu diteruskan ke blok encoder.

python Contoh: token embedding plus posisi learnable
import torch
import torch.nn as nn

torch.manual_seed(0)
d_model, panjang = 32, 16
emb = nn.Embedding(50, d_model)
posisi = nn.Embedding(panjang, d_model)
blok = nn.TransformerEncoderLayer(d_model, nhead=4, batch_first=True, norm_first=True)

token = torch.randint(0, 50, (2, panjang))
idx = torch.arange(panjang)
masukan = emb(token) + posisi(idx)
keluar = blok(masukan)
print("bentuk masukan blok :", tuple(masukan.shape))
print("bentuk keluaran blok:", tuple(keluar.shape))
text Keluaran
bentuk masukan blok : (2, 16, 32)
bentuk keluaran blok: (2, 16, 32)

Penjumlahan sederhana itulah seluruh suntikan posisi pada arsitektur aslinya, dan mekanikanya bertumpu pada dua tabel yang berbeda peran tetapi setara bentuknya. Pada model bahasa modern, varian rotasinya yang disebut RoPE memindahkan informasi posisi ke dalam operasi attention itu sendiri, dan menuliskannya kembali sebagai rotasi pada query dan key, sehingga sifat relatif sinusoidal dipertahankan tanpa menambah parameter. Untuk kebutuhan memahami arsitektur dasar, penjumlahan pada contoh di atas adalah bentuk yang dirujuk seluruh literatur awal.

Ringkasan#

  • Self-attention hanya melihat isi vektor, sehingga mengacak urutan masukan mengacak keluaran tanpa mengubah relasi antar posisi.
  • Encoding sinusoidal memberi tiap posisi pola unik pada rentang −1-1 sampai 1, dengan kecocokan yang murni mengukur jarak antar posisi.
  • Alternatif learnable memakai tabel posisi yang dipelajari, dan pilihannya menyangkut panjang maksimum versus fleksibilitas.
  • Suntikan posisi berupa penjumlahan embedding token dengan vektor posisi sebelum blok pertama, dan varian RoPE memindahkannya ke dalam attention.

Referensi#