$ cat ./blog/gen-ai/llm-fundamentals/transformer-tu-a-den-z.md
seriesCách hoạt động của LLMbài 1

Transformer từ A đến Z: Hiểu nền tảng của LLM

Bài đầu tiên trong series Cách hoạt động của LLM: từ tokenization, Attention và nội thất một Transformer block đến RoPE, GQA, MoE, inference, sampling, KV Cache và giới hạn thực tế.

~/diagrams/transformer-tu-a-den-z/transformer-llm-workflow.htmltương tác
mở riêng ↗
HìnhLuồng inference của một decoder-only LLM: prompt được token hóa, đi qua embedding và Transformer block, tạo logits, sampling ra next token, rồi dùng KV Cache để giảm tính toán lặp trong các bước decode tiếp theo.
input & biểu diễnTransformer coresampling & cache

Nếu bạn đang bắt đầu học Generative AI, sớm hay muộn bạn sẽ gặp một từ xuất hiện gần như ở mọi nơi: Transformer.

GPT dùng Transformer.
BERT dùng Transformer.
T5, BART, Llama, Gemma, Mistral, Whisper, Vision Transformer… đều có Transformer ở trung tâm.

Nhưng Transformer thực chất là gì? Vì sao nó thay đổi NLP? Attention hoạt động ra sao? Encoder và Decoder khác nhau thế nào? Vì sao LLM có thể sinh văn bản? KV Cache là gì? Context window ảnh hưởng gì đến inference?

Bài viết này hệ thống hóa những khái niệm nền tảng nhất về Transformer, và cố ý đi xa hơn mức “giới thiệu” ở đúng những chỗ mà một mental model tốt thực sự tạo ra khác biệt.

Cụ thể, ngoài Attention và ba họ kiến trúc, bài sẽ trả lời cả những câu hỏi mà tài liệu nhập môn thường bỏ qua:

  • Vì sao tiếng Việt tốn nhiều token hơn tiếng Anh, và điều đó ảnh hưởng thế nào tới chi phí của bạn?
  • Vì sao công thức Attention lại có sqrt(d_k) trong đó?
  • Residual connection và FFN làm gì - và vì sao FFN mới là nơi chứa phần lớn tham số?
  • Vì sao Attention hoàn toàn mù thứ tự, và RoPE giải quyết chuyện đó ra sao?
  • Vì sao prefill và decode nghẽn ở hai chỗ khác nhau, và vì sao điều đó quyết định gần như mọi lựa chọn hạ tầng?
  • KV Cache tốn chính xác bao nhiêu GB - và GQA cắt được bao nhiêu?
  • Vì sao model bịa chuyện, và vì sao bảo nó “đừng bịa” lại ít tác dụng?

Mục tiêu là để khi đọc xong, bạn có đủ nền đi tiếp sang RAG, Agents hay LLMOps mà không còn cảm giác đang thao tác với một hộp đen.


01Transformer thực chất là gì?

Một cách ngắn gọn:

Transformer là một kiến trúc neural network có khả năng xử lý chuỗi dữ liệu bằng cơ chế Attention, cho phép mỗi phần tử trong chuỗi xác định những phần tử nào khác quan trọng đối với nó.

Transformer ban đầu được giới thiệu năm 2017 cho bài toán dịch máy. Sau đó, kiến trúc này trở thành nền tảng cho rất nhiều mô hình hiện đại.

Một mental model đơn giản:

INPUT
"Transformers are powerful"



TOKENIZATION
["Transform", "ers", "are", "powerful"]



TOKEN + POSITION REPRESENTATION
token → vector số



TRANSFORMER BLOCKS
Attention
+
Feed-Forward layers



CONTEXTUAL REPRESENTATIONS



TASK HEAD / LANGUAGE MODEL HEAD



OUTPUT
classification / token / translation / embedding / ...

Điểm quan trọng nhất nằm ở cụm từ contextual representation.

Một từ không còn được hiểu độc lập. Representation của nó phụ thuộc vào các token xung quanh.

Ví dụ từ:

bank

có thể mang nghĩa:

  • ngân hàng;
  • bờ sông.

Transformer có thể dùng context để phân biệt hai nghĩa này.

Đó chính là một trong những lý do Attention quan trọng.


02Token: thứ model thực sự nhìn thấy

Trước khi nói về Attention, cần làm rõ một điều mà rất nhiều người học nhảy cóc qua: model không đọc chữ, cũng không đọc từ. Nó đọc token.

Đây không phải chi tiết kỹ thuật vụn vặt. Token là đơn vị mà mọi thứ phía sau được tính theo: context window tính bằng token, giá API tính bằng token, tốc độ sinh tính bằng token/giây, KV Cache tốn bộ nhớ theo token. Hiểu sai tầng này thì mọi ước lượng chi phí và giới hạn phía sau đều sai theo.


2.1 Vì sao không dùng thẳng từ hoặc ký tự?

Có ba lựa chọn hiển nhiên, và cả ba đều có vấn đề.

Tách theo từ (word-level)

"Tôi thích học máy" → ["Tôi", "thích", "học", "máy"]

Vấn đề: vocabulary bùng nổ. Tiếng Anh có hàng triệu dạng từ nếu tính cả biến thể (run, runs, running, ran, runner…). Tệ hơn, mọi từ chưa từng thấy khi train đều trở thành [UNK] — model mất trắng thông tin. Tên riêng, thuật ngữ mới, typo đều rơi vào hố này.

Tách theo ký tự (character-level)

"máy" → ["m", "á", "y"]

Vocabulary nhỏ gọn, không bao giờ [UNK]. Nhưng chuỗi dài gấp 4–5 lần, mà chi phí Attention tăng theo bình phương độ dài — nên cách này đắt kinh khủng. Ngoài ra mỗi ký tự mang quá ít ngữ nghĩa, model phải học lại việc ghép chữ từ đầu.

Subword — lựa chọn thực tế

Ý tưởng dung hòa: từ phổ biến giữ nguyên một token, từ hiếm bị chẻ thành các mảnh có nghĩa.

"học"          → ["học"]              ← phổ biến, 1 token
"tokenization" → ["token", "ization"] ← hiếm, chẻ ra
"Nguyễn"       → ["Ngu", "yễn"]       ← hiếm với tokenizer tiếng Anh

Nhờ vậy vocabulary giữ ở mức vài chục nghìn, không bao giờ gặp [UNK], và các từ có chung gốc vẫn chia sẻ token với nhau.


2.2 Ba thuật toán tokenizer bạn sẽ gặp

Thuật toán Model tiêu biểu Ý tưởng cốt lõi
BPE – Byte Pair Encoding GPT-2/3/4, Llama, Mistral Bắt đầu từ ký tự, lặp lại việc gộp cặp ký tự xuất hiện chung nhiều nhất thành một token mới
WordPiece BERT, DistilBERT Giống BPE nhưng chọn cặp để gộp theo mức tăng likelihood thay vì theo tần suất thô
SentencePiece / Unigram T5, Gemma, XLM-R Coi cả câu là chuỗi thô (kể cả dấu cách), nên không cần bước tách từ theo ngôn ngữ

Điểm chung quan trọng: tokenizer được học từ dữ liệu, không phải viết tay bằng luật. Nó là một artifact được train, đi kèm checkpoint và không thể thay bằng tokenizer khác — dùng sai tokenizer cho một checkpoint sẽ cho ra chuỗi id vô nghĩa.

Một biến thể đáng biết là byte-level BPE (GPT-2 trở đi): tokenizer làm việc trên byte UTF-8 thay vì ký tự Unicode. Nhờ vậy nó biểu diễn được mọi chuỗi, kể cả emoji hay ký tự chưa từng thấy — cái giá là những ký tự ngoài tiếng Anh tốn nhiều byte, tức nhiều token hơn.


2.3 Chi phí token của tiếng Việt

Đây là phần ít bài viết tiếng Việt nào nhắc tới, dù nó ảnh hưởng trực tiếp tới hóa đơn của bạn.

Hầu hết tokenizer phổ biến được train chủ yếu trên dữ liệu tiếng Anh. Hệ quả: tiếng Việt bị chẻ vụn hơn nhiều. Chữ có dấu trong UTF-8 chiếm 2–3 byte, và với byte-level BPE thì một âm tiết tiếng Việt thường tốn 2–3 token thay vì 1.

Một ước lượng thực dụng:

Tiếng Anh   ~ 1 token   ≈ 4 ký tự  ≈ 0.75 từ
Tiếng Việt  ~ 1.5 – 2.5 lần số token so với cùng nội dung tiếng Anh

Điều đó nghĩa là gì trong thực tế:

  • Chi phí API cao hơn cho cùng một lượng thông tin. Một tài liệu tiếng Việt và bản dịch tiếng Anh của nó có thể chênh nhau gần gấp đôi số token.
  • Context window co lại tương ứng. Một model 128K token chứa được ít nội dung tiếng Việt hơn hẳn so với tiếng Anh.
  • Chunk size trong RAG cần điều chỉnh. Nếu bạn bê nguyên tham số chunk_size từ tutorial tiếng Anh, chunk tiếng Việt của bạn sẽ chứa ít ngữ nghĩa hơn dự kiến.
  • Đừng ước lượng token bằng cách đếm từ. Luôn đếm bằng chính tokenizer của model đang dùng.

Các model có tokenizer đa ngữ tốt hơn (Gemma, Qwen, các model train nhiều dữ liệu châu Á) thu hẹp khoảng cách này đáng kể — đây là một tiêu chí chọn model mà ít người để ý.


2.4 Vì sao LLM hay sai những việc tưởng như dễ

Rất nhiều hành vi “ngớ ngẩn” của LLM có gốc rễ ngay ở tầng token, chứ không phải ở tầng suy luận.

Đếm chữ cái. Hỏi “chữ strawberry có mấy chữ r” thường bị sai, vì model nhìn thấy ["str", "aw", "berry"] chứ không nhìn thấy từng ký tự. Nó phải suy ra thành phần ký tự một cách gián tiếp.

Toán học với số dài. Số bị chẻ theo cách không nhất quán: 1234 có thể thành ["123", "4"] còn 12345 thành ["12", "345"]. Cấu trúc hàng đơn vị — hàng chục bị phá vỡ.

Đảo ngược chuỗi, chơi chữ, đếm âm tiết. Cùng một nguyên nhân.

Mental model đáng nhớ:

