Skip to content

model : re-enable -sm tensor for qwen4exp - #28569

Open
kh0pper wants to merge 1 commit into
ggml-org:masterfrom
kh0pper:qwen4exp-sm-tensor
Open

model : re-enable -sm tensor for qwen4exp#28569
kh0pper wants to merge 1 commit into
ggml-org:masterfrom
kh0pper:qwen4exp-sm-tensor

Conversation

@kh0pper

@kh0pper kh0pper commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Overview

Re-enables -sm tensor for qwen4exp. #27941 disabled it because test-llama-archs -a qwen4exp asserted on the Meta device once the fixture carried a PLE layer, and removed the test's earlier Meta skip for the arch.

The abort is a scheduler placement, not QSA. test-llama-archs builds the model with the embeddings host-resident, so the PLE embedding gather (ggml_get_rows on per_layer_token_embd) is a CPU node. In the qwen4exp graph hc_init (the ggml_repeat_4d that fans the embedding out to the hc streams) is first materialised inside layer 0's PLE path, after that gather. ggml_backend_sched_split_graph pass 2 expands a device assignment upwards only until it meets a CPU-assigned node, so the REPEAT is never reached from the first Meta node and "expand rest" leaves it on the CPU. The later ggml_reshape_3d(hc_init) inside the PLE query norm is then a view of a host-resident node inside the meta split, which ggml_backend_meta_graph_compute only tolerates for view_src->op == GGML_OP_NONE: GGML_ASSERT(ggml_backend_buffer_is_meta(tensor->buffer)) at ggml-backend-meta.cpp:476. deepseek4 builds the same hc init but its REPEAT is followed directly by a weight matmul, so the expansion reaches it.

Fix: ggml_build_forward_expand(gf, res_hc) right after hc_init is built. The REPEAT then directly precedes the first device node and pass 2 assigns it there; the embedding reshape stays in the CPU split and is copied in as a split input, the same shape deepseek4's graph has.

test-llama-archs on this branch (master dbeb375 + the change; RelWithDebInfo, RADV gfx1151, Mesa 25.2.8):

arch Vulkan Meta (-sm tensor)
qwen4exp OK (8.67e-08) OK (8.67e-08), was GGML_ASSERT
deepseek4 OK (8.86e-08) OK (8.86e-08)
qwen35 OK (8.80e-08) OK (8.80e-08)

Real model: Qwen3.8-Flash-Next UD-Q4_K_XL, -sm tensor over two RPC devices (#26610 tree with this change, one Vulkan ggml-rpc-server per Strix Halo box, ctx 65536) vs a single device, greedy: byte-identical on a short prompt and on a 1.8k-token prompt (1752 generated tokens), and identical to master's single-device output.

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: YES. AI-assisted analysis of the scheduler passes and test runs; the change and the tests were reviewed and run by me.

ggml-org#27941 disabled -sm tensor for qwen4exp because test-llama-archs asserted on the
Meta device once the fixture carried a PLE layer:
GGML_ASSERT(ggml_backend_buffer_is_meta(tensor->buffer)) at ggml-backend-meta.cpp:476.

With host-resident embeddings the PLE gather is a CPU node and hc_init (the REPEAT
that fans the embedding out to the hc streams) was first reached through layer 0's
PLE path, after that gather. ggml_backend_sched_split_graph pass 2 expands a device
assignment upwards only until it meets a CPU node, so the REPEAT stayed on the CPU
and the later reshape of hc_init inside the meta split viewed a host-resident node.

Expanding hc_init right after it is built puts the REPEAT directly before the first
device node, where pass 2 assigns it; the embedding reshape stays in the CPU split
and is copied in as a split input, as in deepseek4.
@kh0pper
kh0pper requested a review from CISC as a code owner September 7, 2026 17:09
@github-actions github-actions Bot added the model Model specific label Sep 7, 2026
@Zerschranzer

Zerschranzer commented Sep 8, 2026

Copy link
Copy Markdown

Heads-up: with --split-mode tensor, --fit on is ignored:

W common_fit_params: failed to fit params to free device memory: llama_params_fit is not implemented for SPLIT_MODE_TENSOR, abort

In router mode the instance then OOMs on load and the only trace is:

E alloc_tensor_range: failed to allocate ROCm0 buffer of size 28313139456

Tested on an ROCm build, 2x RX 9060 XT.

Edit:
Without fit = on, and after manually testing to find the optimal values for my dual GPU setup, it is running with:

split-mode = tensor
tensor-split = 1,1
n-cpu-moe = 29

Additionally, tokens/s and PP speed remained nearly identical, within a fluctuation margin of ±10%. VRAM allocation is roughly 97% to 96%. However, tensor split mode seems to maintain higher stability over long context lengths.

@cb88

cb88 commented Sep 8, 2026

Copy link
Copy Markdown

RX 9060 XT

Similar experience to @Zerschranzer

2xMI50 32GB and I can load and run it with the following preset , doesn't quite fit in 2 cards with the MMPROJ , getting about 19t/s, 14.5t/s @ 75k context , 7.7t/s at 212k , about 6.5t/s at full context so its a bit better than -sm layer still which is I think under 5t/s at that length.
[Qwen 3.8 Flash Next TS]
model = /home/cb88/models/Qwen3.8-Flash-Next-UD-IQ4_XS-00001-of-00003.gguf
mmproj = /home/cb88/models/mmproj/mmproj-F16.gguf
ctx-size = 262144
parallel = 1
load-on-startup = off
ctk = q8_0
ctv = q8_0
load-mode = mmap
lzm = on
sm = tensor
tensor-split = 1,1
n-cpu-moe = 10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

model Model specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants