β˜€οΈSiang
AI & Data Science

Transformer & Attention Mechanism

TOKEN Lanjut

Tutorial lengkap Transformer β€” self-attention, multi-head attention, positional encoding, encoder-decoder, BERT, GPT, dan implementasi PyTorch

Artikel: Dl Transformer Attention Artikel: Dl Transformer Attention


1. Pengenalan Transformer

Transformer adalah arsitektur deep learning yang diperkenalkan oleh Vaswani et al. dalam makalah bersejarah "Attention Is All You Need" (2017) dari Google. Arsitektur ini menggantikan RNN/LSTM sepenuhnya untuk tugas NLP, dan kini menjadi fondasi dari hampir semua model AI modern β€” dari BERT hingga ChatGPT, dari DALL-E hingga AlphaFold.

Kunci revolusioner Transformer adalah Attention Mechanism β€” mekanisme yang memungkinkan model "melihat" semua token dalam sequence sekaligus (paralel) dan menentukan mana yang paling relevan untuk setiap posisi, tanpa harus memproses secara berurutan seperti RNN.

Mengapa Transformer Menggantikan RNN?

Diagram: RNN vs Transformer
RNN vs Transformer

Transformer (Parallel)

t=1

t=2

t=3

t=4

βœ… Parallel processing\nO(1) parallel steps

RNN (Sequential)

t=1

t=2

t=3

t=4

⚠️ Sequential processing\nO(n) sequential steps

Dampak Transformer

Bidang Model Transformer Pencapaian
NLPBERT, GPT-4, LLaMA, GeminiHuman-level text understanding & generation
Computer VisionViT, DeiT, Swin TransformerMenggantikan CNN di banyak task
AudioWhisper, MusicLMSpeech recognition & music generation
Generative AIDALL-E 3, Stable Diffusion, SoraImage & video generation dari text
ProteinAlphaFold 2Protein structure prediction β†’ Nobel Prize!
CodeGitHub Copilot, CodeLlamaAI-assisted programming
RoboticsRT-2, GatoMulti-modal robot control


2. Konsep Attention

Bayangkan kamu membaca kalimat: "Kucing itu duduk di atas tikar karena ia merasa lelah." Kata "ia" merujuk pada "kucing". Attention adalah mekanisme yang memungkinkan model mengetahui bahwa kata "ia" sangat berkaitan dengan "kucing" β€” bahkan jika keduanya berjauhan dalam kalimat.

Attention dalam Kehidupan Sehari-hari

Diagram: Attention Weight Visualization
/"Kalimat: 'Kucing itu duduk di atas tikar karena..."/
/"Attention weight dari kata 'ia':"/
/"Kata: Kucing itu duduk di atas tikar karena ia ..."/
/"Weight: 0.65 0.02 0.05 0.01 0.02 0.03 0.04 0.02..."/
/"Paling tinggi!"/
/"Visualisasi (garis tebal = attention tinggi):"/
/"'Kucing'"/
/"'itu'"/
/"'duduk'"/
'di'
/"'atas'"/
/"'tikar'"/
/"'karena'"/
'ia'
/"'merasa'"/
/"'lelah'"/
/"Model 'tahu' bahwa 'ia' merujuk ke 'Kucing'"/

Evolusi Attention

Era Mekanisme Penjelasan
2014Seq2Seq + Attention (Bahdanau)Attention ditambahkan pada encoder-decoder RNN. Decoder "melihat" encoder hidden states
2016Self-Attention (Lin et al.)Token dalam satu sequence saling "melihat" satu sama lain
2017Multi-Head Self-Attention (Transformer)Multiple attention heads bekerja paralel. Tanpa RNN!
2018+Sparse Attention, Linear AttentionEfisiensi: O(nΒ²) β†’ O(n log n) atau O(n)


3. Self-Attention Mechanism