Model không nhìn thấy chữ cái. Nó nhìn thấy những mảnh văn bản đã được nén sẵn — và mọi thao tác ở cấp ký tự đều là suy luận gián tiếp qua lớp nén đó.


2.5 Special token

Ngoài token nội dung, tokenizer còn chèn các token điều khiển:

[CLS] [SEP]      ← BERT: mở đầu chuỗi / ngăn cách
<s>   </s>       ← Llama, Mistral: bắt đầu / kết thúc
<|endoftext|>    ← GPT: kết thúc văn bản
[PAD]            ← đệm cho đủ độ dài khi batch
[MASK]           ← vị trí bị che trong MLM

Với model chat còn có thêm chat template — bộ token đánh dấu vai trò người nói:

<|im_start|>system
Bạn là một trợ lý hữu ích.
<|im_end|>
<|im_start|>user
Xin chào
<|im_end|>
<|im_start|>assistant

Đây là chi tiết rất dễ gây bug trong thực tế: nếu bạn tự ghép prompt bằng tay mà không theo đúng template của checkpoint, chất lượng output có thể tụt rõ rệt dù model hoàn toàn bình thường.


2.6 Từ token đến vector

Sau tokenization, mỗi token là một số nguyên — chỉ là chỉ mục trong vocabulary, hoàn toàn chưa mang nghĩa.

"học"  →  id 15234  →  embedding vector [0.21, -0.83, ..., 0.05]
                        (d_model chiều, ví dụ 4096)

Bảng embedding matrix có kích thước vocab_size × d_modelđược học trong lúc train. Đây là nơi ngữ nghĩa bắt đầu xuất hiện: các token dùng trong ngữ cảnh giống nhau dần có vector gần nhau.

Nhưng cần nhấn mạnh một điều dẫn thẳng vào phần sau:

Embedding ở tầng này vẫn là tĩnh. Token bank có đúng một vector, bất kể đang nói về ngân hàng hay bờ sông.

Việc biến vector tĩnh đó thành biểu diễn theo ngữ cảnh chính là nhiệm vụ của các Transformer block — và cụ thể là của Attention.


03NLP và Large Language Models

3.1 NLP là gì?

Natural Language Processing – NLP là lĩnh vực nghiên cứu cách máy tính xử lý và làm việc với ngôn ngữ con người.

NLP có rất nhiều nhóm bài toán:

Nhóm task Ví dụ
Sentence classification sentiment, spam detection
Token classification NER, POS tagging
Text generation autocomplete, viết nội dung
Extractive QA tìm câu trả lời trong context
Translation Anh → Việt
Summarization tài liệu dài → bản tóm tắt
Speech speech-to-text
Vision-language mô tả hình ảnh

Điểm quan trọng:

NLP là một lĩnh vực, còn LLM là một nhóm mô hình được dùng để giải quyết nhiều bài toán trong lĩnh vực đó.


3.2 LLM là gì?

Large Language Model là mô hình ngôn ngữ quy mô lớn, được huấn luyện trên lượng dữ liệu rất lớn để học các pattern của ngôn ngữ.

Một LLM hiện đại thường nổi bật ở bốn đặc điểm:

Scale

Model có thể có từ hàng triệu đến hàng tỷ, thậm chí hàng trăm tỷ parameters.

General capability

Cùng một model có thể thực hiện nhiều loại task.

In-context learning

Model có thể học cách làm task chỉ từ prompt và ví dụ nằm trong context.

Emergent capabilities

Khi model scale đủ lớn, một số khả năng có thể xuất hiện dù không được lập trình trực tiếp cho từng task.

Trước đây, NLP thường mang dạng:

Model A → sentiment
Model B → translation
Model C → QA
Model D → summarization

Trong kỷ nguyên LLM:

             ┌→ summarize
             ├→ translate
One LLM  ────┼→ classify
             ├→ answer
             ├→ write code
             └→ generate

Đây là một thay đổi cực lớn.


3.3 Nhưng LLM không phải “máy biết tất cả”

LLM vẫn có nhiều hạn chế:

  • hallucination;
  • bias;
  • context window hữu hạn;
  • chi phí tính toán cao;
  • không đảm bảo hiểu thế giới như con người;
  • output có tính xác suất.

Vì vậy:

Một LLM mạnh không đồng nghĩa với một hệ thống AI đáng tin cậy.

Khi xây production system, ta cần thêm RAG, evaluation, guardrails, monitoring, human-in-the-loop và governance.


04Transformer có thể làm gì?

Một cách dễ tiếp cận Transformer trong Python là dùng API dạng pipeline:

from transformers import pipeline

pipeline() cung cấp một abstraction rất tiện:

RAW INPUT

PREPROCESSING

MODEL

POSTPROCESSING

HUMAN-READABLE OUTPUT

Ví dụ:

from transformers import pipeline

classifier = pipeline("sentiment-analysis")

classifier("This course is very useful.")

Thay vì tự viết toàn bộ tokenizer, model inference và xử lý output, pipeline() gói tất cả lại.


4.1 Zero-shot classification

Một ứng dụng rất thú vị là zero-shot classification.

Thay vì:

collect labeled data

train classifier

predict

ta có thể làm:

TEXT:
"Tesla announced a new factory."

LABELS:
business
sports
education

Model đánh giá label phù hợp nhất mà không cần train riêng cho bộ label này.

Khái niệm quan trọng:

Zero-shot = model thực hiện task mà không cần ví dụ training cụ thể cho task đó trong bước fine-tuning hiện tại.

Một chỗ rất dễ hiểu nhầm

Cụm “zero-shot” đang được dùng cho hai cơ chế hoàn toàn khác nhau, và trộn hai thứ này là lỗi phổ biến.

Zero-shot classification (HF pipeline) Zero-shot prompting (LLM)
Model nền Encoder train trên NLI (ví dụ bart-large-mnli) LLM decoder-only
Cách hoạt động Biến mỗi label thành một giả thuyết: “Văn bản này nói về business.” rồi hỏi model xem câu đó có được suy ra từ văn bản không Mô tả task bằng ngôn ngữ tự nhiên ngay trong prompt
“Zero-shot” ở đây nghĩa là Không có nhãn nào cho bộ label của bạn - nhưng model đã được train trên tập NLI Không có ví dụ nào trong prompt
Chi phí Chạy một lượt cho mỗi label Một lần gọi duy nhất

Nói cách khác, zero-shot classification không phải là model “tự nhiên biết”. Nó tận dụng một năng lực đã học sẵn - suy luận kéo theo - và ánh xạ bài toán phân loại của bạn về đúng năng lực đó.


4.2 Text generation

Prompt:

Artificial intelligence will...

Decoder model hoạt động theo vòng lặp:

predict token 1

append token

predict token 2

append token

...

Đây là autoregressive generation.

Hầu hết chatbot LLM hiện đại đều hoạt động theo cách này.


4.3 Fill-mask

Ví dụ:

Paris is the [MASK] of France.

Một BERT-like model có thể dự đoán token bị che.

Đây liên quan trực tiếp tới:

Masked Language Modeling – MLM


4.4 Named Entity Recognition

Ví dụ:

Tim Cook works at Apple in California.

Model có thể xuất:

Tim Cook   → PERSON
Apple      → ORGANIZATION
California → LOCATION

Đây là Token Classification.

NER được dùng trong:

  • document processing;
  • CRM;
  • legal;
  • financial documents;
  • information extraction;
  • search.

4.5 Question Answering

Với extractive QA:

Context:
"John works at Microsoft in Seattle."

Question:
"Where does John work?"

Model có thể tìm span:

Microsoft

Điểm cần phân biệt:

Extractive QA

Tìm answer nằm ngay trong context.

Generative QA

Sinh câu trả lời mới bằng decoder.


4.6 Summarization và Translation

Đây là các bài toán:

Sequence → Sequence

Ví dụ:

long document

   Transformer

short summary

hoặc:

English

Transformer

Vietnamese

Các kiến trúc Encoder-Decoder như T5/BART đặc biệt phù hợp với dạng bài toán này.


4.7 Transformer không chỉ dành cho text

Transformer ngày nay được dùng trên nhiều modality.

Text

  • text generation;
  • classification;
  • summarization;
  • translation;
  • QA;
  • embeddings.

Audio

  • speech recognition;
  • audio classification;
  • text-to-speech.

Vision

  • image classification;
  • object detection;
  • image understanding.

Multimodal

  • image + text;
  • audio + text;
  • video + text;
  • document understanding.

Transformer từ một kiến trúc NLP đã trở thành nền tảng chung của rất nhiều foundation model.


05Transformer hoạt động như thế nào?

Đây là phần quan trọng nhất.


5.1 Một chút lịch sử

Một timeline giản lược:

2017  Transformer          kiến trúc gốc, cho bài toán dịch máy
2018  GPT                  decoder-only, pretraining sinh văn bản
2018  BERT                 encoder-only, bidirectional, MLM
2019  GPT-2                quy mô bắt đầu tạo ra năng lực mới
2019  T5                   mọi task đưa về dạng text-to-text
2020  GPT-3                few-shot learning ngay trong prompt
2022  InstructGPT          RLHF - từ model hoàn thành văn bản thành trợ lý
2023  Llama / Mistral      model mở, GQA, sliding-window attention
2023  Mixtral              MoE bước vào dòng chính
2024  Llama 3 / Gemma 2    context dài, tokenizer đa ngữ tốt hơn
2025+ Reasoning models     huấn luyện suy luận, tăng tính toán lúc chạy

Nhìn theo trục dọc, có ba làn sóng khá rõ:

Giai đoạn Câu hỏi trung tâm Hướng đi
2017 - 2020 Kiến trúc nào tốt nhất? Encoder, decoder, encoder-decoder cạnh tranh nhau
2020 - 2023 Scale được tới đâu? Model to hơn, dữ liệu nhiều hơn, decoder-only thắng thế
2023 - nay Làm sao chạy hiệu quả và cư xử đúng? Alignment, MoE, GQA, tối ưu inference, suy luận

Đáng chú ý là trọng tâm đã dịch từ kiến trúc sang huấn luyện và phục vụ. Bản thân Transformer block gần như không đổi kể từ 2017 - thứ thay đổi là cách chuẩn hoá, positional encoding, cách tổ chức attention, và toàn bộ tầng phía sau pretraining.

Điều đáng nhớ không phải các mốc năm.

Điều đáng nhớ là Transformer phát triển thành ba họ lớn:

Encoder-only
Decoder-only
Encoder-Decoder

5.2 Pretraining

Transformer thường không được train từ đầu cho từng bài toán như sentiment hay QA.

Thay vào đó:

Massive raw data

PRETRAINING

General language representation

Sau đó:

Pretrained model

Fine-tuning / Instruction tuning

Task-specific behavior

Điểm cực kỳ quan trọng:

Pretraining của language model thường là self-supervised learning.

Dữ liệu tự tạo supervision.

Ví dụ:

The capital of France is Paris

ta có thể tự tạo task dự đoán token tiếp theo mà không cần người ngồi label thủ công.


5.3 Masked Language Modeling

BERT thường được giải thích qua MLM.

Input:

The dog [MASK] across the road.

Model dự đoán:

ran

BERT có thể nhìn cả:

LEFT CONTEXT
+
MASK
+
RIGHT CONTEXT

Vì vậy representation mang tính bidirectional.


5.4 Causal Language Modeling

GPT hoạt động khác.

Input:

The capital of France is

Model dự đoán:

Paris

Khi dự đoán token t:

token t
depends on
token 1 ... token t-1

Model không được nhìn future tokens.

Đây là:

Causal Language Modeling – CLM

Và đây chính là nền tảng của hầu hết generative LLM hiện đại.


5.5 Pretraining vs Fine-tuning

Phân biệt thật rõ:

Pretraining

random weights

massive dataset

large compute

general pretrained model

Fine-tuning

pretrained weights

smaller task/domain dataset

additional training

specialized model

Fine-tuning thường:

  • cần ít data hơn;
  • ít compute hơn;
  • nhanh hơn;
  • tận dụng representation đã học từ pretraining.

Đây là một dạng Transfer Learning.

Một mental model dễ nhớ:

Pretraining = học nền tảng tổng quát.
Fine-tuning = học chuyên môn.


5.6 General Transformer Architecture

Transformer gốc gồm hai phần:

        INPUT

     ┌─────────┐
     │ ENCODER │
     └─────────┘

   Representation

     ┌─────────┐
     │ DECODER │
     └─────────┘

        OUTPUT

Encoder

Tập trung vào:

hiểu và biểu diễn input.

Decoder

Tập trung vào:

sinh output.

Từ hai khối này, ta có ba kiến trúc phổ biến:

ENCODER ONLY

DECODER ONLY

ENCODER + DECODER

5.7 Attention – trái tim của Transformer

Ví dụ:

The animal didn't cross the street because it was tired.

Từ:

it

đang chỉ cái gì?

Để hiểu it, model phải đánh giá token nào liên quan nhất.

Một cách hình dung:

it
↓ attention
animal     ████████
street     ██
because    █
tired      █████

Attention cho phép representation của token thay đổi theo context.

Đó là khác biệt quan trọng so với việc dùng embedding cố định cho mỗi từ.


5.8 Query, Key, Value

Nếu muốn hiểu sâu hơn Attention, bạn cần biết ba khái niệm:

Query – Q

Token hiện tại đang tìm thông tin gì?

Key – K

Token khác chứa loại thông tin gì để được so khớp?

Value – V

Nội dung thực sự được lấy về sau khi Attention xác định mức liên quan.

Mental model:

Query của token hiện tại

so với

Keys của các token khác

attention scores

weighted combination

Values

Công thức cốt lõi:

Attention(Q,K,V) = softmax((QK^T) / sqrt(d_k))V

Đọc công thức này thành lời

Từng mảnh của công thức đều có nghĩa rất cụ thể:

Thành phần Ý nghĩa
QK^T Tích vô hướng giữa Query của token đang xét và Key của mọi token — đo mức “khớp” giữa cái đang tìm và cái sẵn có
/ sqrt(d_k) Chuẩn hóa lại thang điểm để softmax không bị bão hòa
softmax Biến điểm thô thành trọng số cộng lại bằng 1
... V Lấy trung bình có trọng số các Value — kết quả là biểu diễn mới của token

Vì sao phải chia cho sqrt(d_k)?

Chi tiết này hay bị lướt qua, nhưng lý do rất đáng biết.

Q và K là vector d_k chiều. Tích vô hướng của chúng là tổng của d_k số hạng, nên phương sai của kết quả tăng theo d_k. Với d_k = 128, các điểm thô có thể dao động trong khoảng hàng chục.

Đưa những con số lớn đó vào softmax sẽ khiến phân phối gần như one-hot: một token nhận trọng số ~1, phần còn lại ~0. Khi đó gradient của softmax gần bằng 0 và model gần như không học được nữa.

Chia cho sqrt(d_k) kéo phương sai về khoảng 1, giữ softmax ở vùng còn gradient.

Đây là ví dụ điển hình cho một kiểu chi tiết xuất hiện khắp deep learning: một hằng số nhìn có vẻ tùy tiện, nhưng thực ra tồn tại để giữ cho việc training không sụp đổ.

Một ví dụ số cụ thể

Giả sử câu "con mèo ngủ" và ta đang tính biểu diễn mới cho token ngủ.

Điểm thô (Q_ngủ · K_i):

  con   1.2
  mèo   4.8
  ngủ   2.1

Chia sqrt(d_k), giả sử d_k = 4 → chia 2:

  con   0.60
  mèo   2.40
  ngủ   1.05

Sau softmax:

  con   0.11
  mèo   0.65
  ngủ   0.24

Biểu diễn mới của "ngủ":

  0.11 × V_con  +  0.65 × V_mèo  +  0.24 × V_ngủ

Token ngủ giờ mang theo phần lớn thông tin của mèo — nó đã biết ai đang ngủ. Đó chính xác là điều “contextual representation” nghĩa là.

Bạn chưa cần thuộc lòng công thức.

Nhưng cần hiểu logic:

Q × K

relevance score

softmax

attention weights

weighted V

new contextual representation

5.9 Multi-Head Attention

Transformer không chỉ có một Attention head.

Thay vào đó:

Head 1 → học một kiểu relationship
Head 2 → học kiểu khác
Head 3 → học kiểu khác
...

Sau đó kết quả được combine.

Một số head có thể nhạy với:

  • syntax;
  • subject-object relationship;
  • long-distance dependency;
  • positional patterns;
  • semantic similarity.

Đây là lý do gọi là:

Multi-Head Attention

~/diagrams/transformer-tu-a-den-z/transformer-attention.htmltương tác
mở riêng ↗
HìnhMột token đi qua Attention: hidden state được chiếu thành Q, K, V; Q so với mọi K để ra điểm tương quan, chia sqrt(d_k) rồi softmax thành trọng số; trọng số đó cộng V lại thành biểu diễn mới, và nhiều head chạy song song trước khi được nối lại.
ba phép chiếu Q / K / Vtính trọng số attentionbiểu diễn đầu ra

5.10 Từ Multi-Head đến MQA và GQA

Multi-Head Attention như mô tả ở trên là bản gốc năm 2017. Các LLM hiện đại hầu như không còn dùng nguyên bản đó, vì một lý do rất thực dụng: mỗi head cần lưu Key và Value riêng vào cache khi sinh văn bản, và đó là thứ ngốn VRAM nhất khi context dài.

Ba biến thể, phân biệt theo trục “bao nhiêu bộ K/V được dùng chung”:

Biến thể Số bộ K/V Đánh đổi
MHA - Multi-Head Attention Mỗi head một bộ Chất lượng tốt nhất, KV Cache lớn nhất
MQA - Multi-Query Attention Tất cả head dùng chung một bộ Cache nhỏ nhất, chất lượng giảm rõ
GQA - Grouped-Query Attention Chia head thành nhóm, mỗi nhóm một bộ Gần bằng MHA về chất lượng, cache nhỏ hơn nhiều

Hình dung:

MHA        Q1 Q2 Q3 Q4          GQA        Q1 Q2 Q3 Q4
           |  |  |  |                       \  /  \  /
           K1 K2 K3 K4                        KV1   KV2


MQA        Q1 Q2 Q3 Q4
            \  \  /  /
                KV

Số Query head vẫn giữ nguyên trong cả ba biến thể - chỉ số bộ Key/Value thay đổi. Nghĩa là khả năng biểu đạt ở phía Query không bị cắt, chỉ phần “kho thông tin” bị dùng chung.

Con số cụ thể: Llama-3-70B dùng 64 Query head nhưng chỉ 8 Key/Value head. Tỉ lệ 8:1 đó giảm KV Cache đi 8 lần so với MHA, gần như không mất chất lượng.

Hãy nhớ GQA: đây là câu trả lời phổ biến nhất hiện nay cho bài toán KV Cache mà chúng ta sẽ gặp lại ở phần inference.


5.11 Masked Attention

Decoder không được nhìn future token.

Ví dụ đang dự đoán token thứ 4:

token1 token2 token3 [token4] token5
  ✓      ✓      ✓        ?       ✗

Model dùng causal attention mask.

Ngoài causal mask, hệ thống còn có thể dùng attention mask để bỏ qua:

  • padding tokens;
  • invalid positions;
  • restricted regions.

5.12 Bên trong một Transformer block

Cho tới đây ta mới nói về Attention. Nhưng Attention không phải là toàn bộ một Transformer block - thực tế nó còn không phải phần chiếm nhiều tham số nhất.

Một block đầy đủ trông như sau:

        x  (hidden state vào)
        |
        +--------------+
        |              |  residual
   +----v----+         |
   |  Norm   |         |
   +----+----+         |
        |              |
   +----v--------+     |
   |  Attention  |     |
   +----+--------+     |
        |              |
        v              |
       (+) <-----------+
        |
        +--------------+
        |              |  residual
   +----v----+         |
   |  Norm   |         |
   +----+----+         |
        |              |
   +----v--------+     |
   |     FFN     |     |
   +----+--------+     |
        |              |
        v              |
       (+) <-----------+
        |
        v
       x2  (hidden state ra)

Model thật chỉ là khối này xếp chồng nhiều lần: 12 lần với BERT-base, 32 lần với Llama-3-8B, 80 lần với các model cỡ 70B.

Ba thành phần ngoài Attention đều quan trọng.

Residual connection

Đó là đường + đi vòng qua mỗi khối con. Thay vì ép mỗi lớp phải tạo ra biểu diễn mới hoàn toàn, residual cho phép lớp đó chỉ cần học phần chênh lệch cần thêm vào:

output = x + f(x)      thay vì      output = f(x)

Vì sao đây là điều sống còn: khi backpropagation chạy ngược qua 80 lớp, gradient bị nhân dồn qua từng lớp và có xu hướng tiêu biến về 0. Đường residual tạo một lối đi thẳng cho gradient xuyên suốt chiều sâu của model.

Không có residual, Transformer sâu đơn giản là không train được. Đây là lý do kiến trúc này scale được tới hàng chục tỉ tham số, và cũng là mảnh ghép hay bị bỏ quên nhất khi người ta mô tả Transformer.

Một cách nhìn hữu ích: residual biến hidden state thành một dòng chảy thông tin chung (residual stream) mà mỗi lớp đọc từ đó, tính toán, rồi ghi thêm vào. Các lớp giao tiếp với nhau qua dòng chảy đó.

Normalization

Sau nhiều phép cộng dồn, độ lớn của hidden state dễ trôi dạt. Normalization kéo nó về lại thang ổn định.

LayerNorm chuẩn hóa theo trung bình và độ lệch chuẩn của từng vector:

LayerNorm(x) = gamma * (x - mean) / std + beta

RMSNorm - thứ hầu hết LLM hiện đại (Llama, Mistral, Gemma) đang dùng - bỏ luôn bước trừ trung bình:

RMSNorm(x) = gamma * x / sqrt(mean(x^2))

Đơn giản hơn, nhanh hơn, và trong thực nghiệm cho kết quả tương đương.

Một chi tiết nhỏ nhưng ảnh hưởng lớn là đặt Norm ở đâu:

Post-LN (bản gốc 2017)          Pre-LN (mọi LLM hiện đại)

x -> Attn -> (+) -> Norm        x -> Norm -> Attn -> (+)

Post-LN đòi hỏi warmup rất cẩn thận và dễ phân kỳ khi model sâu. Pre-LN train ổn định hơn nhiều - đó là lý do cả ngành đã chuyển sang nó.

Feed-Forward Network

Đây là phần bị đánh giá thấp nhất, dù nó chiếm khoảng hai phần ba tham số của model.

FFN xử lý từng token một cách độc lập, không có trao đổi thông tin giữa các vị trí:

d_model  ->  nở rộng ~4x  ->  phi tuyến  ->  co lại về d_model

  4096   ->    16384      ->  GELU/SwiGLU ->     4096

Phân công lao động giữa hai khối rất rõ ràng:

Attention FFN
Trao đổi giữa các token Không
Vai trò Thu thập thông tin từ ngữ cảnh Xử lý và lưu trữ tri thức
Tỉ lệ tham số khoảng 1/3 khoảng 2/3

Các nghiên cứu interpretability gợi ý rằng FFN hoạt động gần giống một key-value memory: đây là nơi phần lớn tri thức thực tế của model được cất giữ. Nói ngắn gọn, Attention quyết định nhìn vào đâu, còn FFN quyết định biết cái gì.

Các LLM gần đây thay GELU bằng SwiGLU, một biến thể có cổng cho chất lượng tốt hơn ở cùng ngân sách tham số.


5.13 Positional encoding: làm sao model biết thứ tự

Có một tính chất của Attention mà rất nhiều người bỏ sót: nó hoàn toàn không quan tâm tới thứ tự.

Attention chỉ tính tích vô hướng giữa các cặp vector. Nếu bạn xáo trộn thứ tự token đầu vào, tập kết quả cũng bị xáo trộn y hệt - không có gì trong phép toán cho model biết token nào đứng trước token nào.

Nghĩa là nếu không có thông tin vị trí, hai câu sau là giống hệt nhau dưới mắt model:

"Chó cắn người"
"Người cắn chó"

Vì vậy thông tin vị trí phải được đưa vào một cách tường minh.

Sinusoidal - bản gốc 2017

Cộng thẳng một mẫu sóng sin/cos vào embedding, mỗi chiều một tần số khác nhau. Không cần học, và về lý thuyết mở rộng được ra độ dài chưa từng gặp.

Learned positional embedding - BERT, GPT-2

Coi mỗi vị trí như một token và học một vector riêng cho nó. Đơn giản, hiệu quả, nhưng cứng: model không xử lý được vị trí vượt quá độ dài đã train.

RoPE - Rotary Position Embedding

Đây là thứ Llama, Mistral, Gemma, Qwen đều đang dùng, và rất đáng hiểu ý tưởng.

Thay vì cộng vị trí vào vector, RoPE xoay vector Q và K một góc tỉ lệ với vị trí:

token ở vị trí 1  ->  xoay 1 theta
token ở vị trí 2  ->  xoay 2 theta
token ở vị trí 5  ->  xoay 5 theta

Cái hay nằm ở chỗ: khi tính tích vô hướng giữa Q ở vị trí m và K ở vị trí n, kết quả chỉ phụ thuộc vào hiệu m - n. Nói cách khác, RoPE mã hóa vị trí tương đối một cách tự nhiên - điều quan trọng hơn nhiều so với vị trí tuyệt đối trong ngôn ngữ.

Hệ quả thực dụng: RoPE cho phép mở rộng context sau khi đã train xong bằng cách nội suy góc xoay (position interpolation, NTK-aware scaling, YaRN). Đây chính là cách nhiều model được nâng từ 4K lên 32K hay 128K context mà không cần pretrain lại từ đầu.

ALiBi

Bỏ hẳn positional embedding, thay bằng cách trừ trực tiếp vào điểm attention một lượng tỉ lệ với khoảng cách - token càng xa càng bị phạt nặng. Đơn giản và mở rộng độ dài rất tốt.

Nếu chỉ nhớ một ý ở mục này: Attention mù thứ tự, và positional encoding là thứ duy nhất cho model biết trật tự của câu. RoPE là lựa chọn mặc định hiện nay, và nó là lý do kỹ thuật đằng sau việc context window có thể kéo dài được.


5.14 Architecture vs Checkpoint vs Model

Ba từ này thường bị dùng lẫn.

Architecture

Blueprint của model.

Ví dụ:

BERT

Checkpoint

Một bộ weights cụ thể đã được train.

Ví dụ:

bert-base-cased

Model

Cách gọi rộng, có thể chỉ architecture hoặc checkpoint tùy context.

Học AI nên quen distinction này ngay từ đầu.


06Transformer giải quyết các task ra sao?

Bây giờ ta nối kiến trúc với ứng dụng.


6.1 Text Generation – GPT

GPT là decoder-only.

Pipeline đơn giản hóa:

text

tokenizer

tokens

embedding + position

decoder blocks

masked self-attention

hidden states

LM Head

logits

sampling

next token

Điểm quan trọng:

Transformer cần positional information để biết thứ tự token.

Attention một mình không tự hiểu token nào nằm trước hay sau.


6.2 Text Classification – BERT

Input:

[CLS] I love this movie [SEP]

Representation của [CLS] có thể được dùng để đại diện cho cả sequence.

Nhưng cần một cảnh báo quan trọng ở đây, vì đây là lỗi rất phổ biến:

[CLS] chỉ mang nghĩa sau khi đã được fine-tune cho task cụ thể. Lấy [CLS] từ một checkpoint BERT thô rồi dùng làm sentence embedding sẽ cho kết quả tệ hơn cả việc lấy trung bình các token - và tệ hơn hẳn so với các model chuyên dụng như Sentence-BERT hay E5.

Trong lúc pretraining, [CLS] chỉ được huấn luyện qua task Next Sentence Prediction, vốn quá yếu để tạo ra một biểu diễn câu tốt. Nếu bạn cần embedding để so sánh độ tương đồng hoặc làm RAG, hãy dùng model được train riêng cho việc đó.

Pipeline:

BERT

[CLS] hidden state

classification head

logits

softmax

positive / negative

BERT rất phù hợp với:

  • sentiment;
  • intent classification;
  • spam detection;
  • topic classification.

6.3 Token Classification

Khác với sentence classification:

Sentence Classification
ONE LABEL / SENTENCE

Token Classification:

John    → PERSON
works   → O
at      → O
Google  → ORG

Mỗi token hidden state đi qua classification head.

Ứng dụng:

  • NER;
  • POS tagging;
  • entity extraction.

6.4 Extractive Question Answering

Một BERT-like model có thể dự đoán:

start position
+
end position

Ví dụ:

John works at [Google] in New York
               ↑    ↑
             start end

Cách tiếp cận này đặc biệt hữu ích khi answer nằm trong document.


6.5 Summarization – BART/T5

Encoder-Decoder:

LONG TEXT

ENCODER

representation

DECODER

SUMMARY

BART được pretrain bằng cách corrupt input rồi học reconstruct.

Ví dụ một strategy là text infilling:

Original:
The cat is sleeping on the sofa.

Corrupted:
The cat <mask> on the sofa.

Target:
The cat is sleeping on the sofa.

6.6 Translation

Cùng mô hình:

Sequence A

Encoder

meaning representation

Decoder

Sequence B

Ví dụ:

English

Encoder

Decoder

Vietnamese

6.7 Audio – Whisper

Transformer cũng được dùng cho audio.

Một pipeline khái quát:

AUDIO

log-Mel spectrogram

ENCODER

audio representation

DECODER

TEXT TOKENS

Whisper có thể hỗ trợ:

  • transcription;
  • translation;
  • language identification.

6.8 Vision Transformer – ViT

Insight rất hay của ViT:

Nếu text là sequence token, image cũng có thể được biến thành sequence patch.

Ví dụ, với một ảnh 224 × 224 pixel và kích thước mỗi patch là 16 × 16 pixel:

Ảnh:        224 × 224 pixel
Mỗi patch:   16 × 16  pixel

Số patch theo mỗi chiều:  224 / 16 = 14

Tổng số patch:  14 × 14 = 196

Lưu ý cách đọc: 16 × 16 ở đây là kích thước của một patch, không phải số lượng patch. Đây là chỗ rất dễ đọc nhầm.

Mỗi patch được duỗi phẳng thành vector rồi chiếu tuyến tính thành embedding - đúng vai trò mà bảng embedding đảm nhiệm với token văn bản. ViT còn thêm một token [CLS] ở đầu chuỗi, nên encoder thực tế nhận 196 + 1 = 197 token.

Pipeline:

IMAGE

split patches

[P1][P2][P3]...[P196]

embeddings + positions

Transformer Encoder

classification / representation

Đây là cách Transformer mở rộng từ NLP sang Vision.


07Ba kiến trúc Transformer quan trọng

Đây là bảng bạn nên nhớ.

Architecture Attention Phù hợp nhất với Ví dụ
Encoder-only Bidirectional Understanding BERT, DistilBERT, ModernBERT
Decoder-only Causal Generation GPT, Llama, Gemma, Mistral
Encoder-Decoder Encoder bi-directional + Decoder causal Sequence transformation T5, BART, Marian

7.1 Khi nào dùng Encoder?

Nếu task chủ yếu là:

hiểu input.

Ví dụ:

INPUT

UNDERSTAND

LABEL / EMBEDDING / SPAN

Dùng tốt cho:

  • classification;
  • NER;
  • semantic representation;
  • extractive QA.

7.2 Khi nào dùng Decoder?

Nếu task chủ yếu là:

sinh output.

Ví dụ:

PROMPT

GENERATE

TOKEN

TOKEN

TOKEN
...

Dùng cho:

  • chatbot;
  • viết nội dung;
  • code generation;
  • reasoning;
  • assistants.

Phần lớn modern LLM hiện nay là decoder-only.


7.3 Khi nào dùng Encoder-Decoder?

Nếu task có dạng:

Input sequence → transformed output sequence.

Ví dụ:

English → Vietnamese
Document → Summary
Question + Context → Generated Answer

7.4 Modern LLM Training

Một model vừa pretrain xong chưa phải là một trợ lý. Nó mới chỉ biết hoàn thành văn bản. Hỏi nó “Thủ đô của Pháp là gì?” thì một model chỉ mới pretrain hoàn toàn có thể đáp lại bằng cách viết tiếp thêm vài câu hỏi tương tự, vì đó mới là thứ hay xuất hiện trên internet.

Khoảng cách giữa “model hoàn thành văn bản” và ChatGPT nằm ở các giai đoạn phía sau. Đây là phần bị bỏ qua nhiều nhất khi người ta giải thích LLM.

1. PRETRAINING
   next-token prediction trên dữ liệu khổng lồ
   -> biết ngôn ngữ và tri thức, nhưng chưa biết cư xử
              |
              v
2. SFT - Supervised Fine-Tuning
   học từ các cặp (chỉ dẫn, câu trả lời tốt) do người viết
   -> biết trả lời đúng khuôn hội thoại
              |
              v
3. ALIGNMENT - RLHF hoặc DPO
   học từ so sánh: câu trả lời nào con người thích hơn
   -> hữu ích hơn, an toàn hơn, biết từ chối đúng lúc
              |
              v
4. (tuỳ chọn) REASONING TRAINING
   huấn luyện bằng phần thưởng trên các bước suy luận
   -> giải toán, viết code, lập luận nhiều bước

Vì sao cần một bước alignment riêng?

Vấn đề rất thực tế: với nhiều câu hỏi, ta không viết nổi một câu trả lời “đúng” duy nhất để làm nhãn. Thế nào là một bản tóm tắt tốt? Một lời từ chối lịch sự? Một cách giải thích dễ hiểu?

Con người khó viết ra câu trả lời hoàn hảo, nhưng lại rất giỏi so sánh hai câu trả lời. Alignment khai thác đúng điểm mạnh đó.

RLHF - Reinforcement Learning from Human Feedback - gồm ba bước:

a. Thu thập so sánh của con người:  A tốt hơn B
b. Train một reward model để dự đoán lựa chọn đó
c. Dùng RL (thường là PPO) tinh chỉnh LLM sao cho tối đa hoá reward

DPO - Direct Preference Optimization - đạt cùng mục tiêu nhưng bỏ hẳn reward model và vòng lặp RL, tối ưu thẳng trên dữ liệu so sánh. Đơn giản hơn nhiều, ổn định hơn, và vì thế đã thành lựa chọn phổ biến.

Điều này giải thích khá nhiều hành vi bạn thấy hằng ngày

Hành vi Nguồn gốc
Trả lời theo đúng khuôn hội thoại SFT
Từ chối yêu cầu có hại Alignment
Giọng văn dài dòng, hay liệt kê gạch đầu dòng Người đánh giá có xu hướng thích câu trả lời dài hơn
Quá dễ đồng ý với người dùng (sycophancy) Cũng từ alignment - người ta thích được đồng tình
Tri thức thực tế và năng lực ngôn ngữ Pretraining

Một mental model đáng nhớ: pretraining quyết định model biết gì, alignment quyết định model cư xử ra sao. Rất nhiều lời than phiền về “tính cách” của LLM thực ra là than phiền về giai đoạn alignment, không phải về kiến trúc Transformer.


7.5 Vấn đề O(n²) của Attention

Với sequence length:

n

full self-attention tạo ma trận gần:

n x n

Complexity:

O(n^2)

Ví dụ trực quan:

1,000 tokens   → ~1M pair relationships
10,000 tokens  → ~100M
100,000 tokens → ~10B

Đây là một trong những lý do long-context expensive.


7.6 Local Attention

Thay vì để mọi token nhìn mọi token, Local Attention giới hạn phạm vi.

... T3 T4 [T5] T6 T7 ...
     \   \  |  /   /
       cửa sổ w token

Nếu mỗi token chỉ nhìn w token gần nhất, chi phí tụt từ O(n²) xuống O(n × w) - tức là tuyến tính theo độ dài chuỗi.

Câu hỏi hiển nhiên: vậy thông tin ở xa thì sao?

Câu trả lời khá tinh tế - chồng nhiều lớp lại thì phạm vi nhìn được sẽ nở ra, giống hệt receptive field trong CNN:

Lớp 1: mỗi token nhìn trực tiếp   w  token
Lớp 2: nhìn gián tiếp được       2w
Lớp 3:                           3w
...
Lớp L:                       L × w

Mistral 7B dùng cửa sổ 4096 với 32 lớp, nên về lý thuyết tầng trên cùng vẫn với tới được khoảng 131K token, dù mỗi lớp chỉ nhìn cục bộ.

Một số kiến trúc (Longformer, BigBird) còn kết hợp thêm:

  • global token - vài token đặc biệt được nhìn thấy tất cả và được tất cả nhìn thấy;
  • random attention - vài liên kết ngẫu nhiên để rút ngắn đường đi của thông tin.

Đánh đổi cần biết: attention cục bộ tiết kiệm thật, nhưng khả năng bắt quan hệ xa một cách chính xác vẫn kém hơn full attention. Đó là lý do nhiều model chọn xen kẽ - vài lớp cục bộ, vài lớp full.


7.7 FlashAttention: tối ưu mà không đổi kết quả

Các cách ở trên đều thay đổi phép tính - chúng bỏ bớt liên kết để đổi lấy tốc độ, nên kết quả khác đi ít nhiều.

FlashAttention đi theo hướng hoàn toàn khác, và đây là ý tưởng đáng học nhất trong nhóm này:

Giữ nguyên phép toán attention, không bỏ sót một liên kết nào, nhưng thay đổi cách dữ liệu di chuyển trong bộ nhớ GPU.

Vấn đề nó giải quyết: attention thông thường tạo ra ma trận n × n rồi ghi nguyên ma trận đó ra HBM - vùng nhớ lớn nhưng chậm của GPU - rồi đọc lại. Với n = 8192, ma trận đó là 64 triệu số cho mỗi head của mỗi lớp. Nút thắt cổ chai không nằm ở phép nhân, mà ở lưu lượng đọc/ghi bộ nhớ.

FlashAttention xử lý attention theo từng khối nhỏ nằm gọn trong SRAM - bộ nhớ nhanh, sát nhân tính toán - tính softmax theo kiểu tích luỹ dần, và không bao giờ vật chất hoá ma trận n × n đầy đủ.

Attention thường:  tính -> ghi ma trận n×n ra HBM -> đọc lại -> nhân với V
FlashAttention:    chia khối -> tính gọn trong SRAM -> chỉ ghi kết quả cuối

Kết quả:

  • nhanh hơn nhiều lần trong thực tế;
  • bộ nhớ giảm từ O(n²) xuống O(n);
  • kết quả giống hệt về mặt toán học, không phải xấp xỉ.

Đây là lý do FlashAttention gần như được bật mặc định ở mọi nơi hiện nay, trong khi các phương pháp attention xấp xỉ thời 2020 - Reformer với LSH hashing, Linformer, Performer - lại ít được dùng trong LLM sản xuất. Chúng vẫn thú vị về mặt ý tưởng, nhưng phần lớn đều đánh đổi chất lượng, còn FlashAttention thì không.

Bài học rộng hơn: trong deep learning hiện đại, rất nhiều nút thắt là băng thông bộ nhớ chứ không phải phép tính. Ý này sẽ quay lại ngay ở phần inference.


7.8 Mixture of Experts: tách rời kích thước khỏi chi phí

Cho tới giờ ta ngầm giả định mọi tham số của model đều tham gia vào mỗi token. Model như vậy gọi là dense.

Mixture of Experts phá vỡ giả định đó, và đây là kiến trúc đứng sau phần lớn các model tiền tuyến hiện nay.

Ý tưởng: thay khối FFN duy nhất trong mỗi block bằng nhiều FFN song song gọi là expert, cộng thêm một router nhỏ chọn ra vài expert cho mỗi token.

Dense                          MoE

token                          token
  |                              |
  v                              v
 FFN   (luôn dùng              router
        toàn bộ)                 |  chọn 2 trong 8
                        +--------+--------+
                        v        v        v
                      FFN1     FFN2 ...  FFN8
                        |        |
                        +---+----+
                            v
                     cộng có trọng số

Điểm mấu chốt là số tham số và chi phí tính toán được tách rời nhau:

Tổng tham số Tham số hoạt động mỗi token
Dense 8B 8B 8B
MoE 8×7B khoảng 47B khoảng 13B

Model chứa lượng tri thức tương ứng 47B tham số, nhưng mỗi token chỉ trả chi phí tính toán cỡ 13B.

Điều này ăn khớp trực tiếp với ý ở mục 5.12 - rằng FFN là nơi tri thức được cất giữ. MoE về bản chất nói: hãy có thật nhiều kho tri thức chuyên biệt, nhưng mỗi lần chỉ mở vài cái.

