Bottleneck context vector memaksa seluruh makna kalimat sumber melewati satu vektor berukuran tetap. Bahdanau, Cho, dan Bengio (2014) mengusulkan jalan keluar yang kelak menjadi fondasi hampir seluruh deep learning modern: biarkan decoder melihat kembali seluruh hidden state encoder, lalu hitung rangkuman yang berbeda untuk setiap kata yang sedang diterjemahkan. Mekanisme pemilihan ini dinamai attention — perhatian — karena model belajar memperhatikan bagian masukan yang relevan pada tiap langkah. Chapter ini membedah bentuk paling sederhananya dengan angka konkret: tiga kata sumber, tiga kata target, dan bobot yang berubah dari kata ke kata.
Dari Satu Rangkuman ke Rata-rata Berbobot #
Pada seq2seq klasik, decoder hanya menerima h_N — hidden state terakhir encoder. Attention memperluas aksesnya: seluruh hidden state h_1 sampai h_N tetap disimpan, dan setiap langkah decoder menghitung context vector sendiri lewat tiga langkah berurutan:
- skor relevansi
e_jmenilai kecocokan antara state decoder saat ini dan tiap hidden stateh_j; - softmax mengubah skor menjadi bobot
α_1sampaiα_Nyang jumlahnya tepat 1; - context
c = Σ_j α_j h_j— rata-rata berbobot seluruh hidden state.
| Komponen | Peran |
|---|---|
skor relevansi e_j | menilai kecocokan state decoder dengan hidden state h_j |
bobot α = softmax(e) | porsi perhatian tiap kata sumber, jumlah tepat 1 |
context c = Σ α_j h_j | rangkuman yang berbeda untuk tiap kata target |
Karena α dihasilkan softmax, context selalu berada di antara hidden state para kata sumber — tidak ada informasi baru yang masuk, yang berubah hanyalah takarannya. Bentuk ini disebut soft attention: seluruh kata sumber ikut berkontribusi dalam kadar berbeda. Lawannya, hard attention yang memilih satu posisi saja, jarang dipakai karena pemilihan diskrit tidak menghasilkan gradient yang bisa dilatih.
Diagram di atas merangkum alurnya: satu state decoder dan tiga hidden state masuk ke perhitungan skor, softmax menakar bobotnya, lalu context dirangkai sebagai rata-rata berbobot — rantai yang sama seperti tiga langkah bernomor di atas.
Skor Additive ala Bahdanau #
Dalam makalah aslinya, skor dihitung oleh jaringan kecil yang dilatih: e_j = w^T tanh(W @ s + U @ h_j) — disebut additive attention karena state decoder dan hidden state encoder dijumlahkan di dalam tanh sebelum dinilai vektor bobot w. Jaringan penilai ini efektif, tetapi ia menuntut parameter tambahan dan dihitung pasangan demi pasangan. Ketika Transformer menggantikan skor additive dengan perkalian titik pada chapter Scaled Dot-Product Attention
, salah satu alasannya adalah perkalian titik bisa dilakukan untuk semua pasangan sekaligus sebagai satu operasi matriks.
Tiga Kata Sumber, Tiga Kata Target #
Untuk melihat inti mekanismenya tanpa beban training, kita memakai skor relevansi manual pada kalimat mainan kucing hitam tidur. Skor dipilih dengan tangan agar pola bobotnya mudah dibaca; pada model terlatih, skor yang sama dihasilkan jaringan penilai:
"""Attention ala Bahdanau: konteks = rata-rata berbobot hidden state encoder.
Tiga kata sumber ("kucing", "hitam", "tidur") memiliki hidden state sendiri.
Untuk tiap kata target yang sedang diterjemahkan, kita tetapkan skor
relevansi terhadap ketiga kata sumber, mengubahnya menjadi bobot softmax,
lalu merangkai context vector sebagai rata-rata berbobot. Dua kata isi
menunjukkan fokus sempit; satu kata fungsi menunjukkan sebaran merata.
"""
import numpy as np
def softmax(v):
e = np.exp(v - v.max())
return e / e.sum()
np.set_printoptions(precision=3, suppress=True)
# Hidden state encoder: satu baris per kata sumber (dimensi 4)
sumber = ["kucing", "hitam", "tidur"]
H = np.array(
[
[1.0, 0.2, 0.1, 0.0], # h_1 untuk "kucing"
[0.1, 1.0, 0.2, 0.0], # h_2 untuk "hitam"
[0.2, 0.1, 1.0, 0.5], # h_3 untuk "tidur"
]
)
# Skor relevansi manual (cara menghitungnya dibahas di badan chapter)
kasus = [
("hitam", np.array([1.0, 4.0, 0.5])),
("tidur", np.array([0.5, 1.0, 4.0])),
("the", np.array([1.0, 1.0, 1.0])),
]
print("Kata sumber :", sumber)
print("Hidden state:")
print(H)
print()
for kata, skor in kasus:
alpha = softmax(skor)
konteks = alpha @ H
print(f"Kata target '{kata}' sedang diterjemahkan:")
print(f" skor relevansi e : {skor}")
print(f" bobot alpha : {alpha} (jumlah = {alpha.sum():.1f})")
print(f" konteks = alpha @ H : {konteks}")
if alpha.max() > 0.5:
fokus = int(alpha.argmax())
print(f" -> fokus sempit pada '{sumber[fokus]}' "
f"(bobot {alpha[fokus]:.3f})")
else:
print(" -> sebaran merata, tidak ada fokus tunggal")
print()Output yang Dihasilkan:
Kata sumber : ['kucing', 'hitam', 'tidur']
Hidden state:
[[1. 0.2 0.1 0. ]
[0.1 1. 0.2 0. ]
[0.2 0.1 1. 0.5]]
Kata target 'hitam' sedang diterjemahkan:
skor relevansi e : [1. 4. 0.5]
bobot alpha : [0.046 0.926 0.028] (jumlah = 1.0)
konteks = alpha @ H : [0.144 0.938 0.218 0.014]
-> fokus sempit pada 'hitam' (bobot 0.926)
Kata target 'tidur' sedang diterjemahkan:
skor relevansi e : [0.5 1. 4. ]
bobot alpha : [0.028 0.046 0.926] (jumlah = 1.0)
konteks = alpha @ H : [0.218 0.144 0.938 0.463]
-> fokus sempit pada 'tidur' (bobot 0.926)
Kata target 'the' sedang diterjemahkan:
skor relevansi e : [1. 1. 1.]
bobot alpha : [0.333 0.333 0.333] (jumlah = 1.0)
konteks = alpha @ H : [0.433 0.433 0.433 0.167]
-> sebaran merata, tidak ada fokus tunggalMari kita telaah kode di atas baris per baris:
- Baris 13-15: fungsi
softmaxmengurangi nilai terbesar sebelumexpagar eksponen tidak meluap — pola standar yang juga kita pakai pada chapter-chapter berikutnya. - Baris 21-28: tiga hidden state encoder disusun sebagai matriks
Hberbentuk (3, 4) — satu baris per kata sumber, persis keluaran yang disimpan encoder seq2seq. - Baris 31-35: tiga kasus uji. Kata target
hitamdantidurmembawa skor tinggi pada satu kata sumber; kata fungsithemembawa skor seragam karena tidak punya pasangan makna di kalimat sumber. - Baris 42-44: inti attention dalam dua baris —
alpha = softmax(skor)menakar bobot,konteks = alpha @ Hmerangkai rata-rata berbobot seluruh hidden state. - Baris 46-54: pencetakan hasil plus deteksi pola: bobot terbesar di atas 0,5 dilaporkan sebagai fokus sempit, selebihnya sebagai sebaran merata.
Perhatikan dua hal pada hasilnya. Pertama, context vector berubah dari kata ke kata: [0.144; 0.938; 0.218; 0.014] saat menerjemahkan hitam, lalu [0.218; 0.144; 0.938; 0.463] saat menerjemahkan tidur — decoder menerima rangkuman yang menyesuaikan kebutuhan, bukan satu vektor tetap seperti pada chapter Sequence-to-Sequence
. Kedua, konteks untuk hitam nyaris menyalin hidden state hitam [0.1; 1.0; 0.2; 0.0] karena bobot 0,926 hampir menelan seluruh takaran — softmax tetap membagi sisa 0,074 ke dua kata lain, sehingga informasi latar tetap ikut dalam porsi kecil.
Tutorial resmi PyTorch tentang terjemahan seq2seq dengan attention
memuat implementasi additive attention dalam bentuk nn.Module yang bisa dilatih — kelanjutan yang tepat setelah konsep di sini dikuasai.
Dengan ini hambatan ketiga dari chapter sebelumnya terjawab: context vector tidak lagi sempit karena takarannya dinamis. Dua pertanyaan berikutnya justru lahir dari solusi ini — bagaimana menghitung skor tanpa jaringan terpisah, dan bagaimana memakai attention tanpa struktur encoder-decoder? Keduanya dijawab Transformer lewat tiga peran baru: query, key, dan value — pokok bahasan chapter berikutnya.