Self-Attention adalah mekanisme di mana setiap token dalam sequence menghitung skor relevansi dengan semua token lainnya dalam sequence yang sama β€” termasuk dirinya sendiri. Ini berbeda dari attention biasa (cross-attention) di mana satu sequence attend ke sequence lain.

Query, Key, Value (Q, K, V)

Untuk setiap token, kita buat 3 vektor: Query (Q), Key (K), dan Value (V).

Diagram: Scaled Dot-Product Attention
Scaled Dot-Product Attention

Query (Q)

MatMul

Key (K)

Scale (÷√dk)

Softmax

MatMul

Value (V)

Output

Mengapa Scaling (√d_k)?

Tanpa scaling, jika dimensi d_k besar, dot product QΒ·K bisa bernilai sangat besar. Softmax pada nilai sangat besar menghasilkan distribusi yang sangat "tajam" (satu posisi mendapat hampir semua bobot, yang lain ~0). Ini menyebabkan gradient yang sangat kecil dan training lambat.

πŸ“ Formula Scaled Dot-Product Attention

Attention(Q, K, V) = softmax(Q Γ— Kα΅€ / √d_k) Γ— V

di mana d_k = dimensi key vector. Scaling factor √d_k menjaga agar variance tetap ~1.



4. Multi-Head Attention

Alih-alih melakukan satu attention computation, Multi-Head Attention melakukan h attention computations secara paralel (biasanya h = 8 atau 12), masing-masing dengan proyeksi Q, K, V yang berbeda. Hasilnya digabungkan dan diproyeksikan lagi.

Mengapa Multi-Head?

Diagram: Multi-Head Attention
Multi-Head Attention

Input (X)

Split into h heads

Head 1\n(Q₁,K₁,V₁)

Head 2\n(Qβ‚‚,Kβ‚‚,Vβ‚‚)

Head h\n(Qβ‚•,Kβ‚•,Vβ‚•)

Attention₁

Attentionβ‚‚

Attentionβ‚•

Concat

Linear Projection

Output



5. Positional Encoding

Berbeda dengan RNN yang secara alami menangkap urutan (memproses satu per satu), Transformer memproses semua token secara paralel. Tanpa informasi posisi, model tidak bisa membedakan "Anjing menggigit kucing" dari "Kucing menggigit anjing" β€” padahal maknanya sangat berbeda!

Sinusoidal Positional Encoding

Transformer asli menggunakan fungsi sin dan cos dengan frekuensi berbeda:

  • PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
  • PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
Diagram

DECODER

Cross-Attention

ENCODER

Input Embedding\n+ Positional Encoding

Multi-Head\nSelf-Attention

Feed-Forward\nNetwork

Output Embedding\n+ Positional Encoding

Masked Multi-Head\nSelf-Attention

Cross-Attention\n(from Encoder)

Feed-Forward\nNetwork

Linear + Softmax

Output Probabilities

Komponen Kunci

Komponen Fungsi Dimensi (d_model=512)
Input EmbeddingToken β†’ dense vector(batch, seq_len, 512)
Positional EncodingTambah info urutan posisi(seq_len, 512)
Multi-Head Self-AttentionSetiap token attend ke semua token8 heads Γ— 64 dim
Layer NormalizationNormalisasi aktivasi (stabilkan training)(batch, seq_len, 512)
Feed-Forward NetworkTransformasi non-linear per posisi512 β†’ 2048 β†’ 512
Residual ConnectionSkip connection: x + Sublayer(x)(batch, seq_len, 512)


7. BERT: Encoder-Only

BERT (Bidirectional Encoder Representations from Transformers) diperkenalkan oleh Google pada tahun 2018. BERT menggunakan arsitektur encoder-only dari Transformer dan dilatih dengan dua teknik pre-training yang inovatif.

Pre-training Tasks

Diagram: BERT Pre-training Tasks
BERT Pre-training Tasks

NEXT SENTENCE PREDICTION

Sentence A: The cat sat down

