dflash: load and apply DSpark log-SNR conditioning - #123
Conversation
Drafters exported with the GIDD bundle carry log_snr_fc1 and log_snr_fc2, four tensors in all, and set log_snr_conditioning, min_log_snr and max_log_snr in their metadata. This branch had no support for any of it, so the loader created four fewer tensors than the file holds and refused to load: done_getting_tensors: wrong number of tensors; expected 79, got 75 The failure names no tensor, which sent the investigation toward the Markov head before instrumentation showed the head loads fine and the shortfall is these four. Ignoring the tensors instead would be worse than refusing to load. The metadata flag means the drafter was trained with this conditioning, so dropping it would silently change the draft embedding on every forward pass. Ported from the closed prism-v6 work: - three metadata keys, two tensor kinds, the hparams and the four model tensors - llm_graph_input_dspark_logsnr, which stages the sinusoidal feature matrix. The per-position pattern (each block's anchor at max_log_snr, mask positions at min_log_snr) and its featurization are a pure function of values known at graph-build time, so the host precomputes the [128, n_tokens] matrix once. That keeps it line-for-line auditable against the training reference rather than chaining arange/sin/cos in-graph. - the two-layer SiLU MLP added to the draft noise embedding before the layer loop Required, not optional: when the flag is set the four tensors must be present, and min/max must be finite with max greater than min, because a zero span would fill the conditioning input with NaNs rather than fail. The DSV4 hyper-connection backbone replicates the embedding across hc lanes, so the term would have to be added per lane. No such checkpoint exists yet, so that path asserts instead of silently dropping the input. Measured on Metal with a block-4 drafter that sets the flag: the drafter now loads, and drafts at 65.891% acceptance, mean accepted length 3.58. Before this it could not be loaded at all.
khosravipasha
left a comment
There was a problem hiding this comment.
This looks clean merging first.
There was a problem hiding this comment.
Pull request overview
Adds DSpark log-SNR conditioning so GIDD-bundle drafters load and apply their trained conditioning.
Changes:
- Adds GGUF metadata and tensor definitions.
- Validates and loads conditioning parameters and weights.
- Applies the sinusoidal two-layer conditioning MLP in DFlash graphs.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/models/dflash.cpp |
Loads, validates, and applies conditioning. |
src/llama-model.h |
Stores conditioning tensors. |
src/llama-hparams.h |
Stores conditioning metadata. |
src/llama-graph.h |
Defines the graph input. |
src/llama-graph.cpp |
Uploads precomputed features. |
src/llama-arch.h |
Adds metadata and tensor enums. |
src/llama-arch.cpp |
Registers metadata and tensor names. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| llm_graph_input_dspark_logsnr(std::vector<float> feat) : v_feat(std::move(feat)) {} | ||
| virtual ~llm_graph_input_dspark_logsnr() = default; | ||
|
|
||
| void set_input(const llama_ubatch * ubatch) override; |
There was a problem hiding this comment.
Good catch, and this one was a real regression rather than a style point. Fixed in 9ed9b9b.
You are right that allow_reuse already compares n_tokens and n_seqs_unq, which together with min/max_log_snr (fixed per model) are everything v_feat depends on, so the input can opt in. can_reuse now returns true when the staged tensor still matches n_tokens, following the same shape as llm_graph_input_embd::can_reuse.
Re-ran the drafter afterwards to confirm nothing moved: acceptance 65.891%, mean length 3.58, identical to before.
Re-lands the DSpark log-SNR conditioning from the closed prism-v6 work, which is what currently makes GIDD-bundle drafters unloadable on this branch.
The symptom
The message names no tensor, which is misleading. The file has 79 tensors and the loader creates 75, and the natural first guess is the DSpark Markov head, since that is the one optional block in
load_arch_tensors. It is not: instrumenting the loader showsmarkov_w1.weightis found and the head's four tensors are created normally.The four that are never created are
log_snr_fc1.weight,log_snr_fc1.bias,log_snr_fc2.weightandlog_snr_fc2.bias. This branch has no log-SNR support at all, so nothing ever claims them, anddone_getting_tensorsrefuses the load.Why not just skip them
The drafter's metadata sets
log_snr_conditioning = truealong withmin_log_snrandmax_log_snr. That means it was trained with the conditioning, so the weights are part of the function. Marking the tensors optional would let the model load and quietly compute a different draft embedding on every forward pass. A load failure is the better of the two, which is why this ports the feature rather than relaxing the check.What this adds
llm_graph_input_dspark_logsnr, which stages the sinusoidal feature matrix. The per-position log-SNR pattern (each block's anchor atmax_log_snr, mask positions atmin_log_snr) and its featurization are a pure function of values known at graph-build time, so the host precomputes the whole[128, n_tokens]matrix once. That keeps it auditable line-for-line against the training reference instead of chainingarange/sin/cosin-graph.The weights are required when the flag is set, and
min/maxmust be finite withmax > min, because a zero span divides through the featurizer and fills the conditioning input with NaNs rather than failing.The DSV4 hyper-connection backbone replicates the embedding across
hclanes, so the term would need adding per lane. No checkpoint exercises that combination yet, so that path asserts rather than silently dropping a trained input.Validation
Measured on Metal with a block-4 drafter that sets the flag, against a low-bit target:
The same numbers come out with this branch alone, and with this branch plus the layout auto-detect in the sibling PR, on both the correct and the deliberately wrong
--spec-type. That last case matters because the auto-detect could not be exercised on this branch at all before this change, since no DSpark drafter would load.Not covered: CUDA. This is graph and loader code with no backend-specific paths, and it builds clean, but every number above is Metal.