OpenArchLabOpen Architecture — From Models to Systems

W3 · Training / inference workflow

Bước inference: vòng sinh và bổ sung context

Vòng sinh tự hồi quy: đưa từng token vừa chọn vào mô hình, đọc lại KV cache lịch sử, thêm K, V mới rồi chọn token kế cho tới khi gặp điều kiện dừng.

LESSON ID wf-indecode GROUP Kiến trúc huấn luyện
Mục lục bài học

1Định nghĩa

Decode là vòng lặp tự hồi quy diễn ra ngay sau khi có token trả lời đầu tiên từ bước prefill: ở mỗi vòng, mô hình chỉ nhận đúng một token vừa chọn ở bước trước làm đầu vào để chạy qua các lớp Transformer, rồi chọn token kế tiếp từ kết quả. Vòng này lặp cho tới khi gặp điều kiện dừng.

Nhờ đọc lại các vector Key/Value của prompt và các token đã sinh trong KV cache, mỗi lớp chỉ cần tính thêm một cặp Key/Value cho token hiện tại rồi nối vào cache. Bảng logits mới đi qua sampling để chọn token kế; suốt quá trình trọng số giữ nguyên cố định và chỉ có KV cache dài thêm sau mỗi bước.

Ví dụ đời thường: Decode giống người phiên dịch nói nối tiếp từng từ sau chữ đầu: cứ nói xong một từ lại liếc vào sổ ghi chú (KV cache) và từ vừa phát âm để chọn từ kế tiếp, nối dài câu tới khi diễn đạt trọn ý. Khác người phiên dịch, mỗi lần mô hình chỉ ‘nhìn’ một từ mới và sổ ghi chú; nó không được sửa những từ đã nói.

2Luồng

Đây là nửa sau của ô 5B. Vòng lặp đi qua đúng các phép tính của cột 2 với mỗi lần chỉ một token. Mũi tên quay vòng mang token vừa chọn; cache là trạng thái duy nhất lớn dần, còn trọng số giữ nguyên.

Sơ đồ kiến trúc huấn luyện · 22 ô (1A → 5C)

Kiến trúc huấn luyện LLM · Ánh xạ với Bài Lab tổng hợp

Thứ tự đọc: 1A → 1B ở cột 1, 2A → 2D ở cột 2, 3A → 3E ở cột 3; mũi tên next batch từ 3E quay về cột 1 và mũi tên load weights đi xuống băng 5 (5A → 5C). Cột 4 không phải bước kế tiếp: 4A, 4B tiết kiệm bộ nhớ, còn 4C–4G là các phương pháp huấn luyện thay thế nhau. Di chuột hoặc bấm vào từng ô để đọc pop-over.

Sơ đồ kiến trúc huấn luyện LLM gồm 22 ô từ 1A đến 5C
5B5 · Checkpoint → Inference
prompt một lượt · rồi mỗi bước một token · KV cache

5B · Prefill & Decode

Prefill đọc cả prompt một lượt, rồi decode sinh từng token với KV cache.

Nhận gì
Dãy token ID của prompt từ ô 5A, cùng trọng số đã nạp từ checkpoint ở ô 3E.
Làm gì, vì sao
Prefill đưa cả prompt qua mô hình một lượt (lặp lại cột 2) để lấp đầy KV cache (bộ nhớ key và value của mọi vị trí) và lấy logits ở vị trí cuối. Decode mỗi bước chỉ đưa một token mới, đọc lại K, V cũ từ cache, thêm K, V mới rồi chọn token kế; nhờ cache không phải tính lại cả lịch sử.
Ra gì
Từng token được chọn, vừa nối vào chuỗi vừa đi sang ô 5C; vòng lặp tiếp tục đến khi gặp điều kiện dừng.
Ví dụ, cách đọc ô
Nhãn ô: prompt once · then one token per step · KV cache. Ví dụ trong lab: prompt 13 token và đầu ra 5 token cần 13 + 4 = 17 vị trí xử lý với cache, so với 75 nếu mỗi bước tính lại (số vị trí, không phải thời gian).
Lưu ý
Cache không đổi kết quả toán học, chỉ tránh tính lại. Thời gian thật phụ thuộc phần cứng, và cache lớn dần theo độ dài chuỗi.
Sơ đồ luồng (4 bước)
  1. Token mới nhất

    Nhận token vừa chọn ở bước trước làm đầu vào duy nhất của bước này.

  2. Forward với context

    Mỗi lớp tính Q, K, V của token này và đọc cache của các vị trí trước.

  3. Bổ sung cache

    K, V của token được nối vào cache; cache dài thêm một vị trí.

  4. Chọn tiếp hoặc dừng

    Chọn token từ logits, kiểm tra điều kiện dừng; chưa dừng thì quay lại vòng này.

