Bỏ qua tới nội dung chính
OpenArchLabOpen Architecture — From Models to Systems

Giới thiệu bài lab

Bài Lab tổng hợp: theo dõi một yêu cầu qua 13 khối của đường ống phục vụ LLM bằng NumPy

Sơ đồ ở Tab 01 cho biết hệ thống phục vụ có những khối nào; bài lab này chạy một bản thu nhỏ của chúng để bạn thấy mỗi khối nhận, đổi và đưa 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: năm yêu cầu A đến E đi qua cổng, tokenizer, bộ lập lịch, prefill, KV cache, decode và bộ chọn token, và bạn theo dõi kỹ yêu cầu C.

Bạn cần bài lab vì đọc từng bài riêng khó thấy các khối làm một yêu cầu chậm đi hay bị từ chối ra sao. Ví dụ C mất 22.00 ms mô phỏng để nhận token đầu tiên, và lab tách con số đó thành ba phần để bạn thấy phần nào lớn nhất.

Bài lab gồm

  • Một bảng ánh xạ 13 hàng: mỗi khối của lab khớp ô nào ở Tab 01, bài 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 inference-end-to-end.py: mô hình 1 lớp với 2 head attention, từ vựng 22 token, KV cache 12 block; output gồm 13 khối [n · Tên] rồi dòng TỔNG KẾT.
  • Đồng hồ mô phỏng cho TTFT, TPOT và throughput (số token sinh ra mỗi giây), dựng từ các hằng số chi phí giả định COST_* ở đầu file.
  • Các hằng số để thử, như SLOTS, QUEUE_LIMIT, TOKEN_BUDGET, BLOCK_SIZE, POOL_BLOCKS, QUANT_BITS; sáu bài tập có đáp án nằm ở trang bài đọc Lab đầy đủ.

Làm xong, bạn có thể

  • Giải thích vì sao yêu cầu D bị từ chối với mã 429 (quá tải) ở cổng còn E bị chặn với mã 400 (yêu cầu vượt giới hạn) ở bước chuẩn bị đầu vào.
  • Phân biệt trọng số attention (chia theo các vị trí đã thấy, tổng bằng 1) với xác suất từ vựng (chia theo các token ứng viên, tổng bằng 1).
  • Tách TTFT của C thành chuẩn bị đầu vào 0.65 ms, chờ chỗ chạy 14.55 ms và prefill 6.80 ms, rồi chỉ ra thành phần lớn nhất.
  • Nói KV cache giúp tính 41 vị trí thay vì 197, và vì sao đó là số phép tính chứ chưa phải thời gian tiết kiệm.
  • Nêu điều lab chứng minh (cache cho cùng kết quả với tính lại) và không chứng minh (tốc độ GPU thật, p95 hay p99, chất lượng ngôn ngữ).

Phạm vi: lab chạy một mô hình sinh văn bản thu nhỏ với trọng số ngẫu nhiên chưa huấn luyện, nên văn bản sinh ra không có nghĩa. Token, byte, block và sai số là kết quả tính thật, còn mọi số ms là đồng hồ mô phỏng theo chi phí giả định, không phải tốc độ GPU thật; router, xác thực, hủy yêu cầu, prefix cache, preemption và nhiều GPU không được mô phỏng.

Cách dùng bài lab

  1. Đọc bảng ánh xạ bên dưới: khối 1 đến 13 của lab khớp các ô ở Tab 01, ví dụ khối 3 Iteration scheduler khớp ô L2·1. Khối 1 đến 8 theo thứ tự thời gian của một yêu cầu; khối 9 đến 13 đi kèm: nén trọng số, ngân sách bộ nhớ, số đo, so sánh chính sách lập lịch và cổng chất lượng.
  2. 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 năm yêu cầu A đến E là gì, engine có 2 chỗ chạy cùng lúc và 1 chỗ chờ, mỗi bước xử lý tối đa 6 token.
  3. Dự đoán trước khi bấm Chạy: yêu cầu nào bị từ chối và vì sao, C có phải chờ lâu không. Viết dự đoán ra giấy.
  4. 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. Mốc kiểm tra nhanh: D bị 429, E bị 400, TTFT của C là 22.00 ms mô phỏng, và cuối cùng là dòng PASS.
  5. Khi đọc một số ms, nhớ đó là đồng hồ mô phỏng; số token, byte, block và sai số là tính thật. Dòng PASS chỉ báo các phép kiểm tra cơ chế đạt, như cache khớp tính lại, chứ không đo tốc độ.
  6. 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.

Mỗi yêu cầu có seed riêng và trọng số dùng seed 7, nên chạy lại cho đúng các số cũ.

BẢNG ÁNH XẠ · MỖI KHỐI KIẾN TRÚC Ở TAB 01 ĐƯỢC DỰNG VÀ KIỂM CHỨNG TRONG LAB NHƯ THẾ NÀO?
Khối Thành phần ở Tab 01 (bấm để mở bài) Lab NumPy dựng gì (inference-end-to-end.py) Cách đọc số liệu & phép kiểm chứng
1 Gateway & admission ↗ Hàm admit: cổng chỉ cho tối đa 2 chạy + 1 chờ yêu cầu có mặt trong hệ thống và từ chối bằng mã 429 khi đầy. offered = served + rejected (5 = 3 + 2); D nhận 429 vì lúc xét đã có 3 yêu cầu.
2 Input preparation ↗ BPE 10 phép gộp học từ 5 câu mẫu, thêm token bos, rồi kiểm tra prompt + max_new <= 24. C thành 9 token ID; E bị chặn mã 400 vì 8 + 30 = 38 > 24.
3 Iteration scheduler ↗ Vòng lặp theo bước: nhận yêu cầu khi có chỗ trống, decode trước, chia prompt theo ngân sách 6 token mỗi bước. 12 bước; prompt của C chia thành các đoạn [5, 4]; C chờ chỗ chạy 14.55 ms mô phỏng.
4 Prefill ↗ Đưa từng đoạn prompt qua mô hình, ghi K và V vào cache, lấy hàng logits cuối để chọn token đầu tiên. K có shape (2, 9, 4); hàng logits có 22 điểm số; token đầu của C lúc 23.00 ms, TTFT 22.00 ms mô phỏng.
5 Transformer × N layers ↗ Hàm forward một lớp: RMSNorm, Q/K/V theo head, RoPE, mặt nạ nhân quả, softmax, W_O, SwiGLU, LM head. Trọng số attention (9 phần tử, tổng 1) khác logits (22 điểm số); kết quả qua cache khớp tính lại trong 1e-9.
6 KV state manager ↗ Lớp KVPool: 12 block vật lý, bảng block cho từng chuỗi, cấp phát theo block và trả block khi xong. Cao điểm 7/12 block; K/V gom từ block rời khớp tính lại; cuối còn 12/12 block trống.
7 Decode ↗ Mỗi bước đưa đúng một token mới qua mô hình và đọc lại K/V cũ từ cache. Dùng cache tính 41 vị trí, tính lại cả lịch sử cần 197 vị trí (số vị trí, chưa phải thời gian).
8 Logits → sampling → stop check ↗ Hàm sample: softmax với temperature, lọc top-k và top-p, rút token bằng seed riêng; dừng khi gặp eos hoặc đủ max_new. Xác suất tổng 1 trước và sau lọc; C rút ra token o và dừng vì eos sau 4 token.
9 KV / weight precision ↗ Hàm quantize_weights: INT8 đối xứng với một scale cho mỗi cột của 8 ma trận tuyến tính. 3264 byte còn 1192 byte (tính trên định dạng); sai số khôi phục 0.0056 nằm trong nửa scale 0.0061.
10 HBM memory budget ↗ Tính byte KV từ công thức 2 × lớp × token × KV head × chiều head × byte, cho lab và cho cấu hình mẫu giả định. 128 byte mỗi token trong lab; cấu hình mẫu 32 lớp, 4096 token cần 0.50 GiB mỗi chuỗi (tính tay, không đo).
11 Telemetry & capacity feedback ↗ Ghi từng bước (hàng chờ, số chuỗi chạy, token decode/prefill, block KV) và phân rã TTFT. TTFT của C: 0.65 + 14.55 + 6.80 = 22.00 ms; thành phần lớn nhất là chờ chỗ chạy.
12 Benchmark & SLO methodology ↗ Tính TTFT, TPOT, throughput và chạy cùng trace với 3 chính sách lập lịch (static, continuous, continuous + chunked). Token sinh ra giống hệt ở cả 3 chính sách; chỉ thời gian khác và hoàn toàn là hệ quả của công thức chi phí giả định.
13 Quality gates & rollout ↗ So token top-1 của bản gốc và bản INT8 trên cùng ngữ cảnh (teacher forcing) với ngưỡng giả định 95%. Khớp 40/40 quyết định; quyết định sát nhất chênh 0.0304 (gốc) và 0.0326 (INT8) nên giữ nguyên token.

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ể chín điều: (1) vì sao cổng từ chối một số yêu cầu ngay từ đầu; (2) văn bản trở thành token ID như thế nào và vì sao có yêu cầu bị chặn vì quá ngân sách; (3) bộ lập lịch chọn việc cho mỗi bước ra sao; (4) prefill khác decode ở đâu; (5) trọng số attention khác xác suất từ vựng thế nào; (6) KV cache phân trang dùng bảng block ra sao; (7) logits trở thành xác suất, rồi token, rồi quyết định dừng như thế nào; (8) TTFT, TPOT và throughput gồm những phần nào; (9) nén trọng số xuống INT8 đổi bộ nhớ lấy sai số ra sao và cách kiểm tra.

