jedisct1 commited on
Commit
2b5444a
·
verified ·
1 Parent(s): ebb20bd

Add model card and configuration

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,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ---
24
+
25
+ # Qwen3.8 Flash Next oQ4e 128K for oMLX
26
+
27
+ 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.
28
+
29
+ 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 MTP head. It is not an official Qwen release.
30
+
31
+ ## Quantization
32
+
33
+ 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:
34
+
35
+ - The token embedding and language-model head use 4-bit affine quantization.
36
+ - Large linear and routed-expert weights use importance-matrix-guided mixed precision.
37
+ - Sensitive attention and shared-expert matrices retain higher precision, including 8-bit floors.
38
+ - Routers, recurrent state, convolutions, normalization, residual controls, and related control tensors retain BF16.
39
+ - 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.
40
+
41
+ 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.
42
+
43
+ The resulting checkpoint contains 18 safetensors shards and occupies 86.608 GiB. Its index contains 2,854 tensors.
44
+
45
+ ## Runtime requirements
46
+
47
+ 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`.
48
+
49
+ The tested software stack is:
50
+
51
+ - Apple Silicon
52
+ - MLX and mlx-metal 0.32.1
53
+ - The MLX-LM package bundled with oMLX 0.6.3rc3
54
+ - oMLX 0.6.3rc3
55
+ - MTP disabled
56
+
57
+ 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. [Pull request #3163](https://github.com/jundot/omlx/pull/3163) adds experimental MTP decoding, but MTP was not used here.
58
+
59
+ Install the tested MLX runtime inside the downloaded model directory, then launch the bundled oMLX wrapper:
60
+
61
+ ```sh
62
+ hf download jedisct1/Qwen3.8-Flash-Next-oQ4e-128k \
63
+ --local-dir models/Qwen3.8-Flash-Next-oQ4e-128k
64
+ cd models/Qwen3.8-Flash-Next-oQ4e-128k
65
+ uv pip install --target .mlx-runtime mlx==0.32.1 mlx-metal==0.32.1
66
+ zsh omlx_support/serve
67
+ ```
68
+
69
+ 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.
70
+
71
+ 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. The context budget is total input plus generated output, so keep that total at or below 131,072 tokens.
72
+
73
+ ## Recommended generation settings
74
+
75
+ Thinking mode is enabled by default. The upstream recommended settings are included in `generation_config.json`:
76
+
77
+ ```text
78
+ temperature: 1.0
79
+ top_p: 0.95
80
+ top_k: 20
81
+ min_p: 0.0
82
+ presence_penalty: 0.0
83
+ repetition_penalty: 1.0
84
+ ```
85
+
86
+ For multi-turn agents, preserve `reasoning_content` between tool turns and keep `preserve_thinking` enabled.
87
+
88
+ ## Validation
89
+
90
+ The artifact validator found:
91
+
92
+ - 18 expected and readable safetensors shards
93
+ - 2,854 indexed and stored tensors
94
+ - No missing, unindexed, duplicated, or misplaced tensors
95
+ - All 128 PLE mixed-bit overrides applied as intended
96
+ - No missing or mismatched importance-matrix entries for measurable modules
97
+
98
+ On an M5 Max with 128 GiB of unified memory, the SSD-backed PLE implementation loaded 63.30 GB of Metal-backed model arrays. A fresh request containing 131,071 uncached prompt tokens generated one token, for exactly 131,072 total tokens, with oMLX's balanced memory guard enabled.
99
+
100
+ ## Tool calling
101
+
102
+ The original chat template and XML tool-call protocol are included. Direct structured tool calls, continuation after a tool result, and a multi-turn file-write, checksum, and read-back workflow were tested successfully through oMLX and Swival.
103
+
104
+ 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.
105
+
106
+ The duplicate-call protection used during validation is implemented by Swival and is not part of these model weights.
107
+
108
+ ## Limitations
109
+
110
+ - This is a text-only conversion. Image and video inputs are unsupported.
111
+ - MTP speculative decoding is unsupported by this checkpoint.
112
+ - The architecture supports 262,144 native tokens, but this conversion was validated and operationally limited to 131,072 total tokens.
113
+ - Only the stated Apple Silicon and oMLX configuration was tested.
114
+ - Quantization can reduce quality relative to the FP8 source.
115
+ - The model can produce incorrect content, malformed tool calls, duplicate tool calls, or unsafe actions. Tool execution requires independent validation and appropriate permission boundaries.
116
+ - The model inherits the limitations and intended-use considerations of the upstream Qwen model.
117
+
118
+ ## Source and license
119
+
120
+ The conversion was produced from revision `bcd9f01ddc9cff2316eb84281bebcd5b058bddce` of [Qwen/Qwen3.8-Flash-Next-FP8](https://huggingface.co/Qwen/Qwen3.8-Flash-Next-FP8).
121
+
122
+ 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.
123
+
124
+ The bundled `omlx_support` code is distributed under the Apache License 2.0 in `omlx_support/LICENSE` and includes modifications to the implementation proposed in oMLX pull request #3161.
125
+
126
+ ## Citation
127
+
128
+ ```bibtex
129
+ @techreport{qwen2026design,
130
+ title = {On the Design of {Qwen3.8-Next} Architecture: Evaluation, Efficiency, and Training Stability},
131
+ author = {{Qwen Team}},
132
+ institution = {Alibaba Group},
133
+ month = {August},
134
+ year = {2026}
135
+ }
136
+
137
+ @misc{qwen3.8flashnext,
138
+ title = {{Qwen3.8-Flash-Next}: A New Architecture, Towards Ultimate Cost-Efficiency},
139
+ author = {{Qwen Team}},
140
+ month = {August},
141
+ year = {2026},
142
+ url = {https://qwen.ai/blog?id=qwen3.8-flash-next}
143
+ }
144
+ ```
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,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": 1,
3
+ "models": {
4
+ "Qwen3.8-Flash-Next-oQ4e-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": false,
31
+ "vlm_mtp_enabled": false,
32
+ "is_pinned": false,
33
+ "is_default": true,
34
+ "trust_remote_code": false,
35
+ "display_name": "Qwen3.8 Flash Next oQ4e 128k",
36
+ "description": "Text-only tool-use profile with conservative memory settings."
37
+ }
38
+ }
39
+ }
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,1160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from oMLX PR #3161 and modified for mixed-bit SSD-backed PLE.
2
+ # Licensed under the Apache License 2.0. See LICENSE.
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ import math
8
+ import mmap
9
+ import os
10
+ import struct
11
+ from dataclasses import dataclass, field
12
+ from pathlib import Path
13
+ from typing import Any, Dict, List, Optional
14
+
15
+ import mlx.core as mx
16
+ import mlx.nn as nn
17
+ import numpy as np
18
+
19
+ from mlx_lm.models.activations import swiglu
20
+ from mlx_lm.models.base import BaseModelArgs, create_ssm_mask
21
+ from mlx_lm.models.cache import ArraysCache, KVCache, QuantizedKVCache
22
+ from mlx_lm.models.gated_delta import gated_delta_update
23
+ from mlx_lm.models.switch_layers import SwitchGLU
24
+
25
+
26
+ @dataclass
27
+ class ModelArgs(BaseModelArgs):
28
+ model_type: str = "qwen4_exp"
29
+ vocab_size: int = 248320
30
+ hidden_size: int = 2048
31
+ num_hidden_layers: int = 40
32
+ num_attention_heads: int = 16
33
+ num_key_value_heads: int = 2
34
+ hidden_act: str = "silu"
35
+ max_position_embeddings: int = 32768
36
+ rms_norm_eps: float = 1e-6
37
+ tie_word_embeddings: bool = False
38
+ attention_bias: bool = False
39
+ attention_dropout: float = 0.0
40
+ head_dim: int = 256
41
+ linear_conv_kernel_dim: int = 4
42
+ linear_key_head_dim: int = 128
43
+ linear_value_head_dim: int = 128
44
+ linear_num_key_heads: int = 16
45
+ linear_num_value_heads: int = 32
46
+ moe_intermediate_size: int = 512
47
+ shared_expert_intermediate_size: int = 512
48
+ num_experts_per_tok: int = 10
49
+ num_experts: int = 512
50
+ layer_types: List[str] = field(default_factory=list)
51
+ hc_count: int = 4
52
+ hc_lowrank: int = 320
53
+ ple_layer_ids: List[int] = field(default_factory=list)
54
+ ple_embed_dim: Optional[int] = None
55
+ ple_conv_kernel_size: int = 4
56
+ ngram_size: int = 3
57
+ heads_per_ngram: int = 8
58
+ ngram_vocab_size_base: int = 20_000_000
59
+ make_ngram_vocab_size_divisible_by: int = 128
60
+ seed: int = 1234
61
+ split_ngram_parts: int = 512
62
+ indexer_n_heads: Optional[int] = None
63
+ indexer_kv_heads: Optional[int] = None
64
+ indexer_head_dim: Optional[int] = None
65
+ indexer_budget: Optional[int] = None
66
+ indexer_compress_ratio: Optional[int] = None
67
+ norm_topk_prob: bool = True
68
+ output_gate_type: Optional[str] = None
69
+ eos_token_id: Optional[int | List[int]] = None
70
+ rope_theta: float = 10000.0
71
+ partial_rotary_factor: float = 1.0
72
+ rope_parameters: Optional[Dict[str, Any]] = None
73
+
74
+ @classmethod
75
+ def from_dict(cls, params):
76
+ source = dict(params.get("text_config", params))
77
+ source["model_type"] = params.get("model_type", source.get("model_type", "qwen4_exp"))
78
+ if params.get("eos_token_id") is not None:
79
+ source["eos_token_id"] = params["eos_token_id"]
80
+ rope = source.get("rope_parameters") or {}
81
+ source.setdefault("rope_theta", rope.get("rope_theta", 10000.0))
82
+ source.setdefault("partial_rotary_factor", rope.get("partial_rotary_factor", 1.0))
83
+ return super().from_dict(source)
84
+
85
+ def __post_init__(self):
86
+ if self.ple_embed_dim is None:
87
+ self.ple_embed_dim = self.hidden_size
88
+ if not self.layer_types:
89
+ self.layer_types = [
90
+ "linear_attention" if (i + 1) % 4 else "full_attention"
91
+ for i in range(self.num_hidden_layers)
92
+ ]
93
+ if len(self.layer_types) != self.num_hidden_layers:
94
+ raise ValueError("layer_types must contain one entry per hidden layer")
95
+ if self.hc_count <= 1:
96
+ raise ValueError("hc_count must be greater than one")
97
+ if self.linear_num_value_heads % self.linear_num_key_heads:
98
+ raise ValueError("linear value heads must be divisible by key heads")
99
+ if not 0 < self.num_experts_per_tok <= self.num_experts:
100
+ raise ValueError("num_experts_per_tok must select existing experts")
101
+ if any(layer < 1 or layer > self.num_hidden_layers for layer in self.ple_layer_ids):
102
+ raise ValueError("PLE layer ids are one-indexed hidden-layer ids")
103
+ if self.ple_layer_ids and self.eos_token_id is None:
104
+ raise ValueError("PLE requires eos_token_id")
105
+ qsa = (
106
+ self.indexer_n_heads,
107
+ self.indexer_kv_heads,
108
+ self.indexer_head_dim,
109
+ self.indexer_budget,
110
+ self.indexer_compress_ratio,
111
+ )
112
+ if any(value is None for value in qsa):
113
+ raise ValueError("QSA requires every indexer field")
114
+ if self.indexer_kv_heads != 1:
115
+ raise ValueError("QSA requires one indexer key head")
116
+ if self.indexer_budget % self.indexer_compress_ratio:
117
+ raise ValueError("indexer_budget must divide into complete compressed blocks")
118
+ ngram_heads = (self.ngram_size - 1) * self.heads_per_ngram
119
+ if self.ple_layer_ids and self.ple_embed_dim % ngram_heads:
120
+ raise ValueError("ple_embed_dim must be divisible by its n-gram heads")
121
+
122
+
123
+ class Qwen4RMSNorm(nn.Module):
124
+ def __init__(self, dim: int, eps: float, group_size: Optional[int] = None):
125
+ super().__init__()
126
+ self.weight = mx.zeros(dim)
127
+ self.eps = eps
128
+ self.group_size = group_size
129
+
130
+ def __call__(self, x):
131
+ dtype = x.dtype
132
+ value = x.astype(mx.float32)
133
+ if self.group_size is not None:
134
+ value = value.reshape(*value.shape[:-1], -1, self.group_size)
135
+ value = value * mx.rsqrt(mx.mean(mx.square(value), axis=-1, keepdims=True) + self.eps)
136
+ if self.group_size is not None:
137
+ value = value.reshape(*x.shape)
138
+ return (value * (1.0 + self.weight.astype(mx.float32))).astype(dtype)
139
+
140
+
141
+ class Qwen4RMSNormGated(nn.Module):
142
+ def __init__(self, dim: int, eps: float, activation: str):
143
+ super().__init__()
144
+ self.weight = mx.ones(dim)
145
+ self.eps = eps
146
+ self.activation = activation
147
+
148
+ def __call__(self, x, gate):
149
+ dtype = x.dtype
150
+ value = mx.fast.rms_norm(x, self.weight, self.eps)
151
+ gate = gate.astype(mx.float32)
152
+ gate = mx.sigmoid(gate) if self.activation == "sigmoid" else nn.silu(gate)
153
+ return (value.astype(mx.float32) * gate).astype(dtype)
154
+
155
+
156
+ def _l2_normalize(x, eps=1e-6):
157
+ return x * mx.rsqrt(mx.sum(x * x, axis=-1, keepdims=True) + eps)
158
+
159
+
160
+ def _apply_rope(x, positions, rotary_dim: int, theta: float):
161
+ if rotary_dim == 0:
162
+ return x
163
+ dtype = x.dtype
164
+ inv_freq = theta ** (-mx.arange(0, rotary_dim, 2, dtype=mx.float32) / rotary_dim)
165
+ angles = positions.astype(mx.float32)[..., None] * inv_freq
166
+ cos = mx.concatenate([mx.cos(angles), mx.cos(angles)], axis=-1)
167
+ sin = mx.concatenate([mx.sin(angles), mx.sin(angles)], axis=-1)
168
+ while cos.ndim < x.ndim:
169
+ cos = mx.expand_dims(cos, axis=-2)
170
+ sin = mx.expand_dims(sin, axis=-2)
171
+ rotated, remainder = x[..., :rotary_dim], x[..., rotary_dim:]
172
+ first, second = mx.split(rotated, 2, axis=-1)
173
+ rotated = rotated * cos + mx.concatenate([-second, first], axis=-1) * sin
174
+ return mx.concatenate([rotated, remainder], axis=-1).astype(dtype)
175
+
176
+
177
+ class QSAKVCache(KVCache):
178
+ def __init__(self):
179
+ super().__init__()
180
+ self.index_keys = None
181
+
182
+ def update_indexer(self, keys):
183
+ previous = self.offset
184
+ length = keys.shape[1]
185
+ end = previous + length
186
+ if self.index_keys is None or end > self.index_keys.shape[1]:
187
+ batch, _, head_dim = keys.shape
188
+ steps = (self.step + length - 1) // self.step
189
+ extension = mx.zeros(
190
+ (batch, steps * self.step, head_dim),
191
+ dtype=keys.dtype,
192
+ )
193
+ if self.index_keys is None:
194
+ self.index_keys = extension
195
+ else:
196
+ if previous % self.step:
197
+ self.index_keys = self.index_keys[:, :previous, :]
198
+ self.index_keys = mx.concatenate([self.index_keys, extension], axis=1)
199
+ self.index_keys[:, previous:end, :] = keys
200
+ return self.index_keys[:, :end, :]
201
+
202
+ @property
203
+ def state(self):
204
+ index_state = (
205
+ self.index_keys
206
+ if self.index_keys is None
207
+ else self.index_keys[:, : self.offset, :]
208
+ )
209
+ if self.keys is None:
210
+ return self.keys, self.values, index_state
211
+ return (
212
+ self.keys[..., : self.offset, :],
213
+ self.values[..., : self.offset, :],
214
+ index_state,
215
+ )
216
+
217
+ @state.setter
218
+ def state(self, value):
219
+ self.keys, self.values, self.index_keys = value
220
+ self.offset = 0 if self.keys is None else self.keys.shape[2]
221
+
222
+ def trim(self, count):
223
+ return super().trim(count)
224
+
225
+ def to_quantized(self, group_size=64, bits=4):
226
+ cache = QSAQuantizedKVCache(group_size=group_size, bits=bits)
227
+ cache.offset = self.offset
228
+ cache.index_keys = self.index_keys
229
+ if self.keys is not None:
230
+ cache.keys = mx.quantize(self.keys[..., : self.offset, :], group_size=group_size, bits=bits)
231
+ cache.values = mx.quantize(self.values[..., : self.offset, :], group_size=group_size, bits=bits)
232
+ return cache
233
+
234
+ @property
235
+ def nbytes(self):
236
+ size = super().nbytes
237
+ return size + (0 if self.index_keys is None else self.index_keys.nbytes)
238
+
239
+
240
+ class QSAQuantizedKVCache(QuantizedKVCache):
241
+ def __init__(self, group_size=64, bits=4):
242
+ super().__init__(group_size=group_size, bits=bits)
243
+ self.index_keys = None
244
+
245
+ def update_indexer(self, keys):
246
+ previous = self.offset
247
+ length = keys.shape[1]
248
+ end = previous + length
249
+ if self.index_keys is None or end > self.index_keys.shape[1]:
250
+ batch, _, head_dim = keys.shape
251
+ steps = (self.step + length - 1) // self.step
252
+ extension = mx.zeros(
253
+ (batch, steps * self.step, head_dim),
254
+ dtype=keys.dtype,
255
+ )
256
+ if self.index_keys is None:
257
+ self.index_keys = extension
258
+ else:
259
+ if previous % self.step:
260
+ self.index_keys = self.index_keys[:, :previous, :]
261
+ self.index_keys = mx.concatenate([self.index_keys, extension], axis=1)
262
+ self.index_keys[:, previous:end, :] = keys
263
+ return self.index_keys[:, :end, :]
264
+
265
+ @property
266
+ def state(self):
267
+ quantized_state = (self.keys, self.values) if self.keys is None else super().state
268
+ index_state = (
269
+ self.index_keys
270
+ if self.index_keys is None
271
+ else self.index_keys[:, : self.offset, :]
272
+ )
273
+ return quantized_state, index_state
274
+
275
+ @state.setter
276
+ def state(self, value):
277
+ quantized_state, self.index_keys = value
278
+ QuantizedKVCache.state.fset(self, quantized_state)
279
+ self.offset = 0 if self.keys is None else self.keys[0].shape[2]
280
+
281
+ def trim(self, count):
282
+ return super().trim(count)
283
+
284
+ def to_quantized(self, group_size=64, bits=4):
285
+ if group_size == self.group_size and bits == self.bits:
286
+ return self
287
+ raise ValueError("QSA KV cache is already quantized")
288
+
289
+ @property
290
+ def nbytes(self):
291
+ size = super().nbytes
292
+ return size + (0 if self.index_keys is None else self.index_keys.nbytes)
293
+
294
+
295
+ class Qwen4GatedDeltaNet(nn.Module):
296
+ def __init__(self, args: ModelArgs):
297
+ super().__init__()
298
+ self.num_v_heads = args.linear_num_value_heads
299
+ self.num_k_heads = args.linear_num_key_heads
300
+ self.head_k_dim = args.linear_key_head_dim
301
+ self.head_v_dim = args.linear_value_head_dim
302
+ self.key_dim = self.num_k_heads * self.head_k_dim
303
+ self.value_dim = self.num_v_heads * self.head_v_dim
304
+ self.conv_kernel_size = args.linear_conv_kernel_dim
305
+ self.conv_dim = 2 * self.key_dim + self.value_dim
306
+ self.conv1d = nn.Conv1d(
307
+ self.conv_dim,
308
+ self.conv_dim,
309
+ self.conv_kernel_size,
310
+ groups=self.conv_dim,
311
+ bias=False,
312
+ )
313
+ self.in_proj_qkv = nn.Linear(args.hidden_size, self.conv_dim, bias=False)
314
+ self.in_proj_z = nn.Linear(args.hidden_size, self.value_dim, bias=False)
315
+ self.in_proj_b = nn.Linear(args.hidden_size, self.num_v_heads, bias=False)
316
+ self.in_proj_a = nn.Linear(args.hidden_size, self.num_v_heads, bias=False)
317
+ self.dt_bias = mx.ones(self.num_v_heads)
318
+ self.A_log = mx.log(mx.random.uniform(low=0.01, high=16.0, shape=(self.num_v_heads,)))
319
+ self.norm = Qwen4RMSNormGated(
320
+ self.head_v_dim,
321
+ args.rms_norm_eps,
322
+ args.output_gate_type or args.hidden_act,
323
+ )
324
+ self.out_proj = nn.Linear(self.value_dim, args.hidden_size, bias=False)
325
+
326
+ def __call__(self, x, mask=None, cache=None):
327
+ batch, length, _ = x.shape
328
+ mixed = self.in_proj_qkv(x)
329
+ z = self.in_proj_z(x).reshape(batch, length, self.num_v_heads, self.head_v_dim)
330
+ b = self.in_proj_b(x)
331
+ a = self.in_proj_a(x)
332
+ if mask is not None:
333
+ mixed = mx.where(mask[..., None], mixed, 0)
334
+ if cache is not None and cache[0] is not None:
335
+ conv_state = cache[0]
336
+ else:
337
+ conv_state = mx.zeros((batch, self.conv_kernel_size - 1, self.conv_dim), dtype=x.dtype)
338
+ conv_input = mx.concatenate([conv_state, mixed], axis=1)
339
+ if cache is not None:
340
+ cache[0] = mx.contiguous(conv_input[:, -(self.conv_kernel_size - 1) :, :])
341
+ mixed = nn.silu(self.conv1d(conv_input))
342
+ q, k, value = mx.split(mixed, [self.key_dim, 2 * self.key_dim], axis=-1)
343
+ q = q.reshape(batch, length, self.num_k_heads, self.head_k_dim)
344
+ k = k.reshape(batch, length, self.num_k_heads, self.head_k_dim)
345
+ value = value.reshape(batch, length, self.num_v_heads, self.head_v_dim)
346
+ state = None if cache is None else cache[1]
347
+ q = _l2_normalize(q) * (self.head_k_dim**-0.5)
348
+ k = _l2_normalize(k)
349
+ output, state = gated_delta_update(
350
+ q,
351
+ k,
352
+ value,
353
+ a.astype(mx.float32),
354
+ b,
355
+ self.A_log,
356
+ self.dt_bias,
357
+ state,
358
+ mask,
359
+ use_kernel=not self.training,
360
+ )
361
+ if cache is not None:
362
+ cache[1] = state
363
+ cache.advance(length)
364
+ output = self.norm(output, z).reshape(batch, length, -1)
365
+ return self.out_proj(output)
366
+
367
+
368
+ class Qwen4QSAIndexer(nn.Module):
369
+ def __init__(self, args: ModelArgs):
370
+ super().__init__()
371
+ self.n_heads = args.indexer_n_heads
372
+ self.head_dim = args.indexer_head_dim
373
+ self.budget = args.indexer_budget
374
+ self.compress_ratio = args.indexer_compress_ratio
375
+ self.block_topk = self.budget // self.compress_ratio
376
+ self.rotary_dim = int(args.head_dim * args.partial_rotary_factor)
377
+ self.rope_theta = args.rope_theta
378
+ self.index_qk_proj = nn.Linear(
379
+ args.hidden_size,
380
+ (args.indexer_n_heads + args.indexer_kv_heads) * args.indexer_head_dim,
381
+ bias=False,
382
+ )
383
+ self.q_layernorm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
384
+ self.k_layernorm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
385
+
386
+ def __call__(self, hidden_states, cache, offset):
387
+ batch, length, _ = hidden_states.shape
388
+ qk = self.index_qk_proj(hidden_states)
389
+ split = self.n_heads * self.head_dim
390
+ query, raw_keys = mx.split(qk, [split], axis=-1)
391
+ query = self.q_layernorm(query.reshape(batch, length, self.n_heads, self.head_dim))
392
+ raw_keys = raw_keys.reshape(batch, length, self.head_dim)
393
+ raw_keys = cache.update_indexer(raw_keys) if cache is not None else raw_keys
394
+ positions = offset + mx.arange(length)
395
+ query = _apply_rope(query, positions[None], self.rotary_dim, self.rope_theta)
396
+ return query, raw_keys, positions
397
+
398
+ def select(self, query, raw_keys, positions):
399
+ batch, length, _, _ = query.shape
400
+ key_length = raw_keys.shape[1]
401
+ ratio = self.compress_ratio
402
+ block_count = key_length // ratio
403
+ selected_parts = []
404
+ valid_parts = []
405
+ if block_count:
406
+ pooled = raw_keys[:, : block_count * ratio].reshape(
407
+ batch, block_count, ratio, self.head_dim
408
+ ).mean(axis=2)
409
+ pooled = self.k_layernorm(pooled)
410
+ block_positions = mx.arange(block_count) * ratio
411
+ pooled = _apply_rope(
412
+ pooled,
413
+ block_positions[None],
414
+ self.rotary_dim,
415
+ self.rope_theta,
416
+ )
417
+ scores = mx.einsum(
418
+ "blhd,bkd->blhk",
419
+ query.astype(mx.float32),
420
+ pooled.astype(mx.float32),
421
+ )
422
+ scores = mx.sum(mx.maximum(scores, 0), axis=2) / math.sqrt(self.head_dim)
423
+ complete = (positions + 1) // ratio
424
+ block_valid = mx.arange(block_count)[None, None, :] < complete[None, :, None]
425
+ scores = mx.where(block_valid, scores, mx.finfo(scores.dtype).min)
426
+ take = min(self.block_topk, block_count)
427
+ if take == block_count:
428
+ selected_blocks = mx.broadcast_to(
429
+ mx.arange(block_count)[None, None, :],
430
+ (batch, length, block_count),
431
+ )
432
+ else:
433
+ selected_blocks = mx.argpartition(scores, kth=block_count - take, axis=-1)[..., -take:]
434
+ chosen_valid = mx.take_along_axis(block_valid, selected_blocks, axis=-1)
435
+ selected_parts.append(
436
+ (selected_blocks[..., None] * ratio + mx.arange(ratio)).reshape(batch, length, -1)
437
+ )
438
+ valid_parts.append(
439
+ mx.broadcast_to(chosen_valid[..., None], (*chosen_valid.shape, ratio)).reshape(batch, length, -1)
440
+ )
441
+ tail_width = max(ratio - 1, 1)
442
+ tail_start = ((positions + 1) // ratio) * ratio
443
+ tail = tail_start[:, None] + mx.arange(tail_width)[None]
444
+ tail_valid = tail <= positions[:, None]
445
+ selected_parts.append(mx.broadcast_to(tail[None], (batch, length, tail_width)))
446
+ valid_parts.append(mx.broadcast_to(tail_valid[None], (batch, length, tail_width)))
447
+ return mx.concatenate(selected_parts, axis=-1), mx.concatenate(valid_parts, axis=-1)
448
+
449
+
450
+ class Qwen4Attention(nn.Module):
451
+ def __init__(self, args: ModelArgs):
452
+ super().__init__()
453
+ self.num_heads = args.num_attention_heads
454
+ self.num_kv_heads = args.num_key_value_heads
455
+ self.head_dim = args.head_dim
456
+ self.repeats = self.num_heads // self.num_kv_heads
457
+ self.scale = self.head_dim**-0.5
458
+ self.rotary_dim = int(self.head_dim * args.partial_rotary_factor)
459
+ self.rope_theta = args.rope_theta
460
+ self.q_proj = nn.Linear(args.hidden_size, self.num_heads * self.head_dim * 2, bias=args.attention_bias)
461
+ self.k_proj = nn.Linear(args.hidden_size, self.num_kv_heads * self.head_dim, bias=args.attention_bias)
462
+ self.v_proj = nn.Linear(args.hidden_size, self.num_kv_heads * self.head_dim, bias=args.attention_bias)
463
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, args.hidden_size, bias=args.attention_bias)
464
+ self.q_norm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
465
+ self.k_norm = Qwen4RMSNorm(self.head_dim, args.rms_norm_eps)
466
+ self.indexer = Qwen4QSAIndexer(args)
467
+
468
+ def _select_cache_rows(self, values, batch_index, indices, cache):
469
+ if not isinstance(values, (list, tuple)):
470
+ return values[batch_index, :, indices, :].transpose(2, 0, 1, 3)
471
+ parts = [value[batch_index, :, indices, :].transpose(2, 0, 1, 3) for value in values]
472
+ return mx.dequantize(
473
+ parts[0],
474
+ parts[1],
475
+ parts[2],
476
+ group_size=cache.group_size,
477
+ bits=cache.bits,
478
+ )
479
+
480
+ def _sparse_attention(self, query, keys, values, selected, valid, cache):
481
+ outputs = []
482
+ for batch_index in range(query.shape[0]):
483
+ grouped_query = query[batch_index].reshape(
484
+ self.num_kv_heads, self.repeats, query.shape[2], self.head_dim
485
+ )
486
+ chunks = []
487
+ for start in range(0, query.shape[2], 64):
488
+ end = min(start + 64, query.shape[2])
489
+ key_length = (
490
+ keys[0].shape[2]
491
+ if isinstance(keys, (list, tuple))
492
+ else keys.shape[2]
493
+ )
494
+ indices = mx.clip(
495
+ selected[batch_index, start:end],
496
+ 0,
497
+ key_length - 1,
498
+ )
499
+ selected_keys = self._select_cache_rows(keys, batch_index, indices, cache)
500
+ selected_values = self._select_cache_rows(values, batch_index, indices, cache)
501
+ local_query = grouped_query[:, :, start:end]
502
+ scores = mx.einsum("hrld,hlmd->hrlm", local_query, selected_keys) * self.scale
503
+ scores = mx.where(valid[batch_index, start:end][None, None], scores, mx.finfo(scores.dtype).min)
504
+ probabilities = mx.softmax(scores, axis=-1, precise=True)
505
+ output = mx.einsum("hrlm,hlmd->hrld", probabilities, selected_values)
506
+ mx.eval(output)
507
+ chunks.append(output)
508
+ output = mx.concatenate(chunks, axis=2)
509
+ outputs.append(output.reshape(self.num_heads, query.shape[2], self.head_dim)[None])
510
+ return mx.concatenate(outputs, axis=0)
511
+
512
+ def __call__(self, x, cache=None):
513
+ batch, length, _ = x.shape
514
+ offset = 0 if cache is None else cache.offset
515
+ projected = self.q_proj(x).reshape(batch, length, self.num_heads, 2 * self.head_dim)
516
+ query, gate = mx.split(projected, 2, axis=-1)
517
+ gate = gate.reshape(batch, length, -1)
518
+ keys = self.k_proj(x).reshape(batch, length, self.num_kv_heads, self.head_dim)
519
+ values = self.v_proj(x).reshape(batch, length, self.num_kv_heads, self.head_dim)
520
+ positions = offset + mx.arange(length)
521
+ query = _apply_rope(self.q_norm(query), positions[None], self.rotary_dim, self.rope_theta)
522
+ keys = _apply_rope(self.k_norm(keys), positions[None], self.rotary_dim, self.rope_theta)
523
+ query = query.transpose(0, 2, 1, 3)
524
+ keys = keys.transpose(0, 2, 1, 3)
525
+ values = values.transpose(0, 2, 1, 3)
526
+ index_query, raw_keys, _ = self.indexer(x, cache, offset)
527
+ if cache is not None:
528
+ keys, values = cache.update_and_fetch(keys, values)
529
+ selected, valid = self.indexer.select(index_query, raw_keys, positions)
530
+ output = self._sparse_attention(query, keys, values, selected, valid, cache)
531
+ output = output.transpose(0, 2, 1, 3).reshape(batch, length, -1)
532
+ return self.o_proj(output * mx.sigmoid(gate))
533
+
534
+
535
+ class Qwen4MLP(nn.Module):
536
+ def __init__(self, dim, hidden_dim):
537
+ super().__init__()
538
+ self.gate_proj = nn.Linear(dim, hidden_dim, bias=False)
539
+ self.up_proj = nn.Linear(dim, hidden_dim, bias=False)
540
+ self.down_proj = nn.Linear(hidden_dim, dim, bias=False)
541
+
542
+ def __call__(self, x):
543
+ return self.down_proj(swiglu(self.gate_proj(x), self.up_proj(x)))
544
+
545
+
546
+ class Qwen4SparseMoeBlock(nn.Module):
547
+ def __init__(self, args: ModelArgs):
548
+ super().__init__()
549
+ self.top_k = args.num_experts_per_tok
550
+ self.norm_topk_prob = args.norm_topk_prob
551
+ self.gate = nn.Linear(args.hidden_size, args.num_experts, bias=False)
552
+ self.switch_mlp = SwitchGLU(args.hidden_size, args.moe_intermediate_size, args.num_experts)
553
+ self.shared_expert = Qwen4MLP(args.hidden_size, args.shared_expert_intermediate_size)
554
+ self.shared_expert_gate = nn.Linear(args.hidden_size, 1, bias=False)
555
+
556
+ def _routing_weights(self, router_logits):
557
+ gates = mx.softmax(router_logits.astype(mx.float32), axis=-1, precise=True)
558
+ indices = mx.argpartition(gates, kth=-self.top_k, axis=-1)[..., -self.top_k :]
559
+ scores = mx.take_along_axis(gates, indices, axis=-1)
560
+ if self.norm_topk_prob:
561
+ scores = scores / mx.sum(scores, axis=-1, keepdims=True)
562
+ return scores.astype(router_logits.dtype), indices
563
+
564
+ def __call__(self, x):
565
+ scores, indices = self._routing_weights(self.gate(x))
566
+ routed = mx.sum(self.switch_mlp(x, indices) * scores[..., None], axis=-2)
567
+ shared = mx.sigmoid(self.shared_expert_gate(x)) * self.shared_expert(x)
568
+ return routed + shared
569
+
570
+
571
+ class Qwen4GatedResidual(nn.Module):
572
+ def __init__(self, args: ModelArgs, combine=True):
573
+ super().__init__()
574
+ self.hc_count = args.hc_count
575
+ self.hidden_size = args.hidden_size
576
+ total = self.hc_count * self.hidden_size
577
+ self.hc_norm = Qwen4RMSNorm(total, args.rms_norm_eps, group_size=self.hidden_size)
578
+ self.input_mix_weight_down = nn.Linear(total, args.hc_lowrank, bias=False)
579
+ self.input_mix_weight_up = nn.Linear(args.hc_lowrank, total, bias=False)
580
+ self.block_inject_weight = nn.Linear(total, self.hc_count, bias=False) if combine else None
581
+
582
+ def __call__(self, x):
583
+ normalized = self.hc_norm(x)
584
+ weights = nn.silu(self.input_mix_weight_down(normalized) / self.hc_count)
585
+ weights = mx.sigmoid(self.input_mix_weight_up(weights)).reshape(
586
+ *x.shape[:-1], self.hc_count, self.hidden_size
587
+ )
588
+ mixed = mx.mean(
589
+ weights * normalized.reshape(*x.shape[:-1], self.hc_count, self.hidden_size),
590
+ axis=-2,
591
+ )
592
+ if self.block_inject_weight is None:
593
+ return mixed
594
+ injection = 2 * mx.sigmoid(self.block_inject_weight(normalized) / self.hc_count)
595
+ return mixed, x, injection
596
+
597
+
598
+ _MASK64 = (1 << 64) - 1
599
+ _SPLITMIX_GAMMA = 0x9E3779B97F4A7C15
600
+ _SPLITMIX_M1 = 0xBF58476D1CE4E5B9
601
+ _SPLITMIX_M2 = 0x94D049BB133111EB
602
+
603
+
604
+ def _splitmix64(value):
605
+ value = (value + _SPLITMIX_GAMMA) & _MASK64
606
+ value = ((value ^ (value >> 30)) * _SPLITMIX_M1) & _MASK64
607
+ value = ((value ^ (value >> 27)) * _SPLITMIX_M2) & _MASK64
608
+ return (value ^ (value >> 31)) & _MASK64
609
+
610
+
611
+ def _multipliers(vocab_size, ngram_size, layer_index, seed):
612
+ maximum = ((1 << 63) - 1) // max(vocab_size, 1)
613
+ bound = max(1, maximum // 2)
614
+ base = seed + 10007 * layer_index
615
+ return [
616
+ 2 * (_splitmix64((base + _SPLITMIX_GAMMA * (index + 1)) & _MASK64) % bound) + 1
617
+ for index in range(ngram_size)
618
+ ]
619
+
620
+
621
+ def _is_prime(value):
622
+ if value < 2:
623
+ return False
624
+ if value % 2 == 0:
625
+ return value == 2
626
+ return all(value % divisor for divisor in range(3, math.isqrt(value) + 1, 2))
627
+
628
+
629
+ def _nth_prime_after(start, count):
630
+ value = start
631
+ for _ in range(count):
632
+ value += 1
633
+ while not _is_prime(value):
634
+ value += 1
635
+ return value
636
+
637
+
638
+ class Qwen4NGramEmbedding(nn.Module):
639
+ def __init__(self, args: ModelArgs, layer_index: int, model_layer_index=None):
640
+ super().__init__()
641
+ self.ngram_size = args.ngram_size
642
+ self.context_len = self.ngram_size - 1
643
+ self.heads_per_ngram = args.heads_per_ngram
644
+ self.ngram_heads = self.context_len * self.heads_per_ngram
645
+ self.eos_token_id = args.eos_token_id[0] if isinstance(args.eos_token_id, list) else args.eos_token_id
646
+ sizes = [
647
+ _nth_prime_after(args.ngram_vocab_size_base - 1, head + 1)
648
+ for head in range(self.ngram_heads)
649
+ ]
650
+ offsets = []
651
+ total = 0
652
+ for size in sizes:
653
+ offsets.append(total)
654
+ total += size
655
+ padded = math.ceil(total / args.make_ngram_vocab_size_divisible_by) * args.make_ngram_vocab_size_divisible_by
656
+ self.layer_multipliers = mx.array(
657
+ _multipliers(args.vocab_size, self.ngram_size, layer_index, args.seed),
658
+ dtype=mx.int64,
659
+ )
660
+ self.ngram_heads_vocab_sizes = mx.array(sizes, dtype=mx.int64)
661
+ self.ngram_heads_offsets = mx.array(offsets, dtype=mx.int64)
662
+ model_path = os.environ.get("OMLX_QWEN4_PLE_MODEL_PATH")
663
+ mode = os.environ.get("OMLX_QWEN4_PLE_MODE", "resident")
664
+ embedding_args = (
665
+ padded,
666
+ args.ple_embed_dim // self.ngram_heads,
667
+ args.split_ngram_parts,
668
+ )
669
+ if mode == "mmap":
670
+ if model_path is None or model_layer_index is None:
671
+ raise RuntimeError("SSD-backed PLE requires its model path and decoder layer index")
672
+ prefix = f"model.layers.{model_layer_index}.ple.ple_embedding.ngram_embedding"
673
+ self.ngram_embedding = DiskBackedShardedEmbedding(
674
+ model_path,
675
+ prefix,
676
+ *embedding_args,
677
+ )
678
+ elif mode == "resident":
679
+ self.ngram_embedding = ShardedEmbedding(*embedding_args)
680
+ else:
681
+ raise ValueError("OMLX_QWEN4_PLE_MODE must be resident or mmap")
682
+
683
+ def _shift(self, tokens, shift):
684
+ if shift == 0:
685
+ return tokens
686
+ batch, length = tokens.shape
687
+ positions = mx.arange(length)
688
+ eos_positions = mx.where(tokens == self.eos_token_id, positions[None], -1)
689
+ inclusive = mx.cummax(eos_positions, axis=1)
690
+ previous = mx.concatenate([mx.full((batch, 1), -1, dtype=mx.int64), inclusive[:, :-1]], axis=1)
691
+ source = positions - shift
692
+ gathered = tokens[:, mx.maximum(source, 0)]
693
+ valid = (positions[None] - previous - 1 >= shift) & (source[None] >= 0)
694
+ return mx.where(valid, gathered, self.eos_token_id)
695
+
696
+ def __call__(self, input_ids, cache=None):
697
+ input_ids = input_ids.astype(mx.int64)
698
+ if cache is not None and cache[3] is not None:
699
+ previous = cache[3]
700
+ else:
701
+ previous = mx.full((input_ids.shape[0], self.context_len), self.eos_token_id, dtype=mx.int64)
702
+ history = mx.concatenate([previous, input_ids], axis=1)
703
+ if cache is not None:
704
+ cache[3] = mx.contiguous(history[:, -self.context_len :])
705
+ shifted = [self._shift(history, shift) for shift in range(self.ngram_size)]
706
+ blocks = []
707
+ for ngram in range(2, self.ngram_size + 1):
708
+ start = (ngram - 2) * self.heads_per_ngram
709
+ end = start + self.heads_per_ngram
710
+ mixed = shifted[0] * self.layer_multipliers[0]
711
+ for position in range(1, ngram):
712
+ mixed = mx.bitwise_xor(mixed, shifted[position] * self.layer_multipliers[position])
713
+ ids = mixed[..., None] % self.ngram_heads_vocab_sizes[start:end]
714
+ blocks.append(ids + self.ngram_heads_offsets[start:end])
715
+ ids = mx.concatenate(blocks, axis=-1)[:, -input_ids.shape[1] :]
716
+ return self.ngram_embedding(ids).reshape(input_ids.shape[0], input_ids.shape[1], -1)
717
+
718
+
719
+ class ShardedEmbedding(nn.Module):
720
+ def __init__(self, num_embeddings, dims, shard_count):
721
+ super().__init__()
722
+ if num_embeddings % shard_count:
723
+ raise ValueError("the padded n-gram vocabulary must divide evenly into shards")
724
+ self.shard_size = num_embeddings // shard_count
725
+ self.dims = dims
726
+ self.shards = [nn.Embedding(self.shard_size, dims) for _ in range(shard_count)]
727
+
728
+ def __call__(self, ids):
729
+ shape = ids.shape
730
+ flat_ids = ids.reshape(-1)
731
+ if flat_ids.size == 0:
732
+ return self.shards[0](flat_ids).reshape(*shape, self.dims)
733
+ shard_ids = flat_ids // self.shard_size
734
+ local_ids = flat_ids % self.shard_size
735
+ mx.eval(shard_ids)
736
+ host_shards = shard_ids.tolist()
737
+ output = None
738
+ for shard_index in sorted(set(host_shards)):
739
+ positions = mx.array(
740
+ [index for index, value in enumerate(host_shards) if value == shard_index],
741
+ dtype=mx.int32,
742
+ )
743
+ values = self.shards[shard_index](local_ids[positions])
744
+ if output is None:
745
+ output = mx.zeros((flat_ids.size, self.dims), dtype=values.dtype)
746
+ output[positions] = values
747
+ mx.eval(output)
748
+ return output.reshape(*shape, self.dims)
749
+
750
+
751
+ _SAFETENSORS_NUMPY_DTYPES = {
752
+ "U32": np.dtype("<u4"),
753
+ "I32": np.dtype("<i4"),
754
+ "I64": np.dtype("<i8"),
755
+ "F16": np.dtype("<f2"),
756
+ "F32": np.dtype("<f4"),
757
+ "BF16": np.dtype("<u2"),
758
+ }
759
+
760
+
761
+ class _SafeTensorMMap:
762
+ def __init__(self, path):
763
+ self.path = Path(path)
764
+ self._file = self.path.open("rb")
765
+ raw_header_length = self._file.read(8)
766
+ if len(raw_header_length) != 8:
767
+ self.close()
768
+ raise ValueError(f"Invalid safetensors header in {self.path}")
769
+ header_length = struct.unpack("<Q", raw_header_length)[0]
770
+ raw_header = self._file.read(header_length)
771
+ if len(raw_header) != header_length:
772
+ self.close()
773
+ raise ValueError(f"Truncated safetensors header in {self.path}")
774
+ self._header = json.loads(raw_header)
775
+ self._data_start = 8 + header_length
776
+ self._mapping = mmap.mmap(self._file.fileno(), length=0, access=mmap.ACCESS_READ)
777
+ try:
778
+ self._mapping.madvise(mmap.MADV_RANDOM)
779
+ except (AttributeError, OSError):
780
+ pass
781
+
782
+ def tensor_shape(self, key):
783
+ try:
784
+ return tuple(self._header[key]["shape"])
785
+ except KeyError as exc:
786
+ raise KeyError(f"Tensor {key!r} is missing from {self.path}") from exc
787
+
788
+ def rows(self, key, row_indices):
789
+ try:
790
+ entry = self._header[key]
791
+ except KeyError as exc:
792
+ raise KeyError(f"Tensor {key!r} is missing from {self.path}") from exc
793
+ dtype_name = entry["dtype"]
794
+ try:
795
+ dtype = _SAFETENSORS_NUMPY_DTYPES[dtype_name]
796
+ except KeyError as exc:
797
+ raise TypeError(f"Unsupported safetensors dtype {dtype_name!r} for {key}") from exc
798
+ shape = tuple(entry["shape"])
799
+ if len(shape) != 2:
800
+ raise ValueError(f"Sparse PLE tensor {key!r} must be two-dimensional")
801
+ start, end = entry["data_offsets"]
802
+ if end - start != math.prod(shape) * dtype.itemsize:
803
+ raise ValueError(f"Invalid byte range for safetensors tensor {key!r}")
804
+ view = np.ndarray(
805
+ shape,
806
+ dtype=dtype,
807
+ buffer=self._mapping,
808
+ offset=self._data_start + start,
809
+ )
810
+ copied = np.array(view[np.asarray(row_indices, dtype=np.intp)], copy=True)
811
+ if dtype_name == "BF16":
812
+ copied = (copied.astype(np.uint32) << np.uint32(16)).view(np.float32)
813
+ return copied, dtype_name
814
+
815
+ def close(self):
816
+ mapping = getattr(self, "_mapping", None)
817
+ if mapping is not None:
818
+ mapping.close()
819
+ self._mapping = None
820
+ file_object = getattr(self, "_file", None)
821
+ if file_object is not None:
822
+ file_object.close()
823
+ self._file = None
824
+
825
+ def __del__(self):
826
+ try:
827
+ self.close()
828
+ except Exception:
829
+ pass
830
+
831
+
832
+ class DiskBackedShardedEmbedding(nn.Module):
833
+ def __init__(self, model_path, prefix, num_embeddings, dims, shard_count):
834
+ super().__init__()
835
+ if num_embeddings % shard_count:
836
+ raise ValueError("the padded n-gram vocabulary must divide evenly into shards")
837
+ self.shard_size = num_embeddings // shard_count
838
+ self.dims = dims
839
+ self.shard_count = shard_count
840
+ self.last_touched_shards = ()
841
+ self.rows_read = 0
842
+ self._prefix = prefix
843
+ self._readers = {}
844
+ self._tensor_readers = {}
845
+ self._shard_quantization = []
846
+
847
+ model_path = Path(model_path)
848
+ index_path = model_path / "model.safetensors.index.json"
849
+ config_path = model_path / "config.json"
850
+ if not index_path.exists() or not config_path.exists():
851
+ raise FileNotFoundError("SSD-backed PLE requires config.json and a safetensors index")
852
+ weight_map = json.loads(index_path.read_text()).get("weight_map", {})
853
+ quantization = json.loads(config_path.read_text()).get("quantization") or {}
854
+ default = {
855
+ "bits": int(quantization.get("bits", 4)),
856
+ "group_size": int(quantization.get("group_size", 64)),
857
+ "mode": quantization.get("mode", "affine"),
858
+ }
859
+ for shard_index in range(shard_count):
860
+ module_key = f"{prefix}.shards.{shard_index}"
861
+ settings = dict(default)
862
+ settings.update(quantization.get(module_key) or {})
863
+ bits = int(settings["bits"])
864
+ group_size = int(settings["group_size"])
865
+ mode = settings["mode"]
866
+ if mode != "affine":
867
+ raise ValueError("SSD-backed PLE supports affine quantization")
868
+ if dims % group_size or (dims * bits) % 32:
869
+ raise ValueError(f"Invalid PLE quantization for {module_key}")
870
+ self._shard_quantization.append((group_size, bits, mode))
871
+ expected_shapes = {
872
+ "weight": (self.shard_size, dims * bits // 32),
873
+ "scales": (self.shard_size, dims // group_size),
874
+ "biases": (self.shard_size, dims // group_size),
875
+ }
876
+ for suffix, expected_shape in expected_shapes.items():
877
+ key = f"{module_key}.{suffix}"
878
+ try:
879
+ filename = weight_map[key]
880
+ except KeyError as exc:
881
+ raise KeyError(f"SSD-backed PLE tensor {key!r} is absent from the index") from exc
882
+ reader = self._readers.get(filename)
883
+ if reader is None:
884
+ reader = _SafeTensorMMap(model_path / filename)
885
+ self._readers[filename] = reader
886
+ if reader.tensor_shape(key) != expected_shape:
887
+ raise ValueError(
888
+ f"Unexpected shape for {key}: {reader.tensor_shape(key)} != {expected_shape}"
889
+ )
890
+ self._tensor_readers[key] = reader
891
+
892
+ def _read_rows(self, key, row_indices):
893
+ array, dtype_name = self._tensor_readers[key].rows(key, row_indices)
894
+ self.rows_read += len(row_indices)
895
+ result = mx.array(array)
896
+ return result.astype(mx.bfloat16) if dtype_name == "BF16" else result
897
+
898
+ def __call__(self, ids):
899
+ shape = ids.shape
900
+ flat_ids = ids.reshape(-1).astype(mx.int64)
901
+ mx.eval(flat_ids)
902
+ host_ids = [int(value) for value in flat_ids.tolist()]
903
+ if any(value < 0 or value >= self.shard_size * self.shard_count for value in host_ids):
904
+ raise IndexError("n-gram embedding id is outside the padded vocabulary")
905
+ touched = tuple(sorted({value // self.shard_size for value in host_ids}))
906
+ self.last_touched_shards = touched
907
+ self.rows_read = 0
908
+ output = None
909
+ for shard_index in touched:
910
+ positions_list = [
911
+ index for index, value in enumerate(host_ids) if value // self.shard_size == shard_index
912
+ ]
913
+ local_ids = [host_ids[index] % self.shard_size for index in positions_list]
914
+ base = f"{self._prefix}.shards.{shard_index}"
915
+ weight = self._read_rows(f"{base}.weight", local_ids)
916
+ scales = self._read_rows(f"{base}.scales", local_ids)
917
+ biases = self._read_rows(f"{base}.biases", local_ids)
918
+ group_size, bits, mode = self._shard_quantization[shard_index]
919
+ values = mx.dequantize(
920
+ weight,
921
+ scales=scales,
922
+ biases=biases,
923
+ group_size=group_size,
924
+ bits=bits,
925
+ mode=mode,
926
+ )
927
+ if output is None:
928
+ output = mx.zeros((len(host_ids), self.dims), dtype=values.dtype)
929
+ output[mx.array(positions_list, dtype=mx.int32)] = values
930
+ if output is None:
931
+ output = mx.zeros((0, self.dims), dtype=mx.bfloat16)
932
+ mx.eval(output)
933
+ return output.reshape(*shape, self.dims)
934
+
935
+
936
+ class Qwen4PLELayer(nn.Module):
937
+ def __init__(self, args: ModelArgs, ple_index: int, model_layer_index: int):
938
+ super().__init__()
939
+ total = args.hc_count * args.hidden_size
940
+ self.hc_count = args.hc_count
941
+ self.hidden_size = args.hidden_size
942
+ self.ple_embedding = Qwen4NGramEmbedding(args, ple_index, model_layer_index)
943
+ self.key_proj = nn.Linear(args.ple_embed_dim, total, bias=False)
944
+ self.value_proj = nn.Linear(args.ple_embed_dim, args.hidden_size, bias=False)
945
+ self.norm_key = Qwen4RMSNorm(total, args.rms_norm_eps, args.hidden_size)
946
+ self.norm_query = Qwen4RMSNorm(total, args.rms_norm_eps, args.hidden_size)
947
+ self.norm_conv = Qwen4RMSNorm(total, args.rms_norm_eps, args.hidden_size)
948
+ self.state_len = (args.ple_conv_kernel_size - 1) * args.ngram_size
949
+ self.conv1d = nn.Conv1d(
950
+ total,
951
+ total,
952
+ args.ple_conv_kernel_size,
953
+ dilation=args.ngram_size,
954
+ groups=total,
955
+ bias=False,
956
+ )
957
+
958
+ def __call__(self, x, input_ids, cache=None, mask=None):
959
+ embeddings = self.ple_embedding(input_ids, cache)
960
+ key = self.norm_key(self.key_proj(embeddings)).reshape(*x.shape[:-1], self.hc_count, self.hidden_size)
961
+ value = self.value_proj(embeddings)
962
+ query = self.norm_query(x).reshape(*x.shape[:-1], self.hc_count, self.hidden_size)
963
+ gate = mx.sum(key * query, axis=-1, keepdims=True) / math.sqrt(self.hidden_size)
964
+ gate = mx.sign(gate) * mx.sqrt(mx.maximum(mx.abs(gate), 1e-6))
965
+ gated = (mx.sigmoid(gate) * value[..., None, :]).reshape(*x.shape)
966
+ normalized = self.norm_conv(gated)
967
+ if mask is not None:
968
+ gated = mx.where(mask[..., None], gated, 0)
969
+ normalized = mx.where(mask[..., None], normalized, 0)
970
+ if cache is not None and cache[2] is not None:
971
+ state = cache[2]
972
+ else:
973
+ state = mx.zeros((x.shape[0], self.state_len, x.shape[-1]), dtype=x.dtype)
974
+ conv_input = mx.concatenate([state, normalized], axis=1)
975
+ if cache is not None:
976
+ cache[2] = mx.contiguous(conv_input[:, -self.state_len :, :])
977
+ return gated + nn.silu(self.conv1d(conv_input))
978
+
979
+
980
+ class Qwen4DecoderLayer(nn.Module):
981
+ def __init__(self, args: ModelArgs, index: int):
982
+ super().__init__()
983
+ self.is_linear = args.layer_types[index] == "linear_attention"
984
+ if self.is_linear:
985
+ self.linear_attn = Qwen4GatedDeltaNet(args)
986
+ else:
987
+ self.self_attn = Qwen4Attention(args)
988
+ self.mlp = Qwen4SparseMoeBlock(args)
989
+ one_indexed = index + 1
990
+ self.ple = Qwen4PLELayer(args, args.ple_layer_ids.index(one_indexed), index) if one_indexed in args.ple_layer_ids else None
991
+ self.attn_hyper_connection = Qwen4GatedResidual(args)
992
+ self.mlp_hyper_connection = Qwen4GatedResidual(args)
993
+
994
+ def __call__(self, x, input_ids, mask=None, cache=None):
995
+ if self.ple is not None:
996
+ x = x + self.ple(x, input_ids, cache, mask)
997
+ mixed, residual, injection = self.attn_hyper_connection(x)
998
+ output = self.linear_attn(mixed, mask, cache) if self.is_linear else self.self_attn(mixed, cache)
999
+ x = residual + (output[..., None, :] * injection[..., None]).reshape(*residual.shape)
1000
+ mixed, residual, injection = self.mlp_hyper_connection(x)
1001
+ output = self.mlp(mixed)
1002
+ return residual + (output[..., None, :] * injection[..., None]).reshape(*residual.shape)
1003
+
1004
+
1005
+ class Qwen4TextModel(nn.Module):
1006
+ def __init__(self, args: ModelArgs):
1007
+ super().__init__()
1008
+ self.args = args
1009
+ self.embed_tokens = nn.Embedding(args.vocab_size, args.hidden_size)
1010
+ self.layers = [Qwen4DecoderLayer(args, index) for index in range(args.num_hidden_layers)]
1011
+ self.hyper_connection_mixer = Qwen4GatedResidual(args, combine=False)
1012
+
1013
+ def __call__(self, inputs, cache=None):
1014
+ hidden = self.embed_tokens(inputs)
1015
+ hidden = mx.tile(hidden, (1, 1, self.args.hc_count))
1016
+ if cache is None:
1017
+ cache = [None] * len(self.layers)
1018
+ linear_index = next((i for i, layer in enumerate(self.layers) if layer.is_linear), None)
1019
+ mask = create_ssm_mask(hidden, cache[linear_index]) if linear_index is not None else None
1020
+ for layer, layer_cache in zip(self.layers, cache):
1021
+ hidden = layer(hidden, inputs, mask, layer_cache)
1022
+ return self.hyper_connection_mixer(hidden)
1023
+
1024
+
1025
+ def _decode_block_fp8(weight, scale, block=128):
1026
+ rows, columns = weight.shape
1027
+ grid_rows, grid_columns = scale.shape
1028
+ padded_rows, padded_columns = grid_rows * block, grid_columns * block
1029
+ decoded = mx.from_fp8(weight, dtype=mx.float32)
1030
+ decoded = mx.pad(decoded, ((0, padded_rows - rows), (0, padded_columns - columns)))
1031
+ decoded = decoded.reshape(grid_rows, block, grid_columns, block)
1032
+ decoded = decoded * scale.astype(mx.float32)[:, None, :, None]
1033
+ return decoded.reshape(padded_rows, padded_columns)[:rows, :columns].astype(mx.bfloat16)
1034
+
1035
+
1036
+ def register_oq_virtual_tensors(index, config):
1037
+ if config.get("model_type") != "qwen4_exp":
1038
+ return 0
1039
+ text_config = config.get("text_config", config)
1040
+ registrations = 0
1041
+ shard_count = int(text_config.get("split_ngram_parts", 0))
1042
+ for one_indexed_layer in text_config.get("ple_layer_ids", []):
1043
+ prefix = (
1044
+ f"model.language_model.layers.{one_indexed_layer - 1}.ple."
1045
+ "ple_embedding.ngram_embedding"
1046
+ )
1047
+ scale_key = prefix + ".weight_scale"
1048
+ if index.source_shape(scale_key) is None:
1049
+ continue
1050
+ for shard_index in range(shard_count):
1051
+ weight_key = f"{prefix}.shard_{shard_index}.weight"
1052
+ shape = index.source_shape(weight_key)
1053
+ if shape is None:
1054
+ raise ValueError(f"Missing Qwen4 PLE shard: {weight_key}")
1055
+
1056
+ def materialize(weight_key=weight_key, scale_key=scale_key):
1057
+ weight = index.load_source(weight_key)
1058
+ scale = index.load_source(scale_key)
1059
+ value = mx.from_fp8(weight, dtype=mx.bfloat16) * scale
1060
+ mx.eval(value)
1061
+ return value
1062
+
1063
+ index.register_virtual(
1064
+ weight_key,
1065
+ shape,
1066
+ "BF16",
1067
+ materialize,
1068
+ hides=(weight_key, scale_key),
1069
+ )
1070
+ registrations += 1
1071
+ return registrations
1072
+
1073
+
1074
+ class Model(nn.Module):
1075
+ def __init__(self, args: ModelArgs):
1076
+ super().__init__()
1077
+ self.args = args
1078
+ self.model_type = args.model_type
1079
+ self.model = Qwen4TextModel(args)
1080
+ if not args.tie_word_embeddings:
1081
+ self.lm_head = nn.Linear(args.hidden_size, args.vocab_size, bias=False)
1082
+
1083
+ def __call__(self, inputs, cache=None):
1084
+ output = self.model(inputs, cache)
1085
+ if self.args.tie_word_embeddings:
1086
+ return self.model.embed_tokens.as_linear(output)
1087
+ return self.lm_head(output)
1088
+
1089
+ @property
1090
+ def layers(self):
1091
+ return self.model.layers
1092
+
1093
+ def make_cache(self):
1094
+ return [ArraysCache(size=4) if layer.is_linear else QSAKVCache() for layer in self.layers]
1095
+
1096
+ def sanitize(self, weights):
1097
+ cleaned = {}
1098
+ for key, value in weights.items():
1099
+ if key.startswith("mtp.") or key.startswith("model.visual."):
1100
+ continue
1101
+ if key.startswith("model.language_model."):
1102
+ key = "model." + key[len("model.language_model.") :]
1103
+ cleaned[key] = value
1104
+ weights = cleaned
1105
+ if self.args.tie_word_embeddings:
1106
+ weights.pop("lm_head.weight", None)
1107
+ for layer_index in range(self.args.num_hidden_layers):
1108
+ prefix = f"model.layers.{layer_index}.mlp"
1109
+ if f"{prefix}.experts.0.up_proj.weight" not in weights:
1110
+ continue
1111
+ for projection in ("up_proj", "gate_proj", "down_proj"):
1112
+ values = []
1113
+ for expert in range(self.args.num_experts):
1114
+ key = f"{prefix}.experts.{expert}.{projection}.weight"
1115
+ scale_key = key + "_scale_inv"
1116
+ value = weights.pop(key)
1117
+ if scale_key in weights:
1118
+ value = _decode_block_fp8(value, weights.pop(scale_key))
1119
+ values.append(value)
1120
+ weights[f"{prefix}.switch_mlp.{projection}.weight"] = mx.stack(values)
1121
+ for layer_index in range(self.args.num_hidden_layers):
1122
+ base = f"model.layers.{layer_index}.ple.ple_embedding.ngram_embedding"
1123
+ layer = self.model.layers[layer_index]
1124
+ disk_backed = (
1125
+ layer.ple is not None
1126
+ and isinstance(
1127
+ layer.ple.ple_embedding.ngram_embedding,
1128
+ DiskBackedShardedEmbedding,
1129
+ )
1130
+ )
1131
+ if disk_backed:
1132
+ for key in list(weights):
1133
+ if key.startswith(base + ".shards."):
1134
+ weights.pop(key)
1135
+ shard_keys = [key for key in weights if key.startswith(base + ".shard_") and key.endswith(".weight")]
1136
+ if not shard_keys:
1137
+ continue
1138
+ shard_keys.sort(key=lambda key: int(key.split(".shard_")[1].split(".")[0]))
1139
+ scale = weights.pop(base + ".weight_scale", None)
1140
+ for shard_index, key in enumerate(shard_keys):
1141
+ value = weights.pop(key)
1142
+ if scale is not None:
1143
+ value = mx.from_fp8(value, dtype=mx.bfloat16) * scale
1144
+ weights[f"{base}.shards.{shard_index}.weight"] = value
1145
+ for key in list(weights):
1146
+ value = weights[key]
1147
+ if key.endswith("conv1d.weight") and value.ndim == 3 and value.shape[-1] != 1:
1148
+ weights[key] = value.moveaxis(2, 1)
1149
+ return weights
1150
+
1151
+ @property
1152
+ def quant_predicate(self):
1153
+ def predicate(path, module):
1154
+ if "ple_embedding.ngram_embedding.shards." in path:
1155
+ return {"group_size": 32, "bits": 4}
1156
+ if path.endswith("mlp.gate") or path.endswith("shared_expert_gate"):
1157
+ return {"group_size": 64, "bits": 8}
1158
+ return hasattr(module, "to_quantized")
1159
+
1160
+ return predicate
omlx_support/serve ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
19
+ exec /bin/zsh "$support_root/with-omlx-python" -m omlx.cli serve \
20
+ --model-dir "$models_root" \
21
+ --host 127.0.0.1 \
22
+ --port "$port" \
23
+ --max-concurrent-requests 1 \
24
+ --memory-guard balanced \
25
+ --paged-ssd-cache-dir "$cache_dir" \
26
+ --paged-ssd-cache-max-size 128GB \
27
+ --hot-cache-max-size 0 \
28
+ --initial-cache-blocks 1 \
29
+ --no-hf-cache \
30
+ --base-path "$base_path" \
31
+ --api-key "$api_key"
omlx_support/sitecustomize.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
12
+
13
+ register_qwen4_cache_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