Mã Mermaid
flowchart TD
  step1["Token mới nhất"]
  step2["Forward với context"]
  step3["Bổ sung cache"]
  step4["Chọn tiếp hoặc dừng"]
  step1 --> step2
  step2 --> step3
  step3 --> step4

3Giải pháp

Vị trí trên sơ đồ: nửa sau của ô 5B "Prefill & decode" trong băng "Checkpoint → Inference", ngay sau prefill và trước ô 5C (kết thúc và trả văn bản). Mỗi vòng lặp chạy lại cột 2 của sơ đồ nhưng với một token, và cuối vòng chọn token thay vì tính loss.

Vấn đề cần giải. Mô hình sinh chữ bằng cách chọn từng token một, mỗi token phụ thuộc vào tất cả token trước. Nếu mỗi bước tính lại cả chuỗi từ đầu, công việc tăng rất nhanh theo độ dài. Cần cách chỉ tính phần mới mà vẫn có kết quả giống hệt.

Khái niệm tối thiểu. Tự hồi quy: token vừa sinh trở thành đầu vào. KV cache lưu K, V của mọi vị trí đã xử lý. Ở mỗi bước chỉ có một vị trí mới, nên attention có một Query mới so với toàn bộ Key trong cache (cũ cộng mới).

Ví dụ có số (minh họa, tiếp nối bài prefill: cache đang có 2 vị trí, token đầu là “cá”, ID 4). Bước 1: đưa [4] ở vị trí 2 vào mô hình; mỗi lớp tính Q, K, V của riêng token này, đọc K, V của vị trí 0 và 1 từ cache, nối K, V mới vào, vậy cache dài 3 vị trí (192 byte với mô hình nhỏ trước đó). Logits thu được; giả sử điểm cao nhất rơi vào eos (ID 6). Sampling chọn eos, điều kiện dừng thỏa mãn và vòng kết thúc. Câu trả lời là [4, 6], tức “cá” cộng token kết thúc.

Tại sao nhanh hơn tính lại. Giả sử prompt N = 2 và cần 4 token mới. Có cache: prefill xử lý 2 token, rồi 3 bước decode xử lý mỗi bước 1 token (token thứ 4 không cần đưa vào nếu dừng ở đó): tổng 2 + 3 = 5 lượt xử lý token. Không cache: bước sinh token thứ k phải xử lý lại N + k − 1 token, tức 2 + 3 + 4 + 5 = 14 lượt. Con số 14 so với 5 là số lượt xử lý token theo mô hình đếm đơn giản này, không phải tỉ lệ thời gian đo được.

Kiểm tra tính đúng. So logits của bước có cache với logits khi chạy lại cả chuỗi [1, 3, 4] không cache bằng cùng trọng số: chúng phải trùng trong sai số số học. Nếu trùng, ta kết luận việc tái dùng K, V cũ là đúng. Điều không thể kết luận: trùng khớp không chứng minh mô hình hiểu ngôn ngữ, cũng không chứng minh cache nhanh hơn; tốc độ phải đo riêng.

Cách đọc chi phí. Ở mỗi bước, mô hình đọc toàn bộ trọng số (phần lớn) và toàn bộ cache chỉ để xử lý một token, nên khi nhóm yêu cầu nhỏ, thời gian thường bị chi phối bởi đọc bộ nhớ chứ không phải số phép tính. Vì cache lớn dần, token ở cuối câu trả lời dài thường tốn hơn token ở đầu.

Thực thi và cầu nối sang Inference Engineering. Gộp nhiều chuỗi vào cùng một bước (batching), dùng kernel phù hợp và giảm dữ liệu đọc bằng kiểu số ít bit là các hướng cần thử. Speculative decoding cho phép xác minh nhiều token đề xuất trong một lượt chạy của mô hình chính nhưng thêm chi phí và không bảo đảm nhanh hơn với mọi tải. Xem sinh câu trả lời theo vòng lặp token, đề xuất token rồi xác minh, bộ nhớ đệm key và value, lập lịch theo từng bước và chọn token từ điểm số.

