Nới ngữ cảnh cho một mô hình đã huấn luyện xong
Nới ngữ cảnh cho một mô hình đã huấn luyện xong
Mô hình học ở 4.096 vị trí. Bạn muốn chạy nó ở 32.768. Mọi vị trí vượt quá 4.096 là vùng nó chưa từng thấy, và nó hỏng. Ba cách chữa phổ biến đều tác động lên đúng một chỗ: tần số quay của RoPE.
Ở bài RoPE bạn đã thấy vị trí được mã hoá bằng cách quay từng cặp toạ độ của một đầu chú ý, mỗi cặp quay ở một tốc độ riêng. Ở bài KV cache bạn đã thấy vì sao ngữ cảnh dài lại đắt. Bài này ghép hai chuyện đó lại và hỏi một câu rất thực tế: mô hình đã huấn luyện xong rồi, giờ muốn nó đọc dài gấp tám lần thì làm sao?
Huấn luyện lại từ đầu ở độ dài mới thì quá đắt. Nên người ta đi đường vòng: giữ nguyên trọng số, chỉ vặn lại tần số quay sao cho vị trí xa không rơi vào vùng góc mà mô hình chưa từng gặp. Ba cách vặn dưới đây khác nhau đúng một điểm, và điểm đó quyết định cách nào giữ được khả năng phân biệt hai vị trí liền nhau.
config.json phát hành kèm mô hình, đối chiếu ngày 27/07/2026: head_dim, rope_theta và max_position_embeddings. Đây là ảnh chụp một thời điểm, lĩnh vực này đổi rất nhanh, nên hãy tự đối chiếu lại với nguồn. Mọi tham số dưới đây sửa được. Cửa sổ mục tiêu và phương án cố tình không nằm trong preset: đó là hai thứ của bạn.c_i = 1 với mọi dải Giữ nguyên mọi tần số. Vị trí vượt quá L rơi thẳng vào vùng góc mô hình chưa từng thấy.k = 32.768 / 4.096 = 8.00004.00K → 32.00Kd = 128 nên có 64 cặp toạ độtheta_i = 10.000^(-2i / 128)| i | theta_i rad mỗi vị trí | Bước sóng (vị trí) | Vòng quay trong L | Hệ số nén c_i | Góc mỗi bước sau nới | Góc ở vị trí xa nhất | Vượt gấp | Trạng thái |
|---|---|---|---|---|---|---|---|---|
| 0 | 1.000000 | 6.3 | 651.8986 | 1.0000 | 1.000000 | 32768.000 | ×8.0000 | đã quay hết |
| 4 | 0.562341 | 11.2 | 366.5895 | 1.0000 | 0.562341 | 18426.801 | ×8.0000 | đã quay hết |
| 8 | 0.316228 | 19.9 | 206.1485 | 1.0000 | 0.316228 | 10362.151 | ×8.0000 | đã quay hết |
| 12 | 0.177828 | 35.3 | 115.9258 | 1.0000 | 0.177828 | 5827.066 | ×8.0000 | đã quay hết |
| 16 | 0.100000 | 62.8 | 65.1899 | 1.0000 | 0.100000 | 3276.800 | ×8.0000 | đã quay hết |
| 20 | 0.056234 | 111.7 | 36.6590 | 1.0000 | 0.056234 | 1842.680 | ×8.0000 | đã quay hết |
| 24 | 0.031623 | 198.7 | 20.6148 | 1.0000 | 0.031623 | 1036.215 | ×8.0000 | đã quay hết |
| 28 | 0.017783 | 353.3 | 11.5926 | 1.0000 | 0.017783 | 582.707 | ×8.0000 | đã quay hết |
| 32 | 0.010000 | 628.3 | 6.5190 | 1.0000 | 0.010000 | 327.680 | ×8.0000 | đã quay hết |
| 36 | 0.005623 | 1117.3 | 3.6659 | 1.0000 | 0.005623 | 184.268 | ×8.0000 | đã quay hết |
| 40 | 0.003162 | 1986.9 | 2.0615 | 1.0000 | 0.003162 | 103.622 | ×8.0000 | đã quay hết |
| 44 | 0.001778 | 3533.3 | 1.1593 | 1.0000 | 0.001778 | 58.271 | ×8.0000 | đã quay hết |
| 48 | 0.001000 | 6283.2 | 0.6519 | 1.0000 | 0.001000 | 32.768 | ×8.0000 | chưa từng thấy |
| 52 | 0.000562 | 11173.3 | 0.3666 | 1.0000 | 0.000562 | 18.427 | ×8.0000 | chưa từng thấy |
| 56 | 0.000316 | 19869.2 | 0.2061 | 1.0000 | 0.000316 | 10.362 | ×8.0000 | chưa từng thấy |
| 63 | 0.000115 | 54410.1 | 0.0753 | 1.0000 | 0.000115 | 3.784 | ×8.0000 | chưa từng thấy |
| Phương án | c ở dải nhanh nhất | c ở dải chậm nhất | Độ trải | Bước góc dải nhanh nhất (rad) | Vượt xa nhất | Số dải chưa từng thấy |
|---|---|---|---|---|---|---|
| Không làm gì | 1.0000 | 1.0000 | ×1.000 | 1.000000 | ×8.0000 | 18 |
| Nội suy vị trí | 8.0000 | 8.0000 | ×1.000 | 0.125000 | ×1.0000 | 0 |
| Đổi cơ số kiểu NTK | 1.0000 | 8.0000 | ×8.000 | 1.000000 | ×1.7526 | 17 |
| YaRN theo dải tần | 1.0000 | 8.0000 | ×8.000 | 1.000000 | ×1.0000 | 0 |
128 toạ độ, giá trị lặp 0,2 0,4 0,6 0,8 1,0||x|| = 7.453858061(x0, x1) thành(-0.296555, 0.334746)alpha = 1 và beta = 32 là giá trị công bố cho họ Llama, các mô hình khác chỉnh lại. Cách chia ba vùng, công thức pha trộn và hàm dốc thì đúng theo bản gốc chứ không phải tôi bịa. Ngoài ra sim bỏ qua chuyện phần vị trí trong một số kiến trúc đi đường riêng, và bỏ qua mọi thứ liên quan tới attention sink hay bộ đệm.Vì sao vị trí vượt quá L lại là vấn đề
Mở trang ra, sim đang ở cấu hình Llama 2 7B: mỗi đầu rộng 128 nên có 64 cặp toạ độ, cơ số RoPE 10.000, cửa sổ huấn luyện 4.096, và ta đang đòi chạy ở 32.768, tức hệ số nới k bằng 8. Phương án đang chọn là Không làm gì.
Nhìn cột vòng quay trong L của bảng thứ hai. Cặp 0 quay nhanh nhất, đúng 1 radian mỗi vị trí, nên trong 4.096 vị trí nó quay được 651,8986 vòng. Cặp 16 quay 0,1 radian mỗi vị trí nên được 65,1899 vòng. Cặp 32 được 6,5190 vòng. Cặp 48 chỉ được 0,6519 vòng, và cặp cuối cùng, cặp 63, được vỏn vẹn 0,0753 vòng.
Con số đó là mấu chốt. Cặp nào đã quay trọn ít nhất một vòng thì mô hình đã gặp đủ mọi góc của nó rồi: góc quay vòng lại, không có gì mới. Ở cấu hình này có 46 trên 64 cặp như vậy. Nhưng 18 cặp còn lại chưa quay hết một vòng, nghĩa là chúng chỉ trải qua một cung góc hẹp trong suốt quá trình huấn luyện, và mọi góc nằm ngoài cung đó là góc hoàn toàn xa lạ.
Lấy cặp 48 làm ví dụ chạy suốt bài. Nghịch tần của nó đúng bằng 0,001 radian mỗi vị trí, nên trong cửa sổ huấn luyện nó chỉ đi từ góc 0 tới góc 4,096 radian. Bây giờ ở vị trí 32.768 nó bị đẩy tới góc 32,768 radian, tức xa gấp 8 lần cung nó từng biết. Mô hình chưa bao giờ được dạy con số đó nghĩa là gì. Đây là lý do "cứ thế chạy dài ra" thường hỏng rất nhanh chứ không hỏng dần.
Cách chữa thứ nhất: nén mọi vị trí lại
Ý tưởng đơn giản nhất là chia vị trí cho k. Vị trí 32.768 được đối xử như vị trí 4.096, vị trí 8 được đối xử như vị trí 1. Mọi thứ lại nằm gọn trong dải góc cũ.
Bấm nút Nội suy vị trí và nhìn cột hệ số nén: cả 64 cặp đều bị nén đúng 8 lần, không cặp nào được ưu ái. Cặp 48 quay về đúng góc 4,096 radian ở vị trí xa nhất, tức vượt gấp 1,0000 lần, đúng chạm mép chứ không vượt. Số dải chưa từng thấy tụt từ 18 xuống 0.
Nghe như đã xong, cho tới khi nhìn cột bước góc dải nhanh nhất ở bảng so sánh. Đó là khoảng cách góc giữa hai vị trí liền nhau ở cặp quay nhanh nhất, tức thước đo mịn nhất mà mô hình có để nói "chữ này đứng ngay trước chữ kia". Không làm gì thì thước ấy là 1 radian. Nội suy vị trí kéo nó xuống 0,125 radian, đúng một phần tám.
Hai vị trí cạnh nhau giờ chỉ lệch nhau 0,125 radian, khoảng 7 độ, thay vì 57 độ. Mô hình được huấn luyện để đọc chênh lệch 1 radian mà giờ phải đọc chênh lệch 0,125 radian. Nó vừa mất phần lớn khả năng phân biệt gần với xa. Đây là cái giá thật của nội suy đơn thuần, và nó không nằm ở chỗ ai cũng nhìn: nó nằm ở đầu nhanh của thang tần số, chứ không phải ở đuôi chậm nơi ta đang lo.
Cách chữa thứ hai: đổi cơ số thay vì đổi vị trí
Cách thứ hai không đụng vào vị trí. Nó nâng cơ số RoPE lên, từ base thành base × k^(d / (d - 2)). Nghe như một trò kỹ thuật vụn vặt, nhưng hệ quả thì rất khác.
Nghịch tần của cặp i là base^(-2i / d), nên nhân cơ số lên chia nghịch tần cho k^(2i / (d - 2)). Đọc kỹ số mũ đó:
- Ở cặp 0, số mũ bằng 0, nên hệ số nén bằng
k^0tức đúng 1. Cặp nhanh nhất không bị đụng tới một chút nào. - Ở cặp cuối,
ibằngd/2 - 1nên2ibằngd - 2, số mũ bằng 1, hệ số nén bằng đúngk. Cặp chậm nhất bị nén y hệt như nội suy vị trí. - Giữa hai đầu, hệ số nén tăng dần.
Bấm Đổi cơ số kiểu NTK rồi so hai bảng. Bước góc dải nhanh nhất trở về 1,0000 radian, tức thước đo mịn nguyên vẹn, trong khi nội suy vị trí chỉ còn 0,125. Cột độ trải nhảy từ ×1,000 lên ×8,000: đó chính là con số nói rằng phương án này có phân biệt dải nhanh với dải chậm, còn nội suy vị trí thì không.
Muốn tự kiểm bằng tay thì chọn cấu hình mẫu tròn số, đặt cửa sổ mục tiêu 64 để k bằng 4. Bốn hệ số nén hiện ra là 1,0000 · 1,5874 · 2,5198 · 4,0000, đúng là 4^0, 4^(1/3), 4^(2/3), 4^1. Bốn nghịch tần là 1 · 0,316228 · 0,1 · 0,031623, mỗi bậc chia cho căn của 10. Nhân chia được trên giấy.
Nhưng đổi cơ số không phải bữa trưa miễn phí, và bảng nói thẳng chỗ đó. Quay lại cấu hình mặc định: cặp 48 giờ có hệ số nén 4,8761 chứ không phải 8, nên góc ở vị trí xa nhất vẫn vượt gấp 1,6407 lần cung đã học. Số dải chưa từng thấy giảm từ 18 xuống 17, tức gần như không giảm về số lượng, cái giảm mạnh là mức độ: từ vượt gấp 8 lần xuống vượt gấp 1,75 lần ở dải tệ nhất. Đổi cơ số làm nhẹ vấn đề chứ không xoá nó.
Hai con số của cặp 48 dưới phương án này có dạng đóng, nếu bạn muốn kiểm: hệ số nén là 2^(16/7) và mức vượt là 2^(5/7).
Cách chữa thứ ba: nội suy theo từng dải tần
Nhìn lại hai bảng ở trên thì thấy mỗi phương án đúng ở một nửa. Nội suy vị trí xử lý tốt các dải chậm, tức đúng chỗ đang gặp vấn đề, nhưng nó bôi luôn cả các dải nhanh vốn chẳng cần chữa. Đổi cơ số giữ được dải nhanh nhưng lại chữa chưa tới ở dải chậm.
YaRN lấy đúng nhận xét đó làm quy tắc: quyết định theo từng dải, dựa trên số vòng quay trong cửa sổ huấn luyện. Chia thành ba vùng:
- Dải nào quay nhiều hơn
betavòng thì mô hình đã thấy hết mọi góc rồi, không cần chữa: giữ nguyên. - Dải nào quay chưa tới
alphavòng thì nó chưa hề biết vòng quay là gì: nội suy hết, chia đủk. - Ở giữa thì pha trộn hai tốc độ theo một hàm dốc tuyến tính.
Bấm YaRN theo dải tần, bảng mọc thêm cột vùng YaRN. Với alpha = 1 và beta = 32, thang 64 dải chia thành 21 dải giữ nguyên, 25 dải pha trộn và 18 dải nội suy hết. Cặp 0 quay 651 vòng nên nằm trong vùng giữ nguyên, thước đo mịn vẫn là 1,0000 radian. Cặp 63 quay 0,0753 vòng nên nội suy hết. Cặp 32 quay 6,5190 vòng, rơi vào vùng pha trộn, hệ số dốc bằng (6,5190 - 1) / 31 tức 0,1780, cho ra hệ số nén 3,5615.
Kết quả ở cấu hình này: 0 dải chưa từng thấy và thước đo mịn vẫn nguyên 1,0000 radian. Trên hai thước đo hình học mà sim tính được, đây là phương án tốt nhất trong bốn phương án. Nhớ chữ hình học ở câu vừa rồi, mục cuối bài sẽ nói vì sao nó quan trọng.
Ca vàng: nới bằng 1 thì cả bốn phải giống hệt nhau
Đặt cửa sổ mục tiêu đúng bằng cửa sổ huấn luyện, tức 4.096. Hệ số nới thành 1, và khi đó cả bốn phương án bắt buộc phải cho ra đúng RoPE gốc: mọi hệ số nén bằng 1, mọi góc y như cũ. Nếu chỉ một cột lệch khỏi 1 thì phương án đó cài sai.
Đây là phép thử mạnh nhất của bài, vì nó không cần biết công thức đúng là gì, chỉ cần biết rằng không nới thì không được đổi gì. Cổng kiểm số chạy phép thử này trên 320 cấu hình, gồm cả các ca quái như bề rộng đầu bằng 2, cơ số bằng 1, cửa sổ huấn luyện bằng 1, và kết quả là sai lệch đúng bằng 0, không phải nhỏ hơn 1e-15 mà bằng 0 tuyệt đối. Sai một vị trí thôi, đặt mục tiêu 4.097, là ba phương án đã tách nhau ra ngay.
Một thứ không phương án nào đụng tới
Mục 4 của sim in ra độ dài của một vector thử trước và sau khi quay. Đổi phương án, đổi cửa sổ mục tiêu, đổi gì cũng được: hai con số 7,453858061 đứng im.
Lý do là RoPE chỉ quay từng cặp toạ độ, mà phép quay là phép biến đổi trực giao nên nó không thể làm vector dài ra hay ngắn đi. Vặn tần số vì thế không bao giờ đổi độ lớn của bất cứ thứ gì, nó chỉ đổi góc giữa các vị trí, và góc mới là thứ mà tích vô hướng trong chú ý đọc được. Đây cũng là một bất biến rất tiện để kiểm: nếu bản cài nào làm chuẩn vector thay đổi thì nó không còn là phép quay nữa, và cổng kiểm số khẳng định điều này trên 320 phép quay.
Sim này không nói được gì
Đây là ranh giới quan trọng nhất của bài, nên đọc kỹ trước khi mang con số nào ra ngoài.
Mọi thứ ở trên là hình học của tần số. Tần số quay, bước sóng, số vòng trong cửa sổ huấn luyện, hệ số nén từng dải, góc ở vị trí xa nhất. Phần đó tính chính xác theo đúng cấu hình bạn đặt, và mọi con số bị cổng kiểm số canh.
Nhưng không một con số nào ở đây nói mô hình sau khi nới còn dùng tốt hay không. Bảng cho thấy YaRN có 0 dải ra ngoài vùng đã học và vẫn giữ nguyên thước đo mịn. Đó là một phát biểu về góc, không phải về chất lượng trả lời. Một phương án có bảng tần số đẹp vẫn có thể cho kết quả tệ trên tác vụ thật, và chuyện đó chỉ đo được bằng thực nghiệm: chạy mô hình thật, trên tác vụ thật, ở độ dài thật. Không tab trình duyệt nào làm được việc đó.
Phần lớn cách nới trong thực tế còn cần tinh chỉnh thêm. Sau khi vặn tần số, người ta thường huấn luyện lại mô hình một chút ở độ dài mới để nó làm quen với vùng vị trí vừa mở ra. Không có gì trong sim này mô hình hoá chuyện huấn luyện, nên đừng đọc bảng như thể nó mô tả một quy trình đầy đủ.
Bản YaRN ở đây là bản đơn giản hoá, và tôi nói rõ chỗ nào. Phần chia ba vùng theo số vòng quay, hàm dốc tuyến tính giữa alpha và beta, và công thức pha trộn hai tốc độ đều làm đúng theo bản gốc chứ không phải tôi bịa. Nhưng bản gốc còn hạ nhiệt độ của softmax chú ý theo hệ số nới, và phần đó tôi không cài, vì nó tác động lên trọng số chú ý chứ không lên hình học tần số. Hai mốc alpha = 1 và beta = 32 là giá trị công bố cho họ Llama, các mô hình khác chỉnh lại. Nói gọn: cột YaRN trong sim là phần hình học của YaRN, không phải YaRN đầy đủ.
Preset mang tên mô hình là ảnh chụp một thời điểm. Ba con số kiến trúc của hai preset Llama ghi lại ngày 27/07/2026. Lĩnh vực này đổi rất nhanh nên hãy tự đối chiếu lại với tệp cấu hình phát hành kèm mô hình. Mọi tham số đều sửa được, nên có số mới hơn thì gõ vào là tính lại ngay.
Vài chỗ dễ vấp
- Nới ngữ cảnh không làm bộ đệm KV nhỏ đi. Hai chuyện hoàn toàn khác nhau: bài này nói về góc, còn KV cache nói về byte. Chạy ở 32.768 vị trí vẫn tốn đúng 8 lần bộ đệm so với 4.096, dù bạn dùng phương án nào.
- Cặp 0 luôn có nghịch tần bằng 1, dù cơ số là bao nhiêu. Vì
base^0bằng 1 với mọi cơ số. Đổi cơ số chỉ kéo giãn phần đuôi của thang tần số, không nhấc được đầu thang. - Đổi cơ số không phải lúc nào cũng làm được gì. Đặt bề rộng đầu về 2 thì chỉ còn một cặp, không có dải nhanh và dải chậm để phân biệt, và sim trả về hệ số nén bằng 1 cho phương án NTK thay vì chia cho không. Nó nói thẳng ra chuyện đó chứ không im lặng.
- Bảng chỉ vẽ 16 trong 64 dải. Trần hiển thị là 16 dòng, lấy cách đều và luôn giữ dải đầu với dải cuối. Mọi con số tổng kết vẫn tính trên đủ 64 dải, và sim báo rõ đang giấu bao nhiêu dòng.
- Thu ngữ cảnh lại thì sim chặn. Đặt cửa sổ mục tiêu nhỏ hơn cửa sổ huấn luyện là hệ số nới nhỏ hơn 1, và không phương án nào ở đây được thiết kế cho chuyện đó. Sim dừng bảng lại chứ không cho ra một cột số vô nghĩa.
Cả ba cách nới ngữ cảnh đều làm đúng một việc: chia tốc độ quay của từng dải tần cho một hệ số. Chúng khác nhau ở chỗ hệ số đó có phụ thuộc vào dải hay không. Nội suy vị trí dùng cùng một hệ số cho mọi dải, nên nó kéo được vị trí xa về chỗ cũ nhưng đồng thời làm thô thước đo mịn nhất, từ 1 radian xuống 0,125 radian. Đổi cơ số cho hệ số tăng dần từ 1 tới k, nên giữ nguyên thước đo mịn nhưng chữa chưa tới ở đuôi chậm. YaRN quyết định theo số vòng quay của từng dải và ở cấu hình này ăn cả hai đầu. Còn chuyện phương án nào cho mô hình trả lời tốt hơn thì bảng này không nói được, phải đo bằng thực nghiệm.
- 1Cấu hình mặc định nới từ 4.096 lên 32.768. Nội suy vị trí làm gì với khoảng cách góc giữa hai vị trí liền nhau ở dải quay nhanh nhất?
- 2Vì sao đổi cơ số kiểu NTK giữ được thước đo mịn còn nội suy vị trí thì không?
- 3Ở cấu hình mặc định, bảng cho thấy YaRN có 0 dải nằm ngoài vùng góc đã học và vẫn giữ thước đo mịn ở 1 radian. Kết luận nào đúng?
Đi tiếp
Nếu muốn xem lại vì sao vị trí lại được mã hoá bằng phép quay chứ không phải bằng một vector cộng vào, quay lại RoPE. Còn nếu quan tâm tới cái giá bộ nhớ của ngữ cảnh dài, thứ mà bài này cố tình không đụng tới, thì đó là chuyện của KV cache và những cách nén nó ở chương trước.