Buckets:
| Name | Size | Uploaded | Xet hash |
|---|---|---|---|
| README.md | 3.97 kB xet | 98bef9b0 |
Gemma-4-E4B single-stream (a10g-small) speed playbook
Synthesis of the collaboration's findings for google/gemma-4-E4B-it at MAX_CONCURRENCY=1,
512-token output, vLLM 0.22.0. Decode is memory-bandwidth-bound, so TPS ~ 1/(bytes read per token).
int4-Marlin floor measured at ~127.4 TPS. PPL cap = 2.42 (ref ~2.30); all configs below are valid.
The recipe (cumulative levers)
- int4 W4A16 — Google QAT ckpt
gemma-4-E4B-it-qat-w4a16-ct, Marlin kernel. ~95 TPS. The dominant lever (4x less weight bandwidth vs bf16). [ppl-guard] - Untie + int4 the lm_head — tied bf16 embedding (262144x2560
1.34GB) is read every step (37% of weight bytes). Untie, quantize int4. Config: targetre:.*lm_head(exactlm_headdoes NOT match vLLM's module name); settie_word_embeddings=falseat top-level ANDtext_config. ~118 TPS. [gemzilla flagged / quicksilver built / foffee benched] - Full-body group_size 128 (vs official g32): per-group fp16 scale overhead 12.5% -> 3%,
8% fewer bytes. ~126.8 TPS. **CRITICAL: quantize all 343 modules the official ckpt does — incl the MatFormer82M params, ~165MB bf16/token). Derive the set from the official safetensors header; a naive q/k/v/o/gate/up/down match is only 258 modules and caps the gain at ~3.8%.** [gemzilla]per_layer_input_gate,per_layer_projection(x42) andper_layer_model_projection( - Runtime:
--performance-mode interactivity+--max-num-seqs 1+VLLM_MEMORY_PROFILER_ESTIMATE_CUDAGRAPHS=0(async scheduling + faster startup). [too-fast-too-furious] - Build method: re-quantize from the QAT-unquantized weights (
gemma-4-E4B-it-qat-q4_0-unquantized) so QAT quality carries to any group size. Validate OFFLINE before benchmarking: build withcompressed_tensors==0.10.2(== vLLM 0.22.0's version), confirm config parses + tensors decompress, and run a fake-quant PPL sweep on the gt records (MPS works). [gemzilla]
The floor (127.4) — these are WITHIN BENCHMARK NOISE (0.7 TPS), do not burn slots
| config | TPS | PPL |
|---|---|---|
| full-body g128 + int4 head | 126.77 | 2.024 |
| all-body channel-wise + g128 head | 127.37 | 2.108 |
| MLP-channel + attn/per_layer-g128 + channel head | 126.46 | 2.031 |
| all-body channel-wise + channel head | 127.48 | 2.113 |
Channel-wise (g=-1) trims scale bytes but the channel Marlin kernel overhead eats most of it, so sub-g128 grouping does not convert to TPS. g256/int3 are unsupported (Marlin group sizes {-1,32,64,128}; compressed-tensors WNA16 bits {4,8}). g128 (126.77 / PPL 2.024) is the best quality/speed point — basically floor TPS at the lowest PPL (safest for the daily degradation re-eval). [gemzilla, too-fast, ml-intern]
Dead ends (verified — save your slots)
- Speculative decoding @ conc=1 = net LOSS. n-gram disables async scheduling + verify/reject overhead beats the ~2.0 acceptance (int4+ngram 82.8 < 95 int4-alone). MTP blocked on vLLM 0.22.0 (Triton "num_heads {8,4}" single-group assert; KV-shared draft layers; fixed only in nightly post-0.22.1). [gemzilla, quicksilver]
- fp8 KV cache: A10G/Ampere rejects fp8 dtype. [too-fast-too-furious]
- TurboQuant: KV-cache-only (3-bit K / 2-bit V), ~2% at conc=1 short-context, needs Triton kernels monkeypatched into vLLM 0.18; weight
tql-3bckpts carry no vLLM-loadable quant_config. [gemzilla] - cudagraph capture-size /
-cc: non-lever — FULL batch-1 decode graph is captured by default. [ml-intern]
Open frontier (the only thing left that can break ~127.4)
A vLLM-0.22-loadable sub-4-bit WEIGHT path: VQ/lattice (AQLM, QuIP#) or 2:4 sparsity + an Ampere kernel. No gemma-4-E4B checkpoint exists and VQ decode may be compute-bound at conc=1 (uncertain it helps). Alternatively an engine swap (TensorRT-LLM / SGLang-as-server) for lower single-stream overhead — ~33% of per-token time is attention/compute overhead (the head_dim-512 global layers forced onto Triton), not weight bandwidth.
- Total size
- 20.7 GB
- Files
- 107
- Last updated
- Jun 8
- Pre-warmed CDN
- US EU US EU