Để chạy từng bước decode với cache từ prefill và đối chiếu logits với tính lại toàn bộ, mở giai đoạn 13 · Từ checkpoint sang suy luận của Bài Lab tổng hợp. Hãy đoán trước kích thước cache sau mỗi bước.

4Profiling

  • Thời gian mỗi token đầu ra

    Kiểm tra tính đúng trước (logits có cache trùng không cache). Sau đó đo khoảng giữa các token sau token đầu, phân loại theo độ dài context và số yêu cầu đồng thời. Ghi p50 và p95; một số trung bình đẹp có thể che mất những token chậm.

  • Thời gian đọc bộ nhớ

    Dùng timeline và bộ đếm phần cứng để xem kernel có chờ dữ liệu từ bộ nhớ hay chờ lệnh từ CPU không. Chỉ khi biết điểm nghẽn mới chọn hướng tối ưu (nhóm lớn hơn, kiểu số ít bit hơn, gộp kernel).

  • Tăng trưởng của cache

    Ghi kích thước cache theo từng bước và so với công thức 2 × số lớp × n_kv × số vị trí × d_head × byte. Theo dõi chi phí đọc cache ở đầu và cuối một câu trả lời dài để thấy ảnh hưởng của độ dài context.

Mẹo đo lường: ghim số liệu trên workload thật, ghi cả p50/p95/p99 thay vì chỉ trung bình, và luôn ghi lại điều kiện chạy (batch, cache, đồng thời, phần cứng) trước và sau khi tối ưu. Số đo thiếu điều kiện chạy thì không so sánh được.

5Ví dụ

Chatbot trả lời ngắn

Ưu tiên token đến đều và nhanh; không tăng nhóm xử lý quá mức chỉ để đạt tổng token mỗi giây cao. Dự đoán: tăng nhóm gấp đôi thì thời gian mỗi token của từng người dùng thay đổi thế nào? Có thể tăng, vì mỗi bước phải xử lý nhiều chuỗi hơn; tổng thông lượng có thể tăng nhưng người dùng cảm nhận độ trễ.

Sinh báo cáo dài

Cache tiếp tục lớn theo context. Đo thời gian của các token ở đầu và cuối response để thấy chi phí tăng khi context tăng; đừng suy luận từ một độ dài ngắn. Với mô hình nhỏ trong ví dụ, mỗi token thêm 64 byte, nên 1.000 token thêm 64.000 byte; với mô hình thật con số lớn hơn nhiều và phải tính bằng công thức với cấu hình thật.

Tự kiểm tra: tại sao cần cache

Một chuỗi hiện có 6 token và cần chọn token thứ 7; token thứ 6 vừa được chọn, 5 token trước đã có K, V trong cache. Không cache thì phải xử lý lại bao nhiêu token? Cả 6 token. Có cache thì chỉ xử lý 1 token (token thứ 6) nhưng vẫn phải đọc K, V của 5 vị trí trước.

6Thuật ngữ

Autoregressive generation
Sinh tự hồi quy: token vừa tạo trở thành đầu vào của bước kế tiếp.
Decode step
Một vòng của pha decode: forward một token, thêm K, V vào cache, lấy logits, chọn token.
Inter-token latency (ITL)
Khoảng thời gian người dùng chờ giữa hai token liên tiếp sau token đầu.
Điều kiện dừng
Token eos, chạm max_tokens, khớp chuỗi stop hoặc bị hủy; sau khi gặp, vòng kết thúc.
Speculative decoding
Một mô hình nhỏ đề xuất nhiều token, mô hình chính xác minh trong một lượt; có thêm chi phí và không nhanh hơn trong mọi trường hợp.
Glossary (6)
Model weights
Các số học được; trong decode không đổi.
Cache
Bộ nhớ K, V của các token đã xử lý; lớn dần theo mỗi token.
Logits
Điểm số cho từng token ở vị trí hiện tại; sampling chọn token từ đó.
Kernel
Hàm tính toán chạy trên GPU; với một token, nhiều kernel nhỏ nên dễ bị chờ bộ nhớ hoặc chờ lệnh.
Host
Phần chương trình điều khiển thiết bị, chạy trên CPU; nếu phát lệnh chậm thì GPU nhàn rỗi.
Context
Prompt cộng các token đã sinh; token mới đọc toàn bộ phần này qua cache.

7Bài liên quan

8Nguồn