Penjelasan Cara Kerja Transformer: Memahami Matematika di Baliknya
(osanseviero.github.io)- Menyederhanakan proses inferensi transformer dengan contoh terjemahan Hello World → Hola Mundo, sehingga dapat diikuti secara manual dari tokenisasi hingga encoder, decoder, dan perhitungan probabilitas token berikutnya
- Alih-alih konfigurasi besar dari makalah asli, contoh ini memakai embedding 4 dimensi, 2 attention head, dan feedforward layer 8 dimensi agar alur perkalian matriks dan softmax tetap kecil
- Encoder menambahkan positional encoding ke token embedding, lalu melewati multi-head self-attention dan feedforward layer untuk membuat representasi kontekstual dari urutan input
- Decoder dimulai dari
SOS, menggunakan token yang sudah dihasilkan sebelumnya bersama output encoder; pada encoder-decoder attention, query dihitung dari decoder, sedangkan key/value dari output encoder - Embedding decoder terakhir melewati linear layer dan softmax untuk menjadi probabilitas token berikutnya, tetapi karena contoh memakai bobot acak, kualitas terjemahan nyata tidak diharapkan
Tujuan dan prasyarat
- Memeriksa lewat contoh end-to-end bagaimana matematika saat inferensi berjalan di dalam model transformer
- Ukuran model diperkecil secara signifikan agar perhitungannya mudah diikuti secara manual
- Alih-alih dimensi embedding 512 pada makalah asli, contoh ini memakai 4 dimensi
- Alih-alih 8 attention head pada makalah asli, contoh ini memakai 2 head
- Alih-alih dimensi feedforward 2048 pada makalah asli, contoh ini memakai 8 dimensi
- Prasyarat yang dibutuhkan adalah aljabar linear dasar, dan sebagian besar perhitungan dilakukan lewat perkalian matriks
- Fokusnya bukan pada “apa itu” transformer, melainkan bagaimana perhitungan nyatanya berjalan
- Penjelasan intuitif enak dibaca bersama The Illustrated Transformer, dan makalah aslinya adalah Attention is all you need
Membuat input encoder
-
Tokenisasi
- Karena model machine learning memproses angka, bukan teks, teks input diubah menjadi token ID
- Untuk menyederhanakan, contoh ini membagi
"Hello World"menjadi dua token kata, yaitu"Hello"dan"World" - Metode tokenisasi nyata dapat dibagi menjadi berbasis kata, berbasis karakter, dan berbasis subword
- Tokenisasi berbasis kata membutuhkan vocabulary besar dan memperlakukan
"dog"serta"dogs"sebagai token yang berbeda - Tokenisasi berbasis karakter memiliki vocabulary kecil, tetapi bisa memiliki informasi makna yang lebih sedikit
- Tokenisasi subword berada di tengah antara pendekatan kata dan karakter, dan tokenizer dilatih melalui proses statistik
-
Token embedding
- Karena token ID itu sendiri tidak memiliki makna, tiap token diubah menjadi embedding, yaitu vektor berukuran tetap
- Embedding contoh memakai nilai acak
Hello -> [1, 2, 3, 4]World -> [2, 3, 4, 5]
- Pada transformer nyata, pemetaan embedding juga dipelajari, sehingga model belajar representasi token yang sesuai dengan tugas
- Kedua embedding digabung menjadi satu matriks dan digunakan dalam perkalian matriks berikutnya
-
Positional encoding
- Embedding saja tidak memberi tahu posisi kata di dalam kalimat, sehingga positional encoding ditambahkan
- Makalah asli memakai positional encoding sine/cosine yang tetap, dan contoh ini mengikuti metode yang sama
- Positional encoding pada contoh dihitung sebagai berikut
Hello -> [0, 1, 0, 1]World -> [0.84, 0.99, 0, 1]
- Token embedding dan positional encoding dijumlahkan untuk membuat matriks input encoder
Hello -> [1, 3, 3, 5]World -> [2.84, 3.99, 4, 6]
Perhitungan self-attention
-
Membuat Q, K, V
- Self-attention menghitung query(Q), key(K), dan value(V) dari embedding input
- Contoh ini memakai 2 attention head, dan tiap head memiliki matriks
WQ,WK,WVtersendiri - Tiap matriks bobot mengubah embedding 4 dimensi menjadi query/key/value 3 dimensi
- Pada head pertama, matriks input dikalikan dengan
WK1,WV1, danWQ1untuk mendapatkanK1,V1, danQ1
-
Rumus attention
- Skor attention dihitung dalam empat langkah
- Menghitung dot product antara query dan tiap key
- Membaginya dengan akar kuadrat dimensi key
- Mengubahnya dengan softmax menjadi bobot yang positif dan jumlahnya 1
- Menghitung weighted sum atas vektor value menggunakan bobot tersebut
- Proses ini diringkas oleh rumus dari makalah asli
- [
- Attention(Q,K,V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d}}\right)V
- ]
- Dalam contoh, karena dimensinya kecil dan nilai awalnya acak, hasil softmax hampir condong ke 0 dan 1
- Nilai dot product yang besar dapat diperkuat lebih tajam oleh softmax, sehingga diperlukan scaling dengan membagi akar kuadrat dimensi key
- Untuk penjelasan, contoh juga sementara memakai variasi pembagian dengan 30 alih-alih
sqrt(3), tetapi itu bukan solusi jangka panjang
- Skor attention dihitung dalam empat langkah
-
Output multi-head attention
- Hasil attention dari tiap head di-concatenate, lalu dikalikan dengan matriks bobot yang dipelajari untuk dikembalikan ke dimensi embedding
- Dalam contoh, hasil dua head digabung menjadi matriks 6 dimensi, lalu diubah menjadi output 4 dimensi
- Output ini diteruskan ke tahap berikutnya pada blok encoder, yaitu feedforward layer
Feedforward layer dan blok encoder
-
Feedforward layer
- Setelah self-attention terdapat feedforward neural network (FFN)
- FFN terdiri dari dua transformasi linear dengan aktivasi ReLU di antaranya
- Linear layer pertama memperluas dimensi, dan linear layer kedua mengecilkan dimensi kembali ke ukuran semula
- ReLU membuat nilai negatif menjadi 0 dan mempertahankan nilai positif apa adanya, sehingga menambahkan non-linearitas
- Dalam contoh, input 4 dimensi diperluas menjadi 8 dimensi, lalu diperkecil lagi menjadi 4 dimensi
- [
- \text{FFN}(x) = \text{ReLU}(xW_1 + b_1)W_2 + b_2
- ]
-
Blok encoder
- Satu blok encoder terdiri dari multi-head attention dan FFN
- Makalah asli menumpuk 6 encoder, dan kode contoh juga mengulang encoder dengan
n=6 - Jika beberapa blok encoder dilewati begitu saja, nilainya menjadi terlalu besar sehingga terjadi overflow pada perhitungan softmax dan bisa menghasilkan
nan
Residual connection dan layer normalization
-
Masalah nilai yang melonjak
- Saat contoh melewati 6 encoder, muncul peringatan
overflow encountered in expdaninvalid value encountered in divide, lalu output menjadinan - Fenomena nilai menjadi terlalu besar lalu makin besar di layer berikutnya adalah masalah umum pada deep neural network
- Saat gradient menjadi terlalu besar selama backpropagation, ini disebut gradient explosion
- Saat contoh melewati 6 encoder, muncul peringatan
-
Residual connection
- Residual connection adalah cara menambahkan input layer ke output layer
- [
- \text{Residual}(x) = x + \text{Layer}(x)
- ]
- Dalam contoh, residual connection diterapkan masing-masing pada output attention dan output FFN
- Residual connection digunakan untuk mengurangi masalah vanishing gradient
-
Layer normalization
- Layer normalization menormalkan tiap dimensi embedding agar memiliki rata-rata 0 dan standar deviasi 1
- Rumusnya adalah sebagai berikut
- [
- \text{LayerNorm}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \times \gamma + \beta
- ]
- (\epsilon) adalah nilai kecil untuk menghindari masalah pembagian dengan nol saat standar deviasi bernilai 0
- (\gamma) dan (\beta) adalah parameter terlatih yang mengontrol scaling dan shifting
- Setelah residual connection dan layer normalization ditambahkan, nilai yang normal muncul tanpa
nanmeski melewati 6 encoder
Struktur decoder
-
Input decoder dan cara generasi
- Decoder menerima output encoder dan urutan output yang sudah dihasilkan sejauh ini sebagai input
- Selama inferensi, decoder dimulai dari token SOS(start-of-sequence)
- Decoder menghasilkan satu token setiap kali secara autoregressive
- Iterasi 1: menerima
SOSsebagai input dan menghasilkan"hola" - Iterasi 2: menerima
SOS + holasebagai input dan menghasilkan"mundo" - Iterasi 3: menerima
SOS + hola + mundosebagai input dan menghasilkanEOS
- Iterasi 1: menerima
- Jika token
EOS(end-of-sequence)dihasilkan, decoding berhenti - Encoder dapat membuat representasi dengan satu forward pass, tetapi decoder lebih lambat karena harus melakukan beberapa forward pass
-
Komposisi blok decoder
- Blok decoder lebih kompleks daripada blok encoder dan terdiri dari urutan berikut
- masked self-attention
- residual connection dan layer normalization
- encoder-decoder attention
- residual connection dan layer normalization
- feedforward layer
- residual connection dan layer normalization
- Dalam contoh inferensi, embedding
SOSditambah positional encoding sehingga memakai[1, 1, 0, 1] - Selama pelatihan, digunakan masked self-attention yang memasking attention score menjadi
-infagar token masa depan tidak dapat dilihat
- Blok decoder lebih kompleks daripada blok encoder dan terdiri dari urutan berikut
Encoder-decoder attention
- Encoder-decoder attention adalah tahap yang membuat decoder berfokus pada bagian relevan dari kalimat input
- Cara perhitungannya sama dengan self-attention, tetapi input untuk membuat Q/K/V berbeda
- Query dihitung dari output layer decoder sebelumnya
- Key dan value dihitung dari output encoder
- Struktur ini memungkinkan tiap posisi di decoder merujuk ke semua posisi dalam urutan input
- Ini berguna untuk tugas seperti penerjemahan, ketika token output harus bergantung pada posisi terkait dalam kalimat input
Membuat token output
-
Linear layer dan softmax
- Output decoder belum berupa kata, sehingga embedding terakhir dilewatkan melalui linear layer untuk diubah menjadi vektor logits berukuran vocabulary
- Ukuran vocabulary pada contoh adalah 10, dan kandidat token berikutnya adalah sebagai berikut
hello,mundo,world,how,?,EOS,SOS,a,hola,c
- Logits melewati softmax dan menjadi distribusi probabilitas untuk tiap token
- Dalam probabilitas contoh,
"hola"memiliki probabilitas tertinggi sehingga dipilih sebagai token berikutnya - Cara yang selalu memilih token dengan probabilitas tertinggi disebut greedy decoding, dan tidak selalu yang terbaik
- Teknik generasi dapat dilihat lebih detail dalam artikel Hugging Face
-
Loop generasi lengkap
- Prosedur generasi lengkap mengikuti alur berikut
- Mengubah urutan input menjadi embedding
- Encoder menghasilkan representasi kontekstual dari seluruh input
- Decoder dimulai dari
SOSdan menggunakan token yang sudah dihasilkan sebelumnya bersama output encoder - Menerapkan linear layer dan softmax ke embedding decoder terakhir
- Memilih token berikutnya yang paling mungkin dan menambahkannya ke urutan
- Mengulang sampai
EOSmuncul atau panjang maksimum tercapai
- Eksekusi contoh menghasilkan
SOS hola mundo worlduntuk inputhello world - Karena semua bobot dan embedding memakai nilai acak, hasilnya bukan terjemahan yang baik, dan ini adalah perilaku yang diharapkan
- Prosedur generasi lengkap mengikuti alur berikut
Kesimpulan dan cakupan
- Contoh ini menghubungkan komponen inti transformer—embedding, positional encoding, self-attention, multi-head attention, FFN, residual connection, layer normalization, encoder-decoder attention, dan output softmax—dalam satu alur
- Arsitektur transformer modern menambahkan berbagai teknik, tetapi matematika intinya didasarkan pada struktur yang dibahas dalam contoh ini
- Stack yang digunakan dapat berbeda tergantung jenis tugas
- Tugas berfokus pemahaman seperti klasifikasi dapat menaruh linear layer di atas stack encoder
- Tugas berfokus generasi seperti penerjemahan dapat memakai stack encoder dan decoder bersama-sama
- Tugas generasi bebas seperti ChatGPT atau Mistral dapat memakai stack decoder saja
- Proses pelatihan tidak dibahas; fokusnya adalah memahami matematika inferensi saat memakai model yang sudah ada
- Untuk materi matematika yang lebih formal, lihat PDF ini
1 komentar
Komentar Hacker News
“Misteri” Transformer terletak pada fakta bahwa alih-alih mengalikan bobot statis dan nilai dalam urutan linear di setiap lapisan, ia membuat 3 matriks yang diperoleh dengan mengalikan bobot terlatih pada input yang sama, lalu mengalikan matriks-matriks itu satu sama lain
Ini meningkatkan paralelisme sehingga bekerja dengan baik, tetapi rumus attention itu sendiri tetap sehingga sangat terbatas
Untuk berkembang lebih jauh, tampaknya diperlukan cara untuk menggeneralisasi grafik komputasi itu sendiri menjadi parameter yang dapat dipelajari. Saya tidak tahu apakah itu mungkin dengan metode gradien tradisional karena efek chaos, di mana perubahan kecil dapat menghasilkan perubahan besar pada performa; mungkin secara internal dibutuhkan sesuatu seperti algoritma genetika atau particle swarm optimization
Dibandingkan RNN, keunggulan teoretis besarnya adalah ia mendukung ini tanpa kehilangan informasi. Ini karena setiap elemen dapat mengakses seluruh informasi dari semua elemen lain dalam urutan, atau semua elemen sebelumnya dalam urutan waktu
Sebaliknya, RNN dan “linear Transformer” memampatkan nilai masa lalu, sehingga elemen terakhir dalam urutan panjang biasanya sulit mengakses seluruh informasi dari elemen pertama, dan itu tidak mungkin kecuali state internalnya sangat besar sehingga tidak ada informasi yang dibuang
Masalahnya, tidak banyak yang didapat dari sini. Operasi selain perkalian matriks kemungkinan lebih lambat atau kurang lebih sama cepatnya
Hanya saja, jika kontrol alur ditambahkan, ada risiko itu pada dasarnya menjadi Turing machine, dan kalau begitu pembelajaran memang menjadi masalah seperti yang disebutkan. Namun tetap saja, mungkin ini bukan masalah yang sepenuhnya tak bisa ditangani
Jika ingin penjelasan yang lebih kering, formal, dan ringkas, ada “The Transformer Model in Equations” karya John Thickstun [0]
Seluruhnya muat dalam satu halaman dengan notasi matematika standar
[0] https://johnthickstun.com/docs/transformers.pdf
Para peneliti machine learning sering terlihat seolah sama sekali tidak pernah belajar matematika
Penjelasan “NaN muncul, nilainya terlalu besar lalu meledak saat diteruskan ke encoder berikutnya, inilah exploding gradient” menurut pemahaman saya keliru
Di sini gradien tidak dihitung pada titik mana pun, jadi ini bukan exploding gradient
Masalahnya tampak berada di implementasi softmax, dan cara mengimplementasikan softmax yang stabil secara numerik dijelaskan di sini [0]
[0]: https://jaykmody.com/blog/stable-softmax/
Meski begitu, seluruh jaringan saraf sensitif terhadap nilai besar, jadi softmax yang stabil secara numerik saja tidak cukup untuk menyelesaikannya. Agar jaringan berfungsi, normalisasi adalah kuncinya
Tutorial Transformer mungkin akan menjadi tutorial Monad yang baru. Ini konsep yang sulit dipahami, tetapi termasuk jenis hal yang baru benar-benar dimengerti setelah bergulat dengan contoh-contohnya
Seperti banyak hal lain dalam ilmu komputer
Saya baru membaca enam paragraf dan sudah punya pertanyaan
Pada
Hello -> [1,2,3,4] World -> [2,3,4,5], vektornya memang disebut acak, tetapi tampak ada pola. Saya penasaran apakah2yang muncul di kedua vektor itu berarti sesuatu, atau justru keseluruhan himpunan nilainya yang menciptakan keunikanDi sini jaraknya sekitar 60 derajat dan arahnya agak sama, tetapi karena contoh ini menghindari angka negatif, vektornya jadi terlihat lebih mirip daripada yang sebenarnya
Fakta bahwa angkanya dipakai ulang itu sendiri tidak berarti apa-apa.
1pada posisi pertama hampir tidak ada hubungannya dengan1pada posisi kedua. Lagi pula kita juga tidak melakukan konvolusi pada vektor iniSetelah pelatihan, kata-kata yang mirip memang akan memiliki tingkat kemiripan kosinus tertentu, tetapi hampir tidak pernah mencapai kemiripan kosinus setinggi
[1,2,3,4]dan[2,3,4,5]Ini memang tidak sepenuhnya pertanyaan yang terkait langsung, tetapi saya sedang mencari tulisan atau makalah yang membahas mengapa Transformer, meskipun bekerja seperti “prediktor token berikutnya”, tetap bisa menangani pertanyaan seperti berikut
"sdsfs_ff","fsdf_value"Rasanya ini pasti pertanyaan yang umum, tetapi saya tidak tahu kata kunci pencarian yang tepat. Akan bagus juga kalau ada tautan yang membahas positional embedding secara mendalam; saya juga masih belum mendapatkan jawaban yang memuaskan tentang alasan memakai sinus/cosinus dan tentang perkalian vs penjumlahan
Jika model menilai itu perlu, ia bisa mereproduksi urutan tak dikenal dengan menyalin token karakter tunggal, atau menciptakannya jika masuk akal dalam konteks
P(X_1=x_1, X_2=x_2, X_3=x_3) = P(X_3=x_3 | X_1=X_1, X_2=x_2) • P(X_1=x_1, X_2=x_2)= P(X_3=x_3 | X_1=X_1, X_2=x_2) • P(X_2=x_2 | X_1=x_1) • P(X_1=x_1)Artinya, jika ada distribusi probabilitas bersyarat yang benar untuk token berikutnya ketika token-token sebelumnya diberikan, maka distribusi probabilitas yang benar untuk seluruh urutan token juga dapat dibentuk
“Distribusi probabilitas yang benar untuk urutan token”, atau distribusi probabilitas bersyarat yang benar untuk urutan token di bawah kondisi tertentu, pada praktiknya bisa dipakai untuk menjelaskan hampir semua jenis perilaku input/output dengan istilah seperti itu
Jadi, mengatakan bahwa model “bekerja dengan memprediksi token berikutnya” pada dasarnya bukanlah batasan besar atas jenis perilaku input/output yang bisa dilakukan
Betapapun mengesankannya suatu hal yang dilakukan, itu tidak bertentangan dengan fakta bahwa keluaran tersebut berasal dari
P(X_{n+1}=x_{n+1} | X_1=x_1, ..., X_n=x_n), yakni “prediksi token berikutnya”Prediksi token berikutnya adalah tugas yang lebih cerdas daripada yang terdengar
Saya setuju dengan pernyataan bahwa “kompleksitas datang dari jumlah langkah dan jumlah parameter”
Model Transformer yang cukup sederhana untuk kita pahami tidak bisa melakukan hal yang menarik, dan Transformer yang cukup kompleks untuk melakukan hal yang menarik tampak terlalu rumit untuk kita pahami
Saya ingin meneliti model skala menengah yang cukup sederhana untuk dipahami, tetapi juga cukup kompleks untuk melakukan hal yang menarik
Sulit dipahami jika istilah digunakan tanpa didefinisikan atau diperkenalkan. Bagian Encoder langsung dimulai tanpa menjelaskan apa itu, atau di mana posisinya dalam keseluruhan proses
Saya paham apa yang ingin dilakukan penulis, tetapi struktur dasar tulisan—memperkenalkan ide terlebih dahulu, menjelaskannya, lalu menggunakannya—tidak ada
Jika bukan orang yang sudah sedang mempelajari topik ini dan sudah memahami setengahnya, seluruh tulisan terasa membingungkan
Saya pernah menulis ANN dari nol dan tidak memakai TensorFlow, tetapi penjelasan ini masih tetap membingungkan
Saya meminta ChatGPT menjelaskan bagaimana mengubah ANN dasar agar mengimplementasikan self-attention tanpa menggunakan istilah
MatrixatauVector, dan ternyata penjelasannya cukup sederhana. Saya sendiri belum mencoba mengimplementasikannyaSaya lebih suka memikirkan semuanya dari sudut pandang node, bobot, dan lapisan. Matriks dan vektor membuatnya lebih sulit dihubungkan dengan apa yang benar-benar terjadi di dalam ANN
Dalam cara penulisan ANN yang saya kenal, setiap node input adalah skalar, tetapi algoritme feedforward mengalikan bobot ke semua node input lalu menjumlahkannya, sehingga terlihat seperti perkalian vektor-matriks. Rasanya saya mendekati penjelasan-penjelasan ini dengan kerangka pikir yang keliru, dan mungkin memang kurang punya pengetahuan latar yang diperlukan