Skip to content

llama : fix DFlash output head sharing - #30111

Merged
ruixiang63 merged 4 commits into
ggml-org:masterfrom
hthadicherla:fix/dflash-borrowed-output-head
Oct 8, 2026
Merged

ruixiang63 merged 4 commits into
ggml-org:masterfrom
hthadicherla:fix/dflash-borrowed-output-head

Conversation

@hthadicherla

Copy link
Copy Markdown
Contributor

Overview

Fix a regression from #29226: drafts with embeddings but no output head incorrectly reused their embeddings instead of borrowing the target's head. Restrict embedding reuse to the Gemma DSpark layout.

Nemotron-3.5-Lightning-30B-A3B-NVFP4 + DFlash, three matched coding requests on #29226 (pooled accepted/proposed):

Metric Before fix After fix
Draft acceptance 0.00% 40.65%

The fix matches pre-regression output and draft counters. Gemma tied-head, full-attention and SWA compatibility checks pass.

Requirements

  • I have read and agree with the contributing guidelines.
  • Codex was used to help understand the codebase and write code.

@hthadicherla
hthadicherla requested a review from CISC as a code owner October 7, 2026 18:24
@github-actions github-actions Bot added the model Model specific label Oct 7, 2026
Comment thread src/models/dflash.cpp Outdated
@CISC
CISC requested a review from ruixiang63 October 7, 2026 20:21
Comment thread gguf-py/gguf/constants.py Outdated
Comment thread src/llama-arch.cpp Outdated
Comment thread src/models/dflash.cpp Outdated
@hthadicherla

Copy link
Copy Markdown
Contributor Author

@CISC @ruixiang63 @ggerganov could you PTAL at this PR and see if it looks okay or not now ?

@hthadicherla
hthadicherla requested a review from CISC October 8, 2026 09:55
@ggerganov ggerganov added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Oct 8, 2026
@ruixiang63

ruixiang63 commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Before we merge, could you confirm whether this regression only affects Nemotron-3.5-Lightning-30B-A3B-NVFP4 with DFlash? The tie_word_embeddings setting comes from the ModelOpt checkpoint, but I’m not sure whether other checkpoints also include it. Could you also verify that other DFlash models still work? And I am not sure if this is a correct fix, it feels we make a simpler setting more complex.

@ggerganov ggerganov removed the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Oct 8, 2026
@hthadicherla

Copy link
Copy Markdown
Contributor Author

Before we merge, could you confirm whether this regression only affects Nemotron-3.5-Lightning-30B-A3B-NVFP4 with DFlash? The tie_word_embeddings setting comes from the ModelOpt checkpoint, but I’m not sure whether other checkpoints also include it. Could you also verify that other DFlash models still work? And I am not sure if this is a correct fix, it feels we make a simpler setting more complex.

@ruixiang63 Yes for now, this regression only seems to affect Nemotron 3.5 Lightning Model.

The fix makes output-head selection explicit:

  1. Existing output head: use it.
  2. Missing head, tie_word_embeddings=true: use the draft’s embeddings as its output weights.
  3. Missing head, flag absent or false: borrow the target’s output head.

This preserves the usual DFlash/DFlash2 head-sharing path and fixes Nemotron Lightning, where having its own input embeddings does not mean those embeddings should also be its output head.

I verified Qwen3.8-27B + DFlash2 on the full SPEED-Bench coding subset: 80 conversations / 89 turns, using identical settings before and after the fix.

Metric Before After
Draft acceptance 41.5636% 41.5636%

All generated outputs and per-request draft counters were identical.

@hthadicherla

Copy link
Copy Markdown
Contributor Author

The tie_word_embeddings setting comes from the ModelOpt checkpoint, but I’m not sure whether other checkpoints also include it.

Forgot to answer this question in my earlier reply.

tie_word_embeddings doesn't seem specific to ModelOpt. For example, Qwen3.8-27B-DFlash2 also includes it, set to false.
Link: config.json

We don’t require every checkpoint to provide it. This PR writes the corresponding GGUF metadata through the Gemma DSpark converter; other DFlash/DFlash2 conversion paths are unchanged. If the GGUF flag is absent, a draft without its own output head defaults to borrowing the target’s head.

Comment thread src/models/dflash.cpp Outdated
output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), { n_embd, n_vocab_draft }, TENSOR_NOT_REQUIRED);
if (output == nullptr && tok_embd != nullptr) {

if (output == nullptr && hparams.tie_word_embeddings) {

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.

My question concerns this change in PR #29226 which appears to have introduced this issue.

Is this change necessary, or could we restore the logic from before PR #29226 o resolve the issue?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I checked the checkpoint contents and agree we can remove the fallback. The Gemma DSpark checkpoints I inspected, already contain an explicit output head, so they don’t depend on it. I couldn’t find a checkpoint requiring the draft-embedding fallback.

I’ll simplify the fix to restore the previous behavior before #29226: use the draft’s output head when present; otherwise borrow the target’s head. I’ll also update the Gemma converter to require an explicit head and rerun the regression checks.

@hthadicherla

hthadicherla commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor Author

@ruixiang63 @CISC @ggerganov , i have just removed the tie word embeddings fallback entirely. PTAL at this PR now.

The change now uses the draft’s output head when present, otherwise borrows the target’s head.

Tested the existing Gemma4 with Dspark, Nemotron Lighting with DFlash and Qwen 3.8 27B. All of them are working as expected.

@ruixiang63 ruixiang63 added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Oct 8, 2026
@ruixiang63
ruixiang63 merged commit a11f57b into ggml-org:master Oct 8, 2026
20 of 21 checks passed
feal87 added a commit to feal87/myllama.cpp that referenced this pull request Oct 8, 2026
Upstream brings CUDA top-k/argsort/mmq fixes (PR ggml-org#28713, ggml-org#29953, ggml-org#30147,
ggml-org#29453), a DFlash output-head fix (ggml-org#30111) and a UI fix (ggml-org#29668).

Conflicts and resolution:
- top-k.cu / argsort.cu: upstream reworked the top-k selection and the same
  radix path the fork added. Take upstream's shape-based dispatch and int64_t
  fixes, keep the fork workspace cap in the shared ggml_cuda_chunk_nrows
  (GGML_CUDA_ARGSORT_CHUNK_MB) and the fork benchmark-only GGML_CUDA_TOPK_IMPL
  selector used by bench-topk.py.
- mmq.cu: upstream PR ggml-org#29953 fixes the same mul_mat_id padding over-read the
  fork patched in 1386ec2, but sizes the padding from the chosen J tile in
  both branches. Take upstream's version.
- test-backend-ops.cpp: keep the fork GGML_TOPK_BENCH shapes and add upstream's
  chunk-spanning cases.

Assisted-by: pi (deepseek-flash)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conversion merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. model Model specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants