Chuyển đến nội dung chính
Tối ưu suy luận · Cập nhật 1 tháng 11, 2026

4.3 Weight-only INT4

Hiểu lưu trữ và tính toán W4A16, bù sai số bậc hai của GPTQ, scale theo activation của AWQ, và Marlin biến lưu trữ INT4 thành lợi ích suy luận thế nào

GPTQ AWQ INT4 Weight-only Marlin

W8A8 ở mục 4.2 phải xử lý đồng thời weight và activation. Mục này đi đường khác: giữ activation ở FP16/BF16 và chỉ nén weight xuống 4-bit, tức W4A16. Ở pha decode mỗi bước đọc lại toàn bộ bộ weight từ bộ nhớ GPU. Thu nhỏ weight còn một phần tư thì thời gian đọc cũng thu theo. Cái khó là 4-bit chỉ có 16 mã, và khoảng cách tick khoảng 17× so với 8-bit (mục 4.1), nên cần cách giữ sai số đừng làm hỏng đầu ra quá nhiều.

GPTQ và AWQ là hai cách sửa chính: cái trước giống chỉnh các mảnh còn lại mỗi lần đặt một mảnh puzzle; cái sau tìm các mảnh quan trọng nhất trước rồi bảo vệ chúng. Marlin rồi giúp GPU đọc và tính các weight 4-bit đó hiệu quả.

⏰ Độ mới của thông tin: Phần thuật toán theo từng bài báo tương ứng. Chọn kernel và gợi ý toolchain của vLLM dựa trên vLLM v0.32.0 (phát hành 2026-10-18).

📑 Mục lục


1. Lưu trữ và tính toán W4A16

Weight INT4 nằm trong bộ nhớ GPU theo kiểu đóng gói: một từ 32-bit chứa tám mã 4-bit, cộng thêm một Scale mỗi nhóm, và các scheme bất đối xứng còn lưu zero-point. Lúc suy luận kernel đọc các mã, dequantize trên chip thành FP16/BF16, rồi nhân với activation 16-bit.

Vậy khi thấy “mô hình INT4”, hãy tách hai thứ: kiểu lưu trữ của weight là INT4; kiểu đầu vào của lệnh nhân vẫn là 16-bit. Đường này tiết kiệm băng thông đọc weight, không tiết kiệm tính toán nhân.

Bên trái hình dưới là một nhóm weight trong bộ nhớ (xanh = mã INT4, vàng = Scale FP16, ô trắng = zero-point chỉ với scheme bất đối xứng). Bên phải là kernel khôi phục chúng trên chip thành weight FP16 (xanh lá) rồi nhân với activation 16-bit (đỏ):

Lưu trữ và tính toán W4A16: tám mã 4-bit đóng vào một từ 32-bit trong bộ nhớ, mỗi 128 weight chia sẻ một Scale FP16, và kernel unpack rồi dequantize thành FP16 trên chip trước khi nhân với activation 16-bit

Các tham số nhóm cũng chiếm chỗ. Khi mỗi 128 weight INT4 chia sẻ một Scale FP16, trung bình mỗi weight là:

48+2128=0.515625 byte\frac{4}{8}+\frac{2}{128}=0.515625\ \text{byte}

Thêm zero-point và căn chỉnh thì còn lớn hơn một chút. Tiết kiệm được bao nhiêu thời gian phụ thuộc unpack và dequantize có gộp với nhân ma trận trong một kernel hay không, và phần còn lại của bước còn bao nhiêu đọc KV, Attention, v.v.


2. GPTQ: lượng tử hóa rồi bù dần

2.1 Hàm mục tiêu phải gồm cả đầu vào

Nếu chỉ cực tiểu ∥W−W^∥F2\|W-\widehat W\|_F^2, sai số mỗi weight được chấm ngang nhau. Sau lớp tuyến tính, có sai số bị đầu vào phóng đại và có sai số triệt tiêu. GPTQ dùng đầu vào calibration và đổi mục tiêu sang sai số tái tạo trên đầu ra lớp:

min⁡W^ ∥XW−XW^∥F2\min_{\widehat W}\ \|XW-X\widehat W\|_F^2

Lấy một cột weight kênh đầu ra ww, và viết δ=w−w^\delta=w-\widehat w:

E=∥Xδ∥22=δTXTXδ,H=2XTXE=\|X\delta\|_2^2=\delta^\mathsf TX^\mathsf TX\delta, \qquad H=2X^\mathsf TX

HH mô tả, dưới đầu vào thực, sai số theo mỗi hướng đắt bao nhiêu và các kênh đầu vào tương quan thế nào. Nó chỉ đến từ mục tiêu tái tạo của đúng một lớp tuyến tính đó; bạn không cần Hessian của toàn bộ loss mô hình ngôn ngữ.

2.2 Trực giác bù sai số

Khi một mảnh puzzle lệch, bạn có thể chỉnh nhẹ các mảnh lân cận còn tự do để bù. GPTQ cũng vậy: mỗi lần cố định một weight, bạn trải sai số của nó sang các weight chưa lượng tử hóa.

Lấy ví dụ 2 chiều. Nếu hai cột của đầu vào calibration gần như giống nhau, đầu ra chủ yếu phụ thuộc w1+w2w_1+w_2. Lượng tử hóa w1=0.26w_1=0.26 thành 0.30 vượt 0.04; trong lúc w2w_2 còn tự do, trừ 0.04 khỏi nó thì đầu ra hầu như không đổi. Khi hai cột không hoàn toàn giống nhau, mức bù do HH quyết, không phải cộng trừ đơn giản.

Gọi FF là tập chỉ số các weight chưa cố định, và HFH_F là ma trận con tương ứng. Sau khi cố định wiw_i thành giá trị đã lượng tử hóa w^i\widehat w_i, bù tối ưu là:

ΔwF=−wi−w^i[HF−1]ii[HF−1]:,i\Delta w_F=-\frac{w_i-\widehat w_i}{[H_F^{-1}]_{ii}}[H_F^{-1}]_{:,i}

Phần tử thứ ii biến wiw_i đúng thành w^i\widehat w_i; phần còn lại là chỉnh cho các weight còn lại. w^i\widehat w_i là giá trị đã dequantize cùng thang với weight gốc, không phải mã nguyên. Bản triển khai chính thức còn thêm damping để ổn định số học và dùng phân tích Cholesky kèm cập nhật theo khối để giảm chi phí.

Đừng lẫn hai con “128”: update block size quyết bao nhiêu cột bạn xử lý một lần và tần suất lan truyền sai số theo batch; Group Size quyết bao nhiêu weight chia sẻ một Scale.

2.3 Chi phí và hiệu quả

Bài báo báo cáo GPTQ mất khoảng 4 GPU-giờ để lượng tử hóa một mô hình GPT 175B tham số, rằng mất độ chính xác không đáng kể khi xuống 3–4 bit, và đó là lần đầu một mô hình 175B chạy được trên một GPU duy nhất. Lượng tử hóa là chi phí offline một lần; suy luận không còn cần HH.


3. AWQ: tìm kênh cần bảo vệ từ activation

3.1 Weight lớn chưa chắc quan trọng nhất

Với y=∑jxjwjy=\sum_jx_jw_j, sai số weight Δwj\Delta w_j đánh vào đầu ra thành xjΔwjx_j\Delta w_j. Mức quan trọng của một weight phụ thuộc activation nhân với nó lớn bao nhiêu, không phụ thuộc bản thân weight lớn bao nhiêu.

Bài AWQ nêu hai điểm: chỉ bảo vệ 1% weight nổi bật đã cắt sai số lượng tử hóa rất nhiều; và bạn nên tìm các kênh nổi bật đó từ phân phối activation, không phải từ weight.

3.2 Dùng scale thay vì mixed precision

Cách bảo vệ thẳng nhất là giữ 1% đó ở FP16, nhưng layout lưu trữ mixed-precision khó với kernel. AWQ dùng scale thay thế: trước lượng tử hóa, phóng đại weight kênh nổi bật bằng sjs_j và chia đầu vào tương ứng cho sjs_j. Dùng lại ký hiệu ở mục 4.2:

Y=(XS−1)(SW),Y^=(XS−1) D(Q(SW))Y=(XS^{-1})(SW),\qquad \widehat Y=(XS^{-1})\,D(Q(SW))

QQ sinh mã low-bit; DD dequantize bằng Scale và zero-point. Sau phóng đại, miễn là khoảng cách tick lượng tử hóa của nhóm không tăng cùng hệ số, chia lại cho sjs_j để lại sai số hiệu dụng nhỏ hơn trên kênh đó. Phóng quá mạnh thì mở rộng cả dải của nhóm, làm hại các weight khác trong nhóm, nên AWQ tìm hệ số scale trên dữ liệu calibration và ghép với clipping để kiểm soát tổng sai số.

Thứ bạn triển khai vẫn là layout INT4 thông thường, không lưu riêng weight FP16, nên kernel hiệu quả hỗ trợ dễ. TinyChat đi kèm bài báo nhanh hơn Hugging Face FP16 hơn 3× trên GPU desktop và mobile.

3.3 So với SmoothQuant

Cả hai đều dùng scale theo cặp, nhưng mục tiêu khác:

📊 Phương phápXử lý gìHướng scaleCấu hình điển hình
SmoothQuantOutlier activation khiến activation INT8 khóLàm phẳng activation; đẩy độ khó sang weightINT8 W8A8
AWQSai số weight kênh nổi bật bị activation lớn phóng đạiPhóng đại weight nổi bật; cắt sai số tương đối của chúngINT4 W4A16

