Skip to content

NPU: read all three Q4NX chunk kinds (q4_1, Q4_K, Q8), repack Q4_K into q4_1 - #33

Merged
bong-water-water-bong merged 3 commits into
mainfrom
npu-q4nx-chunks
Sep 24, 2026
Merged

bong-water-water-bong merged 3 commits into
mainfrom
npu-q4nx-chunks

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

Q4NX was fully decoded in 1bit-MONSTER (npu-infer, the Qwen3.5-4B work, merged in #2684): besides the 5120-byte q4_1 tile the engine reads today, Q4NX has a 4736-byte Q4_K chunk and an 8704-byte Q8 chunk. This brings that into the engine.

  • npu/q4nx.{h,cpp} (new, our notice): chunk kind from the tensor shape's last dimension; tile/tensor decoders for all three; a Q4_K -> q4_1 repack (exact apart from rounding S*scale and M*min to bf16) so the lane and dx, which read q4_1, run Q4_K weights unchanged. Q8 does not fit q4_1.
  • Tensor::tiles() understands the 3-d [tile rows, tile cols, chunk] shape Qwen3.5-4B uses.
Chunk Kind Weight Seen in
5120 B q4_1 code * scale + zero Qwen3, Llama, Gemma, Phi
4736 B Q4_K S * scale * code + M * min Qwen3.5-4B projections
8704 B Q8 d * code Qwen3.5-4B lm_head, embedding

Tested (npu_q4nx, runs in CI): each decoder matches 1bit-MONSTER's verified Python decoder bit for bit on a real tile of each kind (committed in tests/golden/q4nx, checked by the SHA-256 of the 32 x 256 f32 output); the repack's max error is 0.00032, 0.92 of its bf16 rounding bound.

Note: the Q4_K layout originally came from OpenFlowLM-Next's q4nx.py (a file-format description, not engine or kernel code).

🤖 Generated with Claude Code

@bong-water-water-bong
bong-water-water-bong enabled auto-merge (squash) September 24, 2026 10:39
bong-water-water-bong and others added 3 commits September 24, 2026 07:40
…K into q4_1

npu/q4nx.{h,cpp}: the chunk kind of a tensor (its shape's last dimension), tile and
tensor decoders for q4_1 (5120 B), Q4_K (4736 B) and Q8 (8704 B), and a Q4_K -> q4_1
repack that is exact apart from rounding S*scale and M*min to bf16, so the lane and
dx (which read q4_1) run Q4_K weights unchanged. Tensor::tiles() understands the
3-d [tile rows, tile cols, chunk] shape Qwen3.5-4B uses.

The layouts are 1bit-MONSTER's (npu-infer/src/q4nx_dequant.c, verified there against
the checkpoint's bf16 twin and a CPU forward). tests/npu_q4nx_test.cpp checks ours
bit for bit against its Python decoder (npu-infer/tools/q4nx_dequant.py at
35fafde8f) on one real tile of each kind (tests/golden/q4nx: Qwen3.5-4B qkv_proj and
lm_head, Qwen3-0.6B q_proj; the expected SHA-256 of each 32 x 256 f32 output), and the
repack against its bound: max error 0.00032, 0.92 of the bf16 rounding bound.
docs/npu.md, "Q4NX chunks".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…annot carry a comment

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bong-water-water-bong
bong-water-water-bong merged commit c217e07 into main Sep 24, 2026
3 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the npu-q4nx-chunks branch September 24, 2026 10:42
bong-water-water-bong added a commit that referenced this pull request Oct 25, 2026
Private HIP add-on pin 744bd713d968 -> 17a882640fa88: NVFP4 + Q2_0 on every family (#33), 2..16-token verify kernels (#32) and the GEAK WMMA rewrite (#37), DFlash2 selector (#34), ZAYA lm_head + one-token kernels (#35), Bonsai ternary verify + PQ2_0 prefill (#36), IQ2_S expert prefill + decode (#38/#39). hw-gate kat goldens (7 models x 9 cases) and KLD bases re-recorded at llama.cpp e7e5cd08 + this pin; check-back 13/13 PASS on the gate box.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant