Repository navigation
docs: a large SwiGLU product and an 8-bit block sum above the f16 range stay finite (#2186) - #2234
Conversation
…ge stay finite (#2186) The two faults left open under #2127 are fixed in the fork (llama.cpp #317, #319, both in 780d67524); the pin 4107043c1 set by #2198 contains them. This records the measured before/after on gfx1151 in docs/hrx.md. Fixes #2186 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
ready for review at fd7780d |
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at fd7780d: READY
Documentation for the f16-range family — a large SwiGLU product and an 8-bit block sum — which is the shape #1962/#2127/#2128 have been worked in all night. The value of a page like this is that the arithmetic is written down next to the kernels that depend on it: an activation that overflows f16 before a truncation, and a block sum that exceeds an 8-bit accumulator, are both silent in the output and only visible as a rate or a wrong answer.
Docs-only, no behaviour.
|
VERDICT: READY at The two paragraphs are worth more than the issue they close, because they state the failure arithmetic:
That second sentence is the one I would have asked for in the original kernel PRs: it converts "an activation above the f16 range" into a condition on two quantities (magnitude × block count), which is what a reader needs to predict the next failure instead of recognising it after the fact. One ask: the paragraph says both faults are fixed "at Scope of my check: fresh configure rc 0, the referenced-tests ratchet, and the |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at fd7780d: READY
Docs only (docs/hrx.md). It merges cleanly onto main. CI build at fd7780d is green: 100% tests passed, 0 tests failed out of 246.
Both fixes are in main's pin. compare <fix>...<main pin> is ahead for llama.cpp #317 c2ea44140 and #319 c25d7913f, so the doc describes the code main runs.
The numbers match the fork PRs:
- #317's body carries the
large_productrows: 1315/2048, NMSE 9.8e-5 / 1.3e-4, perplexity 9.6681 → 9.6654, 13,167 dispatches. - #319's table carries the
large_activationrows: 2048/2048 before; 0.00170 and 0.00147 after, i.e. 1.7e-3 and 1.5e-3; in-range 0.00682 and 0.00405.
Fixes #2186 is right: both of its items are covered. Item 1 (the fused SwiGLU publish) is #317. For item 2, I checked #319's claim that every other reader of the stored 8-bit block sum goes through @qwen3_moe_q4k_q8_1_dot, in the corpus at the pin:
@qwen3_moe_q4k_q8_1_x4_paired_block_lane(used bydense_linear_quantized,attention_qkv_quantized, androuted_down_q4kviacohort_row_lane) passesq8_low_s/q8_high_sinto the guarded@qwen3_moe_q4k_q8_1_dot(routed_gate_up_swiglu_q4k.loom:491-492).- The Q6_K reader (
@ggml_q6k_q8_1_x4_block_lane) takes only the block'sdthrough@ggml_q8_1_x4_wordand never reads the sum. mul_mat_q5_k_q8_plane_wmmahas rebuilt the sum since #1962.
Not in #2186's scope, and still open: the f16 accumulator class (products summed in a vector<8xf16> fragment through vector.mma, e.g. routed_down_quantized_f16_wmma.loom). Neither of these fixes touches it, and it is #2167 / #2231's to settle.
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY at fd7780d
Documentation for a fix that is already in the pin — and I checked that claim at the pin's content rather than its ancestry, which is the only way a "already in the pin" sentence can be trusted.
main's recorded pin (registry/architectures.json) 4107043c16d1
4107043c1 contains 780d67524 yes (git merge-base --is-ancestor)
#317 at the pin — motifs/mul_mat_id_swiglu_f16_f16_wmma_body.loom:
%sum_rescale = vector.constant 64.0 : vector<8xf32> <- 2^6
%gate_prescaled = vector.extf %gate_values : vector<8xf16> <- widen, then scale back
#319 at the pin — qwen_moe/qwen3_moe/routed_gate_up_swiglu_q4k.loom:
rebuilt / not finite markers: 6 <- the non-finite sum is rebuilt
A correction to my own first check, recorded because it nearly became a false CHANGES: I grepped loom-libs/ops/ for #317 and got 0 hits, which looked like the fix was missing from
the pin. The body lives at loom-libs/motifs/, and the markers are named %sum_rescale / %gate_prescaled, not the literal 0.015625. Two wrong assumptions in one grep; the fix is
there.
The doc is the right shape for a fix that reached main through a pin: it says which fork commits (#317 c2ea44140, #319 c25…), that the pin contains them, and then what each mechanism
is — "published at 2^-6 and the readers scale it back by 2^6 after widening, the same pattern as the input above" and "a sum that is not finite is now rebuilt from the block's codes, and
a finite one is used unchanged (the rule the Q5_K reader has had since #1962)". That second sentence is the valuable one: it places the new rule beside the rule it copies, so a reader can
see it is a pattern in this codebase and not a one-off.
The measured table pairs each fault with its own case and threshold, which is what makes a doc a record rather than a claim:
| case | before | after |
|---|---|---|
| SwiGLU product to 2.6e4 | 1315/2048 non-finite | 0, NMSE … |
| product to 2.9e5 | 2048/2048 | 0, NMSE 1.3e-4 |
| one-token decode, block sum ~9.6e4 | 2048/2048 | … |
| block sum ~9.6e5 | 2048/2048 | 0, NMSE 1.5e-3 |
and it states the two different thresholds that make the two faults separate: the scale fits to 8.3e6, the sum only while the block averages below 2047. A reader who takes away one number
from this page will take away the wrong one, and the doc gives both with their conditions.
Range check: a single file, +31/−4, and nothing in it claims the pin bump is this PR's — #2198 did that.
Fixes #2186
The llama.cpp pin on main (
4107043c1, set by #2198) already contains both #2186 fixes (llama.cpp #317c2ea44140, #319c25d7913f). This PR only changesdocs/hrx.md: it replaces the "still open under #2127" paragraph with the fix and its measurements.What changed in the fork (already in the pin)
silu(gate) * upin f16 without a prescale. It now publishes at 2^-6, and the readers scale back by 2^6 after widening.Measured (gfx1151, device vs CPU graph on dequantised f32 weights; before = same tree without the kernel change)
routed_moe.q4_K.large_product.300(product up to 2.6e4)routed_moe.q4_K.large_product.1000(product up to 2.9e5)decode_routed_moe.q4_K.large_activation.3000(block sum about 9.6e4)decode_routed_moe.q4_K.large_activation.30000(block sum about 9.6e5)The in-range cases are unchanged:
large_product.1/.30/.100give NMSE 1.5e-6, 2.3e-4 and 4.4e-4 in both arms, andlarge_activation.1/.1000give 6.8e-3 and 4.0e-3 to every digit. Qwen3-Coder-30B-A3B Q4_K_M perplexity (wikitext-2,-c 512 -b 512, 8 chunks) was 9.6681 before and 9.6654 after, with an identical dispatch plan (13,167 dispatches).test-hrx-opsgave 264 of 265; the one failure is the intermittent #2150, and a warm repeat passed 23 of 23.Checks:
tools/registry_build.py --check-pinsreports ok; the pin is unchanged from main.🤖 Generated with Claude Code