Cái giá phải trả, và đây là chỗ hay bị bỏ qua:

  • VRAM vẫn phải chứa toàn bộ expert, dù mỗi lượt chỉ dùng vài cái. MoE tiết kiệm phép tính, không tiết kiệm bộ nhớ.
  • Cần cân bằng tải giữa các expert, nếu không router sẽ dồn hết vào vài expert phổ biến.
  • Việc phục vụ mô hình phức tạp hơn hẳn, nhất là khi phải chia trên nhiều GPU.

Khi bạn thấy một model được quảng cáo “kích thước A nhưng nhanh như model nhỏ hơn nhiều”, gần như chắc chắn đó là MoE. Hãy đọc kỹ hai con số: tổng tham số quyết định VRAM cần có, tham số hoạt động quyết định tốc độ.

Còn positional encoding cho context dài - sinusoidal, learned, RoPE, ALiBi cùng các kỹ thuật nội suy để kéo dài context - đã được nói ở mục 5.13, vì đó là thành phần cốt lõi của kiến trúc chứ không phải một tối ưu thêm vào.


08Inference với LLM

Đây là phần cực kỳ quan trọng nếu mục tiêu của bạn là xây AI application.


8.1 Training vs Inference

Training:

data

forward pass

loss

backpropagation

update weights

Inference:

fixed weights
+
prompt

prediction

Generative inference:

prompt

predict next token

append

predict next token

append

...

8.2 Context Length

Context length là số token model có thể xử lý trong một lượt.

Context có thể gồm:

system prompt
+
conversation history
+
user input
+
retrieved documents
+
tool outputs
+
generated tokens

Mental model:

Context = working memory tạm thời của model trong request hiện tại.

Đây là nền tảng để học Context Engineering sau này.


8.3 Prompting thực chất là gì?

Prompting không phải phép thuật.

Một cách kỹ thuật hơn:

Prompt thay đổi input context, từ đó thay đổi hidden states và distribution của next token.

Pipeline:

INPUT TOKENS

Transformer

LOGITS

Probability distribution

NEXT TOKEN

Thay đổi prompt → distribution thay đổi → output thay đổi.


8.4 Hai phase của inference

Phase 1 – Prefill

Model xử lý toàn bộ prompt.

prompt

tokenization

tokens

Transformer

representations + KV cache

Toàn bộ prompt được xử lý song song trong một lượt, vì mọi token đã có sẵn.

Phase 2 – Decode

Sau đó model sinh từng token:

token 1

token 2

token 3

...

Decode là autoregressive: mỗi bước chỉ xử lý một token, và phải chờ bước trước xong mới chạy được.

Hai phase bị nghẽn ở hai chỗ hoàn toàn khác nhau

Đây là ý quan trọng nhất của cả mục này, và cũng là thứ giải thích gần như mọi hành vi hiệu năng bạn quan sát được.

Prefill Decode
Token xử lý mỗi lượt Cả nghìn Đúng một
Nghẽn ở Phép tính (compute-bound) Băng thông bộ nhớ (memory-bound)
GPU được tận dụng Gần như tối đa Rất thấp
Quyết định metric TTFT TPOT

Vì sao decode lại nghẽn ở bộ nhớ? Vì để sinh một token, GPU phải đọc toàn bộ trọng số model từ VRAM. Với model 70B ở FP16, đó là 140 GB dữ liệu phải chuyển qua bus bộ nhớ - chỉ để tạo ra đúng một token. Lượng phép tính thực sự thì nhỏ xíu.

Prefill:  nhiều phép tính  trên  một lượt đọc trọng số  ->  GPU bận rộn
Decode:   ít phép tính     trên  cùng lượt đọc đó       ->  GPU ngồi chờ bộ nhớ

Ba hệ quả rất thực tế:

  1. Mua GPU mạnh hơn về mặt tính toán thường không làm decode nhanh hơn bao nhiêu. Thứ cần nhìn là băng thông bộ nhớ, không phải TFLOPS.
  2. Đó là lý do batching hiệu quả đến vậy. Trọng số đã đọc lên rồi thì phục vụ 1 hay 32 request cùng lúc gần như tốn bằng nhau - xem mục 8.14.
  3. Đó cũng là lý do quantization tăng tốc độ. Trọng số nhỏ hơn nghĩa là ít byte phải đọc hơn ở mỗi bước - xem mục 8.15.

Nếu chỉ nhớ một câu từ phần inference: prefill là bài toán tính toán, decode là bài toán bộ nhớ. Gần như mọi kỹ thuật tối ưu serving đều bắt nguồn từ sự bất đối xứng này.


8.5 Logits

Transformer không trực tiếp “chọn từ”.

Nó sinh score cho vocabulary.

Ví dụ:

Paris      4.20
London     2.30
France     1.50
Berlin     1.40
... (còn lại toàn bộ vocabulary)

Các score thô này gọi là:

Logits

Một điểm hay bị bỏ qua: logits được sinh ra cho toàn bộ vocabulary, tức là vài chục nghìn tới vài trăm nghìn số cho mỗi bước sinh token. Ta chỉ nhìn thấy vài dòng đầu vì phần còn lại có điểm rất thấp.

Softmax biến chúng thành xác suất:

Paris     72%
London    11%
France     5%
Berlin     4%
phần còn lại của vocabulary    8%

Cách tính, nếu bạn muốn tự kiểm chứng:

exp(4.20) = 66.7      66.7 / 92.6 = 0.72
exp(2.30) = 10.0      10.0 / 92.6 = 0.11
exp(1.50) =  4.5       4.5 / 92.6 = 0.05
exp(1.40) =  4.1       4.1 / 92.6 = 0.04
phần đuôi =  7.3       7.3 / 92.6 = 0.08
                     -------
tổng      = 92.6

Chi tiết đáng chú ý: khoảng cách giữa các logit quan trọng hơn giá trị tuyệt đối của chúng, vì softmax lấy mũ rồi chuẩn hóa. Cộng cùng một hằng số vào mọi logit thì phân phối không đổi chút nào.

Đây cũng chính là lý do temperature ở mục sau hoạt động được: nó chia logits, tức là kéo giãn hoặc nén lại chính những khoảng cách đó.

Generation strategy sẽ quyết định token cuối cùng được chọn.


8.6 Temperature

Temperature điều chỉnh độ phân tán của distribution.

Low temperature

Paris 90%
London 5%
...

→ predictable hơn.

High temperature

Paris 45%
London 20%
Lyon 12%
...

→ diverse hơn.

Cơ chế thật sự

Temperature không phải một núm vặn huyền bí. Nó chỉ đơn giản là chia logits trước khi đưa vào softmax:

softmax(logits / T)

Nối lại với mục 8.5, nơi ta thấy rằng chỉ khoảng cách giữa các logit mới quan trọng:

T < 1   chia cho số nhỏ  ->  khoảng cách giãn ra  ->  phân phối nhọn hơn
T = 1   giữ nguyên       ->  đúng phân phối model đã học
T > 1   chia cho số lớn  ->  khoảng cách co lại   ->  phân phối phẳng hơn

Lấy lại ví dụ ở mục 8.5:

Logits:      Paris 4.20   London 2.30   France 1.50

T = 0.5      Paris  95%   London   1%   France   0%
T = 1.0      Paris  72%   London  11%   France   5%
T = 2.0      Paris  45%   London  17%   France  12%

Trường hợp đặc biệt T = 0 không thực sự chia cho 0 - các thư viện xử lý nó như greedy decoding: luôn chọn token có xác suất cao nhất.

Một điểm cần nói rõ, vì rất hay bị hiểu sai:

T = 0 cho kết quả ổn định, nhưng không đảm bảo đúng. Model vẫn có thể bịa ra thông tin sai một cách hoàn toàn tự tin - nó chỉ bịa cùng một câu mỗi lần. Temperature điều khiển độ đa dạng, không điều khiển tính chính xác.

Một nguyên tắc thực hành:

Loại task Temperature gợi ý
Trích xuất dữ liệu, phân loại, sinh JSON 0 – 0.3
Hỏi đáp thực tế, RAG 0.2 – 0.5
Hội thoại thông thường 0.7 – 0.9
Viết sáng tạo, brainstorm 0.9 – 1.2

Lưu ý cuối: temperature và top-p cùng tác động lên một phân phối. Chỉnh cả hai cùng lúc khiến hiệu ứng khó dự đoán. Thực hành phổ biến là cố định một cái và chỉ điều chỉnh cái còn lại.


8.7 Top-k

Giữ lại:

k token có probability cao nhất.

Ví dụ:

Vocabulary = 100,000

top_k = 5

Model chỉ sample trong 5 candidate đầu.


8.8 Top-p / Nucleus Sampling

Không cố định số candidate.

Lấy nhóm token nhỏ nhất sao cho cumulative probability đạt ngưỡng p.

Ví dụ:

Paris    .50
London   .20
Berlin   .12
Madrid   .08
Tokyo    .03

Với:

top_p = 0.9

nhóm candidate có thể là:

Paris + London + Berlin + Madrid

8.9 Presence và Frequency Penalty

Hai cách giảm repetition.

Presence penalty

Token đã xuất hiện → bị penalty.

Frequency penalty

Token xuất hiện càng nhiều → penalty càng mạnh.


8.10 EOS và giới hạn generation

Generation có thể dừng bởi:

  • max tokens;
  • stop sequence;
  • EOS token;
  • task-specific rule.

EOS:

End Of Sequence

~/diagrams/transformer-tu-a-den-z/llm-sampling-pipeline.htmltương tác
mở riêng ↗
HìnhToàn bộ quãng đường từ logits đến token tiếp theo: penalty và temperature nắn logits, softmax đổi chúng thành xác suất, top-k và top-p cắt bớt ứng viên, rồi sampling bốc ra một token. Token đó được nối vào chuỗi và vòng lặp chạy tiếp cho tới khi gặp điều kiện dừng.
biến đổi logitsbước xác suấtlọc và điều kiện dừng

Thay vì giữ một candidate duy nhất:

A

B

C

beam search giữ nhiều path:

        ┌ B → C
A ──────┼ D → E
        └ F → G

Sau đó giữ những sequence score tốt nhất.

Beam search phù hợp hơn trong một số bài toán structured generation hơn là chat sáng tạo.


8.12 Metric inference cần biết

Nếu bạn muốn làm AI Engineer, đây là những con số bạn sẽ phải nói tới hằng ngày.

TTFT – Time To First Token

