Bài 2 trên 4 · Attention và ngữ cảnh dài
Tóm tắt
- Nén ngữ cảnh vào một trạng thái cỡ cố định thì rẻ, nhưng trạng thái đó sẽ đầy và làm mất thông tin cũ.
- Sparse attention giữ nguyên ngữ cảnh và chỉ đọc một phần nhỏ, nhưng nếu bộ chỉ mục vẫn chấm mọi khoá hay mọi khối thì chi phí bậc hai vẫn còn, chỉ nhỏ đi một hằng số.
- Muốn thoát hẳn cần hai điều: mỗi câu hỏi chọn phần đọc riêng, và việc tìm kiếm cũng không được quét toàn bộ. Tìm theo cây là một hướng đáp ứng cả hai.
Một người đọc hết cả thư viện rồi được hỏi một câu. Có ba cách để bớt việc: chỉ giữ một sổ ghi chép mỏng, hoặc giữ lại cả thư viện rồi tra danh mục mỗi lần, hoặc giữ cả thư viện nhưng tra theo từng tầng. Các mô hình AI cũng đi theo đúng ba hướng đó. Bài này đặt chúng cạnh nhau trên cùng một ngữ cảnh.
Tự thử: cùng một câu hỏi, năm cách trả lời
Dải trên cùng cho thấy attention thật nằm ở đâu. Mỗi dải bên dưới cho thấy phần ngữ cảnh mà một cách làm đọc. Bảng cho biết nó tốn bao nhiêu phép so sánh và giữ được bao nhiêu attention, so với việc đọc tất cả.
Kéo thanh trượt để đặt điều cần tìm ở xa hay gần, rồi đổi độ dài ngữ cảnh để xem cột chi phí của mỗi cách thay đổi ra sao.
Thử theo thứ tự:
- Giữ mặc định: 16K token, điều cần tìm nằm cách đây 60%. Cửa sổ giữ được 0% attention. Chấm từng khoá giữ được 97%, nhưng tốn gần 17 nghìn phép so sánh, nhiều hơn cả đọc tất cả.
- Kéo thanh trượt xuống 1%. Điều cần tìm nằm ngay gần đây, và cửa sổ giữ được khoảng 91% với chỉ 512 phép so sánh. Cửa sổ không dở, nó chỉ mù với phần xa.
- Quay về 60% rồi đổi sang 64K. Hai hàng có "chấm" tăng khoảng 3 đến 4 lần. Hàng "đi xuống cây" chỉ tăng chưa tới 2 lần, từ 636 lên 1.096.
- Nhìn cột giữ được của cây: khoảng 85% ở 16K, chỉ còn khoảng 62% ở 64K với cùng cấu hình. Đó là cái giá của nó, và bài 4 sẽ quay lại chuyện này.
Bản demo là mô hình đơn giản hoá với khoá tự tạo. Một lần chấm của bộ chỉ mục thật rẻ hơn một lần attention đầy đủ, nhưng số lần vẫn tăng theo độ dài. Hình dạng mới là điều cần nhìn.
Cách 1: nén mọi thứ vào một trạng thái cỡ cố định
Cách này rẻ nhất và quên nhiều nhất. Cửa sổ trượt chỉ giữ N token gần nhất. Các mô hình không gian trạng thái (state-space model) như Mamba giữ một trạng thái cỡ cố định và cập nhật nó dọc theo chuỗi. Với cách này, chi phí đọc vào là tuyến tính và mỗi token viết ra tốn cố định.
Giới hạn nằm ở sức chứa. Thông tin hữu ích vẫn tăng theo văn bản, còn chỗ chứa thì không. Giống như đọc thêm sách mà chỉ được giữ đúng 10 tờ ghi chú: ban đầu đủ, về sau cái mới phải đè lên cái cũ. Một thử nghiệm năm 2024 cho thấy transformer vượt mô hình không gian trạng thái ở việc chép lại chuỗi, đúng là loại việc cần nhớ chính xác.
Vì thế các mô hình "lai" trộn hai loại lớp: phần lớn dùng trạng thái cố định, vài lớp dùng attention đầy đủ. Theo paper về ZHA, ở ngữ cảnh đủ dài, vài lớp attention đó vẫn chiếm phần lớn chi phí.
Cách 2: giữ nguyên ngữ cảnh, chấm từng khoá rồi chỉ đọc phần tốt nhất
Cách này chính xác hơn nhiều nhưng chỉ dời chi phí sang chỗ khác. Sparse attention giữ cả KV cache và để mỗi query chọn phần đọc của riêng mình. Điểm mạnh là query này đọc chỗ này, query kia đọc chỗ khác.
Vướng mắc là: làm sao biết 1% nào đáng đọc? Bộ chỉ mục phải chấm mọi khoá. Phần attention cuối rẻ thật, nhưng bộ chỉ mục tăng theo độ dài y như attention cũ. Có thể làm nó nhẹ hơn bằng cách dùng ít đầu attention hoặc độ chính xác thấp hơn, nhưng paper về ZHA dẫn số liệu rằng ở gần 1 triệu token, 60 đến 90% thời gian của các lớp này vẫn nằm ở việc lập chỉ mục.
Cách 3: chấm theo khối thay vì theo từng khoá
Tóm tắt mỗi nhóm khoá thành một khối rồi chấm khối sẽ rẻ hơn chấm từng khoá, nhưng vẫn phải chấm mọi khối. MiniMax Sparse Attention (MSA) là một ví dụ: paper về ZHA mô tả cấu hình so sánh chọn 16 khối, mỗi khối 128 token.
Số khối vẫn tăng theo độ dài. Đoạn mã dưới đây so hai cách, đều đọc 512 khoá ở bước cuối:
// indexers.ts: node indexers.ts
const everyKey = (n: number) => n + 512; // chấm mọi khoá, rồi đọc 512
const everyChunk = (n: number) => (n / 64) * 4 + 512; // chấm mọi khối bằng 4 bản tóm tắt, rồi đọc 512
for (const n of [1e4, 1e6, 1e8]) {
const a = everyKey(n);
const b = everyChunk(n);
console.log(`${n} tokens: ${a} vs ${b}, ${(a / b).toFixed(1)}x cheaper`);
}
console.log(`100x the tokens costs ${(everyChunk(1e8) / everyChunk(1e6)).toFixed(0)}x more with chunks`);Ngày 3/11/2026, trên Node 26.11.1, kết quả là:
10000 tokens: 10512 vs 1137, 9.2x cheaper
1000000 tokens: 1000512 vs 63012, 15.9x cheaper
100000000 tokens: 100000512 vs 6250512, 16.0x cheaper
100x the tokens costs 99x more with chunksKhối rẻ hơn tới 16 lần, và mức lợi đó dừng ở 16. Ngữ cảnh dài gấp 100 lần thì vẫn tốn gấp 99 lần. Đây là ý của cụm từ nhanh hơn một hằng số: đường chi phí thấp xuống, nhưng độ dốc không đổi.
Cách 4: tìm theo nhiều tầng
Nếu việc tìm kiếm tự nó cũng thưa thì độ dốc mới đổi. Tóm tắt khối thành khối lớn hơn, tóm tắt tiếp, rồi đi từ trên xuống và chỉ mở nhánh có vẻ đúng. Nhánh bị bỏ qua thì mọi khoá bên dưới không phải chấm. Paper về ZHA nêu hai phương pháp nhiều tầng đi trước là PISA và HiP, đạt độ phức tạp log-tuyến tính nhưng theo paper, chúng chưa chứng minh được hiệu quả trên các bài toán suy luận và lập trình khó. Bài tiếp theo đi vào cách một cây như vậy hoạt động.
Cách nào hợp với việc gì?
| Cách | Mỗi câu hỏi tốn | Mất gì | Hợp khi |
|---|---|---|---|
| Đọc tất cả | Tăng theo độ dài | Không mất gì, nhưng đắt | Ngữ cảnh vừa phải, cần độ chính xác tối đa |
| Cửa sổ trượt | Cố định | Mọi thứ nằm ngoài cửa sổ | Việc chỉ cần phần gần đây, như xử lý luồng |
| Trạng thái cố định | Cố định | Chi tiết chính xác của phần cũ | Chuỗi dài, không cần trích lại nguyên văn |
| Chấm từng khoá | Tăng theo độ dài, hằng số nhỏ hơn | Ít, nếu chọn đủ nhiều | Ngữ cảnh dài vừa, đã có bộ chỉ mục tốt |
| Chấm từng khối | Tăng theo độ dài, hằng số nhỏ hơn nữa | Ít, nếu khối đủ phủ | Hàng trăm nghìn token, chi phí chỉ mục là nút thắt |
| Cây nhiều tầng | Tăng chậm hơn độ dài | Một phần attention, tuỳ ngưỡng | Hướng nghiên cứu cho ngữ cảnh hàng triệu token trở lên |
Những lỗi hay gặp khi nghĩ về chuyện này
- Nhầm "chỉ đọc 1%" với "chỉ tốn 1%". Phải cộng cả việc tìm 1% đó. Đây là lỗi hay gặp nhất khi đọc thông báo về sparse attention.
- Xoá hẳn những gì ít được chú ý. Paper về ZHA đo thấy hợp của các tập mà nhiều câu hỏi đọc sẽ phủ dần gần hết cache. Hôm nay không ai đọc không có nghĩa là mai không cần.
- Coi RAG và sparse attention là một. RAG chọn đoạn văn một lần, bên ngoài mô hình. Sparse attention chọn riêng cho từng query ở từng lớp, trong khi cả ngữ cảnh vẫn nằm trong cache.
- So hai phương pháp ở một độ dài duy nhất. Một cách rẻ hơn 16 lần có thể thắng ở 100 nghìn token và thua ở 100 triệu token. Hãy hỏi độ dốc, không chỉ hỏi một điểm.
Từ các giới hạn trên, paper về ZHA rút ra hai yêu cầu cho một phương án thật sự thoát được chi phí bậc hai: mỗi query phải tự chọn phần đọc của mình, và phần đang đọc phải được phép lớn dần nhưng chậm hơn văn bản. Bài tiếp theo xem một thiết kế cố đáp ứng cả hai.
Kiểm tra lại
Chọn một đáp án để xem vì sao đúng hay sai.
Bộ chỉ mục rẻ hơn attention đầy đủ 16 lần, và nó chấm từng khối của ngữ cảnh. Khi ngữ cảnh dài gấp 100 lần thì sao?
Xem đáp án
Vẫn tốn khoảng gấp 100 lần cho mỗi câu hỏi. Số khối tăng theo độ dài, nên việc chấm vẫn tăng tuyến tính cho mỗi câu hỏi và tổng cộng vẫn bậc hai. Rẻ hơn 16 lần chỉ đổi hằng số, không đổi độ dốc.
Vì sao một trạng thái cỡ cố định sẽ gặp vấn đề ở ngữ cảnh rất dài?
Xem đáp án
Vì thông tin hữu ích vẫn tăng mà chỗ chứa thì không, nên cái mới phải đè lên cái cũ. Chi phí của nó đúng là không đổi. Vấn đề nằm ở sức chứa: cứ thêm thông tin mới thì thông tin cũ bị trộn lẫn hoặc mất đi, kể cả khi sau này lại cần.
Vì sao không xoá hẳn những token ít được chú ý khỏi cache?
Xem đáp án
Vì token bị bỏ qua hôm nay có thể là thứ một câu hỏi sau này cần. Paper về ZHA đo hợp của các tập top-p qua nhiều câu hỏi và thấy nó phủ dần gần hết cache. Mỗi câu hỏi đọc ít, nhưng các câu hỏi khác nhau đọc những chỗ khác nhau.
Bạn đưa mô hình một tài liệu và dùng hệ RAG để tìm đoạn liên quan. Điều này giống sparse attention ở đâu?
Xem đáp án
Cùng ý tưởng chỉ đọc phần liên quan, nhưng RAG chạy bên ngoài mô hình, còn sparse attention chạy ở từng query bên trong mô hình. Cả hai đều chọn trước khi đọc. RAG chọn một lần ở tầng ứng dụng trước khi gửi văn bản vào. Sparse attention chọn cho từng query, ở từng lớp, và cả ngữ cảnh vẫn nằm trong cache.
Nguồn
- Lufkin và cộng sự (2026): Subquadratic Attention with a Hierarchical Tree-Structured Indexer
- Lai và cộng sự (2026): MiniMax Sparse Attention
- Jelassi và cộng sự (2024): Repeat After Me: Transformers are Better than State Space Models at Copying
- Gu và Dao (2023): Mamba: Linear-Time Sequence Modeling with Selective State Spaces