Bạn không cần biết trước về LLM. 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ụ (2, 9, 4) là 2 nhóm, mỗi nhóm 9 hàng, mỗi hàng 4 số.

Đầu vào và cấu hình thu nhỏ của bài lab

Đầu vào là năm yêu cầu (request: một lời gọi gửi văn bản tới mô hình để nhận trả lời). A "xin chao model" đến 0.00 ms, tối đa 10 token sinh ra, greedy. B "model hoc token" đến 0.00 ms, tối đa 7 token, lấy mẫu T = 0.8, top-k = 4, top-p = 0.9. E "xin chao ban" đến 0.50 ms nhưng xin tới 30 token. C "ban hoc model" đến 1.00 ms, tối đa 8 token, lấy mẫu T = 0.8, top-k = 5, top-p = 0.9; đây là yêu cầu được theo dõi qua mọi khối. D "xin chao token" đến 1.50 ms, greedy. Thời điểm đến tính trên đồng hồ mô phỏng; mỗi yêu cầu có seed riêng nên lấy mẫu lặp lại được.

Cấu hình thu nhỏ: 2 chỗ chạy cùng lúc và 1 chỗ chờ (SLOTS = 2, QUEUE_LIMIT = 1); mỗi bước tối đa 6 token (TOKEN_BUDGET = 6); KV cache có 12 block, mỗi block 4 token; một chuỗi tối đa 24 token. Mô hình có một lớp, 2 head attention (MHA, multi-head attention: mỗi head có K và V riêng) với mỗi head 4 chiều, d_model = 8 (chiều của vector ẩn), RoPE (mã hóa vị trí bằng phép xoay) và SwiGLU (mạng feed-forward có cổng) là hai chi tiết của lớp mà bạn chỉ cần biết là có mặt, bảng từ vựng 22 token (gồm token bắt đầu bos và token kết thúc eos), trọng số ngẫu nhiên seed 7. Token của lab do một bộ BPE (byte pair encoding: gộp dần cặp ký tự hay gặp) 10 phép gộp học từ 5 câu mẫu. Đồng hồ mô phỏng dùng các hằng số COST giả định (đơn vị micro-giây) ở đầu file.

Bảng ánh xạ giữa sơ đồ Tab 01 và 13 khối của lab

Khối 1 Gateway & admission = hàm admit; khối 2 Input preparation = train_bpe và encode; khối 3 Iteration scheduler = vòng lặp chính của run_engine (nhận yêu cầu, chọn việc mỗi bước, chia prompt theo TOKEN_BUDGET); khối 4 Prefill và khối 7 Decode = hai nhánh task của run_engine; khối 5 Transformer × N layers = hàm forward (attention, RoPE, SwiGLU, LM head); khối 6 KV state manager = lớp KVPool.

Khối 8 Logits → sampling → stop check = hàm sample và điều kiện dừng trong emit; khối 9 KV / weight precision = quantize_weights; khối 10 HBM memory budget = phép tính byte trên KVPool và công thức mẫu; khối 11 Telemetry & capacity feedback, khối 12 Benchmark & SLO methodology = metrics và summary; khối 13 Quality gates & rollout = greedy_teacher_forced. Tên khối trong output khớp tên khối hoặc năng lực 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: trong năm yêu cầu, yêu cầu nào bị từ chối và vì sao? C sẽ phải chờ lâu hay không? Viết dự đoán ra giấy.

2. Bấm Chạy. Ở khối 1 và 2, đối chiếu dự đoán: D nhận 429 vì lúc xét đã có 3 yêu cầu trong hệ thống; E qua cổng nhưng bị chặn 400 vì 8 + 30 = 38 lớn hơn 24. Ở khối 3, đọc từng dòng bước: p là prefill một đoạn prompt, d là decode một token; tìm bước mà một yêu cầu đang decode dùng chung bước với prefill của yêu cầu khác.

3. Ở khối 4 đến 7, theo dõi C: shape (2, 9, 4) của K nghĩa là 2 head, 9 token, 4 số mỗi vị trí; so hai dãy số của khối 5 và khối 4 (trọng số attention có 9 phần tử và tổng bằng 1; logits có 22 phần tử và tổng không bằng 1); đọc bảng block của khối 6 và tìm block được dùng lại; so 41 với 197 ở khối 7 nhưng nhớ rằng đó là số vị trí, chưa phải thời gian.

4. Ở khối 8 đến 10, đọc xác suất trước và sau khi lọc của C, thấy token được rút và lý do dừng của từng yêu cầu; sau đó đọc dung lượng trước và sau INT8 và so sai số khôi phục với nửa scale.

5. Ở khối 11 đến 13, cộng ba thành phần của TTFT để kiểm tra đúng bằng tổng, tìm thành phần lớn nhất, rồi đọc bảng ba chính sách lập lịch và dòng quyết định sát nhất của cổng chất lượng. Cuối cùng, đối chiếu dự đoán ban đầu với kết quả và sửa các hằng số ở đầu file (xem bài tập) để thấy output thay đổi.

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 trace năm yêu cầu này: cache và bảng block cho cùng logits với tính lại toàn bộ (sai lệch không vượt 1e-9); số yêu cầu offered bằng served cộng rejected; mọi xác suất và mọi hàng attention có tổng bằng 1; mọi block được trả đủ khi các chuỗi kết thúc; đổi chính sách lập lịch không đổi token sinh ra.

Lab không chứng minh: tốc độ trên GPU thật (mọi số ms là đồng hồ mô phỏng giả định); chất lượng ngôn ngữ (trọng số ngẫu nhiên, văn bản vô nghĩa); p95 hay p99 (chỉ có ba yêu cầu được phục vụ); chất lượng của INT8 trên tác vụ thật (cổng chất lượng chỉ có 40 quyết định); và hành vi của router, xác thực, hủy yêu cầu, prefix cache, preemption hay nhiều GPU, vì các phần đó không được mô phỏng.

Trình chạy Lab trực tiếp · inference-end-to-end.py

inference-end-to-end.pyPYTHON
Python outputSẵn sàng.

Nguồn công khai tham khảo

Open Architecture — From Models to Systems OpenArchLab
Danh sách bài học (34)
  1. Cổng tiếp nhận và kiểm soát yêu cầu
  2. Lab tổng hợp Inference Engineering · theo dõi một yêu cầu từ cổng tiếp nhận đến lúc dừng bằng NumPy
  3. Chọn bản sao mô hình để xử lý yêu cầu
  4. Chuyển văn bản thành đơn vị mà mô hình hiểu
  5. Lập lịch tính toán theo từng bước sinh token
  6. Xử lý prompt trước khi bắt đầu sinh câu trả lời
  7. Sinh câu trả lời theo vòng lặp token
  8. Chọn token từ điểm số và xuất văn bản
  9. Bộ nhớ đệm key và value của attention
  10. Đề xuất token trước, rồi để mô hình chính xác minh
  11. Mô hình transformer biến token thành dự đoán như thế nào
  12. Tầng thực thi nối bộ điều phối với thiết bị tính toán
  13. Trình biên dịch tối ưu mô hình cho thiết bị đích
  14. Các hàm tính toán hiệu năng cao trên thiết bị
  15. Dùng ít bit hơn để lưu và tính các giá trị của mô hình
  16. Phần tính toán của accelerator và giới hạn hiệu năng
  17. Lập ngân sách bộ nhớ trên accelerator
  18. Chia mô hình hoặc công việc trên nhiều thiết bị
  19. Trao đổi dữ liệu giữa các worker
  20. Tách máy xử lý prompt khỏi máy sinh token
  21. Quản lý vòng đời các bản sao mô hình
  22. Checkpoint, artifact và việc nạp mô hình
  23. Theo dõi và tìm nguyên nhân request chậm
  24. Thiết kế phép đo để so giải pháp công bằng
  25. Tính chi phí trên công việc thực sự hữu ích
  26. Kiểm tra tính đúng và chất lượng sau tối ưu
  27. Cô lập người dùng và quản lý dữ liệu trong cache
  28. Giữ dịch vụ ổn định khi tải tăng hoặc worker lỗi
  29. Biến một ý tưởng tối ưu thành kết quả kiểm chứng được
  30. Viết kernel với tư duy dữ liệu và tính toán song song
  31. Concurrency, hàng đợi và vòng đời dữ liệu ở host
  32. Vì sao hàng đợi tăng mạnh khi gần hết capacity
  33. Hiểu precision và sai số trong phép tính
  34. Đưa operator của mô hình lên accelerator mới