Mekanika self-attention

Scaled dot-product attention langkah demi langkah dengan tensor kecil.

Daftar isi

Self-attention menghitung penggabungan antar posisi dalam satu sekuens dengan formula scaled dot-product, yaitu perkalian titik antara query dan key yang dibagi akar dimensinya, lalu dipakai mencampur value. Topik ini menurunkan formula tersebut langkah demi langkah pada tensor kecil, menunjukkan setiap matriks yang terlibat, dan menutup dengan topeng kausalitas. Setelah selesai, rumus yang selama ini diperlakukan sebagai kotak hitam dapat direproduksi sepenuhnya dengan tangan.

Formula dan arti setiap bagiannya#

Dengan matriks Q Q , K K , dan V V yang baris-barisnya berasal dari setiap posisi, self-attention didefinisikan:

Attention(Q,K,V)=softmax(QK⊤dk)V \text{Attention}(Q, K, V) = \text{softmax}\left( \frac{QK^\top}{\sqrt{d_k}} \right) V

Matriks QK⊤ QK^\top berukuran panjang sekuens kali panjang sekuens, dan sel (i,j) (i, j) -nya adalah kecocokan antara query posisi i i dan key posisi j j . Softmax diterapkan pada setiap baris sehingga bobot posisi sumber berjumlah satu. Pembagi dk \sqrt{d_k} adalah koreksi skala yang menjadi asal nama scaled dot-product. Perkalian titik dua vektor berdimensi dk d_k yang komponennya independen dan bervarians satu menghasilkan skor dengan variansi dk d_k , sehingga pada dimensi besar skor menyebar terlalu lebar dan softmax jatuh ke satu-hot yang gradiennya mati. Membagi dengan dk \sqrt{d_k} menjaga skor tetap pada rentang yang sehat untuk semua dimensi.

Argumen koreksi ini layak diverifikasi angkanya, karena ia bukan konvensi kosong melainkan keputusan numerik. Kode berikut mengukur statistik skor dengan dan tanpa pembagian skala pada dimensi 64.

python Contoh: skala skor dengan dan tanpa pembagi akar dimensi
import torch

torch.manual_seed(0)
d_k = 64
Q = torch.randn(1, d_k)
K = torch.randn(8, d_k)
skor_mentah = K @ Q.squeeze()
skor_skala = skor_mentah / (d_k ** 0.5)
print("std skor mentah :", round(float(skor_mentah.std()), 2))
print("std skor skala  :", round(float(skor_skala.std()), 2))
print("bobot maks mentah:", round(float(torch.softmax(skor_mentah, 0).max()), 3))
print("bobot maks skala :", round(float(torch.softmax(skor_skala, 0).max()), 3))
text Keluaran
std skor mentah : 6.48
std skor skala  : 0.81
bobot maks mentah: 0.812
bobot maks skala : 0.273

Skor mentah bertaburan dengan simpangan baku sekitar delapan, dan softmax-nya menumpuk hampir seluruh bobot pada satu posisi, sedangkan skor berskala kembali ke sebaran yang sehat dengan bobot maksimum yang jauh lebih merata. Pada dimensi 512 ke atas, koreksi ini menjadi pembeda antara attention yang belajar dan attention yang sejak awal mengunci dirinya pada satu posisi.

Hitungan langkah demi langkah#

Seluruh formula dapat dihitung manual pada empat token berdimensi tiga. Kode berikut membangun Q, K, dan V dengan proyeksi linier sederhana dari satu matriks masukan, lalu menjalankan empat langkah, yaitu skor, penskalaan, softmax, dan campuran value, sambil mencetak setiap matriks perantaranya.

python Contoh: self-attention dihitung langkah demi langkah
import torch
import torch.nn.functional as F

