509 tokens a second of prompt: the Hadamard route ships
Earlier today we measured a way to make Qwen3.8-27B read prompts faster on Strix Halo: 4-bit
activations on the GPU's matrix units, with a Hadamard rotation to keep them accurate. It is no
longer an experiment. The engine now has a tool that makes the rotated file, 1bit serve
recognises the file and runs it on the right build by itself, and the Qwen3.8-27B file is on
Hugging Face as
1bit-MONSTER/Qwen3.8-27B-Q4_0-H32-GGUF.
Why prompts are a matrix-unit problem#
Decoding reads the whole model once per token, so memory bandwidth sets its speed. Reading a prompt is different: hundreds of tokens go through each weight at once, and the matrix units set the pace. On the Radeon 8060S those units multiply 8-bit integers at one rate and 4-bit integers at twice that rate. The usual path turns activations into 8-bit numbers. On this model it reads prompts at about 400 tokens a second.
A Q4_0 file already stores its weights as 4-bit numbers. A code q means q - 8, and flipping
its top bit gives exactly that value in two's complement. So the 4-bit kernel can read Unsloth's
Q4_0 weights bit for bit, and only the activations have to go down to 4 bits. That runs at 461-488
tokens a second, but it costs accuracy: KLD against the full model rises from 0.029 to 0.084.
The rotation#
Activations are rounded in blocks of 32 values that share one scale. A few large values in a block force a coarse scale on the other 31, and most of the 4-bit error comes from there. A 32-point Walsh-Hadamard transform spreads each block's energy evenly before rounding, so the scale fits all 32 values better.
The same transform is applied to the weights once, when the file is made. Because the transform
is orthogonal, rotating both sides leaves every dot product unchanged: x . w = (Hx) . (Hw). The
check is the exact 8-bit path: the rotated file gives KLD 0.031 there, against 0.029 for the same
model unrotated. On the GPU the rotation runs inside the step that quantizes activations: two
butterfly steps within each thread and three lane shuffles.
The numbers#
Qwen3.8-27B on Strix Halo, KLD against BF16 over wikitext-2, prompt speed from llama-bench (512 tokens):
| Prompt, tok/s | Perplexity | KLD | Same top token | |
|---|---|---|---|---|
| Q4_0, 8-bit activations | ~400 | 6.021 | 0.029 | 91.9% |
| Q4_0, 4-bit activations | 461-488 | 6.241 | 0.084 | 87.4% |
| Q4_0-H32, rotated, 4-bit activations | 509 | 6.096 | 0.055 | 89.3% |
The rotation removes a third of the 4-bit error. Against the 8-bit path, the rotated file reads
prompts 28% faster for 1.2% more perplexity. Through 1bit serve, a 1,838-token prompt runs at
440-470 tokens a second.
Making the file is part of the engine#
A rotated file only works when the runtime rotates the activations too. Run it anywhere else and it produces garbage. So the engine treats the file and the route as one thing.
tools/hadamard_q4_0.pyrotates the attention, FFN and delta-net projections of a Q8_0 or BF16 source, adjusts the imatrix to match, and quantizes. It then stamps the file and checks that every Q4_0 tensor in it is a rotated one; a file that fails is deleted. Qwen3.8-27B took about 20 minutes.1bit servereads the stamp. With no device flag it runs the file on the lean ROCm build with the rotation and the 4-bit path turned on. It refuses the file on any other device.- A test covers the routing without a GPU, so CI checks it on every change.
tools/hadamard_q4_0.py Qwen3.8-27B-Q8_0.gguf Qwen3.8-27B-Q4_0-H32.gguf --imatrix imatrix.gguf
1bit serve -m Qwen3.8-27B-Q4_0-H32.gguf
Two more kernels on the way#
Qwen3.8's linear-attention layers had two slow steps on ROCm, and the same update fixes both. A new prefill kernel keeps each state column in registers and stages each token's inputs in shared memory. A tiled transpose replaces the strided copy that fed their convolution. Both match the CPU reference in the backend tests, and every model with these layers gets them on ROCm.
What it is for#
This route reads prompts. It decodes at about 11 tokens a second, so long answers belong elsewhere: the Vulkan route with the DFlash2 drafter decodes code at 45.7 tokens a second on the same model. Use the rotated file where prompts are long and answers short, like summaries, code review over whole files, or retrieval with large contexts. The details are in Lean (ROCmFP4, ROCmI4).