@@ -30,44 +30,96 @@ The old TorchInductor demo is no longer the mainline.
3030
3131- ` runtime/examples/sglang_quant/approx_quant_patch.py `
3232 - runtime patch for SGLang ` UnquantizedLinearMethod `
33- - prepares quantized weights and scales
33+ - prepares quantized weights, scales, and SmoothQuant calibration state
3434 - redirects selected linear call sites to quantized Triton kernels
3535
3636- ` runtime/examples/sglang_quant/approx_kernels.py `
37- - W8A16 and W8A8 Triton kernels
37+ - W8A16, W8A8, and SmoothQuant-style W4A16 Triton kernels
3838 - same-signature substitute kernels used by approxMLIR function substitution
3939
40+ - ` runtime/examples/sglang_quant/compare_sglang_logprobs.py `
41+ - exact-vs-approx accuracy probe using SGLang logprob APIs
42+ - reports teacher-forced token-logprob drift and top-k distribution drift
43+ - uses stepwise decode when ` APPROX_SGLANG_DECODE_ONLY=1 `
44+
4045- ` runtime/examples/sglang_quant/bootstrap/sitecustomize.py `
4146 - installs hooks inside SGLang worker subprocesses
4247
4348## Current Quantization Strategy
4449
45- The useful path today is ` APPROX_SGLANG_BACKEND=triton_w8a16 ` .
50+ The useful path today is still ` APPROX_SGLANG_BACKEND=triton_w8a16 ` .
51+
52+ The new lower-bit path is:
53+
54+ - ` APPROX_SGLANG_BACKEND=triton_sq_w4a16 `
55+
56+ This is not a naive int4 path. It is a SmoothQuant-style calibrated ` W4A16 `
57+ flow with:
58+
59+ - offline activation-stat collection on targeted linear layers
60+ - smoothing-factor computation from activation and weight statistics
61+ - one-time load-time packing into group-wise int4 weights
62+ - online activation-side inverse smoothing inside the Triton kernel
4663
4764It is weight-only at runtime:
4865
4966- activation input stays fp16/bf16
50- - weight is prequantized outside the kernel to int8 plus fp32 scale
51- - the Triton kernel loads int8 weight and scale, dequantizes weight values, and
52- multiplies by fp16/bf16 activation
67+ - weight is prequantized outside the kernel to low-bit values plus fp32 scale
68+ - the Triton kernel loads quantized weight and scale, dequantizes weight values,
69+ and multiplies by fp16/bf16 activation
5370- no activation quantization is used in the current best result
5471
5572This is intentionally different from the older W8A8 attempts. The W8A8 paths
5673are still present for comparison, but they are not the current useful frontier
5774because activation quantization cost can dominate at this granularity.
5875
76+ ## SmoothQuant-Style Split: Offline, Load Time, Online
77+
78+ The ` triton_sq_w4a16 ` path is split across three phases.
79+
80+ Offline calibration:
81+
82+ - run the exact model with ` APPROX_SGLANG_SQ_COLLECT=1 `
83+ - collect per-layer activation absmax statistics
84+ - merge worker shards into one artifact with
85+ ` runtime/examples/sglang_quant/build_smoothquant_artifact.py `
86+
87+ Load time:
88+
89+ - read the artifact for each targeted layer
90+ - fold smoothing into the weight tensor
91+ - quantize to group-wise int4
92+ - pack the weight tensor once and cache it on the layer
93+
94+ Online serving:
95+
96+ - route the targeted linear call site to ` sglang_sq_w4a16_linear_kernel `
97+ - apply the activation-side inverse smoothing in-kernel
98+ - unpack int4 weights, load group-wise scales, and run the matmul
99+ - if ` M==1 ` and tile metadata matches, use a decode-only tiled W4 layout that is
100+ repacked at load time; otherwise fall back to the generic packed W4 path
101+
59102## Function Substitution Boundary
60103
61104Current function substitution is same-ABI:
62105
63106``` text
64107sglang_w8a16_linear_kernel(...)
65108 -> approx_sglang_w8a16_linear_kernel_1(...)
109+
110+ sglang_sq_w4a16_linear_kernel(...)
111+ -> approx_sglang_sq_w4a16_linear_kernel_1(...)
66112```
67113
68114The ABI change from original SGLang fp weight to ` qweight + scale ` is currently
69115done by the SGLang runtime patch, not by the compiler pass.
70116
117+ For ` triton_sq_w4a16 ` , that ABI is:
118+
119+ - packed int4 weight
120+ - group-wise scale tensor
121+ - activation smoothing inverse vector
122+
71123What this proves:
72124
73125- approxMLIR can hook Triton compilation inside SGLang workers
@@ -78,8 +130,10 @@ What remains future work:
78130
79131- compiler-level call-site / ABI rewrite from original fp weights to quantized
80132 weight metadata
81- - passing offline information such as AWQ scales through explicit metadata
82- rather than Python monkeypatch state
133+ - more optimized W4 kernels; current decode-tiled SQ-W4 is now ahead on speed
134+ but still behind on accuracy
135+ - richer calibration schemes such as AWQ/GPTQ-style protection on especially
136+ sensitive layers
83137
84138## Current Best Configuration
85139
@@ -107,27 +161,131 @@ APPROX_SGLANG_BLOCK_K=64
107161
108162Observed repeated result on the RTX 4060 Laptop:
109163
110- - exact SGLang/Triton batch=4, 8-token e2e median: about ` 0.212s `
111- - approximate repeated medians: ` 0.166s ` , ` 0.150s ` , ` 0.151s `
112- - speedup range : about ` 1.27x ` to ` 1.41x `
164+ - exact SGLang/Triton batch=4, 8-token e2e median: about ` 0.204s `
165+ - ` gate_up_proj ` W8A16 median: about ` 0.156s `
166+ - speedup: about ` 1.31x `
113167- substitution hits: ` 100% `
114168- output text matched the exact run in the checked prompt
115169
116170Use medians for reporting. SGLang e2e latency has occasional outliers.
117171
172+ ## Current Accuracy Definition
173+
174+ For decode-oriented points, the useful accuracy definition is no longer
175+ "output text matched on one prompt".
176+
177+ The current accuracy probe is:
178+
179+ - exact model generates a reference continuation
180+ - exact and approx are then compared on that same continuation
181+ - when ` APPROX_SGLANG_DECODE_ONLY=1 ` , the comparison is done as stepwise decode:
182+ one token at a time, conditioned on the exact prefix
183+ - metrics are computed from SGLang logprob APIs
184+
185+ Current reported metrics:
186+
187+ - ` teacher_forced_perplexity_ratio `
188+ - ratio of approx NLL to exact NLL on the exact continuation
189+ - ` 1.0 ` is exact; higher is worse
190+ - ` teacher_forced_mean_logprob_delta `
191+ - mean ` (approx_logprob - exact_logprob) ` on the reference token
192+ - ` top1_agreement_rate `
193+ - fraction of decode steps where approx and exact agree on top-1 token
194+ - ` topk_js_mean `
195+ - Jensen-Shannon divergence on returned top-k token distributions
196+ - ` 0.0 ` is exact; lower is better
197+
198+ This is still not full-vocab KL, because the public SGLang interface returns
199+ top-k / selected-token logprobs rather than full logits. But it is much more
200+ meaningful than a single prompt-level text match.
201+
202+ ## Current Pareto Frontier
203+
204+ Measured on:
205+
206+ - ` MODEL_PATH=Qwen/Qwen3.5-2B `
207+ - ` BATCH_SIZE=4 `
208+ - ` MAX_NEW_TOKENS=8 `
209+ - target: ` gate_up_proj `
210+ - decode-heavy serving with CUDA graph enabled
211+ - accuracy probe on 4 prompts x 8 generated tokens = 32 scored decode steps
212+
213+ Latency points:
214+
215+ - ` exact ` : median about ` 0.202s `
216+ - ` gate_up_proj ` ` triton_w8a16 ` : median about ` 0.176s ` (` ~1.15x ` )
217+ - decode-tiled ` gate_up_proj ` ` triton_sq_w4a16 ` : median about ` 0.136s `
218+ (` ~1.48x ` vs exact, ` ~1.29x ` vs W8)
219+
220+ Decode-step logprob accuracy:
221+
222+ - ` exact `
223+ - ` teacher_forced_perplexity_ratio = 1.0000 `
224+ - ` top1_agreement_rate = 1.000 `
225+ - ` topk_js_mean = 0.000000 `
226+ - ` W8A16 `
227+ - ` teacher_forced_perplexity_ratio = 1.0048 `
228+ - ` teacher_forced_mean_logprob_delta = -0.00483 `
229+ - ` top1_agreement_rate = 1.000 `
230+ - ` topk_js_mean = 0.000643 `
231+ - decode-tiled ` W4A16 `
232+ - ` teacher_forced_perplexity_ratio = 1.1569 `
233+ - ` teacher_forced_mean_logprob_delta = -0.14578 `
234+ - ` top1_agreement_rate = 0.875 `
235+ - ` topk_js_mean = 0.009500 `
236+
237+ Interpretation:
238+
239+ - ` W8A16 ` is the current safe Pareto point
240+ - clearly faster than exact
241+ - logits distribution remains very close to exact
242+ - decode-tiled ` W4A16 ` is a strong speed point but not yet on the safe
243+ accuracy/performance frontier
244+ - it is much faster than both exact and W8
245+ - but the decode-step distribution drift is now clearly visible under the new
246+ logprob definition
247+
118248## Frontier Interpretation
119249
120250The current frontier is selective coverage:
121251
122252- ` gate_up_proj ` W8A16 is the best target so far
123253- ` qkv_proj ` W8A16 gives a smaller positive point
124254- ` down_proj ` is not a Pareto point with the current W8A16 kernel
255+ - ` triton_sq_w4a16 ` full coverage is not a Pareto point with the current W4
256+ kernel
257+ - decode-tiled ` triton_sq_w4a16 ` now gives a major speedup, but under the
258+ decode-step logprob definition it is still too inaccurate to count as a safe
259+ frontier point
125260- blindly increasing coverage can erase the speedup
126261
127262CUDA graph must be enabled for serving-like measurements. With CUDA graph
128263disabled, launch overhead dominates and the same replacement can look flat or
129264negative.
130265
266+ ## Accuracy Probe Command
267+
268+ Decode-step exact-vs-approx logprob comparison:
269+
270+ ``` bash
271+ source .venv/bin/activate
272+ MODEL_PATH=Qwen/Qwen3.5-2B \
273+ BATCH_SIZE=4 \
274+ MAX_NEW_TOKENS=8 \
275+ TOP_LOGPROBS_NUM=20 \
276+ SGLANG_MEM_FRACTION_STATIC=0.75 \
277+ SGLANG_DISABLE_CUDA_GRAPH=0 \
278+ PROMPTS_JSON=' ["The capital of France is","The capital of France is","The capital of France is","The capital of France is"]' \
279+ APPROX_SGLANG_QUANT=1 \
280+ APPROX_SGLANG_MODE=approx \
281+ APPROX_SGLANG_TARGET=gate_up_proj \
282+ APPROX_SGLANG_BACKEND=triton_w8a16 \
283+ APPROX_SGLANG_DECODE_ONLY=1 \
284+ python3 approxMLIR/runtime/examples/sglang_quant/compare_sglang_logprobs.py
285+ ```
286+
287+ Swap ` APPROX_SGLANG_BACKEND ` and related W4 envs to compare other points.
288+
131289## Run Commands
132290
133291Single best-config run:
0 commit comments