Giới thiệu bài lab
Bài Lab tổng hợp: huấn luyện một LLM thu nhỏ bằng NumPy, từ dữ liệu đến checkpoint và suy luận
Sơ đồ ở Tab 01 cho biết các ô huấn luyện nối với nhau thế nào; bài lab này cho bạn thấy mỗi ô tính ra con số gì. Một chương trình Python dùng NumPy (thư viện tính trên mảng số) chạy ngay trong trình duyệt và huấn luyện một mô hình ngôn ngữ rất nhỏ, gồm 5856 tham số (mỗi tham số là một con số mô hình học được) và từ vựng 23 token, qua 13 giai đoạn khớp với các ô 1A đến 5C.
Bạn cần bài lab vì đọc về loss, gradient hay LoRA chưa đủ để biết mô tả có đúng. Khi tự thấy loss lúc chưa huấn luyện là 3.2481 và sau 300 bước huấn luyện xuống 0.1014, bạn mới nắm được loss giảm nghĩa là gì và giảm bao nhiêu.
Bài lab gồm
- Một bảng ánh xạ 13 hàng: mỗi giai đoạn của lab khớp ô nào ở Tab 01, bài học nào, lab dựng gì và kiểm chứng gì.
- Mục Hướng dẫn đọc output gồm năm phần gấp lại: bạn sẽ học gì, đầu vào và cấu hình, bảng ánh xạ bằng lời, cách đọc từng khối output, và kết quả chứng tỏ gì cùng giới hạn của nó.
- Trình chạy trực tiếp cho file
training-end-to-end.py: bạn sửa được mã, chạy lại, và nhận output gồm phần mở đầu, 13 khối[n · Tên]rồi dòng TỔNG KẾT. - Dữ liệu tự viết vài chục ký tự, một mô hình 2 lớp với chiều ẩn d = 16 (mỗi vector có 16 số) và seed 7 cố định, nên chạy lại cho đúng các số cũ.
- Các hằng số ở đầu file để thử, như
STEPS,LR,ZERO_WORKERS,MASK_RESPONSE_ONLY,LORA_RANK,DISTILL_T,DPO_BETA; bảy bài tập có đáp án nằm ở trang bài đọc Lab đầy đủ.
Làm xong, bạn có thể
- Đọc từng khối output và nói con số nào chứng tỏ điều gì, ví dụ loss ban đầu 3.2481 gần ln 23 = 3.1355 (logarit tự nhiên của 23, mức loss khi đoán đều trên 23 token) vì mô hình chưa học.
- Giải thích vì sao gradient tính bằng công thức có thể được kiểm tra bằng sai phân hữu hạn: dịch một tham số một chút rồi đo loss đổi bao nhiêu.
- Dự đoán, chạy rồi giải thích kết quả khi đổi một hằng số, ví dụ giảm
STEPStừ 300 xuống 50 hay tăngLRtừ 0.01 lên 0.3. - Phân biệt SFT, LoRA, distillation và DPO bằng số cụ thể: số câu trả lời đúng, tỉ lệ tham số học được (LoRA là 18.6%) và độ lệch so với mô hình lớn.
- Nêu điều lab không chứng minh: chất lượng ngôn ngữ, tốc độ hay bộ nhớ trên GPU thật, và việc LoRA hay distillation tốt hơn ở mô hình thật.
Phạm vi: lab huấn luyện một mô hình văn bản thu nhỏ trên dữ liệu tự viết, không dùng ảnh hay âm thanh, và dòng PASS chỉ nói các phép kiểm tra cơ chế đạt chứ không nói mô hình trả lời giỏi hay chạy nhanh. Muốn xem kiến trúc đa phương thức, đọc bài Text-only / multimodal của LLM Foundations.
Cách dùng bài lab
- Đọc bảng ánh xạ bên dưới: mỗi hàng là một giai đoạn, cho biết ô tương ứng ở Tab 01, bài học (bấm để mở), lab dựng gì và kiểm chứng gì. Giai đoạn
3gộp các ô2Ađến2D, giai đoạn7gộp3Evà4C. - Mở mục Hướng dẫn đọc output, nhất là Đầu vào và cấu hình thu nhỏ của bài lab, để biết dữ liệu, mô hình và các hằng số là gì trước khi chạy.
- Dự đoán trước khi bấm Chạy: loss lúc chưa huấn luyện là bao nhiêu nếu mô hình đoán đều trên 23 token, và sau 300 bước loss kiểm định cao hơn hay thấp hơn loss huấn luyện. Viết dự đoán ra giấy.
- Bấm Chạy (mất vài giây). Đọc từng khối theo bảng: dòng Quan sát trước, đối chiếu các con số, rồi mới đọc Kết luận và Không chứng minh. Mốc kiểm tra nhanh: từ vựng 23 token, 5856 tham số, loss ban đầu 3.2481, và cuối cùng là dòng PASS.
- Sửa một hằng số ở đầu file, dự đoán kết quả, chạy lại và giải thích; sau đó đối chiếu với đáp án của bài tập ở trang bài đọc Lab đầy đủ, nút ở thanh phía trên bảng.
Bạn chạy lại bao nhiêu lần cũng được: seed 7 cố định nên cùng một cấu hình cho đúng các số cũ, nên mọi thay đổi trong output đến từ chỗ bạn vừa sửa.
| Giai đoạn | Ô | Bài học (bấm để mở) | Lab NumPy dựng gì (training-end-to-end.py) | Cách đọc số liệu & phép kiểm chứng |
|---|---|---|---|---|
| 1 | 1A | Dữ liệu → token IDs ↗ | Làm sạch 11 dòng thô còn 8 tài liệu, tokenizer theo ký tự (23 token), đóng gói batch 4 tài liệu. | Tài liệu đầu thành 11 ID kết thúc bằng eos; một batch có 63 vị trí; 2 bước là một epoch. |
| 2 | 1B | Next-token targets ↗ | Dịch nhãn đi một vị trí và dựng mặt nạ nhân quả cắt theo ranh giới từng tài liệu. | Tài liệu 11 token cho 10 cặp (input, nhãn); tài liệu sau không nhìn thấy tài liệu trước (False). |
| 3 | 2A–2D | Forward: embedding, attention, MLP, norm → logits ↗ | Embedding, attention một head có mặt nạ nhân quả, SwiGLU, RMSNorm, residual và đầu ra logits; 2 lớp, d = 16. | Attention ở vị trí 3 chỉ có 4 phần tử khác 0, tổng 1; đổi token cuối không đổi logits phía trước (0.0); logits shape (10, 23). |
| 4 | 3A | Cross-entropy loss ↗ | Softmax, trừ ln p của token đúng, trung bình trên các vị trí được chấm. | Loss ban đầu 3.2481 gần ln 23 = 3.1355 vì mô hình chưa học. |
| 5 | 3B–3C | Backward & gradient từng lớp ↗
Đọc thêm: Gradient từng lớp | Gradient giải tích cho 16 tensor, gom theo lớp, kèm kiểm tra bằng sai phân hữu hạn. | Gradient theo logits tổng mỗi hàng bằng 0; khớp sai phân hữu hạn (sai lệch cỡ 5e-10); lớp 0 là 0.9951, lớp 1 là 0.6791. |
| 6 | 3D | AdamW ↗ | AdamW viết tay với m, v, hiệu chỉnh ở các bước đầu và suy giảm trọng số tách riêng. | Bước đầu mỗi tham số đổi 0.0098 đến 0.0101 khi lr = 0.01; tính tay khớp mã; loss một bước 3.2746 xuống 2.8802. |
| 7 | 3E, 4C | Vòng lặp, eval, checkpoint ↗
Đọc thêm: Pretraining | 300 bước với batch 4 tài liệu, đánh giá mỗi 50 bước, lưu checkpoint weights-only và checkpoint tiếp tục được. | Loss huấn luyện 0.1014; loss kiểm định thấp nhất 0.8048 rồi 1.0469; checkpoint đầy đủ gấp 2.96 lần bản weights-only; chạy tiếp từ bản đầy đủ lệch 0.0. |
| 8 | 4A–4B | Bộ nhớ: ZeRO & recompute ↗
Đọc thêm: Recompute | Đếm byte (16 mỗi tham số) cho data parallel và ZeRO-1/2/3; chia dữ liệu và trạng thái AdamW cho 2 worker; tính lại activation từng lớp khi backward. | ZeRO-3 còn 46848 byte mỗi worker; cập nhật chia và gradient tính lại lệch 0.0; 7 tỉ tham số trên 8 GPU từ 112 xuống 14 GB (tính tay, không đo). |
| 9 | 1C, 4D | SFT: chat template + response mask ↗ | Mẫu hội thoại có token user và assistant, mặt nạ chỉ chấm câu trả lời; 150 bước từ checkpoint nền. | Từ 0 trên 8 lên 8 trên 8 câu đúng, loss 4.1347 xuống 0.0036; loss trên token prompt 3.8980 lên 5.0391; câu chưa gặp vẫn được trả lời bằng câu của cặp khác. |
| 10 | 4E | LoRA ↗ | Cặp adapter A, B hạng 2 trên 14 ma trận, B khởi tạo bằng 0, có thể gộp vào trọng số gốc. | 1088 tham số học được (18.6%); trọng số gốc lệch 0.0; gộp và chưa gộp cho cùng logits (cỡ 1e-14); 8 trên 8 câu đúng. |
| 11 | 4F | Distillation ↗
Đọc thêm: Response distillation | Student (d = 8, 1 lớp) học loss T² nhân KL với soft target của teacher ở T = 2. | KL 0.0068 và 8 trên 8 câu đúng, so với 0.1955 và 5 trên 8 khi chỉ học nhãn cứng; gradient KL khớp sai phân hữu hạn. |
| 12 | 4G | Preference (DPO) ↗ | Loss DPO với mô hình tham chiếu đóng băng trên 6 cặp (chosen, rejected), β = 0.5. | Khi policy bằng tham chiếu loss đúng ln 2 = 0.6931; sau 60 bước biên 8.317 nhưng xác suất câu chosen của cặp đầu lại giảm từ 0.982 xuống 0.520. |
| 13 | 5A–5C | Từ checkpoint sang suy luận ↗ | Nạp checkpoint weights-only, đổi prompt thành token ID, prefill một lượt rồi decode với KV cache và giải mã văn bản. | Logits có cache khớp tính lại (cỡ 1e-15); 17 vị trí xử lý so với 75; đầu ra sua.; nạp nhầm checkpoint cùng cấu hình không báo lỗi. |
Hướng dẫn đọc output
Bạn sẽ học được gì?
Sau bài lab, bạn giải thích được bằng số cụ thể mười điều: (1) văn bản trở thành token ID và batch ra sao; (2) vì sao mỗi chuỗi tự sinh ra các bài toán dự đoán token kế tiếp; (3) forward đi qua embedding, attention, MLP và norm tới logits như thế nào; (4) cross-entropy loss nén bảng điểm thành một số ra sao; (5) backward cho gradient từng lớp và vì sao có thể kiểm chứng bằng sai phân hữu hạn; (6) AdamW đổi gradient thành bước cập nhật thế nào; (7) vòng lặp, đánh giá và checkpoint làm gì; (8) ZeRO và recompute tiết kiệm bộ nhớ mà không đổi toán học; (9) SFT, LoRA, distillation và DPO khác nhau ở phần nào của vòng huấn luyện; (10) checkpoint trở thành suy luận prefill rồi decode với KV cache ra sao.
Bạn không cần biết trước về học máy. Mỗi thuật ngữ được giải thích ở chỗ nó xuất hiện đầu tiên; bạn chỉ cần đọc được Python và biết một mảng NumPy có shape, ví dụ (10, 16) là 10 hàng, mỗi hàng 16 số.
Đầu vào và cấu hình thu nhỏ của bài lab
Dữ liệu do tác giả tự viết, không tải từ đâu. Kho huấn luyện nền gồm 11 dòng thô như "Meo an ca.", một dòng trống và hai dòng trùng; sau khi làm sạch còn 8 tài liệu. Tập kiểm định (validation: dữ liệu chỉ dùng để đo, không dùng để cập nhật) có 2 câu chưa gặp: "cho an ca." và "meo uong nuoc.". Dữ liệu SFT là 8 cặp hỏi đáp như "meo an gi" và "ca."; dữ liệu ưu tiên là 6 bộ (câu hỏi, câu được chọn, câu bị loại) như "meo an gi", "ca.", "sua.".
Mô hình là một bộ giải mã Transformer với 2 lớp, 1 head attention (head: một nhóm tính attention độc lập; ở đây chỉ có một nên head dùng toàn bộ chiều ẩn), chiều ẩn d = 16, mạng truyền thẳng SwiGLU (mạng mở rộng chiều rồi lọc bằng một cổng) rộng 32, RMSNorm (chuẩn hóa biên độ vector) và mã hóa vị trí cố định. Tokenizer tách theo ký tự nên từ vựng chỉ có 23 token: 19 ký tự cộng 4 token đặc biệt là pad (đệm), eos (kết thúc), user và assistant (đánh dấu lượt nói). Tổng cộng 5856 tham số, khởi tạo ngẫu nhiên với seed 7 nên chạy lại cho đúng các số cũ.
Các hằng số ở đầu file (STEPS, LR, ZERO_WORKERS, MASK_RESPONSE_ONLY, LORA_RANK, DISTILL_T, DPO_BETA và các hằng khác) là những núm bạn sẽ xoay ở phần bài tập. Chạy một lần mất vài giây trong trình duyệt.
Bảng ánh xạ giữa sơ đồ Tab 01 và 13 giai đoạn của lab
Giai đoạn 1 Dữ liệu → token IDs (ô 1A) = clean_corpus, encode_text và pack_lm; giai đoạn 2 Next-token targets (ô 1B) = cách pack_lm dịch nhãn và dựng mặt nạ; giai đoạn 3 Forward (ô 2A đến 2D) = block_forward và forward; giai đoạn 4 Cross-entropy loss (ô 3A) = cross_entropy; giai đoạn 5 Backward & gradient từng lớp (ô 3B, 3C) = block_backward, backward và check_gradients; giai đoạn 6 AdamW (ô 3D) = adamw_update; giai đoạn 7 Vòng lặp, eval, checkpoint (ô 3E, cùng ô 4C pretraining) = train_lm, save_checkpoint và load_checkpoint.
Giai đoạn 8 Bộ nhớ: ZeRO & recompute (ô 4A, 4B) = zero_bytes cùng hai phép mô phỏng chia dữ liệu và chia trạng thái AdamW, và nhánh backward tính lại từng lớp; giai đoạn 9 SFT (ô 1C, 4D) = chat_ids và pack_sft; giai đoạn 10 LoRA (ô 4E) = các cặp adapter A, B và hàm merged; giai đoạn 11 Distillation (ô 4F) = distill_loss_grad; giai đoạn 12 Preference (DPO) (ô 4G) = seq_logp_and_dlogits và dpo_grads; giai đoạn 13 Từ checkpoint sang suy luận (ô 5A đến 5C) = step_forward trên checkpoint nạp lại. Tên giai đoạn trong output khớp tên ô trên sơ đồ.
Cách thực hiện và đọc từng khối output
1. Trước khi bấm Chạy, hãy dự đoán: loss lúc chưa huấn luyện là bao nhiêu nếu mô hình đoán đều trên 23 token (gợi ý: ln 23)? Sau 300 bước, loss kiểm định sẽ thấp hơn hay cao hơn loss huấn luyện, và vì sao? Viết dự đoán ra giấy.
2. Bấm Chạy. Ở khối 1 và 2, đọc bảng từ vựng, các ID của tài liệu đầu và cặp input, nhãn: nhãn luôn là token đứng ngay sau input. Ở khối 3, tìm hàng attention chỉ có 4 phần tử khác 0, phép thử đổi token cuối cho sai lệch 0.0 và so shape (10, 16) của x với (10, 23) của logits. Ở khối 4, nhìn từng giá trị trừ ln p ở bốn vị trí đầu rồi so trung bình với ln 23.
3. Ở khối 5, đọc sai lệch giữa gradient giải tích và sai phân hữu hạn; ở khối 6, theo dõi một tham số cụ thể từ gradient g qua m, v tới bước cập nhật và so với SGD. Ở khối 7, đọc bảng loss theo bước: hai cột loss huấn luyện và loss kiểm định có đi cùng nhau không; rồi so lần chạy tiếp từ checkpoint đầy đủ (lệch 0.0) với lần chỉ nạp trọng số.
4. Ở khối 8, tự tính trước byte mỗi worker rồi đối chiếu ba dòng ZeRO và các sai lệch bằng 0. Ở khối 9, nhìn mặt nạ loss của cặp đầu và hai con số loss trên token câu trả lời với token prompt. Ở khối 10 đến 12, so số tham số học được, số câu đúng và các sai lệch kiểm tra; ở khối 12, đọc cả xác suất của câu chosen lẫn câu rejected chứ không chỉ biên.
5. Ở khối 13, đối chiếu ID của prompt, shape của KV cache, số vị trí có cache so với tính lại và dòng nạp nhầm checkpoint. Cuối cùng, đối chiếu dự đoán ban đầu với kết quả rồi làm các bài tập: sửa một hằng số ở đầu file, dự đoán, chạy lại và giải thích.
Kết quả này chứng tỏ điều gì và giới hạn ở đâu?
Các phép kiểm tra trong lab xác nhận, cho đúng mô hình và dữ liệu này: gradient giải tích khớp sai phân hữu hạn trong 1e-6 ở mọi tensor, cả với loss KL của distillation và loss DPO; gradient cả batch bằng tổng gradient từng worker; cập nhật AdamW chia theo ZeRO-1 giống hệt cập nhật không chia; gradient tính lại từng lớp giống hệt gradient lưu đầy đủ; mô hình LoRA gộp và chưa gộp cho cùng logits; trọng số gốc không đổi khi huấn luyện LoRA; logits có KV cache khớp logits tính lại cả chuỗi (sai lệch cỡ 1e-15, chặn trên 1e-9).
Lab không chứng minh: chất lượng ngôn ngữ (dữ liệu chỉ vài chục ký tự, câu trả lời được học thuộc); khả năng trả lời câu hỏi chưa gặp (xem câu meo bay o dau ở khối 9); tốc độ hay bộ nhớ đỉnh trên GPU thật (ZeRO chỉ là phép chia mảng và đếm byte trong một tiến trình, recompute chỉ so gradient); LoRA hay distillation tốt hơn tinh chỉnh toàn bộ ở mô hình thật (kết quả chỉ trên 8 cặp và một seed); và RLHF với dữ liệu ưu tiên của con người (DPO ở đây chỉ có 6 cặp tự viết).
Nguồn công bố tham chiếu
Danh sách bài học (25)
- Lab tổng hợp LLM Training · huấn luyện một LLM thu nhỏ từ dữ liệu đến checkpoint và suy luận bằng NumPy
- Chuẩn bị dữ liệu để huấn luyện dự đoán token kế tiếp
- Tạo câu hỏi và đáp án cho mỗi vị trí trong chuỗi
- Hàm mất mát: model gán bao nhiêu xác suất cho đáp án đúng
- Tính gradient để biết tham số cần thay đổi ra sao
- AdamW: cập nhật tham số từ gradient
- Vòng huấn luyện, đánh giá và lưu trạng thái tiếp tục
- Chuẩn hóa vector và đường cộng residual trong transformer
- Query, key và value kết hợp context như thế nào
- Mạng truyền thẳng và cổng kích hoạt sau attention
- Chia trạng thái huấn luyện để giảm bộ nhớ mỗi worker
- Tính lại biểu diễn trung gian để tiết kiệm memory training
- Bước training: forward từ token đến điểm số
- Bước inference: tiếp nhận prompt và yêu cầu sinh
- Bước inference: chuyển prompt thành mã token
- Bước inference: xử lý prompt và chọn token đầu tiên
- Bước inference: vòng sinh và bổ sung context
- Bước inference: kết thúc và trả văn bản
- Gradient đi qua một lớp transformer
- Pretraining và continued pretraining · học nền tảng rồi học tiếp
- Fine-tuning (SFT) · dạy tiếp model đã học bằng cặp yêu cầu – trả lời mẫu
- LoRA / QLoRA · học một cặp ma trận nhỏ thay vì sửa toàn bộ trọng số
- Knowledge distillation · model nhỏ học từ tín hiệu của model lớn
- Response / sequence distillation · fine-tune student trên câu trả lời của teacher
- Preference training · dạy model ưu tiên câu trả lời tốt hơn (reward model, PPO, DPO)