jedisct1 commited on
Commit
18e250c
·
verified ·
1 Parent(s): 441362f

Add model card, configuration, and oMLX support

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Qwen Community License 1.0
2
+
3
+ Copyright (c) 2026 Qwen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software, including the model weights, parameters, configuration files, inference code and associated documentation files (collectively, the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, sell, deploy, host, fine-tune, and create derivative works from (collectively, "Use" or "Using") copies of the Software; and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ 1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. If the Software (or any derivative works thereof) is Used for any of the licensee's commercial products or services that have more than 100,000,000 monthly active users or US$ 20,000,000 (or equivalent in other currencies) monthly revenue, respective model name must be prominently displayed on the user interface of such product or service; and,
8
+
9
+ 2. If the licensee or any of its affiliates conducts a Model as a Service or AI Work Assistant business, the licensee shall obtain a separate license from Qwen before Using the Software or its derivative works for any commercial purpose. The foregoing requirement shall not apply to the licensee's internal Use of the Software, provided that such Use does not make the Software, its outputs, or its underlying model capabilities available to any third party.
10
+
11
+ "Model as a Service" means giving a third party access to language model inference or fine-tuning (e.g., via API or a hosted endpoint) in a manner that allows such third parties to exercise meaningful control over the inputs, parameters, or training data. This does not include the mere relaying of requests to models hosted by other third parties.
12
+ “AI Work Assistant” means an independent AI-powered product primarily designed for AI-assisted coding or office productivity (e.g., Qoder and QwenWork). It does not include: (a) a single-purpose AI tool (such as an AI translation tool); (b) an AI assistant primarily designed for a domain other than coding or office productivity (such as Taobao AI Shopping Assistant or AMap AI Chat); or (c) an AI assistant that is a feature of a product whose primary purpose is not AI-assisted coding or office productivity.
13
+
14
+ THE SOFTWARE AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL QWEN, ITS AFFILIATES OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE USE OF THE SOFTWARE MUST COMPLY WITH APPLICABLE LAWS AND REGULATIONS, AND MUST NOT INFRINGE THE INTELLECTUAL PROPERTY RIGHTS OF ANY THIRD PARTY.
15
+
16
+ For any questions regarding this license, please contact model-business@notice.qwencloud.com.
README.md ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ base_model:
3
+ - Qwen/Qwen3.8-Flash-Next-FP8
4
+ base_model_relation: quantized
5
+ library_name: mlx
6
+ license: other
7
+ license_name: qwen-community-1.0
8
+ license_link: LICENSE
9
+ pipeline_tag: text-generation
10
+ tags:
11
+ - mlx
12
+ - safetensors
13
+ - qwen4_exp
14
+ - omlx
15
+ - oq
16
+ - quantized
17
+ - apple-silicon
18
+ - mixture-of-experts
19
+ - 4-bit
20
+ - long-context
21
+ - conversational
22
+ - tool-calling
23
+ - speculative-decoding
24
+ - mtp
25
+ ---
26
+
27
+ # Qwen3.8 Flash Next oQ4e MTP 128K for oMLX
28
+
29
+ This is a community, text-only dynamic quantization of [Qwen/Qwen3.8-Flash-Next-FP8](https://huggingface.co/Qwen/Qwen3.8-Flash-Next-FP8) for Apple Silicon and oMLX.
30
+
31
+ It is designed for a 131,072-token context window on a Mac with 128 GiB of unified memory. The conversion removes the vision encoder and retains the released one-layer Multi-Token Prediction head for depth-1 speculative decoding. It is not an official Qwen release.
32
+
33
+ ## Quantization
34
+
35
+ The model uses oMLX enhanced importance-matrix quantization with 4-bit affine, group-size 128 weights as the default. Precision is assigned by tensor family:
36
+
37
+ - The token embedding and language-model head use 4-bit affine quantization.
38
+ - Large linear and routed-expert weights use importance-matrix-guided mixed precision.
39
+ - Sensitive attention and shared-expert matrices retain higher precision, including 8-bit floors.
40
+ - Routers, recurrent state, convolutions, normalization, residual controls, and related control tensors retain BF16.
41
+ - The MTP head's 512 routed experts use importance-weighted 4-bit affine quantization at group size 128. Their three projections are stacked, avoiding 3,072 separate expert weight and scale arrays.
42
+ - MTP attention, shared-expert, and layer mixer matrices use 8-bit affine quantization. Fusion projections, the final mixer, routers, norms, gates, and injection controls retain BF16.
43
+ - The 51.2B-parameter PLE n-gram bank remains split into 128 shards. Shards 0 through 3 use 2-bit affine, group size 32. Shards 4 through 127 use 3-bit affine, group size 32.
44
+
45
+ The importance matrix was collected from 1,024 tool-heavy multilingual calibration samples at sequence length 512. The included `oq_imatrix_report.json` records the allocation inputs and coverage.
46
+
47
+ The MTP expert quantizer uses the calibrated activation importance of the analogous final backbone layer as a proxy. This preserves expert-specific weighting without claiming that the non-MTP calibration cache directly measured the draft head.
48
+
49
+ The resulting checkpoint contains 22 safetensors files and occupies 87.959 GiB. Its index contains 2,916 tensors, including 62 MTP tensors.
50
+
51
+ ## Runtime requirements
52
+
53
+ This checkpoint is not compatible with stock Transformers, stock MLX-LM, or an oMLX release without Qwen4 experimental support. The exact text model, cache integration, and mixed-bit SSD-backed PLE implementation used for validation are included under `omlx_support`.
54
+
55
+ The tested software stack is:
56
+
57
+ - Apple Silicon
58
+ - MLX and mlx-metal 0.32.1
59
+ - The MLX-LM package bundled with oMLX 0.6.3rc3
60
+ - oMLX 0.6.3rc3
61
+ - Depth-1 MTP enabled through oMLX's generic native-MTP scheduler
62
+
63
+ The Qwen4 implementation is based on [oMLX pull request #3161](https://github.com/jundot/omlx/pull/3161) at commit `79e11cf86360ca800db5bdc45cec4ee582ada6b1`, with an adaptation for this checkpoint's per-shard 2-bit and 3-bit PLE metadata. The MTP equations follow draft [pull request #3163](https://github.com/jundot/omlx/pull/3163) at commit `b115fa5d928c11acf4588a55814a307d9161baff`, adapted to the sparse 128K text path and oMLX's installed generic speculative scheduler.
64
+
65
+ Install the tested MLX runtime inside the downloaded model directory, then launch the bundled oMLX wrapper:
66
+
67
+ ```sh
68
+ hf download jedisct1/Qwen3.8-Flash-Next-oQ4e-MTP-128k \
69
+ --local-dir models/Qwen3.8-Flash-Next-oQ4e-MTP-128k
70
+ cd models/Qwen3.8-Flash-Next-oQ4e-MTP-128k
71
+ uv pip install --target .mlx-runtime mlx==0.32.1 mlx-metal==0.32.1
72
+ zsh omlx_support/serve
73
+ ```
74
+
75
+ The launcher expects oMLX at `/Applications/oMLX.app`, listens only on `127.0.0.1:8766`, and uses `omlx` as its default local API key. Set `OMLX_APP_RESOURCES`, `OMLX_API_KEY`, `OMLX_PORT`, `OMLX_CACHE_DIR`, or `OMLX_MLX_RUNTIME` to override those paths and values.
76
+
77
+ It installs the included model settings into a fresh oMLX base path, permits one concurrent request, selects oMLX's balanced memory guard, disables the in-memory hot cache, memory-maps the PLE safetensors, and uses an SSD prompt cache. MTP is fixed at depth 1. Prompt priming is capped at 8,192 tokens so a long request cannot retain a second full-context attention timeline. The context budget is total input plus generated output, so keep that total at or below 131,072 tokens.
78
+
79
+ ## Recommended generation settings
80
+
81
+ Thinking mode is enabled by default. The upstream recommended settings are included in `generation_config.json`:
82
+
83
+ ```text
84
+ temperature: 1.0
85
+ top_p: 0.95
86
+ top_k: 20
87
+ min_p: 0.0
88
+ presence_penalty: 0.0
89
+ repetition_penalty: 1.0
90
+ ```
91
+
92
+ For multi-turn agents, preserve `reasoning_content` between tool turns and keep `preserve_thinking` enabled.
93
+
94
+ ## Validation
95
+
96
+ The artifact validator and strict lazy load found:
97
+
98
+ - 22 expected and readable safetensors files
99
+ - 2,916 indexed and stored tensors, including 62 MTP tensors
100
+ - No missing, unindexed, duplicated, or misplaced tensors
101
+ - No remaining per-expert MTP tensors after stacking
102
+ - All 128 PLE mixed-bit overrides applied as intended
103
+ - No missing or mismatched importance-matrix entries for measurable modules
104
+
105
+ On an M5 Max with 128 GiB of unified memory, the SSD-backed PLE implementation loaded 64.65 GB of Metal-backed model arrays. A fresh request containing 131,071 uncached prompt tokens generated one token, for exactly 131,072 total tokens, in 873.41 seconds with oMLX's balanced memory guard enabled. The guard reclaimed 4.86 GB and 5.87 GB of pooled Metal buffers during prefill instead of weakening Apple's 107.52 GiB working-set ceiling.
106
+
107
+ Live depth-1 requests activated the MTP path. The direct structured-call check accepted 39 of 45 draft tokens, or 86.7 percent. Across the six-turn Swival workflow, per-turn acceptance ranged from 72.5 to 87.7 percent. Acceptance is prompt-dependent and is not a quality guarantee.
108
+
109
+ ## Tool calling
110
+
111
+ The original chat template and XML tool-call protocol are included. With MTP active, direct structured tool calls, continuation after a tool result, and a six-turn Swival file-write, checksum, read-back, and exact-byte comparison workflow were tested successfully. No identical tool invocation executed twice in that workflow.
112
+
113
+ Tool calling is stochastic and is not guaranteed to be flawless. Synthetic exact-call testing passed 17 of 18 cases with resident PLE and 16 of 18 cases with SSD-backed PLE. One failed response emitted duplicate calls. Agents should reject duplicate identical calls before execution, allow at most one bounded repair attempt, and fail closed if the repaired response remains invalid.
114
+
115
+ The dedicated MTP run passed 17 of 18 exact structured-call cases at the official thinking preset. The failed case emitted ordinary text claiming that it had called the requested tool but contained no structured call. The same case passed on an immediate isolated retry. MTP therefore matched the best prior non-MTP soak but did not eliminate the model's stochastic protocol failures.
116
+
117
+ The duplicate-call protection used during validation is implemented by Swival and is not part of these model weights.
118
+
119
+ ## Limitations
120
+
121
+ - This is a text-only conversion. Image and video inputs are unsupported.
122
+ - MTP requires the bundled Qwen4 compatibility hook and oMLX's native-MTP scheduler. Stock MLX-LM cannot use this head.
123
+ - Prompt priming is intentionally disabled for prompts above 8,192 tokens. Long prompts still run correctly but begin drafting without a primed head history.
124
+ - The architecture supports 262,144 native tokens, but this conversion was validated and operationally limited to 131,072 total tokens.
125
+ - Only the stated Apple Silicon and oMLX configuration was tested.
126
+ - Quantization can reduce quality relative to the FP8 source.
127
+ - Greedy MTP-on and MTP-off checks produced the same final JSON answer but not a bit-identical hidden reasoning sequence. Multi-token target verification can take numerically different matrix paths.
128
+ - The model can produce incorrect content, malformed tool calls, duplicate tool calls, or unsafe actions. Tool execution requires independent validation and appropriate permission boundaries.
129
+ - The model inherits the limitations and intended-use considerations of the upstream Qwen model.
130
+
131
+ ## Source and license
132
+
133
+ The conversion was produced from revision `bcd9f01ddc9cff2316eb84281bebcd5b058bddce` of [Qwen/Qwen3.8-Flash-Next-FP8](https://huggingface.co/Qwen/Qwen3.8-Flash-Next-FP8).
134
+
135
+ The weights remain subject to the Qwen Community License 1.0. Read `LICENSE` before using or redistributing the model, particularly its terms for commercial Model as a Service and AI Work Assistant businesses.
136
+
137
+ The bundled `omlx_support` code is distributed under the Apache License 2.0 in `omlx_support/LICENSE` and includes modifications to the implementations proposed in oMLX pull requests #3161 and #3163.
138
+
139
+ ## Citation
140
+
141
+ ```bibtex
142
+ @techreport{qwen2026design,
143
+ title = {On the Design of {Qwen3.8-Next} Architecture: Evaluation, Efficiency, and Training Stability},
144
+ author = {{Qwen Team}},
145
+ institution = {Alibaba Group},
146
+ month = {August},
147
+ year = {2026}
148
+ }
149
+
150
+ @misc{qwen3.8flashnext,
151
+ title = {{Qwen3.8-Flash-Next}: A New Architecture, Towards Ultimate Cost-Efficiency},
152
+ author = {{Qwen Team}},
153
+ month = {August},
154
+ year = {2026},
155
+ url = {https://qwen.ai/blog?id=qwen3.8-flash-next}
156
+ }
157
+ ```
chat_template.jinja ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- if not messages %}
43
+ {{- raise_exception('No messages provided.') }}
44
+ {%- endif %}
45
+ {%- set reasoning_instructions = '' %}
46
+ {%- if enable_thinking is undefined or enable_thinking is true %}
47
+ {%- set resolved_reasoning_effort = reasoning_effort|default('xhigh') %}
48
+ {%- if resolved_reasoning_effort not in ('xhigh', 'medium', 'low') %}
49
+ {{- raise_exception('Unexpected reasoning effort ' ~ reasoning_effort ~ '. Supported types are xhigh (default), medium, and low.') }}
50
+ {%- endif %}
51
+ {%- if resolved_reasoning_effort == 'xhigh' %}
52
+ {%- set reasoning_instructions = 'Reasoning effort is set to xhigh. Please think carefully through the task, validate key assumptions, consider plausible alternatives, and prioritize correctness, consistency, and clarity in the final answer.' %}
53
+ {%- elif resolved_reasoning_effort == 'low' %}
54
+ {%- set reasoning_instructions = 'Reasoning effort is set to low. Keep your thinking brief and focused, moving directly to the conclusion without unnecessary elaboration.' %}
55
+ {%- endif %}
56
+ {%- endif %}
57
+ {%- if tools and tools is iterable and tools is not mapping %}
58
+ {{- '<|im_start|>system\n' }}
59
+ {%- if reasoning_instructions %}
60
+ {{- reasoning_instructions + '\n\n' }}
61
+ {%- endif %}
62
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
63
+ {%- for tool in tools %}
64
+ {{- "\n" }}
65
+ {{- tool | tojson }}
66
+ {%- endfor %}
67
+ {{- "\n</tools>" }}
68
+ {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
69
+ {%- if messages[0].role == 'system' %}
70
+ {%- set content = render_content(messages[0].content, false, true)|trim %}
71
+ {%- if content %}
72
+ {{- '\n\n' + content }}
73
+ {%- endif %}
74
+ {%- endif %}
75
+ {{- '<|im_end|>\n' }}
76
+ {%- else %}
77
+ {%- if messages[0].role == 'system' %}
78
+ {%- set content = render_content(messages[0].content, false, true)|trim %}
79
+ {%- if content %}
80
+ {{- '<|im_start|>system\n' + (reasoning_instructions + '\n\n' if reasoning_instructions else '') + content + '<|im_end|>\n' }}
81
+ {%- elif reasoning_instructions %}
82
+ {{- '<|im_start|>system\n' + reasoning_instructions + '<|im_end|>\n' }}
83
+ {%- endif %}
84
+ {%- elif reasoning_instructions %}
85
+ {{- '<|im_start|>system\n' + reasoning_instructions + '<|im_end|>\n' }}
86
+ {%- endif %}
87
+ {%- endif %}
88
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
89
+ {%- for message in messages[::-1] %}
90
+ {%- set index = (messages|length - 1) - loop.index0 %}
91
+ {%- if ns.multi_step_tool and message.role == "user" %}
92
+ {%- set content = render_content(message.content, false)|trim %}
93
+ {%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}
94
+ {%- set ns.multi_step_tool = false %}
95
+ {%- set ns.last_query_index = index %}
96
+ {%- endif %}
97
+ {%- endif %}
98
+ {%- endfor %}
99
+ {%- if ns.multi_step_tool %}
100
+ {{- raise_exception('No user query found in messages.') }}
101
+ {%- endif %}
102
+ {%- for message in messages %}
103
+ {%- set content = render_content(message.content, true)|trim %}
104
+ {%- if message.role == "system" %}
105
+ {%- if not loop.first %}
106
+ {{- raise_exception('System message must be at the beginning.') }}
107
+ {%- endif %}
108
+ {%- elif message.role == "user" %}
109
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
110
+ {%- elif message.role == "assistant" %}
111
+ {%- set reasoning_content = '' %}
112
+ {%- if message.reasoning_content is string %}
113
+ {%- set reasoning_content = message.reasoning_content %}
114
+ {%- endif %}
115
+ {%- set reasoning_content = reasoning_content|trim %}
116
+ {%- if preserve_thinking is undefined or preserve_thinking is true or loop.index0 > ns.last_query_index %}
117
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
118
+ {%- else %}
119
+ {{- '<|im_start|>' + message.role + '\n' + content }}
120
+ {%- endif %}
121
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
122
+ {%- for tool_call in message.tool_calls %}
123
+ {%- if tool_call.function is defined %}
124
+ {%- set tool_call = tool_call.function %}
125
+ {%- endif %}
126
+ {%- if loop.first %}
127
+ {%- if content|trim %}
128
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
129
+ {%- else %}
130
+ {{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
131
+ {%- endif %}
132
+ {%- else %}
133
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
134
+ {%- endif %}
135
+ {%- if tool_call.arguments is defined and tool_call.arguments != '' %}
136
+ {%- for args_name, args_value in tool_call.arguments|items %}
137
+ {{- '<parameter=' + args_name + '>\n' }}
138
+ {%- set args_value = args_value | string if args_value is string else args_value | tojson | safe %}
139
+ {{- args_value }}
140
+ {{- '\n</parameter>\n' }}
141
+ {%- endfor %}
142
+ {%- endif %}
143
+ {{- '</function>\n</tool_call>' }}
144
+ {%- endfor %}
145
+ {%- endif %}
146
+ {{- '<|im_end|>\n' }}
147
+ {%- elif message.role == "tool" %}
148
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
149
+ {{- '<|im_start|>user' }}
150
+ {%- endif %}
151
+ {{- '\n<tool_response>\n' }}
152
+ {{- content }}
153
+ {{- '\n</tool_response>' }}
154
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
155
+ {{- '<|im_end|>\n' }}
156
+ {%- elif loop.last %}
157
+ {{- '<|im_end|>\n' }}
158
+ {%- endif %}
159
+ {%- else %}
160
+ {{- raise_exception('Unexpected message role.') }}
161
+ {%- endif %}
162
+ {%- endfor %}
163
+ {%- if add_generation_prompt %}
164
+ {{- '<|im_start|>assistant\n' }}
165
+ {%- if enable_thinking is defined and enable_thinking is false %}
166
+ {{- '<think>\n\n</think>\n\n' }}
167
+ {%- else %}
168
+ {{- '<think>\n' }}
169
+ {%- endif %}
170
+ {%- endif %}
config.json ADDED
The diff for this file is too large to render. See raw diff
 
generation_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 248044,
3
+ "do_sample": true,
4
+ "eos_token_id": [
5
+ 248046,
6
+ 248044
7
+ ],
8
+ "pad_token_id": 248044,
9
+ "temperature": 1.0,
10
+ "top_k": 20,
11
+ "top_p": 0.95
12
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors.index.json ADDED
The diff for this file is too large to render. See raw diff
 
omlx_support/LICENSE ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to the Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by the Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding any notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2025 oMLX contributors
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
omlx_support/model_settings.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": 1,
3
+ "models": {
4
+ "Qwen3.8-Flash-Next-oQ4e-MTP-128k": {
5
+ "max_context_window": 131072,
6
+ "max_tokens": 32768,
7
+ "temperature": 1.0,
8
+ "top_p": 0.95,
9
+ "top_k": 20,
10
+ "min_p": 0.0,
11
+ "repetition_penalty": 1.0,
12
+ "presence_penalty": 0.0,
13
+ "force_sampling": true,
14
+ "chat_template_kwargs": {
15
+ "enable_thinking": true,
16
+ "preserve_thinking": true
17
+ },
18
+ "forced_ct_kwargs": [
19
+ "enable_thinking",
20
+ "preserve_thinking"
21
+ ],
22
+ "model_type_override": "llm",
23
+ "enable_thinking": true,
24
+ "preserve_thinking": true,
25
+ "reasoning_parser": "qwen",
26
+ "turboquant_kv_enabled": false,
27
+ "qwen35_ane_prefill_enabled": false,
28
+ "specprefill_enabled": false,
29
+ "dflash_enabled": false,
30
+ "mtp_enabled": true,
31
+ "mtp_num_draft_tokens": 1,
32
+ "vlm_mtp_enabled": false,
33
+ "is_pinned": false,
34
+ "is_default": true,
35
+ "trust_remote_code": false,
36
+ "display_name": "Qwen3.8 Flash Next oQ4e MTP 128k",
37
+ "description": "Text-only tool-use profile with depth-1 MTP and bounded prompt priming."
38
+ }
39
+ }
40
+ }
omlx_support/qwen4_cache_integration.py ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Qwen4 cache integration for oMLX.
2
+ # Licensed under the Apache License 2.0. See LICENSE.
3
+
4
+ from enum import Enum
5
+ from typing import Any
6
+
7
+ import mlx.core as mx
8
+
9
+ from omlx.cache.type_handlers import (
10
+ CacheStateAxisInfo,
11
+ CacheTypeHandler,
12
+ )
13
+ from omlx.cache.type_registry import CacheTypeRegistry
14
+
15
+
16
+ class Qwen4CacheType(Enum):
17
+ QSA_KV = "QSAKVCache"
18
+ QSA_QUANTIZED_KV = "QSAQuantizedKVCache"
19
+
20
+
21
+ def _offset_from_meta(meta_state, fallback):
22
+ if isinstance(meta_state, (list, tuple)) and meta_state:
23
+ return int(meta_state[0])
24
+ if meta_state not in (None, ""):
25
+ return int(meta_state)
26
+ return fallback
27
+
28
+
29
+ class QSAKVCacheHandler(CacheTypeHandler):
30
+ @property
31
+ def cache_type(self):
32
+ return Qwen4CacheType.QSA_KV
33
+
34
+ @property
35
+ def supports_block_slicing(self):
36
+ return True
37
+
38
+ def get_state_axis_info(self):
39
+ return (
40
+ CacheStateAxisInfo("keys", 2, True),
41
+ CacheStateAxisInfo("values", 2, True),
42
+ CacheStateAxisInfo("index_keys", 1, True),
43
+ )
44
+
45
+ def serialize_state(self, cache_obj):
46
+ keys, values, index_keys = cache_obj.state
47
+ return keys, values, index_keys
48
+
49
+ def serialize_meta_state(self, cache_obj):
50
+ return (int(cache_obj.offset),)
51
+
52
+ def extract_state(self, cache_obj):
53
+ elements = self.serialize_state(cache_obj)
54
+ return {
55
+ "keys": elements[0],
56
+ "values": elements[1],
57
+ "index_keys": elements[2],
58
+ "states": elements,
59
+ "cache_type": self.cache_type.value,
60
+ }
61
+
62
+ def get_seq_len(self, state):
63
+ keys = state.get("keys")
64
+ if keys is not None:
65
+ return int(keys.shape[2])
66
+ index_keys = state.get("index_keys")
67
+ return 0 if index_keys is None else int(index_keys.shape[1])
68
+
69
+ def slice_state(self, state, start_idx, end_idx):
70
+ keys = state.get("keys")
71
+ values = state.get("values")
72
+ index_keys = state.get("index_keys")
73
+ if keys is None or values is None:
74
+ return None
75
+ end_idx = min(end_idx, int(keys.shape[2]))
76
+ if start_idx >= end_idx:
77
+ return None
78
+ index_end = min(end_idx, int(index_keys.shape[1]))
79
+ elements = (
80
+ keys[:, :, start_idx:end_idx, :],
81
+ values[:, :, start_idx:end_idx, :],
82
+ index_keys[:, start_idx:index_end, :],
83
+ )
84
+ return {
85
+ "keys": elements[0],
86
+ "values": elements[1],
87
+ "index_keys": elements[2],
88
+ "states": elements,
89
+ "cache_type": self.cache_type.value,
90
+ }
91
+
92
+ def concatenate_states(self, states):
93
+ elements = [state.get("states") for state in states]
94
+ elements = [value for value in elements if value]
95
+ if not elements:
96
+ return {}
97
+ combined = (
98
+ mx.concatenate([value[0] for value in elements], axis=2),
99
+ mx.concatenate([value[1] for value in elements], axis=2),
100
+ mx.concatenate([value[2] for value in elements], axis=1),
101
+ )
102
+ return {
103
+ "keys": combined[0],
104
+ "values": combined[1],
105
+ "index_keys": combined[2],
106
+ "states": combined,
107
+ "cache_type": self.cache_type.value,
108
+ }
109
+
110
+ def deserialize_state(self, elements, meta_state=None):
111
+ from mlx_lm.models.qwen4_exp import QSAKVCache
112
+
113
+ keys = elements[0] if len(elements) > 0 else None
114
+ values = elements[1] if len(elements) > 1 else None
115
+ index_keys = elements[2] if len(elements) > 2 else None
116
+ fallback = 0 if keys is None else int(keys.shape[2])
117
+ cache = QSAKVCache()
118
+ cache.keys = keys
119
+ cache.values = values
120
+ cache.index_keys = index_keys
121
+ cache.offset = _offset_from_meta(meta_state, fallback)
122
+ return cache
123
+
124
+ def reconstruct_cache(self, state, meta_state=None):
125
+ elements = state.get("states")
126
+ if elements is None:
127
+ elements = (
128
+ state.get("keys"),
129
+ state.get("values"),
130
+ state.get("index_keys"),
131
+ )
132
+ return self.deserialize_state(tuple(elements), meta_state)
133
+
134
+
135
+ class QSAQuantizedKVCacheHandler(CacheTypeHandler):
136
+ @property
137
+ def cache_type(self):
138
+ return Qwen4CacheType.QSA_QUANTIZED_KV
139
+
140
+ @property
141
+ def supports_block_slicing(self):
142
+ return True
143
+
144
+ def get_state_axis_info(self):
145
+ return (
146
+ CacheStateAxisInfo("key_weight", 2, True),
147
+ CacheStateAxisInfo("key_scales", 2, True),
148
+ CacheStateAxisInfo("key_biases", 2, True),
149
+ CacheStateAxisInfo("value_weight", 2, True),
150
+ CacheStateAxisInfo("value_scales", 2, True),
151
+ CacheStateAxisInfo("value_biases", 2, True),
152
+ CacheStateAxisInfo("index_keys", 1, True),
153
+ )
154
+
155
+ def serialize_state(self, cache_obj):
156
+ if cache_obj.keys is None:
157
+ return (None,) * 7
158
+ offset = int(cache_obj.offset)
159
+ keys = tuple(value[:, :, :offset, :] for value in cache_obj.keys)
160
+ values = tuple(value[:, :, :offset, :] for value in cache_obj.values)
161
+ index_keys = cache_obj.index_keys
162
+ if index_keys is not None:
163
+ index_keys = index_keys[:, :offset, :]
164
+ return (*keys, *values, index_keys)
165
+
166
+ def serialize_meta_state(self, cache_obj):
167
+ return (
168
+ int(cache_obj.offset),
169
+ int(cache_obj.group_size),
170
+ int(cache_obj.bits),
171
+ )
172
+
173
+ def extract_state(self, cache_obj):
174
+ elements = self.serialize_state(cache_obj)
175
+ return {
176
+ "states": elements,
177
+ "keys": elements[0],
178
+ "values": elements[3],
179
+ "index_keys": elements[6],
180
+ "cache_type": self.cache_type.value,
181
+ }
182
+
183
+ def get_seq_len(self, state):
184
+ keys = state.get("keys")
185
+ if keys is not None:
186
+ return int(keys.shape[2])
187
+ index_keys = state.get("index_keys")
188
+ return 0 if index_keys is None else int(index_keys.shape[1])
189
+
190
+ def slice_state(self, state, start_idx, end_idx):
191
+ elements = state.get("states")
192
+ if not elements or elements[0] is None:
193
+ return None
194
+ end_idx = min(end_idx, int(elements[0].shape[2]))
195
+ if start_idx >= end_idx:
196
+ return None
197
+ sliced = tuple(
198
+ value[:, :, start_idx:end_idx, :] for value in elements[:6]
199
+ ) + (elements[6][:, start_idx:end_idx, :],)
200
+ return {
201
+ "states": sliced,
202
+ "keys": sliced[0],
203
+ "values": sliced[3],
204
+ "index_keys": sliced[6],
205
+ "cache_type": self.cache_type.value,
206
+ }
207
+
208
+ def concatenate_states(self, states):
209
+ elements = [state.get("states") for state in states]
210
+ elements = [value for value in elements if value and value[0] is not None]
211
+ if not elements:
212
+ return {}
213
+ combined = tuple(
214
+ mx.concatenate([value[index] for value in elements], axis=2)
215
+ for index in range(6)
216
+ ) + (mx.concatenate([value[6] for value in elements], axis=1),)
217
+ return {
218
+ "states": combined,
219
+ "keys": combined[0],
220
+ "values": combined[3],
221
+ "index_keys": combined[6],
222
+ "cache_type": self.cache_type.value,
223
+ }
224
+
225
+ def deserialize_state(self, elements, meta_state=None):
226
+ from mlx_lm.models.qwen4_exp import QSAQuantizedKVCache
227
+
228
+ offset = _offset_from_meta(
229
+ meta_state,
230
+ 0 if not elements or elements[0] is None else int(elements[0].shape[2]),
231
+ )
232
+ group_size = int(meta_state[1]) if meta_state and len(meta_state) > 1 else 64
233
+ bits = int(meta_state[2]) if meta_state and len(meta_state) > 2 else 4
234
+ cache = QSAQuantizedKVCache(group_size=group_size, bits=bits)
235
+ if elements and elements[0] is not None:
236
+ cache.keys = tuple(elements[:3])
237
+ cache.values = tuple(elements[3:6])
238
+ cache.index_keys = elements[6] if len(elements) > 6 else None
239
+ cache.offset = offset
240
+ return cache
241
+
242
+ def reconstruct_cache(self, state, meta_state=None):
243
+ return self.deserialize_state(tuple(state.get("states") or ()), meta_state)
244
+
245
+
246
+ def _batch_indices(batch_indices):
247
+ if hasattr(batch_indices, "tolist"):
248
+ return [int(value) for value in batch_indices.tolist()]
249
+ return [int(value) for value in batch_indices]
250
+
251
+
252
+ def _install_single_cache_batch_methods(cache_class):
253
+ def filter_rows(self, batch_indices):
254
+ indices = _batch_indices(batch_indices)
255
+ if not indices:
256
+ self.keys = None
257
+ self.values = None
258
+ self.index_keys = None
259
+ self.offset = 0
260
+ return
261
+ self.keys = _map_cache_arrays(self.keys, lambda value: value[indices])
262
+ self.values = _map_cache_arrays(self.values, lambda value: value[indices])
263
+ if self.index_keys is not None:
264
+ self.index_keys = self.index_keys[indices]
265
+
266
+ def extract_row(self, index):
267
+ result = type(self).__new__(type(self))
268
+ result.keys = _map_cache_arrays(self.keys, lambda value: value[index : index + 1])
269
+ result.values = _map_cache_arrays(self.values, lambda value: value[index : index + 1])
270
+ result.index_keys = (
271
+ None
272
+ if self.index_keys is None
273
+ else self.index_keys[index : index + 1]
274
+ )
275
+ result.offset = self.offset
276
+ if hasattr(self, "group_size"):
277
+ result.group_size = self.group_size
278
+ result.bits = self.bits
279
+ return result
280
+
281
+ def extend_rows(self, other):
282
+ if int(self.offset) != int(other.offset):
283
+ raise ValueError("QSA caches can only batch rows at the same offset")
284
+ if hasattr(self, "group_size") and (
285
+ self.group_size != other.group_size or self.bits != other.bits
286
+ ):
287
+ raise ValueError("quantized QSA caches must use the same layout")
288
+ offset = int(self.offset)
289
+ self.keys = _merge_cache_arrays(self.keys, other.keys, offset, 2)
290
+ self.values = _merge_cache_arrays(self.values, other.values, offset, 2)
291
+ self.index_keys = _merge_cache_arrays(
292
+ self.index_keys,
293
+ other.index_keys,
294
+ offset,
295
+ 1,
296
+ )
297
+
298
+ @classmethod
299
+ def merge_rows(cls, caches):
300
+ caches = list(caches)
301
+ if not caches:
302
+ return cls()
303
+ result = caches[0].extract(0)
304
+ for cache in caches[1:]:
305
+ result.extend(cache)
306
+ return result
307
+
308
+ cache_class.filter = filter_rows
309
+ cache_class.extract = extract_row
310
+ cache_class.extend = extend_rows
311
+ cache_class.merge = merge_rows
312
+
313
+
314
+ def _install_quantized_state_layout(cache_class):
315
+ def get_state(self):
316
+ if self.keys is None:
317
+ return (None,) * 7
318
+ offset = int(self.offset)
319
+ keys = tuple(value[:, :, :offset, :] for value in self.keys)
320
+ values = tuple(value[:, :, :offset, :] for value in self.values)
321
+ index_keys = self.index_keys
322
+ if index_keys is not None:
323
+ index_keys = index_keys[:, :offset, :]
324
+ return (*keys, *values, index_keys)
325
+
326
+ def set_state(self, value):
327
+ if len(value) == 2 and isinstance(value[0], (list, tuple)):
328
+ quantized_state, self.index_keys = value
329
+ self.keys, self.values = quantized_state
330
+ else:
331
+ self.keys = tuple(value[:3]) if value and value[0] is not None else None
332
+ self.values = tuple(value[3:6]) if value and value[3] is not None else None
333
+ self.index_keys = value[6] if len(value) > 6 else None
334
+ self.offset = 0 if self.keys is None else int(self.keys[0].shape[2])
335
+
336
+ cache_class.state = property(get_state, set_state)
337
+
338
+
339
+ def _map_cache_arrays(value, function):
340
+ if value is None:
341
+ return None
342
+ if isinstance(value, (list, tuple)):
343
+ return tuple(function(item) for item in value)
344
+ return function(value)
345
+
346
+
347
+ def _merge_cache_arrays(left, right, length, sequence_axis):
348
+ if left is None:
349
+ return right
350
+ if right is None:
351
+ return left
352
+ if isinstance(left, (list, tuple)):
353
+ return tuple(
354
+ _merge_cache_arrays(a, b, length, sequence_axis)
355
+ for a, b in zip(left, right)
356
+ )
357
+ slices = [slice(None)] * left.ndim
358
+ slices[sequence_axis] = slice(0, length)
359
+ slices = tuple(slices)
360
+ return mx.concatenate([left[slices], right[slices]], axis=0)
361
+
362
+
363
+ def register_qwen4_cache_integration():
364
+ import mlx_lm.models.cache as mlx_cache
365
+
366
+ from mlx_lm.models.qwen4_exp import QSAKVCache, QSAQuantizedKVCache
367
+
368
+ handlers = (QSAKVCacheHandler(), QSAQuantizedKVCacheHandler())
369
+ for handler in handlers:
370
+ CacheTypeRegistry.register(handler)
371
+ CacheTypeRegistry._class_name_map.update(
372
+ {
373
+ QSAKVCache.__name__: Qwen4CacheType.QSA_KV,
374
+ QSAQuantizedKVCache.__name__: Qwen4CacheType.QSA_QUANTIZED_KV,
375
+ }
376
+ )
377
+ _install_single_cache_batch_methods(QSAKVCache)
378
+ _install_single_cache_batch_methods(QSAQuantizedKVCache)
379
+ _install_quantized_state_layout(QSAQuantizedKVCache)
380
+ mlx_cache.QSAKVCache = QSAKVCache
381
+ mlx_cache.QSAQuantizedKVCache = QSAQuantizedKVCache
omlx_support/qwen4_exp.py ADDED
@@ -0,0 +1,1361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import logging
5
+ import math
6
+ import mmap
7
+ import os
8
+ import struct
9
+ from copy import copy
10
+ from dataclasses import dataclass, field
11
+ from pathlib import Path
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ import mlx.core as mx
15
+ import mlx.nn as nn
16
+ import numpy as np
17
+
18
+ from mlx_lm.models.activations import swiglu
19
+ from mlx_lm.models.base import BaseModelArgs, create_ssm_mask
20
+ from mlx_lm.models.cache import ArraysCache, KVCache, QuantizedKVCache
21
+ from mlx_lm.models.gated_delta import gated_delta_update
22
+ from mlx_lm.models.switch_layers import SwitchGLU
23
+
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ @dataclass
29
+ class ModelArgs(BaseModelArgs):
30
+ model_type: str = "qwen4_exp"
31
+ vocab_size: int = 248320
32
+ hidden_size: int = 2048
33
+ num_hidden_layers: int = 40
34
+ mtp_num_hidden_layers: int = 0
35
+ num_attention_heads: int = 16
36
+ num_key_value_heads: int = 2
37
+ hidden_act: str = "silu"
38
+ max_position_embeddings: int = 32768
39
+ rms_norm_eps: float = 1e-6
40
+ tie_word_embeddings: bool = False
41
+ attention_bias: bool = False
42
+ attention_dropout: float = 0.0
43
+ head_dim: int = 256
44
+ linear_conv_kernel_dim: int = 4
45
+ linear_key_head_dim: int = 128
46
+ linear_value_head_dim: int = 128
47
+ linear_num_key_heads: int = 16
48
+ linear_num_value_heads: int = 32
49
+ moe_intermediate_size: int = 512
50
+ shared_expert_intermediate_size: int = 512
51
+ num_experts_per_tok: int = 10
52
+ num_experts: int = 512
53
+ layer_types: List[str] = field(default_factory=list)
54
+ hc_count: int = 4
55
+ hc_lowrank: int = 320
56
+ ple_layer_ids: List[int] = field(default_factory=list)
57
+ ple_embed_dim: Optional[int] = None
58
+ ple_conv_kernel_size: int = 4
59
+ ngram_size: int = 3
60
+ heads_per_ngram: int = 8
61
+ ngram_vocab_size_base: int = 20_000_000
62
+ make_ngram_vocab_size_divisible_by: int = 128
63
+ seed: int = 1234
64
+ split_ngram_parts: int = 512
65
+ indexer_n_heads: Optional[int] = None
66
+ indexer_kv_heads: Optional[int] = None
67
+ indexer_head_dim: Optional[int] = None
68
+ indexer_budget: Optional[int] = None
69
+ indexer_compress_ratio: Optional[int] = None
70
+ norm_topk_prob: bool = True
71
+ output_gate_type: Optional[str] = None
72
+ eos_token_id: Optional[int | List[int]] = None
73
+ rope_theta: float = 10000.0
74
+ partial_rotary_factor: float = 1.0
75
+ rope_parameters: Optional[Dict[str, Any]] = None
76
+
77
+ @classmethod
78
+ def from_dict(cls, params):
79
+ source = dict(params.get("text_config", params))
80
+ source["model_type"] = params.get("model_type", source.get("model_type", "qwen4_exp"))
81
+ if params.get("eos_token_id") is not None:
82
+ source["eos_token_id"] = params["eos_token_id"]
83
+ rope = source.get("rope_parameters") or {}
84
+ source.setdefault("rope_theta", rope.get("rope_theta", 10000.0))
85
+ source.setdefault("partial_rotary_factor", rope.get("partial_rotary_factor", 1.0))
86
+ return super().from_dict(source)
87
+
88
+ def __post_init__(self):
89
+ if self.ple_embed_dim is None:
90
+ self.ple_embed_dim = self.hidden_size
91
+ if not self.layer_types:
92
+ self.layer_types = [
93
+ "linear_attention" if (i + 1) % 4 else "full_attention"
94
+ for i in range(self.num_hidden_layers)
95
+ ]
96
+ if len(self.layer_types) != self.num_hidden_layers:
97
+ raise ValueError("layer_types must contain one entry per hidden layer")
98
+ if self.hc_count <= 1:
99
+ raise ValueError("hc_count must be greater than one")
100
+ if self.linear_num_value_heads % self.linear_num_key_heads:
101
+ raise ValueError("linear value heads must be divisible by key heads")
102
+ if not 0 < self.num_experts_per_tok <= self.num_experts:
103
+ raise ValueError("num_experts_per_tok must select existing experts")
104
+ if any(layer < 1 or layer > self.num_hidden_layers for layer in self.ple_layer_ids):
105
+ raise ValueError("PLE layer ids are one-indexed hidden-layer ids")
106
+ if self.ple_layer_ids and self.eos_token_id is None:
107
+ raise ValueError("PLE requires eos_token_id")
108
+ qsa = (
109
+ self.indexer_n_heads,
110
+ self.indexer_kv_heads,
111
+ self.indexer_head_dim,
112
+ self.indexer_budget,
113
+ self.indexer_compress_ratio,
114
+ )
115
+ if any(value is None for value in qsa):
116
+ raise ValueError("QSA requires every indexer field")
117
+ if self.indexer_kv_heads != 1:
118
+ raise ValueError("QSA requires one indexer key head")
119
+ if self.indexer_budget % self.indexer_compress_ratio:
120
+ raise ValueError("indexer_budget must divide into complete compressed blocks")
121
+ ngram_heads = (self.ngram_size - 1) * self.heads_per_ngram
122
+ if self.ple_layer_ids and self.ple_embed_dim % ngram_heads:
123
+ raise ValueError("ple_embed_dim must be divisible by its n-gram heads")
124
+
125
+
126
+ class Qwen4RMSNorm(nn.Module):
127
+ def __init__(self, dim: int, eps: float, group_size: Optional[int] = None):
128
+ super().__init__()
129
+ self.weight = mx.zeros(dim)
130
+ self.eps = eps
131
+ self.group_size = group_size
132
+
133
+ def __call__(self, x):
134
+ dtype = x.dtype
135
+ value = x.astype(mx.float32)
136
+ if self.group_size is not None:
137
+ value = value.reshape(*value.shape[:-1], -1, self.group_size)
138
+ value = value * mx.rsqrt(mx.mean(mx.square(value), axis=-1, keepdims=True) + self.eps)
139
+ if self.group_size is not None:
140
+ value = value.reshape(*x.shape)
141
+ return (value * (1.0 + self.weight.astype(mx.float32))).astype(dtype)
142
+
143
+
144
+ class Qwen4RMSNormGated(nn.Module):
145
+ def __init__(self, dim: int, eps: float, activation: str):
146
+ super().__init__()
147
+ self.weight = mx.ones(dim)
148
+ self.eps = eps
149
+ self.activation = activation
150
+
151
+ def __call__(self, x, gate):
152
+ dtype = x.dtype
153
+ value = mx.fast.rms_norm(x, self.weight, self.eps)
154
+ gate = gate.astype(mx.float32)
155
+ gate = mx.sigmoid(gate) if self.activation == "sigmoid" else nn.silu(gate)
156
+ return (value.astype(mx.float32) * gate).astype(dtype)
157
+
158
+
159
+ def _l2_normalize(x, eps=1e-6):
160
+ return x * mx.rsqrt(mx.sum(x * x, axis=-1, keepdims=True) + eps)
161
+
162
+
163
+ def _apply_rope(x, positions, rotary_dim: int, theta: float):
164
+ if rotary_dim == 0:
165
+ return x
166
+ dtype = x.dtype
167
+ inv_freq = theta ** (-mx.arange(0, rotary_dim, 2, dtype=mx.float32) / rotary_dim)
168
+ angles = positions.astype(mx.float32)[..., None] * inv_freq
169
+ cos = mx.concatenate([mx.cos(angles), mx.cos(angles)], axis=-1)
170
+ sin = mx.concatenate([mx.sin(angles), mx.sin(angles)], axis=-1)
171
+ while cos.ndim < x.ndim:
172
+ cos = mx.expand_dims(cos, axis=-2)
173
+ sin = mx.expand_dims(sin, axis=-2)
174
+ rotated, remainder = x[..., :rotary_dim], x[..., rotary_dim:]
175
+ first, second = mx.split(rotated, 2, axis=-1)
176
+ rotated = rotated * cos + mx.concatenate([-second, first], axis=-1) * sin
177
+ return mx.concatenate([rotated, remainder], axis=-1).astype(dtype)
178
+
179
+
180
+ class QSAKVCache(KVCache):
181
+ def __init__(self):
182
+ super().__init__()
183
+ self.index_keys = None
184
+
185
+ def update_indexer(self, keys):
186
+ previous = self.offset
187
+ length = keys.shape[1]
188
+ end = previous + length
189
+ if self.index_keys is None or end > self.index_keys.shape[1]:
190
+ batch, _, head_dim = keys.shape
191
+ steps = (self.step + length - 1) // self.step
192
+ extension = mx.zeros(
193
+ (batch, steps * self.step, head_dim),
194
+ dtype=keys.dtype,
195
+ )
196
+ if self.index_keys is None:
197
+ self.index_keys = extension
198
+ else:
199
+ if previous % self.step:
200
+ self.index_keys = self.index_keys[:, :previous, :]
201
+ self.index_keys = mx.concatenate([self.index_keys, extension], axis=1)
202
+ self.index_keys[:, previous:end, :] = keys
203
+ return self.index_keys[:, :end, :]
204
+
205
+ @property
206
+ def state(self):
207
+ index_state = (
208
+ self.index_keys
209
+ if self.index_keys is None
210
+ else self.index_keys[:, : self.offset, :]
211
+ )
212
+ if self.keys is None:
213
+ return self.keys, self.values, index_state
214
+ return (
215
+ self.keys[..., : self.offset, :],
216
+ self.values[..., : self.offset, :],
217
+ index_state,
218
+ )
219
+
220
+ @state.setter
221
+ def state(self, value):
222
+ self.keys, self.values, self.index_keys = value
223
+ self.offset = 0 if self.keys is None else self.keys.shape[2]
224
+
225
+ def trim(self, count):
226
+ return super().trim(count)
227
+
228
+ def to_quantized(self, group_size=64, bits=4):
229
+ cache = QSAQuantizedKVCache(group_size=group_size, bits=bits)
230
+ cache.offset = self.offset
231
+ cache.index_keys = self.index_keys
232
+ if self.keys is not None:
233
+ cache.keys = mx.quantize(self.keys[..., : self.offset, :], group_size=group_size, bits=bits)
234
+ cache.values = mx.quantize(self.values[..., : self.offset, :], group_size=group_size, bits=bits)
235
+ return cache
236
+
237
+ @property
238
+ def nbytes(self):
239
+ size = super().nbytes
240
+ return size + (0 if self.index_keys is None else self.index_keys.nbytes)
241
+
242
+
243
+ class QSAQuantizedKVCache(QuantizedKVCache):
244
+ def __init__(self, group_size=64, bits=4):
245
+ super().__init__(group_size=group_size, bits=bits)
246
+ self.index_keys = None
247
+
248
+ def update_indexer(self, keys):
249
+ previous = self.offset
250
+ length = keys.shape[1]
251
+ end = previous + length
252
+ if self.index_keys is None or end > self.index_keys.shape[1]:
253
+ batch, _, head_dim = keys.shape
254
+ steps = (self.step + length - 1) // self.step
255
+ extension = mx.zeros(
256
+ (batch, steps * self.step, head_dim),
257
+ dtype=keys.dtype,
258
+ )
259
+ if self.index_keys is None:
260
+ self.index_keys = extension
261
+ else:
262
+ if previous % self.step:
263
+ self.index_keys = self.index_keys[:, :previous, :]
264
+ self.index_keys = mx.concatenate([self.index_keys, extension], axis=1)
265
+ self.index_keys[:, previous:end, :] = keys
266
+ return self.index_keys[:, :end, :]
267
+
268
+ @property
269
+ def state(self):
270
+ quantized_state = (self.keys, self.values) if self.keys is None else super().state
271
+ index_state = (
272
+ self.index_keys
273
+ if self.index_keys is None
274
+ else self.index_keys[:, : self.offset, :]
275
+ )
276
+ return quantized_state, index_state
277
+
278
+ @state.setter
279
+ def state(self, value):
280
+ quantized_state, self.index_keys = value
281
+ QuantizedKVCache.state.fset(self, quantized_state)
282
+ self.offset = 0 if self.keys is None else self.keys[0].shape[2]
283
+
284
+ def trim(self, count):
285
+ return super().trim(count)
286
+
287
+ def to_quantized(self, group_size=64, bits=4):
288
+ if group_size == self.group_size and bits == self.bits:
289
+ return self
290
+ raise ValueError("QSA KV cache is already quantized")
291
+
292
+ @property
293
+ def nbytes(self):
294
+ size = super().nbytes
295
+ return size + (0 if self.index_keys is None else self.index_keys.nbytes)
296
+
297
+
298
+ class Qwen4GatedDeltaNet(nn.Module):
299
+ def __init__(self, args: ModelArgs):
300
+ super().__init__()
301
+ self.num_v_heads = args.linear_num_value_heads
302
+ self.num_k_heads = args.linear_num_key_heads
303
+ self.head_k_dim = args.linear_key_head_dim
304
+ self.head_v_dim = args.linear_value_head_dim
305
+ self.key_dim = self.num_k_heads * self.head_k_dim
306
+ self.value_dim = self.num_v_heads * self.head_v_dim
307
+ self.conv_kernel_size = args.linear_conv_kernel_dim
308
+ self.conv_dim = 2 * self.key_dim + self.value_dim
309
+ self.conv1d = nn.Conv1d(
310
+ self.conv_dim,
311
+ self.conv_dim,
312
+ self.conv_kernel_size,
313
+ groups=self.conv_dim,
314
+ bias=False,
315
+ )
316
+ self.in_proj_qkv = nn.Linear(args.hidden_size, self.conv_dim, bias=False)
317
+ self.in_proj_z = nn.Linear(args.hidden_size, self.value_dim, bias=False)
318
+ self.in_proj_b = nn.Linear(args.hidden_size, self.num_v_heads, bias=False)
319
+ self.in_proj_a = nn.Linear(args.hidden_size, self.num_v_heads, bias=False)
320
+ self.dt_bias = mx.ones(self.num_v_heads)
321
+ self.A_log = mx.log(mx.random.uniform(low=0.01, high=16.0, shape=(self.num_v_heads,)))
322
+ self.norm = Qwen4RMSNormGated(
323
+ self.head_v_dim,
324
+ args.rms_norm_eps,
325
+ args.output_gate_type or args.hidden_act,
326
+ )
327
+ self.out_proj = nn.Linear(self.value_dim, args.hidden_size, bias=False)
328
+
329
+ def _process_chunk(self, mixed, a, b, conv_state, state, mask=None):
330
+ batch, length = mixed.shape[:2]
331
+ conv_input = mx.concatenate([conv_state, mixed], axis=1)
332
+ next_conv_state = mx.contiguous(
333
+ conv_input[:, -(self.conv_kernel_size - 1) :, :]
334
+ )
335
+ mixed = nn.silu(self.conv1d(conv_input))
336
+ q, k, value = mx.split(mixed, [self.key_dim, 2 * self.key_dim], axis=-1)
337
+ q = q.reshape(batch, length, self.num_k_heads, self.head_k_dim)
338
+ k = k.reshape(batch, length, self.num_k_heads, self.head_k_dim)
339
+ value = value.reshape(batch, length, self.num_v_heads, self.head_v_dim)
340
+ q = _l2_normalize(q) * (self.head_k_dim**-0.5)
341
+ k = _l2_normalize(k)
342
+ output, state = gated_delta_update(
343
+ q,
344
+ k,
345
+ value,
346
+ a.astype(mx.float32),
347
+ b,
348
+ self.A_log,
349
+ self.dt_bias,
350
+ state,
351
+ mask,
352
+ use_kernel=not self.training,
353
+ )
354
+ return output, next_conv_state, state
355
+
356
+ def __call__(self, x, mask=None, cache=None, n_confirmed=0):
357
+ batch, length, _ = x.shape
358
+ mixed = self.in_proj_qkv(x)
359
+ z = self.in_proj_z(x).reshape(batch, length, self.num_v_heads, self.head_v_dim)
360
+ b = self.in_proj_b(x)
361
+ a = self.in_proj_a(x)
362
+ if mask is not None:
363
+ mixed = mx.where(mask[..., None], mixed, 0)
364
+ if cache is not None and cache[0] is not None:
365
+ conv_state = cache[0]
366
+ else:
367
+ conv_state = mx.zeros((batch, self.conv_kernel_size - 1, self.conv_dim), dtype=x.dtype)
368
+ state = None if cache is None else cache[1]
369
+ output, next_conv_state, next_state = self._process_chunk(
370
+ mixed,
371
+ a,
372
+ b,
373
+ conv_state,
374
+ state,
375
+ mask,
376
+ )
377
+ if cache is not None:
378
+ cache[0] = next_conv_state
379
+ cache[1] = next_state
380
+ if 0 < n_confirmed < length:
381
+ cache.rollback_state = (conv_state, state)
382
+ cache._mtp_draft_stash = (mixed, a, b, mask)
383
+ cache.advance(length)
384
+ output = self.norm(output, z).reshape(batch, length, -1)
385
+ return self.out_proj(output)
386
+
387
+
388
+ class Qwen4QSAIndexer(nn.Module):
389
+ def __init__(self, args: ModelArgs):
390
+ super().__init__()
391
+ self.n_heads = args.indexer_n_heads
392
+ self.head_dim = args.indexer_head_dim
393
+ self.budget = args.indexer_budget
394
+ self.compress_ratio = args.indexer_compress_ratio
395
+ self.block_topk = self.budget // self.compress_ratio
396
+ self.rotary_dim = int(args.head_dim * args.partial_rotary_factor)
397
+ self.rope_theta = args.rope_theta
398
+ self.index_qk_proj = nn.Linear(
399
+ args.hidden_size,
400
+ (args.indexer_n_heads + args.indexer_kv_heads) * args.indexer_head_dim,
401
+ bias=False,
402
+ )
403
+ self.q_layernorm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
404
+ self.k_layernorm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
405
+
406
+ def __call__(self, hidden_states, cache, offset):
407
+ batch, length, _ = hidden_states.shape
408
+ qk = self.index_qk_proj(hidden_states)
409
+ split = self.n_heads * self.head_dim
410
+ query, raw_keys = mx.split(qk, [split], axis=-1)
411
+ query = self.q_layernorm(query.reshape(batch, length, self.n_heads, self.head_dim))
412
+ raw_keys = raw_keys.reshape(batch, length, self.head_dim)
413
+ raw_keys = cache.update_indexer(raw_keys) if cache is not None else raw_keys
414
+ positions = offset + mx.arange(length)
415
+ query = _apply_rope(query, positions[None], self.rotary_dim, self.rope_theta)
416
+ return query, raw_keys, positions
417
+
418
+ def select(self, query, raw_keys, positions):
419
+ batch, length, _, _ = query.shape
420
+ key_length = raw_keys.shape[1]
421
+ ratio = self.compress_ratio
422
+ block_count = key_length // ratio
423
+ selected_parts = []
424
+ valid_parts = []
425
+ if block_count:
426
+ pooled = raw_keys[:, : block_count * ratio].reshape(
427
+ batch, block_count, ratio, self.head_dim
428
+ ).mean(axis=2)
429
+ pooled = self.k_layernorm(pooled)
430
+ block_positions = mx.arange(block_count) * ratio
431
+ pooled = _apply_rope(
432
+ pooled,
433
+ block_positions[None],
434
+ self.rotary_dim,
435
+ self.rope_theta,
436
+ )
437
+ scores = mx.einsum(
438
+ "blhd,bkd->blhk",
439
+ query.astype(mx.float32),
440
+ pooled.astype(mx.float32),
441
+ )
442
+ scores = mx.sum(mx.maximum(scores, 0), axis=2) / math.sqrt(self.head_dim)
443
+ complete = (positions + 1) // ratio
444
+ block_valid = mx.arange(block_count)[None, None, :] < complete[None, :, None]
445
+ scores = mx.where(block_valid, scores, mx.finfo(scores.dtype).min)
446
+ take = min(self.block_topk, block_count)
447
+ if take == block_count:
448
+ selected_blocks = mx.broadcast_to(
449
+ mx.arange(block_count)[None, None, :],
450
+ (batch, length, block_count),
451
+ )
452
+ else:
453
+ selected_blocks = mx.argpartition(scores, kth=block_count - take, axis=-1)[..., -take:]
454
+ chosen_valid = mx.take_along_axis(block_valid, selected_blocks, axis=-1)
455
+ selected_parts.append(
456
+ (selected_blocks[..., None] * ratio + mx.arange(ratio)).reshape(batch, length, -1)
457
+ )
458
+ valid_parts.append(
459
+ mx.broadcast_to(chosen_valid[..., None], (*chosen_valid.shape, ratio)).reshape(batch, length, -1)
460
+ )
461
+ tail_width = max(ratio - 1, 1)
462
+ tail_start = ((positions + 1) // ratio) * ratio
463
+ tail = tail_start[:, None] + mx.arange(tail_width)[None]
464
+ tail_valid = tail <= positions[:, None]
465
+ selected_parts.append(mx.broadcast_to(tail[None], (batch, length, tail_width)))
466
+ valid_parts.append(mx.broadcast_to(tail_valid[None], (batch, length, tail_width)))
467
+ return mx.concatenate(selected_parts, axis=-1), mx.concatenate(valid_parts, axis=-1)
468
+
469
+
470
+ class Qwen4Attention(nn.Module):
471
+ def __init__(self, args: ModelArgs):
472
+ super().__init__()
473
+ self.num_heads = args.num_attention_heads
474
+ self.num_kv_heads = args.num_key_value_heads
475
+ self.head_dim = args.head_dim
476
+ self.repeats = self.num_heads // self.num_kv_heads
477
+ self.scale = self.head_dim**-0.5
478
+ self.rotary_dim = int(self.head_dim * args.partial_rotary_factor)
479
+ self.rope_theta = args.rope_theta
480
+ self.q_proj = nn.Linear(args.hidden_size, self.num_heads * self.head_dim * 2, bias=args.attention_bias)
481
+ self.k_proj = nn.Linear(args.hidden_size, self.num_kv_heads * self.head_dim, bias=args.attention_bias)
482
+ self.v_proj = nn.Linear(args.hidden_size, self.num_kv_heads * self.head_dim, bias=args.attention_bias)
483
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, args.hidden_size, bias=args.attention_bias)
484
+ self.q_norm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
485
+ self.k_norm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
486
+ self.indexer = Qwen4QSAIndexer(args)
487
+
488
+ def _select_cache_rows(self, values, batch_index, indices, cache):
489
+ if not isinstance(values, (list, tuple)):
490
+ return values[batch_index, :, indices, :].transpose(2, 0, 1, 3)
491
+ parts = [value[batch_index, :, indices, :].transpose(2, 0, 1, 3) for value in values]
492
+ return mx.dequantize(
493
+ parts[0],
494
+ parts[1],
495
+ parts[2],
496
+ group_size=cache.group_size,
497
+ bits=cache.bits,
498
+ )
499
+
500
+ def _sparse_attention(self, query, keys, values, selected, valid, cache):
501
+ outputs = []
502
+ for batch_index in range(query.shape[0]):
503
+ grouped_query = query[batch_index].reshape(
504
+ self.num_kv_heads, self.repeats, query.shape[2], self.head_dim
505
+ )
506
+ chunks = []
507
+ for start in range(0, query.shape[2], 64):
508
+ end = min(start + 64, query.shape[2])
509
+ key_length = (
510
+ keys[0].shape[2]
511
+ if isinstance(keys, (list, tuple))
512
+ else keys.shape[2]
513
+ )
514
+ indices = mx.clip(
515
+ selected[batch_index, start:end],
516
+ 0,
517
+ key_length - 1,
518
+ )
519
+ selected_keys = self._select_cache_rows(keys, batch_index, indices, cache)
520
+ selected_values = self._select_cache_rows(values, batch_index, indices, cache)
521
+ local_query = grouped_query[:, :, start:end]
522
+ scores = mx.einsum("hrld,hlmd->hrlm", local_query, selected_keys) * self.scale
523
+ scores = mx.where(valid[batch_index, start:end][None, None], scores, mx.finfo(scores.dtype).min)
524
+ probabilities = mx.softmax(scores, axis=-1, precise=True)
525
+ output = mx.einsum("hrlm,hlmd->hrld", probabilities, selected_values)
526
+ mx.eval(output)
527
+ chunks.append(output)
528
+ output = mx.concatenate(chunks, axis=2)
529
+ outputs.append(output.reshape(self.num_heads, query.shape[2], self.head_dim)[None])
530
+ return mx.concatenate(outputs, axis=0)
531
+
532
+ def __call__(self, x, cache=None):
533
+ batch, length, _ = x.shape
534
+ offset = 0 if cache is None else cache.offset
535
+ projected = self.q_proj(x).reshape(batch, length, self.num_heads, 2 * self.head_dim)
536
+ query, gate = mx.split(projected, 2, axis=-1)
537
+ gate = gate.reshape(batch, length, -1)
538
+ keys = self.k_proj(x).reshape(batch, length, self.num_kv_heads, self.head_dim)
539
+ values = self.v_proj(x).reshape(batch, length, self.num_kv_heads, self.head_dim)
540
+ positions = offset + mx.arange(length)
541
+ query = _apply_rope(self.q_norm(query), positions[None], self.rotary_dim, self.rope_theta)
542
+ keys = _apply_rope(self.k_norm(keys), positions[None], self.rotary_dim, self.rope_theta)
543
+ query = query.transpose(0, 2, 1, 3)
544
+ keys = keys.transpose(0, 2, 1, 3)
545
+ values = values.transpose(0, 2, 1, 3)
546
+ index_query, raw_keys, _ = self.indexer(x, cache, offset)
547
+ if cache is not None:
548
+ keys, values = cache.update_and_fetch(keys, values)
549
+ selected, valid = self.indexer.select(index_query, raw_keys, positions)
550
+ output = self._sparse_attention(query, keys, values, selected, valid, cache)
551
+ output = output.transpose(0, 2, 1, 3).reshape(batch, length, -1)
552
+ return self.o_proj(output * mx.sigmoid(gate))
553
+
554
+
555
+ class Qwen4MLP(nn.Module):
556
+ def __init__(self, dim, hidden_dim):
557
+ super().__init__()
558
+ self.gate_proj = nn.Linear(dim, hidden_dim, bias=False)
559
+ self.up_proj = nn.Linear(dim, hidden_dim, bias=False)
560
+ self.down_proj = nn.Linear(hidden_dim, dim, bias=False)
561
+
562
+ def __call__(self, x):
563
+ return self.down_proj(swiglu(self.gate_proj(x), self.up_proj(x)))
564
+
565
+
566
+ class Qwen4SparseMoeBlock(nn.Module):
567
+ def __init__(self, args: ModelArgs):
568
+ super().__init__()
569
+ self.top_k = args.num_experts_per_tok
570
+ self.norm_topk_prob = args.norm_topk_prob
571
+ self.gate = nn.Linear(args.hidden_size, args.num_experts, bias=False)
572
+ self.switch_mlp = SwitchGLU(args.hidden_size, args.moe_intermediate_size, args.num_experts)
573
+ self.shared_expert = Qwen4MLP(args.hidden_size, args.shared_expert_intermediate_size)
574
+ self.shared_expert_gate = nn.Linear(args.hidden_size, 1, bias=False)
575
+
576
+ def _routing_weights(self, router_logits):
577
+ gates = mx.softmax(router_logits.astype(mx.float32), axis=-1, precise=True)
578
+ indices = mx.argpartition(gates, kth=-self.top_k, axis=-1)[..., -self.top_k :]
579
+ scores = mx.take_along_axis(gates, indices, axis=-1)
580
+ if self.norm_topk_prob:
581
+ scores = scores / mx.sum(scores, axis=-1, keepdims=True)
582
+ return scores.astype(router_logits.dtype), indices
583
+
584
+ def __call__(self, x):
585
+ scores, indices = self._routing_weights(self.gate(x))
586
+ routed = mx.sum(self.switch_mlp(x, indices) * scores[..., None], axis=-2)
587
+ shared = mx.sigmoid(self.shared_expert_gate(x)) * self.shared_expert(x)
588
+ return routed + shared
589
+
590
+
591
+ class Qwen4GatedResidual(nn.Module):
592
+ def __init__(self, args: ModelArgs, combine=True):
593
+ super().__init__()
594
+ self.hc_count = args.hc_count
595
+ self.hidden_size = args.hidden_size
596
+ total = self.hc_count * self.hidden_size
597
+ self.hc_norm = Qwen4RMSNorm(total, args.rms_norm_eps, group_size=self.hidden_size)
598
+ self.input_mix_weight_down = nn.Linear(total, args.hc_lowrank, bias=False)
599
+ self.input_mix_weight_up = nn.Linear(args.hc_lowrank, total, bias=False)
600
+ self.block_inject_weight = nn.Linear(total, self.hc_count, bias=False) if combine else None
601
+
602
+ def __call__(self, x):
603
+ normalized = self.hc_norm(x)
604
+ weights = nn.silu(self.input_mix_weight_down(normalized) / self.hc_count)
605
+ weights = mx.sigmoid(self.input_mix_weight_up(weights)).reshape(
606
+ *x.shape[:-1], self.hc_count, self.hidden_size
607
+ )
608
+ mixed = mx.mean(
609
+ weights * normalized.reshape(*x.shape[:-1], self.hc_count, self.hidden_size),
610
+ axis=-2,
611
+ )
612
+ if self.block_inject_weight is None:
613
+ return mixed
614
+ injection = 2 * mx.sigmoid(self.block_inject_weight(normalized) / self.hc_count)
615
+ return mixed, x, injection
616
+
617
+
618
+ _MASK64 = (1 << 64) - 1
619
+ _SPLITMIX_GAMMA = 0x9E3779B97F4A7C15
620
+ _SPLITMIX_M1 = 0xBF58476D1CE4E5B9
621
+ _SPLITMIX_M2 = 0x94D049BB133111EB
622
+
623
+
624
+ def _splitmix64(value):
625
+ value = (value + _SPLITMIX_GAMMA) & _MASK64
626
+ value = ((value ^ (value >> 30)) * _SPLITMIX_M1) & _MASK64
627
+ value = ((value ^ (value >> 27)) * _SPLITMIX_M2) & _MASK64
628
+ return (value ^ (value >> 31)) & _MASK64
629
+
630
+
631
+ def _multipliers(vocab_size, ngram_size, layer_index, seed):
632
+ maximum = ((1 << 63) - 1) // max(vocab_size, 1)
633
+ bound = max(1, maximum // 2)
634
+ base = seed + 10007 * layer_index
635
+ return [
636
+ 2 * (_splitmix64((base + _SPLITMIX_GAMMA * (index + 1)) & _MASK64) % bound) + 1
637
+ for index in range(ngram_size)
638
+ ]
639
+
640
+
641
+ def _is_prime(value):
642
+ if value < 2:
643
+ return False
644
+ if value % 2 == 0:
645
+ return value == 2
646
+ return all(value % divisor for divisor in range(3, math.isqrt(value) + 1, 2))
647
+
648
+
649
+ def _nth_prime_after(start, count):
650
+ value = start
651
+ for _ in range(count):
652
+ value += 1
653
+ while not _is_prime(value):
654
+ value += 1
655
+ return value
656
+
657
+
658
+ class Qwen4NGramEmbedding(nn.Module):
659
+ def __init__(self, args: ModelArgs, layer_index: int, model_layer_index=None):
660
+ super().__init__()
661
+ self.ngram_size = args.ngram_size
662
+ self.context_len = self.ngram_size - 1
663
+ self.heads_per_ngram = args.heads_per_ngram
664
+ self.ngram_heads = self.context_len * self.heads_per_ngram
665
+ self.eos_token_id = args.eos_token_id[0] if isinstance(args.eos_token_id, list) else args.eos_token_id
666
+ sizes = [
667
+ _nth_prime_after(args.ngram_vocab_size_base - 1, head + 1)
668
+ for head in range(self.ngram_heads)
669
+ ]
670
+ offsets = []
671
+ total = 0
672
+ for size in sizes:
673
+ offsets.append(total)
674
+ total += size
675
+ padded = math.ceil(total / args.make_ngram_vocab_size_divisible_by) * args.make_ngram_vocab_size_divisible_by
676
+ self.layer_multipliers = mx.array(
677
+ _multipliers(args.vocab_size, self.ngram_size, layer_index, args.seed),
678
+ dtype=mx.int64,
679
+ )
680
+ self.ngram_heads_vocab_sizes = mx.array(sizes, dtype=mx.int64)
681
+ self.ngram_heads_offsets = mx.array(offsets, dtype=mx.int64)
682
+ model_path = os.environ.get("OMLX_QWEN4_PLE_MODEL_PATH")
683
+ mode = os.environ.get("OMLX_QWEN4_PLE_MODE", "resident")
684
+ embedding_args = (
685
+ padded,
686
+ args.ple_embed_dim // self.ngram_heads,
687
+ args.split_ngram_parts,
688
+ )
689
+ if mode == "mmap":
690
+ if model_path is None or model_layer_index is None:
691
+ raise RuntimeError("SSD-backed PLE requires its model path and decoder layer index")
692
+ prefix = f"model.layers.{model_layer_index}.ple.ple_embedding.ngram_embedding"
693
+ self.ngram_embedding = DiskBackedShardedEmbedding(
694
+ model_path,
695
+ prefix,
696
+ *embedding_args,
697
+ )
698
+ elif mode == "resident":
699
+ self.ngram_embedding = ShardedEmbedding(*embedding_args)
700
+ else:
701
+ raise ValueError("OMLX_QWEN4_PLE_MODE must be resident or mmap")
702
+
703
+ def _shift(self, tokens, shift):
704
+ if shift == 0:
705
+ return tokens
706
+ batch, length = tokens.shape
707
+ positions = mx.arange(length)
708
+ eos_positions = mx.where(tokens == self.eos_token_id, positions[None], -1)
709
+ inclusive = mx.cummax(eos_positions, axis=1)
710
+ previous = mx.concatenate([mx.full((batch, 1), -1, dtype=mx.int64), inclusive[:, :-1]], axis=1)
711
+ source = positions - shift
712
+ gathered = tokens[:, mx.maximum(source, 0)]
713
+ valid = (positions[None] - previous - 1 >= shift) & (source[None] >= 0)
714
+ return mx.where(valid, gathered, self.eos_token_id)
715
+
716
+ def __call__(self, input_ids, cache=None):
717
+ input_ids = input_ids.astype(mx.int64)
718
+ if cache is not None and cache[3] is not None:
719
+ previous = cache[3]
720
+ else:
721
+ previous = mx.full((input_ids.shape[0], self.context_len), self.eos_token_id, dtype=mx.int64)
722
+ history = mx.concatenate([previous, input_ids], axis=1)
723
+ if cache is not None:
724
+ cache[3] = mx.contiguous(history[:, -self.context_len :])
725
+ shifted = [self._shift(history, shift) for shift in range(self.ngram_size)]
726
+ blocks = []
727
+ for ngram in range(2, self.ngram_size + 1):
728
+ start = (ngram - 2) * self.heads_per_ngram
729
+ end = start + self.heads_per_ngram
730
+ mixed = shifted[0] * self.layer_multipliers[0]
731
+ for position in range(1, ngram):
732
+ mixed = mx.bitwise_xor(mixed, shifted[position] * self.layer_multipliers[position])
733
+ ids = mixed[..., None] % self.ngram_heads_vocab_sizes[start:end]
734
+ blocks.append(ids + self.ngram_heads_offsets[start:end])
735
+ ids = mx.concatenate(blocks, axis=-1)[:, -input_ids.shape[1] :]
736
+ return self.ngram_embedding(ids).reshape(input_ids.shape[0], input_ids.shape[1], -1)
737
+
738
+
739
+ class ShardedEmbedding(nn.Module):
740
+ def __init__(self, num_embeddings, dims, shard_count):
741
+ super().__init__()
742
+ if num_embeddings % shard_count:
743
+ raise ValueError("the padded n-gram vocabulary must divide evenly into shards")
744
+ self.shard_size = num_embeddings // shard_count
745
+ self.dims = dims
746
+ self.shards = [nn.Embedding(self.shard_size, dims) for _ in range(shard_count)]
747
+
748
+ def __call__(self, ids):
749
+ shape = ids.shape
750
+ flat_ids = ids.reshape(-1)
751
+ if flat_ids.size == 0:
752
+ return self.shards[0](flat_ids).reshape(*shape, self.dims)
753
+ shard_ids = flat_ids // self.shard_size
754
+ local_ids = flat_ids % self.shard_size
755
+ mx.eval(shard_ids)
756
+ host_shards = shard_ids.tolist()
757
+ output = None
758
+ for shard_index in sorted(set(host_shards)):
759
+ positions = mx.array(
760
+ [index for index, value in enumerate(host_shards) if value == shard_index],
761
+ dtype=mx.int32,
762
+ )
763
+ values = self.shards[shard_index](local_ids[positions])
764
+ if output is None:
765
+ output = mx.zeros((flat_ids.size, self.dims), dtype=values.dtype)
766
+ output[positions] = values
767
+ mx.eval(output)
768
+ return output.reshape(*shape, self.dims)
769
+
770
+
771
+ _SAFETENSORS_NUMPY_DTYPES = {
772
+ "U32": np.dtype("<u4"),
773
+ "I32": np.dtype("<i4"),
774
+ "I64": np.dtype("<i8"),
775
+ "F16": np.dtype("<f2"),
776
+ "F32": np.dtype("<f4"),
777
+ "BF16": np.dtype("<u2"),
778
+ }
779
+
780
+
781
+ class _SafeTensorMMap:
782
+ def __init__(self, path):
783
+ self.path = Path(path)
784
+ self._file = self.path.open("rb")
785
+ raw_header_length = self._file.read(8)
786
+ if len(raw_header_length) != 8:
787
+ self.close()
788
+ raise ValueError(f"Invalid safetensors header in {self.path}")
789
+ header_length = struct.unpack("<Q", raw_header_length)[0]
790
+ raw_header = self._file.read(header_length)
791
+ if len(raw_header) != header_length:
792
+ self.close()
793
+ raise ValueError(f"Truncated safetensors header in {self.path}")
794
+ self._header = json.loads(raw_header)
795
+ self._data_start = 8 + header_length
796
+ self._mapping = mmap.mmap(self._file.fileno(), length=0, access=mmap.ACCESS_READ)
797
+ try:
798
+ self._mapping.madvise(mmap.MADV_RANDOM)
799
+ except (AttributeError, OSError):
800
+ pass
801
+
802
+ def tensor_shape(self, key):
803
+ try:
804
+ return tuple(self._header[key]["shape"])
805
+ except KeyError as exc:
806
+ raise KeyError(f"Tensor {key!r} is missing from {self.path}") from exc
807
+
808
+ def rows(self, key, row_indices):
809
+ try:
810
+ entry = self._header[key]
811
+ except KeyError as exc:
812
+ raise KeyError(f"Tensor {key!r} is missing from {self.path}") from exc
813
+ dtype_name = entry["dtype"]
814
+ try:
815
+ dtype = _SAFETENSORS_NUMPY_DTYPES[dtype_name]
816
+ except KeyError as exc:
817
+ raise TypeError(f"Unsupported safetensors dtype {dtype_name!r} for {key}") from exc
818
+ shape = tuple(entry["shape"])
819
+ if len(shape) != 2:
820
+ raise ValueError(f"Sparse PLE tensor {key!r} must be two-dimensional")
821
+ start, end = entry["data_offsets"]
822
+ if end - start != math.prod(shape) * dtype.itemsize:
823
+ raise ValueError(f"Invalid byte range for safetensors tensor {key!r}")
824
+ view = np.ndarray(
825
+ shape,
826
+ dtype=dtype,
827
+ buffer=self._mapping,
828
+ offset=self._data_start + start,
829
+ )
830
+ copied = np.array(view[np.asarray(row_indices, dtype=np.intp)], copy=True)
831
+ if dtype_name == "BF16":
832
+ copied = (copied.astype(np.uint32) << np.uint32(16)).view(np.float32)
833
+ return copied, dtype_name
834
+
835
+ def close(self):
836
+ mapping = getattr(self, "_mapping", None)
837
+ if mapping is not None:
838
+ mapping.close()
839
+ self._mapping = None
840
+ file_object = getattr(self, "_file", None)
841
+ if file_object is not None:
842
+ file_object.close()
843
+ self._file = None
844
+
845
+ def __del__(self):
846
+ try:
847
+ self.close()
848
+ except Exception:
849
+ pass
850
+
851
+
852
+ class DiskBackedShardedEmbedding(nn.Module):
853
+ def __init__(self, model_path, prefix, num_embeddings, dims, shard_count):
854
+ super().__init__()
855
+ if num_embeddings % shard_count:
856
+ raise ValueError("the padded n-gram vocabulary must divide evenly into shards")
857
+ self.shard_size = num_embeddings // shard_count
858
+ self.dims = dims
859
+ self.shard_count = shard_count
860
+ self.last_touched_shards = ()
861
+ self.rows_read = 0
862
+ self._prefix = prefix
863
+ self._readers = {}
864
+ self._tensor_readers = {}
865
+ self._shard_quantization = []
866
+
867
+ model_path = Path(model_path)
868
+ index_path = model_path / "model.safetensors.index.json"
869
+ config_path = model_path / "config.json"
870
+ if not index_path.exists() or not config_path.exists():
871
+ raise FileNotFoundError("SSD-backed PLE requires config.json and a safetensors index")
872
+ weight_map = json.loads(index_path.read_text()).get("weight_map", {})
873
+ quantization = json.loads(config_path.read_text()).get("quantization") or {}
874
+ default = {
875
+ "bits": int(quantization.get("bits", 4)),
876
+ "group_size": int(quantization.get("group_size", 64)),
877
+ "mode": quantization.get("mode", "affine"),
878
+ }
879
+ for shard_index in range(shard_count):
880
+ module_key = f"{prefix}.shards.{shard_index}"
881
+ settings = dict(default)
882
+ settings.update(quantization.get(module_key) or {})
883
+ bits = int(settings["bits"])
884
+ group_size = int(settings["group_size"])
885
+ mode = settings["mode"]
886
+ if mode != "affine":
887
+ raise ValueError("SSD-backed PLE supports affine quantization")
888
+ if dims % group_size or (dims * bits) % 32:
889
+ raise ValueError(f"Invalid PLE quantization for {module_key}")
890
+ self._shard_quantization.append((group_size, bits, mode))
891
+ expected_shapes = {
892
+ "weight": (self.shard_size, dims * bits // 32),
893
+ "scales": (self.shard_size, dims // group_size),
894
+ "biases": (self.shard_size, dims // group_size),
895
+ }
896
+ for suffix, expected_shape in expected_shapes.items():
897
+ key = f"{module_key}.{suffix}"
898
+ try:
899
+ filename = weight_map[key]
900
+ except KeyError as exc:
901
+ raise KeyError(f"SSD-backed PLE tensor {key!r} is absent from the index") from exc
902
+ reader = self._readers.get(filename)
903
+ if reader is None:
904
+ reader = _SafeTensorMMap(model_path / filename)
905
+ self._readers[filename] = reader
906
+ if reader.tensor_shape(key) != expected_shape:
907
+ raise ValueError(
908
+ f"Unexpected shape for {key}: {reader.tensor_shape(key)} != {expected_shape}"
909
+ )
910
+ self._tensor_readers[key] = reader
911
+
912
+ def _read_rows(self, key, row_indices):
913
+ array, dtype_name = self._tensor_readers[key].rows(key, row_indices)
914
+ self.rows_read += len(row_indices)
915
+ result = mx.array(array)
916
+ return result.astype(mx.bfloat16) if dtype_name == "BF16" else result
917
+
918
+ def __call__(self, ids):
919
+ shape = ids.shape
920
+ flat_ids = ids.reshape(-1).astype(mx.int64)
921
+ mx.eval(flat_ids)
922
+ host_ids = [int(value) for value in flat_ids.tolist()]
923
+ if any(value < 0 or value >= self.shard_size * self.shard_count for value in host_ids):
924
+ raise IndexError("n-gram embedding id is outside the padded vocabulary")
925
+ touched = tuple(sorted({value // self.shard_size for value in host_ids}))
926
+ self.last_touched_shards = touched
927
+ self.rows_read = 0
928
+ output = None
929
+ for shard_index in touched:
930
+ positions_list = [
931
+ index for index, value in enumerate(host_ids) if value // self.shard_size == shard_index
932
+ ]
933
+ local_ids = [host_ids[index] % self.shard_size for index in positions_list]
934
+ base = f"{self._prefix}.shards.{shard_index}"
935
+ weight = self._read_rows(f"{base}.weight", local_ids)
936
+ scales = self._read_rows(f"{base}.scales", local_ids)
937
+ biases = self._read_rows(f"{base}.biases", local_ids)
938
+ group_size, bits, mode = self._shard_quantization[shard_index]
939
+ values = mx.dequantize(
940
+ weight,
941
+ scales=scales,
942
+ biases=biases,
943
+ group_size=group_size,
944
+ bits=bits,
945
+ mode=mode,
946
+ )
947
+ if output is None:
948
+ output = mx.zeros((len(host_ids), self.dims), dtype=values.dtype)
949
+ output[mx.array(positions_list, dtype=mx.int32)] = values
950
+ if output is None:
951
+ output = mx.zeros((0, self.dims), dtype=mx.bfloat16)
952
+ mx.eval(output)
953
+ return output.reshape(*shape, self.dims)
954
+
955
+
956
+ class Qwen4PLELayer(nn.Module):
957
+ def __init__(self, args: ModelArgs, ple_index: int, model_layer_index: int):
958
+ super().__init__()
959
+ total = args.hc_count * args.hidden_size
960
+ self.hc_count = args.hc_count
961
+ self.hidden_size = args.hidden_size
962
+ self.ple_embedding = Qwen4NGramEmbedding(args, ple_index, model_layer_index)
963
+ self.key_proj = nn.Linear(args.ple_embed_dim, total, bias=False)
964
+ self.value_proj = nn.Linear(args.ple_embed_dim, args.hidden_size, bias=False)
965
+ self.norm_key = Qwen4RMSNorm(total, args.rms_norm_eps, args.hidden_size)
966
+ self.norm_query = Qwen4RMSNorm(total, args.rms_norm_eps, args.hidden_size)
967
+ self.norm_conv = Qwen4RMSNorm(total, args.rms_norm_eps, args.hidden_size)
968
+ self.state_len = (args.ple_conv_kernel_size - 1) * args.ngram_size
969
+ self.conv1d = nn.Conv1d(
970
+ total,
971
+ total,
972
+ args.ple_conv_kernel_size,
973
+ dilation=args.ngram_size,
974
+ groups=total,
975
+ bias=False,
976
+ )
977
+
978
+ def __call__(self, x, input_ids, cache=None, mask=None):
979
+ embeddings = self.ple_embedding(input_ids, cache)
980
+ key = self.norm_key(self.key_proj(embeddings)).reshape(*x.shape[:-1], self.hc_count, self.hidden_size)
981
+ value = self.value_proj(embeddings)
982
+ query = self.norm_query(x).reshape(*x.shape[:-1], self.hc_count, self.hidden_size)
983
+ gate = mx.sum(key * query, axis=-1, keepdims=True) / math.sqrt(self.hidden_size)
984
+ gate = mx.sign(gate) * mx.sqrt(mx.maximum(mx.abs(gate), 1e-6))
985
+ gated = (mx.sigmoid(gate) * value[..., None, :]).reshape(*x.shape)
986
+ normalized = self.norm_conv(gated)
987
+ if mask is not None:
988
+ gated = mx.where(mask[..., None], gated, 0)
989
+ normalized = mx.where(mask[..., None], normalized, 0)
990
+ if cache is not None and cache[2] is not None:
991
+ state = cache[2]
992
+ else:
993
+ state = mx.zeros((x.shape[0], self.state_len, x.shape[-1]), dtype=x.dtype)
994
+ conv_input = mx.concatenate([state, normalized], axis=1)
995
+ if cache is not None:
996
+ cache[2] = mx.contiguous(conv_input[:, -self.state_len :, :])
997
+ return gated + nn.silu(self.conv1d(conv_input))
998
+
999
+
1000
+ class Qwen4DecoderLayer(nn.Module):
1001
+ def __init__(self, args: ModelArgs, index: int):
1002
+ super().__init__()
1003
+ self.is_linear = args.layer_types[index] == "linear_attention"
1004
+ if self.is_linear:
1005
+ self.linear_attn = Qwen4GatedDeltaNet(args)
1006
+ else:
1007
+ self.self_attn = Qwen4Attention(args)
1008
+ self.mlp = Qwen4SparseMoeBlock(args)
1009
+ one_indexed = index + 1
1010
+ self.ple = Qwen4PLELayer(args, args.ple_layer_ids.index(one_indexed), index) if one_indexed in args.ple_layer_ids else None
1011
+ self.attn_hyper_connection = Qwen4GatedResidual(args)
1012
+ self.mlp_hyper_connection = Qwen4GatedResidual(args)
1013
+
1014
+ def __call__(self, x, input_ids, mask=None, cache=None, n_confirmed=0):
1015
+ if self.ple is not None:
1016
+ x = x + self.ple(x, input_ids, cache, mask)
1017
+ mixed, residual, injection = self.attn_hyper_connection(x)
1018
+ output = (
1019
+ self.linear_attn(mixed, mask, cache, n_confirmed=n_confirmed)
1020
+ if self.is_linear
1021
+ else self.self_attn(mixed, cache)
1022
+ )
1023
+ x = residual + (output[..., None, :] * injection[..., None]).reshape(*residual.shape)
1024
+ mixed, residual, injection = self.mlp_hyper_connection(x)
1025
+ output = self.mlp(mixed)
1026
+ return residual + (output[..., None, :] * injection[..., None]).reshape(*residual.shape)
1027
+
1028
+
1029
+ class Qwen4MTPModule(nn.Module):
1030
+ def __init__(self, args: ModelArgs):
1031
+ super().__init__()
1032
+ self.hidden_size = args.hidden_size
1033
+ self.hc_count = args.hc_count
1034
+ total = self.hc_count * self.hidden_size
1035
+ self.pre_fc_norm_embedding = Qwen4RMSNorm(
1036
+ self.hidden_size,
1037
+ args.rms_norm_eps,
1038
+ )
1039
+ self.pre_fc_norm_hidden = Qwen4RMSNorm(total, args.rms_norm_eps)
1040
+ self.fc_embedding = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
1041
+ self.fc_hidden = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
1042
+ mtp_args = copy(args)
1043
+ mtp_args.num_hidden_layers = 1
1044
+ mtp_args.layer_types = ["full_attention"]
1045
+ mtp_args.ple_layer_ids = []
1046
+ self.layers = [Qwen4DecoderLayer(mtp_args, 0)]
1047
+ self.hyper_connection_mixer = Qwen4GatedResidual(mtp_args, combine=False)
1048
+
1049
+ def fuse_inputs(self, input_embeds, hidden_states):
1050
+ input_embeds = self.fc_embedding(
1051
+ self.pre_fc_norm_embedding(input_embeds)
1052
+ )
1053
+ original_shape = hidden_states.shape
1054
+ streams = self.pre_fc_norm_hidden(hidden_states).reshape(
1055
+ *hidden_states.shape[:-1],
1056
+ self.hc_count,
1057
+ self.hidden_size,
1058
+ )
1059
+ streams = self.fc_hidden(streams)
1060
+ return (streams + input_embeds[..., None, :]).reshape(original_shape)
1061
+
1062
+ def __call__(self, hidden_states, next_token_ids, embed_tokens, cache=None):
1063
+ hidden_states = self.fuse_inputs(
1064
+ embed_tokens(next_token_ids),
1065
+ hidden_states,
1066
+ )
1067
+ if cache is None:
1068
+ cache = [None] * len(self.layers)
1069
+ for layer, layer_cache in zip(self.layers, cache):
1070
+ hidden_states = layer(
1071
+ hidden_states,
1072
+ next_token_ids,
1073
+ cache=layer_cache,
1074
+ )
1075
+ return self.hyper_connection_mixer(hidden_states), hidden_states
1076
+
1077
+
1078
+ class Qwen4TextModel(nn.Module):
1079
+ def __init__(self, args: ModelArgs):
1080
+ super().__init__()
1081
+ self.args = args
1082
+ self.embed_tokens = nn.Embedding(args.vocab_size, args.hidden_size)
1083
+ self.layers = [Qwen4DecoderLayer(args, index) for index in range(args.num_hidden_layers)]
1084
+ self.hyper_connection_mixer = Qwen4GatedResidual(args, combine=False)
1085
+
1086
+ def __call__(self, inputs, cache=None, return_hidden=False, n_confirmed=0):
1087
+ hidden = self.embed_tokens(inputs)
1088
+ hidden = mx.tile(hidden, (1, 1, self.args.hc_count))
1089
+ if cache is None:
1090
+ cache = [None] * len(self.layers)
1091
+ linear_index = next((i for i, layer in enumerate(self.layers) if layer.is_linear), None)
1092
+ mask = create_ssm_mask(hidden, cache[linear_index]) if linear_index is not None else None
1093
+ for layer, layer_cache in zip(self.layers, cache):
1094
+ hidden = layer(
1095
+ hidden,
1096
+ inputs,
1097
+ mask,
1098
+ layer_cache,
1099
+ n_confirmed=n_confirmed,
1100
+ )
1101
+ output = self.hyper_connection_mixer(hidden)
1102
+ if return_hidden:
1103
+ return output, hidden
1104
+ return output
1105
+
1106
+
1107
+ def _decode_block_fp8(weight, scale, block=128):
1108
+ rows, columns = weight.shape
1109
+ grid_rows, grid_columns = scale.shape
1110
+ padded_rows, padded_columns = grid_rows * block, grid_columns * block
1111
+ decoded = mx.from_fp8(weight, dtype=mx.float32)
1112
+ decoded = mx.pad(decoded, ((0, padded_rows - rows), (0, padded_columns - columns)))
1113
+ decoded = decoded.reshape(grid_rows, block, grid_columns, block)
1114
+ decoded = decoded * scale.astype(mx.float32)[:, None, :, None]
1115
+ return decoded.reshape(padded_rows, padded_columns)[:rows, :columns].astype(mx.bfloat16)
1116
+
1117
+
1118
+ def register_oq_virtual_tensors(index, config):
1119
+ if config.get("model_type") != "qwen4_exp":
1120
+ return 0
1121
+ text_config = config.get("text_config", config)
1122
+ registrations = 0
1123
+ shard_count = int(text_config.get("split_ngram_parts", 0))
1124
+ for one_indexed_layer in text_config.get("ple_layer_ids", []):
1125
+ prefix = (
1126
+ f"model.language_model.layers.{one_indexed_layer - 1}.ple."
1127
+ "ple_embedding.ngram_embedding"
1128
+ )
1129
+ scale_key = prefix + ".weight_scale"
1130
+ if index.source_shape(scale_key) is None:
1131
+ continue
1132
+ for shard_index in range(shard_count):
1133
+ weight_key = f"{prefix}.shard_{shard_index}.weight"
1134
+ shape = index.source_shape(weight_key)
1135
+ if shape is None:
1136
+ raise ValueError(f"Missing Qwen4 PLE shard: {weight_key}")
1137
+
1138
+ def materialize(weight_key=weight_key, scale_key=scale_key):
1139
+ weight = index.load_source(weight_key)
1140
+ scale = index.load_source(scale_key)
1141
+ value = mx.from_fp8(weight, dtype=mx.bfloat16) * scale
1142
+ mx.eval(value)
1143
+ return value
1144
+
1145
+ index.register_virtual(
1146
+ weight_key,
1147
+ shape,
1148
+ "BF16",
1149
+ materialize,
1150
+ hides=(weight_key, scale_key),
1151
+ )
1152
+ registrations += 1
1153
+ return registrations
1154
+
1155
+
1156
+ class Model(nn.Module):
1157
+ def __init__(self, args: ModelArgs):
1158
+ super().__init__()
1159
+ self.args = args
1160
+ self.model_type = args.model_type
1161
+ self.model = Qwen4TextModel(args)
1162
+ if not args.tie_word_embeddings:
1163
+ self.lm_head = nn.Linear(args.hidden_size, args.vocab_size, bias=False)
1164
+ mtp_active = False
1165
+ if args.mtp_num_hidden_layers:
1166
+ try:
1167
+ from omlx.patches.mlx_lm_mtp import is_mtp_active
1168
+
1169
+ mtp_active = is_mtp_active()
1170
+ except ImportError:
1171
+ mtp_active = False
1172
+ self._omlx_mtp_decode_enabled = bool(mtp_active)
1173
+ if mtp_active:
1174
+ if args.mtp_num_hidden_layers != 1:
1175
+ raise ValueError("Qwen4 requires exactly one MTP decoder layer")
1176
+ self.mtp = Qwen4MTPModule(args)
1177
+ self._omlx_mtp_chain = True
1178
+ self._omlx_mtp_depth = 1
1179
+ self._omlx_mtp_head_prenorm = True
1180
+
1181
+ def __call__(self, inputs, cache=None, return_hidden=False, n_confirmed=0):
1182
+ need_hidden = return_hidden or hasattr(self, "mtp")
1183
+ result = self.model(
1184
+ inputs,
1185
+ cache,
1186
+ return_hidden=need_hidden,
1187
+ n_confirmed=n_confirmed,
1188
+ )
1189
+ if need_hidden:
1190
+ output, hidden = result
1191
+ else:
1192
+ output = result
1193
+ if self.args.tie_word_embeddings:
1194
+ logits = self.model.embed_tokens.as_linear(output)
1195
+ else:
1196
+ logits = self.lm_head(output)
1197
+ if (
1198
+ hasattr(self, "mtp")
1199
+ and not return_hidden
1200
+ and not n_confirmed
1201
+ ):
1202
+ try:
1203
+ from omlx.patches.mlx_lm_mtp import prompt_priming
1204
+
1205
+ prompt_priming.maybe_capture(self, inputs, hidden, cache)
1206
+ except Exception:
1207
+ logger.debug("Qwen4 MTP prompt priming failed", exc_info=True)
1208
+ if return_hidden:
1209
+ return logits, hidden
1210
+ return logits
1211
+
1212
+ def mtp_forward(
1213
+ self,
1214
+ hidden_states,
1215
+ next_token_ids,
1216
+ mtp_cache,
1217
+ return_hidden=False,
1218
+ logits_keep=0,
1219
+ ):
1220
+ if not hasattr(self, "mtp"):
1221
+ raise RuntimeError("Qwen4 MTP forward called without an attached head")
1222
+ output, hidden = self.mtp(
1223
+ hidden_states,
1224
+ next_token_ids,
1225
+ self.model.embed_tokens,
1226
+ mtp_cache,
1227
+ )
1228
+ if logits_keep and output.shape[1] > logits_keep:
1229
+ output = output[:, -logits_keep:, :]
1230
+ if self.args.tie_word_embeddings:
1231
+ logits = self.model.embed_tokens.as_linear(output)
1232
+ else:
1233
+ logits = self.lm_head(output)
1234
+ if return_hidden:
1235
+ return logits, hidden
1236
+ return logits
1237
+
1238
+ def make_mtp_cache(self):
1239
+ if not hasattr(self, "mtp"):
1240
+ return []
1241
+ return [QSAKVCache() for _ in self.mtp.layers]
1242
+
1243
+ def mtp_partial_rollback(self, cache, accepted, num_drafts):
1244
+ if len(cache) != len(self.layers):
1245
+ return False
1246
+ trim = int(num_drafts) - int(accepted)
1247
+ if trim <= 0:
1248
+ return True
1249
+ keep = 1 + int(accepted)
1250
+ for layer, layer_cache in zip(self.layers, cache):
1251
+ if layer.is_linear:
1252
+ if getattr(layer_cache, "rollback_state", None) is None:
1253
+ return False
1254
+ if getattr(layer_cache, "_mtp_draft_stash", None) is None:
1255
+ return False
1256
+ elif not layer_cache.is_trimmable():
1257
+ return False
1258
+ for layer, layer_cache in zip(self.layers, cache):
1259
+ if layer.is_linear:
1260
+ conv_state, state = layer_cache.rollback_state
1261
+ mixed, a, b, mask = layer_cache._mtp_draft_stash
1262
+ if mask is not None:
1263
+ mask = mask[:, :keep]
1264
+ _, next_conv_state, next_state = layer.linear_attn._process_chunk(
1265
+ mixed[:, :keep],
1266
+ a[:, :keep],
1267
+ b[:, :keep],
1268
+ conv_state,
1269
+ state,
1270
+ mask,
1271
+ )
1272
+ layer_cache[0] = next_conv_state
1273
+ layer_cache[1] = next_state
1274
+ layer_cache.rollback_state = None
1275
+ layer_cache._mtp_draft_stash = None
1276
+ else:
1277
+ layer_cache.trim(trim)
1278
+ return True
1279
+
1280
+ @property
1281
+ def layers(self):
1282
+ return self.model.layers
1283
+
1284
+ def make_cache(self):
1285
+ return [ArraysCache(size=4) if layer.is_linear else QSAKVCache() for layer in self.layers]
1286
+
1287
+ def sanitize(self, weights):
1288
+ cleaned = {}
1289
+ for key, value in weights.items():
1290
+ if key.startswith("mtp.") and not hasattr(self, "mtp"):
1291
+ continue
1292
+ if key.startswith("model.visual."):
1293
+ continue
1294
+ if key.startswith("model.language_model."):
1295
+ key = "model." + key[len("model.language_model.") :]
1296
+ cleaned[key] = value
1297
+ weights = cleaned
1298
+ if self.args.tie_word_embeddings:
1299
+ weights.pop("lm_head.weight", None)
1300
+ expert_prefixes = [
1301
+ f"model.layers.{layer_index}.mlp"
1302
+ for layer_index in range(self.args.num_hidden_layers)
1303
+ ]
1304
+ if hasattr(self, "mtp"):
1305
+ expert_prefixes.extend(
1306
+ f"mtp.layers.{layer_index}.mlp"
1307
+ for layer_index in range(self.args.mtp_num_hidden_layers)
1308
+ )
1309
+ for prefix in expert_prefixes:
1310
+ if f"{prefix}.experts.0.up_proj.weight" not in weights:
1311
+ continue
1312
+ for projection in ("up_proj", "gate_proj", "down_proj"):
1313
+ values = []
1314
+ for expert in range(self.args.num_experts):
1315
+ key = f"{prefix}.experts.{expert}.{projection}.weight"
1316
+ scale_key = key + "_scale_inv"
1317
+ value = weights.pop(key)
1318
+ if scale_key in weights:
1319
+ value = _decode_block_fp8(value, weights.pop(scale_key))
1320
+ values.append(value)
1321
+ weights[f"{prefix}.switch_mlp.{projection}.weight"] = mx.stack(values)
1322
+ for layer_index in range(self.args.num_hidden_layers):
1323
+ base = f"model.layers.{layer_index}.ple.ple_embedding.ngram_embedding"
1324
+ layer = self.model.layers[layer_index]
1325
+ disk_backed = (
1326
+ layer.ple is not None
1327
+ and isinstance(
1328
+ layer.ple.ple_embedding.ngram_embedding,
1329
+ DiskBackedShardedEmbedding,
1330
+ )
1331
+ )
1332
+ if disk_backed:
1333
+ for key in list(weights):
1334
+ if key.startswith(base + ".shards."):
1335
+ weights.pop(key)
1336
+ shard_keys = [key for key in weights if key.startswith(base + ".shard_") and key.endswith(".weight")]
1337
+ if not shard_keys:
1338
+ continue
1339
+ shard_keys.sort(key=lambda key: int(key.split(".shard_")[1].split(".")[0]))
1340
+ scale = weights.pop(base + ".weight_scale", None)
1341
+ for shard_index, key in enumerate(shard_keys):
1342
+ value = weights.pop(key)
1343
+ if scale is not None:
1344
+ value = mx.from_fp8(value, dtype=mx.bfloat16) * scale
1345
+ weights[f"{base}.shards.{shard_index}.weight"] = value
1346
+ for key in list(weights):
1347
+ value = weights[key]
1348
+ if key.endswith("conv1d.weight") and value.ndim == 3 and value.shape[-1] != 1:
1349
+ weights[key] = value.moveaxis(2, 1)
1350
+ return weights
1351
+
1352
+ @property
1353
+ def quant_predicate(self):
1354
+ def predicate(path, module):
1355
+ if "ple_embedding.ngram_embedding.shards." in path:
1356
+ return {"group_size": 32, "bits": 4}
1357
+ if path.endswith("mlp.gate") or path.endswith("shared_expert_gate"):
1358
+ return {"group_size": 64, "bits": 8}
1359
+ return hasattr(module, "to_quantized")
1360
+
1361
+ return predicate
omlx_support/qwen4_mtp_integration.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def register_qwen4_mtp_integration():
2
+ try:
3
+ from omlx.utils import model_loading
4
+ except ImportError:
5
+ return False
6
+ if getattr(model_loading, "_qwen4_mtp_compatible_installed", False):
7
+ return True
8
+
9
+ original = model_loading._is_mtp_compatible
10
+
11
+ def compatible(config, model_type):
12
+ if model_type == "qwen4_exp":
13
+ return model_loading._has_mtp_heads(config)
14
+ return original(config, model_type)
15
+
16
+ model_loading._is_mtp_compatible = compatible
17
+ model_loading._qwen4_mtp_compatible_installed = True
18
+ return True
omlx_support/serve ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/zsh
2
+ set -euo pipefail
3
+
4
+ support_root=${0:A:h}
5
+ model_root=${support_root:h}
6
+ models_root=${model_root:h}
7
+ base_path=${OMLX_BASE_PATH:-$model_root/.omlx}
8
+ cache_dir=${OMLX_CACHE_DIR:-$base_path/cache}
9
+ api_key=${OMLX_API_KEY:-omlx}
10
+ port=${OMLX_PORT:-8766}
11
+
12
+ mkdir -p "$cache_dir"
13
+ if [[ ! -f "$base_path/model_settings.json" ]]; then
14
+ cp "$support_root/model_settings.json" "$base_path/model_settings.json"
15
+ fi
16
+ export OMLX_QWEN4_PLE_MODE=mmap
17
+ export OMLX_QWEN4_PLE_MODEL_PATH="$model_root"
18
+ export OMLX_MTP_PROMPT_PRIMING=1
19
+ export OMLX_MTP_PRIME_WINDOW=8192
20
+
21
+ exec /bin/zsh "$support_root/with-omlx-python" -m omlx.cli serve \
22
+ --model-dir "$models_root" \
23
+ --host 127.0.0.1 \
24
+ --port "$port" \
25
+ --max-concurrent-requests 1 \
26
+ --memory-guard balanced \
27
+ --paged-ssd-cache-dir "$cache_dir" \
28
+ --paged-ssd-cache-max-size 128GB \
29
+ --hot-cache-max-size 0 \
30
+ --initial-cache-blocks 1 \
31
+ --no-hf-cache \
32
+ --base-path "$base_path" \
33
+ --api-key "$api_key"
omlx_support/sitecustomize.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ import mlx_lm.models
4
+
5
+
6
+ model_path = str(Path(__file__).resolve().parent)
7
+ if model_path not in mlx_lm.models.__path__:
8
+ mlx_lm.models.__path__.insert(0, model_path)
9
+
10
+ from qwen4_cache_integration import register_qwen4_cache_integration
11
+ from qwen4_mtp_integration import register_qwen4_mtp_integration
12
+
13
+
14
+ register_qwen4_cache_integration()
15
+ register_qwen4_mtp_integration()
omlx_support/with-omlx-python ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/zsh
2
+ set -euo pipefail
3
+
4
+ support_root=${0:A:h}
5
+ model_root=${support_root:h}
6
+ app_resources=${OMLX_APP_RESOURCES:-/Applications/oMLX.app/Contents/Resources}
7
+ python_root=$app_resources/Python
8
+ cpython_root=$python_root/cpython-3.11
9
+ mlx_site=$python_root/framework-mlx-base/lib/python3.11/site-packages
10
+ mlx_runtime=${OMLX_MLX_RUNTIME:-$model_root/.mlx-runtime}
11
+
12
+ if [[ ! -d "$mlx_runtime/mlx" ]]; then
13
+ print -u2 "MLX 0.32.1 is missing from $mlx_runtime"
14
+ print -u2 "Install it with: uv pip install --target $mlx_runtime mlx==0.32.1 mlx-metal==0.32.1"
15
+ exit 1
16
+ fi
17
+
18
+ export PYTHONHOME=$cpython_root
19
+ export PYTHONDONTWRITEBYTECODE=1
20
+ export PYTHONPATH="$support_root:$mlx_runtime:$app_resources:$mlx_site"
21
+
22
+ exec "$cpython_root/bin/python3" "$@"
oq_imatrix_report.json ADDED
@@ -0,0 +1,870 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "enabled": true,
3
+ "cache_path": null,
4
+ "cache_reused": true,
5
+ "entry_count": 914,
6
+ "calib_dataset": "oqe_code_multilingual",
7
+ "collection": {
8
+ "dataset": "oqe_code_multilingual",
9
+ "requested_samples": 128,
10
+ "seq_length": 512,
11
+ "adaptive": true,
12
+ "adaptive_step_samples": 128,
13
+ "adaptive_max_samples": 1024,
14
+ "available_samples": 1024,
15
+ "micro_batch_size": 6,
16
+ "micro_batches": 176,
17
+ "batch_plan": {
18
+ "micro_batch_size": 6,
19
+ "estimated_sample_bytes": 52428800,
20
+ "capture_budget_bytes": 362029891,
21
+ "system_available_bytes": 103756529664,
22
+ "metal_available_bytes": 115443233112,
23
+ "live_available_bytes": 103756529664,
24
+ "model_bytes": 67553540501,
25
+ "remaining_available_bytes": 36202989163,
26
+ "fits_one_sample": true,
27
+ "hidden_size": 2560,
28
+ "num_experts": 512,
29
+ "top_k": 10,
30
+ "gemma4_state_bytes": 0,
31
+ "num_hidden_layers": 48,
32
+ "num_kv_shared_layers": 0,
33
+ "per_layer_input_size": 0
34
+ },
35
+ "processed_samples": 1024,
36
+ "installed_modules": 917,
37
+ "capture_module_classes": {
38
+ "Linear": 388,
39
+ "QuantizedLinear": 385,
40
+ "QuantizedSwitchLinear": 144
41
+ },
42
+ "switch_capture_modules": 144,
43
+ "requires_expert_counts": true,
44
+ "coverage_sufficient": false,
45
+ "collection_sufficient": false,
46
+ "coverage": {
47
+ "has_expert_counts": true,
48
+ "expert_modules": 144,
49
+ "total_experts": 73728,
50
+ "active_experts": 73665,
51
+ "zero_count_experts": 63,
52
+ "active_ratio": 0.9991455078125,
53
+ "min_count": 0,
54
+ "p05_count": 717.0,
55
+ "p10_count": 1432.0,
56
+ "median_count": 7353.0,
57
+ "max_count": 341355,
58
+ "min_required_count": 16,
59
+ "required_percentile": 5
60
+ },
61
+ "rounds": [
62
+ {
63
+ "processed_samples": 128,
64
+ "coverage_sufficient": false,
65
+ "collection_sufficient": false,
66
+ "coverage": {
67
+ "has_expert_counts": true,
68
+ "expert_modules": 144,
69
+ "total_experts": 73728,
70
+ "active_experts": 73530,
71
+ "zero_count_experts": 198,
72
+ "active_ratio": 0.997314453125,
73
+ "min_count": 0,
74
+ "p05_count": 71.0,
75
+ "p10_count": 158.0,
76
+ "median_count": 913.0,
77
+ "max_count": 41723,
78
+ "min_required_count": 16,
79
+ "required_percentile": 5
80
+ }
81
+ },
82
+ {
83
+ "processed_samples": 256,
84
+ "coverage_sufficient": false,
85
+ "collection_sufficient": false,
86
+ "coverage": {
87
+ "has_expert_counts": true,
88
+ "expert_modules": 144,
89
+ "total_experts": 73728,
90
+ "active_experts": 73587,
91
+ "zero_count_experts": 141,
92
+ "active_ratio": 0.9980875651041666,
93
+ "min_count": 0,
94
+ "p05_count": 174.0,
95
+ "p10_count": 353.0,
96
+ "median_count": 1830.0,
97
+ "max_count": 83264,
98
+ "min_required_count": 16,
99
+ "required_percentile": 5
100
+ }
101
+ },
102
+ {
103
+ "processed_samples": 384,
104
+ "coverage_sufficient": false,
105
+ "collection_sufficient": false,
106
+ "coverage": {
107
+ "has_expert_counts": true,
108
+ "expert_modules": 144,
109
+ "total_experts": 73728,
110
+ "active_experts": 73629,
111
+ "zero_count_experts": 99,
112
+ "active_ratio": 0.9986572265625,
113
+ "min_count": 0,
114
+ "p05_count": 285.35000000000036,
115
+ "p10_count": 553.0,
116
+ "median_count": 2755.0,
117
+ "max_count": 124541,
118
+ "min_required_count": 16,
119
+ "required_percentile": 5
120
+ }
121
+ },
122
+ {
123
+ "processed_samples": 512,
124
+ "coverage_sufficient": false,
125
+ "collection_sufficient": false,
126
+ "coverage": {
127
+ "has_expert_counts": true,
128
+ "expert_modules": 144,
129
+ "total_experts": 73728,
130
+ "active_experts": 73641,
131
+ "zero_count_experts": 87,
132
+ "active_ratio": 0.9988199869791666,
133
+ "min_count": 0,
134
+ "p05_count": 369.35000000000036,
135
+ "p10_count": 737.0,
136
+ "median_count": 3687.5,
137
+ "max_count": 168254,
138
+ "min_required_count": 16,
139
+ "required_percentile": 5
140
+ }
141
+ },
142
+ {
143
+ "processed_samples": 640,
144
+ "coverage_sufficient": false,
145
+ "collection_sufficient": false,
146
+ "coverage": {
147
+ "has_expert_counts": true,
148
+ "expert_modules": 144,
149
+ "total_experts": 73728,
150
+ "active_experts": 73653,
151
+ "zero_count_experts": 75,
152
+ "active_ratio": 0.9989827473958334,
153
+ "min_count": 0,
154
+ "p05_count": 453.35000000000036,
155
+ "p10_count": 904.0,
156
+ "median_count": 4619.0,
157
+ "max_count": 213373,
158
+ "min_required_count": 16,
159
+ "required_percentile": 5
160
+ }
161
+ },
162
+ {
163
+ "processed_samples": 768,
164
+ "coverage_sufficient": false,
165
+ "collection_sufficient": false,
166
+ "coverage": {
167
+ "has_expert_counts": true,
168
+ "expert_modules": 144,
169
+ "total_experts": 73728,
170
+ "active_experts": 73656,
171
+ "zero_count_experts": 72,
172
+ "active_ratio": 0.9990234375,
173
+ "min_count": 0,
174
+ "p05_count": 539.0,
175
+ "p10_count": 1076.0,
176
+ "median_count": 5501.5,
177
+ "max_count": 255296,
178
+ "min_required_count": 16,
179
+ "required_percentile": 5
180
+ }
181
+ },
182
+ {
183
+ "processed_samples": 896,
184
+ "coverage_sufficient": false,
185
+ "collection_sufficient": false,
186
+ "coverage": {
187
+ "has_expert_counts": true,
188
+ "expert_modules": 144,
189
+ "total_experts": 73728,
190
+ "active_experts": 73659,
191
+ "zero_count_experts": 69,
192
+ "active_ratio": 0.9990641276041666,
193
+ "min_count": 0,
194
+ "p05_count": 628.0,
195
+ "p10_count": 1257.0,
196
+ "median_count": 6420.0,
197
+ "max_count": 298656,
198
+ "min_required_count": 16,
199
+ "required_percentile": 5
200
+ }
201
+ },
202
+ {
203
+ "processed_samples": 1024,
204
+ "coverage_sufficient": false,
205
+ "collection_sufficient": false,
206
+ "coverage": {
207
+ "has_expert_counts": true,
208
+ "expert_modules": 144,
209
+ "total_experts": 73728,
210
+ "active_experts": 73665,
211
+ "zero_count_experts": 63,
212
+ "active_ratio": 0.9991455078125,
213
+ "min_count": 0,
214
+ "p05_count": 717.0,
215
+ "p10_count": 1432.0,
216
+ "median_count": 7353.0,
217
+ "max_count": 341355,
218
+ "min_required_count": 16,
219
+ "required_percentile": 5
220
+ }
221
+ }
222
+ ]
223
+ },
224
+ "expert_coverage": {
225
+ "has_expert_counts": true,
226
+ "expert_modules": 144,
227
+ "total_experts": 73728,
228
+ "active_experts": 73665,
229
+ "zero_count_experts": 63,
230
+ "active_ratio": 0.9991455078125,
231
+ "min_count": 0,
232
+ "p05_count": 717.0,
233
+ "p10_count": 1432.0,
234
+ "median_count": 7353.0,
235
+ "max_count": 341355,
236
+ "min_required_count": 16,
237
+ "required_percentile": 5
238
+ },
239
+ "applied": [
240
+ "model.layers.0.attn_hyper_connection.input_mix_weight_down",
241
+ "model.layers.0.linear_attn.in_proj_a",
242
+ "model.layers.0.linear_attn.in_proj_b",
243
+ "model.layers.0.linear_attn.in_proj_qkv",
244
+ "model.layers.0.linear_attn.in_proj_z",
245
+ "model.layers.0.linear_attn.out_proj",
246
+ "model.layers.0.mlp.shared_expert.down_proj",
247
+ "model.layers.0.mlp.shared_expert.gate_proj",
248
+ "model.layers.0.mlp.shared_expert.up_proj",
249
+ "model.layers.0.mlp.switch_mlp.down_proj",
250
+ "model.layers.0.mlp.switch_mlp.gate_proj",
251
+ "model.layers.0.mlp.switch_mlp.up_proj",
252
+ "model.layers.0.mlp_hyper_connection.input_mix_weight_down",
253
+ "model.layers.1.attn_hyper_connection.input_mix_weight_down",
254
+ "model.layers.1.linear_attn.in_proj_a",
255
+ "model.layers.1.linear_attn.in_proj_b",
256
+ "model.layers.1.linear_attn.in_proj_qkv",
257
+ "model.layers.1.linear_attn.in_proj_z",
258
+ "model.layers.1.linear_attn.out_proj",
259
+ "model.layers.1.mlp.shared_expert.down_proj",
260
+ "model.layers.1.mlp.shared_expert.gate_proj",
261
+ "model.layers.1.mlp.shared_expert.up_proj",
262
+ "model.layers.1.mlp.switch_mlp.down_proj",
263
+ "model.layers.1.mlp.switch_mlp.gate_proj",
264
+ "model.layers.1.mlp.switch_mlp.up_proj",
265
+ "model.layers.1.mlp_hyper_connection.input_mix_weight_down",
266
+ "model.layers.1.ple.key_proj",
267
+ "model.layers.1.ple.value_proj",
268
+ "model.layers.10.attn_hyper_connection.input_mix_weight_down",
269
+ "model.layers.10.linear_attn.in_proj_a",
270
+ "model.layers.10.linear_attn.in_proj_b",
271
+ "model.layers.10.linear_attn.in_proj_qkv",
272
+ "model.layers.10.linear_attn.in_proj_z",
273
+ "model.layers.10.linear_attn.out_proj",
274
+ "model.layers.10.mlp.shared_expert.down_proj",
275
+ "model.layers.10.mlp.shared_expert.gate_proj",
276
+ "model.layers.10.mlp.shared_expert.up_proj",
277
+ "model.layers.10.mlp.switch_mlp.down_proj",
278
+ "model.layers.10.mlp.switch_mlp.gate_proj",
279
+ "model.layers.10.mlp.switch_mlp.up_proj",
280
+ "model.layers.10.mlp_hyper_connection.input_mix_weight_down",
281
+ "model.layers.11.attn_hyper_connection.input_mix_weight_down",
282
+ "model.layers.11.mlp.shared_expert.down_proj",
283
+ "model.layers.11.mlp.shared_expert.gate_proj",
284
+ "model.layers.11.mlp.shared_expert.up_proj",
285
+ "model.layers.11.mlp.switch_mlp.down_proj",
286
+ "model.layers.11.mlp.switch_mlp.gate_proj",
287
+ "model.layers.11.mlp.switch_mlp.up_proj",
288
+ "model.layers.11.mlp_hyper_connection.input_mix_weight_down",
289
+ "model.layers.11.self_attn.indexer.index_qk_proj",
290
+ "model.layers.11.self_attn.k_proj",
291
+ "model.layers.11.self_attn.o_proj",
292
+ "model.layers.11.self_attn.q_proj",
293
+ "model.layers.11.self_attn.v_proj",
294
+ "model.layers.12.attn_hyper_connection.input_mix_weight_down",
295
+ "model.layers.12.linear_attn.in_proj_a",
296
+ "model.layers.12.linear_attn.in_proj_b",
297
+ "model.layers.12.linear_attn.in_proj_qkv",
298
+ "model.layers.12.linear_attn.in_proj_z",
299
+ "model.layers.12.linear_attn.out_proj",
300
+ "model.layers.12.mlp.shared_expert.down_proj",
301
+ "model.layers.12.mlp.shared_expert.gate_proj",
302
+ "model.layers.12.mlp.shared_expert.up_proj",
303
+ "model.layers.12.mlp.switch_mlp.down_proj",
304
+ "model.layers.12.mlp.switch_mlp.gate_proj",
305
+ "model.layers.12.mlp.switch_mlp.up_proj",
306
+ "model.layers.12.mlp_hyper_connection.input_mix_weight_down",
307
+ "model.layers.13.attn_hyper_connection.input_mix_weight_down",
308
+ "model.layers.13.linear_attn.in_proj_a",
309
+ "model.layers.13.linear_attn.in_proj_b",
310
+ "model.layers.13.linear_attn.in_proj_qkv",
311
+ "model.layers.13.linear_attn.in_proj_z",
312
+ "model.layers.13.linear_attn.out_proj",
313
+ "model.layers.13.mlp.shared_expert.down_proj",
314
+ "model.layers.13.mlp.shared_expert.gate_proj",
315
+ "model.layers.13.mlp.shared_expert.up_proj",
316
+ "model.layers.13.mlp.switch_mlp.down_proj",
317
+ "model.layers.13.mlp.switch_mlp.gate_proj",
318
+ "model.layers.13.mlp.switch_mlp.up_proj",
319
+ "model.layers.13.mlp_hyper_connection.input_mix_weight_down",
320
+ "model.layers.14.attn_hyper_connection.input_mix_weight_down",
321
+ "model.layers.14.linear_attn.in_proj_a",
322
+ "model.layers.14.linear_attn.in_proj_b",
323
+ "model.layers.14.linear_attn.in_proj_qkv",
324
+ "model.layers.14.linear_attn.in_proj_z",
325
+ "model.layers.14.linear_attn.out_proj",
326
+ "model.layers.14.mlp.shared_expert.down_proj",
327
+ "model.layers.14.mlp.shared_expert.gate_proj",
328
+ "model.layers.14.mlp.shared_expert.up_proj",
329
+ "model.layers.14.mlp.switch_mlp.down_proj",
330
+ "model.layers.14.mlp.switch_mlp.gate_proj",
331
+ "model.layers.14.mlp.switch_mlp.up_proj",
332
+ "model.layers.14.mlp_hyper_connection.input_mix_weight_down",
333
+ "model.layers.15.attn_hyper_connection.input_mix_weight_down",
334
+ "model.layers.15.mlp.shared_expert.down_proj",
335
+ "model.layers.15.mlp.shared_expert.gate_proj",
336
+ "model.layers.15.mlp.shared_expert.up_proj",
337
+ "model.layers.15.mlp.switch_mlp.down_proj",
338
+ "model.layers.15.mlp.switch_mlp.gate_proj",
339
+ "model.layers.15.mlp.switch_mlp.up_proj",
340
+ "model.layers.15.mlp_hyper_connection.input_mix_weight_down",
341
+ "model.layers.15.self_attn.indexer.index_qk_proj",
342
+ "model.layers.15.self_attn.k_proj",
343
+ "model.layers.15.self_attn.o_proj",
344
+ "model.layers.15.self_attn.q_proj",
345
+ "model.layers.15.self_attn.v_proj",
346
+ "model.layers.16.attn_hyper_connection.input_mix_weight_down",
347
+ "model.layers.16.linear_attn.in_proj_a",
348
+ "model.layers.16.linear_attn.in_proj_b",
349
+ "model.layers.16.linear_attn.in_proj_qkv",
350
+ "model.layers.16.linear_attn.in_proj_z",
351
+ "model.layers.16.linear_attn.out_proj",
352
+ "model.layers.16.mlp.shared_expert.down_proj",
353
+ "model.layers.16.mlp.shared_expert.gate_proj",
354
+ "model.layers.16.mlp.shared_expert.up_proj",
355
+ "model.layers.16.mlp.switch_mlp.down_proj",
356
+ "model.layers.16.mlp.switch_mlp.gate_proj",
357
+ "model.layers.16.mlp.switch_mlp.up_proj",
358
+ "model.layers.16.mlp_hyper_connection.input_mix_weight_down",
359
+ "model.layers.17.attn_hyper_connection.input_mix_weight_down",
360
+ "model.layers.17.linear_attn.in_proj_a",
361
+ "model.layers.17.linear_attn.in_proj_b",
362
+ "model.layers.17.linear_attn.in_proj_qkv",
363
+ "model.layers.17.linear_attn.in_proj_z",
364
+ "model.layers.17.linear_attn.out_proj",
365
+ "model.layers.17.mlp.shared_expert.down_proj",
366
+ "model.layers.17.mlp.shared_expert.gate_proj",
367
+ "model.layers.17.mlp.shared_expert.up_proj",
368
+ "model.layers.17.mlp.switch_mlp.down_proj",
369
+ "model.layers.17.mlp.switch_mlp.gate_proj",
370
+ "model.layers.17.mlp.switch_mlp.up_proj",
371
+ "model.layers.17.mlp_hyper_connection.input_mix_weight_down",
372
+ "model.layers.18.attn_hyper_connection.input_mix_weight_down",
373
+ "model.layers.18.linear_attn.in_proj_a",
374
+ "model.layers.18.linear_attn.in_proj_b",
375
+ "model.layers.18.linear_attn.in_proj_qkv",
376
+ "model.layers.18.linear_attn.in_proj_z",
377
+ "model.layers.18.linear_attn.out_proj",
378
+ "model.layers.18.mlp.shared_expert.down_proj",
379
+ "model.layers.18.mlp.shared_expert.gate_proj",
380
+ "model.layers.18.mlp.shared_expert.up_proj",
381
+ "model.layers.18.mlp.switch_mlp.down_proj",
382
+ "model.layers.18.mlp.switch_mlp.gate_proj",
383
+ "model.layers.18.mlp.switch_mlp.up_proj",
384
+ "model.layers.18.mlp_hyper_connection.input_mix_weight_down",
385
+ "model.layers.19.attn_hyper_connection.input_mix_weight_down",
386
+ "model.layers.19.mlp.shared_expert.down_proj",
387
+ "model.layers.19.mlp.shared_expert.gate_proj",
388
+ "model.layers.19.mlp.shared_expert.up_proj",
389
+ "model.layers.19.mlp.switch_mlp.down_proj",
390
+ "model.layers.19.mlp.switch_mlp.gate_proj",
391
+ "model.layers.19.mlp.switch_mlp.up_proj",
392
+ "model.layers.19.mlp_hyper_connection.input_mix_weight_down",
393
+ "model.layers.19.self_attn.indexer.index_qk_proj",
394
+ "model.layers.19.self_attn.k_proj",
395
+ "model.layers.19.self_attn.o_proj",
396
+ "model.layers.19.self_attn.q_proj",
397
+ "model.layers.19.self_attn.v_proj",
398
+ "model.layers.2.attn_hyper_connection.input_mix_weight_down",
399
+ "model.layers.2.linear_attn.in_proj_a",
400
+ "model.layers.2.linear_attn.in_proj_b",
401
+ "model.layers.2.linear_attn.in_proj_qkv",
402
+ "model.layers.2.linear_attn.in_proj_z",
403
+ "model.layers.2.linear_attn.out_proj",
404
+ "model.layers.2.mlp.shared_expert.down_proj",
405
+ "model.layers.2.mlp.shared_expert.gate_proj",
406
+ "model.layers.2.mlp.shared_expert.up_proj",
407
+ "model.layers.2.mlp.switch_mlp.down_proj",
408
+ "model.layers.2.mlp.switch_mlp.gate_proj",
409
+ "model.layers.2.mlp.switch_mlp.up_proj",
410
+ "model.layers.2.mlp_hyper_connection.input_mix_weight_down",
411
+ "model.layers.20.attn_hyper_connection.input_mix_weight_down",
412
+ "model.layers.20.linear_attn.in_proj_a",
413
+ "model.layers.20.linear_attn.in_proj_b",
414
+ "model.layers.20.linear_attn.in_proj_qkv",
415
+ "model.layers.20.linear_attn.in_proj_z",
416
+ "model.layers.20.linear_attn.out_proj",
417
+ "model.layers.20.mlp.shared_expert.down_proj",
418
+ "model.layers.20.mlp.shared_expert.gate_proj",
419
+ "model.layers.20.mlp.shared_expert.up_proj",
420
+ "model.layers.20.mlp.switch_mlp.down_proj",
421
+ "model.layers.20.mlp.switch_mlp.gate_proj",
422
+ "model.layers.20.mlp.switch_mlp.up_proj",
423
+ "model.layers.20.mlp_hyper_connection.input_mix_weight_down",
424
+ "model.layers.21.attn_hyper_connection.input_mix_weight_down",
425
+ "model.layers.21.linear_attn.in_proj_a",
426
+ "model.layers.21.linear_attn.in_proj_b",
427
+ "model.layers.21.linear_attn.in_proj_qkv",
428
+ "model.layers.21.linear_attn.in_proj_z",
429
+ "model.layers.21.linear_attn.out_proj",
430
+ "model.layers.21.mlp.shared_expert.down_proj",
431
+ "model.layers.21.mlp.shared_expert.gate_proj",
432
+ "model.layers.21.mlp.shared_expert.up_proj",
433
+ "model.layers.21.mlp.switch_mlp.down_proj",
434
+ "model.layers.21.mlp.switch_mlp.gate_proj",
435
+ "model.layers.21.mlp.switch_mlp.up_proj",
436
+ "model.layers.21.mlp_hyper_connection.input_mix_weight_down",
437
+ "model.layers.22.attn_hyper_connection.input_mix_weight_down",
438
+ "model.layers.22.linear_attn.in_proj_a",
439
+ "model.layers.22.linear_attn.in_proj_b",
440
+ "model.layers.22.linear_attn.in_proj_qkv",
441
+ "model.layers.22.linear_attn.in_proj_z",
442
+ "model.layers.22.linear_attn.out_proj",
443
+ "model.layers.22.mlp.shared_expert.down_proj",
444
+ "model.layers.22.mlp.shared_expert.gate_proj",
445
+ "model.layers.22.mlp.shared_expert.up_proj",
446
+ "model.layers.22.mlp.switch_mlp.down_proj",
447
+ "model.layers.22.mlp.switch_mlp.gate_proj",
448
+ "model.layers.22.mlp.switch_mlp.up_proj",
449
+ "model.layers.22.mlp_hyper_connection.input_mix_weight_down",
450
+ "model.layers.23.attn_hyper_connection.input_mix_weight_down",
451
+ "model.layers.23.mlp.shared_expert.down_proj",
452
+ "model.layers.23.mlp.shared_expert.gate_proj",
453
+ "model.layers.23.mlp.shared_expert.up_proj",
454
+ "model.layers.23.mlp.switch_mlp.down_proj",
455
+ "model.layers.23.mlp.switch_mlp.gate_proj",
456
+ "model.layers.23.mlp.switch_mlp.up_proj",
457
+ "model.layers.23.mlp_hyper_connection.input_mix_weight_down",
458
+ "model.layers.23.self_attn.indexer.index_qk_proj",
459
+ "model.layers.23.self_attn.k_proj",
460
+ "model.layers.23.self_attn.o_proj",
461
+ "model.layers.23.self_attn.q_proj",
462
+ "model.layers.23.self_attn.v_proj",
463
+ "model.layers.24.attn_hyper_connection.input_mix_weight_down",
464
+ "model.layers.24.linear_attn.in_proj_a",
465
+ "model.layers.24.linear_attn.in_proj_b",
466
+ "model.layers.24.linear_attn.in_proj_qkv",
467
+ "model.layers.24.linear_attn.in_proj_z",
468
+ "model.layers.24.linear_attn.out_proj",
469
+ "model.layers.24.mlp.shared_expert.down_proj",
470
+ "model.layers.24.mlp.shared_expert.gate_proj",
471
+ "model.layers.24.mlp.shared_expert.up_proj",
472
+ "model.layers.24.mlp.switch_mlp.down_proj",
473
+ "model.layers.24.mlp.switch_mlp.gate_proj",
474
+ "model.layers.24.mlp.switch_mlp.up_proj",
475
+ "model.layers.24.mlp_hyper_connection.input_mix_weight_down",
476
+ "model.layers.25.attn_hyper_connection.input_mix_weight_down",
477
+ "model.layers.25.linear_attn.in_proj_a",
478
+ "model.layers.25.linear_attn.in_proj_b",
479
+ "model.layers.25.linear_attn.in_proj_qkv",
480
+ "model.layers.25.linear_attn.in_proj_z",
481
+ "model.layers.25.linear_attn.out_proj",
482
+ "model.layers.25.mlp.shared_expert.down_proj",
483
+ "model.layers.25.mlp.shared_expert.gate_proj",
484
+ "model.layers.25.mlp.shared_expert.up_proj",
485
+ "model.layers.25.mlp.switch_mlp.down_proj",
486
+ "model.layers.25.mlp.switch_mlp.gate_proj",
487
+ "model.layers.25.mlp.switch_mlp.up_proj",
488
+ "model.layers.25.mlp_hyper_connection.input_mix_weight_down",
489
+ "model.layers.26.attn_hyper_connection.input_mix_weight_down",
490
+ "model.layers.26.linear_attn.in_proj_a",
491
+ "model.layers.26.linear_attn.in_proj_b",
492
+ "model.layers.26.linear_attn.in_proj_qkv",
493
+ "model.layers.26.linear_attn.in_proj_z",
494
+ "model.layers.26.linear_attn.out_proj",
495
+ "model.layers.26.mlp.shared_expert.down_proj",
496
+ "model.layers.26.mlp.shared_expert.gate_proj",
497
+ "model.layers.26.mlp.shared_expert.up_proj",
498
+ "model.layers.26.mlp.switch_mlp.down_proj",
499
+ "model.layers.26.mlp.switch_mlp.gate_proj",
500
+ "model.layers.26.mlp.switch_mlp.up_proj",
501
+ "model.layers.26.mlp_hyper_connection.input_mix_weight_down",
502
+ "model.layers.27.attn_hyper_connection.input_mix_weight_down",
503
+ "model.layers.27.mlp.shared_expert.down_proj",
504
+ "model.layers.27.mlp.shared_expert.gate_proj",
505
+ "model.layers.27.mlp.shared_expert.up_proj",
506
+ "model.layers.27.mlp.switch_mlp.down_proj",
507
+ "model.layers.27.mlp.switch_mlp.gate_proj",
508
+ "model.layers.27.mlp.switch_mlp.up_proj",
509
+ "model.layers.27.mlp_hyper_connection.input_mix_weight_down",
510
+ "model.layers.27.self_attn.indexer.index_qk_proj",
511
+ "model.layers.27.self_attn.k_proj",
512
+ "model.layers.27.self_attn.o_proj",
513
+ "model.layers.27.self_attn.q_proj",
514
+ "model.layers.27.self_attn.v_proj",
515
+ "model.layers.28.attn_hyper_connection.input_mix_weight_down",
516
+ "model.layers.28.linear_attn.in_proj_a",
517
+ "model.layers.28.linear_attn.in_proj_b",
518
+ "model.layers.28.linear_attn.in_proj_qkv",
519
+ "model.layers.28.linear_attn.in_proj_z",
520
+ "model.layers.28.linear_attn.out_proj",
521
+ "model.layers.28.mlp.shared_expert.down_proj",
522
+ "model.layers.28.mlp.shared_expert.gate_proj",
523
+ "model.layers.28.mlp.shared_expert.up_proj",
524
+ "model.layers.28.mlp.switch_mlp.down_proj",
525
+ "model.layers.28.mlp.switch_mlp.gate_proj",
526
+ "model.layers.28.mlp.switch_mlp.up_proj",
527
+ "model.layers.28.mlp_hyper_connection.input_mix_weight_down",
528
+ "model.layers.29.attn_hyper_connection.input_mix_weight_down",
529
+ "model.layers.29.linear_attn.in_proj_a",
530
+ "model.layers.29.linear_attn.in_proj_b",
531
+ "model.layers.29.linear_attn.in_proj_qkv",
532
+ "model.layers.29.linear_attn.in_proj_z",
533
+ "model.layers.29.linear_attn.out_proj",
534
+ "model.layers.29.mlp.shared_expert.down_proj",
535
+ "model.layers.29.mlp.shared_expert.gate_proj",
536
+ "model.layers.29.mlp.shared_expert.up_proj",
537
+ "model.layers.29.mlp.switch_mlp.down_proj",
538
+ "model.layers.29.mlp.switch_mlp.gate_proj",
539
+ "model.layers.29.mlp.switch_mlp.up_proj",
540
+ "model.layers.29.mlp_hyper_connection.input_mix_weight_down",
541
+ "model.layers.3.attn_hyper_connection.input_mix_weight_down",
542
+ "model.layers.3.mlp.shared_expert.down_proj",
543
+ "model.layers.3.mlp.shared_expert.gate_proj",
544
+ "model.layers.3.mlp.shared_expert.up_proj",
545
+ "model.layers.3.mlp.switch_mlp.down_proj",
546
+ "model.layers.3.mlp.switch_mlp.gate_proj",
547
+ "model.layers.3.mlp.switch_mlp.up_proj",
548
+ "model.layers.3.mlp_hyper_connection.input_mix_weight_down",
549
+ "model.layers.3.self_attn.indexer.index_qk_proj",
550
+ "model.layers.3.self_attn.k_proj",
551
+ "model.layers.3.self_attn.o_proj",
552
+ "model.layers.3.self_attn.q_proj",
553
+ "model.layers.3.self_attn.v_proj",
554
+ "model.layers.30.attn_hyper_connection.input_mix_weight_down",
555
+ "model.layers.30.linear_attn.in_proj_a",
556
+ "model.layers.30.linear_attn.in_proj_b",
557
+ "model.layers.30.linear_attn.in_proj_qkv",
558
+ "model.layers.30.linear_attn.in_proj_z",
559
+ "model.layers.30.linear_attn.out_proj",
560
+ "model.layers.30.mlp.shared_expert.down_proj",
561
+ "model.layers.30.mlp.shared_expert.gate_proj",
562
+ "model.layers.30.mlp.shared_expert.up_proj",
563
+ "model.layers.30.mlp.switch_mlp.down_proj",
564
+ "model.layers.30.mlp.switch_mlp.gate_proj",
565
+ "model.layers.30.mlp.switch_mlp.up_proj",
566
+ "model.layers.30.mlp_hyper_connection.input_mix_weight_down",
567
+ "model.layers.31.attn_hyper_connection.input_mix_weight_down",
568
+ "model.layers.31.mlp.shared_expert.down_proj",
569
+ "model.layers.31.mlp.shared_expert.gate_proj",
570
+ "model.layers.31.mlp.shared_expert.up_proj",
571
+ "model.layers.31.mlp.switch_mlp.down_proj",
572
+ "model.layers.31.mlp.switch_mlp.gate_proj",
573
+ "model.layers.31.mlp.switch_mlp.up_proj",
574
+ "model.layers.31.mlp_hyper_connection.input_mix_weight_down",
575
+ "model.layers.31.self_attn.indexer.index_qk_proj",
576
+ "model.layers.31.self_attn.k_proj",
577
+ "model.layers.31.self_attn.o_proj",
578
+ "model.layers.31.self_attn.q_proj",
579
+ "model.layers.31.self_attn.v_proj",
580
+ "model.layers.32.attn_hyper_connection.input_mix_weight_down",
581
+ "model.layers.32.linear_attn.in_proj_a",
582
+ "model.layers.32.linear_attn.in_proj_b",
583
+ "model.layers.32.linear_attn.in_proj_qkv",
584
+ "model.layers.32.linear_attn.in_proj_z",
585
+ "model.layers.32.linear_attn.out_proj",
586
+ "model.layers.32.mlp.shared_expert.down_proj",
587
+ "model.layers.32.mlp.shared_expert.gate_proj",
588
+ "model.layers.32.mlp.shared_expert.up_proj",
589
+ "model.layers.32.mlp.switch_mlp.down_proj",
590
+ "model.layers.32.mlp.switch_mlp.gate_proj",
591
+ "model.layers.32.mlp.switch_mlp.up_proj",
592
+ "model.layers.32.mlp_hyper_connection.input_mix_weight_down",
593
+ "model.layers.33.attn_hyper_connection.input_mix_weight_down",
594
+ "model.layers.33.linear_attn.in_proj_a",
595
+ "model.layers.33.linear_attn.in_proj_b",
596
+ "model.layers.33.linear_attn.in_proj_qkv",
597
+ "model.layers.33.linear_attn.in_proj_z",
598
+ "model.layers.33.linear_attn.out_proj",
599
+ "model.layers.33.mlp.shared_expert.down_proj",
600
+ "model.layers.33.mlp.shared_expert.gate_proj",
601
+ "model.layers.33.mlp.shared_expert.up_proj",
602
+ "model.layers.33.mlp.switch_mlp.down_proj",
603
+ "model.layers.33.mlp.switch_mlp.gate_proj",
604
+ "model.layers.33.mlp.switch_mlp.up_proj",
605
+ "model.layers.33.mlp_hyper_connection.input_mix_weight_down",
606
+ "model.layers.34.attn_hyper_connection.input_mix_weight_down",
607
+ "model.layers.34.linear_attn.in_proj_a",
608
+ "model.layers.34.linear_attn.in_proj_b",
609
+ "model.layers.34.linear_attn.in_proj_qkv",
610
+ "model.layers.34.linear_attn.in_proj_z",
611
+ "model.layers.34.linear_attn.out_proj",
612
+ "model.layers.34.mlp.shared_expert.down_proj",
613
+ "model.layers.34.mlp.shared_expert.gate_proj",
614
+ "model.layers.34.mlp.shared_expert.up_proj",
615
+ "model.layers.34.mlp.switch_mlp.down_proj",
616
+ "model.layers.34.mlp.switch_mlp.gate_proj",
617
+ "model.layers.34.mlp.switch_mlp.up_proj",
618
+ "model.layers.34.mlp_hyper_connection.input_mix_weight_down",
619
+ "model.layers.35.attn_hyper_connection.input_mix_weight_down",
620
+ "model.layers.35.mlp.shared_expert.down_proj",
621
+ "model.layers.35.mlp.shared_expert.gate_proj",
622
+ "model.layers.35.mlp.shared_expert.up_proj",
623
+ "model.layers.35.mlp.switch_mlp.down_proj",
624
+ "model.layers.35.mlp.switch_mlp.gate_proj",
625
+ "model.layers.35.mlp.switch_mlp.up_proj",
626
+ "model.layers.35.mlp_hyper_connection.input_mix_weight_down",
627
+ "model.layers.35.self_attn.indexer.index_qk_proj",
628
+ "model.layers.35.self_attn.k_proj",
629
+ "model.layers.35.self_attn.o_proj",
630
+ "model.layers.35.self_attn.q_proj",
631
+ "model.layers.35.self_attn.v_proj",
632
+ "model.layers.36.attn_hyper_connection.input_mix_weight_down",
633
+ "model.layers.36.linear_attn.in_proj_a",
634
+ "model.layers.36.linear_attn.in_proj_b",
635
+ "model.layers.36.linear_attn.in_proj_qkv",
636
+ "model.layers.36.linear_attn.in_proj_z",
637
+ "model.layers.36.linear_attn.out_proj",
638
+ "model.layers.36.mlp.shared_expert.down_proj",
639
+ "model.layers.36.mlp.shared_expert.gate_proj",
640
+ "model.layers.36.mlp.shared_expert.up_proj",
641
+ "model.layers.36.mlp.switch_mlp.down_proj",
642
+ "model.layers.36.mlp.switch_mlp.gate_proj",
643
+ "model.layers.36.mlp.switch_mlp.up_proj",
644
+ "model.layers.36.mlp_hyper_connection.input_mix_weight_down",
645
+ "model.layers.37.attn_hyper_connection.input_mix_weight_down",
646
+ "model.layers.37.linear_attn.in_proj_a",
647
+ "model.layers.37.linear_attn.in_proj_b",
648
+ "model.layers.37.linear_attn.in_proj_qkv",
649
+ "model.layers.37.linear_attn.in_proj_z",
650
+ "model.layers.37.linear_attn.out_proj",
651
+ "model.layers.37.mlp.shared_expert.down_proj",
652
+ "model.layers.37.mlp.shared_expert.gate_proj",
653
+ "model.layers.37.mlp.shared_expert.up_proj",
654
+ "model.layers.37.mlp.switch_mlp.down_proj",
655
+ "model.layers.37.mlp.switch_mlp.gate_proj",
656
+ "model.layers.37.mlp.switch_mlp.up_proj",
657
+ "model.layers.37.mlp_hyper_connection.input_mix_weight_down",
658
+ "model.layers.38.attn_hyper_connection.input_mix_weight_down",
659
+ "model.layers.38.linear_attn.in_proj_a",
660
+ "model.layers.38.linear_attn.in_proj_b",
661
+ "model.layers.38.linear_attn.in_proj_qkv",
662
+ "model.layers.38.linear_attn.in_proj_z",
663
+ "model.layers.38.linear_attn.out_proj",
664
+ "model.layers.38.mlp.shared_expert.down_proj",
665
+ "model.layers.38.mlp.shared_expert.gate_proj",
666
+ "model.layers.38.mlp.shared_expert.up_proj",
667
+ "model.layers.38.mlp.switch_mlp.down_proj",
668
+ "model.layers.38.mlp.switch_mlp.gate_proj",
669
+ "model.layers.38.mlp.switch_mlp.up_proj",
670
+ "model.layers.38.mlp_hyper_connection.input_mix_weight_down",
671
+ "model.layers.39.attn_hyper_connection.input_mix_weight_down",
672
+ "model.layers.39.mlp.shared_expert.down_proj",
673
+ "model.layers.39.mlp.shared_expert.gate_proj",
674
+ "model.layers.39.mlp.shared_expert.up_proj",
675
+ "model.layers.39.mlp.switch_mlp.down_proj",
676
+ "model.layers.39.mlp.switch_mlp.gate_proj",
677
+ "model.layers.39.mlp.switch_mlp.up_proj",
678
+ "model.layers.39.mlp_hyper_connection.input_mix_weight_down",
679
+ "model.layers.39.self_attn.indexer.index_qk_proj",
680
+ "model.layers.39.self_attn.k_proj",
681
+ "model.layers.39.self_attn.o_proj",
682
+ "model.layers.39.self_attn.q_proj",
683
+ "model.layers.39.self_attn.v_proj",
684
+ "model.layers.4.attn_hyper_connection.input_mix_weight_down",
685
+ "model.layers.4.linear_attn.in_proj_a",
686
+ "model.layers.4.linear_attn.in_proj_b",
687
+ "model.layers.4.linear_attn.in_proj_qkv",
688
+ "model.layers.4.linear_attn.in_proj_z",
689
+ "model.layers.4.linear_attn.out_proj",
690
+ "model.layers.4.mlp.shared_expert.down_proj",
691
+ "model.layers.4.mlp.shared_expert.gate_proj",
692
+ "model.layers.4.mlp.shared_expert.up_proj",
693
+ "model.layers.4.mlp.switch_mlp.down_proj",
694
+ "model.layers.4.mlp.switch_mlp.gate_proj",
695
+ "model.layers.4.mlp.switch_mlp.up_proj",
696
+ "model.layers.4.mlp_hyper_connection.input_mix_weight_down",
697
+ "model.layers.40.attn_hyper_connection.input_mix_weight_down",
698
+ "model.layers.40.linear_attn.in_proj_a",
699
+ "model.layers.40.linear_attn.in_proj_b",
700
+ "model.layers.40.linear_attn.in_proj_qkv",
701
+ "model.layers.40.linear_attn.in_proj_z",
702
+ "model.layers.40.linear_attn.out_proj",
703
+ "model.layers.40.mlp.shared_expert.down_proj",
704
+ "model.layers.40.mlp.shared_expert.gate_proj",
705
+ "model.layers.40.mlp.shared_expert.up_proj",
706
+ "model.layers.40.mlp.switch_mlp.down_proj",
707
+ "model.layers.40.mlp.switch_mlp.gate_proj",
708
+ "model.layers.40.mlp.switch_mlp.up_proj",
709
+ "model.layers.40.mlp_hyper_connection.input_mix_weight_down",
710
+ "model.layers.41.attn_hyper_connection.input_mix_weight_down",
711
+ "model.layers.41.linear_attn.in_proj_a",
712
+ "model.layers.41.linear_attn.in_proj_b",
713
+ "model.layers.41.linear_attn.in_proj_qkv",
714
+ "model.layers.41.linear_attn.in_proj_z",
715
+ "model.layers.41.linear_attn.out_proj",
716
+ "model.layers.41.mlp.shared_expert.down_proj",
717
+ "model.layers.41.mlp.shared_expert.gate_proj",
718
+ "model.layers.41.mlp.shared_expert.up_proj",
719
+ "model.layers.41.mlp.switch_mlp.down_proj",
720
+ "model.layers.41.mlp.switch_mlp.gate_proj",
721
+ "model.layers.41.mlp.switch_mlp.up_proj",
722
+ "model.layers.41.mlp_hyper_connection.input_mix_weight_down",
723
+ "model.layers.42.attn_hyper_connection.input_mix_weight_down",
724
+ "model.layers.42.linear_attn.in_proj_a",
725
+ "model.layers.42.linear_attn.in_proj_b",
726
+ "model.layers.42.linear_attn.in_proj_qkv",
727
+ "model.layers.42.linear_attn.in_proj_z",
728
+ "model.layers.42.linear_attn.out_proj",
729
+ "model.layers.42.mlp.shared_expert.down_proj",
730
+ "model.layers.42.mlp.shared_expert.gate_proj",
731
+ "model.layers.42.mlp.shared_expert.up_proj",
732
+ "model.layers.42.mlp.switch_mlp.down_proj",
733
+ "model.layers.42.mlp.switch_mlp.gate_proj",
734
+ "model.layers.42.mlp.switch_mlp.up_proj",
735
+ "model.layers.42.mlp_hyper_connection.input_mix_weight_down",
736
+ "model.layers.43.attn_hyper_connection.input_mix_weight_down",
737
+ "model.layers.43.mlp.shared_expert.down_proj",
738
+ "model.layers.43.mlp.shared_expert.gate_proj",
739
+ "model.layers.43.mlp.shared_expert.up_proj",
740
+ "model.layers.43.mlp.switch_mlp.down_proj",
741
+ "model.layers.43.mlp.switch_mlp.gate_proj",
742
+ "model.layers.43.mlp.switch_mlp.up_proj",
743
+ "model.layers.43.mlp_hyper_connection.input_mix_weight_down",
744
+ "model.layers.43.self_attn.indexer.index_qk_proj",
745
+ "model.layers.43.self_attn.k_proj",
746
+ "model.layers.43.self_attn.o_proj",
747
+ "model.layers.43.self_attn.q_proj",
748
+ "model.layers.43.self_attn.v_proj",
749
+ "model.layers.44.attn_hyper_connection.input_mix_weight_down",
750
+ "model.layers.44.linear_attn.in_proj_a",
751
+ "model.layers.44.linear_attn.in_proj_b",
752
+ "model.layers.44.linear_attn.in_proj_qkv",
753
+ "model.layers.44.linear_attn.in_proj_z",
754
+ "model.layers.44.linear_attn.out_proj",
755
+ "model.layers.44.mlp.shared_expert.down_proj",
756
+ "model.layers.44.mlp.shared_expert.gate_proj",
757
+ "model.layers.44.mlp.shared_expert.up_proj",
758
+ "model.layers.44.mlp.switch_mlp.down_proj",
759
+ "model.layers.44.mlp.switch_mlp.gate_proj",
760
+ "model.layers.44.mlp.switch_mlp.up_proj",
761
+ "model.layers.44.mlp_hyper_connection.input_mix_weight_down",
762
+ "model.layers.45.attn_hyper_connection.input_mix_weight_down",
763
+ "model.layers.45.linear_attn.in_proj_a",
764
+ "model.layers.45.linear_attn.in_proj_b",
765
+ "model.layers.45.linear_attn.in_proj_qkv",
766
+ "model.layers.45.linear_attn.in_proj_z",
767
+ "model.layers.45.linear_attn.out_proj",
768
+ "model.layers.45.mlp.shared_expert.down_proj",
769
+ "model.layers.45.mlp.shared_expert.gate_proj",
770
+ "model.layers.45.mlp.shared_expert.up_proj",
771
+ "model.layers.45.mlp.switch_mlp.down_proj",
772
+ "model.layers.45.mlp.switch_mlp.gate_proj",
773
+ "model.layers.45.mlp.switch_mlp.up_proj",
774
+ "model.layers.45.mlp_hyper_connection.input_mix_weight_down",
775
+ "model.layers.46.attn_hyper_connection.input_mix_weight_down",
776
+ "model.layers.46.linear_attn.in_proj_a",
777
+ "model.layers.46.linear_attn.in_proj_b",
778
+ "model.layers.46.linear_attn.in_proj_qkv",
779
+ "model.layers.46.linear_attn.in_proj_z",
780
+ "model.layers.46.linear_attn.out_proj",
781
+ "model.layers.46.mlp.shared_expert.down_proj",
782
+ "model.layers.46.mlp.shared_expert.gate_proj",
783
+ "model.layers.46.mlp.shared_expert.up_proj",
784
+ "model.layers.46.mlp.switch_mlp.down_proj",
785
+ "model.layers.46.mlp.switch_mlp.gate_proj",
786
+ "model.layers.46.mlp.switch_mlp.up_proj",
787
+ "model.layers.46.mlp_hyper_connection.input_mix_weight_down",
788
+ "model.layers.47.attn_hyper_connection.input_mix_weight_down",
789
+ "model.layers.47.mlp.shared_expert.down_proj",
790
+ "model.layers.47.mlp.shared_expert.gate_proj",
791
+ "model.layers.47.mlp.shared_expert.up_proj",
792
+ "model.layers.47.mlp.switch_mlp.down_proj",
793
+ "model.layers.47.mlp.switch_mlp.gate_proj",
794
+ "model.layers.47.mlp.switch_mlp.up_proj",
795
+ "model.layers.47.mlp_hyper_connection.input_mix_weight_down",
796
+ "model.layers.47.self_attn.indexer.index_qk_proj",
797
+ "model.layers.47.self_attn.k_proj",
798
+ "model.layers.47.self_attn.o_proj",
799
+ "model.layers.47.self_attn.q_proj",
800
+ "model.layers.47.self_attn.v_proj",
801
+ "model.layers.5.attn_hyper_connection.input_mix_weight_down",
802
+ "model.layers.5.linear_attn.in_proj_a",
803
+ "model.layers.5.linear_attn.in_proj_b",
804
+ "model.layers.5.linear_attn.in_proj_qkv",
805
+ "model.layers.5.linear_attn.in_proj_z",
806
+ "model.layers.5.linear_attn.out_proj",
807
+ "model.layers.5.mlp.shared_expert.down_proj",
808
+ "model.layers.5.mlp.shared_expert.gate_proj",
809
+ "model.layers.5.mlp.shared_expert.up_proj",
810
+ "model.layers.5.mlp.switch_mlp.down_proj",
811
+ "model.layers.5.mlp.switch_mlp.gate_proj",
812
+ "model.layers.5.mlp.switch_mlp.up_proj",
813
+ "model.layers.5.mlp_hyper_connection.input_mix_weight_down",
814
+ "model.layers.6.attn_hyper_connection.input_mix_weight_down",
815
+ "model.layers.6.linear_attn.in_proj_a",
816
+ "model.layers.6.linear_attn.in_proj_b",
817
+ "model.layers.6.linear_attn.in_proj_qkv",
818
+ "model.layers.6.linear_attn.in_proj_z",
819
+ "model.layers.6.linear_attn.out_proj",
820
+ "model.layers.6.mlp.shared_expert.down_proj",
821
+ "model.layers.6.mlp.shared_expert.gate_proj",
822
+ "model.layers.6.mlp.shared_expert.up_proj",
823
+ "model.layers.6.mlp.switch_mlp.down_proj",
824
+ "model.layers.6.mlp.switch_mlp.gate_proj",
825
+ "model.layers.6.mlp.switch_mlp.up_proj",
826
+ "model.layers.6.mlp_hyper_connection.input_mix_weight_down",
827
+ "model.layers.7.attn_hyper_connection.input_mix_weight_down",
828
+ "model.layers.7.mlp.shared_expert.down_proj",
829
+ "model.layers.7.mlp.shared_expert.gate_proj",
830
+ "model.layers.7.mlp.shared_expert.up_proj",
831
+ "model.layers.7.mlp.switch_mlp.down_proj",
832
+ "model.layers.7.mlp.switch_mlp.gate_proj",
833
+ "model.layers.7.mlp.switch_mlp.up_proj",
834
+ "model.layers.7.mlp_hyper_connection.input_mix_weight_down",
835
+ "model.layers.7.self_attn.indexer.index_qk_proj",
836
+ "model.layers.7.self_attn.k_proj",
837
+ "model.layers.7.self_attn.o_proj",
838
+ "model.layers.7.self_attn.q_proj",
839
+ "model.layers.7.self_attn.v_proj",
840
+ "model.layers.8.attn_hyper_connection.input_mix_weight_down",
841
+ "model.layers.8.linear_attn.in_proj_a",
842
+ "model.layers.8.linear_attn.in_proj_b",
843
+ "model.layers.8.linear_attn.in_proj_qkv",
844
+ "model.layers.8.linear_attn.in_proj_z",
845
+ "model.layers.8.linear_attn.out_proj",
846
+ "model.layers.8.mlp.shared_expert.down_proj",
847
+ "model.layers.8.mlp.shared_expert.gate_proj",
848
+ "model.layers.8.mlp.shared_expert.up_proj",
849
+ "model.layers.8.mlp.switch_mlp.down_proj",
850
+ "model.layers.8.mlp.switch_mlp.gate_proj",
851
+ "model.layers.8.mlp.switch_mlp.up_proj",
852
+ "model.layers.8.mlp_hyper_connection.input_mix_weight_down",
853
+ "model.layers.9.attn_hyper_connection.input_mix_weight_down",
854
+ "model.layers.9.linear_attn.in_proj_a",
855
+ "model.layers.9.linear_attn.in_proj_b",
856
+ "model.layers.9.linear_attn.in_proj_qkv",
857
+ "model.layers.9.linear_attn.in_proj_z",
858
+ "model.layers.9.linear_attn.out_proj",
859
+ "model.layers.9.mlp.shared_expert.down_proj",
860
+ "model.layers.9.mlp.shared_expert.gate_proj",
861
+ "model.layers.9.mlp.shared_expert.up_proj",
862
+ "model.layers.9.mlp.switch_mlp.down_proj",
863
+ "model.layers.9.mlp.switch_mlp.gate_proj",
864
+ "model.layers.9.mlp.switch_mlp.up_proj",
865
+ "model.layers.9.mlp_hyper_connection.input_mix_weight_down"
866
+ ],
867
+ "missing": [],
868
+ "mismatched": [],
869
+ "zero_count_experts": 63
870
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0997f410c57a1f4e53b09e4be8f4a172d90edd9564368fb0847030937229b9f3
3
+ size 12809320
tokenizer_config.json ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "248044": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "248045": {
13
+ "content": "<|im_start|>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "248046": {
21
+ "content": "<|im_end|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "248047": {
29
+ "content": "<|object_ref_start|>",
30
+ "lstrip": false,
31
+ "normalized": false,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "248048": {
37
+ "content": "<|object_ref_end|>",
38
+ "lstrip": false,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ },
44
+ "248049": {
45
+ "content": "<|box_start|>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false,
50
+ "special": true
51
+ },
52
+ "248050": {
53
+ "content": "<|box_end|>",
54
+ "lstrip": false,
55
+ "normalized": false,
56
+ "rstrip": false,
57
+ "single_word": false,
58
+ "special": true
59
+ },
60
+ "248051": {
61
+ "content": "<|quad_start|>",
62
+ "lstrip": false,
63
+ "normalized": false,
64
+ "rstrip": false,
65
+ "single_word": false,
66
+ "special": true
67
+ },
68
+ "248052": {
69
+ "content": "<|quad_end|>",
70
+ "lstrip": false,
71
+ "normalized": false,
72
+ "rstrip": false,
73
+ "single_word": false,
74
+ "special": true
75
+ },
76
+ "248053": {
77
+ "content": "<|vision_start|>",
78
+ "lstrip": false,
79
+ "normalized": false,
80
+ "rstrip": false,
81
+ "single_word": false,
82
+ "special": true
83
+ },
84
+ "248054": {
85
+ "content": "<|vision_end|>",
86
+ "lstrip": false,
87
+ "normalized": false,
88
+ "rstrip": false,
89
+ "single_word": false,
90
+ "special": true
91
+ },
92
+ "248055": {
93
+ "content": "<|vision_pad|>",
94
+ "lstrip": false,
95
+ "normalized": false,
96
+ "rstrip": false,
97
+ "single_word": false,
98
+ "special": true
99
+ },
100
+ "248056": {
101
+ "content": "<|image_pad|>",
102
+ "lstrip": false,
103
+ "normalized": false,
104
+ "rstrip": false,
105
+ "single_word": false,
106
+ "special": true
107
+ },
108
+ "248057": {
109
+ "content": "<|video_pad|>",
110
+ "lstrip": false,
111
+ "normalized": false,
112
+ "rstrip": false,
113
+ "single_word": false,
114
+ "special": true
115
+ },
116
+ "248058": {
117
+ "content": "<tool_call>",
118
+ "lstrip": false,
119
+ "normalized": false,
120
+ "rstrip": false,
121
+ "single_word": false,
122
+ "special": false
123
+ },
124
+ "248059": {
125
+ "content": "</tool_call>",
126
+ "lstrip": false,
127
+ "normalized": false,
128
+ "rstrip": false,
129
+ "single_word": false,
130
+ "special": false
131
+ },
132
+ "248060": {
133
+ "content": "<|fim_prefix|>",
134
+ "lstrip": false,
135
+ "normalized": false,
136
+ "rstrip": false,
137
+ "single_word": false,
138
+ "special": false
139
+ },
140
+ "248061": {
141
+ "content": "<|fim_middle|>",
142
+ "lstrip": false,
143
+ "normalized": false,
144
+ "rstrip": false,
145
+ "single_word": false,
146
+ "special": false
147
+ },
148
+ "248062": {
149
+ "content": "<|fim_suffix|>",
150
+ "lstrip": false,
151
+ "normalized": false,
152
+ "rstrip": false,
153
+ "single_word": false,
154
+ "special": false
155
+ },
156
+ "248063": {
157
+ "content": "<|fim_pad|>",
158
+ "lstrip": false,
159
+ "normalized": false,
160
+ "rstrip": false,
161
+ "single_word": false,
162
+ "special": false
163
+ },
164
+ "248064": {
165
+ "content": "<|repo_name|>",
166
+ "lstrip": false,
167
+ "normalized": false,
168
+ "rstrip": false,
169
+ "single_word": false,
170
+ "special": false
171
+ },
172
+ "248065": {
173
+ "content": "<|file_sep|>",
174
+ "lstrip": false,
175
+ "normalized": false,
176
+ "rstrip": false,
177
+ "single_word": false,
178
+ "special": false
179
+ },
180
+ "248066": {
181
+ "content": "<tool_response>",
182
+ "lstrip": false,
183
+ "normalized": false,
184
+ "rstrip": false,
185
+ "single_word": false,
186
+ "special": false
187
+ },
188
+ "248067": {
189
+ "content": "</tool_response>",
190
+ "lstrip": false,
191
+ "normalized": false,
192
+ "rstrip": false,
193
+ "single_word": false,
194
+ "special": false
195
+ },
196
+ "248068": {
197
+ "content": "<think>",
198
+ "lstrip": false,
199
+ "normalized": false,
200
+ "rstrip": false,
201
+ "single_word": false,
202
+ "special": false
203
+ },
204
+ "248069": {
205
+ "content": "</think>",
206
+ "lstrip": false,
207
+ "normalized": false,
208
+ "rstrip": false,
209
+ "single_word": false,
210
+ "special": false
211
+ },
212
+ "248070": {
213
+ "content": "<|audio_start|>",
214
+ "lstrip": false,
215
+ "normalized": false,
216
+ "rstrip": false,
217
+ "single_word": false,
218
+ "special": true
219
+ },
220
+ "248071": {
221
+ "content": "<|audio_end|>",
222
+ "lstrip": false,
223
+ "normalized": false,
224
+ "rstrip": false,
225
+ "single_word": false,
226
+ "special": true
227
+ },
228
+ "248072": {
229
+ "content": "<tts_pad>",
230
+ "lstrip": false,
231
+ "normalized": false,
232
+ "rstrip": false,
233
+ "single_word": false,
234
+ "special": true
235
+ },
236
+ "248073": {
237
+ "content": "<tts_text_bos>",
238
+ "lstrip": false,
239
+ "normalized": false,
240
+ "rstrip": false,
241
+ "single_word": false,
242
+ "special": true
243
+ },
244
+ "248074": {
245
+ "content": "<tts_text_eod>",
246
+ "lstrip": false,
247
+ "normalized": false,
248
+ "rstrip": false,
249
+ "single_word": false,
250
+ "special": true
251
+ },
252
+ "248075": {
253
+ "content": "<tts_text_bos_single>",
254
+ "lstrip": false,
255
+ "normalized": false,
256
+ "rstrip": false,
257
+ "single_word": false,
258
+ "special": true
259
+ },
260
+ "248076": {
261
+ "content": "<|audio_pad|>",
262
+ "lstrip": false,
263
+ "normalized": false,
264
+ "rstrip": false,
265
+ "single_word": false,
266
+ "special": true
267
+ }
268
+ },
269
+ "additional_special_tokens": [
270
+ "<|im_start|>",
271
+ "<|im_end|>",
272
+ "<|object_ref_start|>",
273
+ "<|object_ref_end|>",
274
+ "<|box_start|>",
275
+ "<|box_end|>",
276
+ "<|quad_start|>",
277
+ "<|quad_end|>",
278
+ "<|vision_start|>",
279
+ "<|vision_end|>",
280
+ "<|vision_pad|>",
281
+ "<|image_pad|>",
282
+ "<|video_pad|>"
283
+ ],
284
+ "bos_token": null,
285
+ "chat_template": "{%- set image_count = namespace(value=0) %}\n{%- set video_count = namespace(value=0) %}\n{%- macro render_content(content, do_vision_count, is_system_content=false) %}\n {%- if content is string %}\n {{- content }}\n {%- elif content is iterable and content is not mapping %}\n {%- for item in content %}\n {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain images.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id %}\n {{- 'Picture ' ~ image_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|image_pad|><|vision_end|>' }}\n {%- elif 'video' in item or item.type == 'video' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain videos.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id %}\n {{- 'Video ' ~ video_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|video_pad|><|vision_end|>' }}\n {%- elif 'text' in item %}\n {{- item.text }}\n {%- else %}\n {{- raise_exception('Unexpected item type in content.') }}\n {%- endif %}\n {%- endfor %}\n {%- elif content is none or content is undefined %}\n {{- '' }}\n {%- else %}\n {{- raise_exception('Unexpected content type.') }}\n {%- endif %}\n{%- endmacro %}\n{%- if not messages %}\n {{- raise_exception('No messages provided.') }}\n{%- endif %}\n{%- set reasoning_instructions = '' %}\n{%- if enable_thinking is undefined or enable_thinking is true %}\n {%- set resolved_reasoning_effort = reasoning_effort|default('xhigh') %}\n {%- if resolved_reasoning_effort not in ('xhigh', 'medium', 'low') %}\n {{- raise_exception('Unexpected reasoning effort ' ~ reasoning_effort ~ '. Supported types are xhigh (default), medium, and low.') }}\n {%- endif %}\n {%- if resolved_reasoning_effort == 'xhigh' %}\n {%- set reasoning_instructions = 'Reasoning effort is set to xhigh. Please think carefully through the task, validate key assumptions, consider plausible alternatives, and prioritize correctness, consistency, and clarity in the final answer.' %}\n {%- elif resolved_reasoning_effort == 'low' %}\n {%- set reasoning_instructions = 'Reasoning effort is set to low. Keep your thinking brief and focused, moving directly to the conclusion without unnecessary elaboration.' %}\n {%- endif %}\n{%- endif %}\n{%- if tools and tools is iterable and tools is not mapping %}\n {{- '<|im_start|>system\\n' }}\n {%- if reasoning_instructions %}\n {{- reasoning_instructions + '\\n\\n' }}\n {%- endif %}\n {{- \"# Tools\\n\\nYou have access to the following functions:\\n\\n<tools>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n</tools>\" }}\n {{- '\\n\\nIf you choose to call a function ONLY reply in the following format with NO suffix:\\n\\n<tool_call>\\n<function=example_function_name>\\n<parameter=example_parameter_1>\\nvalue_1\\n</parameter>\\n<parameter=example_parameter_2>\\nThis is the value for the second parameter\\nthat can span\\nmultiple lines\\n</parameter>\\n</function>\\n</tool_call>\\n\\n<IMPORTANT>\\nReminder:\\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\\n- Required parameters MUST be specified\\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\\n</IMPORTANT>' }}\n {%- if messages[0].role == 'system' %}\n {%- set content = render_content(messages[0].content, false, true)|trim %}\n {%- if content %}\n {{- '\\n\\n' + content }}\n {%- endif %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n{%- else %}\n {%- if messages[0].role == 'system' %}\n {%- set content = render_content(messages[0].content, false, true)|trim %}\n {%- if content %}\n {{- '<|im_start|>system\\n' + (reasoning_instructions + '\\n\\n' if reasoning_instructions else '') + content + '<|im_end|>\\n' }}\n {%- elif reasoning_instructions %}\n {{- '<|im_start|>system\\n' + reasoning_instructions + '<|im_end|>\\n' }}\n {%- endif %}\n {%- elif reasoning_instructions %}\n {{- '<|im_start|>system\\n' + reasoning_instructions + '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for message in messages[::-1] %}\n {%- set index = (messages|length - 1) - loop.index0 %}\n {%- if ns.multi_step_tool and message.role == \"user\" %}\n {%- set content = render_content(message.content, false)|trim %}\n {%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}\n {%- set ns.multi_step_tool = false %}\n {%- set ns.last_query_index = index %}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if ns.multi_step_tool %}\n {{- raise_exception('No user query found in messages.') }}\n{%- endif %}\n{%- for message in messages %}\n {%- set content = render_content(message.content, true)|trim %}\n {%- if message.role == \"system\" %}\n {%- if not loop.first %}\n {{- raise_exception('System message must be at the beginning.') }}\n {%- endif %}\n {%- elif message.role == \"user\" %}\n {{- '<|im_start|>' + message.role + '\\n' + content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {%- set reasoning_content = '' %}\n {%- if message.reasoning_content is string %}\n {%- set reasoning_content = message.reasoning_content %}\n {%- endif %}\n {%- set reasoning_content = reasoning_content|trim %}\n {%- if preserve_thinking is undefined or preserve_thinking is true or loop.index0 > ns.last_query_index %}\n {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content + '\\n</think>\\n\\n' + content }}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}\n {%- for tool_call in message.tool_calls %}\n {%- if tool_call.function is defined %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {%- if loop.first %}\n {%- if content|trim %}\n {{- '\\n\\n<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- else %}\n {{- '<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- endif %}\n {%- else %}\n {{- '\\n<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- endif %}\n {%- if tool_call.arguments is defined and tool_call.arguments != '' %}\n {%- for args_name, args_value in tool_call.arguments|items %}\n {{- '<parameter=' + args_name + '>\\n' }}\n {%- set args_value = args_value | string if args_value is string else args_value | tojson | safe %}\n {{- args_value }}\n {{- '\\n</parameter>\\n' }}\n {%- endfor %}\n {%- endif %}\n {{- '</function>\\n</tool_call>' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.previtem and loop.previtem.role != \"tool\" %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {{- content }}\n {{- '\\n</tool_response>' }}\n {%- if not loop.last and loop.nextitem.role != \"tool\" %}\n {{- '<|im_end|>\\n' }}\n {%- elif loop.last %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- else %}\n {{- raise_exception('Unexpected message role.') }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n {%- if enable_thinking is defined and enable_thinking is false %}\n {{- '<think>\\n\\n</think>\\n\\n' }}\n {%- else %}\n {{- '<think>\\n' }}\n {%- endif %}\n{%- endif %}",
286
+ "clean_up_tokenization_spaces": false,
287
+ "eos_token": "<|im_end|>",
288
+ "errors": "replace",
289
+ "model_max_length": 262144,
290
+ "pad_token": "<|endoftext|>",
291
+ "split_special_tokens": false,
292
+ "tokenizer_class": "Qwen2Tokenizer",
293
+ "unk_token": null,
294
+ "add_bos_token": false,
295
+ "pretokenize_regex": "(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\\r\\n\\p{L}\\p{N}]?[\\p{L}\\p{M}]+|\\p{N}| ?[^\\s\\p{L}\\p{M}\\p{N}]+[\\r\\n]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+",
296
+ "extra_special_tokens": {
297
+ "audio_bos_token": "<|audio_start|>",
298
+ "audio_eos_token": "<|audio_end|>",
299
+ "audio_token": "<|audio_pad|>",
300
+ "image_token": "<|image_pad|>",
301
+ "video_token": "<|video_pad|>",
302
+ "vision_bos_token": "<|vision_start|>",
303
+ "vision_eos_token": "<|vision_end|>"
304
+ }
305
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff