palmfuture commited on
Commit
afe11e2
Β·
verified Β·
1 Parent(s): 88654f9

Add MTP weights + speculative decoding support

Browse files

- mtp.safetensors: 19 MTP tensors in per-expert split format (768 expert keys + 17 non-expert)
- model.safetensors.index.json: weight_map updated with 19 MTP keys, total_size 22.7GB
- config.json: add mlp_only_layers, modules_to_not_convert (Qwen official schema parity)
- README: document vLLM 0.19.1 + SGLang 0.5.10 MTP configs + verified perf metrics

Verified speculative decoding:
- vLLM 0.19.1 + 4Γ— RTX 3060: 56-82 t/s, 70-89% acceptance rate
- SGLang 0.5.10 EAGLE: 60-105 t/s, 36-66% acceptance

vLLM users: do NOT pass --quantization moe_wna16 (auto-detect required).

Files changed (4) hide show
  1. README.md +79 -5
  2. config.json +5 -3
  3. model.safetensors.index.json +2 -2
  4. mtp.safetensors +3 -0
README.md CHANGED
@@ -13,6 +13,8 @@ tags:
13
  - moe
14
  - qwen3.6
15
  - qwen3-5-moe
 
 
16
  library_name: transformers
17
  pipeline_tag: image-text-to-text
18
  ---
@@ -21,6 +23,8 @@ pipeline_tag: image-text-to-text
21
 
22
  GPTQ Int4 quantization of [Qwen/Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwen3.6-35B-A3B), produced on **consumer multi-GPU hardware** (4Γ— RTX 3060 12GB) using Python 3.13t free-threading.
23
 
 
 
24
  ## Quality
25
 
26
  | Metric | Value |
@@ -31,6 +35,7 @@ GPTQ Int4 quantization of [Qwen/Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwe
31
  | Loss median | 9.29e-05 |
32
  | Loss max | 2.14e-03 |
33
  | Total modules | 30,720 |
 
34
 
35
  ## Model specs
36
 
@@ -42,8 +47,9 @@ GPTQ Int4 quantization of [Qwen/Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwe
42
  | Hidden layers | 40 |
43
  | Context length | 262,144 tokens |
44
  | Quantization | GPTQ v2, 4-bit, group_size=128, symmetric |
45
- | Quantized size | 21.2 GB (68.4% reduction from bf16) |
46
  | KV cache support | fp16, bf16, fp8_e4m3 (storage-only on Ampere) |
 
47
 
48
  ### What's quantized vs kept bf16
49
 
@@ -53,7 +59,7 @@ GPTQ Int4 quantization of [Qwen/Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwe
53
  - Attention layers (`*.attn.*`)
54
  - MoE routers (`*.mlp.gate`)
55
  - Shared experts (`*.shared_expert.*`)
56
- - Multi-token prediction heads (`*.mtp.*`)
57
  - Vision encoder (`*.visual.*`)
58
  - Embeddings and `lm_head`
59
 
@@ -111,16 +117,83 @@ Verified on 4Γ— RTX 3060 12GB with SGLang 0.5.10 (`max_total_num_tokens=415184`,
111
 
112
  ```bash
113
  vllm serve palmfuture/Qwen3.6-35B-A3B-GPTQ-Int4 \
114
- --quantization gptq_marlin \
115
  --tensor-parallel-size 4 \
116
- --max-model-len 131072 \
117
- --gpu-memory-utilization 0.85
 
 
 
 
 
 
118
  ```
119
 
 
 
120
  ### Transformers (single-GPU, for testing)
121
 
122
  Requires `trust_remote_code=True` for the Qwen3.5-MoE architecture.
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  ## Reproducibility
125
 
126
  The full per-module quantization log is published as [`quant_log.csv`](./quant_log.csv) (1.8 MB). Each row records the layer, module, GPTQ loss (or RTN fallback marker), sample count, damping value, and wall-clock time β€” making the run fully auditable.
@@ -130,6 +203,7 @@ The full per-module quantization log is published as [`quant_log.csv`](./quant_l
130
  - **Per-layer RTN distribution.** Layers 32–39 show ~7–10% RTN rate vs ~1–3% for early layers. Consistent with MoE routing concentration in deeper layers and memory pressure late in the run.
131
  - **Cold experts.** 157 of 256 expert IDs fell back to RTN in at least one layer; 99 always got GPTQ. Top cold experts: 235, 249, 234, 197, 237. These rarely route at inference.
132
  - **Ampere-only limitations.** On RTX 3060 (SM86), fp8 KV cache is storage-only (dequantized for attention). No FP8 compute path.
 
133
 
134
  ## Credits
135
 
 
13
  - moe
14
  - qwen3.6
15
  - qwen3-5-moe
16
+ - mtp
17
+ - speculative-decoding
18
  library_name: transformers
19
  pipeline_tag: image-text-to-text
20
  ---
 
23
 
24
  GPTQ Int4 quantization of [Qwen/Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwen3.6-35B-A3B), produced on **consumer multi-GPU hardware** (4Γ— RTX 3060 12GB) using Python 3.13t free-threading.
25
 
26
+ This v2 release ships **MTP (Multi-Token Prediction) speculative decoding weights** verified working on both vLLM 0.19.1 and SGLang 0.5.10.
27
+
28
  ## Quality
29
 
30
  | Metric | Value |
 
35
  | Loss median | 9.29e-05 |
36
  | Loss max | 2.14e-03 |
37
  | Total modules | 30,720 |
38
+ | Perplexity (wikitext-2-raw-v1) | 6.1846 (~97.9% BF16 retention) |
39
 
40
  ## Model specs
41
 
 
47
  | Hidden layers | 40 |
48
  | Context length | 262,144 tokens |
49
  | Quantization | GPTQ v2, 4-bit, group_size=128, symmetric |
50
+ | Quantized size | 22.7 GB (incl. MTP weights) |
51
  | KV cache support | fp16, bf16, fp8_e4m3 (storage-only on Ampere) |
52
+ | MTP head | Included (BF16, 785 keys, split per-expert format) |
53
 
54
  ### What's quantized vs kept bf16
55
 
 
59
  - Attention layers (`*.attn.*`)
60
  - MoE routers (`*.mlp.gate`)
61
  - Shared experts (`*.shared_expert.*`)
62
+ - Multi-token prediction heads (`*.mtp.*`) β€” see [Speculative decoding](#speculative-decoding-mtp) below
63
  - Vision encoder (`*.visual.*`)
64
  - Embeddings and `lm_head`
65
 
 
117
 
118
  ```bash
119
  vllm serve palmfuture/Qwen3.6-35B-A3B-GPTQ-Int4 \
 
120
  --tensor-parallel-size 4 \
121
+ --max-model-len 200000 \
122
+ --gpu-memory-utilization 0.85 \
123
+ --kv-cache-dtype fp8 \
124
+ --dtype bfloat16 \
125
+ --reasoning-parser qwen3 \
126
+ --enable-auto-tool-choice \
127
+ --tool-call-parser qwen3_coder \
128
+ --trust-remote-code
129
  ```
130
 
131
+ > **Important:** Do **not** pass `--quantization moe_wna16` to vLLM. Let vLLM auto-detect quantization from `config.json`. Forcing the flag triggers a `KeyError: 'experts.w2_weight'` in the `Qwen3_5MoeMTP` loader path even when MTP is disabled.
132
+
133
  ### Transformers (single-GPU, for testing)
134
 
135
  Requires `trust_remote_code=True` for the Qwen3.5-MoE architecture.
136
 
137
+ ## Speculative decoding (MTP)
138
+
139
+ This release ships **MTP (Multi-Token Prediction) weights** in the per-expert split format expected by vLLM and SGLang loaders (785 MTP keys total, all BF16). Speculative decoding is verified working on both engines.
140
+
141
+ ### vLLM with MTP
142
+
143
+ ```bash
144
+ vllm serve palmfuture/Qwen3.6-35B-A3B-GPTQ-Int4 \
145
+ --tensor-parallel-size 4 \
146
+ --max-model-len 200000 \
147
+ --gpu-memory-utilization 0.85 \
148
+ --kv-cache-dtype fp8 \
149
+ --dtype bfloat16 \
150
+ --reasoning-parser qwen3 \
151
+ --enable-auto-tool-choice \
152
+ --tool-call-parser qwen3_coder \
153
+ --speculative-config '{"method": "mtp", "num_speculative_tokens": 2}' \
154
+ --trust-remote-code
155
+ ```
156
+
157
+ Verified on vLLM 0.19.1 + 4Γ— RTX 3060 12GB:
158
+
159
+ | Metric | Value |
160
+ |--------|-------|
161
+ | Steady-state decode | 56–82 t/s |
162
+ | Avg draft acceptance rate | 70–89% (peak 88.9%) |
163
+ | Per-position acceptance | token 1: ~0.93, token 2: ~0.85 |
164
+ | Mean acceptance length | 2.4–2.8 / 2 draft tokens |
165
+ | KV pool | 160,800 tokens (262K max-model-len, 2.34Γ— concurrency) |
166
+
167
+ ### SGLang with MTP (EAGLE)
168
+
169
+ ```bash
170
+ SGLANG_ENABLE_SPEC_V2=1 \
171
+ SGLANG_MAMBA_CONV_DTYPE=float16 \
172
+ python -m sglang.launch_server \
173
+ --model-path palmfuture/Qwen3.6-35B-A3B-GPTQ-Int4 \
174
+ --tp-size 4 \
175
+ --dtype float16 \
176
+ --quantization moe_wna16 \
177
+ --context-length 200000 \
178
+ --mem-fraction-static 0.80 \
179
+ --mamba-scheduler-strategy extra_buffer \
180
+ --speculative-algorithm EAGLE \
181
+ --speculative-eagle-topk 1 \
182
+ --speculative-num-steps 3 \
183
+ --speculative-num-draft-tokens 4 \
184
+ --reasoning-parser qwen3 \
185
+ --tool-call-parser qwen3_coder \
186
+ --port 30000
187
+ ```
188
+
189
+ Verified on SGLang 0.5.10: 60–105 t/s decode, 36–66% acceptance.
190
+
191
+ ### Notes on MTP weight layout
192
+
193
+ This release stores MTP experts in **per-expert split format** (`mtp.layers.0.mlp.experts.{i}.{gate,up,down}_proj.weight`, 256 experts Γ— 3 projections = 768 expert keys), matching the layout that the Qwen official `Qwen3.5-35B-A3B-GPTQ-Int4` checkpoint and the upstream vLLM/SGLang MTP loaders expect.
194
+
195
+ The Qwen3.6 BF16 base model stores these as **fused 3D tensors** (`gate_up_proj` shape `[E, 2I, H]`, `down_proj` shape `[E, H, I]`). They are split bit-for-bit during release packaging β€” there is no quantization or numerical transformation of the MTP head, only a tensor reshape.
196
+
197
  ## Reproducibility
198
 
199
  The full per-module quantization log is published as [`quant_log.csv`](./quant_log.csv) (1.8 MB). Each row records the layer, module, GPTQ loss (or RTN fallback marker), sample count, damping value, and wall-clock time β€” making the run fully auditable.
 
203
  - **Per-layer RTN distribution.** Layers 32–39 show ~7–10% RTN rate vs ~1–3% for early layers. Consistent with MoE routing concentration in deeper layers and memory pressure late in the run.
204
  - **Cold experts.** 157 of 256 expert IDs fell back to RTN in at least one layer; 99 always got GPTQ. Top cold experts: 235, 249, 234, 197, 237. These rarely route at inference.
205
  - **Ampere-only limitations.** On RTX 3060 (SM86), fp8 KV cache is storage-only (dequantized for attention). No FP8 compute path.
206
+ - **vLLM `--quantization` flag.** Do not pass `--quantization moe_wna16` to vLLM β€” it triggers a `KeyError` in the MTP loader path. SGLang requires the flag; vLLM must auto-detect.
207
 
208
  ## Credits
209
 
config.json CHANGED
@@ -56,7 +56,8 @@
56
  "method": "gptq",
57
  "pack_dtype": "int32",
58
  "quant_method": "gptq",
59
- "sym": true
 
60
  },
61
  "rope_parameters": {
62
  "rope_theta": 10000.0,
@@ -151,7 +152,8 @@
151
  "shared_expert_intermediate_size": 512,
152
  "tie_word_embeddings": false,
153
  "use_cache": true,
154
- "vocab_size": 248320
 
155
  },
156
  "tie_word_embeddings": false,
157
  "transformers_version": "5.5.4",
@@ -176,4 +178,4 @@
176
  },
177
  "vision_end_token_id": 248054,
178
  "vision_start_token_id": 248053
179
- }
 
56
  "method": "gptq",
57
  "pack_dtype": "int32",
58
  "quant_method": "gptq",
59
+ "sym": true,
60
+ "modules_to_not_convert": []
61
  },
62
  "rope_parameters": {
63
  "rope_theta": 10000.0,
 
152
  "shared_expert_intermediate_size": 512,
153
  "tie_word_embeddings": false,
154
  "use_cache": true,
155
+ "vocab_size": 248320,
156
+ "mlp_only_layers": []
157
  },
158
  "tie_word_embeddings": false,
159
  "transformers_version": "5.5.4",
 
178
  },
179
  "vision_end_token_id": 248054,
180
  "vision_start_token_id": 248053
181
+ }
model.safetensors.index.json CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:483170bd31d6eebd8e322b1742dfe0435791105bff74846a8f158201037b1f56
3
- size 13071821
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:06334b7b33fc689c769c71f5ad278423aa92c09f0bcd28d9249b88d21e971215
3
+ size 13127327
mtp.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e6c8f36002c1db3906a771f613a7295486402f5c39e782df1607f01bce5f2e3f
3
+ size 1689376064