olka-fi commited on
Commit
c67eada
·
verified ·
1 Parent(s): 453cca0

NVFP4 (weight-only, mixed precision) quantization of inclusionAI/Ling-3.0-flash via qstream

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ 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
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
37
+ model.safetensors.index.json filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ pipeline_tag: text-generation
4
+ library_name: transformers
5
+ base_model: inclusionAI/Ling-3.0-flash
6
+ base_model_relation: quantized
7
+ tags:
8
+ - moe
9
+ - nvfp4
10
+ - compressed-tensors
11
+ - quantized
12
+ - vllm
13
+ - hybrid-linear-attention
14
+ ---
15
+
16
+ # Ling-3.0-flash — NVFP4 (weight-only, mixed precision)
17
+
18
+ A 4-bit **NVFP4** quantization of [Ling-3.0-flash](https://huggingface.co/inclusionAI/Ling-3.0-flash),
19
+ produced with [**qstream**](https://github.com/olka/qstream). The routed MoE experts
20
+ (~95% of the weights) are quantized to NVFP4; everything quality-sensitive stays **BF16**.
21
+
22
+ **The original model card follows in full [below](#original-model-card).**
23
+
24
+ > ### ⚠️ Speculative decoding (MTP) is broken on this checkpoint — do not enable it
25
+ >
26
+ > Measured **0% acceptance across 89,832 draft tokens** (29,944 draft steps, zero accepted
27
+ > at every draft position). MTP is not merely inefficient here, it contributes nothing
28
+ > while costing a redundant full-checkpoint read at startup, ~6 GB of VRAM for the BF16
29
+ > MTP head, and three wasted draft forwards per decode step. It additionally crashes CUDA
30
+ > graph capture (`gdn_attn.py` → `CUDA error: invalid argument`), forcing `--enforce-eager`
31
+ > and giving up decode throughput.
32
+ >
33
+ > **Serve without `--speculative-config`.** Without a draft model, graph capture succeeds
34
+ > and everything behaves normally. The MTP layer is still shipped at BF16 so the head is
35
+ > intact for whenever the runtime issue is fixed upstream. See
36
+ > [Known issues](#known-issues).
37
+
38
+ | | |
39
+ |---|---|
40
+ | **Size** | **81.4 GB** (down from 255.0 GB BF16 source, ~32%) |
41
+ | **Format** | compressed-tensors `nvfp4-pack-quantized` (E2M1 4-bit + FP8-E4M3 group-16 scales + per-tensor global scale) |
42
+ | **Base** | Ling-3.0-flash — 124B total / 5.1B active hybrid-linear MoE; 42 layers stacked 5:1 as 35 Kimi-Delta-Attention (KDA) + 7 gated-MLA; 512 routed experts top-8 + 1 shared; 2 dense layers; 1 MTP layer; 256K context |
43
+
44
+ ## Which build should you use?
45
+
46
+ **Most people should take the [MXFP4 build](https://huggingface.co/olka-fi/Ling-3.0-flash-MXFP4) instead.**
47
+ NVFP4 reconstructs the weights substantially more faithfully, and that advantage does not
48
+ show up downstream:
49
+
50
+ | | [MXFP4](https://huggingface.co/olka-fi/Ling-3.0-flash-MXFP4) | NVFP4 (this repo) |
51
+ |---|---|---|
52
+ | Size | **77.6 GB** | 81.4 GB |
53
+ | Median weight rel. error | 0.111618 | **0.086498** (−22.5%) |
54
+ | GSM8K 5-shot, full 1319, flexible-extract | **84.38%** ±1.00 | 83.17% ±1.03 |
55
+ | GSM8K 5-shot, full 1319, strict-match | **78.85%** ±1.12 | 78.39% ±1.13 |
56
+
57
+ Both GSM8K gaps are under 1.2σ — the two builds are statistically indistinguishable on
58
+ this benchmark despite NVFP4's much lower weight error. At this magnitude, 4-bit
59
+ reconstruction error is already below what GSM8K can resolve. NVFP4 is published for
60
+ comparison and for anyone wanting the more faithful weights (e.g. for longer-generation
61
+ or harder tasks where the difference may still surface); MXFP4 is the smaller, better-
62
+ tested release.
63
+
64
+ ## What is quantized to what
65
+
66
+ | Component | Precision | Why |
67
+ |---|---|---|
68
+ | Routed experts, layers 2–41 (`model.layers.N.mlp.experts.E.{gate,up,down}_proj`) | **NVFP4** (4-bit) | 120.8B of 127.4B params — the only place worth the size win |
69
+ | Shared expert (`mlp.shared_experts.*`) | **BF16** | active on *every* token; quantizing it costs ~half the quality loss for <1% of the size |
70
+ | Attention — KDA (`q/k/v/f/g/b_proj`, `conv1d`, `A_log`, `dt_bias`) and gated MLA (`kv_a/kv_b`, `dense`) | **BF16** | the KDA gating projections feed a softplus/sigmoid decay gate and are the most precision-sensitive tensors in the model |
71
+ | Router gate + `expert_bias`, dense MLP (layers 0–1) | **BF16** | routing decisions are discrete; a perturbed router changes *which* experts fire |
72
+ | MTP layer 42 (incl. its own 512 experts) | **BF16** | speculative-decoding draft path — see the MTP warning above |
73
+ | Embeddings, `lm_head`, all norms | **BF16** | unchanged |
74
+
75
+ 61,440 tensors quantized (40 layers × 512 experts × 3 projections), each with a packed
76
+ weight, an FP8-E4M3 group scale and a per-tensor global scale.
77
+
78
+ ## Fidelity
79
+
80
+ Weight-reconstruction relative error, 960-tensor stratified sample (24 per layer, expert
81
+ ids strided across the full 512 range, all 40 layers):
82
+
83
+ | min | p25 | median | p75 | p95 | max | std |
84
+ |---|---|---|---|---|---|---|
85
+ | 0.086332 | 0.086459 | **0.086498** | 0.086556 | 0.086652 | 0.086742 | 0.000073 |
86
+
87
+ NVFP4's *worst* sampled tensor (0.0867) is better than MXFP4's *best* (0.1099) — the two
88
+ distributions are disjoint. Two effects compound: group 16 rather than 32 halves how many
89
+ weights share a scale, and FP8-E4M3 scales are continuous where MXFP4's E8M0 scales are
90
+ powers of two, so an MXFP4 block whose ideal scale falls between 2^k and 2^(k+1) must
91
+ round and waste up to 2× of range.
92
+
93
+ ## Known issues
94
+
95
+ 1. **MTP / speculative decoding: 0% acceptance** — see the warning above. Serve without
96
+ `--speculative-config`.
97
+ 2. **MTP also breaks CUDA graph capture** (`gdn_attn.py:382` → `CUDA error: invalid
98
+ argument`). Without a draft model, capture succeeds and `--enforce-eager` is not needed.
99
+ 3. **The MTP draft loader re-reads the entire checkpoint** to extract one layer — two
100
+ full weight-loading passes of near-identical duration at startup. Costs I/O, not VRAM.
101
+ 4. **NVFP4 needs qstream ≥ the `_prune_ignore` fix.** Earlier qstream generalised `ignore`
102
+ entries by layer index, so excluding the MTP layer emitted
103
+ `re:.*layers\.\d+\.mlp\.experts\.\d+\.gate_proj$` — which also ignored the *quantized*
104
+ experts in all 40 other layers. vLLM checks `should_ignore_layer` before target
105
+ matching, so every expert silently resolved to unquantized and the loader tried to
106
+ allocate BF16 buffers for ~242 GB of weights (OOM with no useful error). The
107
+ `config.json` in this repo is already correct.
108
+
109
+ ## Serving with vLLM
110
+
111
+ Ling-3.0 (`BailingMoeV3ForCausalLM`, `model_type: bailing_hybrid`) needs the vendor fork
112
+ **[`inclusionAI/vllm`](https://github.com/inclusionAI/vllm), branch `ling_3_0`**. (The base
113
+ model card points at `inclusionAI/vllm-ling-v3`, which does not exist.) Upstream vLLM has
114
+ only BailingMoe / V2 / V2.5.
115
+
116
+ ### Required: the MoE clamp patch
117
+
118
+ Ling-3.0 declares a **per-layer clamped SwiGLU** (`expert_swiglu_limit_list = [0]*35 + [4]*7`,
119
+ so layers 35–41 clamp at 4). vLLM's compressed-tensors MXFP4/NVFP4 MoE path **drops that
120
+ clamp**: the quant method never reads `layer.swiglu_limit`, the quant-config builder has no
121
+ parameter to receive it, and `run_cutlass_moe_mxfp4` calls `apply_moe_activation()` with no
122
+ clamp argument. The result is unclamped SwiGLU on layers 35–41 — the divergence is large,
123
+ not marginal (gate=10 gives `silu(10)*2 = 20.0` versus `silu(4)*2 = 7.84`).
124
+
125
+ Apply the three files in [`vllm_patch/`](./vllm_patch/) over the fork before serving; they
126
+ are pure Python, so an editable install needs no rebuild. See
127
+ [`vllm_patch/README.md`](./vllm_patch/README.md).
128
+
129
+ ### Launch (Docker)
130
+
131
+ A prebuilt runtime image with the fork, the clamp patch and `flashinfer-jit-cache`:
132
+
133
+ ```bash
134
+ docker run --gpus all -d --name ling3 --ipc=host -p 8000:8000 \
135
+ -v /path/to/Ling-3.0-flash-NVFP4:/models/Ling-3.0-flash-NVFP4:ro \
136
+ olkafi/vllm-bailing-v3:latest \
137
+ /models/Ling-3.0-flash-NVFP4 \
138
+ --served-model-name ling3 --trust-remote-code \
139
+ --host 0.0.0.0 --port 8000 \
140
+ --gpu-memory-utilization 0.85 --max-model-len 32768 \
141
+ --enable-prefix-caching --mamba-cache-mode align \
142
+ --load-format fastsafetensors \
143
+ --enable-auto-tool-choice --tool-call-parser ling3 --reasoning-parser ling3
144
+ ```
145
+
146
+ `--enable-prefix-caching` is **required** for `--mamba-cache-mode align` to take effect —
147
+ without it vLLM silently downgrades the KDA linear-attention state cache to `none` and
148
+ only logs a warning. Note the deliberate absence of `--speculative-config`.
149
+
150
+ Recommended sampling (from the base card): `temperature=0.6`, `top_p=0.95`, `top_k=20`,
151
+ with `enable_thinking`.
152
+
153
+ ## Provenance
154
+
155
+ Built with [qstream](https://github.com/olka/qstream) from the BF16
156
+ `inclusionAI/Ling-3.0-flash` release:
157
+
158
+ ```bash
159
+ qstream-quantize \
160
+ --model_dir Ling-3.0-flash \
161
+ --output_dir Ling-3.0-flash-NVFP4 \
162
+ --quant_format nvfp4 --nvfp4_mse --format ct \
163
+ --include_layers '*.mlp.experts.*' \
164
+ --exclude_layers '*.layers.42.*' \
165
+ --workers 8 --device cuda
166
+ ```
167
+
168
+ `--nvfp4_mse` searches neighbouring E4M3 group scales and keeps the minimum-reconstruction-
169
+ error one, with γ-weighted activation awareness from `post_attention_layernorm`.
170
+
171
+ ## Evaluation notes
172
+
173
+ GSM8K figures above are 5-shot over the full 1319-problem test set via `/v1/completions`
174
+ with plain few-shot prompting — a **non-thinking** protocol. They are not comparable to the
175
+ base model's published scores, which are generated with thinking mode + CoT. They exist to
176
+ bound quantization damage, not as leaderboard claims.
177
+
178
+ ## License
179
+
180
+ Inherits the **MIT** license from the base model. This is a derivative (quantized) work of
181
+ inclusionAI/Ling-3.0-flash.
182
+
183
+ ---
184
+
185
+ # Original model card
186
+
187
+ <p align="center">
188
+ <img src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*4QxcQrBlTiAAAAAAQXAAAAgAemJ7AQ/original" width="100"/>
189
+ </p>
190
+ <p align="center">🤗 <a href="https://huggingface.co/inclusionAI">Hugging Face</a>&nbsp;&nbsp; | &nbsp;&nbsp;🤖 <a href="https://modelscope.cn/organization/inclusionAI">ModelScope </a>&nbsp;&nbsp; | &nbsp;&nbsp;🐙 <a href="https://openrouter.ai/inclusionai/ling-3.0-flash:free">OpenRouter </a>&nbsp;&nbsp;</p>
191
+
192
+ ## <font style="color:rgba(0, 0, 0, 0.88);">Introduction</font>
193
+ We're introducing Ling-3.0-flash, our next-generation native hybrid reasoning model. Operating with **124B** total and **5.1B** active parameters (~12.4% and ~8.1% of our previous 1T-class flagship Ring-2.6-1T), Ling-3.0-flash matches or outperforms its predecessor across key benchmarks.
194
+
195
+ <font style="color:rgb(16, 18, 20);">Key highlights of the model are summarized below:</font>
196
+
197
+ + **Native Hybrid-Linear Architecture:** Ling-3.0 adopts a native hybrid linear attention architecture from the very start of pretraining (5:1 alternating stacking of Kimi Delta Attention (KDA) and MLA), upgraded with KDA fine-grained diagonal gating and 1/64 sparse MoE. With 124B total parameters and 5.1B activated parameters, it achieves a synergistic leap in long-context efficiency and computational cost.
198
+ + **Remarkable Efficiency & Performance:** Engineered for speed, compute efficiency, and production deployment, Ling-3.0-flash delivers class-defying performance against both larger SOTA competitors and previous-generation flagships. Activating only 5.1B parameters per token, it provides impressive reasoning, instruction following, and long-context capabilities to empower complex agentic workflows in production environments.
199
+ + **Comprehensive Agentic Evolution:** Tailored for real-world productivity workflows, the model incorporates 10,000+ interactive training environments to achieve end-to-end closed-loop execution across Coding, General, and Deep Research Agent tasks. It natively integrates the SGLang HiCache + Mooncake hierarchical caching architecture (featuring physical dual-pools and a cluster-shared L3 cache), eliminating redundant recomputation during long-horizon interactions and reducing Time to First Token (TTFT) by 60% to over 80% in long-input scenarios.s the SGLang HiCache + Mooncake hierarchical caching architecture (featuring physical dual-pools and a cluster-shared L3 cache), eliminating redundant recomputation during long-horizon interactions and reducing Time to First Token (TTFT) by 60% to over 80% in long-input scenarios.
200
+
201
+ <!-- 这是一张图片,ocr 内容为:SWE-BENCH MULTILINGUAL TERMINAL-BENCH 2.1 SWE-BENCHPRO TAU3-BANKING-AA LL088000LL 65 6 71.2 76.5 75.9 AP 28.0 60 0 72.4 73.3 56.6 56.2 56.3 71.0 53.9 70 22.9 55 57.0 50 47.9 48.3 60 56.7 14.6 45 11.3 71.3 39.3 39.0 70.1 50 8.9 40 42.7 40 34.1 35 30 30 WIDESEARCH MCP-ATLAS SKILLSBENCH BROWSECOMP 品质88品质品等学导新品 品民品品导品只只口 豆豆复品品导导导 品品&品品定品名品 6 4 79.5 米 0 75.2 73.6 74.4 70.2 69.0 82.0 66.7 6 65.5 62.2 53.5 75.8 61.2 73.2 71.7 74.0 55.2 53.6 52.6 49.4 G 20.3 19.5 71.9 31.3 MULTI-AGENT IFBENCH SYSBENCH MRCR-256K MULTI-IF 100 雪饼 110 110 87.7 89.3 79.2 06 82.9 84.6 86.2 84.6 84.8 75.7 82.3 93.6 91.4 93.9 90793.3949 72.6 84.3 90 品8888元 81.1 86.5 86.2 69.0 70 67.3 70 60 56.6 05 30 0 30 10 ULIO RING-2.6-1T(XHIGH) STEP-3.7-FLASH(HIGH) LING-3.0-FLASH MINIMAX-M2.7 WALBAN DEEPSEEK-V4-FLASH-PREVIEW(MAX) CLAUDE-SONNET-4.6(MAX) GPT-5.4-MINI(HIGH) NEMOTRON-3-SUPER-120B-A12B NOTE:THINKING MODE IS ENABLED BY DEFAULT. -->
202
+ ![](https://intranetproxy.alipay.com/skylark/lark/0/2026/png/23157180/1785831264180-d6ca4404-acef-4424-84db-fbc5a4c6db5f.png)
203
+
204
+ ## Model Overview
205
+ The model summary information and architecture diagram are as follows:
206
+
207
+ | Architecture | Hybrid-linear MoE |
208
+ | --- | --- |
209
+ | Parameter Scale | Totoal 124B, Activated 5.1B |
210
+ | Transformer Layers | 35 KDA + 7 Gated MLA (5:1) |
211
+ | Number of Dense Layers | 2 |
212
+ | Number of Routed Experts | 512 |
213
+ | Number of Shared Experts | 1 |
214
+ | Number of Activated Experts | 8 |
215
+ | Attention Heads | 32 |
216
+ | Hidden Size | 2560 |
217
+ | Expert Intermediate Size | 768 |
218
+ | Dense Intermediate Size | 6144 |
219
+ | Vocabulary Size | 157184 |
220
+ | Context Training Schedule | 8K -> 32K -> 256K |
221
+
222
+
223
+
224
+
225
+ <!-- 这是一张图片,ocr 内容为:LING-3.0-FLASH ARCHITECTURE TRAININGOBJECTIVE:NEXT-TOKENPRE TOKEN PREDICTION AND MULTI-TOKEN PREDICTION (MTP) VOCABULARY O:SIGMOID GATE OUTPUT LINEAR OUTPUT LAYER SIZE OF 157K PROJECTION FINAL RMSNORM MULTI-HEAD LATENT ATTENTION K E512A8+1SHARED MOE ROPE ROPE ERT,ALF-LB EXPERT RMSNORM LINEAR LINEAR RMSNORM RMSNORM SUPPORTED LINEAR LINEAR LINEAR GATED MLA ROPE CONTENTLENGTH-- OF 1M TOKENS RMSNORM O:SIGMOID GATE OUTPUT P:SOFTPLUS GATE PROJECTION 8:SWISH FUNC RMSNORM MOE KIMI DELTA ATTENTION RMSNORM K V L2 NORM LINEAR TIME 8 KDA COMPLEXITY RMSNORM CONV CONV MLP LINEAR TOKEN EMBEDDING LAYER 7 GROUPS LINEAR LINEAR FIRST 2 BLOCKS EMBEDDING TOKENIZED TEXT USE DENSE FFN DIMENSION OF 2,560 个 INSTEAD OF MOE SAMPLE INPUT TEXT -->
226
+ ![](https://intranetproxy.alipay.com/skylark/lark/0/2026/png/23157180/1785822388609-79c06c50-2ea9-40d9-888b-0ff4072a724c.png)
227
+
228
+ ## Evaluation
229
+ We have conducted a comprehensive evaluation of Ling-3.0-flash across multiple authoritative benchmarks. **Ling-3.0-flash** performs strongly on representative code/agent benchmarks such as **SWE-Bench Pro, SWE-Bench Multilingual, Tau3-banking-AA**, **MCP-Atlas** and **SkillsBench, etc**. In practice, Ling-3.0-flash delivers a strong user experience across frameworks including **Claude Code**,**Kilo Code**,**Qwen Code**,**Hermes Agent**,and **OpenClaw**, etc. Beyond agentic tasks, Ling-3.0-flash also delivers strong performance across **general knowledge**,**mathematical reasoning**,**instruction following**,and **long-context understanding**.
230
+
231
+ <!-- 这是一张图片,ocr 内容为:DEEPSEEK CLAUDE- NEMOTRON- LING-3.0 GPT-5.4 STEP-3.7- V4-FLASH- RING-2.6-1T MINIMAX- 3-SUPER FLASH (HIGH) MINI (HIGH) FLASH (XHIGH) 120B-A12B (MAX) (MAX) 120B-A12B 124B-A5.1B 284B-A13B 198B-A11B 230B-A10B 1T-A63B SIZE CODING AGENT SWE-BENCH PRO 47.9 34.1 48.3 56.2 56.3 52.6 53.9 56.6 SWE-BENCH MULTILINGUAL 72.4 71.0 42.7 56.7 724 76.5 73.3 75.9 57.0 TERMINAL-BENCH 2.1 39.3 55.8 55.0 71.2 62.0 43.1 39.0 59.2 77.0 65.1 55.8 ARTIFACTSBENCH 66.8 64.0 51.6 68.7 25.3 19.2 MINIAPPENCH 28.0 14.8 46.3 20.7 58.8 5.8 52.2 ANTSWEBENCH 48.6 46.4 GENERAL AGENT 8.9 11.3 28.0 TAU3-BANKING-AA 11.3 10.1 22.9 14.6 30.5 55.2 53.6 69.0 65.5 MCP-ATLAS 52.6 61.2 49.4 66.7 53.5 24.9 20.3 44.8 54.4 28.4 44.8 11.9 SKILLSBENCH BFCL-V4 59.5 73.0 68.3 73.1 65.4 63.6 60.6 64.8 GDPVAL V2-AA 920 1377 1189 1017 1107 699 1159 SEARCH AGENT WIDESEARCH 75.2 70.2 62.2 73.6 19.5 74.4 56.8 79.5 72.2(W/ CTX) 74.0(W/CTX) BROWSECOMP 73.2 71.7 31.3 75.8 76.3 82.0(MA) 82.1(MA) DRACO 71.3 75.8 61.3 66.8 70.4 INSTRUCTION FOLLOWING 75.7 74.5 IFBENCH 72.6 67.3 79.2 69.0 44.6 56.6 91.4 93.6 93.3 SYSBENCH 86.5 93.9 90.7 86.2 94.9 77.3 71.3 LIFEBENCH 69.2 72.5 71.8 74.1 66.9 60.2 REASONING 91.7 94.2 AIME26 93.2 95.0 95.8 92.9 96.5 94.4 HMMT-FEB26 87.0 71.9 93.5 85.6 94.8 87.9 84.9 83.9 83.7 74.5 87.0 IMO-ANSWERBENCH 77.0 82.1 86.1 66.9 22.7 HLE 19.9 20.6 18.3 18.3 34.8 28.1 30.0 LIVECODEBENCH 82.8 78.1 80.8 87.0 75.6 83.7 78.7 91.6 (2408-2505) LONG CONTEXT & MULTI-TURN DIALOGUE 39.2 MRCR 128K 27.7 90.1 56.1 40.8 90.8 92.5 88.5 92.7 81.1 MRCR 256K 25.7 76.5 50.5 35.8 84.3 70.7 AA-LCR 65.1 64.3 68.7 63.7 63.0 58.3 63.4 89.3 MULTI-IF 86.2 87.7 82.9 84.6 84.8 82.3 84.6 -->
232
+ ![](https://intranetproxy.alipay.com/skylark/lark/0/2026/png/23157180/1785843565924-387dbbd7-90f8-4241-a58d-664cc5e6b486.png)
233
+
234
+ > + Thinking mode is enabled by default. Unless otherwise specified, the default parameters for Ling-3.0-flash are as follows: `temperature=0.6, top_p=0.95, top_k=20`.
235
+ > + <font style="color:rgb(16, 18, 20);">SWE-Bench Series:Evaluated using OpenHands as the agent harness with tailored prompts. Decoding uses </font>`temperature=0.6, top_p=0.95, max_new_tokens=32K`<font style="color:rgb(16, 18, 20);">, with a 256K context window.</font>
236
+ > + <font style="color:rgb(16, 18, 20);">Terminal-Bench 2.1: Evaluated under the Artificial Analysis (AA) protocol using the default Terminus 2 harness, a unified 2-hour timeout, the provided JSON parser in preserve-thinking mode, and 3 runs per task (mean). Decoding uses </font>`temperature=0.6, top_p=1.0, max_new_tokens=32K`<font style="color:rgb(16, 18, 20);">, with a 256K context window.</font>
237
+ > + <font style="color:rgb(16, 18, 20);">MiniAppBench: A 500-task coding benchmark evaluating whether models can turn a single user request into complete, usable interactive HTML apps in real-world application-generation scenarios. Evaluated with `temperature=1.0, top_p=1.0, max_tokens=128K`.
238
+ > + <font style="color:rgb(16, 18, 20);">AntSWEBench: </font><font style="color:rgb(0, 0, 0);">AntSWEBench is an internally used software engineering benchmark that covers mainstream programming languages such as Java, JavaScript, and Python, including various development scenarios like new feature, bug fix, and code refactoring.</font>
239
+ > + <font style="color:rgb(16, 18, 20);">Tau3-banking-AA: Aligned with the AA leaderboard, utilizing GPT-5.4-mini (medium reasoning) for both the user simulator and the natural-language assertion judge.</font>
240
+ > + MCP-Atlas: Evaluated on the 500-task public set using the official v1 harness with a 20-turn limit and Gemini-2.5-Pro as the claim-coverage judger.
241
+ > + SkillsBench: Evaluated via kilo-code on 87 tasks (excluding external API-dependent tasks), averaged over 3 runs.
242
+ > + <font style="color:rgb(16, 18, 20);">GDPval v2-AA : Evaluated on the public 220-task benchmark using the official Stirrup harness, with a 250-turn limit and a 5-hour timeout.</font>
243
+ > + <font style="color:rgb(16, 18, 20);">Search‑agent:For all search‑agent tasks, evaluations are performed using an internal harness. The basic ReAct paradigm is adopted for single-agent evaluation, while a multi-agent setup is employed for BrowseComp. The reported metric is the average pass@1.</font>
244
+ > - <font style="color:rgb(16, 18, 20);">WideSearch: Evaluated using the official prompt and the official judge model GPT-4.1 on the corrected version of the dataset.</font>
245
+ > - <font style="color:rgb(16, 18, 20);">Draco: Scored based on official rubrics per question, with the final score calculated as the average across all questions using </font>Claude Opus 4.6<font style="color:rgb(16, 18, 20);"> as the scoring model.</font>
246
+ > - BrowseComp (Single-Agent): Evaluated using a resume strategy for context management: once the context reaches a 64K-token threshold, the trajectory is summarized, the original history is discarded, and execution is resumed from the summary.
247
+ > - BrowseComp (Multi-Agent):<font style="color:rgb(16, 18, 20);"> Evaluated on English and ZH Revised datasets using an internal multi-agent search harness based on SearchSwarm/Tongyi DeepResearch, configured with </font>`temperature=0.85, top_p=0.95, max_tokens=8K`<font style="color:rgb(16, 18, 20);">, and main/sub-agent context windows of 128K and 64K, respectively.</font>
248
+ >
249
+
250
+ ## Quickstart
251
+ ### SGlang
252
+ #### Install our SGLang
253
+ ```bash
254
+ pip install uv
255
+
256
+ uv venv ~/my_ling_env
257
+
258
+ source ~/my_ling_env/bin/activate
259
+
260
+ git clone -b ling_v3_support https://github.com/inclusionAI/sglang_ling_v3.git
261
+
262
+ cd sglang_ling_v3
263
+
264
+ pip install --upgrade pip
265
+
266
+ pip install -e "python"
267
+ ```
268
+
269
+ #### Run Inference
270
+ Here is an example to run Ling-3.0-flash with 4 GPUs, where the master node IP is `${MASTER_IP}` and server port is `${PORT}`:
271
+
272
+ **Server**
273
+
274
+ Since the model is trained with MTP, we recommend enabling MTP during inference (i.e., --speculative-algorithm NEXTN) for lower latency.
275
+
276
+ ```bash
277
+ export SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1
278
+ export SGLANG_JIT_DEEPGEMM_PRECOMPILE=1
279
+ export SGLANG_ENABLE_SPEC_V2=1
280
+ python -m sglang.launch_server \
281
+ --model-path $MODEL_PATH \
282
+ --dist-init-addr $MASTER_IP:2345 \
283
+ --port $PORT \
284
+ --nnodes 1 \
285
+ --mem-fraction-static 0.8 \
286
+ --max-running-requests 64 \
287
+ --tp-size 4 \
288
+ --chunked-prefill-size 8192 \
289
+ --tool-call-parser ling3 \
290
+ --reasoning-parser ling3 \
291
+ --context-length 262144 \
292
+ --speculative-algorithm NEXTN \
293
+ --max-mamba-cache-size 320 \
294
+ --enable-fp32-lm-head \
295
+ --disable-shared-experts-fusion
296
+ ```
297
+
298
+ **Client**
299
+
300
+ We recommend using the sampling parameters `temperature=0.6`, `top_p=0.95`, and `top_k=20`, and enabling `enable_thinking` for better performance.
301
+
302
+ ```bash
303
+ curl -s http://${MASTER_IP}:${PORT}/v1/chat/completions \
304
+ -H "Content-Type: application/json" \
305
+ -d '{"model": "auto",
306
+ "messages": [{"role": "user", "content": "hello!"}],
307
+ "chat_template_kwargs": {"enable_thinking": true},
308
+ "stream": true,
309
+ "temperature": 0.6,
310
+ "top_k": 20,
311
+ "top_p": 0.95
312
+ }'
313
+ ```
314
+
315
+ ### vLLM
316
+ #### Install our vLLM
317
+ ```bash
318
+ pip install uv
319
+
320
+ uv venv ~/my_ling_env
321
+
322
+ source ~/my_ling_env/bin/activate
323
+
324
+ git clone -b ling_3_0 https://github.com/inclusionAI/vllm-ling-v3.git
325
+
326
+ cd vllm-ling-v3
327
+
328
+ VLLM_USE_PRECOMPILED=1 uv pip install --editable . --torch-backend=auto
329
+ ```
330
+
331
+ #### Run Inference
332
+ Here is the example to run Ling-3.0-flash with 4 GPUs, where the server port is `${PORT}`:
333
+
334
+ **Server**
335
+
336
+ Since the model is trained with MTP, we recommend enabling MTP during inference (i.e., --speculative-config) for lower latency.
337
+
338
+ ```bash
339
+ vllm serve "$MODEL_PATH" \
340
+ --port "$PORT" \
341
+ --trust-remote-code \
342
+ --served-model-name auto \
343
+ --tensor-parallel-size 4 \
344
+ --gpu-memory-utilization 0.85 \
345
+ --enable-prefix-caching \
346
+ --mamba-cache-mode align \
347
+ --enable-auto-tool-choice \
348
+ --tool-call-parser ling3 \
349
+ --reasoning-parser ling3 \
350
+ --speculative-config '{"method":"mtp","num_speculative_tokens":3}'
351
+ ```
352
+
353
+ **Client**
354
+
355
+ We recommend using the sampling parameters `temperature=0.6`, `top_p=0.95`, and `top_k=20`, and enabling `enable_thinking` for better performance.
356
+
357
+ ```bash
358
+ curl -s http://${MASTER_IP}:${PORT}/v1/chat/completions \
359
+ -H "Content-Type: application/json" \
360
+ -d '{"model": "auto",
361
+ "messages": [{"role": "user", "content": "hello!"}],
362
+ "chat_template_kwargs": {"enable_thinking": true},
363
+ "stream": true,
364
+ "temperature": 0.6,
365
+ "top_k": 20,
366
+ "top_p": 0.95
367
+ }'
368
+ ```
chat_template.jinja ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {#- Bailing V3 chat template -#}
2
+ {#- Supports: thinking option, tool calling -#}
3
+
4
+ {#- ==================== thinking option normalization ==================== -#}
5
+ {%- if enable_thinking is defined %}
6
+ {%- if enable_thinking %}
7
+ {%- set thinking_option = 'on' %}
8
+ {%- else %}
9
+ {%- set thinking_option = 'off' %}
10
+ {%- endif %}
11
+ {%- elif thinking_option is not defined %}
12
+ {%- set thinking_option = 'on' %}
13
+ {%- endif %}
14
+
15
+ {#- ==================== preserved thinking ==================== -#}
16
+ {% set preserved_thinking = true %}
17
+
18
+ {#- ==================== system message ==================== -#}
19
+ {{- '<role>SYSTEM</role>' }}
20
+ {%- if tools %}
21
+ {%- if messages[0].role == 'system' %}
22
+ {{- messages[0].content + '\n' }}
23
+ {%- endif %}
24
+ {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
25
+ {%- for tool in tools %}
26
+ {{- "\n" }}
27
+ {{- tool | tojson }}
28
+ {%- endfor %}
29
+ {{- "\n</tools>\n\nIf none of the functions can be used, point it out. If the given question lacks the parameters required by the function, also point it out.\nIf you need to use a function, for each function call, output the function name and arguments within the following XML format:\n<tool_call>{function-name}\n<arg_key>{arg-key-1}</arg_key>\n<arg_value>{arg-value-1}</arg_value>\n<arg_key>{arg-key-2}</arg_key>\n<arg_value>{arg-value-2}</arg_value>\n...\n</tool_call>\n" }}
30
+ {%- if messages[0].role == 'system' and messages[0].content is string and ('detailed thinking on' in messages[0].content or 'detailed thinking off' in messages[0].content) %}
31
+ {{- '<|role_end|>' }}
32
+ {%- else %}
33
+ {{- 'detailed thinking ' + thinking_option + '<|role_end|>' }}
34
+ {%- endif %}
35
+ {%- else %}
36
+ {%- if messages[0].role == 'system' %}
37
+ {%- if 'detailed thinking on' in messages[0].content or 'detailed thinking off' in messages[0].content %}
38
+ {{- messages[0].content + '<|role_end|>' }}
39
+ {%- else %}
40
+ {{- messages[0].content + '\n' }}
41
+ {{- 'detailed thinking ' + thinking_option + '<|role_end|>' }}
42
+ {%- endif %}
43
+ {% else %}
44
+ {{- 'detailed thinking ' + thinking_option + '<|role_end|>' }}
45
+ {%- endif %}
46
+ {%- endif %}
47
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
48
+ {%- for message in messages[::-1] %}
49
+ {%- set index = (messages|length - 1) - loop.index0 %}
50
+ {%- if ns.multi_step_tool and message.role == "user" and message.content is string and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
51
+ {%- set ns.multi_step_tool = false %}
52
+ {%- set ns.last_query_index = index %}
53
+ {%- endif %}
54
+ {%- endfor %}
55
+ {%- for message in messages %}
56
+ {%- if message.content is string %}
57
+ {%- set content = message.content %}
58
+ {%- else %}
59
+ {%- set content = '' %}
60
+ {%- endif %}
61
+ {%- if message.role == "user" %}
62
+ {{- '<role>HUMAN</role>' + message.content + '<|role_end|>' }}
63
+ {%- elif message.role == "system" and not loop.first %}
64
+ {{- '<role>SYSTEM</role>' + message.content + '<|role_end|>' }}
65
+ {%- elif message.role == "assistant" %}
66
+ {%- set reasoning_content = '' %}
67
+ {%- if message.reasoning_content is string and message.reasoning_content != '' %}
68
+ {%- set reasoning_content = message.reasoning_content %}
69
+ {%- else %}
70
+ {%- if '</think>' in content %}
71
+ {%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
72
+ {%- set content = content.split('</think>')[-1].lstrip('\n') %}
73
+ {%- endif %}
74
+ {%- endif %}
75
+ {%- if preserved_thinking or loop.index0 > ns.last_query_index %}
76
+ {%- if reasoning_content != '' %}
77
+ {{- '<role>ASSISTANT</role>' + '\n<think>' + reasoning_content.strip('\n') + '</think>' + content.lstrip('\n') }}
78
+ {%- else %}
79
+ {{- '<role>ASSISTANT</role>\n<think></think>' + content }}
80
+ {%- endif %}
81
+ {%- else %}
82
+ {{- '<role>ASSISTANT</role>\n<think></think>' + content }}
83
+ {%- endif %}
84
+ {%- if message.tool_calls %}
85
+ {%- for tool_call in message.tool_calls %}
86
+ {%- if (loop.first and content) or (not loop.first) %}
87
+ {{- '\n' }}
88
+ {%- endif %}
89
+ {%- set tc = tool_call %}
90
+ {%- if tool_call.function %}
91
+ {%- set tc = tool_call.function %}
92
+ {%- endif %}
93
+ {{- '<tool_call>' + tc.name }}
94
+ {% set _args = tc.arguments %}
95
+ {%- for k, v in _args.items() %}
96
+ {{- '<arg_key>' + k + '</arg_key>' }}
97
+ {{- '\n<arg_value>' }}
98
+ {%- if v is string %}
99
+ {{- v }}
100
+ {%- else %}
101
+ {{- v | tojson(ensure_ascii=False) }}
102
+ {%- endif %}
103
+ {{- '</arg_value>' }}
104
+ {%- endfor %}
105
+ {{- '\n</tool_call>' }}
106
+ {%- endfor %}
107
+ {%- endif %}
108
+ {{- '<|role_end|>' }}
109
+ {%- elif message.role == "tool" %}
110
+ {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
111
+ {{- '<role>OBSERVATION</role>' }}
112
+ {%- endif %}
113
+ {{- '\n<tool_response>\n' }}
114
+ {{- content }}
115
+ {{- '\n</tool_response>' }}
116
+ {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
117
+ {{- '<|role_end|>' }}
118
+ {%- endif %}
119
+ {%- endif %}
120
+ {%- endfor %}
121
+
122
+ {#- ==================== generation prompt ==================== -#}
123
+ {%- if add_generation_prompt %}
124
+ {{- '<role>ASSISTANT</role>' }}
125
+ {%- if thinking_option == 'on' %}
126
+ {{- '\n<think>' }}
127
+ {%- elif thinking_option == 'off' %}
128
+ {{- '\n<think></think>' }}
129
+ {%- endif %}
130
+ {%- endif %}
config.json ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "BailingMoeV3ForCausalLM"
4
+ ],
5
+ "attention_dropout": 0.0,
6
+ "auto_map": {
7
+ "AutoConfig": "configuration_bailing_moe_v3.BailingMoeV3Config",
8
+ "AutoModel": "modeling_bailing_moe_v3.BailingMoeV3Model",
9
+ "AutoModelForCausalLM": "modeling_bailing_moe_v3.BailingMoeV3ForCausalLM"
10
+ },
11
+ "embedding_dropout": 0.0,
12
+ "eos_token_id": 156895,
13
+ "expert_swiglu_limit_list": [
14
+ 0,
15
+ 0,
16
+ 0,
17
+ 0,
18
+ 0,
19
+ 0,
20
+ 0,
21
+ 0,
22
+ 0,
23
+ 0,
24
+ 0,
25
+ 0,
26
+ 0,
27
+ 0,
28
+ 0,
29
+ 0,
30
+ 0,
31
+ 0,
32
+ 0,
33
+ 0,
34
+ 0,
35
+ 0,
36
+ 0,
37
+ 0,
38
+ 0,
39
+ 0,
40
+ 0,
41
+ 0,
42
+ 0,
43
+ 0,
44
+ 0,
45
+ 0,
46
+ 0,
47
+ 0,
48
+ 0,
49
+ 4,
50
+ 4,
51
+ 4,
52
+ 4,
53
+ 4,
54
+ 4,
55
+ 4
56
+ ],
57
+ "first_k_dense_replace": 2,
58
+ "gated_attention_proj_granularity_type": "head_wise",
59
+ "group_norm_size": 1,
60
+ "head_dim": 128,
61
+ "hidden_act": "silu",
62
+ "hidden_size": 2560,
63
+ "initializer_range": 0.02,
64
+ "intermediate_size": 6144,
65
+ "kda_lower_bound": -5.0,
66
+ "kda_safe_gate": true,
67
+ "kv_lora_rank": 512,
68
+ "layer_group_size": 6,
69
+ "linear_silu": true,
70
+ "max_position_embeddings": 131072,
71
+ "max_window_layers": 20,
72
+ "moe_intermediate_size": 768,
73
+ "moe_router_enable_expert_bias": true,
74
+ "moe_shared_expert_intermediate_size": 768,
75
+ "mtp_loss_scaling_factor": 0,
76
+ "mtp_use_kda": false,
77
+ "n_group": 8,
78
+ "no_kda_lora": true,
79
+ "norm_topk_prob": true,
80
+ "num_attention_heads": 32,
81
+ "num_experts": 512,
82
+ "num_experts_per_tok": 8,
83
+ "num_hidden_layers": 42,
84
+ "num_key_value_heads": 32,
85
+ "num_kv_heads_for_linear_attn": 0,
86
+ "num_nextn_predict_layers": 1,
87
+ "num_shared_experts": 1,
88
+ "output_dropout": 0.0,
89
+ "output_router_logits": false,
90
+ "pad_token_id": 156892,
91
+ "partial_rotary_factor": 0.5,
92
+ "q_lora_rank": null,
93
+ "qk_head_dim": 192,
94
+ "qk_nope_head_dim": 128,
95
+ "qk_rope_head_dim": 64,
96
+ "rms_norm_eps": 1e-06,
97
+ "rope_interleave": true,
98
+ "rope_scaling": null,
99
+ "rope_theta": 6000000,
100
+ "rotary_dim": 64,
101
+ "routed_scaling_factor": 2.5,
102
+ "router_dtype": "fp32",
103
+ "scale_router_input": false,
104
+ "score_function": "sigmoid",
105
+ "scoring_func": "sigmoid",
106
+ "seq_aux": true,
107
+ "share_expert_swiglu_limit_list": [
108
+ 0,
109
+ 0,
110
+ 0,
111
+ 0,
112
+ 0,
113
+ 0,
114
+ 0,
115
+ 0,
116
+ 0,
117
+ 0,
118
+ 0,
119
+ 0,
120
+ 0,
121
+ 0,
122
+ 0,
123
+ 0,
124
+ 0,
125
+ 0,
126
+ 0,
127
+ 0,
128
+ 0,
129
+ 0,
130
+ 0,
131
+ 0,
132
+ 0,
133
+ 0,
134
+ 0,
135
+ 0,
136
+ 0,
137
+ 0,
138
+ 0,
139
+ 0,
140
+ 0,
141
+ 0,
142
+ 5,
143
+ 5,
144
+ 5,
145
+ 5,
146
+ 5,
147
+ 5,
148
+ 7,
149
+ 7
150
+ ],
151
+ "short_conv_kernel_size": 4,
152
+ "tie_word_embeddings": false,
153
+ "topk_group": 4,
154
+ "topk_method": "noaux_tc",
155
+ "transformers_version": "4.45.0",
156
+ "up_proj_norm": false,
157
+ "use_bias": false,
158
+ "use_cache": true,
159
+ "use_kda_lora": false,
160
+ "use_mla_nope": false,
161
+ "use_nGPT": false,
162
+ "use_qk_norm": true,
163
+ "use_qkv_bias": false,
164
+ "v_head_dim": 128,
165
+ "value_norm": false,
166
+ "vocab_size": 157184,
167
+ "model_type": "bailing_hybrid",
168
+ "torch_dtype": "bfloat16",
169
+ "quantization_config": {
170
+ "quant_method": "compressed-tensors",
171
+ "format": "nvfp4-pack-quantized",
172
+ "config_groups": {
173
+ "group_0": {
174
+ "targets": [
175
+ "re:.*\\.experts\\.\\d+\\..*",
176
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.experts\\.\\d+\\.gate_up_proj$"
177
+ ],
178
+ "weights": {
179
+ "num_bits": 4,
180
+ "type": "float",
181
+ "strategy": "tensor_group",
182
+ "group_size": 16,
183
+ "symmetric": true
184
+ }
185
+ }
186
+ },
187
+ "ignore": [
188
+ "re:.*lm_head$",
189
+ "re:.*model\\.layers\\.\\d+\\.attention\\.b_proj$",
190
+ "re:.*model\\.layers\\.\\d+\\.attention\\.f_proj$",
191
+ "re:.*model\\.layers\\.\\d+\\.attention\\.g_proj$",
192
+ "re:.*model\\.layers\\.\\d+\\.attention\\.k_conv1d$",
193
+ "re:.*model\\.layers\\.\\d+\\.attention\\.k_proj$",
194
+ "re:.*model\\.layers\\.\\d+\\.attention\\.o_proj$",
195
+ "re:.*model\\.layers\\.\\d+\\.attention\\.q_conv1d$",
196
+ "re:.*model\\.layers\\.\\d+\\.attention\\.q_proj$",
197
+ "re:.*model\\.layers\\.\\d+\\.attention\\.v_conv1d$",
198
+ "re:.*model\\.layers\\.\\d+\\.attention\\.v_proj$",
199
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.down_proj$",
200
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.gate_proj$",
201
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.up_proj$",
202
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.gate$",
203
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.shared_experts\\.down_proj$",
204
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.shared_experts\\.gate_proj$",
205
+ "re:.*model\\.layers\\.\\d+\\.mlp\\.shared_experts\\.up_proj$",
206
+ "re:.*model\\.layers\\.\\d+\\.attention\\.dense$",
207
+ "re:.*model\\.layers\\.\\d+\\.attention\\.kv_a_proj_with_mqa$",
208
+ "re:.*model\\.layers\\.\\d+\\.attention\\.kv_b_proj$",
209
+ "re:.*model\\.layers\\.\\d+\\.eh_proj$",
210
+ "re:.*model\\.word_embeddings$"
211
+ ]
212
+ }
213
+ }
configuration_bailing_moe_v3.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Bailing MoE V2 model configuration"""
2
+
3
+ from transformers.configuration_utils import PretrainedConfig
4
+
5
+
6
+ class BailingMoeV3Config(PretrainedConfig):
7
+
8
+ def __init__(
9
+ self,
10
+ vocab_size=157184,
11
+ hidden_size=2048,
12
+ intermediate_size=5120,
13
+ num_hidden_layers=20,
14
+ num_attention_heads=16,
15
+ num_key_value_heads=4,
16
+ hidden_act="silu",
17
+ use_qkv_bias=False, # bailing only
18
+ use_bias=False, # bailing only
19
+ rms_norm_eps=1e-06,
20
+ tie_word_embeddings=False, # PretrainedConfig key, here change default value.
21
+ embedding_dropout=0.0,
22
+ attention_dropout=0.0,
23
+ output_dropout=0.0,
24
+ initializer_range=0.02,
25
+ max_position_embeddings=32768,
26
+ rope_theta=600000.0,
27
+ use_cache=True,
28
+ max_window_layers=20,
29
+ rope_scaling=None,
30
+ pad_token_id=156892,
31
+ eos_token_id=156892,
32
+ num_experts=256,
33
+ num_shared_experts=1,
34
+ num_experts_per_tok=8,
35
+ n_group=8,
36
+ topk_group=4,
37
+ moe_intermediate_size=512,
38
+ moe_shared_expert_intermediate_size=512,
39
+ first_k_dense_replace=1,
40
+ head_dim=128,
41
+ output_router_logits=False,
42
+ use_qk_norm=True,
43
+ num_nextn_predict_layers=0,
44
+ mtp_loss_scaling_factor=0,
45
+ moe_router_enable_expert_bias=True,
46
+ routed_scaling_factor=1.0,
47
+ layer_group_size=5,
48
+ kv_lora_rank=512,
49
+ q_lora_rank=None,
50
+ qk_rope_head_dim=64,
51
+ v_head_dim=128,
52
+ qk_nope_head_dim=128,
53
+ rope_interleave=True,
54
+ score_function="sigmoid",
55
+ scoring_func="sigmoid",
56
+ seq_aux=True,
57
+ topk_method="noaux_tc",
58
+ router_dtype="fp32",
59
+ gated_attention_proj_granularity_type=None,
60
+ no_kda_lora=False,
61
+ kda_safe_gate=False,
62
+ kda_lower_bound=None,
63
+ short_conv_kernel_size=4,
64
+ **kwargs,
65
+ ):
66
+ self.num_hidden_layers = num_hidden_layers
67
+ self.vocab_size = vocab_size
68
+ self.hidden_size = hidden_size
69
+ self.intermediate_size = intermediate_size
70
+ self.num_attention_heads = num_attention_heads
71
+ self.num_key_value_heads = num_key_value_heads
72
+ self.hidden_act = hidden_act
73
+ self.use_qkv_bias = use_qkv_bias
74
+ self.use_bias = use_bias
75
+ self.rms_norm_eps = rms_norm_eps
76
+ self.embedding_dropout = embedding_dropout
77
+ self.attention_dropout = attention_dropout
78
+ self.output_dropout = output_dropout
79
+ self.num_nextn_predict_layers = num_nextn_predict_layers
80
+ self.mtp_loss_scaling_factor = mtp_loss_scaling_factor
81
+ self.initializer_range = initializer_range
82
+ self.max_position_embeddings = max_position_embeddings
83
+ self.rope_theta = rope_theta
84
+ self.use_cache = use_cache
85
+ self.max_window_layers = max_window_layers
86
+ self.head_dim = head_dim or self.hidden_size // self.num_attention_heads
87
+ self.rope_scaling = rope_scaling
88
+ self.use_qk_norm = use_qk_norm
89
+ self.moe_router_enable_expert_bias = moe_router_enable_expert_bias
90
+ self.routed_scaling_factor = routed_scaling_factor
91
+
92
+ # MoE configs
93
+ self.num_experts = num_experts
94
+ self.num_shared_experts = num_shared_experts
95
+ self.num_experts_per_tok = num_experts_per_tok
96
+ self.n_group = n_group
97
+ self.topk_group = topk_group
98
+ self.moe_intermediate_size = moe_intermediate_size
99
+ self.moe_shared_expert_intermediate_size = moe_shared_expert_intermediate_size
100
+ self.first_k_dense_replace = first_k_dense_replace
101
+ self.output_router_logits = output_router_logits
102
+
103
+ # Linear configs
104
+ self.layer_group_size = layer_group_size
105
+ # mla
106
+ self.kv_lora_rank = kv_lora_rank
107
+ self.q_lora_rank = q_lora_rank
108
+ self.qk_rope_head_dim = qk_rope_head_dim
109
+
110
+ self.score_function = score_function
111
+ self.scoring_func = scoring_func
112
+ self.seq_aux = seq_aux
113
+ self.topk_method = topk_method
114
+ self.v_head_dim = v_head_dim
115
+ self.qk_nope_head_dim = qk_nope_head_dim
116
+ self.qk_head_dim = qk_nope_head_dim + qk_rope_head_dim
117
+ self.rope_interleave = rope_interleave
118
+ self.router_dtype = router_dtype
119
+ self.gated_attention_proj_granularity_type = gated_attention_proj_granularity_type
120
+ self.no_kda_lora = no_kda_lora
121
+ self.kda_safe_gate = kda_safe_gate
122
+ self.kda_lower_bound = kda_lower_bound
123
+ self.short_conv_kernel_size = short_conv_kernel_size
124
+ super().__init__(
125
+ pad_token_id=pad_token_id, eos_token_id=eos_token_id, tie_word_embeddings=tie_word_embeddings, **kwargs
126
+ )
model-00001-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5cd9b840d449aed1362845e1908053c0e3263cdb15a9708bdcb3a87beb386f75
3
+ size 8290737664
model-00002-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:17df0064383fe3ba8c37722f039980dac30a6cbbdd939619cea3b1e950c92768
3
+ size 2960456136
model-00003-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d8cbc95720f20119e7c40b0e0d5f310ce810050ef3010c0b6d65dd83848dfa52
3
+ size 2960456840
model-00004-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1c9b5241a437e4c9580e4d0664270f6a4ce6afc657bd4ec3e20c5d8516b2b1c1
3
+ size 3013558976
model-00005-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cd88b89f5e937ec9828e7c2b7b070a427858e3714aee1c36bf71ecccbe192f8a
3
+ size 2960456136
model-00006-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8fca172022f97e65869e518c0844807b747dc5054da828e0a4eb29ef893dff32
3
+ size 2960462128
model-00007-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:17b8b580df7429d3098bfd1227f9640fd379402c611dcc4d26be8caf94436cd8
3
+ size 2960464864
model-00008-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:66981b6fa4e5b32537fa73d7b80524b3e9da98ce21ccdb8cd25844bf9aca4b0a
3
+ size 3013567152
model-00009-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:50d2b6296ba45deb6e5d8d41b8d2d9d5ae9322716797c9c990338a37bd478a06
3
+ size 2960464160
model-00010-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:de68a392f51f15ccd9a7c025c0123d8c8eab0a17be7d9c247771bd878474286d
3
+ size 2960464160
model-00011-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4596eea10d973426e31d8fbccd012ec0af2a3cc30f79546a158022a8efa9aeb1
3
+ size 2960464864
model-00012-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d6c915d7c51d4f1f828cb17d6ce31e524a0f4209333f6e62516add0a5ab21e20
3
+ size 3013567152
model-00013-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d3f6e0d03bb88c02167904cc6158ad68e3e4dac1f44ea60a2edbd5406c4273eb
3
+ size 2960464160
model-00014-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aaee8a414a8a2495390a18961809b2937af66da9af85e78d866fa3318e461770
3
+ size 2960464160
model-00015-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b807748938cdaacfd9bf20df81fec4d68bdb78ada728955e9c577b46973222f
3
+ size 2960464864
model-00016-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:633ff3df85d9a0ad986fc223ab51d80b530c4afdb597a4a33ddc21d9ebf7528b
3
+ size 3013567152
model-00017-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7285459e671e76c0658d228a67ca6eac0c2455a61bf730cc82ecbcab4564716f
3
+ size 2960464160
model-00018-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fb3a72814336d863aea0449f8553b50b3077805d8d85994793a6b78548cfa737
3
+ size 2960464160
model-00019-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e84a9fbce9923b035fdbb644cc7eb7aaf9213ce56da5cff15495d64a24db1fde
3
+ size 2960464864
model-00020-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c8bc99d20554ec2006f7247c5ecf9518dec0eafb3604f51e4a59729b0315470c
3
+ size 3013567152
model-00021-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1d9c34978ca2cd6f49ef3839494bd96004cd384a54f9557966f0d2b57eb2307e
3
+ size 2960464160
model-00022-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ce3a4734623538bb7a96a30ed9b7fac7d1b00c1f259118ffad9bef791329bc83
3
+ size 2960464160
model-00023-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:183e8939916fff225e4d658f8c133d5f3021319dd8414658e5a058164beeefd9
3
+ size 2960464864
model-00024-of-00024.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:504fb40910f872b84692923115b56d9502b1381c5a8c295add35dd4d624a05f4
3
+ size 7666257952
model.safetensors.index.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:94e24dbc10649edad8909f6d91448616ddbba5318a83a6d05454a244df3b2a30
3
+ size 18563389
modeling_bailing_moe_v3.py ADDED
@@ -0,0 +1,1625 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2025 Antgroup and The HuggingFace Inc. team. All rights reserved.
3
+ #
4
+ # This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
5
+ # and OPT implementations in this library. It has been modified from its
6
+ # original forms to accommodate minor architectural differences compared
7
+ # to GPT-NeoX and OPT used by the Meta AI team that trained the model.
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ """PyTorch BailingMoE model."""
21
+
22
+ import math
23
+ import warnings
24
+ from typing import List, Optional, Tuple, Union, Callable
25
+ from copy import deepcopy
26
+
27
+ import torch
28
+ import torch.nn.functional as F
29
+ from torch import nn
30
+
31
+ from transformers.activations import ACT2FN
32
+ from transformers.cache_utils import Cache, DynamicCache
33
+ from transformers.modeling_attn_mask_utils import (
34
+ AttentionMaskConverter,
35
+ _prepare_4d_attention_mask,
36
+ _prepare_4d_causal_attention_mask,
37
+ _prepare_4d_causal_attention_mask_for_sdpa,
38
+ )
39
+ from transformers.modeling_outputs import MoeModelOutputWithPast
40
+ from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
41
+ from transformers.modeling_utils import PreTrainedModel
42
+ from transformers.pytorch_utils import ALL_LAYERNORM_LAYERS, is_torch_greater_or_equal_than_1_13
43
+ from transformers.utils import (
44
+ add_start_docstrings,
45
+ add_start_docstrings_to_model_forward,
46
+ logging,
47
+ replace_return_docstrings,
48
+ )
49
+ from transformers.utils.import_utils import is_torch_fx_available
50
+ from .configuration_bailing_moe_v3 import BailingMoeV3Config
51
+ from transformers.generation.utils import GenerationMixin
52
+ from dataclasses import dataclass
53
+ from transformers.utils import ModelOutput
54
+ from transformers import DynamicLayer
55
+ from transformers.processing_utils import Unpack
56
+ from transformers.utils import TransformersKwargs
57
+ from transformers.utils.deprecation import deprecate_kwarg
58
+ from transformers.modeling_flash_attention_utils import FlashAttentionKwargs
59
+
60
+ from fla.ops.simple_gla.fused_recurrent import fused_recurrent_simple_gla
61
+ from fla.ops.simple_gla.chunk import chunk_simple_gla
62
+ from einops import rearrange, repeat
63
+
64
+
65
+ try:
66
+ from fla.modules import FusedRMSNormGated, ShortConvolution
67
+ from fla.ops.kda import chunk_kda, fused_recurrent_kda
68
+
69
+ from fla.ops.utils.index import prepare_cu_seqlens_from_mask, prepare_lens_from_mask
70
+ from fla.utils import tensor_cache
71
+ except ImportError:
72
+ raise ImportError("Plese run `pip install -U fla-core`")
73
+
74
+ # This makes `_prepare_4d_causal_attention_mask` a leaf function in the FX graph.
75
+ # It means that the function will not be traced through and simply appear as a node in the graph.
76
+ if is_torch_fx_available():
77
+ if not is_torch_greater_or_equal_than_1_13:
78
+ import torch.fx
79
+
80
+ _prepare_4d_causal_attention_mask = torch.fx.wrap(_prepare_4d_causal_attention_mask)
81
+
82
+
83
+ logger = logging.get_logger(__name__)
84
+
85
+ _CONFIG_FOR_DOC = "BailingMoeV3Config"
86
+
87
+
88
+ def roll_tensor(tensor, shifts=-1, dims=-1, fill_value=0):
89
+ """Roll the tensor input along the given dimension(s).
90
+ Inserted elements are set to be 0.0.
91
+ """
92
+ rolled_tensor = torch.roll(tensor, shifts=shifts, dims=dims)
93
+ rolled_tensor.select(dims, shifts).fill_(fill_value)
94
+ return rolled_tensor, rolled_tensor.sum()
95
+
96
+
97
+ @dataclass
98
+ class MoEV3CausalLMOutputWithPast(ModelOutput):
99
+ """
100
+ Base class for causal language model (or autoregressive) outputs as well as Mixture of Expert's router hidden
101
+ states terms, to train a MoE model.
102
+ Args:
103
+ loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` is provided):
104
+ Language modeling loss (for next-token prediction).
105
+ logits (`torch.FloatTensor` of shape `(batch_size, sequence_length, config.vocab_size)`):
106
+ Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
107
+ past_key_values (`Cache`, *optional*, returned when `use_cache=True` is passed or when `config.use_cache=True`):
108
+ It is a [`~cache_utils.Cache`] instance. For more details, see our [kv cache guide](https://huggingface.co/docs/transformers/en/kv_cache).
109
+ Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see
110
+ `past_key_values` input) to speed up sequential decoding.
111
+ hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
112
+ Tuple of `torch.FloatTensor` (one for the output of the embeddings, if the model has an embedding layer, +
113
+ one for the output of each layer) of shape `(batch_size, sequence_length, hidden_size)`.
114
+ Hidden-states of the model at the output of each layer plus the optional initial embedding outputs.
115
+ attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` is passed or when `config.output_attentions=True`):
116
+ Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length,
117
+ sequence_length)`.
118
+ Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
119
+ heads.
120
+ z_loss (`torch.FloatTensor`, *optional*, returned when `labels` is provided):
121
+ z_loss for the sparse modules.
122
+ aux_loss (`torch.FloatTensor`, *optional*, returned when `labels` is provided):
123
+ aux_loss for the sparse modules.
124
+ router_logits (`tuple(torch.FloatTensor)`, *optional*, returned when `output_router_logits=True` is passed or when `config.add_router_probs=True`):
125
+ Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, sequence_length, num_experts)`.
126
+ Router logits of the encoder model, useful to compute the auxiliary loss and the z_loss for the sparse
127
+ modules.
128
+ """
129
+
130
+ loss: Optional[torch.FloatTensor] = None
131
+ logits: Optional[torch.FloatTensor] = None
132
+ past_key_values: Optional[Cache] = None
133
+ hidden_states: Optional[tuple[torch.FloatTensor, ...]] = None
134
+ attentions: Optional[tuple[torch.FloatTensor, ...]] = None
135
+ z_loss: Optional[torch.FloatTensor] = None
136
+ aux_loss: Optional[torch.FloatTensor] = None
137
+ router_logits: Optional[tuple[torch.FloatTensor]] = None
138
+ mtp_loss: Optional[torch.FloatTensor] = None
139
+ mtp_logits: Optional[tuple[torch.FloatTensor, ...]] = None
140
+
141
+
142
+ class MoeV3ModelOutputWithPast(MoeModelOutputWithPast):
143
+
144
+ def __init__(self, mtp_hidden_states=None, **kwargs):
145
+ super().__init__(**kwargs)
146
+ self.mtp_hidden_states = mtp_hidden_states
147
+
148
+
149
+ def index_first_axis(x, indices):
150
+ other_shape = x.shape[1:]
151
+ second_dim = other_shape.numel()
152
+ return torch.gather(
153
+ rearrange(x, "b ... -> b (...)"),
154
+ 0,
155
+ repeat(indices, "z -> z d", d=second_dim),
156
+ ).reshape(-1, *other_shape)
157
+
158
+
159
+ def index_put_first_axis(x, indices, first_axis_dim):
160
+ y = torch.zeros(first_axis_dim, *x.shape[1:], device=x.device, dtype=x.dtype)
161
+ y[indices] = x
162
+ # y.scatter_(0, repeat(indices, 'z -> z d', d=x.shape[1]), x)
163
+ return y
164
+
165
+
166
+ def pad_input(
167
+ hidden_states: torch.Tensor,
168
+ indices: torch.LongTensor,
169
+ batch_size: int,
170
+ seq_len: int,
171
+ ) -> torch.Tensor:
172
+ output = index_put_first_axis(hidden_states, indices, batch_size * seq_len)
173
+ return rearrange(output, "(b s) ... -> b s ...", b=batch_size)
174
+
175
+
176
+ @tensor_cache
177
+ def _get_unpad_data(attention_mask):
178
+ seqlens_in_batch = attention_mask.sum(dim=-1, dtype=torch.int32)
179
+ indices = torch.nonzero(attention_mask.flatten(), as_tuple=False).flatten()
180
+ max_seqlen_in_batch = seqlens_in_batch.max().item()
181
+ cu_seqlens = F.pad(torch.cumsum(seqlens_in_batch, dim=0, dtype=torch.torch.int32), (1, 0))
182
+ return (
183
+ indices,
184
+ cu_seqlens,
185
+ max_seqlen_in_batch,
186
+ )
187
+
188
+
189
+ def _expand_mask(mask: torch.Tensor, dtype: torch.dtype, tgt_len: Optional[int] = None):
190
+ warnings.warn(
191
+ "Calling `transformers.models.BailingMoeV3.modeling_BailingMoeV3._prepare_4d_attention_mask` is deprecated and will be removed in v4.37. Use `transformers.modeling_attn_mask_utils._prepare_4d_attention_mask"
192
+ )
193
+ return _prepare_4d_attention_mask(mask=mask, dtype=dtype, tgt_len=tgt_len)
194
+
195
+
196
+ def _make_causal_mask(
197
+ input_ids_shape: torch.Size, dtype: torch.dtype, device: torch.device, past_key_values_length: int = 0
198
+ ):
199
+ warnings.warn(
200
+ "Calling `transformers.models.BailingMoeV3.modeling_BailingMoeV3._make_causal_mask` is deprecated and will be removed in v4.37. Use `transformers.models.BailingMoeV3.modeling_BailingMoeV3.AttentionMaskConverter._make_causal_mask"
201
+ )
202
+ return AttentionMaskConverter._make_causal_mask(
203
+ input_ids_shape=input_ids_shape, dtype=dtype, device=device, past_key_values_length=past_key_values_length
204
+ )
205
+
206
+
207
+ class BailingMoeV3RMSNorm(nn.Module):
208
+ def __init__(self, hidden_size, eps=1e-6):
209
+ """
210
+ BailingMoeV3RMSNorm is equivalent to T5LayerNorm
211
+ """
212
+ super().__init__()
213
+ self.weight = nn.Parameter(torch.ones(hidden_size))
214
+ self.variance_epsilon = eps
215
+
216
+ def forward(self, hidden_states):
217
+ input_dtype = hidden_states.dtype
218
+ hidden_states = hidden_states.to(torch.float32)
219
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
220
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
221
+ return self.weight * hidden_states.to(input_dtype)
222
+
223
+
224
+ class BailingMoeV3GroupRMSNorm(nn.Module):
225
+ def __init__(self, hidden_size, group_norm_size, eps=1e-6):
226
+ """
227
+ BailingMoeV3RMSNorm is equivalent to T5LayerNorm
228
+ """
229
+ super().__init__()
230
+ self.weight = nn.Parameter(torch.ones(hidden_size))
231
+ self.group_norm_size = group_norm_size
232
+ assert hidden_size % group_norm_size == 0, "hidden_size must be divisible by group_norm_size"
233
+ self.variance_epsilon = eps
234
+
235
+ def forward(self, hidden_states):
236
+ input_dtype = hidden_states.dtype
237
+ input_shape = hidden_states.size()
238
+ group_input_shape = input_shape[:-1] + (self.group_norm_size, input_shape[-1] // self.group_norm_size)
239
+ hidden_states = hidden_states.view(group_input_shape)
240
+ hidden_states = hidden_states.to(torch.float32)
241
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
242
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
243
+ return self.weight * hidden_states.to(input_dtype).view(input_shape)
244
+
245
+
246
+ ALL_LAYERNORM_LAYERS.append(BailingMoeV3RMSNorm)
247
+
248
+
249
+ class BailingMoeV3RotaryEmbedding(nn.Module):
250
+ def __init__(self, config: BailingMoeV3Config, device=None):
251
+ super().__init__()
252
+ # BC: "rope_type" was originally "type"
253
+ if hasattr(config, "rope_scaling") and config.rope_scaling is not None:
254
+ self.rope_type = config.rope_scaling.get("rope_type", config.rope_scaling.get("type"))
255
+ else:
256
+ self.rope_type = "default"
257
+ self.max_seq_len_cached = config.max_position_embeddings
258
+ self.original_max_seq_len = config.max_position_embeddings
259
+
260
+ self.config = deepcopy(config)
261
+ self.config.head_dim = config.qk_rope_head_dim
262
+ self.config.partial_rotary_factor = 1.0
263
+ self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
264
+
265
+ inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device)
266
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
267
+ self.original_inv_freq = self.inv_freq
268
+
269
+ @torch.no_grad()
270
+ @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
271
+ def forward(self, x, position_ids):
272
+ inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
273
+ position_ids_expanded = position_ids[:, None, :].float()
274
+
275
+ device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
276
+ with torch.autocast(device_type=device_type, enabled=False): # Force float32
277
+ freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
278
+ emb = torch.cat((freqs, freqs), dim=-1)
279
+ cos = emb.cos() * self.attention_scaling
280
+ sin = emb.sin() * self.attention_scaling
281
+
282
+ return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
283
+
284
+
285
+ # Copied from transformers.models.llama.modeling_llama.rotate_half
286
+ def rotate_half(x):
287
+ """Rotates half the hidden dims of the input."""
288
+ x1 = x[..., : x.shape[-1] // 2]
289
+ x2 = x[..., x.shape[-1] // 2 :]
290
+ return torch.cat((-x2, x1), dim=-1)
291
+
292
+
293
+ # Copied from transformers.models.llama.modeling_llama.apply_rotary_pos_emb
294
+ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
295
+ """Applies Rotary Position Embedding to the query and key tensors.
296
+ Args:
297
+ q (`torch.Tensor`): The query tensor.
298
+ k (`torch.Tensor`): The key tensor.
299
+ cos (`torch.Tensor`): The cosine part of the rotary embedding.
300
+ sin (`torch.Tensor`): The sine part of the rotary embedding.
301
+ unsqueeze_dim (`int`, *optional*, defaults to 1):
302
+ The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
303
+ sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
304
+ that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
305
+ k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
306
+ cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
307
+ the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
308
+ Returns:
309
+ `tuple(torch.Tensor)` comprising the query and key tensors rotated using the Rotary Position Embedding.
310
+ """
311
+ cos = cos.unsqueeze(unsqueeze_dim)
312
+ sin = sin.unsqueeze(unsqueeze_dim)
313
+
314
+ # Keep half or full tensor for later concatenation
315
+ rotary_dim = cos.shape[-1]
316
+ q_rot, q_pass = q[..., :rotary_dim], q[..., rotary_dim:]
317
+ k_rot, k_pass = k[..., :rotary_dim], k[..., rotary_dim:]
318
+
319
+ # Apply rotary embeddings on the first half or full tensor
320
+ q_embed = (q_rot * cos) + (rotate_half(q_rot) * sin)
321
+ k_embed = (k_rot * cos) + (rotate_half(k_rot) * sin)
322
+
323
+ # Concatenate back to full shape
324
+ q_embed = torch.cat([q_embed, q_pass], dim=-1)
325
+ k_embed = torch.cat([k_embed, k_pass], dim=-1)
326
+ return q_embed, k_embed
327
+
328
+
329
+ class BailingMoeV3MLP(nn.Module):
330
+ def __init__(self, config: BailingMoeV3Config, intermediate_size: int):
331
+ super().__init__()
332
+ self.config = config
333
+ self.hidden_size = config.hidden_size
334
+ self.intermediate_size = intermediate_size
335
+
336
+ self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
337
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
338
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
339
+ self.act_fn = ACT2FN[config.hidden_act]
340
+
341
+ def forward(self, x):
342
+ return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
343
+
344
+
345
+ class BailingMoeV3Gate(nn.Module):
346
+ def __init__(self, config):
347
+ super().__init__()
348
+ self.config = config
349
+ self.top_k = config.num_experts_per_tok
350
+ self.num_experts = config.num_experts
351
+
352
+ self.n_group = config.n_group
353
+ self.topk_group = config.topk_group
354
+
355
+ # topk selection algorithm
356
+ self.gating_dim = config.hidden_size
357
+ self.weight = nn.Parameter(torch.empty((self.num_experts, self.gating_dim)))
358
+ self.routed_scaling_factor = config.routed_scaling_factor
359
+
360
+ self.register_buffer("expert_bias", torch.zeros((self.num_experts)))
361
+ self.reset_parameters()
362
+
363
+ def reset_parameters(self) -> None:
364
+ import torch.nn.init as init
365
+
366
+ init.kaiming_uniform_(self.weight, a=math.sqrt(5))
367
+
368
+ def group_limited_topk(
369
+ self,
370
+ scores: torch.Tensor,
371
+ ):
372
+ num_tokens, _ = scores.size()
373
+ # Organize the experts into groups
374
+ group_scores = scores.view(num_tokens, self.n_group, -1).topk(2, dim=-1)[0].sum(dim=-1)
375
+ group_idx = torch.topk(group_scores, k=self.topk_group, dim=-1, sorted=False)[1]
376
+ group_mask = torch.zeros_like(group_scores)
377
+ group_mask.scatter_(1, group_idx, 1)
378
+
379
+ # Mask the experts based on selection groups
380
+ score_mask = (
381
+ group_mask.unsqueeze(-1)
382
+ .expand(num_tokens, self.n_group, self.num_experts // self.n_group)
383
+ .reshape(num_tokens, -1)
384
+ )
385
+
386
+ masked_scores = scores.masked_fill(~score_mask.bool(), float('-inf'))
387
+ probs, top_indices = torch.topk(masked_scores, k=self.top_k, dim=-1)
388
+
389
+ return probs, top_indices
390
+
391
+ def forward(self, hidden_states):
392
+ # compute gating score
393
+ hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
394
+ logits = F.linear(hidden_states.type(torch.float32), self.weight.type(torch.float32))
395
+
396
+ scores = torch.sigmoid(logits.float()).type_as(logits)
397
+
398
+ scores_for_routing = scores + self.expert_bias
399
+ _, topk_idx = self.group_limited_topk(scores_for_routing)
400
+
401
+ scores = torch.gather(scores, dim=1, index=topk_idx).type_as(logits)
402
+
403
+ topk_weight = scores / (scores.sum(dim=-1, keepdim=True) + 1e-20) if self.top_k > 1 else scores
404
+ topk_weight = topk_weight * self.routed_scaling_factor
405
+
406
+ return topk_idx, topk_weight, logits
407
+
408
+
409
+ class BailingMoeV3SparseMoeBlock(nn.Module):
410
+ """
411
+ A mixed expert module containing shared experts.
412
+ """
413
+
414
+ def __init__(self, config: BailingMoeV3Config):
415
+ super().__init__()
416
+ self.config = config
417
+ self.num_experts_per_tok = config.num_experts_per_tok
418
+ self._setup_experts()
419
+ self.gate = BailingMoeV3Gate(config)
420
+ if config.num_shared_experts is not None:
421
+ self.shared_experts = BailingMoeV3MLP(
422
+ config=config, intermediate_size=config.moe_shared_expert_intermediate_size * config.num_shared_experts
423
+ )
424
+
425
+ def _setup_experts(self):
426
+ self.experts = nn.ModuleList(
427
+ [
428
+ BailingMoeV3MLP(config=self.config, intermediate_size=self.config.moe_intermediate_size)
429
+ for _ in range(self.config.num_experts)
430
+ ]
431
+ )
432
+
433
+ def forward(self, hidden_states):
434
+ identity = hidden_states
435
+ bsz, seq_len, h = hidden_states.shape
436
+ topk_idx, topk_weight, router_logits = self.gate(hidden_states)
437
+ hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
438
+ flat_topk_idx = topk_idx.view(-1)
439
+ if self.training:
440
+ hidden_states = hidden_states.repeat_interleave(self.num_experts_per_tok, dim=0)
441
+ y = torch.empty_like(hidden_states)
442
+ for i, expert in enumerate(self.experts):
443
+ y[flat_topk_idx == i] = expert(hidden_states[flat_topk_idx == i])
444
+ y = (y.view(*topk_weight.shape, -1) * topk_weight.unsqueeze(-1)).sum(dim=1)
445
+ y = y.to(hidden_states.dtype).view(bsz, seq_len, h)
446
+ else:
447
+ y = self.moe_infer(hidden_states, topk_idx, topk_weight).view(bsz, seq_len, h)
448
+ if self.config.num_shared_experts is not None:
449
+ y = y + self.shared_experts(identity)
450
+ return y, (router_logits.view(bsz, seq_len, -1), topk_idx.view(bsz, seq_len, -1))
451
+
452
+ @torch.no_grad()
453
+ def moe_infer(self, x, topk_ids, topk_weight):
454
+ cnts = topk_ids.new_zeros((topk_ids.shape[0], len(self.experts)))
455
+ cnts.scatter_(1, topk_ids, 1)
456
+ tokens_per_expert = cnts.sum(dim=0)
457
+ idxs = topk_ids.view(-1).argsort()
458
+ sorted_tokens = x[idxs // topk_ids.shape[1]]
459
+ tokens_per_expert = tokens_per_expert.cpu().numpy()
460
+ outputs = []
461
+ start_idx = 0
462
+ for i, num_tokens in enumerate(tokens_per_expert):
463
+ end_idx = start_idx + num_tokens
464
+ if num_tokens == 0:
465
+ continue
466
+ expert = self.experts[i]
467
+ tokens_for_this_expert = sorted_tokens[start_idx:end_idx]
468
+ expert_out = expert(tokens_for_this_expert)
469
+ outputs.append(expert_out.to(x.device))
470
+ start_idx = end_idx
471
+
472
+ outs = torch.cat(outputs, dim=0) if len(outputs) else sorted_tokens.new_empty(0)
473
+ new_x = torch.empty_like(outs)
474
+ new_x[idxs] = outs
475
+ final_out = (
476
+ new_x.view(*topk_ids.shape, -1)
477
+ .type(topk_weight.dtype)
478
+ .mul_(topk_weight.unsqueeze(dim=-1))
479
+ .sum(dim=1)
480
+ .type(new_x.dtype)
481
+ )
482
+ return final_out
483
+
484
+
485
+ # Copied from transformers.models.llama.modeling_llama.repeat_kv
486
+ def repeat_kv(hidden_states: torch.Tensor, n_rep: int, head_first: bool = True) -> torch.Tensor:
487
+ """
488
+ This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). If head_first is True, the hidden states go from (batch,
489
+ num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
490
+ """
491
+ if n_rep == 1:
492
+ return hidden_states
493
+ if head_first:
494
+ batch, num_key_value_heads, slen, head_dim = hidden_states.shape
495
+ hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
496
+ return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
497
+ else:
498
+ batch, slen, num_key_value_heads, head_dim = hidden_states.shape
499
+ hidden_states = hidden_states[:, :, :, None, :].expand(batch, slen, num_key_value_heads, n_rep, head_dim)
500
+ return hidden_states.reshape(batch, slen, num_key_value_heads * n_rep, head_dim)
501
+
502
+
503
+ def repeat_kv2(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
504
+ """
505
+ This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
506
+ num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
507
+ """
508
+ batch, num_key_value_heads, slen, head_dim = hidden_states.shape
509
+ if n_rep == 1:
510
+ return hidden_states
511
+ hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
512
+ return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
513
+
514
+
515
+ def eager_attention_forward(
516
+ module: nn.Module,
517
+ query: torch.Tensor,
518
+ key: torch.Tensor,
519
+ value: torch.Tensor,
520
+ attention_mask: Optional[torch.Tensor],
521
+ scaling: float,
522
+ dropout: float = 0.0,
523
+ **kwargs: Unpack[TransformersKwargs],
524
+ ):
525
+ key_states = repeat_kv2(key, module.num_key_value_groups)
526
+ value_states = repeat_kv2(value, module.num_key_value_groups)
527
+
528
+ attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
529
+ if attention_mask is not None:
530
+ causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
531
+ attn_weights = attn_weights + causal_mask
532
+
533
+ attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
534
+ attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
535
+ attn_output = torch.matmul(attn_weights, value_states)
536
+ attn_output = attn_output.transpose(1, 2).contiguous()
537
+
538
+ return attn_output, attn_weights
539
+
540
+
541
+ def apply_rotary_pos_emb_interleave(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
542
+ r"""
543
+ TODO let's just use the original freqcis computation to not have the view
544
+ transpose + reshape! This is not optimized!
545
+ Applies Rotary Position Embedding to the query and key tensors.
546
+
547
+ Args:
548
+ q (`torch.Tensor`): The query tensor.
549
+ k (`torch.Tensor`): The key tensor.
550
+ cos (`torch.Tensor`): The cosine part of the rotary embedding.
551
+ sin (`torch.Tensor`): The sine part of the rotary embedding.
552
+ position_ids (`torch.Tensor`):
553
+ The position indices of the tokens corresponding to the query and key tensors. For example, this can be
554
+ used to pass offsetted position ids when working with a KV-cache.
555
+ unsqueeze_dim (`int`, *optional*, defaults to 1):
556
+ The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
557
+ sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
558
+ that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
559
+ k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
560
+ cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
561
+ the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
562
+ Returns:
563
+ `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
564
+ """
565
+ cos = cos.unsqueeze(unsqueeze_dim)
566
+ sin = sin.unsqueeze(unsqueeze_dim)
567
+
568
+ b, h, s, d = q.shape
569
+ q = q.view(b, h, s, d // 2, 2).transpose(4, 3).reshape(b, h, s, d)
570
+
571
+ b, h, s, d = k.shape
572
+ k = k.view(b, h, s, d // 2, 2).transpose(4, 3).reshape(b, h, s, d)
573
+
574
+ q_embed = (q * cos) + (rotate_half(q) * sin)
575
+ k_embed = (k * cos) + (rotate_half(k) * sin)
576
+ return q_embed, k_embed
577
+
578
+
579
+ def yarn_get_mscale(scale=1, mscale=1):
580
+ if scale <= 1:
581
+ return 1.0
582
+ return 0.1 * mscale * math.log(scale) + 1.0
583
+
584
+
585
+ class BailingMoeV3MultiLatentAttention(nn.Module):
586
+ """Multi-headed attention from 'Attention Is All You Need' paper"""
587
+
588
+ def __init__(self, config: BailingMoeV3Config, layer_idx: int):
589
+ super().__init__()
590
+ self.config = config
591
+ self.layer_idx = layer_idx
592
+ self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
593
+ self.attention_dropout = config.attention_dropout
594
+ self.num_heads = config.num_attention_heads
595
+ self.rope_theta = config.rope_theta
596
+ self.q_lora_rank = config.q_lora_rank
597
+ self.qk_rope_head_dim = config.qk_rope_head_dim
598
+ self.kv_lora_rank = config.kv_lora_rank
599
+ self.v_head_dim = config.v_head_dim
600
+ self.qk_nope_head_dim = config.qk_nope_head_dim
601
+ self.qk_head_dim = config.qk_head_dim
602
+ self.gated_attention_proj_granularity_type = config.gated_attention_proj_granularity_type
603
+
604
+ self.is_causal = True
605
+ if self.q_lora_rank is None:
606
+ self.q_proj = nn.Linear(config.hidden_size, self.num_heads * self.qk_head_dim, bias=False)
607
+ else:
608
+ self.q_a_proj = nn.Linear(config.hidden_size, config.q_lora_rank, bias=config.use_qkv_bias)
609
+ self.q_a_layernorm = BailingMoeV3RMSNorm(config.q_lora_rank)
610
+ self.q_b_proj = nn.Linear(config.q_lora_rank, self.num_heads * self.qk_head_dim, bias=False)
611
+
612
+ self.kv_a_proj_with_mqa = nn.Linear(
613
+ config.hidden_size,
614
+ self.kv_lora_rank + self.qk_rope_head_dim,
615
+ bias=config.use_qkv_bias,
616
+ )
617
+ self.kv_a_layernorm = BailingMoeV3RMSNorm(self.kv_lora_rank)
618
+ self.kv_b_proj = nn.Linear(
619
+ self.kv_lora_rank,
620
+ self.num_heads * (self.qk_nope_head_dim + self.v_head_dim),
621
+ bias=False,
622
+ )
623
+ if self.gated_attention_proj_granularity_type is None:
624
+ self.g_proj = None
625
+ elif self.gated_attention_proj_granularity_type == "head_wise":
626
+ self.g_proj = nn.Linear(config.hidden_size, self.num_heads, bias=False)
627
+ elif self.gated_attention_proj_granularity_type == "element_wise":
628
+ self.g_proj = nn.Linear(config.hidden_size, self.num_heads * self.v_head_dim, bias=False)
629
+
630
+ self.dense = nn.Linear(
631
+ self.num_heads * self.v_head_dim,
632
+ config.hidden_size,
633
+ bias=config.use_qkv_bias,
634
+ )
635
+
636
+ self.scaling = self.qk_head_dim ** (-0.5)
637
+ if self.config.rope_scaling is not None:
638
+ mscale_all_dim = self.config.rope_scaling.get("mscale_all_dim", 0)
639
+ scaling_factor = self.config.rope_scaling["factor"]
640
+ if mscale_all_dim:
641
+ mscale = yarn_get_mscale(scaling_factor, mscale_all_dim)
642
+ self.scaling = self.scaling * mscale * mscale
643
+
644
+ @deprecate_kwarg("past_key_value", new_name="past_key_values", version="4.58")
645
+ def forward(
646
+ self,
647
+ hidden_states: torch.Tensor,
648
+ position_embeddings: tuple[torch.Tensor, torch.Tensor],
649
+ attention_mask: Optional[torch.Tensor],
650
+ past_key_values: Optional[Cache] = None,
651
+ cache_position: Optional[torch.LongTensor] = None,
652
+ **kwargs: Unpack[FlashAttentionKwargs],
653
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor], Optional[tuple[torch.Tensor]]]:
654
+
655
+ batch_size, seq_length = hidden_states.shape[:-1]
656
+ query_shape = (batch_size, seq_length, -1, self.qk_head_dim)
657
+ key_shape = (batch_size, seq_length, -1, self.qk_nope_head_dim + self.v_head_dim)
658
+
659
+ if self.q_lora_rank is None:
660
+ q_states = self.q_proj(hidden_states)
661
+ else:
662
+ q_states = self.q_b_proj(self.q_a_layernorm(self.q_a_proj(hidden_states)))
663
+ q_states = q_states.view(query_shape).transpose(1, 2)
664
+ q_pass, q_rot = torch.split(q_states, [self.qk_nope_head_dim, self.qk_rope_head_dim], dim=-1)
665
+
666
+ compressed_kv = self.kv_a_proj_with_mqa(hidden_states)
667
+ k_pass, k_rot = torch.split(compressed_kv, [self.kv_lora_rank, self.qk_rope_head_dim], dim=-1)
668
+
669
+ k_pass = self.kv_b_proj(self.kv_a_layernorm(k_pass)).view(key_shape).transpose(1, 2)
670
+ k_pass, value_states = torch.split(k_pass, [self.qk_nope_head_dim, self.v_head_dim], dim=-1)
671
+
672
+ k_rot = k_rot.view(batch_size, 1, seq_length, self.qk_rope_head_dim)
673
+
674
+ cos, sin = position_embeddings # tptest
675
+ if self.config.rope_interleave: # support using interleaved weights for efficiency
676
+ q_rot, k_rot = apply_rotary_pos_emb_interleave(q_rot, k_rot, cos, sin)
677
+ else:
678
+ x = 1 / 0
679
+ q_rot, k_rot = apply_rotary_pos_emb(q_rot, k_rot, cos, sin)
680
+ k_rot = k_rot.expand(*k_pass.shape[:-1], -1)
681
+
682
+ query_states = torch.cat((q_pass, q_rot), dim=-1)
683
+ key_states = torch.cat((k_pass, k_rot), dim=-1)
684
+
685
+ if past_key_values is not None:
686
+ # sin and cos are specific to RoPE models; cache_position needed for the static cache
687
+ cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
688
+ key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx, cache_kwargs)
689
+
690
+ if self.config._attn_implementation == "flash_attention_2" and self.qk_head_dim != self.v_head_dim:
691
+ value_states = F.pad(value_states, [0, self.qk_head_dim - self.v_head_dim])
692
+
693
+ attention_interface: Callable = eager_attention_forward
694
+
695
+ attn_output, attn_weights = attention_interface(
696
+ self,
697
+ query_states,
698
+ key_states,
699
+ value_states,
700
+ attention_mask,
701
+ dropout=0.0 if not self.training else self.attention_dropout,
702
+ scaling=self.scaling,
703
+ **kwargs,
704
+ )
705
+
706
+ if self.config._attn_implementation == "flash_attention_2" and self.qk_head_dim != self.v_head_dim:
707
+ attn_output = attn_output[:, :, :, : self.v_head_dim]
708
+
709
+ if self.g_proj is not None:
710
+ gate = self.g_proj(hidden_states)
711
+ gate = F.sigmoid(gate.float()).type_as(hidden_states)
712
+ if self.gated_attention_proj_granularity_type == "head_wise":
713
+ attn_output = attn_output * gate[:, :, :, None]
714
+ else:
715
+ attn_output = attn_output * gate.view(batch_size, seq_length, self.num_heads, self.v_head_dim)
716
+
717
+ attn_output = attn_output.reshape(batch_size, seq_length, -1).contiguous()
718
+ attn_output = self.dense(attn_output)
719
+ return attn_output, attn_weights, past_key_values
720
+
721
+
722
+ class BailingMoeV3KimiDeltaAttention(nn.Module):
723
+ def __init__(self, config: BailingMoeV3Config, layer_idx: int):
724
+ super().__init__()
725
+ self.config = config
726
+ self.mode = "chunk"
727
+
728
+ self.hidden_size = config.hidden_size
729
+ self.conv_size = config.short_conv_kernel_size
730
+ self.head_dim = config.head_dim
731
+ self.num_heads = config.num_attention_heads
732
+ self.head_k_dim = self.head_dim
733
+ self.num_k_heads = self.num_heads
734
+ self.no_kda_lora = config.no_kda_lora
735
+ self.safe_gate = config.kda_safe_gate
736
+ self.lower_bound = config.kda_lower_bound
737
+
738
+ self.layer_idx = layer_idx
739
+
740
+ assert self.mode in ['chunk', 'fused_recurrent'], f"Not suppoerted mode `{self.mode}`."
741
+
742
+ projection_k_size = self.head_k_dim * self.num_k_heads
743
+ projection_size = self.head_dim * self.num_heads
744
+
745
+ self.q_proj = nn.Linear(self.hidden_size, projection_k_size, bias=False)
746
+ self.k_proj = nn.Linear(self.hidden_size, projection_k_size, bias=False)
747
+ self.v_proj = nn.Linear(self.hidden_size, projection_size, bias=False)
748
+
749
+ self.q_conv1d = ShortConvolution(
750
+ hidden_size=projection_k_size,
751
+ kernel_size=self.conv_size,
752
+ activation='silu',
753
+ )
754
+ self.k_conv1d = ShortConvolution(
755
+ hidden_size=projection_k_size,
756
+ kernel_size=self.conv_size,
757
+ activation='silu',
758
+ )
759
+ self.v_conv1d = ShortConvolution(
760
+ hidden_size=projection_size,
761
+ kernel_size=self.conv_size,
762
+ activation='silu',
763
+ )
764
+
765
+ self.A_log = torch.nn.Parameter(torch.log(torch.empty(self.num_heads, dtype=torch.float32).uniform_(1, 16)))
766
+
767
+ if self.no_kda_lora:
768
+ self.f_proj = nn.Linear(self.hidden_size, projection_size, bias=False)
769
+ else:
770
+ self.f_a_proj = nn.Linear(self.hidden_size, self.head_dim, bias=False)
771
+ self.f_b_proj = nn.Linear(self.head_dim, projection_size, bias=False)
772
+
773
+ self.dt_bias = nn.Parameter(torch.empty(projection_size, dtype=torch.float32))
774
+
775
+ self.b_proj = nn.Linear(self.hidden_size, self.num_heads, bias=False)
776
+
777
+ if self.no_kda_lora:
778
+ self.g_proj = nn.Linear(self.hidden_size, projection_size, bias=False)
779
+ else:
780
+ self.g_a_proj = nn.Linear(self.hidden_size, self.head_dim, bias=False)
781
+ self.g_b_proj = nn.Linear(self.head_dim, projection_size, bias=False)
782
+
783
+ self.o_norm = FusedRMSNormGated(self.head_dim, eps=config.rms_norm_eps, activation='sigmoid')
784
+ self.o_proj = nn.Linear(projection_size, self.hidden_size, bias=False)
785
+
786
+ def forward(
787
+ self,
788
+ hidden_states: torch.Tensor,
789
+ attention_mask: torch.Tensor | None = None,
790
+ past_key_value=None,
791
+ **kwargs: Unpack[dict],
792
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
793
+ attention_mask = None
794
+ if attention_mask is not None:
795
+ if attention_mask.dim() != 2:
796
+ attention_mask = kwargs.get("padding_mask")
797
+
798
+ if attention_mask is not None and attention_mask.dim() != 2:
799
+ raise ValueError(
800
+ "attention_mask must be a 0-1 matrix of shape [batch_size, seq_len] "
801
+ "(0 = padding). 3D masks are not supported here.",
802
+ )
803
+ use_cache = past_key_value is not None
804
+ batch_size, q_len, _ = hidden_states.shape
805
+ mode = 'fused_recurrent' if q_len <= 64 else self.mode
806
+ if self.training:
807
+ assert mode == 'chunk', "Only chunk mode is supported in training."
808
+
809
+ cu_seqlens = kwargs.get('cu_seqlens')
810
+ indices = None
811
+ if attention_mask is not None:
812
+ indices, cu_seqlens, _ = _get_unpad_data(attention_mask[:, -q_len:])
813
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
814
+
815
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
816
+ recurrent_state = None
817
+
818
+ if past_key_value is not None and isinstance(past_key_value, Cache):
819
+ # ensure the cache list is long enough
820
+ while len(past_key_value.layers) <= self.layer_idx:
821
+ past_key_value.layers.append(DynamicLayer())
822
+
823
+ if past_key_value.layers[self.layer_idx].keys is not None:
824
+ recurrent_state = past_key_value.layers[self.layer_idx].keys
825
+ # ensure recurrent_state is on the same device as hidden_states
826
+ if recurrent_state.device != hidden_states.device:
827
+ recurrent_state = recurrent_state.to(hidden_states.device).contiguous()
828
+
829
+ if past_key_value.layers[self.layer_idx].values is not None:
830
+ conv_state_q, conv_state_k, conv_state_v = past_key_value.layers[self.layer_idx].values
831
+
832
+ q, conv_state_q = self.q_conv1d(
833
+ x=self.q_proj(hidden_states),
834
+ cache=conv_state_q,
835
+ output_final_state=use_cache,
836
+ cu_seqlens=cu_seqlens,
837
+ )
838
+ k, conv_state_k = self.k_conv1d(
839
+ x=self.k_proj(hidden_states),
840
+ cache=conv_state_k,
841
+ output_final_state=use_cache,
842
+ cu_seqlens=cu_seqlens,
843
+ )
844
+ v, conv_state_v = self.v_conv1d(
845
+ x=self.v_proj(hidden_states),
846
+ cache=conv_state_v,
847
+ output_final_state=use_cache,
848
+ cu_seqlens=cu_seqlens,
849
+ )
850
+
851
+ if self.no_kda_lora:
852
+ g = self.f_proj(hidden_states)
853
+ else:
854
+ g = self.f_b_proj(self.f_a_proj(hidden_states))
855
+
856
+ beta = self.b_proj(hidden_states).float().sigmoid()
857
+
858
+ q, k = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_k_dim), (q, k))
859
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
860
+ g = rearrange(g, '... (h d) -> ... h d', d=self.head_dim)
861
+
862
+ if mode == 'chunk':
863
+ o, recurrent_state = chunk_kda(
864
+ q=q,
865
+ k=k,
866
+ v=v,
867
+ g=g,
868
+ beta=beta,
869
+ A_log=self.A_log,
870
+ dt_bias=self.dt_bias,
871
+ initial_state=recurrent_state,
872
+ output_final_state=True,
873
+ use_qk_l2norm_in_kernel=True,
874
+ use_gate_in_kernel=True,
875
+ safe_gate=self.safe_gate,
876
+ lower_bound=self.lower_bound,
877
+ cu_seqlens=cu_seqlens,
878
+ )
879
+ else:
880
+ o, recurrent_state = fused_recurrent_kda(
881
+ q=q,
882
+ k=k,
883
+ v=v,
884
+ g=g,
885
+ beta=beta,
886
+ A_log=self.A_log,
887
+ dt_bias=self.dt_bias,
888
+ initial_state=recurrent_state,
889
+ output_final_state=True,
890
+ use_qk_l2norm_in_kernel=True,
891
+ use_gate_in_kernel=True,
892
+ lower_bound=self.lower_bound,
893
+ cu_seqlens=cu_seqlens,
894
+ )
895
+
896
+ if use_cache and past_key_value is not None and isinstance(past_key_value, Cache):
897
+ target_device = None
898
+ for cache in past_key_value.layers:
899
+ if cache.keys is not None:
900
+ target_device = cache.keys.device
901
+ break
902
+ if target_device is None:
903
+ target_device = recurrent_state.device
904
+
905
+ # move to target device
906
+ if recurrent_state.device != target_device:
907
+ recurrent_state = recurrent_state.to(target_device)
908
+
909
+ past_key_value.layers[self.layer_idx].keys = recurrent_state
910
+ past_key_value.layers[self.layer_idx].values = (conv_state_q, conv_state_k, conv_state_v)
911
+
912
+ if self.no_kda_lora:
913
+ g = self.g_proj(hidden_states)
914
+ else:
915
+ g = self.g_b_proj(self.g_a_proj(hidden_states))
916
+ g = rearrange(g, '... (h d) -> ... h d', d=self.head_dim)
917
+ o = self.o_norm(o, g)
918
+
919
+ o = rearrange(o, 'b t h d -> b t (h d)')
920
+ o = self.o_proj(o)
921
+ if attention_mask is not None:
922
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
923
+
924
+ return o, None, past_key_value
925
+
926
+
927
+ class BailingMoeV3MTPLayer(nn.Module):
928
+ def __init__(self, config: BailingMoeV3Config, layer_idx: int):
929
+ super().__init__()
930
+ self.layer_idx = layer_idx
931
+ self.input_layernorm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
932
+ self.enorm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
933
+
934
+ self.eh_proj = nn.Linear(config.hidden_size * 2, config.hidden_size, bias=False)
935
+ self.post_attention_layernorm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
936
+ self.attention = BailingMoeV3MultiLatentAttention(config=config, layer_idx=layer_idx)
937
+ self.mlp = BailingMoeV3SparseMoeBlock(config)
938
+
939
+ self.hnorm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
940
+ self.final_layernorm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
941
+
942
+ def forward(
943
+ self,
944
+ input_embeds,
945
+ hidden_states: torch.Tensor,
946
+ attention_mask: Optional[torch.Tensor] = None,
947
+ position_ids: Optional[torch.LongTensor] = None,
948
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
949
+ output_attentions: Optional[bool] = False,
950
+ output_router_logits: Optional[bool] = False,
951
+ use_cache: Optional[bool] = False,
952
+ position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, # necessary, but kept here for BC
953
+ **kwargs,
954
+ ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
955
+ input_embeds = self.enorm(input_embeds)
956
+ hidden_states = self.hnorm(hidden_states)
957
+ hidden_states = self.eh_proj(torch.cat([input_embeds, hidden_states], dim=-1))
958
+ residual = hidden_states
959
+
960
+ hidden_states = self.input_layernorm(hidden_states)
961
+
962
+ # Self Attention
963
+ hidden_states, self_attn_weights, present_key_value = self.attention(
964
+ hidden_states=hidden_states,
965
+ attention_mask=attention_mask,
966
+ position_ids=position_ids,
967
+ past_key_value=past_key_value,
968
+ output_attentions=output_attentions,
969
+ position_embeddings=position_embeddings,
970
+ use_cache=use_cache,
971
+ )
972
+ hidden_states = residual + hidden_states
973
+
974
+ # Fully Connected
975
+ residual = hidden_states
976
+ hidden_states = self.post_attention_layernorm(hidden_states)
977
+ hidden_states = self.mlp(hidden_states)
978
+ if isinstance(hidden_states, tuple):
979
+ hidden_states, router_logits = hidden_states
980
+ else:
981
+ router_logits = None
982
+ hidden_states = residual + hidden_states.to(residual.device)
983
+ hidden_states = self.final_layernorm(hidden_states)
984
+
985
+ outputs = (hidden_states,)
986
+
987
+ if output_attentions:
988
+ outputs += (self_attn_weights,)
989
+
990
+ if use_cache:
991
+ outputs += (present_key_value,)
992
+
993
+ if output_router_logits:
994
+ outputs += (router_logits,)
995
+
996
+ return outputs
997
+
998
+
999
+ class BailingMoeV3DecoderLayer(nn.Module):
1000
+ def __init__(self, config: BailingMoeV3Config, layer_idx: int):
1001
+ super().__init__()
1002
+ self.hidden_size = config.hidden_size
1003
+ self.layer_idx = layer_idx
1004
+ self.attention_layer_type = (
1005
+ "attention"
1006
+ if (layer_idx + 1) % config.layer_group_size == 0
1007
+ or layer_idx >= config.num_hidden_layers // config.layer_group_size * config.layer_group_size
1008
+ else "linear_attention"
1009
+ )
1010
+
1011
+ if self.attention_layer_type == "attention":
1012
+ self.attention = BailingMoeV3MultiLatentAttention(config=config, layer_idx=layer_idx)
1013
+ else:
1014
+ self.attention = BailingMoeV3KimiDeltaAttention(config=config, layer_idx=layer_idx)
1015
+
1016
+ self.mlp = (
1017
+ BailingMoeV3SparseMoeBlock(config)
1018
+ if (config.num_experts is not None and layer_idx >= config.first_k_dense_replace)
1019
+ else BailingMoeV3MLP(config=config, intermediate_size=config.intermediate_size)
1020
+ )
1021
+ self.input_layernorm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1022
+ self.post_attention_layernorm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1023
+
1024
+ def forward(
1025
+ self,
1026
+ hidden_states: torch.Tensor,
1027
+ attention_mask: Optional[torch.Tensor] = None,
1028
+ position_ids: Optional[torch.LongTensor] = None,
1029
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
1030
+ cache_position: Optional[torch.LongTensor] = None,
1031
+ output_attentions: Optional[bool] = False,
1032
+ output_router_logits: Optional[bool] = False,
1033
+ use_cache: Optional[bool] = False,
1034
+ position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, # necessary, but kept here for BC
1035
+ **kwargs,
1036
+ ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
1037
+ """
1038
+ Args:
1039
+ hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
1040
+ attention_mask (`torch.FloatTensor`, *optional*):
1041
+ attention mask of size `(batch_size, sequence_length)` if flash attention is used or `(batch_size, 1,
1042
+ query_sequence_length, key_sequence_length)` if default attention is used.
1043
+ position_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
1044
+ Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0,
1045
+ config.n_positions - 1]`.
1046
+ past_key_value (`Tuple(torch.FloatTensor)`, *optional*):
1047
+ cached past key and value projection states
1048
+ output_attentions (`bool`, *optional*):
1049
+ Whether to return the attentions tensors of all attention layers. See `attentions` under
1050
+ returned tensors for more detail.
1051
+ output_router_logits (`bool`, *optional*):
1052
+ Whether or not to return the logits of all the routers. They are useful for computing the router loss,
1053
+ and should not be returned during inference.
1054
+ use_cache (`bool`, *optional*):
1055
+ If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
1056
+ (see `past_key_values`).
1057
+ """
1058
+ residual = hidden_states
1059
+
1060
+ hidden_states = self.input_layernorm(hidden_states)
1061
+
1062
+ # Self Attention
1063
+ if self.attention_layer_type == "attention":
1064
+ hidden_states, self_attn_weights, present_key_value = self.attention(
1065
+ hidden_states=hidden_states,
1066
+ attention_mask=attention_mask,
1067
+ position_ids=position_ids,
1068
+ past_key_values=past_key_value,
1069
+ use_cache=use_cache,
1070
+ cache_position=cache_position, #
1071
+ position_embeddings=position_embeddings, #
1072
+ **kwargs,
1073
+ )
1074
+ else:
1075
+ batch_size, seq_len = hidden_states.shape[0], hidden_states.shape[1]
1076
+ device = hidden_states.device
1077
+
1078
+ if attention_mask is None:
1079
+ # if attention_mask is None, create a full mask
1080
+ attention_mask = torch.ones((batch_size, seq_len), dtype=torch.int32, device=device)
1081
+ elif attention_mask.dim() == 4 and attention_mask.shape[1] == 1:
1082
+ attention_mask = attention_mask[:, 0, -1, :].to(torch.int32)
1083
+ attention_mask = (attention_mask > -1e4).to(torch.int32)
1084
+ elif attention_mask.dim() == 2:
1085
+ attention_mask = attention_mask.to(torch.int32)
1086
+ else:
1087
+ raise ValueError(f"Unsupported mask dimension: {attention_mask.shape}")
1088
+
1089
+ hidden_states, self_attn_weights, present_key_value = self.attention(
1090
+ hidden_states=hidden_states,
1091
+ attention_mask=attention_mask,
1092
+ past_key_value=past_key_value,
1093
+ position_ids=position_ids,
1094
+ use_cache=use_cache,
1095
+ output_attentions=output_attentions,
1096
+ )
1097
+
1098
+ hidden_states = residual + hidden_states
1099
+
1100
+ # Fully Connected
1101
+ residual = hidden_states
1102
+ hidden_states = self.post_attention_layernorm(hidden_states)
1103
+ hidden_states = self.mlp(hidden_states)
1104
+ if isinstance(hidden_states, tuple):
1105
+ hidden_states, router_logits = hidden_states
1106
+ else:
1107
+ router_logits = None
1108
+ hidden_states = residual + hidden_states.to(residual.device)
1109
+
1110
+ outputs = (hidden_states,)
1111
+
1112
+ if output_attentions:
1113
+ outputs += (self_attn_weights,)
1114
+
1115
+ if use_cache:
1116
+ outputs += (present_key_value,)
1117
+
1118
+ if output_router_logits:
1119
+ outputs += (router_logits,)
1120
+
1121
+ return outputs
1122
+
1123
+
1124
+ BAILINGMOEV3_START_DOCSTRING = r"""
1125
+ This model inherits from [`PreTrainedModel`]. Check the superclass documentation for the generic methods the
1126
+ library implements for all its model (such as downloading or saving, resizing the input embeddings, pruning heads
1127
+ etc.)
1128
+ This model is also a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass.
1129
+ Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage
1130
+ and behavior.
1131
+ Parameters:
1132
+ config ([`BailingMoeV3Config`]):
1133
+ Model configuration class with all the parameters of the model. Initializing with a config file does not
1134
+ load the weights associated with the model, only the configuration. Check out the
1135
+ [`~PreTrainedModel.from_pretrained`] method to load the model weights.
1136
+ """
1137
+
1138
+
1139
+ @add_start_docstrings(
1140
+ "The bare BailingMoeV3 Model outputting raw hidden-states without any specific head on top.",
1141
+ BAILINGMOEV3_START_DOCSTRING,
1142
+ )
1143
+ class BailingMoeV3PreTrainedModel(PreTrainedModel):
1144
+ config_class = BailingMoeV3Config
1145
+ base_model_prefix = "model"
1146
+ supports_gradient_checkpointing = True
1147
+ _no_split_modules = ["BailingMoeV3DecoderLayer"]
1148
+ _skip_keys_device_placement = "past_key_values"
1149
+ _supports_flash_attn_2 = True
1150
+ _supports_sdpa = True
1151
+ _supports_cache_class = True
1152
+
1153
+ def _init_weights(self, module):
1154
+ std = self.config.initializer_range
1155
+ if isinstance(module, nn.Linear):
1156
+ module.weight.data.normal_(mean=0.0, std=std)
1157
+ if module.bias is not None:
1158
+ module.bias.data.zero_()
1159
+ elif isinstance(module, nn.Embedding):
1160
+ module.weight.data.normal_(mean=0.0, std=std)
1161
+ if module.padding_idx is not None:
1162
+ module.weight.data[module.padding_idx].zero_()
1163
+
1164
+
1165
+ BAILINGMOEV3_INPUTS_DOCSTRING = r"""
1166
+ Args:
1167
+ input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`):
1168
+ Indices of input sequence tokens in the vocabulary. Padding will be ignored by default should you provide
1169
+ it.
1170
+ Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
1171
+ [`PreTrainedTokenizer.__call__`] for details.
1172
+ [What are input IDs?](../glossary#input-ids)
1173
+ attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
1174
+ Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`:
1175
+ - 1 for tokens that are **not masked**,
1176
+ - 0 for tokens that are **masked**.
1177
+ [What are attention masks?](../glossary#attention-mask)
1178
+ Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
1179
+ [`PreTrainedTokenizer.__call__`] for details.
1180
+ If `past_key_values` is used, optionally only the last `input_ids` have to be input (see
1181
+ `past_key_values`).
1182
+ If you want to change padding behavior, you should read [`modeling_opt._prepare_decoder_attention_mask`]
1183
+ and modify to your needs. See diagram 1 in [the paper](https://arxiv.org/abs/1910.13461) for more
1184
+ information on the default strategy.
1185
+ - 1 indicates the head is **not masked**,
1186
+ - 0 indicates the head is **masked**.
1187
+ position_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
1188
+ Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0,
1189
+ config.n_positions - 1]`.
1190
+ [What are position IDs?](../glossary#position-ids)
1191
+ past_key_values (`Cache` or `tuple(tuple(torch.FloatTensor))`, *optional*):
1192
+ Pre-computed hidden-states (key and values in the self-attention blocks and in the cross-attention
1193
+ blocks) that can be used to speed up sequential decoding. This typically consists in the `past_key_values`
1194
+ returned by the model at a previous stage of decoding, when `use_cache=True` or `config.use_cache=True`.
1195
+ Two formats are allowed:
1196
+ - a [`~cache_utils.Cache`] instance;
1197
+ - Tuple of `tuple(torch.FloatTensor)` of length `config.n_layers`, with each tuple having 2 tensors of
1198
+ shape `(batch_size, num_heads, sequence_length, embed_size_per_head)`). This is also known as the legacy
1199
+ cache format.
1200
+ The model will output the same cache format that is fed as input. If no `past_key_values` are passed, the
1201
+ legacy cache format will be returned.
1202
+ If `past_key_values` are used, the user can optionally input only the last `input_ids` (those that don't
1203
+ have their past key value states given to this model) of shape `(batch_size, 1)` instead of all `input_ids`
1204
+ of shape `(batch_size, sequence_length)`.
1205
+ inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
1206
+ Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This
1207
+ is useful if you want more control over how to convert `input_ids` indices into associated vectors than the
1208
+ model's internal embedding lookup matrix.
1209
+ use_cache (`bool`, *optional*):
1210
+ If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding (see
1211
+ `past_key_values`).
1212
+ output_attentions (`bool`, *optional*):
1213
+ Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned
1214
+ tensors for more detail.
1215
+ output_hidden_states (`bool`, *optional*):
1216
+ Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for
1217
+ more detail.
1218
+ return_dict (`bool`, *optional*):
1219
+ Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
1220
+ """
1221
+
1222
+
1223
+ @add_start_docstrings(
1224
+ "The bare BailingMoeV3 Model outputting raw hidden-states without any specific head on top.",
1225
+ BAILINGMOEV3_START_DOCSTRING,
1226
+ )
1227
+ class BailingMoeV3Model(BailingMoeV3PreTrainedModel):
1228
+ """
1229
+ Transformer decoder consisting of *config.num_hidden_layers* layers. Each layer is a [`BailingMoeV3DecoderLayer`]
1230
+ Args:
1231
+ config: BailingMoeV3Config
1232
+ """
1233
+
1234
+ def __init__(self, config: BailingMoeV3Config):
1235
+ super().__init__(config)
1236
+ self.padding_idx = config.pad_token_id
1237
+ self.vocab_size = config.vocab_size
1238
+ self.num_nextn_predict_layers = config.num_nextn_predict_layers
1239
+
1240
+ self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
1241
+ self.layers = []
1242
+ for layer_idx in range(config.num_hidden_layers + config.num_nextn_predict_layers):
1243
+ layer_cls = BailingMoeV3DecoderLayer if layer_idx < config.num_hidden_layers else BailingMoeV3MTPLayer
1244
+ self.layers.append(layer_cls(config, layer_idx))
1245
+
1246
+ self.layers = nn.ModuleList(self.layers)
1247
+
1248
+ self._use_sdpa = config._attn_implementation == "sdpa"
1249
+ self._use_flash_attention_2 = config._attn_implementation == "flash_attention_2"
1250
+ self.norm = BailingMoeV3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1251
+ self.rotary_emb = BailingMoeV3RotaryEmbedding(config=config)
1252
+ self.gradient_checkpointing = False
1253
+ # Initialize weights and apply final processing
1254
+ self.post_init()
1255
+
1256
+ def get_input_embeddings(self):
1257
+ return self.word_embeddings
1258
+
1259
+ def set_input_embeddings(self, value):
1260
+ self.word_embeddings = value
1261
+
1262
+ @add_start_docstrings_to_model_forward(BAILINGMOEV3_INPUTS_DOCSTRING)
1263
+ def forward(
1264
+ self,
1265
+ input_ids: torch.LongTensor = None,
1266
+ attention_mask: Optional[torch.Tensor] = None,
1267
+ position_ids: Optional[torch.LongTensor] = None,
1268
+ past_key_values: Optional[List[torch.FloatTensor]] = None,
1269
+ inputs_embeds: Optional[torch.FloatTensor] = None,
1270
+ cache_position: Optional[torch.LongTensor] = None,
1271
+ use_cache: Optional[bool] = None,
1272
+ output_attentions: Optional[bool] = None,
1273
+ output_hidden_states: Optional[bool] = None,
1274
+ output_router_logits: Optional[bool] = None,
1275
+ return_dict: Optional[bool] = None,
1276
+ **kwargs,
1277
+ ) -> Union[Tuple, MoeV3ModelOutputWithPast]:
1278
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1279
+ output_hidden_states = (
1280
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1281
+ )
1282
+ output_router_logits = (
1283
+ output_router_logits if output_router_logits is not None else self.config.output_router_logits
1284
+ )
1285
+ use_cache = use_cache if use_cache is not None else self.config.use_cache
1286
+
1287
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
1288
+
1289
+ # retrieve input_ids and inputs_embeds
1290
+ if input_ids is not None and inputs_embeds is not None:
1291
+ raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
1292
+ elif input_ids is not None:
1293
+ batch_size, seq_length = input_ids.shape[:2]
1294
+ elif inputs_embeds is not None:
1295
+ batch_size, seq_length = inputs_embeds.shape[:2]
1296
+ else:
1297
+ raise ValueError("You have to specify either input_ids or inputs_embeds")
1298
+
1299
+ if self.gradient_checkpointing and self.training:
1300
+ if use_cache:
1301
+ logger.warning_once(
1302
+ "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`transformers."
1303
+ )
1304
+ use_cache = False
1305
+
1306
+ if use_cache and past_key_values is None:
1307
+ past_key_values = DynamicCache()
1308
+
1309
+ if inputs_embeds is None:
1310
+ inputs_embeds = self.word_embeddings(input_ids)
1311
+
1312
+ if cache_position is None:
1313
+ past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
1314
+ cache_position: torch.Tensor = torch.arange(
1315
+ past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
1316
+ )
1317
+
1318
+ if position_ids is None:
1319
+ position_ids = cache_position.unsqueeze(0)
1320
+
1321
+ softmax_attention_layer_id = self.config.layer_group_size - 1
1322
+ past_seen_tokens = (
1323
+ past_key_values.get_seq_length(layer_idx=softmax_attention_layer_id) if past_key_values is not None else 0
1324
+ )
1325
+
1326
+ if position_ids is None:
1327
+ position_ids = torch.arange(
1328
+ past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
1329
+ )
1330
+ position_ids = position_ids.unsqueeze(0)
1331
+
1332
+ if self._use_flash_attention_2:
1333
+ # 2d mask is passed through the layers
1334
+ attention_mask = attention_mask if (attention_mask is not None and 0 in attention_mask) else None
1335
+ elif self._use_sdpa and not output_attentions:
1336
+ # output_attentions=True can not be supported when using SDPA, and we fall back on
1337
+ # the manual implementation that requires a 4D causal mask in all cases.
1338
+ attention_mask = _prepare_4d_causal_attention_mask_for_sdpa(
1339
+ attention_mask,
1340
+ (batch_size, seq_length),
1341
+ inputs_embeds,
1342
+ past_seen_tokens,
1343
+ )
1344
+ else:
1345
+ # 4d mask is passed through the layers
1346
+ attention_mask = _prepare_4d_causal_attention_mask(
1347
+ attention_mask, (batch_size, seq_length), inputs_embeds, past_seen_tokens
1348
+ )
1349
+
1350
+ # embed positions
1351
+ hidden_states = inputs_embeds
1352
+
1353
+ # create position embeddings to be shared across the decoder layers
1354
+ position_embeddings = self.rotary_emb(hidden_states, position_ids)
1355
+
1356
+ # decoder layers
1357
+ all_hidden_states = () if output_hidden_states else None
1358
+ all_self_attns = () if output_attentions else None
1359
+ all_router_logits = () if output_router_logits else None
1360
+ next_decoder_cache = None
1361
+ layers = self.layers[: -self.num_nextn_predict_layers] if self.num_nextn_predict_layers > 0 else self.layers
1362
+ mtp_layers = self.layers[-self.num_nextn_predict_layers :] if self.num_nextn_predict_layers > 0 else None
1363
+
1364
+ # tptest miss causal_mask = create_causal_mask(
1365
+
1366
+ for decoder_layer in layers:
1367
+ if output_hidden_states:
1368
+ all_hidden_states += (hidden_states,)
1369
+
1370
+ if self.gradient_checkpointing and self.training:
1371
+ layer_outputs = self._gradient_checkpointing_func(
1372
+ decoder_layer.__call__,
1373
+ hidden_states,
1374
+ attention_mask,
1375
+ position_ids,
1376
+ past_key_values,
1377
+ cache_position,
1378
+ output_attentions,
1379
+ output_router_logits,
1380
+ use_cache,
1381
+ position_embeddings,
1382
+ )
1383
+ else:
1384
+ layer_outputs = decoder_layer(
1385
+ hidden_states,
1386
+ attention_mask=attention_mask,
1387
+ position_ids=position_ids,
1388
+ past_key_value=past_key_values,
1389
+ cache_position=cache_position,
1390
+ output_attentions=output_attentions,
1391
+ output_router_logits=output_router_logits,
1392
+ use_cache=use_cache,
1393
+ position_embeddings=position_embeddings,
1394
+ )
1395
+ hidden_states = layer_outputs[0]
1396
+
1397
+ if use_cache:
1398
+ next_decoder_cache = layer_outputs[2 if output_attentions else 1]
1399
+
1400
+ if output_attentions:
1401
+ all_self_attns += (layer_outputs[1],)
1402
+
1403
+ if output_router_logits and layer_outputs[-1] is not None:
1404
+ all_router_logits += (layer_outputs[-1],)
1405
+
1406
+ hidden_states = self.norm(hidden_states)
1407
+ main_hidden_states = hidden_states
1408
+
1409
+ # add hidden states from the last decoder layer
1410
+ if output_hidden_states:
1411
+ all_hidden_states += (main_hidden_states,)
1412
+
1413
+ mtp_hidden_states = None
1414
+
1415
+ if mtp_layers:
1416
+ for decoder_layer in mtp_layers:
1417
+ input_ids, _ = roll_tensor(input_ids, shifts=-1, dims=-1)
1418
+ inputs_embeds = self.word_embeddings(input_ids)
1419
+
1420
+ if self.gradient_checkpointing and self.training:
1421
+ layer_outputs = self._gradient_checkpointing_func(
1422
+ decoder_layer.__call__,
1423
+ inputs_embeds,
1424
+ hidden_states,
1425
+ attention_mask,
1426
+ position_ids,
1427
+ past_key_values,
1428
+ output_attentions,
1429
+ output_router_logits,
1430
+ use_cache,
1431
+ position_embeddings,
1432
+ )
1433
+ else:
1434
+ layer_outputs = decoder_layer(
1435
+ inputs_embeds,
1436
+ hidden_states,
1437
+ attention_mask=attention_mask,
1438
+ position_ids=position_ids,
1439
+ past_key_value=past_key_values,
1440
+ output_attentions=output_attentions,
1441
+ output_router_logits=output_router_logits,
1442
+ use_cache=use_cache,
1443
+ position_embeddings=position_embeddings,
1444
+ )
1445
+ if mtp_hidden_states is None:
1446
+ mtp_hidden_states = []
1447
+ hidden_states = layer_outputs[0]
1448
+ mtp_hidden_states.append(hidden_states)
1449
+
1450
+ if output_hidden_states:
1451
+ all_hidden_states += (hidden_states,)
1452
+
1453
+ if use_cache:
1454
+ next_decoder_cache = layer_outputs[2 if output_attentions else 1]
1455
+
1456
+ if output_attentions:
1457
+ all_self_attns += (layer_outputs[1],)
1458
+
1459
+ if output_router_logits and layer_outputs[-1] is not None:
1460
+ all_router_logits += (layer_outputs[-1],)
1461
+
1462
+ next_cache = None
1463
+ if use_cache:
1464
+ next_cache = next_decoder_cache
1465
+ if not return_dict:
1466
+ return tuple(
1467
+ v
1468
+ for v in [main_hidden_states, next_cache, all_hidden_states, all_self_attns, all_router_logits]
1469
+ if v is not None
1470
+ )
1471
+ return MoeV3ModelOutputWithPast(
1472
+ last_hidden_state=main_hidden_states,
1473
+ past_key_values=next_cache,
1474
+ hidden_states=all_hidden_states,
1475
+ mtp_hidden_states=mtp_hidden_states,
1476
+ attentions=all_self_attns,
1477
+ router_logits=all_router_logits,
1478
+ )
1479
+
1480
+
1481
+ class BailingMoeV3ForCausalLM(BailingMoeV3PreTrainedModel, GenerationMixin):
1482
+ _tied_weights_keys = ["lm_head.weight"]
1483
+
1484
+ def __init__(self, config: BailingMoeV3Config):
1485
+ super().__init__(config)
1486
+ self.model = BailingMoeV3Model(config)
1487
+ self.vocab_size = config.vocab_size
1488
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
1489
+ self.num_nextn_predict_layers = config.num_nextn_predict_layers
1490
+ self.mtp_loss_scaling_factor = config.mtp_loss_scaling_factor
1491
+
1492
+ # Initialize weights and apply final processing
1493
+ self.post_init()
1494
+
1495
+ def get_input_embeddings(self):
1496
+ return self.model.word_embeddings
1497
+
1498
+ def set_input_embeddings(self, value):
1499
+ self.model.word_embeddings = value
1500
+
1501
+ def get_output_embeddings(self):
1502
+ return self.lm_head
1503
+
1504
+ def set_output_embeddings(self, new_embeddings):
1505
+ self.lm_head = new_embeddings
1506
+
1507
+ def set_decoder(self, decoder):
1508
+ self.model = decoder
1509
+
1510
+ def get_decoder(self):
1511
+ return self.model
1512
+
1513
+ @add_start_docstrings_to_model_forward(BAILINGMOEV3_INPUTS_DOCSTRING)
1514
+ @replace_return_docstrings(output_type=MoEV3CausalLMOutputWithPast, config_class=_CONFIG_FOR_DOC)
1515
+ def forward(
1516
+ self,
1517
+ input_ids: torch.LongTensor = None,
1518
+ attention_mask: Optional[torch.Tensor] = None,
1519
+ position_ids: Optional[torch.LongTensor] = None,
1520
+ past_key_values: Optional[List[torch.FloatTensor]] = None,
1521
+ inputs_embeds: Optional[torch.FloatTensor] = None,
1522
+ labels: Optional[torch.LongTensor] = None,
1523
+ use_cache: Optional[bool] = None,
1524
+ output_attentions: Optional[bool] = None,
1525
+ output_hidden_states: Optional[bool] = None,
1526
+ output_router_logits: Optional[bool] = None,
1527
+ return_dict: Optional[bool] = None,
1528
+ **kwargs,
1529
+ ) -> Union[Tuple, MoEV3CausalLMOutputWithPast]:
1530
+ r"""
1531
+ Args:
1532
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
1533
+ Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
1534
+ config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
1535
+ (masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
1536
+ Returns:
1537
+ Example:
1538
+ ```python
1539
+ >>> from transformers import AutoTokenizer
1540
+ >>> model = BailingMoeV3ForCausalLM.from_pretrained(PATH_TO_CONVERTED_WEIGHTS)
1541
+ >>> tokenizer = AutoTokenizer.from_pretrained(PATH_TO_CONVERTED_TOKENIZER)
1542
+ >>> prompt = "Hey, are you conscious? Can you talk to me?"
1543
+ >>> inputs = tokenizer(prompt, return_tensors="pt")
1544
+ >>> # Generate
1545
+ >>> generate_ids = model.generate(inputs.input_ids, max_length=30)
1546
+ >>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
1547
+ "Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
1548
+ ```"""
1549
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1550
+ output_hidden_states = (
1551
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1552
+ )
1553
+ output_router_logits = (
1554
+ output_router_logits if output_router_logits is not None else self.config.output_router_logits
1555
+ )
1556
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
1557
+ # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
1558
+ outputs = self.model(
1559
+ input_ids=input_ids,
1560
+ attention_mask=attention_mask,
1561
+ position_ids=position_ids,
1562
+ past_key_values=past_key_values,
1563
+ inputs_embeds=inputs_embeds,
1564
+ use_cache=use_cache,
1565
+ output_attentions=output_attentions,
1566
+ output_hidden_states=output_hidden_states,
1567
+ output_router_logits=output_router_logits,
1568
+ return_dict=return_dict,
1569
+ **kwargs,
1570
+ )
1571
+
1572
+ loss = None
1573
+ all_mtp_loss = None
1574
+ aux_loss = None
1575
+ hidden_states = outputs[0]
1576
+ logits = self.lm_head(hidden_states)
1577
+ logits = logits.float()
1578
+
1579
+ if labels is not None:
1580
+ loss = self.loss_function(logits, labels, self.config.vocab_size, **kwargs)
1581
+
1582
+ all_mtp_logits = None
1583
+ if self.num_nextn_predict_layers > 0:
1584
+ mtp_hidden_states = outputs.mtp_hidden_states
1585
+ shift_labels_mtp = None
1586
+ for i in range(self.num_nextn_predict_layers):
1587
+ mtp_hidden_states = mtp_hidden_states[i]
1588
+ mtp_logits = self.lm_head(mtp_hidden_states).float()
1589
+ if all_mtp_logits is None:
1590
+ all_mtp_logits = []
1591
+ all_mtp_logits.append(mtp_logits)
1592
+ if labels is not None:
1593
+ if shift_labels_mtp is None:
1594
+ shift_labels_mtp = labels.clone()
1595
+ shift_labels_mtp, _ = roll_tensor(shift_labels_mtp, shifts=-1, dims=-1, fill_value=-100)
1596
+ mtp_logits_ = mtp_logits.view(-1, self.config.vocab_size)
1597
+ mtp_loss = self.loss_function(
1598
+ mtp_logits_, shift_labels_mtp.to(mtp_logits_.device).view(-1), self.config.vocab_size, **kwargs
1599
+ )
1600
+ if loss is not None:
1601
+ loss += self.mtp_loss_scaling_factor * mtp_loss
1602
+ else:
1603
+ loss = self.mtp_loss_scaling_factor * mtp_loss
1604
+
1605
+ if all_mtp_loss is None:
1606
+ all_mtp_loss = []
1607
+ all_mtp_loss.append(mtp_loss)
1608
+
1609
+ if not return_dict:
1610
+ output = (logits,) + outputs[1:]
1611
+ if output_router_logits:
1612
+ output = (aux_loss,) + output
1613
+ return (loss,) + output if loss is not None else output
1614
+
1615
+ return MoEV3CausalLMOutputWithPast(
1616
+ loss=loss,
1617
+ mtp_loss=all_mtp_loss,
1618
+ aux_loss=aux_loss,
1619
+ logits=logits,
1620
+ mtp_logits=all_mtp_logits,
1621
+ past_key_values=outputs.past_key_values,
1622
+ hidden_states=outputs.hidden_states,
1623
+ attentions=outputs.attentions,
1624
+ router_logits=outputs.router_logits,
1625
+ )
special_tokens_map.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "<|startoftext|>",
4
+ "lstrip": false,
5
+ "normalized": false,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "cls_token": {
10
+ "content": "[CLS]",
11
+ "lstrip": false,
12
+ "normalized": false,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "eos_token": {
17
+ "content": "<|role_end|>",
18
+ "lstrip": false,
19
+ "normalized": false,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "pad_token": {
24
+ "content": "<|endoftext|>",
25
+ "lstrip": false,
26
+ "normalized": false,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ }
30
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:40fb9d7d7795b8bd305aeff39ce9963f3f450915b9553f2938e009be9a1fed60
3
+ size 12205732
tokenizer_config.json ADDED
@@ -0,0 +1,2113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_eos_token": false,
4
+ "added_tokens_decoder": {
5
+ "156891": {
6
+ "content": "<|startoftext|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ },
13
+ "156892": {
14
+ "content": "<|endoftext|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false,
19
+ "special": true
20
+ },
21
+ "156893": {
22
+ "content": "[CLS]",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false,
27
+ "special": true
28
+ },
29
+ "156894": {
30
+ "content": "[gMASK]",
31
+ "lstrip": false,
32
+ "normalized": false,
33
+ "rstrip": false,
34
+ "single_word": false,
35
+ "special": true
36
+ },
37
+ "156895": {
38
+ "content": "<|role_end|>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false,
43
+ "special": true
44
+ },
45
+ "156896": {
46
+ "content": "<tool_call>",
47
+ "lstrip": false,
48
+ "normalized": false,
49
+ "rstrip": false,
50
+ "single_word": false,
51
+ "special": false
52
+ },
53
+ "156897": {
54
+ "content": "</tool_call>",
55
+ "lstrip": false,
56
+ "normalized": false,
57
+ "rstrip": false,
58
+ "single_word": false,
59
+ "special": false
60
+ },
61
+ "156898": {
62
+ "content": "<tool_response>",
63
+ "lstrip": false,
64
+ "normalized": false,
65
+ "rstrip": false,
66
+ "single_word": false,
67
+ "special": false
68
+ },
69
+ "156899": {
70
+ "content": "</tool_response>",
71
+ "lstrip": false,
72
+ "normalized": false,
73
+ "rstrip": false,
74
+ "single_word": false,
75
+ "special": false
76
+ },
77
+ "156900": {
78
+ "content": "<|fim_start|>",
79
+ "lstrip": false,
80
+ "normalized": false,
81
+ "rstrip": false,
82
+ "single_word": false,
83
+ "special": true
84
+ },
85
+ "156901": {
86
+ "content": "<|fim_hole|>",
87
+ "lstrip": false,
88
+ "normalized": false,
89
+ "rstrip": false,
90
+ "single_word": false,
91
+ "special": true
92
+ },
93
+ "156902": {
94
+ "content": "<|fim_end|>",
95
+ "lstrip": false,
96
+ "normalized": false,
97
+ "rstrip": false,
98
+ "single_word": false,
99
+ "special": true
100
+ },
101
+ "156903": {
102
+ "content": "<think>",
103
+ "lstrip": false,
104
+ "normalized": false,
105
+ "rstrip": false,
106
+ "single_word": false,
107
+ "special": false
108
+ },
109
+ "156904": {
110
+ "content": "</think>",
111
+ "lstrip": false,
112
+ "normalized": false,
113
+ "rstrip": false,
114
+ "single_word": false,
115
+ "special": false
116
+ },
117
+ "156905": {
118
+ "content": "<arg_key>",
119
+ "lstrip": false,
120
+ "normalized": false,
121
+ "rstrip": false,
122
+ "single_word": false,
123
+ "special": false
124
+ },
125
+ "156906": {
126
+ "content": "</arg_key>",
127
+ "lstrip": false,
128
+ "normalized": false,
129
+ "rstrip": false,
130
+ "single_word": false,
131
+ "special": false
132
+ },
133
+ "156907": {
134
+ "content": "<arg_value>",
135
+ "lstrip": false,
136
+ "normalized": false,
137
+ "rstrip": false,
138
+ "single_word": false,
139
+ "special": false
140
+ },
141
+ "156908": {
142
+ "content": "</arg_value>",
143
+ "lstrip": false,
144
+ "normalized": false,
145
+ "rstrip": false,
146
+ "single_word": false,
147
+ "special": false
148
+ },
149
+ "156909": {
150
+ "content": "<|reserved_token_14|>",
151
+ "lstrip": false,
152
+ "normalized": false,
153
+ "rstrip": false,
154
+ "single_word": false,
155
+ "special": true
156
+ },
157
+ "156910": {
158
+ "content": "<|reserved_token_15|>",
159
+ "lstrip": false,
160
+ "normalized": false,
161
+ "rstrip": false,
162
+ "single_word": false,
163
+ "special": true
164
+ },
165
+ "156911": {
166
+ "content": "<|reserved_token_16|>",
167
+ "lstrip": false,
168
+ "normalized": false,
169
+ "rstrip": false,
170
+ "single_word": false,
171
+ "special": true
172
+ },
173
+ "156912": {
174
+ "content": "<|reserved_token_17|>",
175
+ "lstrip": false,
176
+ "normalized": false,
177
+ "rstrip": false,
178
+ "single_word": false,
179
+ "special": true
180
+ },
181
+ "156913": {
182
+ "content": "<|reserved_token_18|>",
183
+ "lstrip": false,
184
+ "normalized": false,
185
+ "rstrip": false,
186
+ "single_word": false,
187
+ "special": true
188
+ },
189
+ "156914": {
190
+ "content": "<|reserved_token_19|>",
191
+ "lstrip": false,
192
+ "normalized": false,
193
+ "rstrip": false,
194
+ "single_word": false,
195
+ "special": true
196
+ },
197
+ "156915": {
198
+ "content": "<|reserved_token_20|>",
199
+ "lstrip": false,
200
+ "normalized": false,
201
+ "rstrip": false,
202
+ "single_word": false,
203
+ "special": true
204
+ },
205
+ "156916": {
206
+ "content": "<|reserved_token_21|>",
207
+ "lstrip": false,
208
+ "normalized": false,
209
+ "rstrip": false,
210
+ "single_word": false,
211
+ "special": true
212
+ },
213
+ "156917": {
214
+ "content": "<|reserved_token_22|>",
215
+ "lstrip": false,
216
+ "normalized": false,
217
+ "rstrip": false,
218
+ "single_word": false,
219
+ "special": true
220
+ },
221
+ "156918": {
222
+ "content": "<|reserved_token_23|>",
223
+ "lstrip": false,
224
+ "normalized": false,
225
+ "rstrip": false,
226
+ "single_word": false,
227
+ "special": true
228
+ },
229
+ "156919": {
230
+ "content": "<|reserved_token_24|>",
231
+ "lstrip": false,
232
+ "normalized": false,
233
+ "rstrip": false,
234
+ "single_word": false,
235
+ "special": true
236
+ },
237
+ "156920": {
238
+ "content": "<|reserved_token_25|>",
239
+ "lstrip": false,
240
+ "normalized": false,
241
+ "rstrip": false,
242
+ "single_word": false,
243
+ "special": true
244
+ },
245
+ "156921": {
246
+ "content": "<|reserved_token_26|>",
247
+ "lstrip": false,
248
+ "normalized": false,
249
+ "rstrip": false,
250
+ "single_word": false,
251
+ "special": true
252
+ },
253
+ "156922": {
254
+ "content": "<|reserved_token_27|>",
255
+ "lstrip": false,
256
+ "normalized": false,
257
+ "rstrip": false,
258
+ "single_word": false,
259
+ "special": true
260
+ },
261
+ "156923": {
262
+ "content": "<|reserved_token_28|>",
263
+ "lstrip": false,
264
+ "normalized": false,
265
+ "rstrip": false,
266
+ "single_word": false,
267
+ "special": true
268
+ },
269
+ "156924": {
270
+ "content": "<|reserved_token_29|>",
271
+ "lstrip": false,
272
+ "normalized": false,
273
+ "rstrip": false,
274
+ "single_word": false,
275
+ "special": true
276
+ },
277
+ "156925": {
278
+ "content": "<|reserved_token_30|>",
279
+ "lstrip": false,
280
+ "normalized": false,
281
+ "rstrip": false,
282
+ "single_word": false,
283
+ "special": true
284
+ },
285
+ "156926": {
286
+ "content": "<|reserved_token_31|>",
287
+ "lstrip": false,
288
+ "normalized": false,
289
+ "rstrip": false,
290
+ "single_word": false,
291
+ "special": true
292
+ },
293
+ "156927": {
294
+ "content": "<|reserved_token_32|>",
295
+ "lstrip": false,
296
+ "normalized": false,
297
+ "rstrip": false,
298
+ "single_word": false,
299
+ "special": true
300
+ },
301
+ "156928": {
302
+ "content": "<|reserved_token_33|>",
303
+ "lstrip": false,
304
+ "normalized": false,
305
+ "rstrip": false,
306
+ "single_word": false,
307
+ "special": true
308
+ },
309
+ "156929": {
310
+ "content": "<|reserved_token_34|>",
311
+ "lstrip": false,
312
+ "normalized": false,
313
+ "rstrip": false,
314
+ "single_word": false,
315
+ "special": true
316
+ },
317
+ "156930": {
318
+ "content": "<|reserved_token_35|>",
319
+ "lstrip": false,
320
+ "normalized": false,
321
+ "rstrip": false,
322
+ "single_word": false,
323
+ "special": true
324
+ },
325
+ "156931": {
326
+ "content": "<|reserved_token_36|>",
327
+ "lstrip": false,
328
+ "normalized": false,
329
+ "rstrip": false,
330
+ "single_word": false,
331
+ "special": true
332
+ },
333
+ "156932": {
334
+ "content": "<|reserved_token_37|>",
335
+ "lstrip": false,
336
+ "normalized": false,
337
+ "rstrip": false,
338
+ "single_word": false,
339
+ "special": true
340
+ },
341
+ "156933": {
342
+ "content": "<|reserved_token_38|>",
343
+ "lstrip": false,
344
+ "normalized": false,
345
+ "rstrip": false,
346
+ "single_word": false,
347
+ "special": true
348
+ },
349
+ "156934": {
350
+ "content": "<|reserved_token_39|>",
351
+ "lstrip": false,
352
+ "normalized": false,
353
+ "rstrip": false,
354
+ "single_word": false,
355
+ "special": true
356
+ },
357
+ "156935": {
358
+ "content": "<|reserved_token_40|>",
359
+ "lstrip": false,
360
+ "normalized": false,
361
+ "rstrip": false,
362
+ "single_word": false,
363
+ "special": true
364
+ },
365
+ "156936": {
366
+ "content": "<|reserved_token_41|>",
367
+ "lstrip": false,
368
+ "normalized": false,
369
+ "rstrip": false,
370
+ "single_word": false,
371
+ "special": true
372
+ },
373
+ "156937": {
374
+ "content": "<|reserved_token_42|>",
375
+ "lstrip": false,
376
+ "normalized": false,
377
+ "rstrip": false,
378
+ "single_word": false,
379
+ "special": true
380
+ },
381
+ "156938": {
382
+ "content": "<|reserved_token_43|>",
383
+ "lstrip": false,
384
+ "normalized": false,
385
+ "rstrip": false,
386
+ "single_word": false,
387
+ "special": true
388
+ },
389
+ "156939": {
390
+ "content": "<|reserved_token_44|>",
391
+ "lstrip": false,
392
+ "normalized": false,
393
+ "rstrip": false,
394
+ "single_word": false,
395
+ "special": true
396
+ },
397
+ "156940": {
398
+ "content": "<|reserved_token_45|>",
399
+ "lstrip": false,
400
+ "normalized": false,
401
+ "rstrip": false,
402
+ "single_word": false,
403
+ "special": true
404
+ },
405
+ "156941": {
406
+ "content": "<|reserved_token_46|>",
407
+ "lstrip": false,
408
+ "normalized": false,
409
+ "rstrip": false,
410
+ "single_word": false,
411
+ "special": true
412
+ },
413
+ "156942": {
414
+ "content": "<|reserved_token_47|>",
415
+ "lstrip": false,
416
+ "normalized": false,
417
+ "rstrip": false,
418
+ "single_word": false,
419
+ "special": true
420
+ },
421
+ "156943": {
422
+ "content": "<|reserved_token_48|>",
423
+ "lstrip": false,
424
+ "normalized": false,
425
+ "rstrip": false,
426
+ "single_word": false,
427
+ "special": true
428
+ },
429
+ "156944": {
430
+ "content": "<|reserved_token_49|>",
431
+ "lstrip": false,
432
+ "normalized": false,
433
+ "rstrip": false,
434
+ "single_word": false,
435
+ "special": true
436
+ },
437
+ "156945": {
438
+ "content": "<|reserved_token_50|>",
439
+ "lstrip": false,
440
+ "normalized": false,
441
+ "rstrip": false,
442
+ "single_word": false,
443
+ "special": true
444
+ },
445
+ "156946": {
446
+ "content": "<|reserved_token_51|>",
447
+ "lstrip": false,
448
+ "normalized": false,
449
+ "rstrip": false,
450
+ "single_word": false,
451
+ "special": true
452
+ },
453
+ "156947": {
454
+ "content": "<|reserved_token_52|>",
455
+ "lstrip": false,
456
+ "normalized": false,
457
+ "rstrip": false,
458
+ "single_word": false,
459
+ "special": true
460
+ },
461
+ "156948": {
462
+ "content": "<|reserved_token_53|>",
463
+ "lstrip": false,
464
+ "normalized": false,
465
+ "rstrip": false,
466
+ "single_word": false,
467
+ "special": true
468
+ },
469
+ "156949": {
470
+ "content": "<|reserved_token_54|>",
471
+ "lstrip": false,
472
+ "normalized": false,
473
+ "rstrip": false,
474
+ "single_word": false,
475
+ "special": true
476
+ },
477
+ "156950": {
478
+ "content": "<|reserved_token_55|>",
479
+ "lstrip": false,
480
+ "normalized": false,
481
+ "rstrip": false,
482
+ "single_word": false,
483
+ "special": true
484
+ },
485
+ "156951": {
486
+ "content": "<|reserved_token_56|>",
487
+ "lstrip": false,
488
+ "normalized": false,
489
+ "rstrip": false,
490
+ "single_word": false,
491
+ "special": true
492
+ },
493
+ "156952": {
494
+ "content": "<|reserved_token_57|>",
495
+ "lstrip": false,
496
+ "normalized": false,
497
+ "rstrip": false,
498
+ "single_word": false,
499
+ "special": true
500
+ },
501
+ "156953": {
502
+ "content": "<|reserved_token_58|>",
503
+ "lstrip": false,
504
+ "normalized": false,
505
+ "rstrip": false,
506
+ "single_word": false,
507
+ "special": true
508
+ },
509
+ "156954": {
510
+ "content": "<|reserved_token_59|>",
511
+ "lstrip": false,
512
+ "normalized": false,
513
+ "rstrip": false,
514
+ "single_word": false,
515
+ "special": true
516
+ },
517
+ "156955": {
518
+ "content": "<|reserved_token_60|>",
519
+ "lstrip": false,
520
+ "normalized": false,
521
+ "rstrip": false,
522
+ "single_word": false,
523
+ "special": true
524
+ },
525
+ "156956": {
526
+ "content": "<|reserved_token_61|>",
527
+ "lstrip": false,
528
+ "normalized": false,
529
+ "rstrip": false,
530
+ "single_word": false,
531
+ "special": true
532
+ },
533
+ "156957": {
534
+ "content": "<|reserved_token_62|>",
535
+ "lstrip": false,
536
+ "normalized": false,
537
+ "rstrip": false,
538
+ "single_word": false,
539
+ "special": true
540
+ },
541
+ "156958": {
542
+ "content": "<|reserved_token_63|>",
543
+ "lstrip": false,
544
+ "normalized": false,
545
+ "rstrip": false,
546
+ "single_word": false,
547
+ "special": true
548
+ },
549
+ "156959": {
550
+ "content": "<|reserved_token_64|>",
551
+ "lstrip": false,
552
+ "normalized": false,
553
+ "rstrip": false,
554
+ "single_word": false,
555
+ "special": true
556
+ },
557
+ "156960": {
558
+ "content": "<|reserved_token_65|>",
559
+ "lstrip": false,
560
+ "normalized": false,
561
+ "rstrip": false,
562
+ "single_word": false,
563
+ "special": true
564
+ },
565
+ "156961": {
566
+ "content": "<|reserved_token_66|>",
567
+ "lstrip": false,
568
+ "normalized": false,
569
+ "rstrip": false,
570
+ "single_word": false,
571
+ "special": true
572
+ },
573
+ "156962": {
574
+ "content": "<|reserved_token_67|>",
575
+ "lstrip": false,
576
+ "normalized": false,
577
+ "rstrip": false,
578
+ "single_word": false,
579
+ "special": true
580
+ },
581
+ "156963": {
582
+ "content": "<|reserved_token_68|>",
583
+ "lstrip": false,
584
+ "normalized": false,
585
+ "rstrip": false,
586
+ "single_word": false,
587
+ "special": true
588
+ },
589
+ "156964": {
590
+ "content": "<|reserved_token_69|>",
591
+ "lstrip": false,
592
+ "normalized": false,
593
+ "rstrip": false,
594
+ "single_word": false,
595
+ "special": true
596
+ },
597
+ "156965": {
598
+ "content": "<|reserved_token_70|>",
599
+ "lstrip": false,
600
+ "normalized": false,
601
+ "rstrip": false,
602
+ "single_word": false,
603
+ "special": true
604
+ },
605
+ "156966": {
606
+ "content": "<|reserved_token_71|>",
607
+ "lstrip": false,
608
+ "normalized": false,
609
+ "rstrip": false,
610
+ "single_word": false,
611
+ "special": true
612
+ },
613
+ "156967": {
614
+ "content": "<|reserved_token_72|>",
615
+ "lstrip": false,
616
+ "normalized": false,
617
+ "rstrip": false,
618
+ "single_word": false,
619
+ "special": true
620
+ },
621
+ "156968": {
622
+ "content": "<|reserved_token_73|>",
623
+ "lstrip": false,
624
+ "normalized": false,
625
+ "rstrip": false,
626
+ "single_word": false,
627
+ "special": true
628
+ },
629
+ "156969": {
630
+ "content": "<|reserved_token_74|>",
631
+ "lstrip": false,
632
+ "normalized": false,
633
+ "rstrip": false,
634
+ "single_word": false,
635
+ "special": true
636
+ },
637
+ "156970": {
638
+ "content": "<|reserved_token_75|>",
639
+ "lstrip": false,
640
+ "normalized": false,
641
+ "rstrip": false,
642
+ "single_word": false,
643
+ "special": true
644
+ },
645
+ "156971": {
646
+ "content": "<|reserved_token_76|>",
647
+ "lstrip": false,
648
+ "normalized": false,
649
+ "rstrip": false,
650
+ "single_word": false,
651
+ "special": true
652
+ },
653
+ "156972": {
654
+ "content": "<|reserved_token_77|>",
655
+ "lstrip": false,
656
+ "normalized": false,
657
+ "rstrip": false,
658
+ "single_word": false,
659
+ "special": true
660
+ },
661
+ "156973": {
662
+ "content": "<|reserved_token_78|>",
663
+ "lstrip": false,
664
+ "normalized": false,
665
+ "rstrip": false,
666
+ "single_word": false,
667
+ "special": true
668
+ },
669
+ "156974": {
670
+ "content": "<|reserved_token_79|>",
671
+ "lstrip": false,
672
+ "normalized": false,
673
+ "rstrip": false,
674
+ "single_word": false,
675
+ "special": true
676
+ },
677
+ "156975": {
678
+ "content": "<|reserved_token_80|>",
679
+ "lstrip": false,
680
+ "normalized": false,
681
+ "rstrip": false,
682
+ "single_word": false,
683
+ "special": true
684
+ },
685
+ "156976": {
686
+ "content": "<|reserved_token_81|>",
687
+ "lstrip": false,
688
+ "normalized": false,
689
+ "rstrip": false,
690
+ "single_word": false,
691
+ "special": true
692
+ },
693
+ "156977": {
694
+ "content": "<|reserved_token_82|>",
695
+ "lstrip": false,
696
+ "normalized": false,
697
+ "rstrip": false,
698
+ "single_word": false,
699
+ "special": true
700
+ },
701
+ "156978": {
702
+ "content": "<|reserved_token_83|>",
703
+ "lstrip": false,
704
+ "normalized": false,
705
+ "rstrip": false,
706
+ "single_word": false,
707
+ "special": true
708
+ },
709
+ "156979": {
710
+ "content": "<|reserved_token_84|>",
711
+ "lstrip": false,
712
+ "normalized": false,
713
+ "rstrip": false,
714
+ "single_word": false,
715
+ "special": true
716
+ },
717
+ "156980": {
718
+ "content": "<|reserved_token_85|>",
719
+ "lstrip": false,
720
+ "normalized": false,
721
+ "rstrip": false,
722
+ "single_word": false,
723
+ "special": true
724
+ },
725
+ "156981": {
726
+ "content": "<|reserved_token_86|>",
727
+ "lstrip": false,
728
+ "normalized": false,
729
+ "rstrip": false,
730
+ "single_word": false,
731
+ "special": true
732
+ },
733
+ "156982": {
734
+ "content": "<|reserved_token_87|>",
735
+ "lstrip": false,
736
+ "normalized": false,
737
+ "rstrip": false,
738
+ "single_word": false,
739
+ "special": true
740
+ },
741
+ "156983": {
742
+ "content": "<|reserved_token_88|>",
743
+ "lstrip": false,
744
+ "normalized": false,
745
+ "rstrip": false,
746
+ "single_word": false,
747
+ "special": true
748
+ },
749
+ "156984": {
750
+ "content": "<|reserved_token_89|>",
751
+ "lstrip": false,
752
+ "normalized": false,
753
+ "rstrip": false,
754
+ "single_word": false,
755
+ "special": true
756
+ },
757
+ "156985": {
758
+ "content": "<|reserved_token_90|>",
759
+ "lstrip": false,
760
+ "normalized": false,
761
+ "rstrip": false,
762
+ "single_word": false,
763
+ "special": true
764
+ },
765
+ "156986": {
766
+ "content": "<|reserved_token_91|>",
767
+ "lstrip": false,
768
+ "normalized": false,
769
+ "rstrip": false,
770
+ "single_word": false,
771
+ "special": true
772
+ },
773
+ "156987": {
774
+ "content": "<|reserved_token_92|>",
775
+ "lstrip": false,
776
+ "normalized": false,
777
+ "rstrip": false,
778
+ "single_word": false,
779
+ "special": true
780
+ },
781
+ "156988": {
782
+ "content": "<|reserved_token_93|>",
783
+ "lstrip": false,
784
+ "normalized": false,
785
+ "rstrip": false,
786
+ "single_word": false,
787
+ "special": true
788
+ },
789
+ "156989": {
790
+ "content": "<|reserved_token_94|>",
791
+ "lstrip": false,
792
+ "normalized": false,
793
+ "rstrip": false,
794
+ "single_word": false,
795
+ "special": true
796
+ },
797
+ "156990": {
798
+ "content": "<|reserved_token_95|>",
799
+ "lstrip": false,
800
+ "normalized": false,
801
+ "rstrip": false,
802
+ "single_word": false,
803
+ "special": true
804
+ },
805
+ "156991": {
806
+ "content": "<|reserved_token_96|>",
807
+ "lstrip": false,
808
+ "normalized": false,
809
+ "rstrip": false,
810
+ "single_word": false,
811
+ "special": true
812
+ },
813
+ "156992": {
814
+ "content": "<|reserved_token_97|>",
815
+ "lstrip": false,
816
+ "normalized": false,
817
+ "rstrip": false,
818
+ "single_word": false,
819
+ "special": true
820
+ },
821
+ "156993": {
822
+ "content": "<|reserved_token_98|>",
823
+ "lstrip": false,
824
+ "normalized": false,
825
+ "rstrip": false,
826
+ "single_word": false,
827
+ "special": true
828
+ },
829
+ "156994": {
830
+ "content": "<|reserved_token_99|>",
831
+ "lstrip": false,
832
+ "normalized": false,
833
+ "rstrip": false,
834
+ "single_word": false,
835
+ "special": true
836
+ },
837
+ "156995": {
838
+ "content": "<|reserved_token_100|>",
839
+ "lstrip": false,
840
+ "normalized": false,
841
+ "rstrip": false,
842
+ "single_word": false,
843
+ "special": true
844
+ },
845
+ "156996": {
846
+ "content": "<|reserved_token_101|>",
847
+ "lstrip": false,
848
+ "normalized": false,
849
+ "rstrip": false,
850
+ "single_word": false,
851
+ "special": true
852
+ },
853
+ "156997": {
854
+ "content": "<|reserved_token_102|>",
855
+ "lstrip": false,
856
+ "normalized": false,
857
+ "rstrip": false,
858
+ "single_word": false,
859
+ "special": true
860
+ },
861
+ "156998": {
862
+ "content": "<|reserved_token_103|>",
863
+ "lstrip": false,
864
+ "normalized": false,
865
+ "rstrip": false,
866
+ "single_word": false,
867
+ "special": true
868
+ },
869
+ "156999": {
870
+ "content": "<|reserved_token_104|>",
871
+ "lstrip": false,
872
+ "normalized": false,
873
+ "rstrip": false,
874
+ "single_word": false,
875
+ "special": true
876
+ },
877
+ "157000": {
878
+ "content": "<|reserved_token_105|>",
879
+ "lstrip": false,
880
+ "normalized": false,
881
+ "rstrip": false,
882
+ "single_word": false,
883
+ "special": true
884
+ },
885
+ "157001": {
886
+ "content": "<|reserved_token_106|>",
887
+ "lstrip": false,
888
+ "normalized": false,
889
+ "rstrip": false,
890
+ "single_word": false,
891
+ "special": true
892
+ },
893
+ "157002": {
894
+ "content": "<|reserved_token_107|>",
895
+ "lstrip": false,
896
+ "normalized": false,
897
+ "rstrip": false,
898
+ "single_word": false,
899
+ "special": true
900
+ },
901
+ "157003": {
902
+ "content": "<|reserved_token_108|>",
903
+ "lstrip": false,
904
+ "normalized": false,
905
+ "rstrip": false,
906
+ "single_word": false,
907
+ "special": true
908
+ },
909
+ "157004": {
910
+ "content": "<|reserved_token_109|>",
911
+ "lstrip": false,
912
+ "normalized": false,
913
+ "rstrip": false,
914
+ "single_word": false,
915
+ "special": true
916
+ },
917
+ "157005": {
918
+ "content": "<|reserved_token_110|>",
919
+ "lstrip": false,
920
+ "normalized": false,
921
+ "rstrip": false,
922
+ "single_word": false,
923
+ "special": true
924
+ },
925
+ "157006": {
926
+ "content": "<|reserved_token_111|>",
927
+ "lstrip": false,
928
+ "normalized": false,
929
+ "rstrip": false,
930
+ "single_word": false,
931
+ "special": true
932
+ },
933
+ "157007": {
934
+ "content": "<|reserved_token_112|>",
935
+ "lstrip": false,
936
+ "normalized": false,
937
+ "rstrip": false,
938
+ "single_word": false,
939
+ "special": true
940
+ },
941
+ "157008": {
942
+ "content": "<|reserved_token_113|>",
943
+ "lstrip": false,
944
+ "normalized": false,
945
+ "rstrip": false,
946
+ "single_word": false,
947
+ "special": true
948
+ },
949
+ "157009": {
950
+ "content": "<|reserved_token_114|>",
951
+ "lstrip": false,
952
+ "normalized": false,
953
+ "rstrip": false,
954
+ "single_word": false,
955
+ "special": true
956
+ },
957
+ "157010": {
958
+ "content": "<|reserved_token_115|>",
959
+ "lstrip": false,
960
+ "normalized": false,
961
+ "rstrip": false,
962
+ "single_word": false,
963
+ "special": true
964
+ },
965
+ "157011": {
966
+ "content": "<|reserved_token_116|>",
967
+ "lstrip": false,
968
+ "normalized": false,
969
+ "rstrip": false,
970
+ "single_word": false,
971
+ "special": true
972
+ },
973
+ "157012": {
974
+ "content": "<|reserved_token_117|>",
975
+ "lstrip": false,
976
+ "normalized": false,
977
+ "rstrip": false,
978
+ "single_word": false,
979
+ "special": true
980
+ },
981
+ "157013": {
982
+ "content": "<|reserved_token_118|>",
983
+ "lstrip": false,
984
+ "normalized": false,
985
+ "rstrip": false,
986
+ "single_word": false,
987
+ "special": true
988
+ },
989
+ "157014": {
990
+ "content": "<|reserved_token_119|>",
991
+ "lstrip": false,
992
+ "normalized": false,
993
+ "rstrip": false,
994
+ "single_word": false,
995
+ "special": true
996
+ },
997
+ "157015": {
998
+ "content": "<|reserved_token_120|>",
999
+ "lstrip": false,
1000
+ "normalized": false,
1001
+ "rstrip": false,
1002
+ "single_word": false,
1003
+ "special": true
1004
+ },
1005
+ "157016": {
1006
+ "content": "<|reserved_token_121|>",
1007
+ "lstrip": false,
1008
+ "normalized": false,
1009
+ "rstrip": false,
1010
+ "single_word": false,
1011
+ "special": true
1012
+ },
1013
+ "157017": {
1014
+ "content": "<|reserved_token_122|>",
1015
+ "lstrip": false,
1016
+ "normalized": false,
1017
+ "rstrip": false,
1018
+ "single_word": false,
1019
+ "special": true
1020
+ },
1021
+ "157018": {
1022
+ "content": "<|reserved_token_123|>",
1023
+ "lstrip": false,
1024
+ "normalized": false,
1025
+ "rstrip": false,
1026
+ "single_word": false,
1027
+ "special": true
1028
+ },
1029
+ "157019": {
1030
+ "content": "<|reserved_token_124|>",
1031
+ "lstrip": false,
1032
+ "normalized": false,
1033
+ "rstrip": false,
1034
+ "single_word": false,
1035
+ "special": true
1036
+ },
1037
+ "157020": {
1038
+ "content": "<|reserved_token_125|>",
1039
+ "lstrip": false,
1040
+ "normalized": false,
1041
+ "rstrip": false,
1042
+ "single_word": false,
1043
+ "special": true
1044
+ },
1045
+ "157021": {
1046
+ "content": "<|reserved_token_126|>",
1047
+ "lstrip": false,
1048
+ "normalized": false,
1049
+ "rstrip": false,
1050
+ "single_word": false,
1051
+ "special": true
1052
+ },
1053
+ "157022": {
1054
+ "content": "<|reserved_token_127|>",
1055
+ "lstrip": false,
1056
+ "normalized": false,
1057
+ "rstrip": false,
1058
+ "single_word": false,
1059
+ "special": true
1060
+ },
1061
+ "157023": {
1062
+ "content": "<|reserved_token_128|>",
1063
+ "lstrip": false,
1064
+ "normalized": false,
1065
+ "rstrip": false,
1066
+ "single_word": false,
1067
+ "special": true
1068
+ },
1069
+ "157024": {
1070
+ "content": "<|reserved_token_129|>",
1071
+ "lstrip": false,
1072
+ "normalized": false,
1073
+ "rstrip": false,
1074
+ "single_word": false,
1075
+ "special": true
1076
+ },
1077
+ "157025": {
1078
+ "content": "<|reserved_token_130|>",
1079
+ "lstrip": false,
1080
+ "normalized": false,
1081
+ "rstrip": false,
1082
+ "single_word": false,
1083
+ "special": true
1084
+ },
1085
+ "157026": {
1086
+ "content": "<|reserved_token_131|>",
1087
+ "lstrip": false,
1088
+ "normalized": false,
1089
+ "rstrip": false,
1090
+ "single_word": false,
1091
+ "special": true
1092
+ },
1093
+ "157027": {
1094
+ "content": "<|reserved_token_132|>",
1095
+ "lstrip": false,
1096
+ "normalized": false,
1097
+ "rstrip": false,
1098
+ "single_word": false,
1099
+ "special": true
1100
+ },
1101
+ "157028": {
1102
+ "content": "<|reserved_token_133|>",
1103
+ "lstrip": false,
1104
+ "normalized": false,
1105
+ "rstrip": false,
1106
+ "single_word": false,
1107
+ "special": true
1108
+ },
1109
+ "157029": {
1110
+ "content": "<|reserved_token_134|>",
1111
+ "lstrip": false,
1112
+ "normalized": false,
1113
+ "rstrip": false,
1114
+ "single_word": false,
1115
+ "special": true
1116
+ },
1117
+ "157030": {
1118
+ "content": "<|reserved_token_135|>",
1119
+ "lstrip": false,
1120
+ "normalized": false,
1121
+ "rstrip": false,
1122
+ "single_word": false,
1123
+ "special": true
1124
+ },
1125
+ "157031": {
1126
+ "content": "<|reserved_token_136|>",
1127
+ "lstrip": false,
1128
+ "normalized": false,
1129
+ "rstrip": false,
1130
+ "single_word": false,
1131
+ "special": true
1132
+ },
1133
+ "157032": {
1134
+ "content": "<|reserved_token_137|>",
1135
+ "lstrip": false,
1136
+ "normalized": false,
1137
+ "rstrip": false,
1138
+ "single_word": false,
1139
+ "special": true
1140
+ },
1141
+ "157033": {
1142
+ "content": "<|reserved_token_138|>",
1143
+ "lstrip": false,
1144
+ "normalized": false,
1145
+ "rstrip": false,
1146
+ "single_word": false,
1147
+ "special": true
1148
+ },
1149
+ "157034": {
1150
+ "content": "<|reserved_token_139|>",
1151
+ "lstrip": false,
1152
+ "normalized": false,
1153
+ "rstrip": false,
1154
+ "single_word": false,
1155
+ "special": true
1156
+ },
1157
+ "157035": {
1158
+ "content": "<|reserved_token_140|>",
1159
+ "lstrip": false,
1160
+ "normalized": false,
1161
+ "rstrip": false,
1162
+ "single_word": false,
1163
+ "special": true
1164
+ },
1165
+ "157036": {
1166
+ "content": "<|reserved_token_141|>",
1167
+ "lstrip": false,
1168
+ "normalized": false,
1169
+ "rstrip": false,
1170
+ "single_word": false,
1171
+ "special": true
1172
+ },
1173
+ "157037": {
1174
+ "content": "<|reserved_token_142|>",
1175
+ "lstrip": false,
1176
+ "normalized": false,
1177
+ "rstrip": false,
1178
+ "single_word": false,
1179
+ "special": true
1180
+ },
1181
+ "157038": {
1182
+ "content": "<|reserved_token_143|>",
1183
+ "lstrip": false,
1184
+ "normalized": false,
1185
+ "rstrip": false,
1186
+ "single_word": false,
1187
+ "special": true
1188
+ },
1189
+ "157039": {
1190
+ "content": "<|reserved_token_144|>",
1191
+ "lstrip": false,
1192
+ "normalized": false,
1193
+ "rstrip": false,
1194
+ "single_word": false,
1195
+ "special": true
1196
+ },
1197
+ "157040": {
1198
+ "content": "<|reserved_token_145|>",
1199
+ "lstrip": false,
1200
+ "normalized": false,
1201
+ "rstrip": false,
1202
+ "single_word": false,
1203
+ "special": true
1204
+ },
1205
+ "157041": {
1206
+ "content": "<|reserved_token_146|>",
1207
+ "lstrip": false,
1208
+ "normalized": false,
1209
+ "rstrip": false,
1210
+ "single_word": false,
1211
+ "special": true
1212
+ },
1213
+ "157042": {
1214
+ "content": "<|reserved_token_147|>",
1215
+ "lstrip": false,
1216
+ "normalized": false,
1217
+ "rstrip": false,
1218
+ "single_word": false,
1219
+ "special": true
1220
+ },
1221
+ "157043": {
1222
+ "content": "<|reserved_token_148|>",
1223
+ "lstrip": false,
1224
+ "normalized": false,
1225
+ "rstrip": false,
1226
+ "single_word": false,
1227
+ "special": true
1228
+ },
1229
+ "157044": {
1230
+ "content": "<|reserved_token_149|>",
1231
+ "lstrip": false,
1232
+ "normalized": false,
1233
+ "rstrip": false,
1234
+ "single_word": false,
1235
+ "special": true
1236
+ },
1237
+ "157045": {
1238
+ "content": "<|reserved_token_150|>",
1239
+ "lstrip": false,
1240
+ "normalized": false,
1241
+ "rstrip": false,
1242
+ "single_word": false,
1243
+ "special": true
1244
+ },
1245
+ "157046": {
1246
+ "content": "<|reserved_token_151|>",
1247
+ "lstrip": false,
1248
+ "normalized": false,
1249
+ "rstrip": false,
1250
+ "single_word": false,
1251
+ "special": true
1252
+ },
1253
+ "157047": {
1254
+ "content": "<|reserved_token_152|>",
1255
+ "lstrip": false,
1256
+ "normalized": false,
1257
+ "rstrip": false,
1258
+ "single_word": false,
1259
+ "special": true
1260
+ },
1261
+ "157048": {
1262
+ "content": "<|reserved_token_153|>",
1263
+ "lstrip": false,
1264
+ "normalized": false,
1265
+ "rstrip": false,
1266
+ "single_word": false,
1267
+ "special": true
1268
+ },
1269
+ "157049": {
1270
+ "content": "<|reserved_token_154|>",
1271
+ "lstrip": false,
1272
+ "normalized": false,
1273
+ "rstrip": false,
1274
+ "single_word": false,
1275
+ "special": true
1276
+ },
1277
+ "157050": {
1278
+ "content": "<|reserved_token_155|>",
1279
+ "lstrip": false,
1280
+ "normalized": false,
1281
+ "rstrip": false,
1282
+ "single_word": false,
1283
+ "special": true
1284
+ },
1285
+ "157051": {
1286
+ "content": "<|reserved_token_156|>",
1287
+ "lstrip": false,
1288
+ "normalized": false,
1289
+ "rstrip": false,
1290
+ "single_word": false,
1291
+ "special": true
1292
+ },
1293
+ "157052": {
1294
+ "content": "<|reserved_token_157|>",
1295
+ "lstrip": false,
1296
+ "normalized": false,
1297
+ "rstrip": false,
1298
+ "single_word": false,
1299
+ "special": true
1300
+ },
1301
+ "157053": {
1302
+ "content": "<|reserved_token_158|>",
1303
+ "lstrip": false,
1304
+ "normalized": false,
1305
+ "rstrip": false,
1306
+ "single_word": false,
1307
+ "special": true
1308
+ },
1309
+ "157054": {
1310
+ "content": "<|reserved_token_159|>",
1311
+ "lstrip": false,
1312
+ "normalized": false,
1313
+ "rstrip": false,
1314
+ "single_word": false,
1315
+ "special": true
1316
+ },
1317
+ "157055": {
1318
+ "content": "<|reserved_token_160|>",
1319
+ "lstrip": false,
1320
+ "normalized": false,
1321
+ "rstrip": false,
1322
+ "single_word": false,
1323
+ "special": true
1324
+ },
1325
+ "157056": {
1326
+ "content": "<|reserved_token_161|>",
1327
+ "lstrip": false,
1328
+ "normalized": false,
1329
+ "rstrip": false,
1330
+ "single_word": false,
1331
+ "special": true
1332
+ },
1333
+ "157057": {
1334
+ "content": "<|reserved_token_162|>",
1335
+ "lstrip": false,
1336
+ "normalized": false,
1337
+ "rstrip": false,
1338
+ "single_word": false,
1339
+ "special": true
1340
+ },
1341
+ "157058": {
1342
+ "content": "<|reserved_token_163|>",
1343
+ "lstrip": false,
1344
+ "normalized": false,
1345
+ "rstrip": false,
1346
+ "single_word": false,
1347
+ "special": true
1348
+ },
1349
+ "157059": {
1350
+ "content": "<|reserved_token_164|>",
1351
+ "lstrip": false,
1352
+ "normalized": false,
1353
+ "rstrip": false,
1354
+ "single_word": false,
1355
+ "special": true
1356
+ },
1357
+ "157060": {
1358
+ "content": "<|reserved_token_165|>",
1359
+ "lstrip": false,
1360
+ "normalized": false,
1361
+ "rstrip": false,
1362
+ "single_word": false,
1363
+ "special": true
1364
+ },
1365
+ "157061": {
1366
+ "content": "<|reserved_token_166|>",
1367
+ "lstrip": false,
1368
+ "normalized": false,
1369
+ "rstrip": false,
1370
+ "single_word": false,
1371
+ "special": true
1372
+ },
1373
+ "157062": {
1374
+ "content": "<|reserved_token_167|>",
1375
+ "lstrip": false,
1376
+ "normalized": false,
1377
+ "rstrip": false,
1378
+ "single_word": false,
1379
+ "special": true
1380
+ },
1381
+ "157063": {
1382
+ "content": "<|reserved_token_168|>",
1383
+ "lstrip": false,
1384
+ "normalized": false,
1385
+ "rstrip": false,
1386
+ "single_word": false,
1387
+ "special": true
1388
+ },
1389
+ "157064": {
1390
+ "content": "<|reserved_token_169|>",
1391
+ "lstrip": false,
1392
+ "normalized": false,
1393
+ "rstrip": false,
1394
+ "single_word": false,
1395
+ "special": true
1396
+ },
1397
+ "157065": {
1398
+ "content": "<|reserved_token_170|>",
1399
+ "lstrip": false,
1400
+ "normalized": false,
1401
+ "rstrip": false,
1402
+ "single_word": false,
1403
+ "special": true
1404
+ },
1405
+ "157066": {
1406
+ "content": "<|reserved_token_171|>",
1407
+ "lstrip": false,
1408
+ "normalized": false,
1409
+ "rstrip": false,
1410
+ "single_word": false,
1411
+ "special": true
1412
+ },
1413
+ "157067": {
1414
+ "content": "<|reserved_token_172|>",
1415
+ "lstrip": false,
1416
+ "normalized": false,
1417
+ "rstrip": false,
1418
+ "single_word": false,
1419
+ "special": true
1420
+ },
1421
+ "157068": {
1422
+ "content": "<|reserved_token_173|>",
1423
+ "lstrip": false,
1424
+ "normalized": false,
1425
+ "rstrip": false,
1426
+ "single_word": false,
1427
+ "special": true
1428
+ },
1429
+ "157069": {
1430
+ "content": "<|reserved_token_174|>",
1431
+ "lstrip": false,
1432
+ "normalized": false,
1433
+ "rstrip": false,
1434
+ "single_word": false,
1435
+ "special": true
1436
+ },
1437
+ "157070": {
1438
+ "content": "<|reserved_token_175|>",
1439
+ "lstrip": false,
1440
+ "normalized": false,
1441
+ "rstrip": false,
1442
+ "single_word": false,
1443
+ "special": true
1444
+ },
1445
+ "157071": {
1446
+ "content": "<|reserved_token_176|>",
1447
+ "lstrip": false,
1448
+ "normalized": false,
1449
+ "rstrip": false,
1450
+ "single_word": false,
1451
+ "special": true
1452
+ },
1453
+ "157072": {
1454
+ "content": "<|reserved_token_177|>",
1455
+ "lstrip": false,
1456
+ "normalized": false,
1457
+ "rstrip": false,
1458
+ "single_word": false,
1459
+ "special": true
1460
+ },
1461
+ "157073": {
1462
+ "content": "<|reserved_token_178|>",
1463
+ "lstrip": false,
1464
+ "normalized": false,
1465
+ "rstrip": false,
1466
+ "single_word": false,
1467
+ "special": true
1468
+ },
1469
+ "157074": {
1470
+ "content": "<|reserved_token_179|>",
1471
+ "lstrip": false,
1472
+ "normalized": false,
1473
+ "rstrip": false,
1474
+ "single_word": false,
1475
+ "special": true
1476
+ },
1477
+ "157075": {
1478
+ "content": "<|reserved_token_180|>",
1479
+ "lstrip": false,
1480
+ "normalized": false,
1481
+ "rstrip": false,
1482
+ "single_word": false,
1483
+ "special": true
1484
+ },
1485
+ "157076": {
1486
+ "content": "<|reserved_token_181|>",
1487
+ "lstrip": false,
1488
+ "normalized": false,
1489
+ "rstrip": false,
1490
+ "single_word": false,
1491
+ "special": true
1492
+ },
1493
+ "157077": {
1494
+ "content": "<|reserved_token_182|>",
1495
+ "lstrip": false,
1496
+ "normalized": false,
1497
+ "rstrip": false,
1498
+ "single_word": false,
1499
+ "special": true
1500
+ },
1501
+ "157078": {
1502
+ "content": "<|reserved_token_183|>",
1503
+ "lstrip": false,
1504
+ "normalized": false,
1505
+ "rstrip": false,
1506
+ "single_word": false,
1507
+ "special": true
1508
+ },
1509
+ "157079": {
1510
+ "content": "<|reserved_token_184|>",
1511
+ "lstrip": false,
1512
+ "normalized": false,
1513
+ "rstrip": false,
1514
+ "single_word": false,
1515
+ "special": true
1516
+ },
1517
+ "157080": {
1518
+ "content": "<|reserved_token_185|>",
1519
+ "lstrip": false,
1520
+ "normalized": false,
1521
+ "rstrip": false,
1522
+ "single_word": false,
1523
+ "special": true
1524
+ },
1525
+ "157081": {
1526
+ "content": "<|reserved_token_186|>",
1527
+ "lstrip": false,
1528
+ "normalized": false,
1529
+ "rstrip": false,
1530
+ "single_word": false,
1531
+ "special": true
1532
+ },
1533
+ "157082": {
1534
+ "content": "<|reserved_token_187|>",
1535
+ "lstrip": false,
1536
+ "normalized": false,
1537
+ "rstrip": false,
1538
+ "single_word": false,
1539
+ "special": true
1540
+ },
1541
+ "157083": {
1542
+ "content": "<|reserved_token_188|>",
1543
+ "lstrip": false,
1544
+ "normalized": false,
1545
+ "rstrip": false,
1546
+ "single_word": false,
1547
+ "special": true
1548
+ },
1549
+ "157084": {
1550
+ "content": "<|reserved_token_189|>",
1551
+ "lstrip": false,
1552
+ "normalized": false,
1553
+ "rstrip": false,
1554
+ "single_word": false,
1555
+ "special": true
1556
+ },
1557
+ "157085": {
1558
+ "content": "<|reserved_token_190|>",
1559
+ "lstrip": false,
1560
+ "normalized": false,
1561
+ "rstrip": false,
1562
+ "single_word": false,
1563
+ "special": true
1564
+ },
1565
+ "157086": {
1566
+ "content": "<|reserved_token_191|>",
1567
+ "lstrip": false,
1568
+ "normalized": false,
1569
+ "rstrip": false,
1570
+ "single_word": false,
1571
+ "special": true
1572
+ },
1573
+ "157087": {
1574
+ "content": "<|reserved_token_192|>",
1575
+ "lstrip": false,
1576
+ "normalized": false,
1577
+ "rstrip": false,
1578
+ "single_word": false,
1579
+ "special": true
1580
+ },
1581
+ "157088": {
1582
+ "content": "<|reserved_token_193|>",
1583
+ "lstrip": false,
1584
+ "normalized": false,
1585
+ "rstrip": false,
1586
+ "single_word": false,
1587
+ "special": true
1588
+ },
1589
+ "157089": {
1590
+ "content": "<|reserved_token_194|>",
1591
+ "lstrip": false,
1592
+ "normalized": false,
1593
+ "rstrip": false,
1594
+ "single_word": false,
1595
+ "special": true
1596
+ },
1597
+ "157090": {
1598
+ "content": "<|reserved_token_195|>",
1599
+ "lstrip": false,
1600
+ "normalized": false,
1601
+ "rstrip": false,
1602
+ "single_word": false,
1603
+ "special": true
1604
+ },
1605
+ "157091": {
1606
+ "content": "<|reserved_token_196|>",
1607
+ "lstrip": false,
1608
+ "normalized": false,
1609
+ "rstrip": false,
1610
+ "single_word": false,
1611
+ "special": true
1612
+ },
1613
+ "157092": {
1614
+ "content": "<|reserved_token_197|>",
1615
+ "lstrip": false,
1616
+ "normalized": false,
1617
+ "rstrip": false,
1618
+ "single_word": false,
1619
+ "special": true
1620
+ },
1621
+ "157093": {
1622
+ "content": "<|reserved_token_198|>",
1623
+ "lstrip": false,
1624
+ "normalized": false,
1625
+ "rstrip": false,
1626
+ "single_word": false,
1627
+ "special": true
1628
+ },
1629
+ "157094": {
1630
+ "content": "<|reserved_token_199|>",
1631
+ "lstrip": false,
1632
+ "normalized": false,
1633
+ "rstrip": false,
1634
+ "single_word": false,
1635
+ "special": true
1636
+ },
1637
+ "157095": {
1638
+ "content": "<|reserved_token_200|>",
1639
+ "lstrip": false,
1640
+ "normalized": false,
1641
+ "rstrip": false,
1642
+ "single_word": false,
1643
+ "special": true
1644
+ },
1645
+ "157096": {
1646
+ "content": "<|reserved_token_201|>",
1647
+ "lstrip": false,
1648
+ "normalized": false,
1649
+ "rstrip": false,
1650
+ "single_word": false,
1651
+ "special": true
1652
+ },
1653
+ "157097": {
1654
+ "content": "<|reserved_token_202|>",
1655
+ "lstrip": false,
1656
+ "normalized": false,
1657
+ "rstrip": false,
1658
+ "single_word": false,
1659
+ "special": true
1660
+ },
1661
+ "157098": {
1662
+ "content": "<|reserved_token_203|>",
1663
+ "lstrip": false,
1664
+ "normalized": false,
1665
+ "rstrip": false,
1666
+ "single_word": false,
1667
+ "special": true
1668
+ },
1669
+ "157099": {
1670
+ "content": "<|reserved_token_204|>",
1671
+ "lstrip": false,
1672
+ "normalized": false,
1673
+ "rstrip": false,
1674
+ "single_word": false,
1675
+ "special": true
1676
+ },
1677
+ "157100": {
1678
+ "content": "<|reserved_token_205|>",
1679
+ "lstrip": false,
1680
+ "normalized": false,
1681
+ "rstrip": false,
1682
+ "single_word": false,
1683
+ "special": true
1684
+ },
1685
+ "157101": {
1686
+ "content": "<|reserved_token_206|>",
1687
+ "lstrip": false,
1688
+ "normalized": false,
1689
+ "rstrip": false,
1690
+ "single_word": false,
1691
+ "special": true
1692
+ },
1693
+ "157102": {
1694
+ "content": "<|reserved_token_207|>",
1695
+ "lstrip": false,
1696
+ "normalized": false,
1697
+ "rstrip": false,
1698
+ "single_word": false,
1699
+ "special": true
1700
+ },
1701
+ "157103": {
1702
+ "content": "<|reserved_token_208|>",
1703
+ "lstrip": false,
1704
+ "normalized": false,
1705
+ "rstrip": false,
1706
+ "single_word": false,
1707
+ "special": true
1708
+ },
1709
+ "157104": {
1710
+ "content": "<|reserved_token_209|>",
1711
+ "lstrip": false,
1712
+ "normalized": false,
1713
+ "rstrip": false,
1714
+ "single_word": false,
1715
+ "special": true
1716
+ },
1717
+ "157105": {
1718
+ "content": "<|reserved_token_210|>",
1719
+ "lstrip": false,
1720
+ "normalized": false,
1721
+ "rstrip": false,
1722
+ "single_word": false,
1723
+ "special": true
1724
+ },
1725
+ "157106": {
1726
+ "content": "<|reserved_token_211|>",
1727
+ "lstrip": false,
1728
+ "normalized": false,
1729
+ "rstrip": false,
1730
+ "single_word": false,
1731
+ "special": true
1732
+ },
1733
+ "157107": {
1734
+ "content": "<|reserved_token_212|>",
1735
+ "lstrip": false,
1736
+ "normalized": false,
1737
+ "rstrip": false,
1738
+ "single_word": false,
1739
+ "special": true
1740
+ },
1741
+ "157108": {
1742
+ "content": "<|reserved_token_213|>",
1743
+ "lstrip": false,
1744
+ "normalized": false,
1745
+ "rstrip": false,
1746
+ "single_word": false,
1747
+ "special": true
1748
+ },
1749
+ "157109": {
1750
+ "content": "<|reserved_token_214|>",
1751
+ "lstrip": false,
1752
+ "normalized": false,
1753
+ "rstrip": false,
1754
+ "single_word": false,
1755
+ "special": true
1756
+ },
1757
+ "157110": {
1758
+ "content": "<|reserved_token_215|>",
1759
+ "lstrip": false,
1760
+ "normalized": false,
1761
+ "rstrip": false,
1762
+ "single_word": false,
1763
+ "special": true
1764
+ },
1765
+ "157111": {
1766
+ "content": "<|reserved_token_216|>",
1767
+ "lstrip": false,
1768
+ "normalized": false,
1769
+ "rstrip": false,
1770
+ "single_word": false,
1771
+ "special": true
1772
+ },
1773
+ "157112": {
1774
+ "content": "<|reserved_token_217|>",
1775
+ "lstrip": false,
1776
+ "normalized": false,
1777
+ "rstrip": false,
1778
+ "single_word": false,
1779
+ "special": true
1780
+ },
1781
+ "157113": {
1782
+ "content": "<|reserved_token_218|>",
1783
+ "lstrip": false,
1784
+ "normalized": false,
1785
+ "rstrip": false,
1786
+ "single_word": false,
1787
+ "special": true
1788
+ },
1789
+ "157114": {
1790
+ "content": "<|reserved_token_219|>",
1791
+ "lstrip": false,
1792
+ "normalized": false,
1793
+ "rstrip": false,
1794
+ "single_word": false,
1795
+ "special": true
1796
+ },
1797
+ "157115": {
1798
+ "content": "<|reserved_token_220|>",
1799
+ "lstrip": false,
1800
+ "normalized": false,
1801
+ "rstrip": false,
1802
+ "single_word": false,
1803
+ "special": true
1804
+ },
1805
+ "157116": {
1806
+ "content": "<|reserved_token_221|>",
1807
+ "lstrip": false,
1808
+ "normalized": false,
1809
+ "rstrip": false,
1810
+ "single_word": false,
1811
+ "special": true
1812
+ },
1813
+ "157117": {
1814
+ "content": "<|reserved_token_222|>",
1815
+ "lstrip": false,
1816
+ "normalized": false,
1817
+ "rstrip": false,
1818
+ "single_word": false,
1819
+ "special": true
1820
+ },
1821
+ "157118": {
1822
+ "content": "<|reserved_token_223|>",
1823
+ "lstrip": false,
1824
+ "normalized": false,
1825
+ "rstrip": false,
1826
+ "single_word": false,
1827
+ "special": true
1828
+ },
1829
+ "157119": {
1830
+ "content": "<|reserved_token_224|>",
1831
+ "lstrip": false,
1832
+ "normalized": false,
1833
+ "rstrip": false,
1834
+ "single_word": false,
1835
+ "special": true
1836
+ },
1837
+ "157120": {
1838
+ "content": "<|reserved_token_225|>",
1839
+ "lstrip": false,
1840
+ "normalized": false,
1841
+ "rstrip": false,
1842
+ "single_word": false,
1843
+ "special": true
1844
+ },
1845
+ "157121": {
1846
+ "content": "<|reserved_token_226|>",
1847
+ "lstrip": false,
1848
+ "normalized": false,
1849
+ "rstrip": false,
1850
+ "single_word": false,
1851
+ "special": true
1852
+ },
1853
+ "157122": {
1854
+ "content": "<|reserved_token_227|>",
1855
+ "lstrip": false,
1856
+ "normalized": false,
1857
+ "rstrip": false,
1858
+ "single_word": false,
1859
+ "special": true
1860
+ },
1861
+ "157123": {
1862
+ "content": "<|reserved_token_228|>",
1863
+ "lstrip": false,
1864
+ "normalized": false,
1865
+ "rstrip": false,
1866
+ "single_word": false,
1867
+ "special": true
1868
+ },
1869
+ "157124": {
1870
+ "content": "<|reserved_token_229|>",
1871
+ "lstrip": false,
1872
+ "normalized": false,
1873
+ "rstrip": false,
1874
+ "single_word": false,
1875
+ "special": true
1876
+ },
1877
+ "157125": {
1878
+ "content": "<|reserved_token_230|>",
1879
+ "lstrip": false,
1880
+ "normalized": false,
1881
+ "rstrip": false,
1882
+ "single_word": false,
1883
+ "special": true
1884
+ },
1885
+ "157126": {
1886
+ "content": "<|reserved_token_231|>",
1887
+ "lstrip": false,
1888
+ "normalized": false,
1889
+ "rstrip": false,
1890
+ "single_word": false,
1891
+ "special": true
1892
+ },
1893
+ "157127": {
1894
+ "content": "<|reserved_token_232|>",
1895
+ "lstrip": false,
1896
+ "normalized": false,
1897
+ "rstrip": false,
1898
+ "single_word": false,
1899
+ "special": true
1900
+ },
1901
+ "157128": {
1902
+ "content": "<|reserved_token_233|>",
1903
+ "lstrip": false,
1904
+ "normalized": false,
1905
+ "rstrip": false,
1906
+ "single_word": false,
1907
+ "special": true
1908
+ },
1909
+ "157129": {
1910
+ "content": "<|reserved_token_234|>",
1911
+ "lstrip": false,
1912
+ "normalized": false,
1913
+ "rstrip": false,
1914
+ "single_word": false,
1915
+ "special": true
1916
+ },
1917
+ "157130": {
1918
+ "content": "<|reserved_token_235|>",
1919
+ "lstrip": false,
1920
+ "normalized": false,
1921
+ "rstrip": false,
1922
+ "single_word": false,
1923
+ "special": true
1924
+ },
1925
+ "157131": {
1926
+ "content": "<|reserved_token_236|>",
1927
+ "lstrip": false,
1928
+ "normalized": false,
1929
+ "rstrip": false,
1930
+ "single_word": false,
1931
+ "special": true
1932
+ },
1933
+ "157132": {
1934
+ "content": "<|reserved_token_237|>",
1935
+ "lstrip": false,
1936
+ "normalized": false,
1937
+ "rstrip": false,
1938
+ "single_word": false,
1939
+ "special": true
1940
+ },
1941
+ "157133": {
1942
+ "content": "<|reserved_token_238|>",
1943
+ "lstrip": false,
1944
+ "normalized": false,
1945
+ "rstrip": false,
1946
+ "single_word": false,
1947
+ "special": true
1948
+ },
1949
+ "157134": {
1950
+ "content": "<|reserved_token_239|>",
1951
+ "lstrip": false,
1952
+ "normalized": false,
1953
+ "rstrip": false,
1954
+ "single_word": false,
1955
+ "special": true
1956
+ },
1957
+ "157135": {
1958
+ "content": "<|reserved_token_240|>",
1959
+ "lstrip": false,
1960
+ "normalized": false,
1961
+ "rstrip": false,
1962
+ "single_word": false,
1963
+ "special": true
1964
+ },
1965
+ "157136": {
1966
+ "content": "<|reserved_token_241|>",
1967
+ "lstrip": false,
1968
+ "normalized": false,
1969
+ "rstrip": false,
1970
+ "single_word": false,
1971
+ "special": true
1972
+ },
1973
+ "157137": {
1974
+ "content": "<|reserved_token_242|>",
1975
+ "lstrip": false,
1976
+ "normalized": false,
1977
+ "rstrip": false,
1978
+ "single_word": false,
1979
+ "special": true
1980
+ },
1981
+ "157138": {
1982
+ "content": "<|reserved_token_243|>",
1983
+ "lstrip": false,
1984
+ "normalized": false,
1985
+ "rstrip": false,
1986
+ "single_word": false,
1987
+ "special": true
1988
+ },
1989
+ "157139": {
1990
+ "content": "<|reserved_token_244|>",
1991
+ "lstrip": false,
1992
+ "normalized": false,
1993
+ "rstrip": false,
1994
+ "single_word": false,
1995
+ "special": true
1996
+ },
1997
+ "157140": {
1998
+ "content": "<|reserved_token_245|>",
1999
+ "lstrip": false,
2000
+ "normalized": false,
2001
+ "rstrip": false,
2002
+ "single_word": false,
2003
+ "special": true
2004
+ },
2005
+ "157141": {
2006
+ "content": "<|reserved_token_246|>",
2007
+ "lstrip": false,
2008
+ "normalized": false,
2009
+ "rstrip": false,
2010
+ "single_word": false,
2011
+ "special": true
2012
+ },
2013
+ "157142": {
2014
+ "content": "<|reserved_token_247|>",
2015
+ "lstrip": false,
2016
+ "normalized": false,
2017
+ "rstrip": false,
2018
+ "single_word": false,
2019
+ "special": true
2020
+ },
2021
+ "157143": {
2022
+ "content": "<|reserved_token_248|>",
2023
+ "lstrip": false,
2024
+ "normalized": false,
2025
+ "rstrip": false,
2026
+ "single_word": false,
2027
+ "special": true
2028
+ },
2029
+ "157144": {
2030
+ "content": "<|reserved_token_249|>",
2031
+ "lstrip": false,
2032
+ "normalized": false,
2033
+ "rstrip": false,
2034
+ "single_word": false,
2035
+ "special": true
2036
+ },
2037
+ "157145": {
2038
+ "content": "<|reserved_token_250|>",
2039
+ "lstrip": false,
2040
+ "normalized": false,
2041
+ "rstrip": false,
2042
+ "single_word": false,
2043
+ "special": true
2044
+ },
2045
+ "157146": {
2046
+ "content": "<|reserved_token_251|>",
2047
+ "lstrip": false,
2048
+ "normalized": false,
2049
+ "rstrip": false,
2050
+ "single_word": false,
2051
+ "special": true
2052
+ },
2053
+ "157147": {
2054
+ "content": "<|reserved_token_252|>",
2055
+ "lstrip": false,
2056
+ "normalized": false,
2057
+ "rstrip": false,
2058
+ "single_word": false,
2059
+ "special": true
2060
+ },
2061
+ "157148": {
2062
+ "content": "<|reserved_token_253|>",
2063
+ "lstrip": false,
2064
+ "normalized": false,
2065
+ "rstrip": false,
2066
+ "single_word": false,
2067
+ "special": true
2068
+ },
2069
+ "157149": {
2070
+ "content": "<|reserved_token_254|>",
2071
+ "lstrip": false,
2072
+ "normalized": false,
2073
+ "rstrip": false,
2074
+ "single_word": false,
2075
+ "special": true
2076
+ },
2077
+ "157150": {
2078
+ "content": "<|reserved_token_255|>",
2079
+ "lstrip": false,
2080
+ "normalized": false,
2081
+ "rstrip": false,
2082
+ "single_word": false,
2083
+ "special": true
2084
+ },
2085
+ "157151": {
2086
+ "content": "<role>",
2087
+ "lstrip": false,
2088
+ "normalized": false,
2089
+ "rstrip": false,
2090
+ "single_word": false,
2091
+ "special": true
2092
+ },
2093
+ "157152": {
2094
+ "content": "</role>",
2095
+ "lstrip": false,
2096
+ "normalized": false,
2097
+ "rstrip": false,
2098
+ "single_word": false,
2099
+ "special": true
2100
+ }
2101
+ },
2102
+ "bos_token": "<|startoftext|>",
2103
+ "clean_up_tokenization_spaces": false,
2104
+ "cls_token": "[CLS]",
2105
+ "eos_token": "<|role_end|>",
2106
+ "fast_tokenizer": true,
2107
+ "gmask_token": "[gMASK]",
2108
+ "merges_file": null,
2109
+ "model_max_length": 1000000000000000019884624838656,
2110
+ "pad_token": "<|endoftext|>",
2111
+ "tokenizer_class": "PreTrainedTokenizerFast",
2112
+ "trust_remote_code": true
2113
+ }
vllm_patch/README.md ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Local patch: keep the per-layer SwiGLU clamp on the compressed-tensors MXFP4 MoE path
2
+
3
+ Applied on top of `inclusionAI/vllm@ling_3_0` (`e0040c3` "[Model] Add Bailing V3 support").
4
+
5
+ ## The problem
6
+
7
+ Ling-3.0-flash declares a per-layer clamped SwiGLU:
8
+
9
+ ```json
10
+ "expert_swiglu_limit_list": [0]*35 + [4]*7, // layers 35-41
11
+ "share_expert_swiglu_limit_list": [0]*34 + [5]*6 + [7]*2
12
+ ```
13
+
14
+ `bailing_moe_v3.py` reads it correctly (`_get_layer_swiglu_limit`) and passes
15
+ `swiglu_limit=` into `FusedMoEFactory`, which stores it on `RoutedExperts.swiglu_limit`.
16
+ The unquantized path then honours it — `unquantized_fused_moe_method.py` reads
17
+ `getattr(layer, "swiglu_limit", None)`.
18
+
19
+ The compressed-tensors MXFP4 path did not. Three independent gaps, all of which had to
20
+ be closed for the value to reach the kernel:
21
+
22
+ 1. `CompressedTensorsW4A4Mxfp4MoEMethod.get_fused_moe_quant_config` never read
23
+ `layer.swiglu_limit`.
24
+ 2. `mxfp4_moe_quant_config` (the W4A4 cutlass builder) had no `gemm1_clamp_limit`
25
+ parameter at all, so even a caller that wanted to pass one could not.
26
+ 3. `run_cutlass_moe_mxfp4` took no clamp argument and called
27
+ `apply_moe_activation(activation, c2, c1)` bare. For `MoEActivation.SILU` it also
28
+ takes a fused `ops.silu_and_mul_mxfp4_experts_quant` fast path that has no clamp
29
+ variant.
30
+
31
+ Net effect: on an MXFP4 checkpoint, layers 35-41 computed **unclamped** SwiGLU while
32
+ BF16 clamped them. The divergence is large, not marginal — for a gate activation of
33
+ 10.0, `silu(10)*2 = 20.0` against `silu(4)*2 = 7.84`.
34
+
35
+ This is not specific to our quantization: any MXFP4 compressed-tensors checkpoint of a
36
+ model with a SwiGLU limit hits it (gpt-oss-style `limit=7.0` models included).
37
+
38
+ ## The change
39
+
40
+ | File | Change |
41
+ |---|---|
42
+ | `vllm/model_executor/layers/fused_moe/config.py` | `mxfp4_moe_quant_config` accepts `gemm1_clamp_limit` and forwards it to `FusedMoEQuantConfig.make` (which already supported it). |
43
+ | `.../compressed_tensors_moe/compressed_tensors_moe_w4a4_mxfp4.py` | `get_fused_moe_quant_config` reads `getattr(layer, "swiglu_limit", None)` and passes it down both the cutlass (`gemm1_clamp_limit=`) and Marlin (`swiglu_limit=`) branches. |
44
+ | `vllm/model_executor/layers/fused_moe/experts/cutlass_moe.py` | `run_cutlass_moe_mxfp4` takes `swiglu_limit`; when set, SILU falls out of the fused fast path into `apply_moe_activation(..., clamp_limit=...)`. `CutlassExpertsMxfp4.apply` passes `self.quant_config.gemm1_clamp_limit`. |
45
+
46
+ `c2` and `workspace2` are allocated unconditionally (`workspace2 = (M * topk, N)`), so
47
+ the generic path is safe to take for any activation.
48
+
49
+ Models that declare no limit are unaffected: `swiglu_limit` stays `None`, the quant
50
+ config field stays `None`, and SILU keeps the fused fast path.
51
+
52
+ ## Verification
53
+
54
+ ```
55
+ mxfp4_moe_quant_config(..., gemm1_clamp_limit=4.0).gemm1_clamp_limit -> 4.0
56
+ mxfp4_moe_quant_config(...) .gemm1_clamp_limit -> None
57
+ get_fused_moe_quant_config(layer.swiglu_limit=4.0).gemm1_clamp_limit -> 4.0
58
+ get_fused_moe_quant_config(layer.swiglu_limit=None).gemm1_clamp_limit -> None
59
+ apply_moe_activation(SILU, x=[10,-10,2,1]) -> [20.0, -0.00045]
60
+ apply_moe_activation(SILU, x=[10,-10,2,1], clamp_limit=4) -> [ 7.844, -0.00045]
61
+ ```
62
+
63
+ All four edits are pure Python, so an editable install picks them up with no rebuild.
vllm_patch/compressed_tensors_moe_w4a4_mxfp4.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+
5
+ import torch
6
+
7
+ import vllm.model_executor.layers.fused_moe.modular_kernel as mk
8
+ from vllm.logger import init_logger
9
+ from vllm.model_executor.layers.fused_moe import (
10
+ FusedMoeWeightScaleSupported,
11
+ RoutedExperts,
12
+ SharedExperts,
13
+ )
14
+ from vllm.model_executor.layers.fused_moe.config import (
15
+ FusedMoEQuantConfig,
16
+ mxfp4_moe_quant_config,
17
+ )
18
+ from vllm.model_executor.layers.fused_moe.experts.cutlass_moe import (
19
+ CutlassExpertsMxfp4,
20
+ )
21
+ from vllm.model_executor.layers.fused_moe.experts.marlin_moe import (
22
+ MarlinExperts,
23
+ )
24
+ from vllm.model_executor.layers.fused_moe.experts.xpu_moe import (
25
+ XPUExpertsMxFp4,
26
+ )
27
+ from vllm.model_executor.layers.fused_moe.oracle.mxfp4 import (
28
+ Mxfp4MoeBackend,
29
+ make_mxfp4_moe_kernel,
30
+ make_mxfp4_moe_quant_config,
31
+ )
32
+ from vllm.model_executor.layers.quantization.compressed_tensors.compressed_tensors_moe import ( # noqa E501
33
+ CompressedTensorsMoEMethod,
34
+ )
35
+ from vllm.model_executor.layers.quantization.utils.marlin_utils_fp4 import (
36
+ prepare_moe_fp4_layer_for_marlin,
37
+ )
38
+ from vllm.model_executor.utils import set_weight_attrs
39
+ from vllm.platforms import current_platform
40
+
41
+ logger = init_logger(__name__)
42
+
43
+
44
+ class CompressedTensorsW4A4Mxfp4MoEMethod(CompressedTensorsMoEMethod):
45
+ def __init__(self, moe):
46
+ super().__init__(moe)
47
+ self.group_size = 32
48
+ self.mxfp4_backend = Mxfp4MoeBackend.MARLIN
49
+ # use cutlass if supported, otherwise fallback to marlin for weight-only FP4
50
+ self.use_cutlass_mxfp4 = CutlassExpertsMxfp4._supports_current_device()
51
+ self.experts_cls: type[mk.FusedMoEExperts]
52
+ if self.use_cutlass_mxfp4:
53
+ logger.info_once("Using CutlassExpertsMxfp4 for MXFP4 MoE")
54
+ self.experts_cls = CutlassExpertsMxfp4
55
+ elif current_platform.is_xpu():
56
+ self.mxfp4_backend = Mxfp4MoeBackend.XPU
57
+ self.experts_cls = XPUExpertsMxFp4
58
+ logger.info_once("Using XPUExpertsMxFp4 for MXFP4 MoE on XPU platform")
59
+ else:
60
+ logger.info_once("Using MarlinExperts for MXFP4 MoE")
61
+ self.experts_cls = MarlinExperts
62
+
63
+ def create_weights(
64
+ self,
65
+ layer: torch.nn.Module,
66
+ num_experts: int,
67
+ hidden_size: int,
68
+ intermediate_size_per_partition: int,
69
+ params_dtype: torch.dtype,
70
+ **extra_weight_attrs,
71
+ ):
72
+ layer.num_experts = num_experts
73
+ layer.params_dtype = params_dtype
74
+
75
+ w13_weight = torch.nn.Parameter(
76
+ torch.empty(
77
+ num_experts,
78
+ 2 * intermediate_size_per_partition,
79
+ # 2 fp4 items are packed in the input dimension
80
+ hidden_size // 2,
81
+ requires_grad=False,
82
+ dtype=torch.uint8,
83
+ ),
84
+ requires_grad=False,
85
+ )
86
+ layer.register_parameter("w13_weight_packed", w13_weight)
87
+ set_weight_attrs(w13_weight, extra_weight_attrs)
88
+
89
+ w2_weight = torch.nn.Parameter(
90
+ torch.empty(
91
+ num_experts,
92
+ hidden_size,
93
+ # 2 fp4 items are packed in the input dimension
94
+ intermediate_size_per_partition // 2,
95
+ dtype=torch.uint8,
96
+ ),
97
+ requires_grad=False,
98
+ )
99
+ layer.register_parameter("w2_weight_packed", w2_weight)
100
+ set_weight_attrs(w2_weight, extra_weight_attrs)
101
+
102
+ w13_weight_scale = torch.nn.Parameter(
103
+ torch.empty(
104
+ num_experts,
105
+ 2 * intermediate_size_per_partition,
106
+ # 2 fp4 items are packed in the input dimension
107
+ hidden_size // self.group_size,
108
+ dtype=torch.uint8,
109
+ ),
110
+ requires_grad=False,
111
+ )
112
+ layer.register_parameter("w13_weight_scale", w13_weight_scale)
113
+ extra_weight_attrs.update(
114
+ {"quant_method": FusedMoeWeightScaleSupported.GROUP.value}
115
+ )
116
+ set_weight_attrs(w13_weight_scale, extra_weight_attrs)
117
+
118
+ w2_weight_scale = torch.nn.Parameter(
119
+ torch.empty(
120
+ num_experts,
121
+ hidden_size,
122
+ # 2 fp4 items are packed in the input dimension
123
+ intermediate_size_per_partition // self.group_size,
124
+ dtype=torch.uint8,
125
+ ),
126
+ requires_grad=False,
127
+ )
128
+ layer.register_parameter("w2_weight_scale", w2_weight_scale)
129
+ set_weight_attrs(w2_weight_scale, extra_weight_attrs)
130
+
131
+ def get_fused_moe_quant_config(
132
+ self, layer: torch.nn.Module
133
+ ) -> FusedMoEQuantConfig | None:
134
+ # A per-layer SwiGLU clamp is part of the model's forward, not of the
135
+ # quantization scheme — it has to survive into the MXFP4 kernels the same
136
+ # way it does for the unquantized path.
137
+ swiglu_limit = getattr(layer, "swiglu_limit", None)
138
+ if self.use_cutlass_mxfp4:
139
+ # W4A4: both weights and activations quantized to MXFP4
140
+ return mxfp4_moe_quant_config(
141
+ w1_scale=layer.w13_weight_scale,
142
+ w2_scale=layer.w2_weight_scale,
143
+ gemm1_clamp_limit=swiglu_limit,
144
+ )
145
+ else:
146
+ # W4A16: weight-only via Marlin
147
+ return make_mxfp4_moe_quant_config(
148
+ mxfp4_backend=self.mxfp4_backend,
149
+ w1_scale=layer.w13_weight_scale,
150
+ w2_scale=layer.w2_weight_scale,
151
+ swiglu_limit=swiglu_limit,
152
+ layer=layer,
153
+ )
154
+
155
+ def process_weights_after_loading(self, layer: RoutedExperts) -> None:
156
+ layer.w13_weight = torch.nn.Parameter(
157
+ layer.w13_weight_packed.data, requires_grad=False
158
+ )
159
+ delattr(layer, "w13_weight_packed")
160
+
161
+ layer.w2_weight = torch.nn.Parameter(
162
+ layer.w2_weight_packed.data, requires_grad=False
163
+ )
164
+ delattr(layer, "w2_weight_packed")
165
+
166
+ if self.use_cutlass_mxfp4:
167
+ # Swizzle weight scales from flat checkpoint layout [E, N, K//32]
168
+ # to CUTLASS tiled layout [E, numMTiles*numKTiles*512].
169
+ from vllm.model_executor.layers.fused_moe.experts.cutlass_moe import (
170
+ swizzle_mxfp4_scales,
171
+ )
172
+
173
+ E = layer.w13_weight_scale.shape[0]
174
+ w13_N = layer.w13_weight_scale.shape[1]
175
+ w13_scale_K = layer.w13_weight_scale.shape[2]
176
+ w13_K = w13_scale_K * 32
177
+
178
+ w2_M = layer.w2_weight_scale.shape[1]
179
+ w2_scale_N = layer.w2_weight_scale.shape[2]
180
+ w2_N = w2_scale_N * 32
181
+
182
+ swizzled_w13 = []
183
+ swizzled_w2 = []
184
+ for e_idx in range(E):
185
+ s13 = layer.w13_weight_scale[e_idx]
186
+ sw13 = swizzle_mxfp4_scales(s13, w13_N, w13_K)
187
+ swizzled_w13.append(sw13.reshape(w13_N, w13_scale_K))
188
+ s2 = layer.w2_weight_scale[e_idx]
189
+ sw2 = swizzle_mxfp4_scales(s2, w2_M, w2_N)
190
+ swizzled_w2.append(sw2.reshape(w2_M, w2_scale_N))
191
+ layer.w13_weight_scale = torch.nn.Parameter(
192
+ torch.stack(swizzled_w13), requires_grad=False
193
+ )
194
+ layer.w2_weight_scale = torch.nn.Parameter(
195
+ torch.stack(swizzled_w2), requires_grad=False
196
+ )
197
+ elif current_platform.is_xpu():
198
+ pass
199
+ else:
200
+ logger.warning_once(
201
+ "Your GPU does not have native support for FP4 computation "
202
+ "but FP4 quantization is being used. Weight-only FP4 "
203
+ "compression will be used leveraging the Marlin kernel. "
204
+ "This may degrade performance for compute-heavy workloads."
205
+ )
206
+ prepare_moe_fp4_layer_for_marlin(layer)
207
+
208
+ self.moe_quant_config = self.get_fused_moe_quant_config(layer)
209
+ if self.moe_quant_config is not None:
210
+ self.moe_kernel = make_mxfp4_moe_kernel(
211
+ moe_quant_config=self.moe_quant_config,
212
+ moe_config=self.moe,
213
+ experts_cls=self.experts_cls,
214
+ mxfp4_backend=self.mxfp4_backend,
215
+ routing_tables=layer._expert_routing_tables(),
216
+ )
217
+
218
+ def apply(
219
+ self,
220
+ layer: RoutedExperts,
221
+ x: torch.Tensor,
222
+ topk_weights: torch.Tensor,
223
+ topk_ids: torch.Tensor,
224
+ shared_experts: SharedExperts | None,
225
+ shared_experts_input: torch.Tensor | None,
226
+ ) -> torch.Tensor:
227
+ assert self.moe_kernel is not None
228
+ return self.moe_kernel.apply(
229
+ x,
230
+ layer.w13_weight,
231
+ layer.w2_weight,
232
+ topk_weights,
233
+ topk_ids,
234
+ activation=layer.activation,
235
+ global_num_experts=layer.global_num_experts,
236
+ expert_map=layer.expert_map,
237
+ apply_router_weight_on_input=layer.apply_router_weight_on_input,
238
+ shared_experts=shared_experts,
239
+ shared_experts_input=shared_experts_input,
240
+ )
vllm_patch/config.py ADDED
@@ -0,0 +1,1462 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+ from dataclasses import dataclass
4
+ from enum import IntEnum
5
+ from typing import Union
6
+
7
+ import torch
8
+
9
+ from vllm.config import ParallelConfig, SchedulerConfig
10
+ from vllm.config.kernel import MoEBackend
11
+ from vllm.distributed import get_dp_group, get_pcp_group, get_tensor_model_parallel_rank
12
+ from vllm.logger import init_logger
13
+ from vllm.model_executor.layers.fused_moe.activation import MoEActivation
14
+ from vllm.model_executor.layers.quantization.utils.ocp_mx_utils import (
15
+ OCP_MX_DTYPES,
16
+ OCP_MX_Scheme,
17
+ )
18
+ from vllm.model_executor.layers.quantization.utils.quant_utils import GroupShape
19
+ from vllm.platforms import current_platform
20
+ from vllm.utils.import_utils import has_triton_kernels
21
+ from vllm.utils.math_utils import cdiv
22
+
23
+ logger = init_logger(__name__)
24
+
25
+ if has_triton_kernels():
26
+ try:
27
+ from triton_kernels.matmul_ogs import PrecisionConfig
28
+ except (ImportError, AttributeError) as e:
29
+ logger.error(
30
+ "Failed to import Triton kernels. Please make sure your triton "
31
+ "version is compatible. Error: %s",
32
+ e,
33
+ )
34
+
35
+
36
+ def _get_config_dtype_str(
37
+ dtype: torch.dtype,
38
+ use_fp8_w8a8: bool = False,
39
+ use_fp8_w8a16: bool = False,
40
+ use_int8_w8a16: bool = False,
41
+ use_int4_w4a16: bool = False,
42
+ ocp_mx_scheme: str | None = None,
43
+ ) -> str | None:
44
+ """
45
+ Return a string used to construct the filename that contains the
46
+ tuning info for a particular quantization scheme. See
47
+ try_get_optimal_moe_config in fused_moe.py.
48
+ """
49
+ if use_fp8_w8a8:
50
+ return "fp8_w8a8"
51
+ elif use_fp8_w8a16:
52
+ return "fp8_w8a16"
53
+ elif use_int8_w8a16:
54
+ return "int8_w8a16"
55
+ elif use_int4_w4a16:
56
+ return "int4_w4a16"
57
+ elif ocp_mx_scheme is not None:
58
+ # The output of this function is passed to `try_get_optimal_moe_config`,
59
+ # and as we only simulate OCP MX execution in fused_moe for now,
60
+ # we will NOT look for `*,dtype=w_mxfp4_a_mxfp4.json` for now.
61
+ return None
62
+ elif dtype == torch.float:
63
+ # avoiding cases where kernel fails when float32 MoE
64
+ # use fp16/bfloat16 configs
65
+ return "float32"
66
+ return None
67
+
68
+
69
+ def _quant_flags_to_group_shape(
70
+ quant_dtype: torch.dtype | str | None,
71
+ per_act_token_quant: bool,
72
+ per_out_ch_quant: bool,
73
+ block_shape: list[int] | None,
74
+ ) -> tuple[GroupShape | None, GroupShape | None]:
75
+ """
76
+ Convert MoE quantization flags into more generic GroupShapes.
77
+ """
78
+ a_shape: GroupShape | None
79
+ w_shape: GroupShape | None
80
+ if block_shape is not None:
81
+ assert not per_act_token_quant
82
+ assert not per_out_ch_quant
83
+ # TODO(bnell): this is not quite right for activations since first
84
+ # dim should be 1.
85
+ a_shape = GroupShape(row=block_shape[0], col=block_shape[1])
86
+ w_shape = GroupShape(row=block_shape[0], col=block_shape[1])
87
+ else:
88
+ w_shape = None
89
+ a_shape = None if quant_dtype is None else GroupShape.PER_TENSOR
90
+
91
+ if per_act_token_quant:
92
+ a_shape = GroupShape.PER_TOKEN
93
+
94
+ if per_out_ch_quant:
95
+ w_shape = GroupShape.PER_TOKEN
96
+
97
+ return a_shape, w_shape
98
+
99
+
100
+ # The type of method in top-K routing
101
+ # Please keep this in sync with the counterpart defined in https://github.com/flashinfer-ai/flashinfer/blob/main/include/flashinfer/trtllm/fused_moe/runner.h
102
+ class RoutingMethodType(IntEnum):
103
+ # Default: Softmax -> TopK
104
+ Default = (0,)
105
+ # Renormalize: TopK -> Softmax
106
+ Renormalize = (1,)
107
+ # DeepSeekV3: Sigmoid -> RoutingBiasAdd -> Top2 in group -> Top4 groups
108
+ # -> Top8 experts from the Top4 groups
109
+ DeepSeekV3 = (2,)
110
+ # Llama4: Top1 -> Sigmoid
111
+ Llama4 = (3,)
112
+ # RenormalizeNaive: Softmax -> TopK -> Renormalize
113
+ RenormalizeNaive = (4,)
114
+ # TopK: TopK (no softmax)
115
+ TopK = (5,)
116
+ # SigmoidRenorm: Sigmoid -> TopK -> Renormalize (divide by sum of top-K)
117
+ SigmoidRenorm = (6,)
118
+ # MiniMax2: Sigmoid + Bias -> TopK -> ScaledSumNormalize
119
+ # (routeScale=1.0, epsilon=1e-20)
120
+ MiniMax2 = (7,)
121
+ # Sigmoid: Sigmoid -> TopK (no renormalization)
122
+ Sigmoid = (8,)
123
+ # Unspecified
124
+ Unspecified = (9,)
125
+ # other routing types (not passed to FlashInfer kernels)
126
+ # Deepseek V4 -> sqrtsoftplus + Bias + Normalize
127
+ DeepseekV4 = (100,)
128
+ Custom = (101,)
129
+ Simulated = (102,)
130
+
131
+
132
+ def get_routing_method_type(
133
+ scoring_func: str,
134
+ top_k: int,
135
+ renormalize: bool,
136
+ num_expert_group: int | None,
137
+ has_e_score_bias: bool,
138
+ routed_scaling_factor: float | None = 1.0,
139
+ ) -> RoutingMethodType:
140
+ if scoring_func == "sqrtsoftplus":
141
+ # DeepSeek V4 uses sqrtsoftplus routing with optional routing bias
142
+ # and top-k renormalization.
143
+ if renormalize:
144
+ return RoutingMethodType.DeepseekV4
145
+ else:
146
+ return RoutingMethodType.Unspecified
147
+
148
+ if has_e_score_bias:
149
+ if scoring_func == "sigmoid":
150
+ if not renormalize:
151
+ return RoutingMethodType.Unspecified
152
+ if (num_expert_group or 0) > 0:
153
+ return RoutingMethodType.DeepSeekV3
154
+ if routed_scaling_factor in (None, 1.0):
155
+ return RoutingMethodType.MiniMax2
156
+ return RoutingMethodType.Unspecified
157
+ else:
158
+ return RoutingMethodType.Unspecified
159
+
160
+ if scoring_func == "sigmoid":
161
+ if renormalize:
162
+ return RoutingMethodType.SigmoidRenorm
163
+ return RoutingMethodType.Sigmoid
164
+
165
+ if scoring_func == "softmax":
166
+ if renormalize:
167
+ return RoutingMethodType.RenormalizeNaive
168
+ else:
169
+ return RoutingMethodType.Default
170
+
171
+ return RoutingMethodType.Unspecified
172
+
173
+
174
+ @dataclass
175
+ class FusedMoEQuantDesc:
176
+ """
177
+ A quantization descriptor for fused MoE ops. This class can describe
178
+ either activations or weights.
179
+ """
180
+
181
+ # The quantized type of this parameters. None means unquantized or
182
+ # already quantized.
183
+ # TODO (bnell): use scalar_type instead of Union.
184
+ dtype: torch.dtype | str | None = None
185
+
186
+ # A field that describes the quantization group shape, from quant_utils.py.
187
+ # * (-1, -1) for per-tensor quantization
188
+ # * (1, -1) for per-row quantization
189
+ # * (-1, 1) for per-column quantization
190
+ # * (128, 128) for 128x128 deepseek style block quantization
191
+ # * (1, 128) for deepseek style activation quantization
192
+ # (i.e. per-token-per-group)
193
+ shape: GroupShape | None = None
194
+
195
+ # Quantization scales.
196
+ # TODO(bnell): maybe put PrecisionConfigs in subclass of QuantDesc?
197
+ scale: Union[torch.Tensor, "PrecisionConfig", None] = None
198
+
199
+ # Quantization alphas or gscales, used for nvfp4 types.
200
+ # W4A8 FP8: used for per-channel scales
201
+ # TODO(bnell): put some of these in subclasses
202
+ alpha_or_gscale: torch.Tensor | None = None
203
+
204
+ # Zero points for int4/int8 types
205
+ zp: torch.Tensor | None = None
206
+
207
+ # Biases for GPT triton MoE
208
+ bias: torch.Tensor | None = None
209
+
210
+
211
+ # TODO(bnell): have subclasses for specific moe methods?
212
+ # e.g. for specific arguments bias, precision, etc.
213
+ @dataclass
214
+ class FusedMoEQuantConfig:
215
+ """
216
+ The FusedMoEQuantConfig contains all the quantization parameters for
217
+ a single FusedMoEMethodBase operation. It consists of four
218
+ FusedMoEQuantDescs, one for each activation and set of weights.
219
+
220
+ Each FusedMoEMethodBase must implement a get_fused_moe_quant_config
221
+ method to construct a FusedMoEQuantConfig for use with that class.
222
+
223
+ FusedMoEQuant configs are only used for modular kernels, fused_experts
224
+ (from fused_moe.py), cutlass_moe_fp[48], rocm_aiter_fused_experts and
225
+ triton_kernel_moe_forward. Other MoE methods can ignore the
226
+ FusedMoEQuantConfig (for now) and hardcode it to None.
227
+
228
+ There are currently some restrictions on what can be expressed:
229
+ - Most MoE ops only support similar quantization strategies for
230
+ each parameter, e.g. both weights must have the same GroupShape
231
+ and both activations must share the same GroupShape. One exception to
232
+ this is the cutlass moe which allows per channel quantization on the
233
+ outputs. Note: this restrictions are not always rigorously checked.
234
+ - Not all fused MoE functions support all the parameters, e.g. zero points,
235
+ global scales, alphas and biases are not universally supported.
236
+ - Fully general GroupShapes are not allowed. Activations only support
237
+ per token, per tensor or K-blocked.
238
+ - Weights are not required to have a GroupShape since they have already
239
+ been quantized.
240
+
241
+ Other notes:
242
+ - PrecisionConfigs are specific to GPT OSS Triton.
243
+ - As a follow up it would probably make sense to subclass FusedMoEQuantDesc
244
+ or FusedMoEQuantConfig for particular FusedMoEMethodBase subclasses
245
+ so that only the required quantization parameters are used/stored.
246
+ """
247
+
248
+ # TODO(bnell) make sure a1_scales/a2_scales don't interfere with chunking
249
+ _a1: FusedMoEQuantDesc
250
+ _a2: FusedMoEQuantDesc
251
+ _w1: FusedMoEQuantDesc
252
+ _w2: FusedMoEQuantDesc
253
+ is_scale_swizzled: bool = True
254
+
255
+ # MXFP4-specific TRTLLM parameters for SwiGLU activation clamping.
256
+ # These correspond to gemm1_alpha, gemm1_beta, gemm1_clamp_limit
257
+ # in TrtLlmMxfp4ExpertsBase.
258
+ gemm1_alpha: float | None = None
259
+ gemm1_beta: float | None = None
260
+ gemm1_clamp_limit: float | None = None
261
+
262
+ mx_alignment: int = 0
263
+
264
+ def __post_init__(self):
265
+ assert not self.per_act_token_quant or self.block_shape is None, (
266
+ "illegal quantization"
267
+ )
268
+
269
+ #
270
+ # Convenience accessors for various properties.
271
+ #
272
+
273
+ @property
274
+ def quant_dtype(self) -> torch.dtype | str | None:
275
+ return self._a1.dtype
276
+
277
+ @property
278
+ def weight_quant_dtype(self) -> torch.dtype | str | None:
279
+ return self._w1.dtype
280
+
281
+ @property
282
+ def is_quantized(self) -> bool:
283
+ return self.quant_dtype is not None
284
+
285
+ @property
286
+ def is_per_act_token(self) -> bool:
287
+ return self._a1.shape == GroupShape.PER_TOKEN
288
+
289
+ @property
290
+ def per_act_token_quant(self) -> bool:
291
+ return self._a1.shape == GroupShape.PER_TOKEN
292
+
293
+ @property
294
+ def per_out_ch_quant(self) -> bool:
295
+ return self._w1.shape == GroupShape.PER_TOKEN
296
+
297
+ @property
298
+ def is_per_tensor(self) -> bool:
299
+ return self._a1.shape == GroupShape.PER_TENSOR
300
+
301
+ @property
302
+ def block_shape(self) -> list[int] | None:
303
+ if (
304
+ self._a1.shape is not None
305
+ and self._a1.shape != GroupShape.PER_TENSOR
306
+ and self._a1.shape != GroupShape.PER_TOKEN
307
+ ):
308
+ return [self._a1.shape.row, self._a1.shape.col]
309
+ else:
310
+ return None
311
+
312
+ @property
313
+ def is_block_quantized(self) -> bool:
314
+ return self.block_shape is not None
315
+
316
+ @property
317
+ def a1_scale(self) -> torch.Tensor | None:
318
+ assert self._a1.scale is None or isinstance(self._a1.scale, torch.Tensor)
319
+ return self._a1.scale
320
+
321
+ @property
322
+ def a1_gscale(self) -> torch.Tensor | None:
323
+ return self._a1.alpha_or_gscale
324
+
325
+ @property
326
+ def a2_scale(self) -> torch.Tensor | None:
327
+ assert self._a2.scale is None or isinstance(self._a2.scale, torch.Tensor)
328
+ return self._a2.scale
329
+
330
+ @property
331
+ def a2_gscale(self) -> torch.Tensor | None:
332
+ return self._a2.alpha_or_gscale
333
+
334
+ @property
335
+ def w1_scale(self) -> torch.Tensor | None:
336
+ assert self._w1.scale is None or isinstance(self._w1.scale, torch.Tensor)
337
+ return self._w1.scale
338
+
339
+ @property
340
+ def w1_zp(self) -> torch.Tensor | None:
341
+ return self._w1.zp
342
+
343
+ @property
344
+ def w1_bias(self) -> torch.Tensor | None:
345
+ return self._w1.bias
346
+
347
+ @property
348
+ def w1_precision(self) -> "PrecisionConfig | None":
349
+ assert self._w1.scale is None or isinstance(self._w1.scale, PrecisionConfig)
350
+ return self._w1.scale
351
+
352
+ @property
353
+ def g1_alphas(self) -> torch.Tensor | None:
354
+ return self._w1.alpha_or_gscale
355
+
356
+ @property
357
+ def w2_scale(self) -> torch.Tensor | None:
358
+ assert self._w2.scale is None or isinstance(self._w2.scale, torch.Tensor)
359
+ return self._w2.scale
360
+
361
+ @property
362
+ def w2_zp(self) -> torch.Tensor | None:
363
+ return self._w2.zp
364
+
365
+ @property
366
+ def w2_bias(self) -> torch.Tensor | None:
367
+ return self._w2.bias
368
+
369
+ @property
370
+ def w2_precision(self) -> "PrecisionConfig | None":
371
+ assert self._w2.scale is None or isinstance(self._w2.scale, PrecisionConfig)
372
+ return self._w2.scale
373
+
374
+ @property
375
+ def g2_alphas(self) -> torch.Tensor | None:
376
+ return self._w2.alpha_or_gscale
377
+
378
+ @property
379
+ def use_fp8_w8a8(self) -> bool:
380
+ return self.quant_dtype == current_platform.fp8_dtype()
381
+
382
+ @property
383
+ def use_int8_w8a8(self) -> bool:
384
+ return self.quant_dtype == torch.int8
385
+
386
+ @property
387
+ def use_int8_w8a16(self) -> bool:
388
+ return self._a1.dtype is None and self._w1.dtype == torch.int8
389
+
390
+ @property
391
+ def use_fp8_w8a16(self) -> bool:
392
+ return self._a1.dtype is None and self._w1.dtype == current_platform.fp8_dtype()
393
+
394
+ @property
395
+ def use_int4_w4a16(self) -> bool:
396
+ return self._a1.dtype is None and self._w1.dtype == "int4"
397
+
398
+ @property
399
+ def use_nvfp4_w4a16(self) -> bool:
400
+ return self._a1.dtype is None and self._w1.dtype == "nvfp4"
401
+
402
+ @property
403
+ def ocp_mx_scheme(self) -> str | None:
404
+ if not hasattr(self, "_ocp_mx_scheme"):
405
+ if (self._a1.dtype is not None and not isinstance(self._a1.dtype, str)) or (
406
+ self._w1.dtype is not None and not isinstance(self._w1.dtype, str)
407
+ ):
408
+ self._ocp_mx_scheme = None
409
+ else:
410
+ ocp_mx_scheme = OCP_MX_Scheme.from_quant_dtype(
411
+ self._a1.dtype, self._w1.dtype
412
+ )
413
+
414
+ if ocp_mx_scheme is not None:
415
+ ocp_mx_scheme = ocp_mx_scheme.value
416
+
417
+ self._ocp_mx_scheme = ocp_mx_scheme
418
+
419
+ return self._ocp_mx_scheme
420
+
421
+ @property
422
+ def use_mxfp4_w4a16(self) -> bool:
423
+ return self._a1.dtype is None and self._w1.dtype == "mxfp4"
424
+
425
+ @property
426
+ def use_mxfp4_w4a4(self) -> bool:
427
+ return self._a1.dtype == "mxfp4" and self._w1.dtype == "mxfp4"
428
+
429
+ @property
430
+ def use_nvfp4_w4a4(self) -> bool:
431
+ return self.quant_dtype == "nvfp4"
432
+
433
+ @property
434
+ def use_mxfp4_w4a8(self) -> bool:
435
+ return self._a1.dtype == "fp8" and self._w1.dtype == "mxfp4"
436
+
437
+ def config_name(self, dtype: torch.dtype) -> str | None:
438
+ """
439
+ Return a string used to construct the filename that contains the
440
+ tuning info for a particular quantization scheme. See
441
+ try_get_optimal_moe_config in fused_moe.py.
442
+ """
443
+ return _get_config_dtype_str(
444
+ use_fp8_w8a8=self.use_fp8_w8a8,
445
+ use_fp8_w8a16=self.use_fp8_w8a16,
446
+ use_int8_w8a16=self.use_int8_w8a16,
447
+ use_int4_w4a16=self.use_int4_w4a16,
448
+ ocp_mx_scheme=self.ocp_mx_scheme,
449
+ dtype=dtype,
450
+ )
451
+
452
+ def scale_shape(
453
+ self,
454
+ max_tokens: int,
455
+ hidden_dim: int,
456
+ ) -> tuple[int, int] | None:
457
+ """
458
+ Construct the proper activation scale shape for this
459
+ config.
460
+ """
461
+ if self.is_quantized:
462
+ if self.is_block_quantized:
463
+ assert self.block_shape is not None
464
+ _, block_k = self.block_shape
465
+ k_tiles = cdiv(hidden_dim, block_k)
466
+ return (max_tokens, k_tiles)
467
+ elif self.is_per_act_token:
468
+ return (max_tokens, 1)
469
+ else:
470
+ return (1, 1)
471
+ else:
472
+ return None
473
+
474
+ def batched_scale_shape(
475
+ self,
476
+ num_experts: int,
477
+ max_tokens: int,
478
+ hidden_dim: int,
479
+ ) -> tuple[int, int, int] | None:
480
+ """
481
+ Construct the proper activation batched scale shape for this
482
+ config, e.g. (num experts, *scale_shape).
483
+ """
484
+ if self.is_quantized:
485
+ scale_shape = self.scale_shape(max_tokens, hidden_dim)
486
+ assert scale_shape is not None
487
+ return (num_experts, *scale_shape)
488
+ else:
489
+ return None
490
+
491
+ @staticmethod
492
+ def make(
493
+ quant_dtype: torch.dtype | str | None = None,
494
+ per_act_token_quant: bool = False,
495
+ per_out_ch_quant: bool = False,
496
+ block_shape: list[int] | None = None,
497
+ w1_scale: Union[torch.Tensor, "PrecisionConfig", None] = None,
498
+ w2_scale: Union[torch.Tensor, "PrecisionConfig", None] = None,
499
+ a1_scale: torch.Tensor | None = None,
500
+ a2_scale: torch.Tensor | None = None,
501
+ g1_alphas: torch.Tensor | None = None,
502
+ g2_alphas: torch.Tensor | None = None,
503
+ a1_gscale: torch.Tensor | None = None,
504
+ a2_gscale: torch.Tensor | None = None,
505
+ w1_bias: torch.Tensor | None = None,
506
+ w2_bias: torch.Tensor | None = None,
507
+ w1_zp: torch.Tensor | None = None,
508
+ w2_zp: torch.Tensor | None = None,
509
+ weight_dtype: torch.dtype | str | None = None,
510
+ is_scale_swizzled: bool = True,
511
+ gemm1_alpha: float | None = None,
512
+ gemm1_beta: float | None = None,
513
+ gemm1_clamp_limit: float | None = None,
514
+ ) -> "FusedMoEQuantConfig":
515
+ """
516
+ General builder function for a FusedMoEQuantConfig.
517
+ - quant_dtype: Optional quantization type. None if activations are
518
+ unquantized or quantized prior to calling. Note: "nvfp4", "mxfp4",
519
+ "mxfp6_e3m2", "mxfp6_e2m3" are the only valid string values
520
+ for quant_dtype.
521
+ - per_act_token_quant: Activations have per token quantization.
522
+ - per_out_ch_quant: Outputs have per channel quantization. (only
523
+ for cutlass).
524
+ - block_shape: Optional block size for block-wise quantization.
525
+ Incompatible with per_act_token and per_out_ch quant.
526
+ - w1_scale: Optional scale to be used for w1.
527
+ - w2_scale: Optional scale to be used for w2.
528
+ - a1_scale: Optional scale to be used for a1.
529
+ - a2_scale: Optional scale to be used for a2.
530
+ - g1_alphas: Optional global quantization scales for w1 (for nvfp4).
531
+ Optional per-channel scales for w1 (for W4A8 FP8).
532
+ Optional dq scale i.e. w_scale * a_scale (for W8A8 fp8).
533
+ - g2_alphas: Optional global quantization scales for w2 (for nvfp4).
534
+ Optional per-channel scales for w2 (for W4A8 FP8).
535
+ Optional dq scale i.e. w_scale * a_scale (for W8A8 fp8).
536
+ - a1_gscale: Optional global quantization scales for a1 (1.0 /a2_scale).
537
+ - a2_gscale: Optional global quantization scales for a2 (1.0 /a2_scale).
538
+
539
+ - w1_bias: Optional biases for w1 (GPT OSS Triton).
540
+ - w2_bias: Optional biases for w1 (GPT OSS Triton).
541
+ - w1_zp: Optional w1 zero points for int4/int8 quantization.
542
+ - w2_zp: Optional w2 zero points for int4/int8 quantization.
543
+ - is_scale_swizzled: Whether the activation scale-factor layout is
544
+ swizzled. Pass through to the underlying quantization kernel for
545
+ dtypes that distinguish layouts (nvfp4, mxfp8). Defaults to True.
546
+ - gemm1_alpha: Optional MXFP4 TRTLLM SwiGLU alpha parameter.
547
+ - gemm1_beta: Optional MXFP4 TRTLLM SwiGLU beta parameter.
548
+ - gemm1_clamp_limit: Optional MXFP4 TRTLLM SwiGLU clamp limit.
549
+ """
550
+ assert not isinstance(quant_dtype, str) or quant_dtype in {
551
+ "nvfp4",
552
+ "mxfp4",
553
+ "mxfp6_e3m2",
554
+ "mxfp6_e2m3",
555
+ "mxfp8",
556
+ }
557
+ assert not isinstance(weight_dtype, str) or weight_dtype in {
558
+ "nvfp4",
559
+ "mxfp4",
560
+ "mxfp6_e3m2",
561
+ "mxfp6_e2m3",
562
+ "int4",
563
+ "mxfp8",
564
+ }
565
+
566
+ if weight_dtype is None:
567
+ weight_dtype = quant_dtype
568
+
569
+ a_shape, w_shape = _quant_flags_to_group_shape(
570
+ quant_dtype, per_act_token_quant, per_out_ch_quant, block_shape
571
+ )
572
+ quant_config = FusedMoEQuantConfig(
573
+ _a1=FusedMoEQuantDesc(quant_dtype, a_shape, a1_scale, a1_gscale),
574
+ _a2=FusedMoEQuantDesc(quant_dtype, a_shape, a2_scale, a2_gscale),
575
+ _w1=FusedMoEQuantDesc(
576
+ weight_dtype, w_shape, w1_scale, g1_alphas, w1_zp, w1_bias
577
+ ),
578
+ _w2=FusedMoEQuantDesc(
579
+ weight_dtype, w_shape, w2_scale, g2_alphas, w2_zp, w2_bias
580
+ ),
581
+ is_scale_swizzled=is_scale_swizzled,
582
+ gemm1_alpha=gemm1_alpha,
583
+ gemm1_beta=gemm1_beta,
584
+ gemm1_clamp_limit=gemm1_clamp_limit,
585
+ )
586
+ assert quant_config.per_act_token_quant == per_act_token_quant
587
+ assert quant_config.per_out_ch_quant == per_out_ch_quant
588
+ assert quant_config.block_shape == block_shape
589
+ return quant_config
590
+
591
+
592
+ def fp8_w8a8_moe_quant_config(
593
+ w1_scale: torch.Tensor,
594
+ w2_scale: torch.Tensor,
595
+ a1_scale: torch.Tensor | None = None,
596
+ a2_scale: torch.Tensor | None = None,
597
+ w1_bias: torch.Tensor | None = None,
598
+ w2_bias: torch.Tensor | None = None,
599
+ per_act_token_quant: bool = False,
600
+ per_out_ch_quant: bool = False,
601
+ block_shape: list[int] | None = None,
602
+ a1_gscale: torch.Tensor | None = None,
603
+ a2_gscale: torch.Tensor | None = None,
604
+ g1_alphas: torch.Tensor | None = None,
605
+ g2_alphas: torch.Tensor | None = None,
606
+ gemm1_alpha: float | None = None,
607
+ gemm1_beta: float | None = None,
608
+ gemm1_clamp_limit: float | None = None,
609
+ ) -> FusedMoEQuantConfig:
610
+ """
611
+ Construct a quant config for fp8 activations and fp8 weights.
612
+ """
613
+ return FusedMoEQuantConfig.make(
614
+ current_platform.fp8_dtype(),
615
+ w1_scale=w1_scale,
616
+ g1_alphas=g1_alphas,
617
+ w2_scale=w2_scale,
618
+ g2_alphas=g2_alphas,
619
+ w1_bias=w1_bias,
620
+ w2_bias=w2_bias,
621
+ a1_scale=a1_scale,
622
+ a1_gscale=a1_gscale,
623
+ a2_scale=a2_scale,
624
+ a2_gscale=a2_gscale,
625
+ per_act_token_quant=per_act_token_quant,
626
+ per_out_ch_quant=per_out_ch_quant,
627
+ block_shape=block_shape,
628
+ gemm1_alpha=gemm1_alpha,
629
+ gemm1_beta=gemm1_beta,
630
+ gemm1_clamp_limit=gemm1_clamp_limit,
631
+ )
632
+
633
+
634
+ def int8_w8a8_moe_quant_config(
635
+ w1_scale: torch.Tensor,
636
+ w2_scale: torch.Tensor,
637
+ a1_scale: torch.Tensor | None,
638
+ a2_scale: torch.Tensor | None,
639
+ w1_bias: torch.Tensor | None = None,
640
+ w2_bias: torch.Tensor | None = None,
641
+ per_act_token_quant: bool = False,
642
+ ) -> FusedMoEQuantConfig:
643
+ """
644
+ Construct a quant config for int8 activations and int8 weights.
645
+ """
646
+ return FusedMoEQuantConfig.make(
647
+ torch.int8,
648
+ w1_scale=w1_scale,
649
+ w2_scale=w2_scale,
650
+ a1_scale=a1_scale,
651
+ a2_scale=a2_scale,
652
+ w1_bias=w1_bias,
653
+ w2_bias=w2_bias,
654
+ per_act_token_quant=per_act_token_quant,
655
+ per_out_ch_quant=False,
656
+ block_shape=None,
657
+ )
658
+
659
+
660
+ def gptq_marlin_moe_quant_config(
661
+ w1_scale: torch.Tensor,
662
+ w2_scale: torch.Tensor,
663
+ weight_bits: int,
664
+ group_size: int,
665
+ w1_zp: torch.Tensor | None = None,
666
+ w2_zp: torch.Tensor | None = None,
667
+ w1_bias: torch.Tensor | None = None,
668
+ w2_bias: torch.Tensor | None = None,
669
+ ):
670
+ """
671
+ Construct a quant config for gptq marlin quantization.
672
+ """
673
+ from vllm.model_executor.layers.quantization.utils.quant_utils import GroupShape
674
+
675
+ w_shape = None if group_size == -1 else GroupShape(row=1, col=group_size)
676
+
677
+ # Activations are NOT quantized for GPTQ (fp16/bf16)
678
+ a_shape = w_shape # Same as weight shape for alignment
679
+
680
+ # Determine weight dtype
681
+ if weight_bits == 4:
682
+ weight_dtype = "int4"
683
+ elif weight_bits == 8:
684
+ weight_dtype = torch.int8
685
+ else:
686
+ raise ValueError(f"Unsupported weight_bits: {weight_bits}")
687
+
688
+ return FusedMoEQuantConfig(
689
+ _a1=FusedMoEQuantDesc(dtype=None, shape=a_shape),
690
+ _a2=FusedMoEQuantDesc(dtype=None, shape=a_shape),
691
+ _w1=FusedMoEQuantDesc(weight_dtype, w_shape, w1_scale, None, w1_zp, w1_bias),
692
+ _w2=FusedMoEQuantDesc(weight_dtype, w_shape, w2_scale, None, w2_zp, w2_bias),
693
+ )
694
+
695
+
696
+ def mxfp4_w4a16_moe_quant_config(
697
+ w1_scale: Union[torch.Tensor, "PrecisionConfig"],
698
+ w2_scale: Union[torch.Tensor, "PrecisionConfig"],
699
+ w1_bias: torch.Tensor | None = None,
700
+ w2_bias: torch.Tensor | None = None,
701
+ gemm1_alpha: float | None = None,
702
+ gemm1_beta: float | None = None,
703
+ gemm1_clamp_limit: float | None = None,
704
+ ) -> FusedMoEQuantConfig:
705
+ """
706
+ Construct a quant config for unquantized activations and mxfp4 weights.
707
+ """
708
+ return FusedMoEQuantConfig(
709
+ _a1=FusedMoEQuantDesc(),
710
+ _a2=FusedMoEQuantDesc(),
711
+ _w1=FusedMoEQuantDesc("mxfp4", None, w1_scale, None, None, w1_bias),
712
+ _w2=FusedMoEQuantDesc("mxfp4", None, w2_scale, None, None, w2_bias),
713
+ gemm1_alpha=gemm1_alpha,
714
+ gemm1_beta=gemm1_beta,
715
+ gemm1_clamp_limit=gemm1_clamp_limit,
716
+ )
717
+
718
+
719
+ def mxfp4_mxfp8_moe_quant_config(
720
+ w1_scale: Union[torch.Tensor, "PrecisionConfig"],
721
+ w2_scale: Union[torch.Tensor, "PrecisionConfig"],
722
+ a1_scale: torch.Tensor | None = None,
723
+ a2_scale: torch.Tensor | None = None,
724
+ w1_bias: torch.Tensor | None = None,
725
+ w2_bias: torch.Tensor | None = None,
726
+ block_shape: list[int] | None = None,
727
+ gemm1_alpha: float | None = None,
728
+ gemm1_beta: float | None = None,
729
+ gemm1_clamp_limit: float | None = None,
730
+ mx_alignment: int = 0,
731
+ is_scale_swizzled: bool = True,
732
+ ) -> FusedMoEQuantConfig:
733
+ """
734
+ Construct a quant config for mxfp4 activations and mxfp4 weights.
735
+ """
736
+ return FusedMoEQuantConfig(
737
+ _a1=FusedMoEQuantDesc("mxfp8"),
738
+ _a2=FusedMoEQuantDesc("mxfp8"),
739
+ _w1=FusedMoEQuantDesc("mxfp4", None, w1_scale, None, None, w1_bias),
740
+ _w2=FusedMoEQuantDesc("mxfp4", None, w2_scale, None, None, w2_bias),
741
+ gemm1_alpha=gemm1_alpha,
742
+ gemm1_beta=gemm1_beta,
743
+ gemm1_clamp_limit=gemm1_clamp_limit,
744
+ mx_alignment=mx_alignment,
745
+ is_scale_swizzled=is_scale_swizzled,
746
+ )
747
+
748
+
749
+ def mxfp4_w4a8_moe_quant_config(
750
+ w1_scale: Union[torch.Tensor, "PrecisionConfig"],
751
+ w2_scale: Union[torch.Tensor, "PrecisionConfig"],
752
+ a1_scale: torch.Tensor | None = None,
753
+ a2_scale: torch.Tensor | None = None,
754
+ w1_bias: torch.Tensor | None = None,
755
+ w2_bias: torch.Tensor | None = None,
756
+ block_shape: list[int] | None = None,
757
+ gemm1_clamp_limit: float | None = None,
758
+ ) -> FusedMoEQuantConfig:
759
+ """
760
+ Construct a quant config for fp8 activations and mxfp4 weights.
761
+ """
762
+ return FusedMoEQuantConfig(
763
+ _a1=FusedMoEQuantDesc("fp8", None, a1_scale, None, None, None),
764
+ _a2=FusedMoEQuantDesc("fp8", None, a2_scale, None, None, None),
765
+ _w1=FusedMoEQuantDesc("mxfp4", None, w1_scale, None, None, w1_bias),
766
+ _w2=FusedMoEQuantDesc("mxfp4", None, w2_scale, None, None, w2_bias),
767
+ gemm1_clamp_limit=gemm1_clamp_limit,
768
+ )
769
+
770
+
771
+ def ocp_mx_moe_quant_config(
772
+ quant_dtype: str,
773
+ w1_scale: Union[torch.Tensor, "PrecisionConfig"],
774
+ w2_scale: Union[torch.Tensor, "PrecisionConfig"],
775
+ weight_dtype: str | None = None,
776
+ a1_scale: torch.Tensor | None = None,
777
+ a2_scale: torch.Tensor | None = None,
778
+ w1_bias: torch.Tensor | None = None,
779
+ w2_bias: torch.Tensor | None = None,
780
+ block_shape: list[int] | None = None,
781
+ gemm1_alpha: float | None = None,
782
+ gemm1_beta: float | None = None,
783
+ gemm1_clamp_limit: float | None = None,
784
+ ) -> FusedMoEQuantConfig:
785
+ """
786
+ Construct a quant config for mxfp4 activations and mxfp4 weights.
787
+ """
788
+ assert quant_dtype in OCP_MX_DTYPES
789
+ return FusedMoEQuantConfig.make(
790
+ quant_dtype=quant_dtype,
791
+ weight_dtype=weight_dtype,
792
+ w1_scale=w1_scale,
793
+ w2_scale=w2_scale,
794
+ a1_scale=a1_scale,
795
+ a2_scale=a2_scale,
796
+ w1_bias=w1_bias,
797
+ w2_bias=w2_bias,
798
+ per_act_token_quant=False,
799
+ per_out_ch_quant=False,
800
+ block_shape=block_shape,
801
+ gemm1_alpha=gemm1_alpha,
802
+ gemm1_beta=gemm1_beta,
803
+ gemm1_clamp_limit=gemm1_clamp_limit,
804
+ )
805
+
806
+
807
+ def nvfp4_moe_quant_config(
808
+ g1_alphas: torch.Tensor,
809
+ g2_alphas: torch.Tensor,
810
+ a1_gscale: torch.Tensor,
811
+ a2_gscale: torch.Tensor,
812
+ w1_scale: torch.Tensor,
813
+ w2_scale: torch.Tensor,
814
+ w1_bias: torch.Tensor | None = None,
815
+ w2_bias: torch.Tensor | None = None,
816
+ is_scale_swizzled: bool = True,
817
+ gemm1_clamp_limit: float | None = None,
818
+ ) -> FusedMoEQuantConfig:
819
+ """
820
+ Construct a quant config for mxfp4 activations and nvp4 weights.
821
+ """
822
+ return FusedMoEQuantConfig.make(
823
+ "nvfp4",
824
+ w1_scale=w1_scale,
825
+ w2_scale=w2_scale,
826
+ w1_bias=w1_bias,
827
+ w2_bias=w2_bias,
828
+ a1_gscale=a1_gscale,
829
+ a2_gscale=a2_gscale,
830
+ g1_alphas=g1_alphas,
831
+ g2_alphas=g2_alphas,
832
+ per_act_token_quant=False,
833
+ per_out_ch_quant=False,
834
+ block_shape=None,
835
+ is_scale_swizzled=is_scale_swizzled,
836
+ gemm1_clamp_limit=gemm1_clamp_limit,
837
+ )
838
+
839
+
840
+ def mxfp4_moe_quant_config(
841
+ w1_scale: torch.Tensor,
842
+ w2_scale: torch.Tensor,
843
+ gemm1_clamp_limit: float | None = None,
844
+ ) -> FusedMoEQuantConfig:
845
+ """
846
+ Construct a quant config for MXFP4 x MXFP4 MoE.
847
+ MXFP4 uses block scaling only (E8M0 scales, 32-element groups), with no
848
+ separate alphas / global activation scales in this config.
849
+
850
+ ``gemm1_clamp_limit`` carries a per-layer SwiGLU clamp (Ling-3.0 sets one on
851
+ its last 7 MoE layers). Without it the MXFP4 path silently computes unclamped
852
+ SwiGLU while the BF16 path clamps.
853
+ """
854
+ return FusedMoEQuantConfig.make(
855
+ "mxfp4",
856
+ w1_scale=w1_scale,
857
+ w2_scale=w2_scale,
858
+ per_act_token_quant=False,
859
+ per_out_ch_quant=False,
860
+ block_shape=None,
861
+ gemm1_clamp_limit=gemm1_clamp_limit,
862
+ )
863
+
864
+
865
+ def nvfp4_w4a16_moe_quant_config(
866
+ g1_alphas: torch.Tensor,
867
+ g2_alphas: torch.Tensor,
868
+ w1_scale: torch.Tensor,
869
+ w2_scale: torch.Tensor,
870
+ gemm1_clamp_limit: float | None = None,
871
+ ) -> FusedMoEQuantConfig:
872
+ """
873
+ Construct a quant config for 16-but activations and nvp4 weights.
874
+ """
875
+ return FusedMoEQuantConfig.make(
876
+ quant_dtype=None,
877
+ w1_scale=w1_scale,
878
+ w2_scale=w2_scale,
879
+ g1_alphas=g1_alphas,
880
+ g2_alphas=g2_alphas,
881
+ weight_dtype="nvfp4",
882
+ gemm1_clamp_limit=gemm1_clamp_limit,
883
+ )
884
+
885
+
886
+ def int4_w4a16_moe_quant_config(
887
+ w1_scale: torch.Tensor,
888
+ w2_scale: torch.Tensor,
889
+ w1_zp: torch.Tensor | None = None,
890
+ w2_zp: torch.Tensor | None = None,
891
+ w1_bias: torch.Tensor | None = None,
892
+ w2_bias: torch.Tensor | None = None,
893
+ block_shape: list[int] | None = None,
894
+ a1_gscale: torch.Tensor | None = None,
895
+ a2_gscale: torch.Tensor | None = None,
896
+ gemm1_clamp_limit: float | None = None,
897
+ gemm1_alpha: float | None = None,
898
+ gemm1_beta: float | None = None,
899
+ ) -> FusedMoEQuantConfig:
900
+ """
901
+ Construct a quant config for 16-bit float activations and int4 weights.
902
+ """
903
+ group_shape = GroupShape(*block_shape) if block_shape is not None else None
904
+ return FusedMoEQuantConfig(
905
+ _a1=FusedMoEQuantDesc(shape=group_shape, alpha_or_gscale=a1_gscale),
906
+ _a2=FusedMoEQuantDesc(shape=group_shape, alpha_or_gscale=a2_gscale),
907
+ _w1=FusedMoEQuantDesc("int4", group_shape, w1_scale, None, w1_zp, w1_bias),
908
+ _w2=FusedMoEQuantDesc("int4", group_shape, w2_scale, None, w2_zp, w2_bias),
909
+ gemm1_clamp_limit=gemm1_clamp_limit,
910
+ gemm1_alpha=gemm1_alpha,
911
+ gemm1_beta=gemm1_beta,
912
+ )
913
+
914
+
915
+ def fp8_w8a16_moe_quant_config(
916
+ w1_scale: torch.Tensor,
917
+ w2_scale: torch.Tensor,
918
+ w1_bias: torch.Tensor | None = None,
919
+ w2_bias: torch.Tensor | None = None,
920
+ block_shape: list[int] | None = None,
921
+ gemm1_alpha: float | None = None,
922
+ gemm1_beta: float | None = None,
923
+ gemm1_clamp_limit: float | None = None,
924
+ ) -> FusedMoEQuantConfig:
925
+ """
926
+ Construct a quant config for 16-bit float activations and fp8 weights.
927
+ """
928
+ group_shape = GroupShape(*block_shape) if block_shape is not None else None
929
+ fp8_dtype = current_platform.fp8_dtype()
930
+ return FusedMoEQuantConfig(
931
+ _a1=FusedMoEQuantDesc(),
932
+ _a2=FusedMoEQuantDesc(),
933
+ _w1=FusedMoEQuantDesc(
934
+ fp8_dtype,
935
+ group_shape,
936
+ w1_scale,
937
+ None,
938
+ None,
939
+ w1_bias,
940
+ ),
941
+ _w2=FusedMoEQuantDesc(
942
+ fp8_dtype,
943
+ group_shape,
944
+ w2_scale,
945
+ None,
946
+ None,
947
+ w2_bias,
948
+ ),
949
+ gemm1_alpha=gemm1_alpha,
950
+ gemm1_beta=gemm1_beta,
951
+ gemm1_clamp_limit=gemm1_clamp_limit,
952
+ )
953
+
954
+
955
+ def int8_w8a16_moe_quant_config(
956
+ w1_scale: torch.Tensor,
957
+ w2_scale: torch.Tensor,
958
+ w1_zp: torch.Tensor | None = None,
959
+ w2_zp: torch.Tensor | None = None,
960
+ w1_bias: torch.Tensor | None = None,
961
+ w2_bias: torch.Tensor | None = None,
962
+ block_shape: list[int] | None = None,
963
+ a1_gscale: torch.Tensor | None = None,
964
+ a2_gscale: torch.Tensor | None = None,
965
+ gemm1_clamp_limit: float | None = None,
966
+ gemm1_alpha: float | None = None,
967
+ gemm1_beta: float | None = None,
968
+ ) -> FusedMoEQuantConfig:
969
+ """
970
+ Construct a quant config for 16-bit float activations and int8 weights.
971
+ """
972
+ group_shape = GroupShape(*block_shape) if block_shape is not None else None
973
+ return FusedMoEQuantConfig(
974
+ _a1=FusedMoEQuantDesc(shape=group_shape, alpha_or_gscale=a1_gscale),
975
+ _a2=FusedMoEQuantDesc(shape=group_shape, alpha_or_gscale=a2_gscale),
976
+ _w1=FusedMoEQuantDesc(torch.int8, group_shape, w1_scale, None, w1_zp, w1_bias),
977
+ _w2=FusedMoEQuantDesc(torch.int8, group_shape, w2_scale, None, w2_zp, w2_bias),
978
+ gemm1_clamp_limit=gemm1_clamp_limit,
979
+ gemm1_alpha=gemm1_alpha,
980
+ gemm1_beta=gemm1_beta,
981
+ )
982
+
983
+
984
+ def int4_w4afp8_moe_quant_config(
985
+ w1_scale: torch.Tensor,
986
+ w2_scale: torch.Tensor,
987
+ g1_alphas: torch.Tensor,
988
+ g2_alphas: torch.Tensor,
989
+ per_act_token_quant: bool = False,
990
+ per_out_ch_quant: bool = False,
991
+ block_shape: list[int] | None = None,
992
+ ) -> FusedMoEQuantConfig:
993
+ """
994
+ Construct a quant config for fp8 activations and int4 weights.
995
+ """
996
+ return FusedMoEQuantConfig.make(
997
+ torch.float8_e4m3fn, # quant dtype for activations
998
+ w1_scale=w1_scale,
999
+ w2_scale=w2_scale,
1000
+ g1_alphas=g1_alphas,
1001
+ g2_alphas=g2_alphas,
1002
+ per_act_token_quant=per_act_token_quant,
1003
+ per_out_ch_quant=per_out_ch_quant,
1004
+ block_shape=block_shape,
1005
+ weight_dtype="int4", # weight dtype for weights
1006
+ )
1007
+
1008
+
1009
+ def biased_moe_quant_config(
1010
+ w1_bias: torch.Tensor | None,
1011
+ w2_bias: torch.Tensor | None,
1012
+ gemm1_alpha: float | None = None,
1013
+ gemm1_beta: float | None = None,
1014
+ gemm1_clamp_limit: float | None = None,
1015
+ ) -> FusedMoEQuantConfig:
1016
+ """
1017
+ Construct a quant config for unquantized activations with biases.
1018
+
1019
+ gemm1_alpha/gemm1_beta/gemm1_clamp_limit carry the SwiGLU gate params
1020
+ through to the fused activation kernel (e.g. swigluoai_uninterleave).
1021
+ """
1022
+ return FusedMoEQuantConfig(
1023
+ _a1=FusedMoEQuantDesc(),
1024
+ _a2=FusedMoEQuantDesc(),
1025
+ _w1=FusedMoEQuantDesc(bias=w1_bias),
1026
+ _w2=FusedMoEQuantDesc(bias=w2_bias),
1027
+ gemm1_alpha=gemm1_alpha,
1028
+ gemm1_beta=gemm1_beta,
1029
+ gemm1_clamp_limit=gemm1_clamp_limit,
1030
+ )
1031
+
1032
+
1033
+ # A FusedMoEQuantConfig constant for an unquantized MoE op.
1034
+ FUSED_MOE_UNQUANTIZED_CONFIG: FusedMoEQuantConfig = FusedMoEQuantConfig.make()
1035
+
1036
+
1037
+ @dataclass
1038
+ class FusedMoEParallelConfig:
1039
+ tp_size: int
1040
+ pcp_size: int
1041
+ dp_size: int
1042
+ ep_size: int
1043
+ tp_rank: int
1044
+ pcp_rank: int
1045
+ dp_rank: int
1046
+ ep_rank: int
1047
+ sp_size: int
1048
+
1049
+ use_ep: bool # whether to use EP or not
1050
+ all2all_backend: str # all2all backend for MoE communication
1051
+ enable_eplb: bool # whether to enable expert load balancing
1052
+
1053
+ @property
1054
+ def is_sequence_parallel(self) -> bool:
1055
+ return self.sp_size > 1
1056
+
1057
+ @property
1058
+ def use_all2all_kernels(self):
1059
+ return self.use_ep and (
1060
+ self.dp_size > 1 or self.pcp_size > 1 or self.is_sequence_parallel
1061
+ )
1062
+
1063
+ @property
1064
+ def use_deepep_ht_kernels(self):
1065
+ return (
1066
+ self.use_all2all_kernels
1067
+ and self.all2all_backend == "deepep_high_throughput"
1068
+ )
1069
+
1070
+ @property
1071
+ def use_deepep_ll_kernels(self):
1072
+ return self.use_all2all_kernels and self.all2all_backend == "deepep_low_latency"
1073
+
1074
+ @property
1075
+ def use_fi_nvl_two_sided_kernels(self):
1076
+ return self.use_all2all_kernels and (
1077
+ self.all2all_backend == "flashinfer_all2allv"
1078
+ or self.all2all_backend == "flashinfer_nvlink_two_sided"
1079
+ )
1080
+
1081
+ @property
1082
+ def use_fi_nvl_one_sided_kernels(self):
1083
+ return (
1084
+ self.use_all2all_kernels
1085
+ and self.all2all_backend == "flashinfer_nvlink_one_sided"
1086
+ )
1087
+
1088
+ @property
1089
+ def use_batched_activation_format(self):
1090
+ return self.use_deepep_ll_kernels or self.use_nixl_ep_kernels
1091
+
1092
+ @property
1093
+ def needs_round_robin_routing_tables(self):
1094
+ return self.use_deepep_ll_kernels or self.use_nixl_ep_kernels
1095
+
1096
+ @property
1097
+ def use_ag_rs_all2all_kernels(self):
1098
+ return (
1099
+ self.use_all2all_kernels
1100
+ and self.all2all_backend == "allgather_reducescatter"
1101
+ )
1102
+
1103
+ @property
1104
+ def use_mori_kernels(self):
1105
+ return self.use_all2all_kernels and self.all2all_backend in (
1106
+ "mori_high_throughput",
1107
+ "mori_low_latency",
1108
+ )
1109
+
1110
+ @property
1111
+ def use_nixl_ep_kernels(self):
1112
+ return self.use_all2all_kernels and self.all2all_backend == "nixl_ep"
1113
+
1114
+ @property
1115
+ def use_deepep_v2_kernels(self):
1116
+ return self.use_all2all_kernels and self.all2all_backend == "deepep_v2"
1117
+
1118
+ @staticmethod
1119
+ def flatten_tp_across_dp_and_pcp(
1120
+ tp_size: int, dp_size: int, dp_rank: int, pcp_size: int, pcp_rank: int
1121
+ ) -> tuple[int, int]:
1122
+ tp_rank = 0 if tp_size == 1 else get_tensor_model_parallel_rank()
1123
+ # There are actually dp_size * pcp_size * tp_size devices.
1124
+ # Update tp_size and tp_rank so we shard across all devices.
1125
+ flatten_tp_size = dp_size * pcp_size * tp_size
1126
+ flatten_tp_rank = dp_rank * pcp_size * tp_size + pcp_rank * tp_size + tp_rank
1127
+ return flatten_tp_size, flatten_tp_rank
1128
+
1129
+ @staticmethod
1130
+ def make(
1131
+ tp_size_: int,
1132
+ pcp_size_: int,
1133
+ dp_size_: int,
1134
+ sp_size_: int,
1135
+ vllm_parallel_config: ParallelConfig,
1136
+ ) -> "FusedMoEParallelConfig":
1137
+ """
1138
+ Determine MoE parallel configuration. Based on the input `tp_size_`,
1139
+ `dp_size_` and vllm's parallel config, determine what
1140
+ level's of parallelism to use in the fused moe layer.
1141
+
1142
+ Args:
1143
+ tp_size_ (int): `tp_size` passed into the FusedMoEFactory constructor.
1144
+ pcp_size_ (int): `pcp_size` passed into the FusedMoEFactory constructor.
1145
+ dp_size_ (int): `dp_size` passed into the FusedMoEFactory constructor.
1146
+ vllm_parallel_config (ParallelConfig): vLLM's parallel config
1147
+ object which contains the `enable_expert_parallel` flag.
1148
+
1149
+ Examples:
1150
+ When there is no parallelism requested,
1151
+ i.e. `tp_size_` = `pcp_size_` = `dp_size_` = 1, we simply return the sizes
1152
+ unaltered and the ranks set to 0.
1153
+
1154
+ Expert Parallelism is considered only when either `dp_size_`, `pcp_size_` or
1155
+ `tp_size_` is non trivial.
1156
+
1157
+ Note that PCP serves the same function as DP here.
1158
+
1159
+ When TP = 2, DP(PCP) = 1 and EP = False, the configuration on different
1160
+ devices:
1161
+
1162
+ - device 0 : TP = {2, 0} DP = {1, 0} EP = {1, 0} //
1163
+ legend : {size, rank}
1164
+ - device 1 : TP = {2, 1} DP = {1, 0} EP = {1, 0}
1165
+ - Comment : Tensors are sharded across 2 devices.
1166
+
1167
+ When TP = 1, DP(PCP) = 2 and EP = False, the configuration on different
1168
+ devices:
1169
+
1170
+ - device 0 : TP = {2, 0} DP = {2, 0} EP = {1, 0}
1171
+ - device 1 : TP = {2, 1} DP = {2, 1} EP = {1, 0}
1172
+ - Comment: There are 2 engine instances and the tensors are sharded
1173
+ across 2 decvices.
1174
+
1175
+ When TP = 2, DP(PCP) = 2 and EP = False, the configuration on different
1176
+ devices:
1177
+
1178
+ - device 0: TP = {4, 0} DP = {2, 0} EP = {1, 0}
1179
+ - device 1: TP = {4, 1} DP = {2, 0} EP = {1, 0}
1180
+ - device 2: TP = {4, 2} DP = {2, 1} EP = {1, 0}
1181
+ - device 3: TP = {4, 3} DP = {2, 1} EP = {1, 0}
1182
+ - Comment: There are 2 engine instances and the tensors are sharded
1183
+ across 4 devices.
1184
+
1185
+ When, TP = 2, DP(PCP) = 1 and EP = True, the configuration on different
1186
+ devices:
1187
+
1188
+ - device 0: TP = {1, 0} DP = {1, 0} EP = {2, 0}
1189
+ - device 1: TP = {1, 0} DP = {1, 0} EP = {2, 1}
1190
+ - Comment: The experts are split between the 2 devices.
1191
+
1192
+ When, TP = 1, DP(PCP) = 2 and EP = True, the configuration on different
1193
+ devices:
1194
+
1195
+ - device 0: TP = {1, 0} DP = {2, 0} EP = {2, 0}
1196
+ - device 1: TP = {1, 0} DP = {2, 1} EP = {2, 1}
1197
+ - Comment: There are 2 engine instances and the experts are split
1198
+ between the 2 devices.
1199
+
1200
+ When TP = 2, DP(PCP) = 2 and EP = True, the configuration on different
1201
+ devices:
1202
+
1203
+ - device 0: TP = {1, 0} DP = {2, 0} EP = {4, 0}
1204
+ - device 1: TP = {1, 0} DP = {2, 0} EP = {4, 1}
1205
+ - device 2: TP = {1, 0} DP = {2, 1} EP = {4, 2}
1206
+ - device 3: TP = {1, 0} DP = {2, 1} EP = {4, 3}
1207
+ - Comment: There are 2 engine instances and the experts are split
1208
+ between the 4 devices.
1209
+ """
1210
+ use_ep = (
1211
+ dp_size_ * pcp_size_ * tp_size_ > 1
1212
+ and vllm_parallel_config.enable_expert_parallel
1213
+ )
1214
+
1215
+ dp_size = dp_size_
1216
+ dp_rank = get_dp_group().rank_in_group if dp_size > 1 else 0
1217
+ pcp_size = pcp_size_
1218
+ pcp_rank = get_pcp_group().rank_in_group if pcp_size > 1 else 0
1219
+ tp_size, tp_rank = FusedMoEParallelConfig.flatten_tp_across_dp_and_pcp(
1220
+ tp_size_, dp_size_, dp_rank, pcp_size_, pcp_rank
1221
+ )
1222
+
1223
+ if not use_ep:
1224
+ return FusedMoEParallelConfig(
1225
+ tp_size=tp_size,
1226
+ tp_rank=tp_rank,
1227
+ pcp_size=pcp_size,
1228
+ pcp_rank=pcp_rank,
1229
+ dp_size=dp_size,
1230
+ dp_rank=dp_rank,
1231
+ ep_size=1,
1232
+ ep_rank=0,
1233
+ sp_size=sp_size_,
1234
+ use_ep=False,
1235
+ all2all_backend=vllm_parallel_config.all2all_backend,
1236
+ enable_eplb=vllm_parallel_config.enable_eplb,
1237
+ )
1238
+ # DP + EP / TP + EP / DP + TP + EP
1239
+ assert use_ep
1240
+ # In EP, each device owns a set of experts fully. There is no tensor
1241
+ # parallel update tp_size, tp_rank, ep_size and ep_rank to reflect that.
1242
+ ep_size = tp_size
1243
+ ep_rank = tp_rank
1244
+ return FusedMoEParallelConfig(
1245
+ tp_size=1,
1246
+ tp_rank=0,
1247
+ pcp_size=pcp_size,
1248
+ pcp_rank=pcp_rank,
1249
+ dp_size=dp_size,
1250
+ dp_rank=dp_rank,
1251
+ ep_size=ep_size,
1252
+ ep_rank=ep_rank,
1253
+ sp_size=sp_size_,
1254
+ use_ep=True,
1255
+ all2all_backend=vllm_parallel_config.all2all_backend,
1256
+ enable_eplb=vllm_parallel_config.enable_eplb,
1257
+ )
1258
+
1259
+ @classmethod
1260
+ def make_no_parallel(cls) -> "FusedMoEParallelConfig":
1261
+ """For usage in CI/CD and testing."""
1262
+ return FusedMoEParallelConfig(
1263
+ tp_size=1,
1264
+ tp_rank=0,
1265
+ pcp_size=1,
1266
+ pcp_rank=0,
1267
+ dp_size=1,
1268
+ dp_rank=0,
1269
+ ep_size=1,
1270
+ ep_rank=0,
1271
+ sp_size=1,
1272
+ use_ep=False,
1273
+ all2all_backend="allgather_reducescatter",
1274
+ enable_eplb=False,
1275
+ )
1276
+
1277
+
1278
+ # Adapted from pplx-kernels tests/all_to_all_utils.py
1279
+ @dataclass
1280
+ class FusedMoEConfig:
1281
+ num_experts: int
1282
+ experts_per_token: int
1283
+ hidden_dim: int
1284
+ intermediate_size: int
1285
+ num_local_experts: int
1286
+ num_logical_experts: int
1287
+ activation: MoEActivation
1288
+ device: torch.device | str
1289
+ routing_method: RoutingMethodType
1290
+ moe_parallel_config: FusedMoEParallelConfig
1291
+
1292
+ # The activation type.
1293
+ in_dtype: torch.dtype
1294
+
1295
+ # Defaults to in_dtype if not specified.
1296
+ router_logits_dtype: torch.dtype | None = None
1297
+
1298
+ # Defaults to hidden_dim if not specified.
1299
+ hidden_dim_unpadded: int | None = None
1300
+ # Defaults to intermediate_size_per_partition if not specified.
1301
+ intermediate_size_per_partition_unpadded: int | None = None
1302
+ # Model specific override
1303
+ intermediate_pad: int | None = None
1304
+
1305
+ moe_backend: MoEBackend = "auto"
1306
+ max_num_tokens: int = SchedulerConfig.DEFAULT_MAX_NUM_BATCHED_TOKENS_FOR_BATCHED_DP
1307
+ has_bias: bool = False
1308
+ is_lora_enabled: bool = False
1309
+
1310
+ # When True, the MoE skips its final cross-rank all-reduce (and the separate
1311
+ # shared-expert reduce), returning the partial per-rank sum. The caller is
1312
+ # then responsible for the reduction (e.g. fusing it into the next RMSNorm).
1313
+ # Only honored on the non-reduced (late-AR) TP path. Default False.
1314
+ skip_final_all_reduce: bool = False
1315
+
1316
+ # SwiGLU clamp limit. When set, backends that do not implement the clamp
1317
+ # are filtered out by `FusedMoEExperts.is_supported_config` so the oracle
1318
+ # cannot silently select one and drop the clamp.
1319
+ swiglu_limit: float | None = None
1320
+ swiglu_alpha: float | None = None
1321
+ swiglu_beta: float | None = None
1322
+
1323
+ # SituGLU parameters used by Kimi sit(u/v2) activations.
1324
+ activation_situ_beta: float | None = None
1325
+ activation_situ_linear_beta: float | None = None
1326
+
1327
+ max_capture_size: int = 0
1328
+
1329
+ # Set by __post_init__
1330
+ intermediate_size_per_partition: int = -1
1331
+ rocm_aiter_fmoe_enabled: bool = False
1332
+ aiter_fmoe_shared_expert_enabled: bool = False
1333
+
1334
+ def __post_init__(self):
1335
+ from vllm._aiter_ops import rocm_aiter_ops
1336
+
1337
+ tp_size = self.moe_parallel_config.tp_size
1338
+ assert self.intermediate_size % tp_size == 0
1339
+ self.intermediate_size_per_partition = self.intermediate_size // tp_size
1340
+
1341
+ if self.dp_size > 1:
1342
+ logger.debug_once(
1343
+ "Using FusedMoEConfig::max_num_tokens=%d", self.max_num_tokens
1344
+ )
1345
+
1346
+ assert self.max_num_tokens > 0
1347
+
1348
+ if self.router_logits_dtype is None:
1349
+ self.router_logits_dtype = self.in_dtype
1350
+
1351
+ if self.hidden_dim_unpadded is None:
1352
+ self.hidden_dim_unpadded = self.hidden_dim
1353
+ if self.intermediate_size_per_partition_unpadded is None:
1354
+ self.intermediate_size_per_partition_unpadded = (
1355
+ self.intermediate_size_per_partition
1356
+ )
1357
+
1358
+ if self.is_act_and_mul:
1359
+ self.rocm_aiter_fmoe_enabled = rocm_aiter_ops.is_fused_moe_enabled()
1360
+ self.aiter_fmoe_shared_expert_enabled = (
1361
+ rocm_aiter_ops.is_fusion_moe_shared_experts_enabled()
1362
+ )
1363
+
1364
+ if self.use_mori_kernels:
1365
+ assert self.rocm_aiter_fmoe_enabled, (
1366
+ "Mori needs to be used with aiter fused_moe for now."
1367
+ )
1368
+ assert not self.aiter_fmoe_shared_expert_enabled, (
1369
+ "Mori does not support fusion shared expert now. "
1370
+ "Turn it off by setting VLLM_ROCM_USE_AITER_FUSION_SHARED_EXPERTS=0"
1371
+ )
1372
+
1373
+ if not self.is_act_and_mul and not (
1374
+ current_platform.is_cuda_alike() or current_platform.is_xpu()
1375
+ ):
1376
+ raise NotImplementedError(
1377
+ "is_act_and_mul=False is supported only for CUDA, XPU and ROCm for now"
1378
+ )
1379
+
1380
+ @property
1381
+ def is_act_and_mul(self) -> bool:
1382
+ return self.activation.is_gated
1383
+
1384
+ @property
1385
+ def tp_size(self):
1386
+ return self.moe_parallel_config.tp_size
1387
+
1388
+ @property
1389
+ def dp_size(self):
1390
+ return self.moe_parallel_config.dp_size
1391
+
1392
+ @property
1393
+ def pcp_size(self):
1394
+ return self.moe_parallel_config.pcp_size
1395
+
1396
+ @property
1397
+ def ep_size(self):
1398
+ return self.moe_parallel_config.ep_size
1399
+
1400
+ @property
1401
+ def sp_size(self):
1402
+ return self.moe_parallel_config.sp_size
1403
+
1404
+ @property
1405
+ def is_sequence_parallel(self):
1406
+ return self.moe_parallel_config.is_sequence_parallel
1407
+
1408
+ @property
1409
+ def tp_rank(self):
1410
+ return self.moe_parallel_config.tp_rank
1411
+
1412
+ @property
1413
+ def dp_rank(self):
1414
+ return self.moe_parallel_config.dp_rank
1415
+
1416
+ @property
1417
+ def pcp_rank(self):
1418
+ return self.moe_parallel_config.pcp_rank
1419
+
1420
+ @property
1421
+ def ep_rank(self):
1422
+ return self.moe_parallel_config.ep_rank
1423
+
1424
+ @property
1425
+ def use_ep(self):
1426
+ return self.moe_parallel_config.use_ep
1427
+
1428
+ @property
1429
+ def use_deepep_ht_kernels(self):
1430
+ return self.moe_parallel_config.use_deepep_ht_kernels
1431
+
1432
+ @property
1433
+ def use_deepep_ll_kernels(self):
1434
+ return self.moe_parallel_config.use_deepep_ll_kernels
1435
+
1436
+ @property
1437
+ def use_mori_kernels(self):
1438
+ return self.moe_parallel_config.use_mori_kernels
1439
+
1440
+ @property
1441
+ def use_fi_nvl_two_sided_kernels(self):
1442
+ return self.moe_parallel_config.use_fi_nvl_two_sided_kernels
1443
+
1444
+ @property
1445
+ def use_fi_nvl_one_sided_kernels(self):
1446
+ return self.moe_parallel_config.use_fi_nvl_one_sided_kernels
1447
+
1448
+ @property
1449
+ def use_ag_rs_all2all_kernels(self):
1450
+ return self.moe_parallel_config.use_ag_rs_all2all_kernels
1451
+
1452
+ @property
1453
+ def use_nixl_ep_kernels(self):
1454
+ return self.moe_parallel_config.use_nixl_ep_kernels
1455
+
1456
+ @property
1457
+ def use_deepep_v2_kernels(self):
1458
+ return self.moe_parallel_config.use_deepep_v2_kernels
1459
+
1460
+ @property
1461
+ def needs_round_robin_routing_tables(self):
1462
+ return self.moe_parallel_config.needs_round_robin_routing_tables
vllm_patch/cutlass_moe.py ADDED
@@ -0,0 +1,1441 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+ """CUTLASS based Fused MoE kernels."""
4
+
5
+ import torch
6
+
7
+ import vllm.model_executor.layers.fused_moe.modular_kernel as mk
8
+ from vllm import _custom_ops as ops
9
+ from vllm.logger import init_logger
10
+ from vllm.model_executor.layers.fused_moe.activation import (
11
+ MoEActivation,
12
+ apply_moe_activation,
13
+ )
14
+ from vllm.model_executor.layers.fused_moe.config import (
15
+ FusedMoEConfig,
16
+ FusedMoEParallelConfig,
17
+ FusedMoEQuantConfig,
18
+ )
19
+ from vllm.model_executor.layers.fused_moe.moe_permute_unpermute import (
20
+ MoEPermuteScratch,
21
+ moe_permute,
22
+ moe_permute_unpermute_supported,
23
+ moe_unpermute,
24
+ )
25
+ from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
26
+ TopKWeightAndReduceDelegate,
27
+ TopKWeightAndReduceNoOP,
28
+ )
29
+ from vllm.model_executor.layers.fused_moe.utils import (
30
+ _resize_cache,
31
+ )
32
+ from vllm.model_executor.layers.quantization.utils.quant_utils import (
33
+ QuantKey,
34
+ kFp8DynamicTensorSym,
35
+ kFp8DynamicTokenSym,
36
+ kFp8StaticChannelSym,
37
+ kFp8StaticTensorSym,
38
+ kInt4Static,
39
+ kMxfp4Dynamic,
40
+ kMxfp4Static,
41
+ kNvfp4Dynamic,
42
+ kNvfp4Static,
43
+ )
44
+ from vllm.model_executor.layers.quantization.utils.w8a8_utils import (
45
+ cutlass_group_gemm_supported,
46
+ )
47
+ from vllm.platforms import current_platform
48
+ from vllm.scalar_type import scalar_types
49
+
50
+ logger = init_logger(__name__)
51
+
52
+
53
+ def run_cutlass_moe_fp8(
54
+ output: torch.Tensor,
55
+ hidden_states: torch.Tensor,
56
+ w1: torch.Tensor,
57
+ w2: torch.Tensor,
58
+ topk_ids: torch.Tensor,
59
+ activation: MoEActivation,
60
+ global_num_experts: int,
61
+ expert_map: torch.Tensor | None,
62
+ w1_scale: torch.Tensor | None,
63
+ w2_scale: torch.Tensor | None,
64
+ a1q_scale: torch.Tensor | None,
65
+ a2_scale: torch.Tensor | None,
66
+ ab_strides1: torch.Tensor,
67
+ ab_strides2: torch.Tensor,
68
+ c_strides1: torch.Tensor,
69
+ c_strides2: torch.Tensor,
70
+ workspace13: torch.Tensor,
71
+ workspace2: torch.Tensor,
72
+ expert_num_tokens: torch.Tensor | None,
73
+ out_dtype: torch.dtype,
74
+ per_act_token: bool,
75
+ per_out_ch: bool,
76
+ use_batched_format: bool,
77
+ topk_weights: torch.Tensor | None,
78
+ permute_scratch: MoEPermuteScratch | None,
79
+ ):
80
+ a1q = hidden_states
81
+
82
+ assert activation.is_gated, "Only gated activation is supported"
83
+ assert w1_scale is not None
84
+ assert w2_scale is not None
85
+ assert w1.dtype == torch.float8_e4m3fn
86
+ assert w2.dtype == torch.float8_e4m3fn
87
+ assert a1q.size(-1) == w1.size(2), "Hidden size mismatch w1"
88
+ assert w1.size(1) == w2.size(2) * 2, "Hidden size mismatch w2"
89
+ assert (
90
+ w1_scale.dim() == 1 or w1_scale.size(1) == 1 or w1_scale.shape[1] == w1.size(1)
91
+ ), "W1 scale shape mismatch"
92
+ assert (
93
+ w2_scale.dim() == 1 or w2_scale.size(1) == 1 or w2_scale.shape[1] == w2.size(1)
94
+ ), "W2 scale shape mismatch"
95
+ assert w1.size(0) == w2.size(0), "Expert number mismatch"
96
+ assert (
97
+ a1q_scale is None
98
+ or a1q_scale.dim() == 0
99
+ or a1q_scale.size(0) == 1
100
+ or a1q_scale.size(0) == a1q.shape[0]
101
+ ), "Input scale shape mismatch"
102
+ assert w1.size(0) == w2.size(0), "Weights expert number mismatch"
103
+ assert w1.size(0) == w1_scale.size(0), "w1 scales expert number mismatch"
104
+ assert w1.size(0) == w2_scale.size(0), "w2 scales expert number mismatch"
105
+ assert (
106
+ a2_scale is None
107
+ or a2_scale.dim() == 0
108
+ or a2_scale.size(0) == 1
109
+ or a2_scale.size(0) == a1q.shape[0]
110
+ ), "Intermediate scale shape mismatch"
111
+ assert out_dtype in [torch.half, torch.bfloat16], "Invalid output dtype"
112
+
113
+ # NOTE(rob): the expert_map is used for the STANDARD case and
114
+ # the batched format is used by the BATCHED case.
115
+ # TODO(rob): update the MK interface to only pass the expert_map
116
+ # during the STANDARD case to make this clearer across all kernels.
117
+ if use_batched_format:
118
+ assert expert_num_tokens is not None
119
+ else:
120
+ assert expert_num_tokens is None
121
+
122
+ # We have two modes: batched experts and non-batched experts.
123
+ # In the non-batched mode, the input tokens are not padded: thus, the shape
124
+ # of the input is [total_num_tokens, hidden_size]. The input and output
125
+ # require shuffling by a_map and c_map such that the tokens assigned to
126
+ # each expert are contiguous.
127
+ # In the batched mode, the input tokens are padded per expert to ensure that
128
+ # the batched dispatch and combine functions work correctly: thus, the shape
129
+ # of the input is [num_experts, max_num_tokens_per_expert, hidden_size].
130
+ # The batched input and output require no shuffling by a_map and c_map since
131
+ # their tokens are already contiguous for each expert as a result of
132
+ # the dispatch function.
133
+
134
+ M = a1q.size(0) # non batched expert M
135
+ padded_M = a1q.size(1) # batched expert M
136
+ _, K, N = w2.shape
137
+ device = a1q.device
138
+
139
+ assert w1.size(2) == K
140
+ assert global_num_experts != -1
141
+ assert a1q_scale is not None
142
+
143
+ topk = topk_ids.size(1)
144
+ local_E = w1.size(0)
145
+
146
+ if use_batched_format:
147
+ mm1_out = _resize_cache(workspace13, (local_E * padded_M, N * 2))
148
+ act_out = _resize_cache(workspace2, (local_E * padded_M, N))
149
+ quant_out = _resize_cache(
150
+ workspace13.view(dtype=torch.float8_e4m3fn), (local_E * padded_M, N)
151
+ )
152
+ mm2_out = _resize_cache(workspace2, (local_E * padded_M, K))
153
+ else:
154
+ a1q_perm = _resize_cache(
155
+ workspace2.view(dtype=torch.float8_e4m3fn), (M * topk, K)
156
+ )
157
+ mm1_out = _resize_cache(workspace13, (M * topk, N * 2))
158
+ act_out = _resize_cache(workspace2, (M * topk, N))
159
+ # original workspace are based on input hidden_states dtype (bf16)
160
+ quant_out = _resize_cache(
161
+ workspace13.view(dtype=torch.float8_e4m3fn), (M * topk, N)
162
+ )
163
+ mm2_out = _resize_cache(workspace2, (M * topk, K))
164
+
165
+ if use_batched_format:
166
+ assert expert_num_tokens is not None
167
+
168
+ expert_offsets = torch.empty((local_E), dtype=torch.int32, device=device)
169
+ problem_sizes1 = torch.empty((local_E, 3), dtype=torch.int32, device=device)
170
+ problem_sizes2 = torch.empty((local_E, 3), dtype=torch.int32, device=device)
171
+
172
+ ops.get_cutlass_batched_moe_mm_data(
173
+ expert_offsets,
174
+ problem_sizes1,
175
+ problem_sizes2,
176
+ expert_num_tokens,
177
+ local_E,
178
+ padded_M,
179
+ N,
180
+ K,
181
+ )
182
+
183
+ w1_scale = w1_scale.reshape(w1_scale.size(0), -1)
184
+ w2_scale = w2_scale.reshape(w2_scale.size(0), -1)
185
+ a1q = a1q.reshape(-1, a1q.size(2))
186
+ a1q_scale = a1q_scale.reshape(-1, a1q_scale.size(2)).contiguous()
187
+ # c3x get_group_gemm_starts expects int64 to avoid overflow
188
+ # during offset calculations
189
+ expert_offsets = expert_offsets.to(torch.int64)
190
+ else:
191
+ problem_sizes1 = torch.empty((local_E, 3), dtype=torch.int32, device=device)
192
+ problem_sizes2 = torch.empty((local_E, 3), dtype=torch.int32, device=device)
193
+
194
+ num_expert = global_num_experts if expert_map is None else expert_map.size(0)
195
+ # permuted a1q reuses workspace2
196
+ a1q, a1q_scale, expert_first_token_offset, inv_perm, _ = moe_permute(
197
+ a1q,
198
+ a1q_scale,
199
+ topk_ids,
200
+ num_expert,
201
+ local_E,
202
+ expert_map,
203
+ permuted_hidden_states=a1q_perm,
204
+ scratch=permute_scratch,
205
+ )
206
+ # swap_ab is a CUTLASS grouped-GEMM optimization (M <= 64 reduces padding).
207
+ swap_ab = a1q.size(0) <= 64
208
+ ops.get_cutlass_moe_mm_problem_sizes_from_expert_offsets(
209
+ expert_first_token_offset, problem_sizes1, problem_sizes2, N, K, swap_ab
210
+ )
211
+ expert_offsets = expert_first_token_offset[:-1]
212
+
213
+ if not per_act_token and (expert_map is not None or use_batched_format):
214
+ # this is necessary to avoid imprecise scale calculation caused by
215
+ # random data in the unused workspace. The workspace is unused when
216
+ # this rank handles only partial tokens, or when it is batched .
217
+ mm1_out.fill_(0)
218
+
219
+ ops.cutlass_moe_mm(
220
+ mm1_out,
221
+ a1q,
222
+ w1,
223
+ a1q_scale,
224
+ w1_scale,
225
+ expert_offsets,
226
+ problem_sizes1,
227
+ ab_strides1,
228
+ ab_strides1,
229
+ c_strides1,
230
+ per_act_token,
231
+ per_out_ch,
232
+ )
233
+
234
+ apply_moe_activation(activation, act_out, mm1_out)
235
+
236
+ a2q, a2q_scale = ops.scaled_fp8_quant(
237
+ act_out, a2_scale, use_per_token_if_dynamic=per_act_token, output=quant_out
238
+ )
239
+
240
+ ops.cutlass_moe_mm(
241
+ mm2_out,
242
+ a2q,
243
+ w2,
244
+ a2q_scale,
245
+ w2_scale,
246
+ expert_offsets,
247
+ problem_sizes2,
248
+ ab_strides2,
249
+ ab_strides2,
250
+ c_strides2,
251
+ per_act_token,
252
+ per_out_ch,
253
+ )
254
+
255
+ if use_batched_format:
256
+ output.copy_(mm2_out.reshape(local_E, padded_M, K), non_blocking=True)
257
+ else:
258
+ # for non-chunking mode the output is resized from workspace13
259
+ # so we need to make sure mm2_out uses workspace2.
260
+ moe_unpermute(
261
+ out=output,
262
+ permuted_hidden_states=mm2_out,
263
+ topk_weights=topk_weights,
264
+ inv_permuted_idx=inv_perm,
265
+ expert_first_token_offset=expert_first_token_offset,
266
+ )
267
+
268
+
269
+ class CutlassExpertsFp8Base(mk.FusedMoEExpertsModular):
270
+ def __init__(
271
+ self,
272
+ moe_config: FusedMoEConfig,
273
+ quant_config: FusedMoEQuantConfig,
274
+ max_num_tokens: int | None = None,
275
+ num_dispatchers: int | None = None,
276
+ ):
277
+ super().__init__(
278
+ moe_config=moe_config,
279
+ quant_config=quant_config,
280
+ max_num_tokens=max_num_tokens,
281
+ num_dispatchers=num_dispatchers,
282
+ )
283
+ assert quant_config.use_fp8_w8a8
284
+
285
+ e = moe_config.num_local_experts
286
+ n = moe_config.intermediate_size_per_partition
287
+ k = moe_config.hidden_dim
288
+ device = moe_config.device
289
+ ab_strides1_c_strides2 = torch.full((e,), k, device=device, dtype=torch.int64)
290
+ ab_strides2 = torch.full((e,), n, device=device, dtype=torch.int64)
291
+ c_strides1 = torch.full((e,), 2 * n, device=device, dtype=torch.int64)
292
+
293
+ self.out_dtype = moe_config.in_dtype
294
+ self.ab_strides1 = ab_strides1_c_strides2
295
+ self.ab_strides2 = ab_strides2
296
+ self.c_strides1 = c_strides1
297
+ self.c_strides2 = ab_strides1_c_strides2
298
+ self._permute_scratch: MoEPermuteScratch | None = None
299
+
300
+ @staticmethod
301
+ def _supports_current_device() -> bool:
302
+ return cutlass_group_gemm_supported()
303
+
304
+ @staticmethod
305
+ def _supports_no_act_and_mul() -> bool:
306
+ return False
307
+
308
+ @staticmethod
309
+ def _supports_quant_scheme(
310
+ weight_key: QuantKey | None,
311
+ activation_key: QuantKey | None,
312
+ ) -> bool:
313
+ SUPPORTED_W_A = [
314
+ (kFp8StaticChannelSym, kFp8DynamicTokenSym),
315
+ (kFp8StaticTensorSym, kFp8DynamicTensorSym),
316
+ (kFp8StaticTensorSym, kFp8StaticTensorSym),
317
+ ]
318
+ return (weight_key, activation_key) in SUPPORTED_W_A
319
+
320
+ @staticmethod
321
+ def _supports_activation(activation: MoEActivation) -> bool:
322
+ return activation in [
323
+ MoEActivation.SILU,
324
+ MoEActivation.GELU,
325
+ MoEActivation.GELU_TANH,
326
+ MoEActivation.SWIGLUOAI,
327
+ ]
328
+
329
+ def finalize_weight_and_reduce_impl(self) -> mk.TopKWeightAndReduce:
330
+ # Let PrepareAndFinalize::finalize() decide the impl.
331
+ return TopKWeightAndReduceDelegate()
332
+
333
+ def _get_permute_scratch(self) -> MoEPermuteScratch | None:
334
+ if self._permute_scratch is None and moe_permute_unpermute_supported():
335
+ self._permute_scratch = MoEPermuteScratch(
336
+ max_num_tokens=self.moe_config.max_num_tokens,
337
+ topk=self.moe_config.experts_per_token,
338
+ num_experts=self.moe_config.num_experts,
339
+ num_local_experts=self.moe_config.num_local_experts,
340
+ device=torch.device(self.moe_config.device),
341
+ )
342
+ return self._permute_scratch
343
+
344
+ def apply(
345
+ self,
346
+ output: torch.Tensor,
347
+ hidden_states: torch.Tensor,
348
+ w1: torch.Tensor,
349
+ w2: torch.Tensor,
350
+ topk_weights: torch.Tensor,
351
+ topk_ids: torch.Tensor,
352
+ activation: MoEActivation,
353
+ global_num_experts: int,
354
+ expert_map: torch.Tensor | None,
355
+ a1q_scale: torch.Tensor | None,
356
+ a2_scale: torch.Tensor | None,
357
+ workspace13: torch.Tensor,
358
+ workspace2: torch.Tensor,
359
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
360
+ apply_router_weight_on_input: bool,
361
+ ):
362
+ assert self.w1_zp is None, "w1_zp is not supported in CUTLASS MoE"
363
+ assert self.w2_zp is None, "w2_zp is not supported in CUTLASS MoE"
364
+
365
+ expert_num_tokens = None
366
+ if expert_tokens_meta is not None:
367
+ expert_num_tokens = expert_tokens_meta.expert_num_tokens
368
+
369
+ use_batched_format = (
370
+ self.activation_format() == mk.FusedMoEActivationFormat.BatchedExperts
371
+ )
372
+
373
+ in_dtype = hidden_states.dtype
374
+ run_cutlass_moe_fp8(
375
+ output,
376
+ hidden_states,
377
+ w1,
378
+ w2,
379
+ topk_ids,
380
+ activation,
381
+ global_num_experts,
382
+ expert_map,
383
+ self.w1_scale,
384
+ self.w2_scale,
385
+ a1q_scale,
386
+ a2_scale,
387
+ self.ab_strides1,
388
+ self.ab_strides2,
389
+ self.c_strides1,
390
+ self.c_strides2,
391
+ workspace13,
392
+ workspace2,
393
+ expert_num_tokens,
394
+ self.out_dtype if self.out_dtype is not None else in_dtype,
395
+ self.per_act_token_quant,
396
+ self.per_out_ch_quant,
397
+ use_batched_format,
398
+ topk_weights,
399
+ self._get_permute_scratch(),
400
+ )
401
+
402
+
403
+ class CutlassExpertsFp8(CutlassExpertsFp8Base):
404
+ """CUTLASS FP8 fused MoE expert implementation."""
405
+
406
+ @staticmethod
407
+ def activation_format() -> mk.FusedMoEActivationFormat:
408
+ return mk.FusedMoEActivationFormat.Standard
409
+
410
+ @staticmethod
411
+ def _supports_parallel_config(moe_parallel_config: FusedMoEParallelConfig) -> bool:
412
+ # CutlassExpertsFp8 does not support expert map, which is
413
+ # needed for STANDARD activation format kernels in DP/EP mode.
414
+ # Note that the BATCHED activation format does not use
415
+ # the expert map for identifying experts.
416
+ return not (
417
+ moe_parallel_config.use_fi_nvl_two_sided_kernels
418
+ or moe_parallel_config.use_deepep_ht_kernels
419
+ or moe_parallel_config.use_fi_nvl_one_sided_kernels
420
+ )
421
+
422
+ def finalize_weight_and_reduce_impl(self) -> mk.TopKWeightAndReduce:
423
+ # topk weights and reduction are fused in moe_unpermute cuda kernel
424
+ return TopKWeightAndReduceNoOP()
425
+
426
+ def workspace_dtype(self, act_dtype: torch.dtype) -> torch.dtype:
427
+ return self.out_dtype if self.out_dtype is not None else act_dtype
428
+
429
+ def workspace_shapes(
430
+ self,
431
+ M: int,
432
+ N: int,
433
+ K: int,
434
+ topk: int,
435
+ global_num_experts: int,
436
+ local_num_experts: int,
437
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
438
+ activation: MoEActivation,
439
+ ) -> tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...]]:
440
+ activation_out_dim = self.adjust_N_for_activation(N, activation)
441
+ workspace1 = (M * topk, max(N, K))
442
+ workspace2 = (M * topk, max(activation_out_dim, K))
443
+ output = (M, K)
444
+ return (workspace1, workspace2, output)
445
+
446
+
447
+ class CutlassBatchedExpertsFp8(CutlassExpertsFp8Base):
448
+ """Batched CUTLASS FP8 fused MoE expert implementation."""
449
+
450
+ @staticmethod
451
+ def _supports_parallel_config(moe_parallel_config: FusedMoEParallelConfig) -> bool:
452
+ # BATCHED activation format works with EP because
453
+ # expert_map is not used to identify experts (the
454
+ # info is encoded/managed by the P/F logic).
455
+ return True
456
+
457
+ @staticmethod
458
+ def activation_format() -> mk.FusedMoEActivationFormat:
459
+ return mk.FusedMoEActivationFormat.BatchedExperts
460
+
461
+ def workspace_dtype(self, act_dtype: torch.dtype) -> torch.dtype:
462
+ return self.out_dtype if self.out_dtype is not None else act_dtype
463
+
464
+ def workspace_shapes(
465
+ self,
466
+ M: int,
467
+ N: int,
468
+ K: int,
469
+ topk: int,
470
+ global_num_experts: int,
471
+ local_num_experts: int,
472
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
473
+ activation: MoEActivation,
474
+ ) -> tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...]]:
475
+ num_dp = self.num_dispatchers
476
+ assert num_dp is not None
477
+ experts_per_worker = self.moe_config.num_local_experts
478
+ activation_out_dim = self.adjust_N_for_activation(N, activation)
479
+ workspace1 = (experts_per_worker, M * num_dp, max(N, K))
480
+ workspace2 = (
481
+ experts_per_worker,
482
+ M * num_dp,
483
+ max(activation_out_dim, K),
484
+ )
485
+ output = (experts_per_worker, M, K)
486
+ return (workspace1, workspace2, output)
487
+
488
+
489
+ FLOAT4_E2M1_MAX = scalar_types.float4_e2m1f.max()
490
+ FLOAT8_E4M3_MAX = torch.finfo(torch.float8_e4m3fn).max
491
+
492
+
493
+ def run_cutlass_moe_fp4(
494
+ output: torch.Tensor,
495
+ a: torch.Tensor,
496
+ a1_gscale: torch.Tensor,
497
+ w1_fp4: torch.Tensor,
498
+ w1_blockscale: torch.Tensor,
499
+ w1_alphas: torch.Tensor,
500
+ a2_gscale: torch.Tensor,
501
+ w2_fp4: torch.Tensor,
502
+ w2_blockscale: torch.Tensor,
503
+ w2_alphas: torch.Tensor,
504
+ topk_weights: torch.Tensor,
505
+ topk_ids: torch.Tensor,
506
+ activation: MoEActivation,
507
+ workspace13: torch.Tensor,
508
+ workspace2: torch.Tensor,
509
+ m: int,
510
+ n: int,
511
+ k: int,
512
+ e: int,
513
+ device: torch.device,
514
+ apply_router_weight_on_input: bool = False,
515
+ ) -> None:
516
+ """
517
+ MoE implementation for FP4 Inputs
518
+
519
+ # Gemm 1
520
+ a: Input tensor: [m, k] (half/bfloat16)
521
+ a1_gscale: Activation scale per expert: [e] (float32)
522
+ w1 (not an argument to cutlass_moe_fp4): [e, w1_n, k]
523
+ w1_fp4: [e, w1_n, k // 2], dtype: torch.uint8 (stacked fp4: E2M1)
524
+ where w1_n = 2*n for gated activations (gate+up), n for non-gated (up only).
525
+ (Note: `n` is the up projection output dim, `k` is the input dim in
526
+ full precision)
527
+ w1_blockscale: [e, w1_n, k // block_size] (float8_e4m3)
528
+ (Block size = 16 for NVFP4)
529
+
530
+ # Gemm 2
531
+ a2_gscale: Activation scale per expert: [e]
532
+ w2(down projection) (not an argument to cutlass_moe_fp4): [e, k, n]
533
+ w2_fp4: [e, k, n // 2], dtype: torch.uint8 (stacked E2M1)
534
+ w2_blockscale: [e, k, n // block_size], dtype: float8_e4m3
535
+
536
+ topk_weights: [m, topk] dtype: float8
537
+ topk_ids: [m, topk] dtype: float8
538
+
539
+ m, n, k: Unquantized weight shapes, dtype: int
540
+ e: number of experts, dtype: int
541
+
542
+ assumes that topk < k < n to satisfy - up/down projection expectations.
543
+ """
544
+ is_gated = activation.is_gated
545
+ # For gated activations (e.g. SiLU), w1 output is 2*n (gate + up).
546
+ # For non-gated activations (e.g. SiLU_NO_MUL), w1 output is n (up only).
547
+ w1_n = n * 2 if is_gated else n
548
+
549
+ assert topk_weights.shape == topk_ids.shape, "topk shape mismatch"
550
+ assert w1_fp4.dtype == torch.uint8, "weight 1 must be uint8"
551
+ assert w2_fp4.dtype == torch.uint8, "weight 2 must be uint8"
552
+ assert (
553
+ w1_fp4.ndim == 3
554
+ and w2_fp4.ndim == 3
555
+ and w1_blockscale.ndim == 3
556
+ and w2_blockscale.ndim == 3
557
+ ), "All Weights must be of rank 3 for cutlass_moe_fp4"
558
+ m_a, k_a = a.shape
559
+ e_w1, w1_n_actual, half_k_w1 = w1_fp4.shape
560
+ e_w2, k_w2, half_n_w2 = w2_fp4.shape
561
+
562
+ assert e_w1 == e_w2 and e_w1 == e, (
563
+ "Number of experts must match",
564
+ f" between weights. {e_w1}, {e_w2}, {e}",
565
+ )
566
+ assert k_a == half_k_w1 * 2 and k == k_w2, (
567
+ "Hidden size mismatch between a, w1 and w2"
568
+ )
569
+ assert w1_n_actual == w1_n and half_n_w2 * 2 == n, "mismatch in expected `n`"
570
+ assert m == m_a, "input shape mismatch"
571
+ assert 2 * half_k_w1 == k_w2, "Hidden size mismatch w2 and w1"
572
+ assert a.dtype in [torch.half, torch.bfloat16], "Invalid input dtype"
573
+ assert topk_weights.size(0) == m and topk_ids.size(0) == m, (
574
+ "topk must be provided for each row of a"
575
+ )
576
+ topk = topk_ids.size(1)
577
+ out_dtype = a.dtype
578
+ num_topk = topk_ids.size(1)
579
+
580
+ expert_offsets = torch.empty((e + 1), dtype=torch.int32, device=device)
581
+ blockscale_offsets = torch.empty((e + 1), dtype=torch.int32, device=device)
582
+ # Problem size: (num_experts, (m,2n,k))
583
+ problem_sizes1 = torch.empty((e, 3), dtype=torch.int32, device=device)
584
+ # Problem size: (num_experts, (m,n,k))
585
+ problem_sizes2 = torch.empty((e, 3), dtype=torch.int32, device=device)
586
+
587
+ a_map = torch.empty((topk_ids.numel()), dtype=torch.int32, device=device)
588
+ c_map = torch.empty((topk_ids.numel()), dtype=torch.int32, device=device)
589
+
590
+ if apply_router_weight_on_input:
591
+ # TODO: this only works for topK=1, will need to update for topK>1
592
+ assert num_topk == 1, (
593
+ "apply_router_weight_on_input is only implemented for topk=1"
594
+ )
595
+ a.mul_(topk_weights.to(out_dtype))
596
+
597
+ # problem shapes should have [m, n, k]
598
+ # Note that problem sizes are based on logical number of elements.
599
+ ops.get_cutlass_moe_mm_data(
600
+ topk_ids,
601
+ expert_offsets,
602
+ problem_sizes1,
603
+ problem_sizes2,
604
+ a_map,
605
+ c_map,
606
+ e,
607
+ n,
608
+ k,
609
+ blockscale_offsets,
610
+ is_gated=is_gated,
611
+ )
612
+
613
+ a = ops.shuffle_rows(a, a_map)
614
+ rep_a_fp4, rep_a_blockscale = ops.scaled_fp4_experts_quant(
615
+ a,
616
+ a1_gscale,
617
+ expert_offsets,
618
+ blockscale_offsets,
619
+ num_topk,
620
+ )
621
+ c1 = _resize_cache(workspace13, (m * topk, w1_n))
622
+ c2 = _resize_cache(workspace2, (m * topk, n))
623
+ c3 = _resize_cache(workspace13, (m * topk, k))
624
+ ops.cutlass_fp4_moe_mm(
625
+ c1,
626
+ rep_a_fp4,
627
+ w1_fp4,
628
+ rep_a_blockscale,
629
+ w1_blockscale,
630
+ w1_alphas,
631
+ problem_sizes1,
632
+ expert_offsets[:-1],
633
+ blockscale_offsets[:-1],
634
+ )
635
+ del rep_a_fp4, rep_a_blockscale
636
+ if activation == MoEActivation.SILU:
637
+ # Fused SiLU+Mul+NVFP4 quantization
638
+ # Note: c2 workspace is no longer needed since SiLU is fused with quantization.
639
+ # c3 reuses workspace13 after c1 is consumed.
640
+ int_fp4, int_blockscale = ops.silu_and_mul_scaled_fp4_experts_quant(
641
+ c1, a2_gscale, expert_offsets, blockscale_offsets, num_topk
642
+ )
643
+ else:
644
+ apply_moe_activation(activation, c2, c1)
645
+ int_fp4, int_blockscale = ops.scaled_fp4_experts_quant(
646
+ c2, a2_gscale, expert_offsets, blockscale_offsets, num_topk
647
+ )
648
+
649
+ ops.cutlass_fp4_moe_mm(
650
+ c3,
651
+ int_fp4,
652
+ w2_fp4,
653
+ int_blockscale,
654
+ w2_blockscale,
655
+ w2_alphas,
656
+ problem_sizes2,
657
+ expert_offsets[:-1],
658
+ blockscale_offsets[:-1],
659
+ )
660
+ del int_fp4, int_blockscale
661
+
662
+ c3 = ops.shuffle_rows(c3, c_map)
663
+
664
+ assert output.dtype == out_dtype
665
+ if not apply_router_weight_on_input:
666
+ output.copy_(
667
+ (
668
+ c3.view(m, num_topk, k)
669
+ * topk_weights.view(m, num_topk, 1).to(out_dtype)
670
+ ).sum(dim=1),
671
+ non_blocking=True,
672
+ )
673
+ else:
674
+ output.copy_(c3.view(m, num_topk, k).sum(dim=1), non_blocking=True)
675
+ return
676
+
677
+
678
+ class CutlassExpertsFp4(mk.FusedMoEExpertsModular):
679
+ """CUTLASS FP4 fused MoE expert implementation."""
680
+
681
+ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
682
+ # Fuse activation scales into w_scale_2 in-place so that
683
+ # g1/g2_alphas (which reference the same tensor) stay in sync
684
+ # when EPLB rearranges the parameter.
685
+ layer.w13_weight_scale_2.data.mul_(layer.w13_input_scale)
686
+ layer.w2_weight_scale_2.data.mul_(layer.w2_input_scale)
687
+
688
+ @property
689
+ def expects_unquantized_inputs(self) -> bool:
690
+ return True
691
+
692
+ @staticmethod
693
+ def _supports_current_device() -> bool:
694
+ p = current_platform
695
+ return p.is_cuda() and (
696
+ p.is_device_capability_family(100)
697
+ or p.is_device_capability_family(110)
698
+ or p.is_device_capability_family(120)
699
+ )
700
+
701
+ @staticmethod
702
+ def _supports_no_act_and_mul() -> bool:
703
+ return True
704
+
705
+ @staticmethod
706
+ def _supports_quant_scheme(
707
+ weight_key: QuantKey | None,
708
+ activation_key: QuantKey | None,
709
+ ) -> bool:
710
+ return (weight_key, activation_key) == (kNvfp4Static, kNvfp4Dynamic)
711
+
712
+ @staticmethod
713
+ def _supports_activation(activation: MoEActivation) -> bool:
714
+ # SILU uses a fused silu+mul+fp4_quant kernel path.
715
+ # Other gated activations use the generic apply_moe_activation()
716
+ # fallback + separate fp4 quantization in run_cutlass_moe_fp4().
717
+ # Non-gated activations (_NO_MUL) are also supported for models
718
+ # like Nemotron-Nano that don't use gated MLP.
719
+ return activation in [
720
+ MoEActivation.SILU,
721
+ MoEActivation.GELU,
722
+ MoEActivation.GELU_TANH,
723
+ MoEActivation.SWIGLUOAI,
724
+ MoEActivation.SWIGLUSTEP,
725
+ MoEActivation.SILU_NO_MUL,
726
+ MoEActivation.GELU_NO_MUL,
727
+ MoEActivation.GELU_TANH_NO_MUL,
728
+ MoEActivation.RELU2_NO_MUL,
729
+ ]
730
+
731
+ @staticmethod
732
+ def _supports_parallel_config(moe_parallel_config: FusedMoEParallelConfig) -> bool:
733
+ # CutlassExpertsFp4 does not support expert map, which is
734
+ # needed for STANDARD activation format kernels in EP mode.
735
+ return moe_parallel_config.ep_size == 1
736
+
737
+ @staticmethod
738
+ def activation_format() -> mk.FusedMoEActivationFormat:
739
+ return mk.FusedMoEActivationFormat.Standard
740
+
741
+ def finalize_weight_and_reduce_impl(self) -> mk.TopKWeightAndReduce:
742
+ return TopKWeightAndReduceNoOP()
743
+
744
+ def workspace_dtype(self, act_dtype: torch.dtype) -> torch.dtype:
745
+ return act_dtype
746
+
747
+ def workspace_shapes(
748
+ self,
749
+ M: int,
750
+ N: int,
751
+ K: int,
752
+ topk: int,
753
+ global_num_experts: int,
754
+ local_num_experts: int,
755
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
756
+ activation: MoEActivation,
757
+ ) -> tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...]]:
758
+ workspace1 = (M * topk, max(2 * N, K))
759
+ workspace2 = (M * topk, N)
760
+ output = (M, K)
761
+ return (workspace1, workspace2, output)
762
+
763
+ def apply(
764
+ self,
765
+ output: torch.Tensor,
766
+ hidden_states: torch.Tensor,
767
+ w1: torch.Tensor,
768
+ w2: torch.Tensor,
769
+ topk_weights: torch.Tensor,
770
+ topk_ids: torch.Tensor,
771
+ activation: MoEActivation,
772
+ global_num_experts: int,
773
+ expert_map: torch.Tensor | None,
774
+ a1q_scale: torch.Tensor | None, # unused
775
+ a2_scale: torch.Tensor | None, # unused
776
+ workspace13: torch.Tensor | None,
777
+ workspace2: torch.Tensor | None,
778
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
779
+ apply_router_weight_on_input: bool,
780
+ ):
781
+ e, m, n, k, _ = self.moe_problem_size(hidden_states, w1, w2, topk_ids)
782
+ n = w2.shape[2] * 2
783
+
784
+ run_cutlass_moe_fp4(
785
+ output=output,
786
+ a=hidden_states,
787
+ a1_gscale=self.a1_gscale,
788
+ w1_fp4=w1,
789
+ w1_blockscale=self.w1_scale,
790
+ w1_alphas=self.g1_alphas,
791
+ a2_gscale=self.a2_gscale,
792
+ w2_fp4=w2,
793
+ w2_blockscale=self.w2_scale,
794
+ w2_alphas=self.g2_alphas,
795
+ topk_weights=topk_weights,
796
+ topk_ids=topk_ids,
797
+ activation=activation,
798
+ workspace13=workspace13,
799
+ workspace2=workspace2,
800
+ m=m,
801
+ n=n,
802
+ k=k,
803
+ e=e,
804
+ device=hidden_states.device,
805
+ apply_router_weight_on_input=apply_router_weight_on_input,
806
+ )
807
+
808
+
809
+ def run_cutlass_moe_mxfp4(
810
+ output: torch.Tensor,
811
+ a: torch.Tensor,
812
+ w1_fp4: torch.Tensor,
813
+ w1_blockscale: torch.Tensor,
814
+ w2_fp4: torch.Tensor,
815
+ w2_blockscale: torch.Tensor,
816
+ topk_weights: torch.Tensor,
817
+ topk_ids: torch.Tensor,
818
+ activation: MoEActivation,
819
+ workspace13: torch.Tensor,
820
+ workspace2: torch.Tensor,
821
+ m: int,
822
+ n: int,
823
+ k: int,
824
+ e: int,
825
+ device: torch.device,
826
+ apply_router_weight_on_input: bool = False,
827
+ swiglu_limit: float | None = None,
828
+ ) -> None:
829
+ """MXFP4 x MXFP4 MoE implementation using CUTLASS grouped GEMM."""
830
+ is_gated = activation.is_gated
831
+ w1_n = n * 2 if is_gated else n
832
+
833
+ assert topk_weights.shape == topk_ids.shape, "topk shape mismatch"
834
+ assert w1_fp4.dtype == torch.uint8, "weight 1 must be uint8"
835
+ assert w2_fp4.dtype == torch.uint8, "weight 2 must be uint8"
836
+ assert (
837
+ w1_fp4.ndim == 3
838
+ and w2_fp4.ndim == 3
839
+ and w1_blockscale.ndim == 3
840
+ and w2_blockscale.ndim == 3
841
+ ), "All Weights must be of rank 3 for cutlass_moe_mxfp4"
842
+ m_a, k_a = a.shape
843
+ e_w1, w1_n_actual, half_k_w1 = w1_fp4.shape
844
+ e_w2, k_w2, half_n_w2 = w2_fp4.shape
845
+
846
+ assert e_w1 == e_w2 and e_w1 == e
847
+ assert k_a == half_k_w1 * 2 and k == k_w2
848
+ assert w1_n_actual == w1_n and half_n_w2 * 2 == n
849
+ assert m == m_a
850
+ assert 2 * half_k_w1 == k_w2
851
+ assert a.dtype in [torch.half, torch.bfloat16], "Invalid input dtype"
852
+ assert topk_weights.size(0) == m and topk_ids.size(0) == m
853
+
854
+ topk = topk_ids.size(1)
855
+ out_dtype = a.dtype
856
+ num_topk = topk_ids.size(1)
857
+
858
+ expert_offsets = torch.empty((e + 1), dtype=torch.int32, device=device)
859
+ blockscale_offsets = torch.empty((e + 1), dtype=torch.int32, device=device)
860
+ problem_sizes1 = torch.empty((e, 3), dtype=torch.int32, device=device)
861
+ problem_sizes2 = torch.empty((e, 3), dtype=torch.int32, device=device)
862
+
863
+ a_map = torch.empty((topk_ids.numel()), dtype=torch.int32, device=device)
864
+ c_map = torch.empty((topk_ids.numel()), dtype=torch.int32, device=device)
865
+
866
+ if apply_router_weight_on_input:
867
+ assert num_topk == 1, (
868
+ "apply_router_weight_on_input is only implemented for topk=1"
869
+ )
870
+ a.mul_(topk_weights.to(out_dtype))
871
+
872
+ ops.get_cutlass_moe_mm_data(
873
+ topk_ids,
874
+ expert_offsets,
875
+ problem_sizes1,
876
+ problem_sizes2,
877
+ a_map,
878
+ c_map,
879
+ e,
880
+ n,
881
+ k,
882
+ blockscale_offsets,
883
+ is_gated=is_gated,
884
+ )
885
+
886
+ a = ops.shuffle_rows(a, a_map)
887
+ rep_a_fp4, rep_a_blockscale = ops.mxfp4_experts_quant(
888
+ a,
889
+ expert_offsets,
890
+ blockscale_offsets,
891
+ e,
892
+ num_topk,
893
+ )
894
+ c1 = _resize_cache(workspace13, (m * topk, w1_n))
895
+ c2 = _resize_cache(workspace2, (m * topk, n))
896
+ c3 = _resize_cache(workspace13, (m * topk, k))
897
+
898
+ ops.cutlass_mxfp4_moe_mm(
899
+ c1,
900
+ rep_a_fp4,
901
+ w1_fp4,
902
+ rep_a_blockscale,
903
+ w1_blockscale,
904
+ problem_sizes1,
905
+ expert_offsets[:-1],
906
+ blockscale_offsets[:-1],
907
+ )
908
+ del rep_a_fp4, rep_a_blockscale
909
+ if activation == MoEActivation.SILU and swiglu_limit is None:
910
+ # Fused silu+mul+requantize; no clamp variant exists, so a layer that
911
+ # declares a SwiGLU limit has to take the generic path below.
912
+ int_fp4, int_blockscale = ops.silu_and_mul_mxfp4_experts_quant(
913
+ c1, expert_offsets, blockscale_offsets, e, num_topk
914
+ )
915
+ else:
916
+ apply_moe_activation(activation, c2, c1, clamp_limit=swiglu_limit)
917
+ int_fp4, int_blockscale = ops.mxfp4_experts_quant(
918
+ c2, expert_offsets, blockscale_offsets, e, num_topk
919
+ )
920
+
921
+ ops.cutlass_mxfp4_moe_mm(
922
+ c3,
923
+ int_fp4,
924
+ w2_fp4,
925
+ int_blockscale,
926
+ w2_blockscale,
927
+ problem_sizes2,
928
+ expert_offsets[:-1],
929
+ blockscale_offsets[:-1],
930
+ )
931
+ del int_fp4, int_blockscale
932
+
933
+ c3 = ops.shuffle_rows(c3, c_map)
934
+
935
+ assert output.dtype == out_dtype
936
+ if not apply_router_weight_on_input:
937
+ output.copy_(
938
+ (
939
+ c3.view(m, num_topk, k)
940
+ * topk_weights.view(m, num_topk, 1).to(out_dtype)
941
+ ).sum(dim=1),
942
+ non_blocking=True,
943
+ )
944
+ else:
945
+ output.copy_(c3.view(m, num_topk, k).sum(dim=1), non_blocking=True)
946
+ return
947
+
948
+
949
+ def swizzle_mxfp4_scales(
950
+ scales: torch.Tensor,
951
+ N: int,
952
+ K: int,
953
+ ) -> torch.Tensor:
954
+ """Swizzle flat [N, K//32] E8M0 scales to CUTLASS tiled layout.
955
+
956
+ CUTLASS expects MX scale factors in a tiled layout:
957
+ [numMTiles, numKTiles, 32, 4, 4]
958
+ where numMTiles = ceil(N/128), numKTiles = ceil(K/128),
959
+ and the inner dimensions correspond to the swizzle pattern:
960
+ mTileIdx = mIdx / 128
961
+ outerMIdx = mIdx % 32
962
+ innerMIdx = (mIdx / 32) % 4
963
+ kTileIdx = kIdx / 4
964
+ innerKIdx = kIdx % 4
965
+ with kIdx = col_in_scale_space (i.e., index into K//32).
966
+ """
967
+ assert scales.dtype == torch.uint8
968
+ num_scale_cols = K // 32 # number of E8M0 scale values per row
969
+
970
+ num_m_tiles = (N + 127) // 128
971
+ num_k_tiles = (num_scale_cols + 3) // 4
972
+
973
+ # Pad N to multiple of 128 and scale_cols to multiple of 4
974
+ padded_N = num_m_tiles * 128
975
+ padded_scale_cols = num_k_tiles * 4
976
+
977
+ # Start with flat scales, pad if needed
978
+ padded = torch.zeros(
979
+ padded_N, padded_scale_cols, dtype=torch.uint8, device=scales.device
980
+ )
981
+ padded[:N, :num_scale_cols] = scales
982
+
983
+ # Reshape to tile structure:
984
+ # [numMTiles, 4, 32, numKTiles, 4]
985
+ # mTileIdx, innerMIdx, outerMIdx, kTileIdx, innerKIdx
986
+ tiled = padded.reshape(num_m_tiles, 4, 32, num_k_tiles, 4)
987
+ # Permute to [numMTiles, numKTiles, 32, 4, 4]
988
+ # (outerMIdx, innerMIdx, innerKIdx)
989
+ tiled = tiled.permute(0, 3, 2, 1, 4).contiguous()
990
+ return tiled.reshape(-1)
991
+
992
+
993
+ class CutlassExpertsMxfp4(mk.FusedMoEExpertsModular):
994
+ """CUTLASS MXFP4 x MXFP4 fused MoE expert implementation."""
995
+
996
+ @property
997
+ def expects_unquantized_inputs(self) -> bool:
998
+ return True
999
+
1000
+ @staticmethod
1001
+ def _supports_current_device() -> bool:
1002
+ p = current_platform
1003
+ capability = p.get_device_capability()
1004
+ return (
1005
+ p.is_cuda()
1006
+ and capability is not None
1007
+ and ops.mxfp4_experts_quant_supported(capability.to_int())
1008
+ )
1009
+
1010
+ @staticmethod
1011
+ def _supports_no_act_and_mul() -> bool:
1012
+ return True
1013
+
1014
+ @staticmethod
1015
+ def _supports_quant_scheme(
1016
+ weight_key: QuantKey | None,
1017
+ activation_key: QuantKey | None,
1018
+ ) -> bool:
1019
+ return (weight_key, activation_key) == (kMxfp4Static, kMxfp4Dynamic)
1020
+
1021
+ @staticmethod
1022
+ def _supports_activation(activation: MoEActivation) -> bool:
1023
+ return activation in [
1024
+ MoEActivation.SILU,
1025
+ MoEActivation.GELU,
1026
+ MoEActivation.SWIGLUOAI,
1027
+ MoEActivation.SWIGLUSTEP,
1028
+ MoEActivation.SILU_NO_MUL,
1029
+ MoEActivation.GELU_NO_MUL,
1030
+ MoEActivation.RELU2_NO_MUL,
1031
+ ]
1032
+
1033
+ @staticmethod
1034
+ def _supports_parallel_config(
1035
+ moe_parallel_config: FusedMoEParallelConfig,
1036
+ ) -> bool:
1037
+ return moe_parallel_config.ep_size == 1
1038
+
1039
+ @staticmethod
1040
+ def activation_format() -> mk.FusedMoEActivationFormat:
1041
+ return mk.FusedMoEActivationFormat.Standard
1042
+
1043
+ def finalize_weight_and_reduce_impl(self) -> mk.TopKWeightAndReduce:
1044
+ return TopKWeightAndReduceNoOP()
1045
+
1046
+ def workspace_dtype(self, act_dtype: torch.dtype) -> torch.dtype:
1047
+ return act_dtype
1048
+
1049
+ def workspace_shapes(
1050
+ self,
1051
+ M: int,
1052
+ N: int,
1053
+ K: int,
1054
+ topk: int,
1055
+ global_num_experts: int,
1056
+ local_num_experts: int,
1057
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
1058
+ activation: MoEActivation,
1059
+ ) -> tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...]]:
1060
+ workspace1 = (M * topk, max(2 * N, K))
1061
+ workspace2 = (M * topk, N)
1062
+ output = (M, K)
1063
+ return (workspace1, workspace2, output)
1064
+
1065
+ def apply(
1066
+ self,
1067
+ output: torch.Tensor,
1068
+ hidden_states: torch.Tensor,
1069
+ w1: torch.Tensor,
1070
+ w2: torch.Tensor,
1071
+ topk_weights: torch.Tensor,
1072
+ topk_ids: torch.Tensor,
1073
+ activation: MoEActivation,
1074
+ global_num_experts: int,
1075
+ expert_map: torch.Tensor | None,
1076
+ a1q_scale: torch.Tensor | None,
1077
+ a2_scale: torch.Tensor | None,
1078
+ workspace13: torch.Tensor | None,
1079
+ workspace2: torch.Tensor | None,
1080
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
1081
+ apply_router_weight_on_input: bool,
1082
+ ):
1083
+ e, m, n, k, _ = self.moe_problem_size(hidden_states, w1, w2, topk_ids)
1084
+ n = w2.shape[2] * 2
1085
+
1086
+ run_cutlass_moe_mxfp4(
1087
+ output=output,
1088
+ a=hidden_states,
1089
+ w1_fp4=w1,
1090
+ w1_blockscale=self.w1_scale,
1091
+ w2_fp4=w2,
1092
+ w2_blockscale=self.w2_scale,
1093
+ topk_weights=topk_weights,
1094
+ topk_ids=topk_ids,
1095
+ activation=activation,
1096
+ workspace13=workspace13,
1097
+ workspace2=workspace2,
1098
+ m=m,
1099
+ n=n,
1100
+ k=k,
1101
+ e=e,
1102
+ device=hidden_states.device,
1103
+ apply_router_weight_on_input=apply_router_weight_on_input,
1104
+ swiglu_limit=self.quant_config.gemm1_clamp_limit,
1105
+ )
1106
+
1107
+
1108
+ # W4A8
1109
+ def run_cutlass_moe_w4a8_fp8(
1110
+ output: torch.Tensor,
1111
+ hidden_states: torch.Tensor,
1112
+ w1: torch.Tensor,
1113
+ w2: torch.Tensor,
1114
+ topk_ids: torch.Tensor,
1115
+ activation: MoEActivation,
1116
+ global_num_experts: int,
1117
+ expert_map: torch.Tensor | None,
1118
+ w1_scale: torch.Tensor | None,
1119
+ w2_scale: torch.Tensor | None,
1120
+ a1q_scale: torch.Tensor | None,
1121
+ a2_scale: torch.Tensor | None,
1122
+ w1_chan_scale: torch.Tensor,
1123
+ w2_chan_scale: torch.Tensor,
1124
+ a_strides1: torch.Tensor,
1125
+ a_strides2: torch.Tensor,
1126
+ b_strides1: torch.Tensor,
1127
+ b_strides2: torch.Tensor,
1128
+ c_strides1: torch.Tensor,
1129
+ c_strides2: torch.Tensor,
1130
+ s_strides1: torch.Tensor,
1131
+ s_strides2: torch.Tensor,
1132
+ workspace13: torch.Tensor,
1133
+ workspace2: torch.Tensor,
1134
+ expert_num_tokens: torch.Tensor | None,
1135
+ out_dtype: torch.dtype,
1136
+ per_act_token: bool,
1137
+ per_out_ch: bool,
1138
+ use_batched_format: bool,
1139
+ topk_weights: torch.Tensor | None,
1140
+ group_size: int,
1141
+ permute_scratch: MoEPermuteScratch | None,
1142
+ ):
1143
+ a1q = hidden_states
1144
+ M = a1q.size(0)
1145
+ local_E = w1.size(0)
1146
+ device = a1q.device
1147
+ _, K, N_packed = w2.shape
1148
+ N = N_packed * 8 # logical N, pack 8 int4 into 1 int32
1149
+
1150
+ assert per_act_token, "W4A8 must use per-token scales"
1151
+ assert per_out_ch, "W4A8 must use per-channel scales"
1152
+ assert w1_scale is not None
1153
+ assert w2_scale is not None
1154
+ assert w1_scale.dtype == torch.float8_e4m3fn
1155
+ assert w2_scale.dtype == torch.float8_e4m3fn
1156
+ assert w1.dtype == torch.int32
1157
+ assert w2.dtype == torch.int32
1158
+ assert w1_chan_scale.dtype == torch.float32
1159
+ assert w2_chan_scale.dtype == torch.float32
1160
+ assert w1.size(0) == w2.size(0), "Weights expert number mismatch"
1161
+ assert a1q_scale is not None
1162
+ assert a2_scale is None
1163
+ assert out_dtype in [torch.bfloat16], f"Invalid output dtype: {out_dtype}"
1164
+ if expert_map is not None:
1165
+ assert expert_num_tokens is None
1166
+ assert not use_batched_format, "batched format not supported yet"
1167
+ assert group_size == 128, f"Only group size 128 supported but got {group_size=}"
1168
+
1169
+ assert global_num_experts != -1
1170
+ assert w1.size(2) * 8 == K, (
1171
+ f"w1 hidden size mismatch: got {w1.size(2) * 8}, expected {K=}"
1172
+ )
1173
+
1174
+ topk = topk_ids.size(1)
1175
+ a1q_perm = _resize_cache(workspace2.view(dtype=torch.float8_e4m3fn), (M * topk, K))
1176
+ mm1_out = _resize_cache(workspace13, (M * topk, N * 2))
1177
+ act_out = _resize_cache(workspace2, (M * topk, N))
1178
+ # original workspace are based on input hidden_states dtype (bf16)
1179
+ quant_out = _resize_cache(
1180
+ workspace13.view(dtype=torch.float8_e4m3fn), (M * topk, N)
1181
+ )
1182
+ mm2_out = _resize_cache(workspace2, (M * topk, K))
1183
+
1184
+ problem_sizes1 = torch.empty((local_E, 3), dtype=torch.int32, device=device)
1185
+ problem_sizes2 = torch.empty((local_E, 3), dtype=torch.int32, device=device)
1186
+
1187
+ num_expert = global_num_experts if expert_map is None else expert_map.size(0)
1188
+ # permuted a1q reuses workspace2
1189
+ a1q, a1q_scale, expert_first_token_offset, inv_perm, _ = moe_permute(
1190
+ a1q,
1191
+ a1q_scale,
1192
+ topk_ids,
1193
+ num_expert,
1194
+ local_E,
1195
+ expert_map,
1196
+ permuted_hidden_states=a1q_perm,
1197
+ scratch=permute_scratch,
1198
+ )
1199
+ # for RS gemm SwapAB is always enabled (swap logical M, N in the problem shape).
1200
+ ops.get_cutlass_moe_mm_problem_sizes_from_expert_offsets(
1201
+ expert_first_token_offset, problem_sizes1, problem_sizes2, N, K, True
1202
+ )
1203
+ expert_offsets = expert_first_token_offset[:-1]
1204
+
1205
+ ops.cutlass_w4a8_moe_mm(
1206
+ mm1_out,
1207
+ a1q,
1208
+ w1,
1209
+ a1q_scale,
1210
+ w1_chan_scale,
1211
+ w1_scale,
1212
+ group_size,
1213
+ expert_offsets,
1214
+ problem_sizes1,
1215
+ a_strides1,
1216
+ b_strides1,
1217
+ c_strides1,
1218
+ s_strides1,
1219
+ )
1220
+
1221
+ apply_moe_activation(activation, act_out, mm1_out)
1222
+
1223
+ a2q, a2q_scale = ops.scaled_fp8_quant(
1224
+ act_out, a2_scale, use_per_token_if_dynamic=per_act_token, output=quant_out
1225
+ )
1226
+
1227
+ ops.cutlass_w4a8_moe_mm(
1228
+ mm2_out,
1229
+ a2q,
1230
+ w2,
1231
+ a2q_scale,
1232
+ w2_chan_scale,
1233
+ w2_scale,
1234
+ group_size,
1235
+ expert_offsets,
1236
+ problem_sizes2,
1237
+ a_strides2,
1238
+ b_strides2,
1239
+ c_strides2,
1240
+ s_strides2,
1241
+ )
1242
+
1243
+ # for non-chunking mode the output is resized from workspace13
1244
+ # so we need to make sure mm2_out uses workspace2.
1245
+ moe_unpermute(
1246
+ out=output,
1247
+ permuted_hidden_states=mm2_out,
1248
+ topk_weights=topk_weights,
1249
+ inv_permuted_idx=inv_perm,
1250
+ expert_first_token_offset=expert_first_token_offset,
1251
+ )
1252
+
1253
+
1254
+ class CutlassExpertsW4A8Fp8(mk.FusedMoEExpertsModular):
1255
+ def __init__(
1256
+ self,
1257
+ moe_config: FusedMoEConfig,
1258
+ quant_config: FusedMoEQuantConfig,
1259
+ b_strides1: torch.Tensor,
1260
+ b_strides2: torch.Tensor,
1261
+ group_size: int,
1262
+ ):
1263
+ super().__init__(moe_config=moe_config, quant_config=quant_config)
1264
+
1265
+ e = moe_config.num_local_experts
1266
+ n = moe_config.intermediate_size_per_partition
1267
+ k = moe_config.hidden_dim
1268
+ device = moe_config.device
1269
+
1270
+ self.out_dtype = moe_config.in_dtype
1271
+
1272
+ a_strides1_c_strides2 = torch.full((e,), k, device=device, dtype=torch.int64)
1273
+ self.a_strides1 = a_strides1_c_strides2
1274
+ self.a_strides2 = torch.full((e,), n, device=device, dtype=torch.int64)
1275
+ self.c_strides1 = torch.full((e,), 2 * n, device=device, dtype=torch.int64)
1276
+ self.c_strides2 = a_strides1_c_strides2
1277
+
1278
+ self.b_strides1 = b_strides1
1279
+ self.b_strides2 = b_strides2
1280
+
1281
+ # sizeof(StrideS) = 16 bytes, encoded as 2xint64.
1282
+ self.s_strides1 = torch.zeros((e, 2), device=device, dtype=torch.int64)
1283
+ self.s_strides1[:, 0] = 2 * n
1284
+ self.s_strides2 = torch.zeros((e, 2), device=device, dtype=torch.int64)
1285
+ self.s_strides2[:, 0] = k
1286
+
1287
+ self.group_size = group_size
1288
+ self._permute_scratch: MoEPermuteScratch | None = None
1289
+
1290
+ @staticmethod
1291
+ def activation_format() -> mk.FusedMoEActivationFormat:
1292
+ return mk.FusedMoEActivationFormat.Standard
1293
+
1294
+ @staticmethod
1295
+ def is_supported_config(
1296
+ cls: type[mk.FusedMoEExperts],
1297
+ moe_config: FusedMoEConfig,
1298
+ weight_key: QuantKey | None,
1299
+ activation_key: QuantKey | None,
1300
+ activation_format: mk.FusedMoEActivationFormat,
1301
+ ) -> tuple[bool, str | None]:
1302
+ if moe_config.in_dtype != torch.bfloat16:
1303
+ return (
1304
+ False,
1305
+ f"kernel does not support {moe_config.in_dtype} input/output dtype",
1306
+ )
1307
+
1308
+ return mk.FusedMoEExperts.is_supported_config(
1309
+ cls,
1310
+ moe_config,
1311
+ weight_key,
1312
+ activation_key,
1313
+ activation_format,
1314
+ )
1315
+
1316
+ @staticmethod
1317
+ def _supports_current_device() -> bool:
1318
+ return cutlass_group_gemm_supported()
1319
+
1320
+ @staticmethod
1321
+ def _supports_no_act_and_mul() -> bool:
1322
+ return False
1323
+
1324
+ @staticmethod
1325
+ def _supports_quant_scheme(
1326
+ weight_key: QuantKey | None,
1327
+ activation_key: QuantKey | None,
1328
+ ) -> bool:
1329
+ return (weight_key, activation_key) == (kInt4Static, kFp8DynamicTokenSym)
1330
+
1331
+ @staticmethod
1332
+ def _supports_activation(activation: MoEActivation) -> bool:
1333
+ return activation in (
1334
+ MoEActivation.SILU,
1335
+ MoEActivation.GELU,
1336
+ MoEActivation.SWIGLUOAI,
1337
+ )
1338
+
1339
+ @staticmethod
1340
+ def _supports_parallel_config(moe_parallel_config: FusedMoEParallelConfig) -> bool:
1341
+ return True
1342
+
1343
+ def finalize_weight_and_reduce_impl(self) -> mk.TopKWeightAndReduce:
1344
+ # topk weights and reduction are fused in moe_unpermute cuda kernel
1345
+ return TopKWeightAndReduceNoOP()
1346
+
1347
+ def workspace_dtype(self, act_dtype: torch.dtype) -> torch.dtype:
1348
+ return self.out_dtype if self.out_dtype is not None else act_dtype
1349
+
1350
+ def _get_permute_scratch(self) -> MoEPermuteScratch | None:
1351
+ if self._permute_scratch is None and moe_permute_unpermute_supported():
1352
+ self._permute_scratch = MoEPermuteScratch(
1353
+ max_num_tokens=self.moe_config.max_num_tokens,
1354
+ topk=self.moe_config.experts_per_token,
1355
+ num_experts=self.moe_config.num_experts,
1356
+ num_local_experts=self.moe_config.num_local_experts,
1357
+ device=torch.device(self.moe_config.device),
1358
+ )
1359
+ return self._permute_scratch
1360
+
1361
+ def workspace_shapes(
1362
+ self,
1363
+ M: int,
1364
+ N: int,
1365
+ K: int,
1366
+ topk: int,
1367
+ global_num_experts: int,
1368
+ local_num_experts: int,
1369
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
1370
+ activation: MoEActivation,
1371
+ ) -> tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...]]:
1372
+ activation_out_dim = self.adjust_N_for_activation(N, activation)
1373
+ workspace1 = (M * topk, max(N, K))
1374
+ workspace2 = (M * topk, max(activation_out_dim, K))
1375
+ output = (M, K)
1376
+ return (workspace1, workspace2, output)
1377
+
1378
+ def apply(
1379
+ self,
1380
+ output: torch.Tensor,
1381
+ hidden_states: torch.Tensor,
1382
+ w1: torch.Tensor,
1383
+ w2: torch.Tensor,
1384
+ topk_weights: torch.Tensor,
1385
+ topk_ids: torch.Tensor,
1386
+ activation: MoEActivation,
1387
+ global_num_experts: int,
1388
+ expert_map: torch.Tensor | None,
1389
+ a1q_scale: torch.Tensor | None,
1390
+ a2_scale: torch.Tensor | None,
1391
+ workspace13: torch.Tensor | None,
1392
+ workspace2: torch.Tensor | None,
1393
+ expert_tokens_meta: mk.ExpertTokensMetadata | None,
1394
+ apply_router_weight_on_input: bool,
1395
+ ):
1396
+ assert self.w1_zp is None, "w1_zp is not supported in CUTLASS MoE"
1397
+ assert self.w2_zp is None, "w2_zp is not supported in CUTLASS MoE"
1398
+
1399
+ expert_num_tokens = None
1400
+
1401
+ use_batched_format = (
1402
+ self.activation_format() == mk.FusedMoEActivationFormat.BatchedExperts
1403
+ )
1404
+ assert not use_batched_format, "batched format not supported"
1405
+
1406
+ in_dtype = hidden_states.dtype
1407
+
1408
+ run_cutlass_moe_w4a8_fp8(
1409
+ output,
1410
+ hidden_states,
1411
+ w1,
1412
+ w2,
1413
+ topk_ids,
1414
+ activation,
1415
+ global_num_experts,
1416
+ expert_map,
1417
+ self.w1_scale,
1418
+ self.w2_scale,
1419
+ a1q_scale,
1420
+ a2_scale,
1421
+ self.g1_alphas, # per-channel scales
1422
+ self.g2_alphas, # per-channel scales
1423
+ self.a_strides1,
1424
+ self.a_strides2,
1425
+ self.b_strides1,
1426
+ self.b_strides2,
1427
+ self.c_strides1,
1428
+ self.c_strides2,
1429
+ self.s_strides1,
1430
+ self.s_strides2,
1431
+ workspace13,
1432
+ workspace2,
1433
+ expert_num_tokens,
1434
+ self.out_dtype if self.out_dtype is not None else in_dtype,
1435
+ self.per_act_token_quant,
1436
+ self.per_out_ch_quant,
1437
+ use_batched_format,
1438
+ topk_weights,
1439
+ self.group_size,
1440
+ self._get_permute_scratch(),
1441
+ )