Skip to content

spec : add DFlash2 support (local convolution + candidate selector) - #27342

Open
SubSir wants to merge 16 commits into
ggml-org:masterfrom
z-lab:dflash2
Open

spec : add DFlash2 support (local convolution + candidate selector)#27342
SubSir wants to merge 16 commits into
ggml-org:masterfrom
z-lab:dflash2

Conversation

@SubSir

@SubSir SubSir commented Aug 18, 2026

Copy link
Copy Markdown

Overview

DFlash2 adds two more modules compared to DFlash, grouped dynamic depthwise convolution and candidate selector.

The formula is for reference. out[i,c] = Σ_t (base[t,c] + δ[i,t,g(c)]) · x[i−t,c]. base is the static kernel, δ is the dynamic part predicted from the input.x is divided into groups g(c) and δ is shared across a group. Another one is edge(p→c) = ⟨A[p] ⊙ project(h), B[c]⟩ + unary[c]. A/B are the codebooks for the predecessor and the candidate. This position's hidden is projected by project(h)to the same rank to multiply A. And unary[c] is the draft's own score for c.

DFlash2 is enabled when the checkpoint is DFlash2; no need to use extra flag.

We evaled Qwen3.8-27B at Q4_K_Mon Apple M5 Pro 64 GB. And the test data is first 8 problems of GSM8K.
Concurrency is set to 1 and temperature is 1.0, top-p 0.95, top-k 20. We use default xhigh reasoning and set
2,048 maximum new tokens.

Method Draft quant Block Decode TPS Decode speedup Acceptance Normal stops
Autoregressive 10.42 1.00× 8/8
DFlash2 BF16 8 19.31 1.85× 4.92 8/8
DFlash2 Q8_0 8 18.43 1.77× 5.08 8/8
DFlash2 Q4_K_M 8 18.89 1.81× 5.03 8/8

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: YES. Using AI to inspect and analyze code in the llama.cpp project, and using AI to update the code.

@SubSir
SubSir requested review from a team, CISC and ggerganov as code owners August 18, 2026 20:53
@ggml-gh-bot

ggml-gh-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

Hi @SubSir, thanks for your contribution!

Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:

  • AI-generated content: While code is allowed to be generated by AI, please write the PR description and commit messages on your own without the help of AI.

Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below.

@SubSir

SubSir commented Aug 18, 2026

Copy link
Copy Markdown
Author

I've revised the PR description. It's fully hand-written now.

@showgood163

This comment has been minimized.

@ManTouMT

This comment has been minimized.

Nathanw1014 added a commit to Nathanw1014/strix-halo-llamacpp that referenced this pull request Aug 19, 2026
…and DFlash v1

Adds docs/dflash2-strix.md with the four-arm llama-benchy comparison on
Qwen3.8-27B UD-Q4_K_XL, and vendors the unedited tool output under
benchmarks/results/dflash2-20260819/.

Headline, decode t/s at depth 0 / 8k / 32k:

  base (no spec decode)   11.81  11.44  10.54
  DFlash v1 (n=5)         21.09  12.87  10.75
  DFlash2 (n=4)           26.39  21.58  21.11
  DFlash2 (n=7)           25.18  21.46  16.32

DFlash2 holds about 2x over base at every depth measured, while DFlash v1
decays to 1.02x by 32k, i.e. by then it is worth nothing over plain decode.
Draft width matters at depth: at 32k, width 4 beats width 7 by 29 percent,
and the two tie at shallow depth.

DFlash2 engine support is upstream ggml-org/llama.cpp#27342 by Jian Chen and
is not our work; the page says so. What is ours is the gfx1151/Vulkan
validation and the draft-width tuning. Drafter weights are inco's published
Apache-2.0 GGUFs.

Measured with llama-benchy 0.4.0, which draws prompts from a Gutenberg book so
acceptance reflects real prose. Content matters more than expected here: a
code-corpus prompt set decays about 47 percent from shallow to 32k where this
corpus decays about 20 percent, so the page carries that caveat rather than
presenting one number as definitive. --runs 2, so the spec arms carry +/- 1.0
to 2.5 and only the 32k width gap is comfortably outside the noise.

Prefill was taken at the server default -ub 512; -ub 256 is the measured dense
optimum on these weights, so that column is a few percent below the ceiling.
Noted in the page, rerun deferred.

Assisted-by: Claude Opus 5
@am17an
am17an requested a review from ruixiang63 August 19, 2026 06:23
@KaruroChori

This comment has been minimized.

@Shamish

This comment was marked as off-topic.

@treo

treo commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

@Shamish There is already a fix for the reported problem at z-lab#1

As for the Performance on a single RTX3090, it seems to be not significantly better than MTP:

MTP:

$ ./build/bin/llama-server -m ~/.cache/huggingface/hub/models--unsloth--Qwen3.8-27B-GGUF/snapshots/f1bfb127c64f7072bdd2cad55f258b9c8b2910fe/Qwen3.8-27B-UD-Q4_K_XL.gguf  --fit off -np 1  -fa on --spec-type draft-mtp --spec-draft-n-max 3 --reasoning-preserve -c 32000 -ctk q8_0 -ctv q8_0

$ python speed_bench.py --url localhost:8080 --model qwen3.8-27b --concurrency 1 --limit 2
Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
speed_bench: loaded 22 samples from bench=qualitative category=all
speed_bench: 100%|██████████████████████████████████████████████████████████████████████████████████████████| 22/22 [11:57<00:00, 32.60s/sample]

Summary (elapsed=717.20s)
category       samples  avg_prompt_t/s  avg_pred_t/s  avg_latency  accept_rate
-------------  -------  --------------  ------------  -----------  -----------
coding         2        454.24          59.84         69.160s      0.6047     
humanities     2        508.66          57.24         56.283s      0.6075     
math           2        27.86           55.76         17.593s      0.5927     
qa             2        85.46           54.37         18.066s      0.5589     
rag            2        704.60          59.45         40.403s      0.6777     
reasoning      2        60.51           54.47         18.138s      0.5954     
stem           2        28.90           54.39         17.867s      0.5981     
writing        2        612.05          61.74         42.117s      0.6609     
multilingual   2        164.13          65.08         4.339s       0.7778     
summarization  2        131.48          54.36         4.965s       0.5473     
roleplay       2        397.24          58.95         69.665s      0.6814     
overall        22       288.65          57.79         32.600s      0.6317  

DFlash2 (using maxn=4 because 7 was slower):

$ ./build/bin/llama-server -m ~/.cache/huggingface/hub/models--unsloth--Qwen3.8-27B-GGUF/snapshots/f1bfb127c64f7072bdd2cad55f258b9c8b2910fe/Qwen3.8-27B-UD-Q4_K_XL.gguf  --fit off -np 1  -fa on --spec-type draft-dflash --spec-draft-n-max 4 --reasoning-preserve -c 32000 -ctk q8_0 -ctv q8_0 -md ~/.cache/huggingface/hub/models--incoai--Qwen3.8-27B-DFlash2-GGUF/snapshots/6cb5872e2cee6b4e780a8414922350be8e42d65c/Qwen3.8-27B-DFlash2-Q4_K_M.gguf

$ python speed_bench.py --url localhost:8080 --model qwen3.8-27b --concurrency 1 --limit 2
Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
speed_bench: loaded 22 samples from bench=qualitative category=all
speed_bench: 100%|██████████████████████████████████████████████████████████████████████████████████████████| 22/22 [11:40<00:00, 31.85s/sample]

Summary (elapsed=700.65s)
category       samples  avg_prompt_t/s  avg_pred_t/s  avg_latency  accept_rate
-------------  -------  --------------  ------------  -----------  -----------
coding         2        271.99          68.00         48.928s      0.6691     
humanities     2        470.70          59.87         62.873s      0.5610     
math           2        28.45           60.14         29.131s      0.5827     
qa             2        82.64           53.74         13.088s      0.5039     
rag            2        701.27          66.42         37.589s      0.6378     
reasoning      2        58.79           60.55         29.046s      0.5827     
stem           2        29.38           60.20         28.899s      0.5827     
writing        2        607.63          69.16         38.621s      0.6552     
multilingual   2        167.16          62.26         5.469s       0.5316     
summarization  2        136.16          59.60         4.324s       0.5690     
roleplay       2        375.62          64.43         52.359s      0.6758     
overall        22       266.35          62.21         31.848s      0.6153  

@Stoney49th

This comment has been minimized.

@ruixiang63 ruixiang63 self-assigned this Aug 19, 2026
@ruixiang63

Copy link
Copy Markdown
Member

Thanks for the PR. It would be great if you could run the benchmark on SpeedBench using the corresponding checkpoints and report the performance numbers. @SubSir

@KaruroChori

This comment has been minimized.

@Zeldatales

This comment has been minimized.

@jhstatewide

This comment has been minimized.

Assisted-by: Claude Opus 5
ngxson
ngxson previously approved these changes Aug 24, 2026

@ngxson ngxson left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

llama.cpp code looks ok, but need an approval for CUDA part

regarding vision input bug: that will be a follow-up hot fix. proper fix will come after #24669

comments regarding this bug will be removed

Comment thread include/llama.h Outdated
LLAMA_API int32_t llama_model_n_embd_out (const struct llama_model * model);
LLAMA_API int32_t llama_model_n_layer (const struct llama_model * model);
LLAMA_API int32_t llama_model_n_layer_nextn(const struct llama_model * model);
LLAMA_API int32_t llama_model_dflash_selector_top_k(const struct llama_model * model);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to llama-ext.h

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e91bca5.

Comment thread gguf-py/gguf/constants.py Outdated
Comment on lines +1889 to +1895
MODEL_TENSOR.DFLASH_ATTN_CONV_BASE: "blk.{bid}.attn_conv_base",
MODEL_TENSOR.DFLASH_ATTN_CONV_PROJ: "blk.{bid}.attn_conv_proj",
MODEL_TENSOR.DFLASH_FFN_CONV_BASE: "blk.{bid}.ffn_conv_base",
MODEL_TENSOR.DFLASH_FFN_CONV_PROJ: "blk.{bid}.ffn_conv_proj",
MODEL_TENSOR.DFLASH_SELECTOR_PREV: "selector_predecessor",
MODEL_TENSOR.DFLASH_SELECTOR_NEXT: "selector_successor",
MODEL_TENSOR.DFLASH_SELECTOR_HIDDEN: "selector_hidden",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MODEL_TENSOR.DFLASH_ATTN_CONV_BASE: "blk.{bid}.attn_conv_base",
MODEL_TENSOR.DFLASH_ATTN_CONV_PROJ: "blk.{bid}.attn_conv_proj",
MODEL_TENSOR.DFLASH_FFN_CONV_BASE: "blk.{bid}.ffn_conv_base",
MODEL_TENSOR.DFLASH_FFN_CONV_PROJ: "blk.{bid}.ffn_conv_proj",
MODEL_TENSOR.DFLASH_SELECTOR_PREV: "selector_predecessor",
MODEL_TENSOR.DFLASH_SELECTOR_NEXT: "selector_successor",
MODEL_TENSOR.DFLASH_SELECTOR_HIDDEN: "selector_hidden",
MODEL_TENSOR.DFLASH_ATTN_CONV_BASE: "blk.{bid}.attn_conv_base",
MODEL_TENSOR.DFLASH_ATTN_CONV_PROJ: "blk.{bid}.attn_conv_proj",
MODEL_TENSOR.DFLASH_FFN_CONV_BASE: "blk.{bid}.ffn_conv_base",
MODEL_TENSOR.DFLASH_FFN_CONV_PROJ: "blk.{bid}.ffn_conv_proj",
MODEL_TENSOR.DFLASH_SELECTOR_PREV: "selector_predecessor",
MODEL_TENSOR.DFLASH_SELECTOR_NEXT: "selector_successor",
MODEL_TENSOR.DFLASH_SELECTOR_HIDDEN: "selector_hidden",

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 64f765f

Comment thread src/models/dflash.cpp Outdated
Comment on lines +10 to +14
ml.get_key(LLM_KV_LOGIT_SCALE, hparams.f_logit_scale, false);
hparams.f_final_logit_softcapping = 0.0f;
ml.get_key(LLM_KV_FINAL_LOGIT_SOFTCAPPING, hparams.f_final_logit_softcapping, false);

ml.get_key(LLM_KV_DFLASH_BLOCK_SIZE, hparams.dflash_block_size, false);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ml.get_key(LLM_KV_LOGIT_SCALE, hparams.f_logit_scale, false);
hparams.f_final_logit_softcapping = 0.0f;
ml.get_key(LLM_KV_FINAL_LOGIT_SOFTCAPPING, hparams.f_final_logit_softcapping, false);
ml.get_key(LLM_KV_DFLASH_BLOCK_SIZE, hparams.dflash_block_size, false);
ml.get_key(LLM_KV_LOGIT_SCALE, hparams.f_logit_scale, false);
hparams.f_final_logit_softcapping = 0.0f;
ml.get_key(LLM_KV_FINAL_LOGIT_SOFTCAPPING, hparams.f_final_logit_softcapping, false);
ml.get_key(LLM_KV_DFLASH_BLOCK_SIZE, hparams.dflash_block_size, false);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 64f765f