Riêng bước tìm scale của AWQ vẫn để lại weight số thực; bạn vẫn phải lượng tử hóa và đóng gói sau. Khi so phương pháp, hãy tách ba sản phẩm trung gian: weight số thực đã scale, weight số thực Fake-Quant (QDQ), và weight đóng gói triển khai thật.


4. Marlin: đừng để unpack làm chậm tính toán

Khi mã đã sẵn, vẫn còn một bài kỹ thuật. Đường ngây thơ bung toàn bộ INT4 của lớp thành FP16, ghi lại bộ nhớ GPU, rồi gọi GEMM thường. Việc đó thêm một vòng đọc/ghi lớn và trả lại hết băng thông vừa tiết kiệm.

Marlin đưa đọc weight, unpack, dequantize và nhân ma trận vào một pipeline kernel. Bên trái hình là đường ngây thơ, nơi weight FP16 đã bung (xanh lá) ghi lại bộ nhớ rồi bị đọc lại; bên phải là Marlin, nơi chuyển dữ liệu xanh và tính trên chip vàng lệch nhau một tile và chạy cùng lúc:

Đường ngây thơ bung INT4 thành FP16, ghi lại, rồi chạy GEMM, khoảng 4.5 B đọc/ghi mỗi weight; Marlin đọc INT4 theo tile trong một kernel, unpack và dequantize trên chip, nhân, và chồng chuyển dữ liệu với tính toán

Weight được sắp sẵn theo layout hợp đọc lúc chạy, rồi tiling và đệm nhiều tầng từ module 2 chồng chuyển dữ liệu với tính toán. Bài báo báo cáo gần trần tăng tốc lý thuyết 4× với batch 16–32, vẫn còn lợi rõ ở 64–128 khi tốc độ tăng thu hẹp, và tới khoảng 2.8× end-to-end khi gắn vào backend vLLM.

Khi batch đủ lớn, tính toán lại thành bottleneck và lợi thế đọc ít weight bị pha loãng. Điều đó khớp phân tích Roofline ở chương 1.

4.1 Chọn kernel trong vLLM

Trong vLLM v0.32.0, tên phương pháp lượng tử hóa và kernel đã tách:

  • --quantization đặt awq, awq_marlin, hoặc auto_awq đều resolve về cùng cấu hình auto_awq; GPTQ với gptq, gptq_marlin, và auto_gptq cũng vậy. Để trống thì vLLM tự nhận từ quant_method trong checkpoint.
  • Kernel nào thực sự chạy do vLLM kiểm các ứng viên theo thứ tự ưu tiên cho lớp hiện tại. Trên CUDA, các ứng viên weight INT4 W4A16 chính theo thứ tự là Machete (chỉ Hopper, compute capability 9.0), Marlin (Turing trở lên), Conch, Exllama, Triton, v.v. Cái đầu tiên vượt kiểm thắng.
  • Log khởi động in dòng kiểu Using MarlinLinearKernel for AutoAWQMarlinLinearMethod. Khi một lớp AWQ không đủ điều kiện, bạn thấy “Falling back to unoptimized AWQ kernels”.
  • Để loại một kernel khi so sánh, dùng biến môi trường VLLM_DISABLED_KERNELS.

GPTQ/AWQ quyết sai số của encoding; kernel quyết encoding đó chạy nhanh bao nhiêu. Muốn biết đường nào bạn thực sự đi, đọc log khởi động. Đừng chỉ nhìn tên mô hình.


5. So sánh GPTQ và AWQ thế nào

5.1 Tách bốn chiều trước

Một chuỗi kiểu “GPTQ, INT4 W4A16, Group Size 128, Marlin” trả lời bốn câu khác nhau:

📊 ChiềuVí dụTrả lời gì
Thuật toán lượng tử hóaGPTQ hoặc AWQSai số lượng tử hóa được kiểm soát thế nào
Định dạng và độ rộng bitINT4 W4A16Weight được mã hóa thế nào; activation giữ độ chính xác nào
Độ hạt lượng tử hóaGroup Size 128Bao nhiêu weight chia sẻ một nhóm Scale
Triển khai thực thiMarlin, MacheteCác mã được đọc và tính thế nào

W4A16 không khóa một thuật toán, và cùng một thuật toán có thể ghép với nhóm và kernel khác nhau.

Hình dưới đặt hai thuật toán cạnh nhau. Bên trái, GPTQ lượng tử hóa từng cột (xanh đặc = đã lượng tử hóa, xanh gạch chéo = cột hiện tại) và bù sai số sang các weight còn nổi bên phải (xanh lá). Bên phải, AWQ tìm kênh nổi bật từ độ lớn activation (đỏ đặc), phóng đại weight tương ứng, rồi lượng tử hóa cả nhóm. Cả hai đường cuối cùng xuất cùng một checkpoint INT4 thông thường:

GPTQ lượng tử hóa từng cột và bù các weight còn lại; AWQ tìm kênh nổi bật từ activation và scale để bảo vệ chúng; cả hai đóng thành INT4 và xuất Scale cùng zero-point

Khi cả bốn đã cố định, mới so bản thân thuật toán:

📊 ChiềuGPTQAWQ
Dữ liệu calibration dùng đểDựng HH; đo sai số đầu ra lớpThu thập activation; tìm scale theo kênh
Đòn bẩy chínhLượng tử hóa từng cột; bù các weight còn lạiPhóng đại kênh nổi bật; cắt sai số tương đối của chúng
Tính offlineGiải bài tái tạo mỗi lớp; cập nhật mọi weightTìm hệ số scale theo kênh; không viết lại weight từng cái
Tốc độ suy luậnPhụ thuộc layout xuất và kernelCũng phụ thuộc layout xuất và kernel

“AWQ luôn nhanh hơn” và “GPTQ luôn chính xác hơn” đều thiếu tiền đề. So sánh công bằng ít nhất phải cố định mô hình gốc, độ rộng bit, Group Size, tập calibration, độ dài đầu vào và tải, rồi ghi kernel nào thực sự được nạp.

5.2 Lượng tử hóa bằng công cụ nào

  • LLM Compressor: do dự án vLLM duy trì; hỗ trợ GPTQ, AWQ và SmoothQuant; xuất compressed-tensors mà vLLM nạp trực tiếp. Ví dụ INT4 W4A16 trong tài liệu vLLM dùng GPTQModifier(scheme="W4A16").
  • GPTQModel: tập trung họ GPTQ; tài liệu ghi các mô hình tương thích có thể dùng kernel Marlin và Machete của vLLM.
  • AutoAWQ: không còn được duy trì. Tài liệu vLLM khuyên chuyển sang AWQ trong LLM Compressor. Checkpoint AutoAWQ sẵn có vẫn nạp bình thường.

5.3 Thứ tự gỡ lỗi

  1. Xác nhận checkpoint: cấu hình lượng tử hóa có đủ không, và mô hình gốc cùng phiên bản có khớp không.
  2. Đọc log nạp: kernel nào thắng, và có fallback không.
  3. Kiểm chất lượng trước: đánh giá trên tập nhiệm vụ độc lập; đừng chọn vài đầu ra đẹp.
  4. Rồi mới đo hiệu năng: nhìn riêng decode batch nhỏ, batch lớn và prompt dài. Bộ nhớ lượng tử hóa giải phóng cũng có thể đổ vào concurrency cao hơn.

📝 Tóm tắt

  • W4A16 chỉ nén weight. Lưu trữ là INT4; đầu vào nhân vẫn 16-bit. Thứ bạn tiết kiệm là băng thông đọc weight.
  • GPTQ đo sai số đầu ra lớp bằng đầu vào calibration và, qua H=2XTXH=2X^\mathsf TX, bù sai số mỗi weight sang các weight chưa lượng tử hóa.
  • AWQ tìm kênh nổi bật theo độ lớn activation và bảo vệ chúng bằng scale thay vì mixed precision, nên layout triển khai vẫn đều.
  • Marlin gộp unpack, dequantize và nhân ma trận thành một pipeline. Batch nhỏ gần tăng tốc lý thuyết 4×; lợi ích thu hẹp khi batch lớn.
  • Trong vLLM v0.32.0, alias phương pháp AWQ/GPTQ được thống nhất và kernel được chọn tự động theo ưu tiên. Tin log khởi động.
  • Trước khi so GPTQ và AWQ, hãy cố định định dạng, độ hạt và kernel trước.

🎯 Danh sách tự kiểm

  • Tính được dung lượng trung bình mỗi weight INT4 dưới Group Size 128 với Scale FP16
  • Giải thích được vì sao ∥XW−XW^∥\|XW-X\widehat W\| gần đầu ra lớp hơn là chỉ nhìn sai số weight
  • Minh họa được ý bù của GPTQ với hai kênh đầu vào tương quan cao
  • Phân biệt được update block size của GPTQ với Group Size lượng tử hóa
  • Giải thích được vì sao AWQ tìm kênh nổi bật từ activation chứ không từ weight, và vì sao dùng scale thay mixed precision
  • Đối chiếu được hướng và mục đích của scale theo cặp ở AWQ và SmoothQuant
  • Giải thích được vì sao tăng tốc của Marlin thu hẹp khi batch lớn
  • Từ log khởi động vLLM, nói được mô hình INT4 thực sự dùng kernel nào

📚 Tài liệu tham khảo