Summary
Loading a DFlash2 draft model (--model-draft) against a target model with --split-mode tensor crashes with a GGML_ASSERT in ggml-backend-meta.cpp during graph allocation. The identical launch succeeds with --split-mode layer.
Environment
Repro
llama-server \
--model Qwen3.8-27B-UD-Q4_K_XL.gguf \
--model-draft Qwen3.8-27B-DFlash2-Q8_0.gguf \
--host 127.0.0.1 --port 9006 --n-gpu-layers 99 \
--cache-type-k q4_0 --cache-type-v q4_0 --parallel 1 --flash-attn on \
--reasoning off --jinja --metrics --load-mode mmap \
--ubatch-size 256 --batch-size 2048 --ctx-size 65536 \
--split-mode tensor --tensor-split 1,1
Observed
0.00.641.175 I spec common_specu: auto-detected speculative type 'draft-dflash' from the draft model metadata
0.00.647.618 I srv load_model: loading model '.../Qwen3.8-27B-UD-Q4_K_XL.gguf'
0.01.188.086 E llama_init_from_model: failed to initialize the context: dflash requires ctx_other to be set (this warning is normal during memory fitting)
0.01.244.547 W srv load_model: [spec] failed to measure draft model memory: failed to create llama_context from model
0.01.244.576 W common_fit_params: failed to fit params to free device memory: llama_params_fit is not implemented for SPLIT_MODE_TENSOR, abort
...
0.07.022.081 I common_speculative_impl_draft_dflash: adding speculative implementation 'draft-dflash'
0.07.022.082 I common_speculative_impl_draft_dflash: - n_max=3, n_min=0, p_min=0.00
0.07.022.082 I common_speculative_impl_draft_dflash: - block_size=8, mask_token_id=248070, n_extract=5, sample_from_anchor=true
/path/to/ggml/src/ggml-backend-meta.cpp:543: GGML_ASSERT(src_ss[0].axis != GGML_BACKEND_SPLIT_AXIS_0) failed
...
ggml_gallocr_alloc_graph+0x45c
ggml_backend_sched_alloc_graph+0x18f
llama_context::process_ubatch(...)
llama_context::decode(llama_batch const&)
llama_decode
common_context_can_seq_rm(llama_context*)
server_context_impl::load_model(common_params&)
Expected
Either DFlash2 works correctly under --split-mode tensor (with correct output — the same silent-wrongness class of bug as a bad draft-model quantization, so it should be verified for correctness, not just "doesn't crash"), or the two options should refuse to combine with a clear error instead of an assert/crash.
Analysis
The assert is in the generic per-op split-axis planner used by the automatic tensor-parallel graph splitter (ggml-backend-meta):
auto handle_per_row = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
GGML_ASSERT(src_ss[0].axis != GGML_BACKEND_SPLIT_AXIS_0);
return src_ss[0];
};
This handler asserts its input isn't split along axis 0 rather than repartitioning it if it is. Some tensor in DFlash2's block-diffusion candidate-selector subgraph arrives at a per-row op split along axis 0 under tensor-parallel, which this handler has no case for — plausibly because DFlash2 was developed/tested primarily against --split-mode layer, not tensor-parallel, so this interaction was never exercised.
Workaround: use --split-mode layer instead of --split-mode tensor when using a DFlash2 draft model.
Summary
Loading a DFlash2 draft model (
--model-draft) against a target model with--split-mode tensorcrashes with aGGML_ASSERTinggml-backend-meta.cppduring graph allocation. The identical launch succeeds with--split-mode layer.Environment
1deefcca3("Add p_min in DFlash2"), built with CUDA backend (build-cuda)Repro
Observed
Expected
Either DFlash2 works correctly under
--split-mode tensor(with correct output — the same silent-wrongness class of bug as a bad draft-model quantization, so it should be verified for correctness, not just "doesn't crash"), or the two options should refuse to combine with a clear error instead of an assert/crash.Analysis
The assert is in the generic per-op split-axis planner used by the automatic tensor-parallel graph splitter (
ggml-backend-meta):This handler asserts its input isn't split along axis 0 rather than repartitioning it if it is. Some tensor in DFlash2's block-diffusion candidate-selector subgraph arrives at a per-row op split along axis 0 under tensor-parallel, which this handler has no case for — plausibly because DFlash2 was developed/tested primarily against
--split-mode layer, not tensor-parallel, so this interaction was never exercised.Workaround: use
--split-mode layerinstead of--split-mode tensorwhen using a DFlash2 draft model.