Comment thread src/llama-arch.cpp Outdated
Comment on lines +337 to +341
{ LLM_KV_DFLASH_BLOCK_SIZE, "%s.block_size" },
{ LLM_KV_DFLASH_CONV_KERNEL_SIZE, "%s.conv_kernel_size" },
{ LLM_KV_DFLASH_CONV_GROUP_SIZE, "%s.conv_group_size" },
{ LLM_KV_DFLASH_SELECTOR_RANK, "%s.selector_rank" },
{ LLM_KV_DFLASH_SELECTOR_TOP_K, "%s.selector_top_k" },

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to a separate block - no need to break the indentation here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 64f765f. Thanks!

SubSir added 2 commits August 24, 2026 01:47
Assisted-by: Claude Opus 5
@am17an

am17an commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

cc: @fairydreaming @ORippler for changes to the top-k kernel

@russovincenzo

This comment was marked as spam.

@ngxson
ngxson dismissed their stale review August 24, 2026 15:25

Temporary dismiss my review because the m-rope bug is quite déjà-vu, saw smth similar during muse glimmer development. I will have a look

@fairydreaming

fairydreaming commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

cc: @fairydreaming @ORippler for changes to the top-k kernel

I tested the performance of the included TOP_K kernel on RTX PRO 6000 Max-Q - compared it to the CUB argsort implementation and upcoming DeviceBatchedTopK (we don't use it yet, still waiting for the next CCCL release).

Used the following test cases and compared times per one test case run (k=64):

for (auto nrows : {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 }) {
    for (auto cols : {128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65000, 200000}) {
        test_cases.emplace_back(new test_top_k(GGML_TYPE_F32, {cols, nrows, 1, 1}, 64));
     }
}

But noticed that this implementation runtime increases with k, so I also ran slightly different test set with k=1024:

for (auto nrows : {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 }) {
    for (auto cols : {2048, 4096, 8192, 16384, 32768, 65000, 200000}) {
        test_cases.emplace_back(new test_top_k(GGML_TYPE_F32, {cols, nrows, 1, 1}, 1024));
     }
}

Results (k=64)

top_k_DFlash2_vs_DeviceBatchedTopK

As you can see this kernel is generally slower than DeviceBatchedTopK.

top_k_DFlash2_vs_argsort

But for small k it's faster than the argsort-based implementation. For 200000 cols the implementation falls back to argsort-based implementation.

Results (k=1024)

top_k_DFlash2_vs_argsort_k1024

For large k the new kernel is used only for low number of cols but it's clearly much slower.

Verdict

This kernel is faster only in some cases (small k values). My opinion is that it's better to wait for DeviceBatchedTopK (CUDA) and rocprim::segmented_topk (ROCm) that should be universally faster instead of adding multiple implementations for specialized cases.

@ORippler

Copy link
Copy Markdown
Collaborator

And I added a topk kernel. I found that the original topk implementation is relatively slow in a small k and large number of candidates, which is just the Dflash2 selector's topk case. It overrides ggml_cuda_op_top_k when the row is wider than 1024 and k is small enough, and in my test it's 17x faster than the original topk function on H200 and 15x faster on A10G in Dflash2's setting. Since I override ggml_cuda_op_top_k, it also takes over for the original backend sampler. But in my test, it's faster than the original kernel. If you guys want me to gate the topk kernel only for Dflash2 to achieve a minimal change in this pr, just tell me and I don't mind.

How do these per-kernel times transfer to E2E times on consumer-grade HW?

@ngxson

ngxson commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

@SubSir could you please apply this patch to fix the image input (mrope bug)? https://gist.github.com/ngxson/b5ef18797c1bdcb1814cf09afadfd7eb

that should make it aligned with muse glimmer rope handling

Assisted-by: Claude Opus 5

@ngxson ngxson left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GGUF will need to be reconverted, and vision input should work with new GGUF (tested on my side)

Please also fix the failing CI

Comment thread src/models/dflash.cpp Outdated
@sswtodo

This comment was marked as low quality.

Assisted-by: Claude Opus 5
@SubSir

SubSir commented Aug 24, 2026

Copy link
Copy Markdown
Author

@ORippler, I tested on RTX PRO 6000 Blackwell using Qwen3.8-27B. It's about 2-5% end to end throughput impact.

old top-k, t/s new top-k, t/s gain
BF16 59.77 61.33 +2.62%
Q4_K_M 60.14 62.14 +3.33%
Q4_K_M, MMVQ capped 92.69 97.08 +4.74%

(Q4_K_M MMVQ capped means I use GEMM kernel for an 8-token batch. It's another issue, not directly related to Dflash2. I provided the data here because otherwise it's a bit strange that BF16's throughput is nearly the same as Q4_K_M).

So if it's not that much to you, I'll follow @fairydreaming's opinion and use the original kernel. But the cost of Dflash2 is a bit higher on llama.cpp than sglang or vllm.

@ngxson @sswtodo, the ci fail is fixed in f7aadef, and I just uploaded the converted GGUF to z-lab/Qwen3.8-27B-DFlash2-GGUF. Later we'll update incoai/Qwen3.8-27B-DFlash2-GGUF. Thanks!

@cuiyuxin-gif

This comment was marked as low quality.

@zective

This comment was marked as spam.

LaurentZuijdwijk pushed a commit to LaurentZuijdwijk/llama.cpp that referenced this pull request Aug 25, 2026
Replace the headline block with the measured set: the speculative table for the
FP4 stack including its draft acceptance, prefill against upstream as a curve
over context depth for both a dense hybrid and a MoE, and the per-gate
ablations across three quant families. Link bench/ for the structured data,
methodology and charts.

Three corrections rather than additions:

The against-mainline table was stale. It showed the MoE at +3.2% where the
current measurement is +12.6% at depth 0; the difference is the tiled
concat-transpose kernel. It now carries depth as an axis, because the gain
decays with it - +13.0% at depth 0 down to +4.6% at 64k on the dense model.

Generation is now stated rather than omitted. It is flat within about 1% on
stock K-quants, a small consistent loss on the dense model, and the README says
so with the reason it is the wrong test for this fork's generation story.

The LDS stride row claimed +14% prefill. That was the whole-fork figure at the
time, not the pad's own contribution, which measures +7.3% whole-model. The pad
explanation also now documents the coopMatLoad alignment contract and the
RADV >= 25.3 gate, because the previous text recommended a pad that collapses
pp512 on older drivers.

Adds a fork-specific acknowledgements block: ciru-ai/ROCmFPX for the quant
formats, Jian Chen for DFlash2 (PR ggml-org#27342), and Nathanw1014/llama.cpp for the
Strix Halo Vulkan branch the prefill gates were ported from - noting that every
one was re-measured here and two of their defaults are disabled because the
gain does not reproduce on this hardware.

Assisted-by: Claude Opus 5
@ORippler

Copy link
Copy Markdown
Collaborator

So if it's not that much to you, I'll follow @fairydreaming's opinion and use the original kernel. But the cost of Dflash2 is a bit higher on llama.cpp than sglang or vllm.

For 2-4% E2E I'm fine with taking it, at least until CCCL3.5 has released. This was Linux? Or Windows

Comment thread src/models/dflash.cpp
Comment on lines +141 to +142
dflash_selector_prev = create_tensor(tn(LLM_TENSOR_DFLASH_SELECTOR_PREV, "weight"), { rank, n_vocab }, 0);
dflash_selector_next = create_tensor(tn(LLM_TENSOR_DFLASH_SELECTOR_NEXT, "weight"), { rank, n_vocab }, 0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question: It looks the size of dflash_selector is not small as described in blog +2.0M, e.g. with rank = 256 and n_vocab = 248320(qwen3.8 27B) that comes out to 2 × 256 × 248320 ≈ 127M parameters. Is this expected?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't explain it clearly in the blog. Actually predecessor_codebook and successor_codebook are projected from the target embedding and for Qwen3-4B, plus the hidden projection is 3 * 2560 * 256 = 1.97M. That's what we said 2M. And for implementation convenience, we materialized the projection into codebooks since 77.8M or 127M is not that much.

Comment thread src/models/dflash.cpp
Comment on lines +419 to +441
ggml_tensor * blocks = ggml_reshape_3d(ctx0, hidden, hidden_size, block_size, n_blocks);
ggml_tensor * coeffs = ggml_reshape_4d(ctx0, dynamic, n_groups, kernel_size, 2, n_tokens);
ggml_tensor * coeffs_side = ggml_view_3d(ctx0, coeffs, n_groups, kernel_size, n_tokens,
coeffs->nb[1], coeffs->nb[3], side * coeffs->nb[2]);

ggml_tensor * coeff_all = ggml_cont(ctx0, coeffs_side);
coeff_all = ggml_reshape_4d(ctx0, coeff_all, 1, n_groups, kernel_size, n_tokens);
coeff_all = ggml_repeat_4d(ctx0, coeff_all, group_size, n_groups, kernel_size, n_tokens);

ggml_tensor * base_side = ggml_reshape_4d(ctx0,
ggml_view_1d(ctx0, base, hidden_size * kernel_size, side * base->nb[2]),
group_size, n_groups, kernel_size, 1);

ggml_tensor * weight_all = ggml_add(ctx0, coeff_all, base_side);

ggml_tensor * result = nullptr;
for (int64_t tap = 0; tap < kernel_size; ++tap) {
ggml_tensor * values = blocks;
if (tap > 0) {
ggml_tensor * zeros = ggml_fill(ctx0,
ggml_new_tensor_3d(ctx0, hidden->type, hidden_size, std::min(tap, block_size), n_blocks), 0.0f);
if (tap < block_size) {
ggml_tensor * previous = ggml_view_3d(ctx0, blocks, hidden_size, block_size - tap, n_blocks,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this part we could optimize with some fusions. Need suggestions from @ggerganov

Comment thread src/models/dflash.cpp Outdated
Comment on lines +492 to +494
ggml_tensor * cand3 = ggml_reshape_3d(ctx0, candidates, top_k, tokens_per_block, n_blocks);
ggml_tensor * unary3 = ggml_reshape_3d(ctx0, unary, top_k, tokens_per_block, n_blocks);
ggml_tensor * hid3 = ggml_reshape_3d(ctx0, hidden, rank, tokens_per_block, n_blocks);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nits: the 3/4 suffixes here encode tensor rank rather than meaning, and it gets hard to follow once hid3 / hid / hid4 (and unary / unary3 / un / un4) all coexist across nested scopes. Something like cand_blk / unary_blk / gate_blk would read better.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 2f3923b. Thanks!

Comment thread src/llama-context.cpp Outdated
// and never more rows than a ubatch holds - so take the tighter bound
const uint32_t selector_tokens = std::min<uint32_t>(
n_tokens, model.hparams.dflash_block_size * cparams.n_seq_max);
res += 32*selector_tokens;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is 32? can you add comment to explain it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this is from the old version where selector is implemented by for loop. The node number shouldn't be calculated from the num of token in the batch in this version, and I missed it.

I counted on different number of layers and found that nodes per tensor is about 8.8, a bit higher than 8 nodes per tensor in the original code. So I add a special case for Dflash2 to lift the node per tensor to 12. Just in case that when the number of layers is larger than 8, graph nodes is larger than 1024 and it will throw an error.

layers tensors graph nodes nodes / tensor
4 66 582 8.8
6 96 840 8.8
8 126 1098 8.7
12 186 1614 8.7
16 246 2130 8.7

@art-den

art-den commented Aug 26, 2026

Copy link
Copy Markdown
ggml\src\ggml-backend-meta.cpp:543: GGML_ASSERT(src_ss[0].axis != GGML_BACKEND_SPLIT_AXIS_0) failed

On startup with --split-mode tensor for my x2 RTX 5060 Ti.

PS:
DFlash2 file: https://huggingface.co/z-lab/Qwen3.8-27B-DFlash2-GGUF/blob/main/Qwen3.8-27B-DFlash2-Q4_K_M.gguf
It works with --split-mode layer

SubSir added 2 commits August 26, 2026 13:38
Assisted-by: Claude Opus 5
Assisted-by: Claude Opus 5
@SubSir

SubSir commented Aug 26, 2026

Copy link
Copy Markdown
Author

@ORippler It's on Linux. Sorry I don't have resources on Windows.

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

Labels

conversion CUDA Related to the CUDA backend ggml changes relating to the ggml tensor library for machine learning model Model specific server testing Everything test related

Projects

None yet

Development

Successfully merging this pull request may close these issues.