Skip to content

spec: greedy output diverges from non-speculative baseline under batched verification on CUDA (deterministic numerics; draft-simple alone reproduces, DFlash2 amplifies) #27407

Description

@indubwestep

Summary

With speculative decoding enabled (temp 0, fixed seed, otherwise identical settings), greedy output diverges from the identical non-speculative run. The divergence is deterministic (reruns are byte-identical) and is classified as CUDA numerical divergence under batched speculative verification, not a logic bug: the plain draft-simple path — which exercises batched verification with none of the DFlash2 code — reproduces it on one workload, while the DFlash2 path amplifies it (diverges on both workloads tested, and earlier).

Outputs remain coherent; this is a bit-exactness concern only, and speculative acceptance is unaffected. No fix is claimed here — this is a documentation/confirmation request.

Environment

  • llama.cpp at PR spec : add DFlash2 support (local convolution + candidate selector) #27342 head: 5ecbe1ac17ec0484c5b44af0bd580cdc9c428ed4 (local build, MSVC 19.44, CUDA 12.4, sm_86)
  • OS: Windows 11 x86_64
  • GPU: NVIDIA RTX 3090 Ti 24 GB
  • Target: empero-ai/Qwen3.8-27B-Ridge-GGUF Qwen3.8-27B-Ridge-3.7bpw.gguf (IQ2_M)
  • Draft: incoai/Qwen3.8-27B-DFlash2-GGUF Qwen3.8-27B-DFlash2-Q4_K_M.gguf (1,143,006,752 bytes; SHA-256 18a380efc9b7ed8d88677fc895f5c11ae170653434ee378f7348f715c14d0594)

Repro (llama-cli, 6 runs)

Baseline (--spec-type none):

llama-cli -m <target> -ngl 999 --flash-attn on -c 8192 \
  --cache-type-k q4_0 --cache-type-v q4_0 -b 256 -ub 128 -t 8 \
  --temp 0 -s 42 --no-display-prompt -no-cnv -st \
  -n 256 -f prompt_short.txt < nul

Speculative variants add:

  -md <draft> --spec-draft-ngl 999 --spec-draft-n-max 7 --spec-draft-p-min 0 \
  --spec-type draft-simple        # or draft-dflash

Run the same with -n 512 -f prompt_coding.txt. Note: --draft-model is not a valid flag in this build; use -md (cli) / --spec-draft-model (server).

Results (token-level, same-vocab llama-tokenize)

workload none vs draft-simple none vs draft-dflash
short (n=256) diverge at gen-token ~109 diverge at gen-token ~49
coding (n=512) identical 512/512 diverge at gen-token ~372

Stripped-output MD5 (static banner/prompt-echo removed; generation content only):

run short coding
none db0b78ede21fcb32543217e5cbfd437f (1330 B) 1d69d9619a1bde9249dac21e6fccaf99 (2482 B)
draft-simple c55e97dec9b537272f72dc578e1f00dc (1346 B) 1d69d9619a1bde9249dac21e6fccaf99 (2482 B) — = none
draft-dflash 25dfca084f4cec36bc8f71f5eaa8da24 (1401 B) 24d531f596c8aa41c1119ea01bd824d7 (2459 B)

Reruns are byte-identical (determinism confirmed).

Example near-tie flips (short workload): " storage of information." vs ", recall, forgetting"; ". Too many" vs "syllables. Too". Coding workload: digit flip "1, 2" vs "8, 4" in generated code.

Analysis

  • Batched verification alone (draft-simple, no DFlash hooks) perturbs CUDA target logits at near-ties: it diverges on the short workload yet is byte-identical on coding → near-tie dependent, not systematic.
  • draft-dflash diverges on both workloads and earlier: DFlash2's extraction graph (llama_set_embeddings_layer_inp graph-output marking) amplifies the numeric shift but is not the sole cause (proven by the draft-simple divergence).
  • Deterministic across reruns → consistent with CUDA fp-non-associativity in the batched verification decode (e.g. n_max=7 draft batch in one flash-attn batch vs sequential target decode) and/or graph-extraction side effects.
  • Supporting data point: z-lab's Metal validation of DFlash2 achieved byte-identical greedy output (see dflash: zero-fill draft-cache holes left by mtmd chunks and reused prefixes z-lab/llama.cpp-fork#1), suggesting a platform-numeric component.

Questions

  1. Is bit-exact greedy output expected to be preserved under batched speculative verification on CUDA? (MTP presumably shows the same class of divergence.)
  2. Is there a supported way to force the sequential target-decode path during verification, for bit-exact comparisons?
  3. If this is accepted as generic numerics, it may be worth a short note in PR spec : add DFlash2 support (local convolution + candidate selector) #27342 so downstream users don't mistake it for output corruption.

Cross-links: PR #27342 (DFlash2), companion issue mtmd vision position-gap, z-lab#1 (Metal byte-identical validation).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions