Lewati ke konten utama

Memahami Multi-Head Attention pada Transformer

Pelajari apa itu multi-head attention, bagaimana self-attention bekerja di dalam transformer, dan mengapa mekanisme ini penting untuk menjalankan LLM seperti GPT-5 dan VLM seperti CLIP—dengan contoh sederhana, diagram, dan kode.
· 12 mnt Baca

Jelajahi bersama AI

Pendahuluan ke Mekanisme Self-Attention

Mekanisme attention, atau lebih spesifik lagi, mekanisme self-attention, pertama kali diperkenalkan dalam makalah terkenal  “Attention is All You Need“ oleh Vaswani dkk. pada 2017. 

Mekanisme inilah yang menggerakkan model Transformer, yang pada gilirannya menjadi fondasi beberapa model terkuat yang kita miliki, seperti LLM dan VLM. 

Jadi ya, ini cukup penting!

Namun begini: banyak orang (dan dulu saya salah satunya!) percaya bahwa attention ditemukan pada 2017.

Faktanya tidak demikian.

Mekanisme attention asli pertama kali diperkenalkan pada 2015, ketika Bahdanau dkk. memperkenalkannya dalam konteks penerjemahan mesin. Gagasannya adalah membiarkan decoder berfokus pada bagian-bagian berbeda dari kalimat masukan di setiap langkah decoding, alih-alih bergantung pada satu vektor konteks tetap.

Perubahan kecil itu berdampak besar — dan menanamkan benih bagi apa yang kemudian menjadi self-attention dan pada akhirnya multi-head attention.

Namun pada titik ini Anda mungkin punya pertanyaan:

“Sebenarnya apa arti attention?”

Izinkan saya memperkenalkan konsep ini dengan dua kalimat sederhana:

  • “The cat sat on the mat.” → Model kita mungkin memusatkan attention dari sat ke cat dan mat sekaligus.
  • “She drank her tea because she was thirsty.” → Attention dari drank menunjuk ke tea dan thirsty, menghubungkan sebab dan tindakan.

Dari contoh-contoh ini, kita mulai melihat apa yang ingin dicapai oleh attention. Intinya adalah fokus; membantu model memutuskan kata mana yang relevan dengan kata yang sedang diproses, sering kali berdasarkan makna semantik atau hubungan gramatikal.

Hal penting yang perlu dicatat adalah semua token digunakan saat menghitung bobot dan skor attention (lebih lanjut tentang ini nanti), bukan hanya token tertentu saja, seperti terlihat pada diagram di atas. Ini juga berarti akan ada attention yang lebih kuat antara beberapa kata dibandingkan yang lain, tergambar dari ketebalan panah.

Inilah yang membuat transformer sangat unggul dalam memahami bahasa; mereka menggunakan attention untuk secara dinamis mengaitkan setiap kata dengan kata lainnya.

Langkah perantara

Kita sekarang telah memahami apa itu attention, tetapi kita masih belum tahu bagaimana pemrosesan internalnya.

Di sinilah Query, Key, dan Value (umumnya disingkat Q, K, dan V) berperan. Untuk sisa artikel ini, kita akan tetap menggunakan kalimat contoh kita - “the cat sat on the mat”. 

Pertama, saat sebuah kalimat dimasukkan ke Transformer, kalimat itu langsung ditokenisasi oleh tokenizer; salah satu tokenizer terkenal adalah Byte-pair encoding. 

Kita bisa menganggap tokenisasi sebagai memecah teks menjadi unit-unit yang lebih kecil. Karena semua kata dalam kalimat kita cukup pendek, untuk contoh ini, kita dapat mengasumsikan bahwa tiap unit setara dengan satu kata. Secara visual, kalimat setelah melalui tokenizer akan terlihat seperti ini:

Perhatikan bahwa bahkan tanda baca (titik) juga telah diubah menjadi Token. Sekali lagi, demi kesederhanaan, kita mengasumsikan bahwa tanda titik adalah token terpisahnya sendiri. 

Setelah tokenisasi, kita menggunakan kosakata tokenizer untuk mengonversi setiap token ke Token ID masing-masing. Kosakata tokenizer dapat dianggap sebagai basis data/tabel yang menyimpan semua token yang dapat dikenali model beserta Token ID-nya masing-masing.

Setelah itu, setiap token ID unik ini dipetakan ke embedding token masing-masing menggunakan matriks embedding. Penting untuk dicatat bahwa semua embedding token ini akan berupa vektor dengan dimensi yang sama; dalam contoh kita, kita mengasumsikan 512.

Langkah terakhir adalah penambahan positional embedding agar model memiliki informasi posisi untuk setiap token. Dua metode umum adalah:

  1. Pengodean sinusoidal (digunakan pada Transformer asli)
  2. Positional embedding terpelajar (digunakan pada BERT, GPT)

Mekanisme dasar dari positional embedding ini berada di luar cakupan tutorial ini. Yang perlu kita ketahui untuk saat ini adalah kita memperoleh vektor masukan melalui rumus berikut:

Vektor input = Token Embedding + Positional Embedding

Query, key, dan value

Sekarang kita akhirnya siap memperkenalkan vektor Q, K, V. Untuk memulai, perhatikan bahwa untuk setiap kata dalam masukan, kita membuat tiga vektor:

  • Query (Q) – ini adalah apa yang sedang dicari oleh kata tersebut
  • Key (K) – ini adalah apa yang ditawarkan kata tersebut kepada yang lain
  • Value (V) – ini adalah informasi yang benar-benar dipegang oleh kata tersebut

Ini adalah transformasi yang dapat dipelajari dan juga merupakan matriks masing-masing. Secara matematis, transformasi ini dituliskan seperti ini:

Dari sini, setiap token dapat direpresentasikan oleh tiga vektor baru. Saya membuat diagram di bawah untuk membantu memvisualisasikan proses ini:

Menghitung scaled dot-product 

Dalam makalah “Attention is all you need”, diberikan sebuah rumus matematika yang menunjukkan bagaimana vektor baru digunakan untuk menghitung Bobot Attention. Mari kita lewati langkah demi langkah, dengan asumsi kita menghitung Bobot Attention saat berada pada “sat”:

Formula presented in the "Attention is all you need" paper.

Untuk mulai, kita menggunakan vektor Query dari “sat” untuk membandingkannya dengan vektor Key dari setiap kata lain — termasuk dirinya sendiri. Hasilnya adalah sekumpulan skor kemiripan (ini berupa skalar) yang memberi tahu kita seberapa relevan setiap kata terhadap “sat”. Secara formal ini dikenal sebagai Attention Score.

Skor ini kemudian diskalakan melalui sqrt(d_k) untuk mencegah skor menjadi terlalu besar dan membantu menstabilkan gradien saat pelatihan melalui backpropagation. Skor tereskalasi ini kemudian dilewatkan melalui softmax, mengubahnya menjadi bobot attention. 

Softmax memberi kita probabilitas yang memberi tahu model seberapa besar bobot yang diberikan ke setiap kata, dan oleh karena itu bobot attention untuk suatu token akan berjumlah 1. 

Terakhir, kita mengambil jumlah tertimbang dari vektor value, menggunakan bobot attention ini. 

Ini memberi kita vektor baru yang merepresentasikan “sat” dalam konteks, diperkaya oleh informasi dari semua token, tetapi terutama dari cat, mat, dan token relevan lain.

Proses ini terjadi untuk setiap token dalam kalimat. Setiap token memperhatikan setiap token lainnya, bahkan dirinya sendiri. Itulah mengapa kita menyebutnya self-attention.

Perhatikan juga bahwa kita menghitung vektor diperkaya baru untuk satu token, tetapi dalam praktiknya, kita akan melakukannya untuk banyak, jika bukan semua, token secara sekaligus, karena perkalian matriks sangat efisien. 

Kita bisa melakukannya karena arsitekturnya sepenuhnya dapat diparalelkan. Berbeda dengan recurrent neural networks (RNN) yang memproses secara berurutan, mekanisme ini memungkinkan Transformer memproses semua token sekaligus, menjadikannya cepat dan bertenaga.

Untuk membantu visualisasi, lihat diagram di atas. Anda dapat melihat bahwa matriks masukan X ditransformasikan menjadi matriks Query, Key, dan Value masing-masing, lalu rumus scaled dot-product attention diterapkan, untuk memperoleh vektor embedding kaya konteks dari semua token dalam masukan kita - A.

Mengimplementasikan scaled dot-product attention di PyTorch

Sekarang mari kita tuliskan kode dari apa yang baru saja kita bahas di PyTorch. Mengejutkannya, ini cukup mudah:

import torchimport torch.nn.functional as Fdef scaled_dot_product_attention(Q, K, V):    d_k = Q.size(-1)  # the dimension of the key vectors    scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))    attn_weights = F.softmax(scores, dim=-1)    output = torch.matmul(attn_weights, V)    return output, attn_weights

Dengan mengimplementasikan fungsi sederhana, kita dapat mereplikasi pembahasan di atas! Berikut poin-poin terpentingnya:

  • Q, K, dan V adalah tensor berbentuk [batch_size, seq_len, dim]
  • Keluaran adalah sekumpulan vektor baru di mana setiap token direpresentasikan dalam konteks seluruh urutan
  • Attention Score adalah kemiripan mentah yang belum ternormalisasi
  • Bobot Attention adalah nilai yang ternormalisasi (melalui softmax) untuk memfokuskan dan berjumlah 1

Berbagai Jenis Attention

Namun ada satu detail penting yang belum saya sebutkan. Lihat, bukan hanya ada satu jenis attention di dalam Transformer — sebenarnya ada tiga:

  1. Encoder self-attention
  2. Decoder self-attention
  3. Encoder–decoder (cross) attention

Masing-masing memiliki peran yang sedikit berbeda, jadi mari kita bahas secara singkat.

Encoder self-attention

Inilah yang telah kita jelajahi sejauh ini, di mana pada encoder, setiap token memperhatikan setiap token lain dalam urutan masukan yang sama, seperti contoh “the cat sat on the mat.” 

Hal penting yang perlu dicatat di sini adalah tidak ada pembatasan karena seluruh masukan telah diketahui sebelumnya, memungkinkan model membangun representasi kontekstual yang dalam untuk setiap token, di mana ia memahami apa yang datang sebelum dan sesudahnya. 

Perhatikan juga bahwa ini terjadi di encoder. 

Decoder self-attention

Di sinilah hal-hal menjadi sedikit lebih sulit. Karena kita sekarang berada di decoder, kita tidak ingin setiap token melihat masa depan, karena itu akan menjadi kecurangan saat generasi teks.

Mari ambil contoh lain, “The dog barked very loudly.” Saat model menghasilkan “barked” (dengan asumsi setiap kata adalah token untuk kesederhanaan), model tidak boleh mengetahui bahwa token berikutnya adalah “very”, jika tidak model tidak akan belajar menghasilkan token baru. 

Untuk mengatasi masalah ini, kita menerapkan causal mask (kadang juga disebut triangular mask) yang memastikan setiap token hanya dapat memperhatikan dirinya sendiri dan token-token sebelumnya, tidak pernah yang di depannya.

Diagram shows a Causal mask being applied to a 5 token input

Dari diagram di atas, kita dapat melihat bahwa skor attention untuk masa depan dihapus dengan masking, memungkinkan model belajar menghasilkan token baru yang akurat dan masuk akal.

Encoder-decoder (cross) attention

Setelah decoder mulai menghasilkan keluaran, ia tetap memerlukan informasi dari masukan asli (yang menjadi acuan responsnya). Di sinilah cross attention berperan.

Di sini, decoder memperhatikan keluaran encoder. Jadi sementara self-attention pada decoder dimasking, cross-attention tidak, sehingga decoder boleh melihat semua token encoder sekaligus.

Saat saya mempelajari konsep ini, saya sangat menyukai Contoh Penerjemahan. Bayangkan Anda menerjemahkan “Bonjour tout le monde” ke bahasa Inggris, decoder seharusnya dapat melihat semua kata Prancis saat memutuskan tiap kata bahasa Inggris, bukan? 

Inilah tepatnya yang dilakukan cross attention. Namun, kita tidak akan membahas cross attention lebih dalam di sini, karena tidak diperlukan untuk cakupan artikel ini.

Kebutuhan akan Multi-Head Attention

Sekarang kita memahami bagaimana self-attention bekerja. Tetapi Anda mungkin punya pertanyaan ini:

Jika kita sudah memiliki attention, mengapa kita memerlukan banyak head?

Untuk ini, saya ingin menyajikan analogi senter, yang membantu membangun intuisi saya saat pertama kali belajar.

Bayangkan satu head attention sebagai satu senter yang mencoba menerangi bagian-bagian penting dari sebuah kalimat. Namun sebuah kalimat memiliki banyak jenis hubungan untuk dipahami: subjek-verba, objek-pronomina, adjektiva-nomina, ketergantungan jarak jauh, dan sebagainya.

Bukankah lebih baik jika kita dapat menangkap lebih banyak hubungan ini alih-alih hanya satu setiap kali?

Karena itu, solusinya adalah memberi model beberapa senter, masing-masing berfokus pada bagian berbeda dari kalimat. Inilah yang disebut multi-head attention.

Alih-alih menghitung satu set Q, K, V, dan menjalankan satu kali perhitungan attention, kita membagi embedding menjadi bagian-bagian lebih kecil dan menjalankan beberapa head attention independen secara paralel. 

Illustration showing how an Input Embedding is split evenly across the Multiple Heads

Seperti terlihat pada diagram di atas, embedding masukan (untuk satu token dalam kasus ini, demi kesederhanaan) dibagi rata ke seluruh n head berbeda. 

Dalam contoh kita, misalkan dimensinya 512 dan jumlah head 8, maka setiap head attention akan memproses (512/8=64) dimensi secara paralel, berupaya menangkap berbagai hubungan. 

Untuk membangun intuisi Anda lebih jauh tentang jenis hubungan apa yang mungkin (saya katakan mungkin karena kita masih belum sepenuhnya memahami hubungan apa yang dilihat tiap head) diproses oleh head-head ini, mari kita bahas contoh sederhana:

Pertimbangkan kalimat ini:

“The quick brown fox jumps over the lazy dog.”

  • Satu head mungkin berfokus pada pasangan adjektiva–nomina: “quick → fox”, “lazy → dog”
  • Head lain mungkin berfokus pada subjek–verba: “fox → jumps”
  • Dan head lainnya mungkin menangkap hubungan jarak jauh: “jumps → over → dog”

Hal utama yang perlu dicatat adalah semua head ini berjalan secara simultan, dan keluarannya kemudian digabungkan (concatenate) dan diproyeksikan kembali ke ukuran embedding asli (dalam kasus kita 512). 

Memvisualisasikan banyak head melalui kode

Untuk benar-benar memantapkan pemahaman kita tentang Multi-Head Attention, mari gunakan pustaka HuggingFace untuk melihat bagaimana mekanisme Multi-Head Attention bekerja. 

!pip install transformers bertviz torch

Pertama, jalankan sel kode di atas untuk mengunduh semua paket yang relevan.

from transformers import BertTokenizer, BertModelfrom bertviz import head_viewimport torchmodel_name = 'bert-base-uncased' # We will be using the Bert modelmodel = BertModel.from_pretrained(model_name, output_attentions=True)tokenizer = BertTokenizer.from_pretrained(model_name)model.eval() # As we are not training, we have set the model to evaluation mode so no updates are made# This is our input sentencesentence = "The quick brown fox jumps over the lazy dog."# Using the tokenizer to convert the sentence into tokensinputs = tokenizer(sentence, return_tensors='pt')input_ids = inputs['input_ids']# Forward pass with attentionswith torch.no_grad():    outputs = model(**inputs)    attentions = outputs.attentions  # Tuple of (num_layers, batch, num_heads, seq_len, seq_len)# Here we decode the tokens tokens = tokenizer.convert_ids_to_tokens(input_ids[0])head_view(attentions, tokens) # Visualization

Keluaran yang kita dapatkan dapat dilihat di bawah. Perhatikan ada 12 warna berbeda, yang berarti ada 12 Head dalam model ini. Ketebalan garis juga berkorelasi dengan besarnya skor attention antar token. 

Layer 1's Multi-Head Attention Visualization of our example

Mengimplementasikan Multi-Head Attention: Praktik Terbaik

Di bagian ini, kita akan menuliskan pseudocode untuk mekanisme Multi-Head Attention. Mari asumsikan terlebih dahulu bahwa masukan kita: X memiliki bentuk [batch, seq_len, d_model]. 

Kemudian kita dapat melanjutkan dengan pseudocode: 

Q = X @ W_Q # Calculating the Query valuesK = X @ W_K # Calculating the Key valuesV = X @ W_V# Calculating the Value valuesQ_i, K_i, V_i = split_into_heads(Q, K, V, num_heads) # Now we split the Q,K,V into multiple different heads (by evenly splitting the dimensions)# Here we compute scaled dot-product attention for each headscores = (Q_i @ K_i.T) / sqrt(head_dim)scores += maskA_i = softmax(scores)A_i = dropout(A_i)Z_i = A_i @ V_iZ = concat_heads(Z_i) # We have to concatenate all of the Heads# This is our final linear projection matrixoutput = Z @ W_Ooutput = dropout(output)

Semua ini seharusnya sudah familier bagi Anda sekarang, kecuali mungkin matriks proyeksi linear terakhir. 

Mari kita bahas ini secara singkat. 

Setelah semua head attention individual menyelesaikan pekerjaannya, keluarannya digabungkan kembali menjadi satu vektor. Namun keluaran gabungan ini masih perlu dibentuk kembali ke dimensi model asli dan di sinilah matriks proyeksi linear terakhir berperan. Matriks ini sekadar memetakan keluaran yang digabungkan kembali ke ukuran yang sama dengan embedding masukan, sehingga dapat diteruskan ke lapisan berikutnya dalam Transformer.

Mari kita juga bahas beberapa optimisasi dan praktik terbaik:

  1. Paralelisasi: Karena setiap head independen, kita dapat menghitung semuanya secara paralel.
  2. Perkalian matriks: Kita mem-batch semuanya menggunakan operasi aljabar linear (mis. matmul), yang sangat dioptimalkan.
  3. FlashAttention (Lanjutan): Ini adalah teknik lebih baru yang menggunakan trik CUDA tingkat rendah untuk mengurangi overhead memori dan mempercepat attention — terutama pada urutan panjang.

Dalam hal praktik terbaik, saat kita menulis lapisan attention, ada 3 hiperparameter utama yang perlu diperhatikan:

  1. num_heads: Berapa banyak head attention yang dijalankan secara paralel, yang harus dipastikan membagi habis d_model.
  2. head_dim: Dimensi setiap head.
  3. dropout_rate: Untuk mencegah overfitting.

Kesimpulan

Kita membahas banyak hal dalam artikel ini. Kita mulai dari gagasan sederhana: attention adalah soal fokus. Lalu, kita mengeksplorasi bagaimana Transformer menggunakan fokus ini dengan menghitung bagaimana setiap kata berhubungan dengan kata lainnya menggunakan Query, Key, dan Value.

Kita melihat bagaimana self-attention (dan secara singkat jenis Attention lain seperti Causal dan Cross Attention) memberi setiap token representasi yang kaya dan peka konteks. Lalu kita melangkah lebih jauh dengan multi-head attention, di mana alih-alih mengandalkan hanya satu "senter", kita memberi model beberapa senter, masing-masing menangkap pola berbeda dalam kalimat, secara bersamaan.

Inilah yang memberi Transformer kekuatan sebenarnya. Mereka tidak sekadar membaca; mereka memahami struktur, makna, dan hubungan yang mendasari di seluruh urutan. 

Sekarang, dalam artikel ini, kita telah membahas satu aspek dari Transformer, tetapi masih banyak yang bisa dipelajari, jadi lihat kursus lengkap dan mendetail ini: Kursus Transformer Models with PyTorch. 

Jika Anda ingin langsung ke sisi aplikasi, saya juga merekomendasikan proyek Developing Multi-Input Models For OCR atau kursus Working with HuggingFace. Jika Anda lebih menyukai artikel, lihat Panduan Lengkap Membangun Model Transformer dengan PyTorch dan panduan saya yang lain tentang Vision Transformer. 

Multi-Head Attention FAQs

Bagaimana multi-head attention meningkatkan kinerja Transformer?

Dengan menjalankan beberapa head attention yang lebih kecil secara paralel, model dapat menangkap pola berbeda (seperti sintaksis, posisi, dll.) secara bersamaan, meningkatkan akurasi dan stabilitas.

Apa fungsi query, key, dan value?

Secara sederhana, query bertanya “apa yang saya cari?”, key mengatakan “apa yang saya tawarkan?”, dan value membawa informasi yang dicampurkan menggunakan bobot attention.

Single-head vs multi-head—apa bedanya?

Single-head menggunakan satu proyeksi sedangkan multi-head membagi dimensi model menjadi subruang h (yaitu jumlah Head), melakukan attention secara independen pada masing-masing, lalu menggabungkan dan memproyeksikannya kembali.

Berapa banyak head yang sebaiknya kita gunakan?

Terserah kita! Anda hanya perlu memastikan dimensi embedding dapat dibagi habis oleh h - jumlah Head. Beberapa pilihan umum adalah kelipatan 2, tetapi ingat bahwa semakin banyak head meningkatkan komputasi dan memori.

Di mana multi-head attention digunakan?

Ini adalah blok bangunan inti dari model fondasi modern seperti di NLP (penerjemahan, QA, peringkasan), visi (ViT), dan suara (ASR, Conformer).

Vaibhav Mehra

Penulis

Vaibhav Mehra

Topik

Terkait

blogs

Tutorial Korelasi di R

blogs

Spaghetti Plot dan Jalur Badai