torch.manual_seed(0)
x = torch.randn(4, 3)
W_q, W_k, W_v = torch.eye(3), torch.eye(3), torch.eye(3)
Q, K, V = x @ W_q, x @ W_k, x @ W_v
skor = Q @ K.T
skor = skor / (3 ** 0.5)
bobot = F.softmax(skor, dim=-1)
keluar = bobot @ V
print("bentuk skor :", tuple(skor.shape), "| baris berjumlah:", [round(v, 3) for v in bobot.sum(-1).tolist()])
print("bobot baris 1:", [round(v, 3) for v in bobot[0].tolist()])
print("keluaran baris 1:", [round(v, 3) for v in keluar[0].tolist()])
text Keluaran
bentuk skor : (4, 4) | baris berjumlah: [1.0, 1.0, 1.0, 1.0]
bobot baris 1: [0.808, 0.146, 0.039, 0.008]
keluaran baris 1: [1.34, -0.367, -1.99]

Baris pertama matriks bobot menyatakan seberapa besar token pertama memperhatikan setiap posisi, dan jumlahnya satu sebagaimana dua baris lainnya. Keluaran baris pertama adalah campuran terbobot seluruh value, sehingga setiap baris keluaran sudah membawa informasi dari empat posisi sekaligus. Perhatikan pula tidak ada parameter yang dipelajari pada contoh ini selain proyeksi identitas, karena tujuannya adalah mekanika murni, dan proyeksi yang dipelajari adalah isi topik Multi-head attention.

Topeng kausalitas untuk decoder#

Self-attention encoder membiarkan setiap posisi melihat seluruh sekuens, tetapi decoder generatif melarang posisi melihat masa depan, karena saat memprediksi token berikutnya, token itu memang belum ada. Larangan ditegakkan topeng yang menetapkan skor pasangan masa depan menjadi negatif sangat besar, sehingga softmax menghasilkan bobot nol tanpa mengubah bentuk perhitungan lainnya. Bentuk topengnya segitiga bawah, dan posisi diagonal tetap diperbolehkan karena posisi boleh melihat dirinya sendiri.

python Contoh: topeng kausalitas pada matriks skor
import torch
import torch.nn.functional as F

torch.manual_seed(0)
skor = torch.randn(4, 4)
topeng = torch.tril(torch.ones(4, 4)) == 0
skor_tertutup = skor.masked_fill(topeng, float("-inf"))
bobot = F.softmax(skor_tertutup, dim=-1)
print("matriks topeng:", topeng.int().tolist())
print("bobot baris 3 :", [round(v, 3) for v in bobot[3].tolist()])
print("bobot baris 0 :", [round(v, 3) for v in bobot[0].tolist()])
text Keluaran
matriks topeng: [[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]]
bobot baris 3 : [0.134, 0.41, 0.363, 0.093]
bobot baris 0 : [1.0, 0.0, 0.0, 0.0]

Baris pertama hanya melihat posisi dirinya dengan bobot satu, sedangkan baris keempat membagi perhatiannya ke empat posisi pertama dan nol ke sisanya. Bentuk segitiga bawah ini juga menjelaskan kenapa decoder dapat dilatih paralel, karena seluruh baris matriks dihitung bersama, dan kenapa generasinya tetap berurutan pada saat inference.

Dari formula ke arsitektur#

Tiga keputusan menyambung formula ini menjadi arsitektur transformer. Pertama, Q, K, dan V dihitung dari proyeksi linier yang dipelajari, bukan dari masukan mentah. Kedua, satu set proyeksi memadatkan semua informasi ke satu cara memperhatikan, dan multi-head membagi masukannya menjadi beberapa kepala yang paralel. Ketiga, keluaran attention dipadatkan dengan jaringan umpan-maju dan sambungan sisa, dan keseluruhan paket itulah isi topik Blok transformer. Informasi posisi yang tidak dimiliki formula ini dibahas pada topik penutup modul.

Ringkasan#

  • Scaled dot-product attention menghitung skor QK⊤/dk QK^\top/\sqrt{d_k} , menormalkannya per baris dengan softmax, lalu mencampur V.
  • Pembagi dk \sqrt{d_k} menjaga variansi skor stabil pada dimensi besar, dan tanpa itu softmax jatuh ke satu-hot yang gradiennya mati.
  • Satu pass self-attention menghasilkan campuran antar posisi untuk semua posisi sekaligus, dengan tidak ada parameter selain proyeksi masukannya.
  • Topeng kausalitas menutup pasangan masa depan dengan −∞-\infty sehingga decoder melatih paralel tetapi generasi tetap berurutan.

Referensi#