Skip to content

sycl : fix Q8_0/k-quant reorder get_rows (garbage output with GGML_SYCL_ENABLE_OPT) - #3964

Open
xuhancn wants to merge 6 commits into
ggml-org:masterfrom
xuhancn:fix/sycl-q8-reorder-getrows
Open

sycl : fix Q8_0/k-quant reorder get_rows (garbage output with GGML_SYCL_ENABLE_OPT)#3964
xuhancn wants to merge 6 commits into
ggml-org:masterfrom
xuhancn:fix/sycl-q8-reorder-getrows

Conversation

@xuhancn

@xuhancn xuhancn commented Aug 2, 2026

Copy link
Copy Markdown

Found while working on whisper_xpu (https://github.com/xuhancn/whisper_xpu) (a SYCL fork of whisper.cpp for Intel Arc GPU). Q8_0 models gave garbage output on GPU when the reorder optimization was on (GGML_SYCL_ENABLE_OPT=1, the default), but worked when it was off.

Root cause: opt_for_reorder rewrites quantized weights in place into a split layout (qs | scales | d) for the MMVQ mul_mat path. But ggml_sycl_op_get_rows (token embedding lookup) still dequantized with the standard interleaved block layout, reading misaligned data
from the split buffer and producing NaN. The NaN propagated GET_ROWS -> ADD -> NORM -> MUL -> ADD into the mul_mat_vec_q activation, leaving some logits zero and letting argmax pick random tokens.

Fix: reorder-aware path in ggml_sycl_op_get_rows. When src0->extra->optimized_feature.reorder is set, index the split layout directly:

  • Q8_0/Q4_0: per-element template k_get_rows_reorder via block_q_t::get_block_offset/get_d_offset + dequantize_kernel_t_reorder
  • Q3_K/Q4_K/Q5_K/Q6_K: block-cooperative kernels (32/64 threads, scales via shared memory + barrier); offsets match the existing dequantize_block_q*_K_reorder; block index = src1[row]*nblocks_per_row + block_in_row
  • Q1_0 aborts (block_q_t<GGML_TYPE_Q1_0> unspecialized — left as follow-up)

Also fixed the mul_mat quantize path to use quantize_f instead of the hardcoded quantize_q8_1 (so the SoA quantizer is dispatched), and made mul_mat_q fall back to dequantize when the weight was already reordered.

Tests: standalone SYCL UTs for the reorder get_rows of Q3_K/Q4_K/Q5_K/Q6_K (host golden from dequantize_row_q*_K) — all pass; one caught a Q3_K thread-count mistake (128 vs 64). Lives at https://github.com/xuhancn/whisper_xpu/tree/main/tests (superproject PR #43
merged with the UTs: xuhancn/whisper_xpu#43). Q8_0 verified end-to-end with whisper-cli on large-v3-turbo-q8_0 and q4_0 tiny models: correct text.

Disclosure: AI tools were used to help write the kernel boilerplate and run the tests; the root-cause isolation, fix design, and verification were done by hand.

xuhancn added 5 commits August 3, 2026 03:57
* add /Zi + /DEBUG so cdb resolves frames in ggml-sycl.dll
* use quantize_f instead of hardcoded quantize_q8_1 in mul_mat
* restore Q8_0 in the reorder support lists
* fallback mul_mat_q to dequantize when weight is reordered
* add debug prints to isolate the reorder issue
* k_get_rows_reorder template for Q8_0/Q4_0 (per-element)
* block kernels for Q3_K/Q4_K/Q5_K/Q6_K (32/64 threads)
* dispatch reorder path when src0 is reordered
@xuhancn xuhancn changed the title Fix/sycl q8 reorder getrows sycl : fix Q8_0/k-quant reorder get_rows (garbage output with GGML_SYCL_ENABLE_OPT) Aug 2, 2026
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