Thời gian từ lúc gửi request tới khi token đầu tiên xuất hiện. Do prefill quyết định, nên nó tăng theo độ dài prompt.

Đây là metric người dùng cảm nhận rõ nhất: khoảng lặng trước khi chữ bắt đầu chạy ra. Prompt dài, RAG nhồi nhiều tài liệu, lịch sử hội thoại chưa được cắt bớt - tất cả đều đánh thẳng vào TTFT.

TPOT – Time Per Output Token

Thời gian sinh mỗi token sau token đầu tiên. Do decode quyết định, nên nó phụ thuộc băng thông bộ nhớ.

TPOT quyết định tốc độ chữ chạy ra. Khoảng 30 ms/token tương đương chừng 33 token/giây - nhanh hơn tốc độ đọc của phần lớn người dùng, nên thường đã là đủ.

Latency tổng

Hai metric trên gộp lại thành thời gian chờ thực sự:

Tổng thời gian = TTFT + (TPOT × số token sinh ra)

Ví dụ:  TTFT 400 ms,  TPOT 30 ms,  sinh 300 token

  400 ms + (30 ms × 300) = 9.4 giây

Một quan sát đáng giá: độ dài output ảnh hưởng tới thời gian chờ mạnh hơn độ dài input rất nhiều. Yêu cầu model trả lời ngắn gọn thường là cách tối ưu latency rẻ nhất mà ai cũng bỏ qua.

Throughput

Hệ thống phục vụ được bao nhiêu:

  • request mỗi giây;
  • token mỗi giây;
  • người dùng đồng thời.

Cần phân biệt rõ với latency, vì hai thứ này đánh đổi lẫn nhau: tăng kích thước batch thì throughput lên nhưng latency của từng request cũng dài ra.

VRAM Usage

Bộ nhớ GPU cần có, gồm ba phần:

Trọng số model     +     KV Cache     +     Bộ đệm hoạt động
   (cố định)          (theo số token)         (theo batch)

Người mới hay chỉ tính phần trọng số rồi ngạc nhiên khi gặp lỗi hết bộ nhớ lúc chạy. KV Cache mới thường là thứ quyết định bạn phục vụ được bao nhiêu người dùng đồng thời - mục kế tiếp sẽ tính cụ thể.


8.13 KV Cache

Autoregressive generation lặp lại rất nhiều.

Ví dụ:

Token 1
Token 2
Token 3
Token 4
...

Ở bước sinh token mới, model vẫn cần Attention tới token cũ.

Nếu cứ tính lại toàn bộ Key/Value quá khứ thì rất lãng phí.

KV Cache:

Past Keys / Values

CACHE

reuse at next decode step

Nó tiết kiệm được bao nhiêu?

Không có cache, mỗi bước decode phải tính lại K và V cho toàn bộ ngữ cảnh. Sinh n token thì tổng công việc tỉ lệ với .

Có cache, mỗi bước chỉ tính K/V cho đúng token mới, rồi ghép vào phần đã lưu:

Không cache:  bước thứ t tính lại K,V cho cả t token   ->  tổng O(n²)
Có cache:     bước thứ t chỉ tính K,V cho 1 token      ->  tổng O(n)

Với chuỗi vài nghìn token, khác biệt là hàng trăm lần. Không có KV Cache thì các chatbot LLM ngày nay đơn giản là không dùng được.

Cái giá: một công thức bạn nên thuộc

KV Cache đổi phép tính lấy bộ nhớ, và lượng bộ nhớ đó tính được chính xác:

Kích thước KV Cache
  = 2  ×  n_layers  ×  n_kv_heads  ×  head_dim  ×  n_tokens  ×  bytes_per_value

    ^
    2 vì phải lưu cả Key và Value

Thử với Llama-3-8B ở FP16, ngữ cảnh 8192 token:

n_layers    = 32
n_kv_heads  = 8        (GQA - nếu là MHA thì con số này là 32)
head_dim    = 128
n_tokens    = 8192
bytes       = 2        (FP16)

2 × 32 × 8 × 128 × 8192 × 2  =  1.07 GB

Hơn 1 GB VRAM cho một người dùng duy nhất. Phục vụ 50 người đồng thời là hơn 50 GB chỉ riêng cho cache - vượt cả phần bộ nhớ dành cho trọng số model.

Và đây là lúc mục 5.10 phát huy tác dụng: nếu model này dùng MHA thay vì GQA, n_kv_heads sẽ là 32 thay vì 8, và con số trên thành 4.3 GB.

GQA không phải chi tiết học thuật. Nó là khác biệt giữa việc phục vụ được 50 người dùng hay chỉ 12 người trên cùng một GPU.

Vì sao context dài lại đắt tới hai lần

Giờ ta có thể ghép các mảnh lại với nhau:

Chi phí Tăng theo Ảnh hưởng
Prefill attention O(n²) theo độ dài prompt TTFT chậm
KV Cache O(n) theo số token VRAM, giới hạn số người dùng đồng thời
Mỗi bước decode O(n) để quét cache TPOT tăng dần khi hội thoại dài ra

Đó là lý do một cuộc hội thoại dài vừa khởi động chậm hơn, vừa sinh chữ chậm hơn, vừa tốn nhiều bộ nhớ hơn - ba loại chi phí khác nhau chồng lên nhau.

Các kỹ thuật giảm nhẹ trong hệ thống serving thực tế:

  • PagedAttention (vLLM) - quản lý cache theo trang giống bộ nhớ ảo của hệ điều hành, giảm phân mảnh rất đáng kể;
  • Prefix caching - các hội thoại dùng chung system prompt thì dùng chung luôn phần cache đó;
  • Quantize KV cache - lưu cache ở INT8 thay vì FP16, giảm một nửa;
  • Cắt bớt cửa sổ - loại bỏ token cũ khỏi cache khi hội thoại quá dài.

8.14 Batching: vì sao phục vụ nhiều người lại gần như miễn phí

Quay lại chuyện decode nghẽn ở bộ nhớ chứ không phải ở phép tính. Hệ quả của nó khá phản trực giác.

Khi GPU đã đọc toàn bộ trọng số model lên để sinh một token, nó có thể sinh token cho nhiều request cùng lúc mà gần như không tốn thêm gì - vì trọng số đã nằm sẵn ở đó rồi.

Batch 1 request:    đọc 16 GB trọng số  ->  1 token
Batch 32 request:   đọc 16 GB trọng số  ->  32 token

Cùng lượng đọc bộ nhớ. Throughput gấp 32 lần.

Đây là lý do chi phí trên mỗi token của các nhà cung cấp API lại thấp đến vậy: họ gộp rất nhiều request của rất nhiều khách hàng vào cùng một batch.

Continuous batching đẩy ý tưởng này đi xa hơn. Batching kiểu cũ phải chờ cả batch cùng xong, nghĩa là một request ngắn bị kẹt sau một request dài. Continuous batching cho phép request mới nhảy vào ngay khi có chỗ trống:

Batching tĩnh        [====][====][====]   phải chờ request chậm nhất
Continuous batching  [==][======][===]    lấp chỗ trống ngay lập tức

Ranh giới của phương pháp: batch càng lớn thì KV Cache càng phình, và đến một ngưỡng nào đó bộ nhớ hết trước khi phép tính kịp bão hoà. Đó chính là lúc mọi con số ở mục 8.13 trở thành ràng buộc thật.


8.15 Quantization: đổi độ chính xác lấy tốc độ

Trọng số model thường được train ở FP16 hoặc BF16 - 2 byte mỗi số. Quantization lưu chúng ở độ chính xác thấp hơn.

Định dạng Byte/tham số Model 8B cần Ghi chú
FP16 / BF16 2 khoảng 16 GB Mặc định khi train
INT8 1 khoảng 8 GB Chất lượng gần như không đổi
INT4 0.5 khoảng 4 GB Giảm nhẹ, thường vẫn chấp nhận được

Vì decode nghẽn ở bộ nhớ, giảm một nửa số byte của trọng số thì gần như tăng gấp đôi tốc độ decode. Quantization vừa tiết kiệm VRAM vừa chạy nhanh hơn - hiếm khi có đánh đổi nào thuận lợi đến thế.

Đây chính là điều khiến việc chạy model trên laptop trở nên khả thi: một model 8B ở INT4 vừa vặn trong 4-5 GB.

Cần lưu ý: mức suy giảm chất lượng phụ thuộc mạnh vào phương pháp (GPTQ, AWQ, GGUF ở các mức khác nhau) và vào từng model cụ thể. Luôn đánh giá trên chính task của bạn thay vì tin vào benchmark chung.


8.16 Speculative decoding: đoán trước rồi kiểm tra

Một kỹ thuật thanh lịch, cũng sinh ra từ đúng sự bất đối xứng compute/memory ở trên.

Ý tưởng: dùng một model nháp nhỏ và nhanh để đoán trước vài token, rồi để model lớn kiểm tra tất cả trong cùng một lượt.

Model nháp (1B) đoán:     "thủ"  "đô"  "của"  "Pháp"
                             |      |     |      |
Model lớn (70B) kiểm tra:    v      v     v      v     trong MỘT lượt
                            OK     OK    OK     sai
                                                 |
                            giữ 3 token, sửa lại token thứ 4

Vì sao có lãi: kiểm tra 4 token cùng lúc tốn gần bằng sinh 1 token - lại vẫn là chuyện trọng số chỉ phải đọc một lần. Nếu model nháp đoán đúng phần lớn, ta được 2-3 token cho cái giá của một.

Điểm mấu chốt: kết quả về mặt phân phối là giống hệt với việc để model lớn tự sinh. Đây là tăng tốc thuần tuý chứ không phải xấp xỉ - chỉ những token được model lớn xác nhận mới được giữ lại.


8.17 Tự tay chạy thử: từ logits đến token

Toàn bộ mục 8.5 đến 8.8 gói lại chỉ trong chừng ba mươi dòng code. Chạy thử một lần sẽ giúp bạn nhớ lâu hơn hẳn so với việc chỉ đọc.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

name = "gpt2"
tok = AutoTokenizer.from_pretrained(name)
model = AutoModelForCausalLM.from_pretrained(name)

prompt = "The capital of France is"
ids = tok(prompt, return_tensors="pt").input_ids

with torch.no_grad():
    out = model(ids)

# Logits cho token TIẾP THEO: lấy ở vị trí cuối cùng của chuỗi
logits = out.logits[0, -1, :]          # kích thước: [vocab_size]
print("Kích thước vocabulary:", logits.shape[0])

# --- Temperature: chia logits (mục 8.6) ---
T = 0.8
scaled = logits / T

# --- Softmax: đổi thành xác suất (mục 8.5) ---
probs = torch.softmax(scaled, dim=-1)

# --- Xem 5 ứng viên hàng đầu ---
top = torch.topk(probs, 5)
for prob, idx in zip(top.values, top.indices):
    print("%-12s %.4f" % (tok.decode(idx), prob.item()))

# --- Top-p: giữ nhóm nhỏ nhất đạt ngưỡng tích luỹ (mục 8.8) ---
sorted_probs, sorted_idx = torch.sort(probs, descending=True)
cumulative = torch.cumsum(sorted_probs, dim=-1)
keep = cumulative <= 0.9
keep[0] = True                          # luôn giữ ít nhất một ứng viên

# --- Sampling: bốc ra một token ---
candidates = sorted_probs[keep]
chosen = torch.multinomial(candidates / candidates.sum(), 1)
next_id = sorted_idx[keep][chosen]

print("Token được chọn:", repr(tok.decode(next_id)))

Hai thí nghiệm đáng làm ngay:

  1. Đặt T = 0.1 rồi T = 2.0 và xem bảng xác suất thay đổi ra sao. Bạn sẽ thấy đúng hiện tượng đã mô tả ở mục 8.6.
  2. Chạy đoạn cuối vài lần liên tiếp. Với T cao, mỗi lần cho ra một token khác nhau - đó chính là lý do LLM không trả lời lặp lại y hệt.

Đây cũng chính là vòng lặp mà mọi hàm generate() thực hiện, chỉ khác là chúng lặp cho tới khi gặp EOS và có thêm KV Cache.


09Bias và limitations

Đây không phải phần “đạo đức phụ thêm”.

Đây là kiến thức production bắt buộc.

Model học từ dữ liệu.

Nếu dữ liệu chứa stereotype, model có thể internalize pattern đó.

Ví dụ kiểu:

This man works as a [MASK]

và:

This woman works as a [MASK]

có thể tạo ra phân phối nghề nghiệp khác nhau.

Điều này cho thấy:

Internet / corpus bias

Pretraining

Pretrained model

Fine-tuning

Application

User

Fine-tuning không tự động xóa bias từ pretrained model.


9.1 Hallucination: vì sao model bịa chuyện

Bias không phải giới hạn duy nhất, và hallucination mới là thứ bạn gặp hằng ngày. Điều đáng nói là nó không phải một lỗi - nó là hệ quả trực tiếp của cách model được huấn luyện.

Nhớ lại mục 5.4: model được train để dự đoán token tiếp theo có xác suất cao nhất. Nó chưa bao giờ được train để phân biệt “tôi biết điều này” với “tôi không biết điều này”.

Prompt:  "Bài báo về X do ... viết"

Model:   Cấu trúc câu này gần như luôn được nối tiếp
         bằng một cái tên. Vậy hãy sinh ra một cái tên
         nghe có vẻ hợp lý.

Kết quả là một câu trả lời trôi chảy, đúng ngữ pháp, tự tin và sai. Không có cơ chế nội tại nào bảo model dừng lại.

Vài hệ quả thực dụng:

  • Model tự tin nhất ở đúng những chỗ nó sai nhiều nhất - sự kiện hiếm, tên riêng, con số, trích dẫn, ngày tháng.
  • Bảo model “đừng bịa” chỉ có tác dụng hạn chế. Bạn đang yêu cầu nó làm một việc mà kiến trúc của nó không hỗ trợ.
  • RAG có tác dụng vì nó đổi bản chất bài toán - từ “nhớ lại từ tham số” thành “đọc từ ngữ cảnh”. Đó là lý do RAG là chủ đề tiếp theo tự nhiên sau bài này.

9.2 Những giới hạn khác đáng biết trước khi lên production

Giới hạn Biểu hiện Hướng xử lý
Cắt mốc tri thức Không biết gì sau ngày ngừng thu thập dữ liệu RAG, tool calling, tìm kiếm web
Lost in the middle Thông tin nằm giữa context dài dễ bị bỏ sót hơn ở đầu và cuối Đặt nội dung quan trọng ở đầu hoặc cuối prompt
Nhạy cảm với cách diễn đạt Đổi vài chữ trong prompt làm output khác hẳn Cố định prompt, đánh giá bằng bộ test có sẵn
Không xác định Cùng input cho ra output khác nhau Đặt temperature = 0 khi cần lặp lại được
Yếu ở tính toán chính xác Sai số học, đếm sai (xem lại mục 2.4) Giao cho công cụ ngoài, đừng để model tự tính
Sycophancy Đổi câu trả lời khi người dùng phản đối Hỏi trung lập, tránh dẫn dắt
Injection qua prompt Nội dung người dùng đưa vào bị model coi là chỉ dẫn Tách rõ chỉ dẫn với dữ liệu, kiểm tra đầu vào

9.3 Kiểm tra bias một cách cụ thể

Nói “cần đánh giá bias” thì dễ, nhưng đây là những việc làm được ngay:

Kiểm thử đối xứng. Chạy cùng một prompt nhưng hoán đổi các thuộc tính nhân khẩu, rồi so sánh output:

"Bạn có duyệt khoản vay này cho Nguyễn Văn A không?"
"Bạn có duyệt khoản vay này cho Nguyễn Thị B không?"

Mọi thông tin khác giữ nguyên hoàn toàn.
Output khác nhau đáng kể = có tín hiệu bias.

Kiểm tra độ ổn định trên các biến thể. Diễn đạt lại cùng một câu hỏi theo 5-10 cách và đo mức dao động của kết quả.

Đánh giá theo lát cắt. Đừng chỉ nhìn độ chính xác tổng thể - hãy tách theo nhóm người dùng, theo chủ đề, theo ngôn ngữ. Một model đạt 90% tổng thể vẫn có thể chỉ đạt 60% trên một phân khúc quan trọng.

Bộ test hồi quy. Giữ một tập ví dụ cố định phản ánh đúng phạm vi sử dụng của bạn, và chạy lại nó mỗi lần đổi model, đổi prompt hay đổi phiên bản.


9.4 Vì sao đây là chuyện của kỹ sư, không chỉ của bộ phận tuân thủ

Một hệ thống production cần các lớp bảo vệ mà bản thân model không cung cấp:

Đánh giá             đo chất lượng trên chính task của bạn, không phải benchmark chung
Guardrails           lọc đầu vào và đầu ra, giới hạn phạm vi hành động
Trích dẫn            buộc câu trả lời phải dẫn về nguồn kiểm chứng được
Giám sát             theo dõi chất lượng theo thời gian, không chỉ latency
Con người tham gia   xem xét thủ công ở các quyết định rủi ro cao
Đường lùi            kịch bản xử lý khi model từ chối hoặc trả lời sai

Một mental model đáng nhớ: LLM là một thành phần có xác suất nằm trong một hệ thống tất định. Toàn bộ công việc kỹ thuật nằm ở phần bao quanh nó - ràng buộc, kiểm chứng, và xử lý khi nó sai.


10Tóm tắt toàn bộ Transformer trong một mental model

Nếu phải gói toàn bộ bài này thành một sơ đồ:

~/diagrams/transformer-tu-a-den-z/transformer-mental-model.htmltương tác
mở riêng ↗
HìnhToàn bộ bài gói lại: Attention cho biểu diễn có ngữ cảnh, pretraining tách thành ba mục tiêu khác nhau (MLM, CLM, denoising), từ đó ra ba họ kiến trúc, ba nhóm checkpoint tiêu biểu và ba nhóm task tương ứng.
cơ chế cốt lõi và pretrainingba họ kiến trúcnhóm task

Còn với generative inference:

PROMPT

TOKENIZER

PREFILL

ATTENTION

LOGITS

TEMPERATURE / TOP-P / TOP-K

NEXT TOKEN

KV CACHE

NEXT TOKEN

...

Nếu hai sơ đồ trên đã trở nên trực quan trong đầu bạn, nghĩa là bạn đã có nền tảng Transformer khá tốt.


Kết luận

Transformer không chỉ là một kiến trúc neural network cần học thuộc.

Nó là nền móng giúp bạn hiểu gần như mọi khái niệm quan trọng của Generative AI hiện đại:

  • token;
  • context;
  • attention;
  • inference;
  • embeddings;
  • generation;
  • long context;
  • KV Cache;
  • RAG;
  • Agents.

Khi bạn hiểu rõ Transformer, những chủ đề phía sau như RAG hay Agents sẽ bớt mang cảm giác “black box” rất nhiều.

Và đó mới là mục tiêu quan trọng nhất của việc học Transformer: không phải nhớ công thức, mà là xây được một mental model đủ tốt để khi gặp một hệ thống GenAI mới, bạn có thể tự hỏi:

Input được biểu diễn thế nào? Model nhìn context ra sao? Nó đang hiểu, transform hay generate? Inference tốn ở đâu? Và limitation thực sự nằm ở tầng nào?

Nếu trả lời được những câu hỏi đó, bạn đã đi qua bước nền tảng quan trọng nhất để bước vào AI Engineering.


Đọc tiếp

Những nguồn dưới đây là nơi tôi khuyên bạn đi tiếp, xếp theo thứ tự nên đọc.

Bài báo gốc

Đi sâu vào từng cơ chế

Tài liệu học

  • The Illustrated Transformer - bản giải thích bằng hình ảnh kinh điển của Jay Alammar.
  • Hugging Face NLP Course - miễn phí, thực hành nhiều, đi kèm code chạy được.
  • Let’s build GPT - Andrej Karpathy viết một Transformer từ con số không. Nếu chỉ chọn được một tài nguyên, hãy chọn cái này.
  • Tokenizer Playground - dán văn bản tiếng Việt vào để tự thấy chi phí token đã nói ở mục 2.3.

Trong series này

Bài tiếp theo sẽ đi vào RAG - cách đưa tri thức bên ngoài vào context để xử lý đúng hai vấn đề hallucination và cắt mốc tri thức đã bàn ở mục 9.1 và 9.2.

Trương Đức Dũng

AI Engineer - Hà Nội

Tập trung vào LLM, RAG và các hệ thống AI cần chạy ổn định trong môi trường vận hành thật.