Expand description
W3 — in-project GPU↔CPU kernel-parity oracle (no external LLM libs).
The “no external libraries” rule (Prime Directive #4) means the only trustworthy reference for a
GPU kernel is an in-project CPU implementation of the identical math. This module supplies the
comparison metrics (max / mean absolute error + ULP distance) and helpers to synthesize valid
quantized weights, so a GPU shader can be checked against its CPU twin on random, controlled
inputs — fast, deterministic, and library-free. The first consumer is the GEMM parity test
(QTensorEngine::gemm_parity_probe: GPU dispatch_gemm_raw_into vs CPU stack_gemm_quant).
Pure CPU + zero-heap on the metric paths (slices in, scalars out); safe on every target.
Functions§
- f16_
bytes - Bytes needed to hold
n_elemsweights as little-endian IEEE F16 (2 bytes each). - max_
abs_ err - Maximum absolute error between two equal-length slices. Returns
+infon length mismatch so a caller cannot silently pass a comparison of differently-shaped outputs. - max_
ulp_ diff - Maximum ULP (unit-in-the-last-place) distance over finite pairs; non-finite pairs are skipped.
Returns
u64::MAXon length mismatch. - mean_
abs_ err - Mean absolute error (f64 accumulation to avoid catastrophic cancellation over long vectors).
- q4_
0_ bytes - Bytes for
n_elemsweights as ggml Q4_0 (18-byte blocks of 32: f16 scale + 16 nibble bytes). - q4_
k_ bytes - Bytes for
n_elemsweights as ggml Q4_K (144-byte super-blocks of 256). - q8_
0_ bytes - Bytes needed to hold
n_elemsweights in Q8_0 (ceil to whole 32-element blocks). - quantize_
f16_ from_ f32 - Encode
weights(f32) as little-endian IEEE F16 intoout(>=f16_bytes(weights.len())). The exact byte layoutdequant_f16/ the GPUunpack2x16floatpath consume. - quantize_
q4_ 0_ from_ f32 - Quantize
weights(f32) to ggml Q4_0 intoout(>=q4_0_bytes). Matchesggml_quants::dequant_q4_0exactly: per 32-blockd = max_abs_signed / -8, nibbleq = clamp(round(x/d)+8, 0..15), dequantx = (q-8)*d; interleaved layout — block indexk < 16is the low nibble of bytek,k >= 16the high nibble of bytek-16. - quantize_
q4_ k_ from_ f32 - Quantize
weights(f32) to ggml Q4_K intoout(>=q4_k_bytes). Matchesggml_quants::dequant_q4_k: super-block of 256 = 8 sub-blocks of 32, each with an asymmetric scale+min — 6-bit sub-scales (d*sc) and mins (dmin*m) packed viaget_scale_min_k4, 4-bit quants (even sub-block = low nibble, odd = high nibble of the sameqsbyte). Dequant:x = d*sc[s]*q - dmin*m[s]. Simplified vs ggml’s iterative search (per-sub-block min clamped ≤ 0, which holds for zero-centred weights); round-trip tested. Q4_K’s 6-bit sub-scales make it markedly more accurate per bit than Q4_0 — AWQ’s intended 4-bit partner. - quantize_
q8_ 0_ from_ f32 - Quantize
weights(f32) into Q8_0 blocks inout(must be >=q8_0_bytes(weights.len())). Standard ggml Q8_0: per 32-block,scale = absmax / 127,q = round(w / scale)clamped to i8, stored as little-endian f16 scale followed by 32 signed bytes. Returns false ifoutis too small.