Sentence B: It was a sunny day

Is B the next\nsentence?

MASKED LANGUAGE MODEL

The [MASK] sat on\nthe [MASK]

Predict: cat, mat

Python β€” BERT dengan Hugging Face
from transformers import BertTokenizer, BertModel, BertForSequenceClassification
import torch

# =============================================
# 1. LOAD PRE-TRAINED BERT
# =============================================
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')

print(f"Model: BERT-base-uncased")
print(f"Parameters: {sum(p.numel() for p in model.parameters()):,}")
print(f"Vocabulary size: {tokenizer.vocab_size:,}")
print(f"Max position: {model.config.max_position_embeddings}")

# =============================================
# 2. TOKENIZATION
# =============================================
text = "Transformer is a revolutionary architecture in NLP."
tokens = tokenizer(text, return_tensors='pt', padding=True, truncation=True)

print(f"\nOriginal text: {text}")
print(f"Token IDs: {tokens['input_ids']}")
print(f"Tokens: {tokenizer.convert_ids_to_tokens(tokens['input_ids'][0])}")
print(f"Attention mask: {tokens['attention_mask']}")

# BERT tokenization menggunakan WordPiece:
# "revolutionary" β†’ ["revolution", "##ary"]
# "#" = subword continuation token

# =============================================
# 3. GET EMBEDDINGS
# =============================================
with torch.no_grad():
    outputs = model(**tokens)

# outputs.last_hidden_state: (batch, seq_len, hidden_size=768)
# outputs.pooler_output: (batch, hidden_size=768) β€” [CLS] token

print(f"\nLast hidden state shape: {outputs.last_hidden_state.shape}")
print(f"Pooler output (CLS) shape: {outputs.pooler_output.shape}")

# =============================================
# 4. FINE-TUNE UNTUK SENTIMENT ANALYSIS
# =============================================
from transformers import BertForSequenceClassification
import torch.nn as nn

# Load BERT untuk klasifikasi (2 labels: positive/negative)
model_clf = BertForSequenceClassification.from_pretrained(
    'bert-base-uncased',
    num_labels=2
)

# Fine-tuning example
texts = ["This movie is amazing!", "I hated this film."]
labels = torch.tensor([1, 0])  # 1=positive, 0=negative

inputs = tokenizer(texts, return_tensors='pt', padding=True, truncation=True)
outputs = model_clf(**inputs, labels=labels)

print(f"\nFine-tuning Loss: {outputs.loss.item():.4f}")
print(f"Logits shape: {outputs.logits.shape}")

# Prediction
predictions = torch.softmax(outputs.logits, dim=1)
print(f"Predictions: {predictions}")
# [positive_prob, negative_prob] untuk setiap teks


8. GPT: Decoder-Only

GPT (Generative Pre-trained Transformer) oleh OpenAI menggunakan arsitektur decoder-only dari Transformer. Berbeda dengan BERT yang bersifat bidirectional, GPT bersifat autoregressive β€” memprediksi token berikutnya berdasarkan token sebelumnya.

Perbedaan BERT vs GPT

Aspek BERT GPT
ArsitekturEncoder-onlyDecoder-only
DirectionBidirectional (melihat ke depan & belakang)Unidirectional (hanya ke belakang)
Pre-trainingMLM + NSPNext Token Prediction
MaskingRandom mask (15% token)Causal mask (token masa depan tersembunyi)
Terbaik untukUnderstanding (klasifikasi, NER, QA)Generation (teks, kode, cerita)
Fine-tuningTask-specific headIn-context learning (prompt) + RLHF
ContohBERT, RoBERTa, DeBERTaGPT-4, LLaMA, Mistral, PaLM

Evolusi GPT

Diagram: Evolusi GPT Model

Evolusi Model GPT (OpenAI):

GPT-1 (2018):
  β€’ 117M parameters, 12 layers
  β€’ Pre-training + fine-tuning paradigm
  β€’ Menunjukkan zero-shot capability

GPT-2 (2019):
  β€’ 1.5B parameters, 48 layers
  β€’ "Too dangerous to release"
  β€’ Multi-task tanpa fine-tuning

GPT-3 (2020):
  β€’ 175B parameters, 96 layers
  β€’ In-context learning: few-shot, one-shot, zero-shot
  β€’ Muncul prompt engineering
  β€’ Biaya training: ~$4.6 juta

GPT-3.5 / ChatGPT (2022):
  β€’ Fine-tuned dengan RLHF (Reinforcement Learning from Human Feedback)
  β€’ Conversational AI yang viral
  β€’ 100 juta user dalam 2 bulan!

GPT-4 (2023):
  β€’ Multi-modal (text + image input)
  β€’ Massive improvement in reasoning
  β€’ M4 architecture (rumored mixture of experts)

GPT-4o (2024):
  β€’ Omni-modal (text, image, audio, video)
  β€’ Real-time voice conversation
  β€’ Faster & cheaper

Emergent Abilities (muncul pada scale besar):
  β€’ Chain-of-thought reasoning
  β€’ Code generation
  β€’ Mathematical reasoning
  β€’ In-context learning
  β€’ Instruction following


9. Implementasi Self-Attention PyTorch

Python β€” Multi-Head Self-Attention dari Nol
import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class ScaledDotProductAttention(nn.Module):
    """Scaled Dot-Product Attention."""
    def __init__(self, d_k):
        super().__init__()
        self.d_k = d_k
    
    def forward(self, Q, K, V, mask=None):
        # Q, K, V shape: (batch, heads, seq_len, d_k)
        
        # Step 1: Hitung attention scores
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        # scores shape: (batch, heads, seq_len, seq_len)
        
        # Step 2: Apply mask (untuk decoder - cegah melihat masa depan)
        if mask is not None:
            scores = scores.masked_fill(mask == 0, float('-inf'))
        
        # Step 3: Softmax
        attn_weights = F.softmax(scores, dim=-1)
        
        # Step 4: Weighted sum
        output = torch.matmul(attn_weights, V)
        # output shape: (batch, heads, seq_len, d_k)
        
        return output, attn_weights


class MultiHeadAttention(nn.Module):
    """Multi-Head Attention."""
    def __init__(self, d_model, n_heads):
        super().__init__()
        assert d_model % n_heads == 0
        
        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads  # dimensi per head
        
        # Linear projections
        self.W_q = nn.Linear(d_model, d_model)  # Query projection
        self.W_k = nn.Linear(d_model, d_model)  # Key projection
        self.W_v = nn.Linear(d_model, d_model)  # Value projection
        self.W_o = nn.Linear(d_model, d_model)  # Output projection
        
        self.attention = ScaledDotProductAttention(self.d_k)
    
    def forward(self, Q, K, V, mask=None):
        batch_size = Q.size(0)
        
        # 1. Linear projection
        Q = self.W_q(Q)  # (batch, seq_len, d_model)
        K = self.W_k(K)
        V = self.W_v(V)
        
        # 2. Split into multiple heads
        # (batch, seq_len, d_model) β†’ (batch, n_heads, seq_len, d_k)
        Q = Q.view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        K = K.view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        V = V.view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        
        # 3. Scaled dot-product attention
        output, attn_weights = self.attention(Q, K, V, mask)
        
        # 4. Concatenate heads
        # (batch, n_heads, seq_len, d_k) β†’ (batch, seq_len, d_model)
        output = output.transpose(1, 2).contiguous().view(
            batch_size, -1, self.d_model
        )
        
        # 5. Final linear projection
        output = self.W_o(output)
        
        return output, attn_weights


