Mô hình này chạy được trên máy nào
Mô hình này chạy được trên máy nào
Câu hỏi thực dụng nhất của cả chương, và nó chỉ cần ba phép nhân với một phép so sánh. Phần thú vị nằm ở chiều ngược lại: máy này chịu được ngữ cảnh dài bao nhiêu?
Cả chương này bạn đã đếm từng khoản riêng lẻ. Bộ đệm KV lớn lên tuyến tính theo ngữ cảnh và theo cỡ lô. Chú ý theo nhóm cắt số đầu KV nên cắt thẳng vào cái bộ đệm đó. Cửa sổ trượt làm nó thôi lớn lên. Định dạng số đổi số byte mỗi phần tử. Bộ nhớ khi huấn luyện cho thấy huấn luyện là một hoá đơn khác hẳn. Còn hai bài đầu chương này thì dạy bạn đọc tệp cấu hình và các tệp trọng số để lấy đúng những con số ấy.
Bài này gộp chúng lại để trả lời một câu rất đời: mô hình này chạy được trên máy nào. Câu trả lời là ba phép nhân, một phép cộng và một phép so sánh. Nhưng có một con số thứ hai quan trọng hơn chữ vừa hay không vừa, và hầu như không ai chịu tính: với máy này thì ngữ cảnh dài nhất còn nhét được là bao nhiêu token. Sim dưới đây tính cả hai, và mọi tham số bạn sửa được.
1 · Mô hình ✎ sửa được
2 · Máy, và phần dôi khi chạy ✎ sửa được
3 · Hoá đơn
| khoản | byte | phần của tổng | cách tính |
|---|---|---|---|
| trọng số | 14,9 GiB | 43,8% | số tham số × 2 byte |
| bộ đệm KV | 16,0 GiB | 47,1% | 2 × lớp × đầu KV × chiều × byte × token × lô |
| phần dôi khi chạy (ước lượng) | 3,1 GiB | 9,1% | 10% của hai dòng trên, làm tròn lên |
| tổng phải có | 34,0 GiB | 100,0% | 141,6% của dung lượng đang có |
trọng số: 8.000.000.000 tham số × 2 byte = 16.000.000.000 byte
bộ đệm KV: 2 × 32 × 8 × 128 × 2 × 131.072 × 1 = 17.179.869.184 byte
tổng: 16.000.000.000 + 17.179.869.184 + 3.317.986.919 = 36.497.856.103 byte
tổng ≤ dung lượng, và ở đúng chỗ bằng nhau thì kết luận là vừa. Với hoá đơn này, 2 thiết bị 24 GiB là ít nhất mà vẫn vừa, còn 1 thiết bị thì không.4 · Giải ngược: ngữ cảnh dài nhất còn nhét được
(100 × 25.769.803.776 trừ 16.000.000.000 × 110) ÷ (131.072 × 110) → lấy phần nguyên = 56.664 token
5 · Các độ dài ngữ cảnh khác thì sao
| ngữ cảnh | bộ đệm KV | tổng phải có | kết luận |
|---|---|---|---|
| 4.096 token | 512,0 MiB | 16,9 GiB | ✔ vừa |
| 8.192 token | 1,0 GiB | 17,5 GiB | ✔ vừa |
| 32.768 token | 4,0 GiB | 20,8 GiB | ✔ vừa |
| 131.072 token (đang đặt) | 16,0 GiB | 34,0 GiB | ✘ không vừa |
| 524.288 token | 64,0 GiB | 86,8 GiB | ✘ không vừa |
| 1.048.576 token | 128,0 GiB | 157,2 GiB | ✘ không vừa |
- Nó cộng byte. Nó không nói mô hình chạy nhanh bao nhiêu. Một cấu hình vừa khít có thể chậm tới mức vô dụng, và một cấu hình dư bộ nhớ vẫn có thể nghẽn ở băng thông. Tốc độ phải đo, không suy ra được từ bảng này.
- Nhiều thiết bị ở đây bị coi như một bể bộ nhớ chung. Thực tế bạn phải chọn cách chia: chia theo lớp thì mỗi thiết bị giữ vài lớp và dữ liệu chạy qua chúng lần lượt, chia theo tensor thì mỗi thiết bị giữ một phần của cùng một phép nhân và phải gộp kết quả liên tục. Mỗi cách có phí liên lạc và phần dôi riêng, sim không tính khoản nào trong đó.
- Bộ đệm được đếm thẳng, tức đặt trước đủ chỗ cho toàn bộ độ dài ngữ cảnh của mọi câu trong lô. Bộ đệm phân trang chỉ cấp theo khối khi cần, nên nó thường dùng bộ nhớ hiệu quả hơn cách đếm ở đây. Con số này là trường hợp xấu, không phải mức đo được.
- Dung lượng lấy nguyên con số công bố của thiết bị. Phần thật sự dùng được luôn nhỏ hơn, vì trình điều khiển và ngữ cảnh CUDA đã lấy một ít. Nói cách khác: sim lạc quan ở cả hai phía, đòi hỏi thì đếm thiếu mà cung thì đếm thừa.
- Phần dôi là một hệ số bạn đặt. Không có con số đúng cho nó. Cách duy nhất biết máy bạn tốn bao nhiêu là chạy rồi đo.
- Preset chỉ chép lại số công bố kèm nguồn và ngày. Cổng kiểm số canh phép tính, không canh chuyện mô hình hay thiết bị ngoài kia có đúng những con số đó hay không.
Hoá đơn gồm đúng ba khoản
Khoản một, trọng số, bằng số tham số nhân số byte mỗi tham số. Ở trạng thái mở bài là 8 tỉ tham số ở 2 byte, tức 8.000.000.000 × 2 = 16.000.000.000 byte, hiện là 14,9 GiB. Khoản này là hằng số: nó không quan tâm câu nhắc dài một trăm hay một trăm nghìn token. Đổi sang 1 byte thì nó còn một nửa, đổi sang 4 bit thì còn một phần tư, và đó là toàn bộ lý do người ta lượng tử hoá trọng số.
Khoản hai, bộ đệm KV, đúng công thức bài bộ đệm KV đã dựng: 2 × số lớp × số đầu KV × chiều mỗi đầu × số byte × số token × cỡ lô. Số 2 đứng đầu là vì mỗi token để lại một vectơ khoá và một vectơ giá trị, không có gì khác nấp trong đó. Với 32 lớp, 8 đầu KV, 128 chiều mỗi đầu và 2 byte, một token ở một lớp tốn 2 × 8 × 128 × 2 = 4096 byte, nhân 32 lớp thành 131.072 byte tức 128,0 KiB cho mỗi token. Ngữ cảnh 131.072 token với lô 1 thì thành 17.179.869.184 byte, đúng 16,0 GiB. Khoản này lớn hơn khoản trọng số ngay ở trạng thái mở bài: 47,1% của tổng so với 43,8%.
Khoản ba, phần dôi khi chạy, là ước lượng chứ không phải phép đo. Vùng làm việc tạm của các nhân tính, phân mảnh bộ cấp phát, đệm thừa, ngữ cảnh CUDA: những thứ này có thật, chúng tốn bộ nhớ thật, và không phép nhân nào trên trang này đoán được chúng. Nên sim để chúng thành một hệ số bạn đặt, mặc định 10% của hai khoản trên, làm tròn lên. Ở trạng thái mở bài đó là 3.317.986.919 byte tức 3,1 GiB. Hãy coi con số 10% là một quy ước để có cái mà bàn, không phải một hằng số của tự nhiên. Kéo nó về 0 thì cả trang chỉ còn số học thuần, và đó là cách kiểm tra xem kết luận của bạn có phụ thuộc vào phần đoán hay không.
Cộng lại: 16.000.000.000 + 17.179.869.184 + 3.317.986.919 = 36.497.856.103 byte, tức 34,0 GiB.
Kết luận nhị phân, và cái mốc bằng nhau
Thiết bị mở bài là một thẻ 24 GiB, tức 25.769.803.776 byte. Tổng đang là 141,6% của con số đó, nên kết luận là không vừa, thiếu 10.728.052.327 byte tức 10,0 GiB. Sim còn nói luôn: cần 2 thiết bị 24 GiB mới vừa, và với 2 thiết bị thì còn dư 14,0 GiB.
Mốc được định nghĩa là tổng ≤ dung lượng, và ở đúng chỗ bằng nhau thì kết luận là vừa. Nghe như chi li thừa thãi, nhưng đây là loại lỗi không con số nào trên màn hình tố cáo được: viết nhầm thành tổng < dung lượng thì mọi cấu hình vẫn hiện đúng byte, chỉ riêng cấu hình rơi trúng mốc bị kết luận sai, và không ai đứng đúng vào chỗ đó để phát hiện. Cổng kiểm số của bài vì vậy khẳng định cả ba điểm: đúng trên mốc, thấp hơn mốc một byte, cao hơn mốc một byte.
Nói cho công bằng: trong thực tế bạn sẽ không muốn chạy ở đúng 100% dung lượng. Nhưng chỗ để cài cái thận trọng đó là núm phần dôi, không phải phép so sánh. Trộn hai thứ vào nhau là cách chắc chắn để sau này không biết mình đang đo cái gì.
Con số ít ai tính: ngữ cảnh dài nhất còn nhét được
Chữ vừa hay không vừa chỉ trả lời một bit. Câu hỏi có ích hơn là: giữ nguyên máy và trọng số, ngữ cảnh dài nhất mà bộ đệm còn nhét được là bao nhiêu. Phép giải ngược khá gọn. Gọi W là byte trọng số, c là giá một token ngữ cảnh cho cả lô, p là phần dôi tính theo phần trăm, C là dung lượng. Hoá đơn ở ngữ cảnh T là W + cT cộng thêm phần dôi của chính nó, nên điều kiện vừa rút gọn được thành
(W + cT) × (100 + p) ≤ 100 × C
và số token tối đa là phần nguyên của (100C - W(100 + p)) ÷ (c(100 + p)).
Ở trạng thái mở bài, phép đó cho 56.664 token. Tức mô hình 8 tỉ tham số ở 2 byte đúng là chạy được trên một thẻ 24 GiB, nhưng chỉ với khoảng 43% ngữ cảnh mà nó được huấn luyện để dùng. Con số này chính xác tới từng byte: ở 56.664 token thì hoá đơn là 25.769.770.189 byte, còn dư 33.587 byte; thêm đúng một token nữa thành 25.769.914.368 byte và vượt thẻ. Cổng kiểm số khẳng định cả hai chiều, vì chỉ khẳng định một chiều thì một công thức lệch một đơn vị vẫn xanh mãi mãi.
Bấm sang preset Llama 3.1 8B ở 4 bit: cùng mô hình, cùng thẻ, chỉ đổi hai ô byte. Hoá đơn tụt xuống 12,9 GiB, kết luận thành vừa, và ngữ cảnh tối đa lên 296.433 token, tức vượt xa cái 131.072 mà mô hình được huấn luyện. Đây là toàn bộ nội dung của câu "lượng tử hoá để chạy trên máy cá nhân", viết bằng số.
Khi cắt ngữ cảnh không cứu được gì
Preset Llama 3.1 70B trên một thẻ 80 GiB là ca đáng nhìn kỹ nhất. Trọng số ở 2 byte là 140.000.000.000 byte tức 130,4 GiB, trong khi thẻ chỉ có 85.899.345.920 byte tức 80,0 GiB. Ngữ cảnh tối đa ra 0 token, và đó là số 0 thật chứ không phải một số âm bị che đi: ngay cả khi bộ đệm rỗng hoàn toàn thì trọng số một mình đã không nạp nổi.
Điều này nghe hiển nhiên khi viết ra, nhưng nó đổi hẳn việc cần làm. Khi ngữ cảnh tối đa bằng 0 thì cắt ngữ cảnh là vô nghĩa, dù cắt bao nhiêu: bạn phải hạ số byte mỗi trọng số hoặc thêm thiết bị. Sim nói luôn cần 3 thiết bị 80 GiB mới vừa cho cấu hình đó, và 2 thiết bị thì không.
Có một biến thể tinh vi hơn mà sim cũng phân biệt: trọng số vừa, nhưng cộng phần dôi lên chúng thì đã vượt. Lúc đó ngữ cảnh tối đa cũng bằng 0, mà lý do khác hẳn, nên sim ghi hai câu giải thích khác nhau chứ không dùng chung một câu cho tiện.
Đọc preset và đọc dung lượng cho đúng
Preset ở đây là một cặp: một mô hình và một thiết bị, vì câu hỏi của bài là cặp đó chứ không phải riêng cái nào. Mỗi vế mang tên, ngày chép và nguồn riêng, và ngày hiện ngay dưới hàng preset. Preset thứ nhất ghi rõ cả mô hình lẫn thiết bị đều là số minh hoạ, không phải cấu hình của ai cả, vì thà nói là minh hoạ còn hơn dán một cái tên lên những con số mình không kiểm được.
Hai điểm nhỏ nhưng hay làm người ta nhầm:
- Dung lượng công bố không phải dung lượng dùng được. Trình điều khiển và ngữ cảnh CUDA đã lấy một ít trước khi tiến trình của bạn thấy byte nào. Sim lấy nguyên con số công bố, nên nó lạc quan ở cả hai phía: đòi hỏi thì đếm thiếu, còn cung thì đếm thừa.
- Cỡ lô và phần dôi không thuộc về preset. Đó là cách bạn phục vụ mô hình, không phải thuộc tính của mô hình hay của thẻ, nên bấm preset không đụng vào hai ô đó. Đổi cỡ lô từ 1 lên 2 là nhân đôi toàn bộ khoản bộ đệm, và bảng sẽ cho bạn thấy ngay.
Sim này không chứng minh được gì
Phần này quan trọng ngang phần trên, nên đọc kỹ.
- Nó không nói mô hình chạy nhanh bao nhiêu. Nó cộng byte. Một cấu hình vừa khít vẫn có thể chậm tới mức không dùng được, và một cấu hình dư bộ nhớ vẫn có thể nghẽn ở băng thông. Tốc độ phải đo.
- Nó gộp nhiều thiết bị thành một bể bộ nhớ chung. Thực tế bạn phải chọn cách chia. Chia theo lớp thì mỗi thiết bị giữ một số lớp và dữ liệu đi qua chúng lần lượt. Chia theo tensor thì mỗi thiết bị giữ một phần của cùng một phép nhân và phải gộp kết quả liên tục. Mỗi cách có phí liên lạc và phần dôi riêng, và sim không tính khoản nào trong đó. Đây là chỗ nó yếu nhất.
- Nó đếm bộ đệm thẳng, tức đặt trước đủ chỗ cho toàn bộ độ dài ngữ cảnh của mọi câu trong lô. Bộ đệm KV phân trang chỉ cấp theo khối khi cần nên thường dùng bộ nhớ hiệu quả hơn hẳn cách đếm ở đây. Con số của sim là trường hợp xấu, không phải mức đo được.
- Phần dôi là hệ số bạn đặt. Không có con số đúng cho nó. Cách duy nhất biết máy bạn tốn bao nhiêu là chạy rồi đo.
Cổng kiểm số của bài canh phép tính: nếu cấu hình là như vậy thì từng khoản, tổng, kết luận vừa hay không vừa và số token tối đa phải đúng như vậy, kiểm cả ở đúng mốc biên lẫn một byte hai bên. Nó không canh, và không thể canh, những khẳng định về tốc độ hay về việc mô hình ngoài kia có thật sự mang những con số này.
Hoá đơn để chạy một mô hình gồm ba khoản: trọng số là hằng số, bộ đệm KV lớn lên theo ngữ cảnh nhân cỡ lô, phần dôi khi chạy là ước lượng nên phải để nó thành một núm chứ đừng giả vờ biết. Cộng lại rồi so với dung lượng nhân số thiết bị, và nhớ rằng mốc bằng nhau thì tính là vừa. Nhưng con số đáng mang đi dùng không phải chữ vừa hay không vừa mà là ngữ cảnh dài nhất còn nhét được: nó chỉ là một phép chia, và nó cho biết bạn phải cắt gì. Khi số đó bằng 0 thì cắt ngữ cảnh không cứu được gì, phải hạ bit hoặc thêm máy. Cuối cùng: phép cộng này nói được cái gì vừa, nó không nói được cái gì nhanh.
- 1Một cấu hình cộng lại ra đúng 25.769.803.776 byte, và thiết bị cũng đúng 25.769.803.776 byte. Sim kết luận thế nào, và vì sao lại phải nói rõ chuyện này?
- 2Llama 3.1 8B ở 2 byte trên một thẻ 24 GiB: tổng ra 34,0 GiB nên không vừa, còn ngữ cảnh tối đa là 56.664 token. Con số 56.664 nói cho bạn biết phải làm gì?
- 3Llama 3.1 70B ở 2 byte trên một thẻ 80 GiB, sim báo ngữ cảnh tối đa bằng 0 token. Đọc con số 0 đó thế nào cho đúng?