Bài thứ sáu dừng lại ở chỗ một chuỗi token đã trở thành một dãy vector:
Text
-> Tokenization
-> [token_1, token_2, ..., token_n]
-> Embedding
-> [x_1, x_2, ..., x_n]
Nhưng có một vấn đề mà bài đó cố tình để lại: một vector embedding ban đầu chưa đủ để biểu diễn ý nghĩa của token trong ngữ cảnh cụ thể.
Từ bank trong river bank và trong bank account nhận cùng một vector ở cửa vào model, nếu tokenizer sinh ra cùng một token. Nhưng nghĩa của chúng khác hẳn nhau. Model cần một cơ chế để representation của mỗi token thay đổi được theo những token đứng quanh nó.
Đó là việc của Self-Attention.
Nếu embedding trả lời câu hỏi “token này là gì”, thì self-attention trả lời câu hỏi khó hơn: “token này có nghĩa gì trong câu hiện tại, và tôi nên lấy thông tin từ token nào khác để hiểu nó”.
Cả bài đi tới đúng một công thức:
Attention(Q, K, V) = softmax( Q Kᵀ / căn(d_k) ) V
Mục tiêu không phải là thuộc công thức. Mục tiêu là sau khi đọc xong, nhìn vào từng thành phần và nói được nó đang làm gì, vì sao cần nó, và nó nằm ở đâu trong một LLM thật. Sơ đồ ở đầu bài (Hình 1) là toàn bộ chặng đó gói trong một hình.
01Từ embedding đến ngữ cảnh: vì sao cần attention
Lấy một câu quen thuộc trong mọi bài giảng về Transformer:
The animal didn't cross the street because it was tired.
Tokenizer cắt câu thành token, embedding layer biến mỗi token thành một vector. Ở tầng đầu tiên, trước khi các token trao đổi gì với nhau, representation của it chưa chứa thông tin nào nói rằng it có liên quan đến animal.
Việc model cần làm là tạo ra một representation mới cho it bằng cách kết hợp có chọn lọc thông tin từ những token khác trong câu.
Cách đơn giản nhất là lấy trung bình toàn bộ embedding trong câu:
(x_1 + x_2 + ... + x_n) / n
Nhưng như vậy mọi token đều quan trọng như nhau. Trong ngôn ngữ, điều đó gần như không bao giờ đúng.
Cách thứ hai là chỉ nhìn vài token gần nhất. Nhưng quan hệ ngữ nghĩa và cú pháp không phụ thuộc vào khoảng cách. Chủ ngữ có thể cách động từ rất nhiều token. Một đại từ có thể trỏ về danh từ ở đầu đoạn. Một dấu ngoặc mở trong code có thể đóng ở rất xa.
Attention giải quyết chuyện này bằng cách để model học một trọng số riêng cho từng quan hệ giữa hai token:
Embedding ban đầu
-> token chưa biết token nào quan trọng với mình
-> tính mức độ liên quan với từng token khác
-> gán attention weight
-> tổng hợp thông tin theo các weight đó
-> contextualized representation
Ý tưởng “chọn mềm” này xuất hiện trước Transformer, trong neural machine translation. Bahdanau, Cho và Bengio đề xuất để decoder không phải nén cả câu nguồn vào một vector cố định, mà có thể soft-search những phần của câu nguồn liên quan đến từ đang được sinh ra. Transformer sau đó đưa attention lên thành cơ chế trung tâm và bỏ hẳn recurrence khỏi đường xử lý chính.
Một điểm cần phân biệt ngay từ đầu. Ở layer đầu tiên, input là token embedding cộng thông tin vị trí. Ở các layer sâu hơn, input của self-attention đã là hidden state có ngữ cảnh từ những layer trước. Vì vậy đừng hiểu rằng mọi self-attention layer đều nhận “embedding chưa có ngữ cảnh”. Đúng hơn: mỗi layer tiếp tục tinh chỉnh representation bằng cách cho các vị trí trao đổi thêm thông tin.
02Attention thực chất là một phép tra cứu mềm
Cách dễ hiểu nhất để nhìn attention là coi nó như một hệ thống tra cứu dựa trên Query - Key - Value.
Tưởng tượng một database:
Key Value
-------------------------------------
"animal" thông tin về animal
"street" thông tin về street
"tired" thông tin về tired
Có một Query, hệ thống tìm Key nào khớp nhất rồi trả về Value tương ứng.
Attention làm gần như vậy, chỉ khác một chỗ quan trọng: thay vì chọn đúng một Key, nó cho phép Query khớp với nhiều Key ở những mức độ khác nhau.
Ba khái niệm gói gọn trong ba câu hỏi:
- Query (Q): tôi đang tìm loại thông tin gì?
- Key (K): tôi có phù hợp với thứ Query đang tìm không?
- Value (V): nếu tôi được chú ý tới, thông tin nào của tôi sẽ đi sang output?
Điểm quan trọng nhất trong cả phần này: Key và Value có vai trò khác nhau.
Key dùng để quyết định mức độ liên quan. Value là thông tin thực sự được tổng hợp. Đây là lý do attention không đơn giản là “tính similarity giữa các embedding rồi cộng embedding lại”. Model có thể học hai không gian tách biệt - một không gian để khớp và một không gian để truyền thông tin.
Về mặt toán, với một query q, các key k_i và value v_i, output có dạng:
out(q) = tổng theo i của ( alpha_i * v_i )
trong đó alpha_i là attention weight của value thứ i. Token rất liên quan thì alpha_i lớn. Gần như không liên quan thì alpha_i gần 0 - nhưng không bao giờ bị loại hẳn khỏi phép tính.
Đây là lý do có thể gọi attention là một dạng content-addressable retrieval: thay vì truy cập thông tin bằng địa chỉ cố định, model truy cập dựa trên nội dung mà Query và Key biểu diễn.
03Attention, Self-Attention và Cross-Attention
“Attention” là tên của cơ chế tổng quát. Self-Attention và Cross-Attention mô tả nguồn mà Q, K, V được tạo ra - không phải hai cơ chế khác nhau về bản chất.
Với Self-Attention, cùng một input X được chiếu sang ba không gian:
Q = X W_Q
K = X W_K
V = X W_V
Mỗi position trong sequence dùng Query của mình để tìm thông tin từ các Key của chính sequence đó.
Sequence X
|----------> Q
|----------> K
+----------> V
Với Cross-Attention, hai nguồn tách nhau:
Stream A -----> Q
Stream B -----> K
+----> V
Trong Transformer encoder-decoder cổ điển, decoder tạo Query, còn Key và Value đến từ output của encoder. Nhờ đó decoder lấy được thông tin từ câu nguồn khi sinh câu đích.
Trong các decoder-only language model kiểu GPT, cơ chế cốt lõi là causal self-attention: Q, K, V cùng đến từ chuỗi token đang xử lý, nhưng mỗi vị trí bị cấm nhìn những token nằm ở tương lai.
| Cơ chế | Q đến từ | K, V đến từ | Token được phép nhìn |
|---|---|---|---|
| Encoder self-attention | encoder states | encoder states | thường là toàn bộ sequence |
| Decoder causal self-attention | decoder states | decoder states | chỉ hiện tại và quá khứ |
| Cross-attention | decoder / query stream | encoder / memory stream | toàn bộ nguồn được cung cấp |
Bài này tập trung vào self-attention, vì đó là cơ chế nằm trực tiếp trong lõi của các LLM decoder-only hiện đại.
04Q, K, V đến từ đâu
Đây là điểm dễ gây nhầm lẫn nhất trong cả bài.
Q, K và V không phải ba loại embedding được lưu sẵn trong vocabulary. Chúng được tính từ hidden representation bằng những phép chiếu tuyến tính có tham số học được.
Giả sử sequence có n token và mỗi hidden vector có d_model chiều. Gom chúng thành một ma trận X cỡ n × d_model. Model giữ ba ma trận trọng số:
W_Q cỡ d_model × d_k
W_K cỡ d_model × d_k
W_V cỡ d_model × d_v
Sau đó, với từng token x_i:
q_i = x_i W_Q
k_i = x_i W_K
v_i = x_i W_V
Một trực giác hữu ích:
x_i
|
|-- W_Q -> q_i : token i muốn tìm gì?
|
|-- W_K -> k_i : token i được tìm thấy theo tiêu chí nào?
|
+-- W_V -> v_i : nếu token i được chọn, nó gửi thông tin gì?
W_Q, W_K và W_V là learnable parameters. Trong training, gradient descent điều chỉnh chúng sao cho những phép khớp Q-K và những Value được truyền đi trở nên hữu ích cho objective của model.
Không có người lập trình nào quy định rằng:
Q = chủ ngữ
K = động từ
V = ngữ nghĩa
Những representation này được học end-to-end. Đây cũng là lý do không nên diễn giải một attention head quá cứng nhắc theo kiểu “head này luôn làm coreference, head kia luôn làm syntax”. Một số head có thể biểu hiện pattern dễ đọc trên một số input, nhưng vai trò của chúng là emergent và có thể phân tán giữa nhiều head và nhiều layer.
05Scaled Dot-Product Attention, từng bước một
Đây là công thức trung tâm:
Attention(Q, K, V) = softmax( Q Kᵀ / căn(d_k) ) V
Thay vì nhìn cả công thức cùng lúc, hãy tách nó thành một pipeline bốn bước.
5.1 Bước 1 - tính similarity bằng Q Kᵀ
Nếu Q cỡ n × d_k và K cỡ n × d_k, thì Q Kᵀ cỡ n × n. Phần tử ở hàng i, cột j là:
s_ij = q_i · k_j
Nó trả lời đúng một câu hỏi: với Query của token i, Key của token j phù hợp đến mức nào? Tích vô hướng càng lớn thì hai vector càng thẳng hàng theo phép đo mà model đã học.
5.2 Bước 2 - chia cho căn(d_k)
Transformer không dùng q · k trần, mà dùng:
q_i · k_j / căn(d_k)
Tại sao? Giả sử các thành phần của q và k độc lập, trung bình xấp xỉ 0 và phương sai xấp xỉ 1. Khi đó:
q · k = tổng theo r từ 1 đến d_k của ( q_r * k_r )
có phương sai tăng theo d_k. Khi d_k lớn, tích vô hướng dễ có độ lớn rất cao. Đưa những score quá lớn vào softmax làm phân phối trở nên cực đoan - gần như toàn bộ khối lượng dồn vào một ô - và khi đó gradient ở phần lớn vị trí gần bằng 0. Chia cho căn(d_k) giữ thang giá trị ổn định hơn.
Đây không phải một hằng số tuỳ ý. Nó gắn trực tiếp với số chiều của Query và Key.
5.3 Bước 3 - softmax biến score thành weight
Với token i:
alpha_ij = exp(s_ij / căn(d_k)) / tổng theo t của exp(s_it / căn(d_k))
Khi đó alpha_ij không âm và tổng theo j bằng đúng 1. Nói cách khác, với mỗi Query, softmax biến một hàng score thành một phân phối trọng số trên các Key.
5.4 Bước 4 - lấy weighted sum của Value
Output tại position i:
o_i = tổng theo j của ( alpha_ij * v_j )
Đây chính là lúc thông tin thực sự được truyền giữa các token.
5.5 Một ví dụ số nhỏ
Giả sử một Query có tích vô hướng với ba Key là [1.2, 2.4, 0.3], và d_k = 4 nên căn(d_k) = 2. Sau khi chia:
[0.6, 1.2, 0.15]
Softmax cho xấp xỉ:
[0.289, 0.527, 0.184]
Nếu ba Value là v_1 = [1, 0], v_2 = [0, 2] và v_3 = [1, 1], thì:
o = 0.289 * v_1 + 0.527 * v_2 + 0.184 * v_3
o ≈ [0.473, 1.238]
Chú ý kết quả: nó không trùng với bất kỳ Value nào. Output không phải bản sao của một token được chọn, mà là một hỗn hợp có trọng số.
Toàn bộ trực giác của công thức có thể rút thành bốn câu:
Q Kᵀ -> ai liên quan tới ai?
chia căn d_k -> giữ thang giá trị ổn định
softmax -> liên quan bao nhiêu?
nhân V -> lấy thông tin gì từ họ?
Và một phiên bản pseudo-code rất gần với cài đặt thật:
scores = Q @ K.transpose(-2, -1)
scores = scores / sqrt(d_k)
scores = scores + mask # nếu có
weights = softmax(scores, dim=-1)
output = weights @ V
Đây gần như đúng logic của scaled_dot_product_attention trong các framework hiện đại, dù bản production có thể dùng kernel fused hoặc thuật toán IO-aware để chạy nhanh hơn.
06Attention matrix: mỗi token đang nhìn token nào
Với sequence dài n token, ma trận
A = softmax( Q Kᵀ / căn(d_k) )
có cỡ n × n. Mỗi hàng là một Query token. Mỗi cột là một Key token.
Một ví dụ minh hoạ giả định:
| Query ↓ / Key → | The | animal | was | tired |
|---|---|---|---|---|
| The | 0.55 | 0.25 | 0.10 | 0.10 |
| animal | 0.15 | 0.45 | 0.15 | 0.25 |
| was | 0.08 | 0.27 | 0.40 | 0.25 |
| tired | 0.05 | 0.45 | 0.15 | 0.35 |
Nếu hàng tired đặt trọng số lớn vào animal, hidden representation mới của tired sẽ lấy một phần đáng kể thông tin từ Value của animal.
Keys
The animal was tired
Query The ### ## . .
animal . ### . ##
was . ## ### ##
tired . ### . ##
Cách hình dung này thường được gọi là attention heatmap, và nó là một cửa sổ rất tiện để quan sát những interaction mà một head đang tạo ra.
Nhưng cần rất cẩn thận với câu sau:
“Token có attention weight cao nhất chính là lý do model đưa ra prediction.”
Điều đó không nhất thiết đúng.
Attention weight cho biết mức độ Value được sử dụng bên trong chính phép attention đó. Output cuối cùng của LLM còn đi qua residual connection, nhiều attention head, MLP/FFN, normalization và hàng chục tới hàng trăm layer. Nghiên cứu về interpretability đã cho thấy có trường hợp những attention distribution rất khác nhau vẫn dẫn tới prediction tương tự, và tương quan giữa attention weight với các thước đo feature importance khác không phải lúc nào cũng cao.
Attention map ≠ bản giải thích hoàn chỉnh về reasoning của model
Dù vậy, attention map vẫn rất có giá trị để debug, quan sát pattern và hiểu cơ chế cục bộ của một head. Chỉ đừng biến nó thành lời giải thích cho toàn bộ model.
07Causal mask: vì sao LLM không được nhìn tương lai
Với language model autoregressive, mục tiêu là dự đoán token kế tiếp:
P( x_t | x_1, x_2, ..., x_(t-1) )
Khi tính hidden state tại vị trí t, model không được phép dùng x_(t+1), x_(t+2) và những token sau đó. Nếu được nhìn tương lai trong training, bài toán next-token prediction sẽ bị rò rỉ đáp án - model chỉ việc chép lại.
Vì vậy decoder-only LLM dùng causal mask. Với 4 token:
Key position
1 2 3 4
Query 1 v x x x
2 v v x x
3 v v v x
4 v v v v
Dưới dạng ma trận, mask M có giá trị 0 ở ô được phép và âm vô cùng ở ô bị cấm:
M = [ 0 -inf -inf -inf ]
[ 0 0 -inf -inf ]
[ 0 0 0 -inf ]
[ 0 0 0 0 ]
Mask được cộng vào score trước softmax:
A = softmax( Q Kᵀ / căn(d_k) + M )
Vì e mũ âm vô cùng bằng 0, các vị trí tương lai nhận attention weight đúng bằng 0.
Điểm quan trọng: causal masking không xoá token khỏi sequence. Model vẫn tính toàn bộ sequence song song trong training. Mask chỉ ngăn mỗi Query truy cập những Key không hợp lệ. Đây là một trong những lợi thế lớn so với RNN: dù dependency là autoregressive, phần lớn phép toán trong training Transformer vẫn vectorize và chạy song song được.
Ngoài causal mask còn có padding mask. Khi nhiều sequence độ dài khác nhau được pad về cùng một shape, padding mask ngăn model attention vào những token đệm giả.
Causal mask -> chặn thông tin từ tương lai
Padding mask -> chặn vị trí không chứa dữ liệu thật
Một lưu ý rất thực dụng khi implement: convention boolean của mỗi framework một khác. Trong một số API, True nghĩa là “được phép attend”; trong API khác, True lại nghĩa là “bị mask”. Đọc đúng semantics của hàm đang dùng, đừng chỉ nhìn shape của mask rồi cho là xong.
08Multi-Head Attention: vì sao không chỉ dùng một head
Một attention head chỉ tạo ra một bộ Q, K, V projection và một attention distribution tại mỗi position. Transformer dùng nhiều head chạy song song.
Với head thứ i:
Q_i = X W_i^Q
K_i = X W_i^K
V_i = X W_i^V
head_i = Attention(Q_i, K_i, V_i)
Các head được nối lại rồi chiếu qua W_O:
H = Concat(head_1, head_2, ..., head_h)
MultiHead(X) = H W_O
Tại sao chuyện này hữu ích?
Mỗi head có projection matrix riêng, nghĩa là mỗi head có thể so khớp trong một representation subspace khác nhau. Một head có thể đặt attention mạnh vào quan hệ gần, một head khác học dependency xa, một head khác nữa tập trung vào dấu câu hoặc một cấu trúc nào đó. Quan trọng: đây là khả năng của multi-head attention, không phải phân công cố định do kiến trúc đặt ra.
Trong Transformer gốc:
d_k = d_v = d_model / h
Ví dụ:
d_model = 512
h = 8 head
-> d_k = d_v = 64 cho mỗi head
Nhờ giảm số chiều của mỗi head, nhiều attention operation chạy song song được mà tổng chi phí vẫn ở cùng bậc với một attention full-dimension.
Có thể hình dung multi-head như việc một token đặt nhiều câu hỏi khác nhau về cùng một ngữ cảnh:
Token hiện tại
|-- Head 1: có token nào liên quan theo pattern A?
|-- Head 2: có token nào liên quan theo pattern B?
|-- Head 3: có token nào liên quan theo pattern C?
+-- Head 4: có token nào liên quan theo pattern D?
-> ghép các kết quả
-> representation phong phú hơn
Multi-head attention vì thế không phải “chạy cùng một attention nhiều lần rồi lấy trung bình”, mà là nhiều phép chiếu Q/K/V được học độc lập rồi ghép kết quả lại.
09Self-Attention nằm ở đâu, và vị trí đi vào bằng cách nào
Self-Attention là thành phần trung tâm, nhưng Self-Attention không phải toàn bộ Transformer.
Trong các kiến trúc hiện đại, thứ tự normalization có thể khác Transformer gốc - ví dụ Pre-Norm thay vì Post-Norm - nhưng ý tưởng lớn giữ nguyên:
- Attention: trao đổi thông tin giữa các vị trí.
- MLP/FFN: biến đổi feature tại từng vị trí một cách độc lập.
- Residual connection: giữ đường truyền thông tin trực tiếp xuyên qua layer.
- Normalization: kiểm soát scale và giúp optimization ổn định.
Một điểm cực kỳ quan trọng: self-attention thuần tuý không tự biết thứ tự token.
Nếu chỉ đưa vào một tập vector mà không có bất kỳ tín hiệu vị trí nào, phép attention dựa trên nội dung không có cơ chế nội tại nào để biết token nào ở vị trí 1, vị trí 2 hay vị trí 100. Đảo thứ tự các token rồi tính lại sẽ cho ra cùng một tập kết quả. Vì vậy Transformer phải đưa thông tin vị trí vào representation, hoặc đưa thẳng vào phép tính attention.
Transformer gốc cộng sinusoidal positional encoding vào embedding:
Token embedding
+
Positional encoding
-> input vào Transformer
Các LLM hiện đại có thể làm khác. Một ví dụ phổ biến là Rotary Position Embedding (RoPE), trong đó thông tin vị trí được đưa vào Query và Key thông qua một phép quay trong không gian vector, khiến attention score biểu diễn quan hệ vị trí tương đối theo cách khác hẳn phép cộng sinusoidal truyền thống. RoPE là một chủ đề đủ lớn để tách riêng; bài về embedding đã đi qua bốn cách mã hoá vị trí và cái giá của từng cách.
Điều cần giữ lại ở đây:
Attention trả lời “token nào liên quan?”, còn cơ chế vị trí cung cấp thông tin để model biết “token nằm ở đâu và quan hệ vị trí giữa chúng là gì”.
Đến đây có thể nối lại toàn bộ pipeline:
Text
-> Tokens
-> Embeddings
-> cộng thông tin vị trí
-> Q / K / V projections
-> Self-Attention
-> hidden states đã mang ngữ cảnh
-> MLP / FFN
-> block tiếp theo
Một LLM xếp chồng nhiều block như vậy. Qua mỗi block, hidden representation được cập nhật thêm một lần. Vì thế “model hiểu ngữ cảnh” không xảy ra trong một phép attention duy nhất; nó là kết quả của nhiều vòng communication cộng transformation qua nhiều layer.
10Cái giá của Self-Attention: vì sao context dài lại đắt
Phần cốt lõi tạo ra attention score là Q Kᵀ. Nếu sequence có n token thì score matrix có cỡ n × n, và số cặp token cần xét tăng theo n bình phương.
| Sequence length | Số phần tử trong một attention matrix |
|---|---|
| 1.024 | 1.048.576 |
| 4.096 | 16.777.216 |
| 16.384 | 268.435.456 |
| 32.768 | 1.073.741.824 |
Con số này là cho mỗi head, trước khi tính đến batch và số layer, nếu hình dung attention matrix được dựng đầy đủ trong bộ nhớ.
Về computational complexity của phần self-attention cốt lõi, Transformer gốc mô tả bậc O(n² d), trong đó n là sequence length và d là số chiều representation.
Cần lưu ý rằng một Transformer layer đầy đủ còn có chi phí của Q/K/V projection, output projection và FFN - những phần này thường chứa các term theo O(n d²). Vì vậy câu “Transformer luôn có cost bậc hai” là cách nói rút gọn về tương tác attention theo sequence length, không phải toàn bộ FLOPs của mọi thành phần trong block.
Đây là lý do context window dài trở thành một bài toán hệ thống lớn.
Một bước tiến quan trọng là FlashAttention. Điểm cần hiểu đúng: ở phiên bản exact, FlashAttention không thay công thức attention bằng một xấp xỉ khác. Nó tổ chức lại cách tính theo hướng IO-aware, dùng tiling để giảm số lần đọc/ghi giữa các cấp bộ nhớ GPU, đặc biệt giữa HBM và SRAM trên chip.
Cách hình dung tiêu chuẩn
Q Kᵀ -> dựng cả score matrix -> softmax -> dựng cả weight matrix -> nhân V
Ý tưởng kiểu FlashAttention
chia Q/K/V thành block
-> tính từng tile
-> cập nhật softmax và output theo block
-> tránh dựng toàn bộ attention matrix trong HBM
Nói cách khác:
Toán học của exact attention: giữ nguyên
Cách schedule computation và memory: thay đổi mạnh
Đây là một phân biệt rất quan trọng. Khi nói “attention optimization”, có hai hướng khác hẳn nhau:
1. Thay thuật toán hoặc attention pattern
-> sparse attention, local attention, approximate attention
2. Giữ exact attention nhưng tính thông minh hơn
-> FlashAttention và các fused SDPA kernel
Những chủ đề như FlashAttention, KV Cache, MQA/GQA, sliding-window attention hay long-context optimization xứng đáng được đào sâu ở các bài về inference optimization và context window. Ở đây chỉ cần giữ một ý: tương tác all-pairs bậc hai là một trong những nguyên nhân chính khiến context dài tốn tài nguyên.
11Ghép tất cả lại: một token đi qua Self-Attention
Nếu phải rút cả bài thành bốn dòng, đó là:
Q = X W_Q, K = X W_K, V = X W_V
S = Q Kᵀ / căn(d_k)
A = softmax(S + M)
O = A V
Trong đó:
Q -> tôi cần gì?
K -> tôi có phù hợp không?
V -> tôi sẽ cung cấp thông tin gì?
S -> mức độ tương thích
M -> vị trí nào bị cấm
A -> attention weights
O -> representation mới sau khi lấy ngữ cảnh
Với Multi-Head Attention, toàn bộ quá trình đó diễn ra nhiều lần song song với những projection khác nhau, rồi mới được ghép lại và chiếu qua W_O. Sau đó tới residual, normalization, MLP, và block kế tiếp - lặp lại cho tới khi model có được hidden representation đủ hữu ích để đoán token tiếp theo.
12Những hiểu lầm thường gặp
| Hiểu lầm | Thực tế |
|---|---|
| “Attention chỉ chọn một token quan trọng nhất” | softmax thường tạo phân phối trên nhiều token; output là weighted sum của nhiều Value |
| “Q, K, V là ba embedding cố định của mỗi token” | chúng được tạo động từ hidden state bằng các learned projection, tính lại mỗi lần chạy |
| “Self-Attention nghĩa là token chỉ attention vào chính nó” | self nghĩa là Q, K, V đến từ cùng một sequence; token vẫn attention sang nhiều token khác |
| “Attention weight cao thì token đó chắc chắn là nguyên nhân” | weight mô tả một phép trộn cục bộ trong một head, không phải causal explanation của cả model |
| “Causal attention buộc Transformer xử lý tuần tự khi training” | mask chặn thông tin tương lai nhưng nhiều position vẫn vectorize và tính song song được |
| “Multi-head attention là nhiều bản copy giống hệt nhau” | mỗi head có Q/K/V projection riêng và học được các attention pattern khác nhau |
| “Self-attention tự biết thứ tự từ” | không; cần positional encoding, learned position embedding, RoPE hoặc cơ chế tương đương |
| “FlashAttention là một loại attention gần đúng” | bản exact tính đúng cùng kết quả, chỉ khác ở cách tổ chức IO; sparse hay approximate là chuyện khác |
| “Chia căn d_k là một thủ thuật tuỳ ý” | nó gắn trực tiếp với phương sai của tích vô hướng d_k chiều |
| “Cost của Transformer luôn là bậc hai” | bậc hai là chi phí attention theo độ dài; projection và FFN đóng góp các term theo d bình phương |
Attention là chỗ token thôi đứng một mình
Self-Attention là cầu nối giữa hai ý tưởng quan trọng nhất trong LLM:
Token có một vector
->
Vector đó cần thay đổi theo ngữ cảnh
Embedding cung cấp representation ban đầu. Self-Attention cho phép mỗi position truy vấn, đánh giá và lấy thông tin từ những position khác. Multi-Head mở rộng quá trình đó sang nhiều representation subspace. Causal mask đảm bảo language model không nhìn tương lai. Cơ chế vị trí cung cấp trật tự. Nhiều Transformer block xếp chồng lặp lại vòng communication và transformation đó cho tới khi model tạo được hidden representation đủ tốt để đoán token kế tiếp.
Những gì nên mang theo:
- attention là tra cứu mềm theo nội dung, không phải tra cứu cứng theo địa chỉ;
- Key quyết định mức liên quan, Value mang nội dung, và hai vai trò đó cố tình tách nhau;
- Q, K, V được sinh từ hidden state bằng ba ma trận học được, không phải ba bảng lưu sẵn;
- chia căn d_k là để softmax không rơi vào vùng gradient gần 0;
- mask cộng vào score trước softmax, và nó không xoá token khỏi sequence;
- attention map là công cụ debug tốt, không phải lời giải thích đầy đủ;
- multi-head là nhiều phép chiếu độc lập, không phải nhiều bản sao;
- attention không tự biết thứ tự, và tương tác all-pairs là nguồn gốc của chi phí bậc hai.
Từ đây, những khái niệm ở các bài sau - KV Cache, context window, long-context attention, inference optimization - sẽ trở nên tự nhiên hơn nhiều. Tất cả đều bắt đầu từ đúng một câu hỏi: Q đang tương tác với K và V như thế nào.
Tài liệu tham khảo
- Vaswani et al. — Attention Is All You Need
- Bahdanau, Cho and Bengio — Neural Machine Translation by Jointly Learning to Align and Translate
- Stanford CS224N — Transformers and Self-Attention lecture materials
- PyTorch — scaled_dot_product_attention
- Dao et al. — FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness
- Jain and Wallace — Attention is not Explanation
- Wiegreffe and Pinter — Attention is not not Explanation
- Su et al. — RoFormer: Enhanced Transformer with Rotary Position Embedding
- Elhage et al. — A Mathematical Framework for Transformer Circuits