class TransformerBlock(nn.Module):
    """Single Transformer Encoder Block."""
    def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
        super().__init__()
        
        # Multi-Head Self-Attention
        self.attention = MultiHeadAttention(d_model, n_heads)
        
        # Feed-Forward Network
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model)
        )
        
        # Layer Normalization
        self.ln1 = nn.LayerNorm(d_model)
        self.ln2 = nn.LayerNorm(d_model)
        
        # Dropout
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # 1. Self-Attention + Residual + LayerNorm
        attn_out, attn_weights = self.attention(x, x, x, mask)
        x = self.ln1(x + self.dropout(attn_out))
        
        # 2. FFN + Residual + LayerNorm
        ffn_out = self.ffn(x)
        x = self.ln2(x + self.dropout(ffn_out))
        
        return x, attn_weights


# =============================================
# TEST: Jalankan Multi-Head Attention
# =============================================
print("=" * 60)
print("TESTING MULTI-HEAD SELF-ATTENTION")
print("=" * 60)

# Hyperparameters
d_model = 512
n_heads = 8
d_ff = 2048
seq_len = 10
batch_size = 2

# Create model
block = TransformerBlock(d_model, n_heads, d_ff)

# Random input (simulating token embeddings)
x = torch.randn(batch_size, seq_len, d_model)

# Forward pass
output, attn_weights = block(x)

print(f"Input shape: {x.shape}")             # (2, 10, 512)
print(f"Output shape: {output.shape}")        # (2, 10, 512)
print(f"Attention weights shape: {attn_weights.shape}")  # (2, 8, 10, 10)

# Attention weight visualization
print(f"\nAttention weights (Head 0, Sample 0):")
print(f"Shape: {attn_weights[0, 0].shape} (seq_len Γ— seq_len)")
print(f"Row sum: {attn_weights[0, 0].sum(dim=-1).tolist()}")  # β‰ˆ 1.0 per row

# Parameter count
params = sum(p.numel() for p in block.parameters())
print(f"\nParameters in Transformer block: {params:,}")

# Multi-head attention shapes summary
print("\n=== Shape Summary ===")
print(f"d_model = {d_model}")
print(f"n_heads = {n_heads}")
print(f"d_k = d_v = {d_model // n_heads}")
print(f"Q, K, V per head: ({seq_len}, {d_model // n_heads})")
print(f"Attention matrix: ({seq_len}, {seq_len})")
print(f"Output per head: ({seq_len}, {d_model // n_heads})")
print(f"Concat output: ({seq_len}, {d_model})")


10. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Transformer & Attention:

Pertanyaan 1: Apa yang dimaksud dengan "Self-Attention"?

a) Model memperhatikan input dari pengguna
b) Setiap token dalam sequence attend ke semua token lain dalam sequence yang sama
c) Model hanya fokus pada token pertama
d) Decoder attend ke encoder output

Pertanyaan 2: Mengapa Transformer menggunakan Positional Encoding?

a) Untuk mempercepat training
b) Untuk mengurangi jumlah parameter
c) Karena Transformer memproses semua token paralel dan tidak tahu urutan
d) Untuk memungkinkan multi-head attention

Pertanyaan 3: BERT menggunakan arsitektur...

a) Encoder-Decoder (full Transformer)
b) Encoder-only
c) Decoder-only
d) RNN dengan attention

Pertanyaan 4: Mengapa GPT menggunakan "causal mask" (masked attention)?

a) Agar model lebih cepat saat inference
b) Agar model hanya bisa melihat token sebelumnya (autoregressive)
c) Untuk mengurangi overfitting
d) Agar model bisa menangani bahasa yang berbeda

Pertanyaan 5: Apa fungsi dari scaling factor √d_k dalam Scaled Dot-Product Attention?

a) Membuat model lebih kecil
b) Mencegah dot product terlalu besar yang menyebabkan softmax menghasilkan gradient sangat kecil
c) Mengurangi jumlah parameter
d) Menambah non-linearity pada model
πŸ” Zoom
100%
🎨 Tema