Repository navigation
sycl : fix get_rows on reordered quantized weights - #30430
Conversation
arthw
left a comment
There was a problem hiding this comment.
It's good job!
The reordered weight only happen in mul_mat of SYCL backend.
We didn't meet the issue #30428 before.
I think it would happen frequently when mix backends (CPU, CUDA, Vulkan) in the future.
It's good to make the other OP to support reordered weight.
It's the base to apply reordered weight in all OPs of SYCL backend.
Thank you!
|
Thanks a lot @skipzx-lab, this is exactly the kind of help I needed since I have no Intel hardware to test on. I cherry-picked your get_rows fix into the ggml module used by my music and vocoder projects, so acestep.cpp and yue2.cpp get the full speed SYCL path right now without waiting for the upstream merge. audio.cpp should benefit too once it resyncs its ggml, since several of its decoders share one tensor between the token embedding and the lm_head. Next on my side is the Snake fusion for SYCL, and your VAE profile shows IM2COL is worth a look too. I'll ping you when there is something to test on the B60. |
Thanks @arthw, agreed on making every SYCL op reorder aware. I'll leave the merge button to you since you own the backend. |
|
Thanks @arthw and @ServeurpersoCom for the reviews, and glad it's already useful in acestep.cpp and yue2.cpp. Happy to test the Snake fusion and anything on IM2COL on the B60 when they're ready. Ping me and I'll run them and report numbers. |
…ghts gets its per-block kernels back Upstream ggml-org#30430 lets get_rows read weights that a mat-mul has already reordered, through the per-block q4_K / q5_K / q6_K reorder dequantize kernels with an explicit block index. This branch replaced those kernels with the wide ones (and replayed with its own side winning), so they come back next to the wide kernels, used by get_rows only. The reorder layouts of q4_0, q8_0 and q2_K .. q6_K are identical here and upstream. The q6_K pair shares a name: ours takes the store width as a template argument and 4 arguments, upstream's a block index and 5. Assisted-by: Claude Opus 5.5
…ghts gets its per-block kernels back Upstream ggml-org#30430 lets get_rows read weights that a mat-mul has already reordered, through the per-block q4_K / q5_K / q6_K reorder dequantize kernels with an explicit block index. This branch replaced those kernels with the wide ones (and replayed with its own side winning), so they come back next to the wide kernels, used by get_rows only. The reorder layouts of q4_0, q8_0 and q2_K .. q6_K are identical here and upstream. The q6_K pair shares a name: ours takes the store width as a template argument and 4 arguments, upstream's a block index and 5. Assisted-by: Claude Opus 5.5
Co-authored-by: Sam <sam@garagellm.tail7dd858.ts.net>
Cherry-pick from upstream sycl-fa-q4-xmx-up. Fixes incorrect get_rows results when weight tensors use the reorder layout (q4_0/q8_0). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Sam <sam@garagellm.tail7dd858.ts.net>
…ghts gets its per-block kernels back Upstream ggml-org#30430 lets get_rows read weights that a mat-mul has already reordered, through the per-block q4_K / q5_K / q6_K reorder dequantize kernels with an explicit block index. This branch replaced those kernels with the wide ones (and replayed with its own side winning), so they come back next to the wide kernels, used by get_rows only. The reorder layouts of q4_0, q8_0 and q2_K .. q6_K are identical here and upstream. The q6_K pair shares a name: ours takes the store width as a template argument and 4 arguments, upstream's a block index and 5. Assisted-by: Claude Opus 5.5
Fixes #30428
Overview
With
GGML_SYCL_ENABLE_OPT=1(the default), ggml-sycl reorders Q4_0, Q8_0, Q2_K, Q3_K, Q4_K, Q5_K and Q6_K weights in place on their first small-batch mul_mat (8 tokens or fewer), and setsextra->optimized_feature.reorder. That's every type ggml-sycl reorders for 2D weights.get_rowsignored the flag, so a tensor read by both ops returned wrong rows or NaN after the first mul_mat.It's triggered by tied embeddings kept on the device. llama.cpp itself mostly avoids it because input embeddings stay on the CPU and a tied output gets its own copy, but other ggml programs hit it.
Changes (4 files, +262 / -21):
getrows.cppk_get_rows_reorderandget_rows_sycl_reorder. Same indexing ask_get_rows, but reading from the reordered layout via the existingdequantize_q4_0_reorder/dequantize_q8_0_reorder.get_rows_sycl_reorder_k, one work-group per 256-value block of a requested row, calling the existingdequantize_block_qX_K_reorderfunctions with each type's existing thread count and local scratch.dequantize.hpp: the 5 K-quant reorder dequantisers now take the block index and output pointer as parameters instead of readingget_group(), soget_rowscan call them for an arbitrary row.convert.cpp: the 5 existing callers passy + group * QK_Kandgroup, the same values as before, so behaviour there is unchanged.tests/test-backend-ops.cpp: newtest_get_rows_after_mul_mat. It runs a one-column mul_mat on a weight, thenget_rowson the same weight. The mul_mat runs first because it's the first input of the final ADD. Covers all 7 types with a 5e-4 tolerance, same astest_mul_mat.Additional information
Tested on an Arc Pro B60 24 GB, oneAPI 2026.1, Level Zero 1.14.37020, Ubuntu 26.04, master cbe28bb.
How I found it. acestep.cpp's 4B LM (Q8_0, tied embeddings) produced random output lengths on SYCL. Setting
GGML_SYCL_ENABLE_OPT=0fixed it at roughly 4x slower decoding, which pointed at the reorder. Logs and timings are in ServeurpersoCom/acestep.cpp#54, where the acestep.cpp maintainer agreed the fix belongs upstream.Why fix
get_rowsinstead of skipping the reorder? The reorder happens on the first mul_mat, and the backend can't easily see every other op that'll use the tensor later. Teachingget_rowsthe layout keeps the fix local, keeps the speedup, and matches what the dequantize path already does for reordered weights.Related PRs. #30374 (reordered Q4_0 dequantize kernel) and #29107 (IQ3 reorder) are open SYCL reorder work, but neither touches
get_rows, so this doesn't overlap.Requirements