Add DSpark drafter for Inkling-Small-NVFP4 + acceptance eval
Browse files- .gitattributes +1 -0
- README.md +84 -0
- acceptance_by_position.png +3 -0
- acceptance_eval.csv +10 -0
- config.json +85 -0
- config.py +67 -0
- model.safetensors +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
acceptance_by_position.png filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
library_name: speculators
|
| 3 |
+
tags:
|
| 4 |
+
- speculative-decoding
|
| 5 |
+
- dspark
|
| 6 |
+
- draft-model
|
| 7 |
+
- vllm
|
| 8 |
+
base_model: thinkingmachines/Inkling-Small-NVFP4
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# DSpark drafter for Inkling-Small-NVFP4
|
| 12 |
+
|
| 13 |
+
A [DSpark](https://github.com/neuralmagic/speculators) speculative-decoding drafter
|
| 14 |
+
trained for the verifier
|
| 15 |
+
[`thinkingmachines/Inkling-Small-NVFP4`](https://huggingface.co/thinkingmachines/Inkling-Small-NVFP4)
|
| 16 |
+
(multimodal MoE, NVFP4). DSpark drafts a whole block in one parallel pass
|
| 17 |
+
(DFlash-style backbone) and injects intra-block dependency with a lightweight
|
| 18 |
+
sequential Markov head, plus a per-position confidence head.
|
| 19 |
+
|
| 20 |
+
## Model details
|
| 21 |
+
|
| 22 |
+
| | |
|
| 23 |
+
|---|---|
|
| 24 |
+
| Algorithm | DSpark (greedy proposal) |
|
| 25 |
+
| Verifier | `thinkingmachines/Inkling-Small-NVFP4` |
|
| 26 |
+
| Backbone layers | 6 |
|
| 27 |
+
| Hidden size | 4096 |
|
| 28 |
+
| Attention heads / KV heads | 32 / 8 |
|
| 29 |
+
| Draft vocab size | 201024 (full padded vocab) |
|
| 30 |
+
| Block size | 16 |
|
| 31 |
+
| Markov rank | 256 (vanilla) |
|
| 32 |
+
| Confidence head | enabled (with Markov) |
|
| 33 |
+
| Aux hidden-state layers | 2, 10, 18, 26, 34, 39 |
|
| 34 |
+
| dtype | bfloat16 |
|
| 35 |
+
|
| 36 |
+
## Acceptance evaluation
|
| 37 |
+
|
| 38 |
+
Inference acceptance measured with vLLM spec-decode over 9 task subsets
|
| 39 |
+
(~300k drafts total). **Mean acceptance length (AL)** = expected number of
|
| 40 |
+
tokens accepted per draft step (higher is better; block size 16).
|
| 41 |
+
|
| 42 |
+
| Subset | Acceptance length | pos-0 accept |
|
| 43 |
+
|---|---|---|
|
| 44 |
+
| math_reasoning | **4.55** | 0.776 |
|
| 45 |
+
| HumanEval | **3.90** | 0.740 |
|
| 46 |
+
| rag | 3.73 | 0.736 |
|
| 47 |
+
| translation | 3.56 | 0.736 |
|
| 48 |
+
| summarization | 3.40 | 0.731 |
|
| 49 |
+
| tool_call | 3.20 | 0.707 |
|
| 50 |
+
| writing | 3.11 | 0.679 |
|
| 51 |
+
| qa | 3.10 | 0.684 |
|
| 52 |
+
| question | 3.09 | 0.679 |
|
| 53 |
+
|
| 54 |
+
**Weighted mean acceptance length ≈ 3.40** across all subsets.
|
| 55 |
+
|
| 56 |
+
Per-position acceptance rate by subset:
|
| 57 |
+
|
| 58 |
+

|
| 59 |
+
|
| 60 |
+
Full per-position numbers are in [`acceptance_eval.csv`](./acceptance_eval.csv).
|
| 61 |
+
|
| 62 |
+
## Usage (vLLM)
|
| 63 |
+
|
| 64 |
+
Serve the verifier with this drafter as the speculative model:
|
| 65 |
+
|
| 66 |
+
```bash
|
| 67 |
+
vllm serve thinkingmachines/Inkling-Small-NVFP4 \
|
| 68 |
+
--speculative-config '{"model": "<this-repo>", "num_speculative_tokens": 16}' \
|
| 69 |
+
--enforce-eager \
|
| 70 |
+
--trust-remote-code
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
> **Note:** Inkling currently requires `--enforce-eager` (CUDA-graph capture of
|
| 74 |
+
> the custom ops crashes). The drafter uses the full padded vocab (draft
|
| 75 |
+
> `vocab_size` 201024 vs. the verifier's logical 200058); loading it in vLLM
|
| 76 |
+
> needs [vllm-project/vllm#55133](https://github.com/vllm-project/vllm/pull/55133),
|
| 77 |
+
> which treats a padded/full-vocab draft as an identity map (no `d2t` required).
|
| 78 |
+
|
| 79 |
+
## Training
|
| 80 |
+
|
| 81 |
+
Trained with [speculators](https://github.com/neuralmagic/speculators) for 3
|
| 82 |
+
epochs (`checkpoint_best` = best validation epoch). Validation at the selected
|
| 83 |
+
checkpoint: accept_len 3.67, accept_rate 0.40, pos-0 acc 0.776. Loss
|
| 84 |
+
`{"ce": 0.1, "tv": 0.9}`, lr 1e-4, seq len 8192, block size 16.
|
acceptance_by_position.png
ADDED
|
Git LFS Details
|
acceptance_eval.csv
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
subset,num_drafts,num_draft_tokens,num_accepted_tokens,acceptance_length,acceptance_at_pos_0,acceptance_at_pos_1,acceptance_at_pos_2,acceptance_at_pos_3,acceptance_at_pos_4,acceptance_at_pos_5,acceptance_at_pos_6,acceptance_at_pos_7,acceptance_at_pos_8,acceptance_at_pos_9,acceptance_at_pos_10,acceptance_at_pos_11,acceptance_at_pos_12,acceptance_at_pos_13,acceptance_at_pos_14,acceptance_at_pos_15
|
| 2 |
+
HumanEval,53377.0,854032.0,154985.0,3.9035914345129923,0.740487475879124,0.5334320025479139,0.38891282762238416,0.2877643929033104,0.21533619349157876,0.16514603668246622,0.12870712104464468,0.10127957734604792,0.08095247016505236,0.06463458043726698,0.05305655994154786,0.04256514978361466,0.03460291886018323,0.027895910223504506,0.021750941416715065,0.017067276167637747
|
| 3 |
+
math_reasoning,7168.0,114688.0,25469.0,4.553152901785714,0.7759486607142857,0.6106305803571429,0.4755859375,0.3755580357142857,0.2972935267857143,0.23158482142857142,0.18233816964285715,0.14104352678571427,0.11481584821428571,0.091796875,0.0712890625,0.056640625,0.04450334821428571,0.03655133928571429,0.0283203125,0.019252232142857144
|
| 4 |
+
qa,55900.0,894400.0,117644.0,3.1045438282647586,0.6840608228980322,0.4641323792486583,0.31783542039355994,0.21556350626118068,0.1460107334525939,0.0981216457960644,0.06474060822898033,0.04255813953488372,0.02745974955277281,0.017173524150268335,0.010894454382826477,0.006708407871198569,0.004114490161001789,0.002701252236135957,0.00148479427549195,0.0009838998211091235
|
| 5 |
+
question,40020.0,640320.0,83773.0,3.0932783608195904,0.6787606196901549,0.445552223888056,0.2939030484757621,0.1973263368315842,0.13555722138930534,0.09317841079460269,0.06664167916041978,0.04832583708145927,0.034907546226886556,0.026586706646676662,0.020889555222388806,0.016391804097951025,0.012693653173413293,0.009645177411294352,0.007296351824087956,0.005622188905547227
|
| 6 |
+
rag,25011.0,400176.0,68386.0,3.734236935748271,0.7355563552037103,0.536803806325217,0.3943864699532206,0.28811323017872137,0.21246651473351724,0.15561153092639238,0.11267042501299428,0.08344328495461997,0.062172644036623884,0.0477389948422694,0.034824677142057496,0.025268881692055496,0.017992083483267363,0.012594458438287154,0.008556235256487146,0.006037343568829715
|
| 7 |
+
summarization,13314.0,213024.0,31998.0,3.4033348355114916,0.7314856541985879,0.5298182364428421,0.37546943067447797,0.265209553853087,0.17823343848580442,0.11904761904761904,0.07683641279855791,0.0501727504882079,0.030118672074508038,0.01892744479495268,0.011566771819137749,0.007210455159981974,0.00405588102748986,0.0026288117770767614,0.0016523959741625357,0.0009013068949977468
|
| 8 |
+
tool_call,42535.0,680560.0,93512.0,3.1984718467144706,0.707299870694722,0.4844481015634184,0.32829434583284356,0.2216762666039732,0.14844245915128718,0.09991771482308687,0.06686258375455507,0.04495121664511579,0.031150816974256496,0.021958387210532504,0.015399083108028682,0.010344422240507817,0.0072410955683554715,0.005007640766427648,0.003244386975431997,0.0022334548019278242
|
| 9 |
+
translation,23167.0,370672.0,59377.0,3.5629990935382225,0.7360469633530453,0.5348556135882937,0.3816635731859973,0.26930547761902707,0.18819873095351147,0.13247291405879053,0.09353822247161911,0.06651702853196356,0.04825829844174904,0.034402382699529506,0.025424094617343636,0.01834505978331247,0.013078948504338068,0.009194112314930721,0.007122199680580136,0.004575473734190875
|
| 10 |
+
writing,38853.0,621648.0,82092.0,3.112887035750135,0.6792783054075618,0.447481532957558,0.2956528453401282,0.19774534784958692,0.1360770082104342,0.09505057524515481,0.0681800633155741,0.050189174581113424,0.03747458368723136,0.02874938872159164,0.022237665045170257,0.017012843281085117,0.01310066146758294,0.010243739222196483,0.008339124391938846,0.006074177026227061
|
config.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"DSparkDraftModel"
|
| 4 |
+
],
|
| 5 |
+
"auto_map": {
|
| 6 |
+
"": "config.DSparkSpeculatorConfig"
|
| 7 |
+
},
|
| 8 |
+
"aux_hidden_state_layer_ids": [
|
| 9 |
+
2,
|
| 10 |
+
10,
|
| 11 |
+
18,
|
| 12 |
+
26,
|
| 13 |
+
34,
|
| 14 |
+
39
|
| 15 |
+
],
|
| 16 |
+
"block_size": 16,
|
| 17 |
+
"confidence_head_with_markov": true,
|
| 18 |
+
"draft_vocab_size": 201024,
|
| 19 |
+
"dtype": "bfloat16",
|
| 20 |
+
"enable_confidence_head": true,
|
| 21 |
+
"markov_head_type": "vanilla",
|
| 22 |
+
"markov_rank": 256,
|
| 23 |
+
"mask_token_id": 200058,
|
| 24 |
+
"sample_from_anchor": true,
|
| 25 |
+
"sliding_window_non_causal": false,
|
| 26 |
+
"speculators_config": {
|
| 27 |
+
"algorithm": "dspark",
|
| 28 |
+
"default_proposal_method": "greedy",
|
| 29 |
+
"proposal_methods": [
|
| 30 |
+
{
|
| 31 |
+
"accept_tolerance": 0.0,
|
| 32 |
+
"proposal_type": "greedy",
|
| 33 |
+
"speculative_tokens": 16,
|
| 34 |
+
"verifier_accept_k": 1
|
| 35 |
+
}
|
| 36 |
+
],
|
| 37 |
+
"verifier": {
|
| 38 |
+
"architectures": [
|
| 39 |
+
"InklingForConditionalGeneration"
|
| 40 |
+
],
|
| 41 |
+
"name_or_path": "thinkingmachines/Inkling-Small-NVFP4"
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"speculators_model_type": "dspark",
|
| 45 |
+
"speculators_version": "0.7.0.dev155",
|
| 46 |
+
"target_hidden_size": null,
|
| 47 |
+
"tie_word_embeddings": false,
|
| 48 |
+
"transformer_layer_config": {
|
| 49 |
+
"attention_bias": false,
|
| 50 |
+
"attention_dropout": 0.0,
|
| 51 |
+
"bos_token_id": null,
|
| 52 |
+
"eos_token_id": null,
|
| 53 |
+
"head_dim": 128,
|
| 54 |
+
"hidden_act": "silu",
|
| 55 |
+
"hidden_size": 4096,
|
| 56 |
+
"initializer_range": 0.02,
|
| 57 |
+
"intermediate_size": 16384,
|
| 58 |
+
"layer_types": [
|
| 59 |
+
"sliding_attention",
|
| 60 |
+
"sliding_attention",
|
| 61 |
+
"sliding_attention",
|
| 62 |
+
"sliding_attention",
|
| 63 |
+
"sliding_attention",
|
| 64 |
+
"sliding_attention"
|
| 65 |
+
],
|
| 66 |
+
"max_position_embeddings": 1048576,
|
| 67 |
+
"max_window_layers": 28,
|
| 68 |
+
"model_type": "qwen3",
|
| 69 |
+
"num_attention_heads": 32,
|
| 70 |
+
"num_hidden_layers": 6,
|
| 71 |
+
"num_key_value_heads": 8,
|
| 72 |
+
"pad_token_id": null,
|
| 73 |
+
"rms_norm_eps": 1e-06,
|
| 74 |
+
"rope_parameters": {
|
| 75 |
+
"rope_theta": 10000.0,
|
| 76 |
+
"rope_type": "default"
|
| 77 |
+
},
|
| 78 |
+
"sliding_window": 2048,
|
| 79 |
+
"tie_word_embeddings": false,
|
| 80 |
+
"use_cache": true,
|
| 81 |
+
"use_sliding_window": true,
|
| 82 |
+
"vocab_size": 201024
|
| 83 |
+
},
|
| 84 |
+
"transformers_version": "5.15.0"
|
| 85 |
+
}
|
config.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Literal
|
| 2 |
+
|
| 3 |
+
from pydantic import Field
|
| 4 |
+
|
| 5 |
+
from speculators import SpeculatorModelConfig
|
| 6 |
+
from speculators.models.dflash.config import DFlashSpeculatorConfig
|
| 7 |
+
|
| 8 |
+
__all__ = [
|
| 9 |
+
"DSparkSpeculatorConfig",
|
| 10 |
+
]
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
@SpeculatorModelConfig.register("dspark")
|
| 14 |
+
class DSparkSpeculatorConfig(DFlashSpeculatorConfig):
|
| 15 |
+
"""DFlash config plus a Markov logit-bias head and a confidence head.
|
| 16 |
+
|
| 17 |
+
The Markov head lets each draft position condition on previously sampled
|
| 18 |
+
tokens within the block; the confidence head predicts the per-position
|
| 19 |
+
acceptance probability. All DFlash fields are inherited unchanged.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
speculators_model_type: Literal["dspark"] = "dspark" # type: ignore[assignment]
|
| 23 |
+
architectures: list[str] = Field(
|
| 24 |
+
default_factory=lambda: ["DSparkSpeculator"],
|
| 25 |
+
description="Model architectures that can load these weights",
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
sample_from_anchor: bool = Field(
|
| 29 |
+
default=True,
|
| 30 |
+
description=(
|
| 31 |
+
"Whether to sample from the anchor position. "
|
| 32 |
+
"False: anchor is the bonus token, only mask tokens predict "
|
| 33 |
+
"(block_size-1 speculative tokens). "
|
| 34 |
+
"True: sample from anchor and all mask positions "
|
| 35 |
+
"(block_size speculative tokens). "
|
| 36 |
+
"Default True matches DeepSeek/DeepSpec convention."
|
| 37 |
+
),
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
# Sequential (Markov) head.
|
| 41 |
+
markov_rank: int = Field(
|
| 42 |
+
default=256,
|
| 43 |
+
description=(
|
| 44 |
+
"Low-rank dimension of the Markov logit-bias factorization B = W1 @ W2. "
|
| 45 |
+
"Set to 0 to disable the sequential head (pure DFlash drafting)."
|
| 46 |
+
),
|
| 47 |
+
)
|
| 48 |
+
markov_head_type: Literal["vanilla", "gated", "rnn"] = Field(
|
| 49 |
+
default="vanilla",
|
| 50 |
+
description=(
|
| 51 |
+
"Sequential head variant: 'vanilla' (first-order Markov bias), 'gated' "
|
| 52 |
+
"(hidden-gated bias), or 'rnn' (recurrent state over the block)."
|
| 53 |
+
),
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
# Confidence head.
|
| 57 |
+
enable_confidence_head: bool = Field(
|
| 58 |
+
default=True,
|
| 59 |
+
description="Whether to attach the per-position acceptance-probability head.",
|
| 60 |
+
)
|
| 61 |
+
confidence_head_with_markov: bool = Field(
|
| 62 |
+
default=True,
|
| 63 |
+
description=(
|
| 64 |
+
"Concatenate the Markov previous-token embedding with the backbone "
|
| 65 |
+
"hidden state as the confidence-head input."
|
| 66 |
+
),
|
| 67 |
+
)
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7f452ea94a09757cece52e723abf058ce0210e90f479a39231f95d81e19a3e5a
|
| 3 |
+
size 6620122506
|