This document compares GPTQ GPU memory usage on main and the batched GPTQ PR,
with and without Hessian offloading. Measurements were collected on an NVIDIA
H100 using torch.cuda.max_memory_allocated() and
torch.cuda.max_memory_reserved(). Process RSS was additionally sampled for the
MoE experiment to show the CPU cost of Hessian offloading.
These are memory-focused, reduced-calibration experiments. Both used eight synthetic calibration samples of 256 tokens rather than the 512 samples of 2048 tokens used by the production examples.
The folder contains separate Python harnesses for the dense and MoE models and a runner that executes the PR and main comparisons in fresh processes:
chg run -- bash gptq_memory_benchmarks/run_comparison.sh allRun only one model with llama3, qwen3-moe, or qwen3-full in place of
all. The runner
uses the current repository as the PR checkout and /tmp/llm-compressor-main
as the main checkout. Override these with PR_REPO and MAIN_REPO. Per-case
logs are written under /tmp/gptq-memory-benchmarks by default; use LOG_DIR
to change that location.
The Python scripts default to the local Hugging Face snapshots used for the
measurements. Their --model-path argument can point to another local snapshot
or model identifier.
The full matrix was rerun after changing the eager GPTQ backend to use CT's
fake_quantize semantics and updating Triton to preserve BF16/FP16 dequantized
results. The rerun used the same H100, checkpoint, calibration data, and fresh
process per case. Raw logs are in /tmp/gptq-memory-benchmarks-rerun.
The memory conclusions did not change:
- Llama PR active memory remained 19.20 GiB in all four PR configurations.
- Qwen PR active memory remained 7.01/3.45 GiB unbatched and 20.18/15.91 GiB batched, without/with Hessian offloading respectively.
- The peak phases and the main-versus-PR memory relationships were unchanged.
- Peak reserved memory was unchanged at the displayed precision.
The measured runtimes moved modestly between runs: PR Llama increased by 0.20--1.42 seconds and PR Qwen by 0.84--2.37 seconds. CPU RSS varied by up to about 1 GiB in the offloaded Qwen cases. These are runtime/process variations; the successful benchmark cases use the Triton backend, so the eager fallback change does not add allocations to their normal path.
Configuration:
- Model: Meta-Llama-3-8B-Instruct
- Full 32-layer model resident on the GPU in BF16
- Quantization: W4A16, group size 128
- Calibration: 8 samples of 256 tokens
- Loaded-model CUDA allocation: 15.0 GiB
| Implementation | Hessian offload | Batching | Peak allocated | Peak reserved | Runtime |
|---|---|---|---|---|---|
| PR | No | No | 19.20 GiB | 20.38 GiB | 17.83 s |
| PR | Yes | No | 19.20 GiB | 20.06 GiB | 139.19 s |
| PR | No | Yes | 19.20 GiB | 20.58 GiB | 19.81 s |
| PR | Yes | Yes | 19.20 GiB | 20.48 GiB | 140.77 s |
| Main | No | N/A | 19.31 GiB | 20.58 GiB | 264.04 s |
| Main | Yes | N/A | 19.31 GiB | 20.06 GiB | 380.67 s |
Main does not support batched GPTQ.
For this dense model, batching did not change the active-memory peak. The largest peak appears while processing a singleton projection, while the same-shaped modules that can be batched are smaller. Batching still increased the allocator's reserved peak by approximately 200--420 MiB.
Hessian offloading did not reduce peak allocated GPU memory in this experiment. It reduced peak reserved memory by approximately 320--530 MiB, but made the PR run roughly seven to eight times slower because Hessians were repeatedly moved between CPU and GPU.
The PR's approximately 109 MiB allocated-memory advantage over main is not a meaningful batching advantage. For singleton batches, its FP32 stacks replace main's working copies, and the PR performs Hessian factorization and inversion in place while main creates additional temporary tensors.
Phase-local CUDA peaks show that quantization, rather than stack construction
or activation-order permutation, determines the overall peak in every Llama
case. Compression setup includes normalization and stack construction.
| Implementation | Hessian offload | Batching | Compression setup | Permutation | Quantization | Peak phase |
|---|---|---|---|---|---|---|
| PR | No | No | 17.89 GiB | 18.43 GiB | 19.20 GiB | Quantization |
| PR | Yes | No | 17.89 GiB | 18.43 GiB | 19.20 GiB | Quantization |
| PR | No | Yes | 18.01 GiB | 18.44 GiB | 19.20 GiB | Quantization |
| PR | Yes | Yes | 18.01 GiB | 18.44 GiB | 19.20 GiB | Quantization |
| Main | No | N/A | 16.79 GiB | 17.99 GiB | 19.31 GiB | Quantization |
| Main | Yes | N/A | 16.79 GiB | 17.99 GiB | 19.31 GiB | Quantization |
Removing the transient overlap between the unpermuted and permuted stacks would reduce the permutation phase, but it would not reduce the measured overall Llama peak because later GPTQ workspaces already exceed it by 0.76--1.31 GiB.
Configuration:
- Model: Qwen3-30B-A3B, truncated through its configuration to one transformer layer
- All 128 experts in that layer retained
- Model resident on the GPU in BF16
- Quantization: W4A16, group size 128
- Calibration: 8 samples of 256 tokens with all experts calibrated
- Loaded-model CUDA allocation: 2.32 GiB
| Implementation | Hessian offload | Batching | Peak GPU allocated | Peak GPU reserved | Peak CPU RSS | Runtime |
|---|---|---|---|---|---|---|
| PR | No | No | 7.01 GiB | 7.25 GiB | 3.01 GiB | 7.45 s |
| PR | Yes | No | 3.45 GiB | 3.61 GiB | 10.72 GiB | 17.05 s |
| PR | No | Yes | 20.18 GiB | 28.42 GiB | 2.95 GiB | 4.44 s |
| PR | Yes | Yes | 15.91 GiB | 24.13 GiB | 13.59 GiB | 16.11 s |
| Main | No | N/A | 7.02 GiB | 7.30 GiB | 2.36 GiB | 133.23 s |
| Main | Yes | N/A | 3.45 GiB | 3.61 GiB | 10.62 GiB | 146.29 s |
The batched PR grouped all 256 expert gate_proj and up_proj modules into one
batch and all 128 expert down_proj modules into another batch. This makes the
cost of stacked weights, Hessians, and GPTQ workspaces visible:
- Batching without offloading added about 13.17 GiB of active GPU memory over the PR's unbatched path.
- Hessian offloading saved about 3.56 GiB in the unbatched path and 4.27 GiB in the batched path.
- Offloading shifted substantial memory to the CPU. Peak process RSS increased by about 6.82 GiB unbatched and 11.02 GiB batched.
- Batching reduced PR runtime from 5.89 seconds to 3.30 seconds without offloading, at the cost of much higher GPU memory usage.
- Main and the unbatched PR had effectively identical GPU memory peaks. This confirms that the dense-model PR advantage was incidental rather than an inherent memory benefit from the new implementation.
| Implementation | Hessian offload | Batching | Compression setup | Permutation | Quantization | Overall peak phase |
|---|---|---|---|---|---|---|
| PR | No | No | 6.92 GiB | 6.95 GiB | 7.01 GiB | Quantization |
| PR | Yes | No | 2.63 GiB | 2.66 GiB | 2.73 GiB | MoE linearization (3.45 GiB) |
| PR | No | Yes | 17.67 GiB | 20.17 GiB | 20.18 GiB | Quantization |
| PR | Yes | Yes | 13.40 GiB | 15.90 GiB | 15.91 GiB | Quantization |
| Main | No | N/A | 6.80 GiB | 6.92 GiB | 7.02 GiB | Quantization |
| Main | Yes | N/A | 2.51 GiB | 2.64 GiB | 2.73 GiB | MoE linearization (3.45 GiB) |
For the offloaded unbatched cases, CUDA allocation history identified the
3.45-GiB peak in post-load linearize_moe(), while converting and offloading
the expert module. It is unrelated to GPTQ stack construction.
For batched MoE, permutation is very close to the maximum, but quantization still reaches a slightly higher peak after the old unpermuted stack has been released: 12.1 MiB higher in both offload modes. Constructing the stacks in permuted order would therefore remove a large temporary overlap without lowering the current end-to-end peak; the GPTQ workspaces would become the limiting allocation at essentially the same value.
Configuration:
- Model: Qwen3-30B-A3B, truncated to one transformer layer
- All 128 experts in that layer retained
- Model resident on the GPU in BF16
- Quantization: W4A16, group size 128
- Calibration: 8 samples of 256 tokens with all experts calibrated
- Loaded-model CUDA allocation: 2.32 GiB
The activation-order permutation now gathers into a temporary and copies the result back into the disposable weight/Hessian stacks. The original and permuted stacks therefore do not remain live throughout quantization. The following table uses the complete PR matrix; the main rows are the previously recorded eager-GPTQ baseline, since main does not support batching.
| Implementation | Hessian offload | Batching | Peak GPU allocated | Peak GPU reserved | Runtime |
|---|---|---|---|---|---|
| PR after in-place permutation | No | No | 6.95 GiB | 7.16 GiB | 7.59 s |
| PR after in-place permutation | Yes | No | 3.45 GiB | 3.61 GiB | 16.49 s |
| PR after in-place permutation | No | Yes | 16.18 GiB | 20.66 GiB | 4.96 s |
| PR after in-place permutation | Yes | Yes | 15.90 GiB | 20.14 GiB | 14.11 s |
| Main | No | N/A | 7.02 GiB | 7.30 GiB | 133.23 s |
| Main | Yes | N/A | 3.45 GiB | 3.61 GiB | 146.29 s |
For comparison, the preceding implementation measured 20.18/15.91 GiB of allocated memory and 28.42/24.13 GiB of reserved memory without/with Hessian offloading. The in-place permutation therefore reduced the active peak by approximately 4.0 GiB without Hessian offloading and left the offloaded active peak essentially unchanged. Reserved memory fell by approximately 7.8 GiB without offloading and 4.0 GiB with offloading.
The previous excess memory came from retaining the original batched stacks
while quantize_weight created separately permuted weight and Hessian stacks.
The new implementation reuses the original stack storage after the temporary
copy completes. The gather temporary still exists briefly during permutation,
but it is released before the main GPTQ workspaces are allocated.
Hessian offloading now reduces active GPU memory by only about 0.29 GiB in this batched experiment because the peak is dominated by the batched weight and GPTQ workspace allocations. It still reduces reserved memory by about 0.51 GiB and increases CPU use and runtime because the Hessians are transferred between CPU and GPU.
| Implementation | Hessian offload | Batching | Batch setup | Quantization | Overall peak phase |
|---|---|---|---|---|---|
| PR after in-place permutation | No | No | 6.82 GiB | 6.95 GiB | Quantization |
| PR after in-place permutation | Yes | No | 2.53 GiB | 2.66 GiB | MoE linearization (3.45 GiB) |
| PR after in-place permutation | No | Yes | 10.76 GiB | 16.18 GiB | Quantization |
| PR after in-place permutation | Yes | Yes | 10.48 GiB | 15.90 GiB | Quantization |
| Main | No | N/A | 6.80 GiB | 7.02 GiB | Quantization |
| Main | Yes | N/A | 2.51 GiB | 2.73 GiB | MoE linearization (3.45 GiB) |
The permutation is now part of the quantization phase rather than a separate phase. Even with the transient gather allocation, the quantization peak is lower than the previous permutation peak because the original stacks are reused instead of being held alongside the permuted copies.
Raw logs are in /tmp/gptq-memory-benchmarks-rtn-rerun, with the focused cases
labeled rtn_inplace_unbatched_hess0, rtn_inplace_unbatched_hess1,
rtn_inplace_batched_hess0, and rtn_inplace_batched_hess1.
Configuration:
- Model: Meta-Llama-3-8B-Instruct
- Full 32-layer model resident on the GPU in BF16
- Quantization: W4A16, group size 128
- Calibration: 8 samples of 256 tokens
- Loaded-model CUDA allocation: 15.0 GiB
The following is the post-in-place-permutation PR rerun. The Main rows are
the previously recorded eager-GPTQ baseline; main does not support batching.
| Implementation | Hessian offload | Batching | Peak GPU allocated | Peak GPU reserved | Runtime |
|---|---|---|---|---|---|
| PR after in-place permutation | No | No | 18.43 GiB | 19.61 GiB | 17.75 s |
| PR after in-place permutation | Yes | No | 18.43 GiB | 19.30 GiB | 127.80 s |
| PR after in-place permutation | No | Yes | 18.43 GiB | 19.82 GiB | 19.80 s |
| PR after in-place permutation | Yes | Yes | 18.43 GiB | 19.71 GiB | 131.66 s |
| Main | No | N/A | 19.31 GiB | 20.58 GiB | 264.04 s |
| Main | Yes | N/A | 19.31 GiB | 20.06 GiB | 380.67 s |
The in-place activation ordering change reduced the current PR's allocated peak by about 1.0 GiB compared with the preceding PR rerun. Llama's active peak is unchanged across the four current PR configurations because the largest singleton projection's GPTQ workspace dominates. Batching still changes allocator reservation: the current reserved peaks are 19.61--19.82 GiB, compared with 19.30 GiB in the offloaded unbatched case.
The current phase tracker reports stack construction as batch_setup and
activation ordering as part of quantization; there is no separate live
permuted stack at the quantization peak.
| Implementation | Hessian offload | Batching | Batch setup | Quantization | Peak phase |
|---|---|---|---|---|---|
| PR after in-place permutation | No | No | 16.97 GiB | 18.43 GiB | Quantization |
| PR after in-place permutation | Yes | No | 16.97 GiB | 18.43 GiB | Quantization |
| PR after in-place permutation | No | Yes | 17.25 GiB | 18.43 GiB | Quantization |
| PR after in-place permutation | Yes | Yes | 17.25 GiB | 18.43 GiB | Quantization |
Dense and MoE models exercise different peak-memory behavior. On the dense Llama model, singleton projections determined the peak, so batching had little effect on active memory. On the MoE model, hundreds of same-shaped expert projections were combined, and their stacked tensors dominated the peak.
Hessian offloading is effective at lowering active GPU memory when many expert Hessians coexist, but it trades that memory for CPU usage and transfer overhead. The current 75%-of-free-memory batching budget can therefore produce very large MoE batches and high reserved-memory peaks even when the run fits successfully.
At this point in the development history, the quantized module.weight
tensors were compared by hashing their raw
bytes. Both runs used the same checkpoint, deterministic synthetic calibration
inputs, and W4A16-G128 configuration. The PR used batched Triton GPTQ while main
used its eager GPTQ implementation.
| Model | Quantized weights | Bitwise matches | Bitwise mismatches |
|---|---|---|---|
| Llama 3 8B | 224 | 0 | 224 |
| Qwen3 30B-A3B, one layer | 388 | 0 | 388 |
The compared module names, tensor shapes, and dtypes matched, but every final weight payload differed. This historical comparison preceded the exact-parity fixes described below.
The complete dense and one-layer MoE matrices were rerun after matching main's
column-major inverse-Hessian factor layout and using per-item 2D matrix
multiplication for cross-block error propagation. Raw logs are in
/tmp/gptq-memory-benchmarks-hinv-layout.
These changes ensure bitwise parity with main, but the separate column-major factor adds a Hessian-sized allocation. All 224 Llama 3 weights matched main bitwise in PR eager, PR Triton, and PR batched Triton runs.
Configuration remains the same as the earlier full-model Llama runs: 32 BF16 layers, W4A16-G128, and 8 synthetic samples of 256 tokens.
| Implementation | Hessian offload | Batching | Peak GPU allocated | Peak GPU reserved | Runtime |
|---|---|---|---|---|---|
| PR exact parity | No | No | 19.20 GiB | 20.38 GiB | 18.20 s |
| PR exact parity | Yes | No | 19.20 GiB | 20.06 GiB | 133.54 s |
| PR exact parity | No | Yes | 19.20 GiB | 20.94 GiB | 17.55 s |
| PR exact parity | Yes | Yes | 19.20 GiB | 20.06 GiB | 133.36 s |
| Main | No | N/A | 19.31 GiB | 20.58 GiB | 266.39 s |
| Main | Yes | N/A | 19.31 GiB | 20.06 GiB | 408.70 s |
Compared with the preceding in-place-permutation rerun, PR peak allocation rose from 18.43 GiB to 19.20 GiB. Quantization remains the peak phase in every case. The batched and unbatched active peaks are identical because the largest singleton projection still determines the maximum.
Configuration remains one BF16 transformer layer with all 128 experts, W4A16-G128, and 8 synthetic samples of 256 tokens.
| Implementation | Hessian offload | Batching | Peak GPU allocated | Peak GPU reserved | Peak CPU RSS | Runtime |
|---|---|---|---|---|---|---|
| PR exact parity | No | No | 7.01 GiB | 7.23 GiB | 2.37 GiB | 7.39 s |
| PR exact parity | Yes | No | 3.45 GiB | 3.61 GiB | 10.50 GiB | 16.31 s |
| PR exact parity | No | Yes | 16.18 GiB | 20.73 GiB | 2.94 GiB | 5.87 s |
| PR exact parity | Yes | Yes | 15.89 GiB | 20.14 GiB | 10.44 GiB | 15.96 s |
| Main | No | N/A | 7.02 GiB | 7.30 GiB | 2.93 GiB | 128.42 s |
| Main | Yes | N/A | 3.45 GiB | 3.61 GiB | 10.14 GiB | 146.28 s |
Hessian offloading remains decisive for the unbatched MoE case, reducing peak GPU allocation from 7.01 GiB to 3.45 GiB. In batched mode, stacked expert weights and GPTQ workspaces dominate, so offloading only reduces the active peak by about 0.29 GiB.
This is a new full-model benchmark using all 48 transformer layers and all 128 experts per layer. The model is loaded with compressed-tensors CPU offloading and layers are onloaded sequentially; loading the complete BF16 checkpoint on one H100 reached 79.16 GiB and OOMed during MoE linearization before GPTQ.
Configuration:
- Model: full Qwen3-30B-A3B, 48 layers and 128 experts per layer
- Model storage: CPU offloaded, with sequential GPU onloading
- Quantization: W4A16, group size 128
- Calibration: 8 synthetic samples of 256 tokens with all experts calibrated
- Hessian offloading: disabled
| Implementation | Backend | Batching | Peak GPU allocated | Peak GPU reserved | Peak CPU RSS | Runtime |
|---|---|---|---|---|---|---|
| PR exact parity | Triton | No | 5.96 GiB | 6.14 GiB | 59.96 GiB | 328.72 s |
| PR exact parity | Triton | Yes | 15.11 GiB | 19.51 GiB | 59.96 GiB | 260.23 s |
| PR exact parity | Eager | No | 5.96 GiB | 6.14 GiB | 59.96 GiB | 3,829.18 s |
| Main | Eager | N/A | 5.96 GiB | 6.14 GiB | 59.96 GiB | 6,653.18 s |
Batching reduced runtime by 68.49 seconds (20.8%) while increasing peak active GPU memory by 9.15 GiB and peak reserved memory by 13.37 GiB. Peak CPU RSS was essentially unchanged because it is dominated by the CPU-offloaded model weights. Quantization was the peak GPU phase in both cases.
The PR eager path completed in 63.82 minutes, compared with 110.89 minutes for main eager: a 1.74x speedup with effectively identical memory usage. Unbatched PR Triton was 11.65x faster than PR eager, while batched PR Triton was 14.72x faster. The eager measurements confirm that the Triton speedup does not explain the PR-versus-main memory result; all three unbatched implementations reached essentially the same 5.96-GiB active peak.
This rerun follows removal of the exact-parity execution path and Hessian
offloading. Batched GPTQ now always uses batched mean, Cholesky, and GEMM
operations. Setting batched_quantization=False processes modules one at a
time. The batch-size estimate includes both the quantization peak and the
3H + 2W activation-ordering candidate peak.
Configuration remains 32 resident BF16 layers, W4A16-G128, and 8 synthetic samples of 256 tokens.
| Backend | Batching | Peak GPU allocated | Peak GPU reserved | Runtime |
|---|---|---|---|---|
| Triton | Yes | 18.43 GiB | 19.82 GiB | 17.19 s |
| Triton | No | 18.43 GiB | 19.61 GiB | 17.90 s |
| Eager | Yes | 18.43 GiB | 19.82 GiB | 115.17 s |
| Eager | No | 18.43 GiB | 19.61 GiB | 157.61 s |
The largest singleton projection remains the active-memory peak, so batching does not change peak allocation. It increases reserved memory by about 0.21 GiB.
Batch eligibility requires an identical full weight shape. Thus, per Llama
layer, batching forms only three pairs: Q/O, K/V, and gate/up; down_proj is a
singleton. A section-timed run on one layer explains the different results.
For eager GPTQ, batching reduces total column-update time from 6.535 s to
4.495 s. The reductions are in fake quantization (2.333 s to 1.576 s),
error/loss computation (1.976 s to 1.334 s), and intra-block propagation
(1.187 s to 0.818 s). Batched Hessian factorization is slightly slower (0.369 s
to 0.505 s), but that 0.137 s cost is much smaller than the 2.040 s update-loop
saving. This produces the full-run eager improvement (115.17 s versus
157.61 s).
For Triton GPTQ, batching improves the fused column updates, from 92.8 ms to
70.4 ms, and reduces cross-block propagation from 96.1 ms to 84.7 ms. Before
the current threshold, the B=2 batches lost more time in batched Hessian
factorization than they saved in those updates. The current code instead uses
the serial factorization sequence below B=16, avoiding that tiny-batch CUDA
linear-algebra regression while retaining the batched Triton updates. The new
full-model batched Triton runtime is 17.19 s, faster than the previously
recorded unbatched Triton runtime of 17.90 s. There is no distinct large batched
workspace responsible here: the batches are mostly pairs, and the explicit extra
work is stack construction plus the different linear-algebra call form.
An isolated H100 microbenchmark of the same Cholesky → inverse → Cholesky
sequence at Llama's 4096-wide Hessian size attributes this to the CUDA linear
algebra implementation: B=2 batched factorization took 53.61 ms, compared
with 26.83 ms for two 2-D calls. The penalty decreases as batch size grows
(B=8: 115.14 ms batched versus 107.71 ms serial) and reverses at B=16
(156.54 ms versus 213.95 ms). Therefore a batch-size threshold could be useful,
but it should apply specifically to the batched Hessian factorization, not
disable the rest of GPTQ batching: eager's batched update loop is already much
faster at B=2. The exact crossover is hardware-, CUDA-, and Hessian-width-
dependent.
Configuration remains one BF16 transformer layer with all 128 experts, W4A16-G128, and 8 synthetic samples of 256 tokens.
| Backend | Batching | Peak GPU allocated | Peak GPU reserved | Peak CPU RSS | Runtime |
|---|---|---|---|---|---|
| Triton | Yes | 16.18 GiB | 20.66 GiB | 2.94 GiB | 4.69 s |
| Triton | No | 6.95 GiB | 7.16 GiB | 2.36 GiB | 7.14 s |
| Eager | Yes | 16.18 GiB | 20.66 GiB | 2.37 GiB | 6.10 s |
| Eager | No | 6.95 GiB | 7.16 GiB | 2.37 GiB | 75.10 s |
Batching increases active GPU memory by 9.23 GiB because expert workspaces are processed together. It improves Triton runtime by 1.52x and eager runtime by 12.31x.
The large eager speedup is not a batching effect. A focused eager run of one
real expert gate_proj with batching disabled showed 329.2 ms in PR column
updates versus 555.1 ms in main, a 225.9 ms saving per projection. The largest
component is fake quantization (117.1 ms in PR versus 223.8 ms in main). The
remainder is main's extra per-column quantized-weight clone (28.5 ms), plus
slower error/loss (135.7 versus 100.1 ms) and intra-block propagation (91.4
versus 59.0 ms). Hessian factorization does not explain the improvement: it was
slightly slower in PR (58.0 versus 50.1 ms).
The one-layer MoE has 128 expert gate_proj and 128 same-shaped up_proj
modules. Scaling the measured 225.9 ms per-projection column-update difference
across those 256 projections gives 57.8 s per transformer layer, or about
2,775 s across Qwen3-30B-A3B's 48 layers. That accounts for essentially all of
the measured full-model PR-eager versus main-eager gap (approximately 2,824 s).
The gain is therefore the accumulated cost of main's eager per-column path,
especially fake quantization, repeated hundreds of times per layer.
The individual-Linear configuration was rerun with unbatched Triton and
sequential_targets=["Linear"]. It required two sequential-pipeline fixes:
preserving PretrainedConfig objects in the intermediate cache and preserving
the eager attention implementation in reconstructed traced configs. The full
Qwen run then completed successfully across 18,626 subgraphs.
| Model | Backend | Batching | Peak GPU allocated | Peak GPU reserved | Peak CPU RSS | Runtime |
|---|---|---|---|---|---|---|
| Qwen3-30B-A3B, one layer | Triton | No | 3.45 GiB | 4.25 GiB | 3.65 GiB | 14.43 s |
| Qwen3-30B-A3B | Triton | No | 0.65 GiB | 1.26 GiB | 62.46 GiB | 668.69 s |
For the full model, the peak moved out of GPTQ entirely: propagation reached 0.65 GiB allocated, while the one-layer case peaked during MoE linearization at 3.45 GiB. The full Linear-target run is much slower because it creates and executes an individual sequential subgraph for every Linear module.
The full-model four-way backend/batching matrix was then completed using the same CPU-offloaded model and 8x256 calibration configuration.
| Backend | Batching | Peak GPU allocated | Peak GPU reserved | Peak CPU RSS | Runtime |
|---|---|---|---|---|---|
| Triton | Yes | 15.11 GiB | 19.45 GiB | 59.97 GiB | 212.79 s |
| Triton | No | 5.90 GiB | 6.07 GiB | 59.96 GiB | 336.76 s |
| Eager | Yes | 15.11 GiB | 19.45 GiB | 59.96 GiB | 278.94 s |
| Eager | No | 5.90 GiB | 6.07 GiB | 59.97 GiB | 3,779.61 s |
For this full model, eager batching is faster than unbatched Triton
(278.94 s versus 336.76 s) at the cost of about 9.21 GiB additional active
GPU memory. Unbatched Triton remains about 11.2x faster than unbatched eager.
This run used the more memory-efficient MoE sequential partitioning strategy:
sequential_targets=["Attention", "ExpertMLPWithGate"]
sequential_targets_per_subgraph=8The Qwen3 experts were linearized through load_context(), so
ExpertMLPWithGate matched the individual expert modules. Quantization used
the Triton GPTQ backend with batched quantization enabled, W4A16-G128, and the
same 8 samples of 256 tokens. Hessian offloading was disabled.
| Model | Subgraphs | Peak GPU allocated | Peak GPU reserved | Peak CPU RSS | Runtime |
|---|---|---|---|---|---|
| Qwen3-30B-A3B, one layer | 17 | 3.34 GiB | 4.06 GiB | 3.17 GiB | 7.04 s |
| Qwen3-30B-A3B, full model | 769 | 1.25 GiB | 1.91 GiB | 61.38 GiB | 281.99 s |
The one-layer run processed all 128 experts and grouped eight experts per sequential subgraph. The full-model run used CPU model offloading, so its GPU allocation stayed low while CPU RSS was dominated by the offloaded BF16 model. Both runs completed successfully with Triton GPTQ.
kernel_microbenchmark.py isolates GPTQ for the actual Qwen3-30B-A3B and
Llama 3 8B Linear shapes. It includes observer/qparam setup, Hessian
factorization, GPTQ, and stack construction, but excludes model calibration and
sequential propagation. Dense-model batches use their actual compatible size
(B=2); Qwen expert batches sweep up to all 128 same-shaped experts. The
comparison below is batched execution against an extrapolated loop of the same
single-module fused path, and also reports the fused Triton versus eager
single-module comparison, using W4A16-G128 on an H100.
| Model shape | Triton B=1 | Eager B=1 | Triton speedup | Batch | Batched | Loop extrapolation | Batch speedup |
|---|---|---|---|---|---|---|---|
Qwen attention Q/O (2048×2048) |
22.4 ms | 402.6 ms | 17.96x | 2 | 42.4 ms | 44.8 ms | 1.06x |
Qwen attention K/V (256×2048) |
10.8 ms | 244.9 ms | 22.60x | 2 | 17.8 ms | 21.7 ms | 1.22x |
Qwen expert gate/up (768×2048) |
14.1 ms | 254.1 ms | 18.05x | 128 | 1,062.3 ms | 1,802.7 ms | 1.70x |
Qwen expert down (2048×768) |
8.8 ms | 104.6 ms | 11.85x | 128 | 893.9 ms | 1,129.7 ms | 1.26x |
Llama attention Q/O (4096×4096) |
74.2 ms | 860.2 ms | 11.60x | 2 | 144.5 ms | 148.3 ms | 1.03x |
Llama attention K/V (1024×4096) |
33.9 ms | 520.6 ms | 15.36x | 2 | 62.1 ms | 67.8 ms | 1.09x |
Llama MLP gate/up (14336×4096) |
235.4 ms | 766.7 ms | 3.26x | 2 | 464.8 ms | 470.8 ms | 1.01x |
Llama MLP down (4096×14336) |
482.1 ms | 2,249.3 ms | 4.67x | 1 | 486.0 ms | 482.1 ms | 0.99x |
This isolates why Qwen benefits materially from batching while Llama does not:
the Qwen expert groups supply 128 independent same-shaped projections, while
Llama supplies only pairs and one singleton. The equivalent NVFP4-G16 results
show the same pattern: 1.74x for Qwen gate/up and 1.27x for Qwen down at B=128,
versus 1.02--1.15x for Llama's B=2 groups. Full raw outputs are retained in
kernel_microbenchmark_int4_results.txt and
kernel_microbenchmark_nvfp4_results.txt.
Main was run with the full Qwen3-30B-A3B model CPU-offloaded and
offload_hessians=True, then intentionally stopped after quantizing every
target module in transformer layer 0. That real first-layer run peaked at 1.60
GiB CUDA allocated and 1.71 GiB reserved. Since every transformer layer has the
same attention and 128-expert MoE structure, 1.60 GiB is a reasonable estimate
of the full run's GPU allocation peak. It is marked as an estimate below: the
48-layer run itself was not completed, so no full-run runtime is reported.
The tables below consolidate the final 8-sample, 256-token, W4A16-G128 measurements. Main does not have quantization batching. Hessian offloading was removed from the final PR, so the PR rows use the no-offload configuration.
| Implementation | Batching | Llama 3 8B | Qwen3-30B-A3B, one layer | Qwen3-30B-A3B, full model |
|---|---|---|---|---|
| Main - Hessian offload | N/A | 19.31 GiB | 3.45 GiB | ~1.60 GiB (first-layer estimate) |
| Main - No Hessian offload | N/A | 19.31 GiB | 7.02 GiB | 5.96 GiB |
| PR eager | No | 18.43 GiB | 6.95 GiB | 5.90 GiB |
| PR eager | Yes | 18.43 GiB | 16.18 GiB | 15.11 GiB |
| PR Triton | No | 18.43 GiB | 6.95 GiB | 5.90 GiB |
| PR Triton | Yes | 18.43 GiB | 16.18 GiB | 15.11 GiB |
PR Triton, attention + ExpertMLPWithGate 8 targets |
Yes | N/A | 3.34 GiB | 1.25 GiB |
| Implementation | Batching | Llama 3 8B | Qwen3-30B-A3B, one layer | Qwen3-30B-A3B, full model |
|---|---|---|---|---|
| Main - Hessian offload | N/A | 408.70 s | 146.28 s | N/A |
| Main - No Hessian offload | N/A | 266.39 s | 128.42 s | 6,653.18 s |
| PR eager | No | 157.61 s | 75.10 s | 3,779.61 s |
| PR eager | Yes | 115.17 s | 6.10 s | 278.94 s |
| PR Triton | No | 17.90 s | 7.14 s | 336.76 s |
| PR Triton | Yes | 17.19 s | 4.69 s | 212.79 s |
PR Triton, attention + ExpertMLPWithGate 8 targets |
Yes | N/A | 7.04 s | 281.99 s |
The memory table reports GiB; the runtime table reports seconds.
The sequential-target row uses
sequential_targets=["Attention", "ExpertMLPWithGate"] and
sequential_targets_per_subgraph=8. The full-model main + Hessian offload
runtime is marked N/A because that run was not completed. Its peak-allocation
cell is a first-layer estimate; all other cells are measured results.