nightscape commited on
Commit
b23eaff
·
verified ·
1 Parent(s): d131e0b

Add Intern-S2-Mobius 4-bit MLX (group-64) conversion

Browse files
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 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 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 those 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
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2025-2026 Shanghai AI Laboratory
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
README.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: mlx
3
+ license: apache-2.0
4
+ license_link: https://huggingface.co/internlm/Intern-S2-Mobius/blob/main/LICENSE
5
+ pipeline_tag: text-generation
6
+ base_model: internlm/Intern-S2-Mobius
7
+ tags:
8
+ - mlx
9
+ - mlx-lm
10
+ - quantization
11
+ - 4-bit
12
+ ---
13
+
14
+ # Intern-S2-Mobius (4-bit MLX)
15
+
16
+ An MLX **4-bit** (affine, group size 64) quantization of
17
+ [internlm/Intern-S2-Mobius](https://huggingface.co/internlm/Intern-S2-Mobius) — a 35B hybrid model:
18
+ Gated-DeltaNet linear attention / full attention at interval 4, with 2560 experts in 4 globally-shared
19
+ routed MoE banks. Runs on Apple Silicon.
20
+
21
+ - Base model: [internlm/Intern-S2-Mobius](https://huggingface.co/internlm/Intern-S2-Mobius) (Apache-2.0).
22
+ - Quantization: 4-bit affine, group size 64; shared-expert / router gates kept at 8-bit. ~19.6 GB peak, ~4.5 bpw.
23
+ - Architecture: `interns2_mobius` (`text_config.model_type = interns2_mobius_text`), 40 layers, `head_dim` 256,
24
+ MoE 2560 experts / top-8, `num_blocks` 4. `max_position_embeddings` 262144.
25
+
26
+ ## Quick start
27
+
28
+ Requires the `mlx-lm` build that ships the `interns2_mobius` architecture
29
+ (official part of `mlx-lm` as of the model-support PR):
30
+
31
+ ```bash
32
+ pip install -U mlx-lm
33
+ mlx_lm.generate --model nightscape/Intern-S2-Mobius-4bit-mlx \
34
+ -p "The secret to baking a good cake is" -m 1024 --trust-remote-code
35
+ ```
36
+
37
+ `--trust-remote-code` is mandatory: the checkpoint bundles a custom tokenizer
38
+ (`tokenization_interns1.py`) and model code.
39
+
40
+ ## Details
41
+
42
+ - This is an MLX conversion; `transformers` does not yet ship `interns2_mobius`. The reference is the
43
+ upstream repo's `trust_remote_code` implementation, verified by full bf16 logit diff (argmax agreement
44
+ 38/39, the sole miss a bit-identical tie).
45
+ - Capability spot-check (this 4-bit conversion): MMLU-Pro 88.3% ± 4.1 (n=60) vs upstream bf16 89.05;
46
+ GSM8K 97–98% (n=100). Short-generation-budget evals truncate chain-of-thought and depress scores — an
47
+ eval artifact, not a capability drop.
48
+ - Text-only: this conversion is the language model. The upstream checkpoint is tagged `image-text-to-text`,
49
+ but the MLX port loads the language model and generates text (no vision tower on this path).
50
+
51
+ ## Companion
52
+
53
+ An experimental MTP (Multi-Token-Prediction) head is published separately:
54
+ [nightscape/Intern-S2-Mobius-4bit-mlx-mtp](https://huggingface.co/nightscape/Intern-S2-Mobius-4bit-mlx-mtp).
55
+ It is consumed by the `omlx` server's `interns2_mobius` MTP driver, **not** by stock `mlx-lm`.
56
+
57
+ ## License
58
+
59
+ Weights and code under Apache-2.0 — see [LICENSE](LICENSE). Model by InternLM; this is a derivative
60
+ conversion of their weights plus the MLX port.
chat_template.jinja ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 'time_series' in item or item.type == 'time_series' %}
31
+ {%- if is_system_content %}
32
+ {{- raise_exception('System message cannot contain time series.') }}
33
+ {%- endif %}
34
+ {{- '<|ts|><TS_CONTEXT><|/ts|>' }}
35
+ {%- elif 'text' in item %}
36
+ {{- item.text }}
37
+ {%- else %}
38
+ {{- raise_exception('Unexpected item type in content.') }}
39
+ {%- endif %}
40
+ {%- endfor %}
41
+ {%- elif content is none or content is undefined %}
42
+ {{- '' }}
43
+ {%- else %}
44
+ {{- raise_exception('Unexpected content type.') }}
45
+ {%- endif %}
46
+ {%- endmacro %}
47
+ {%- if not messages %}
48
+ {{- raise_exception('No messages provided.') }}
49
+ {%- endif %}
50
+ {%- if tools and tools is iterable and tools is not mapping %}
51
+ {{- '<|im_start|>system\n' }}
52
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
53
+ {%- for tool in tools %}
54
+ {{- "\n" }}
55
+ {{- tool | tojson }}
56
+ {%- endfor %}
57
+ {{- "\n</tools>" }}
58
+ {{- '\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>' }}
59
+ {%- if messages[0].role == 'system' %}
60
+ {%- set content = render_content(messages[0].content, false, true)|trim %}
61
+ {%- if content %}
62
+ {{- '\n\n' + content }}
63
+ {%- endif %}
64
+ {%- endif %}
65
+ {{- '<|im_end|>\n' }}
66
+ {%- else %}
67
+ {%- if messages[0].role == 'system' %}
68
+ {%- set content = render_content(messages[0].content, false, true)|trim %}
69
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
70
+ {%- endif %}
71
+ {%- endif %}
72
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
73
+ {%- for message in messages[::-1] %}
74
+ {%- set index = (messages|length - 1) - loop.index0 %}
75
+ {%- if ns.multi_step_tool and message.role == "user" %}
76
+ {%- set content = render_content(message.content, false)|trim %}
77
+ {%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}
78
+ {%- set ns.multi_step_tool = false %}
79
+ {%- set ns.last_query_index = index %}
80
+ {%- endif %}
81
+ {%- endif %}
82
+ {%- endfor %}
83
+ {%- if ns.multi_step_tool %}
84
+ {{- raise_exception('No user query found in messages.') }}
85
+ {%- endif %}
86
+ {%- for message in messages %}
87
+ {%- set content = render_content(message.content, true)|trim %}
88
+ {%- if message.role == "system" %}
89
+ {%- if not loop.first %}
90
+ {{- raise_exception('System message must be at the beginning.') }}
91
+ {%- endif %}
92
+ {%- elif message.role == "user" %}
93
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
94
+ {%- elif message.role == "assistant" %}
95
+ {%- set reasoning_content = '' %}
96
+ {%- if message.reasoning_content is string %}
97
+ {%- set reasoning_content = message.reasoning_content %}
98
+ {%- else %}
99
+ {%- if '</think>' in content %}
100
+ {%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
101
+ {%- set content = content.split('</think>')[-1].lstrip('\n') %}
102
+ {%- endif %}
103
+ {%- endif %}
104
+ {%- set reasoning_content = reasoning_content|trim %}
105
+ {%- if loop.index0 > ns.last_query_index %}
106
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
107
+ {%- else %}
108
+ {{- '<|im_start|>' + message.role + '\n' + content }}
109
+ {%- endif %}
110
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
111
+ {%- for tool_call in message.tool_calls %}
112
+ {%- if tool_call.function is defined %}
113
+ {%- set tool_call = tool_call.function %}
114
+ {%- endif %}
115
+ {%- if loop.first %}
116
+ {%- if content|trim %}
117
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
118
+ {%- else %}
119
+ {{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
120
+ {%- endif %}
121
+ {%- else %}
122
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
123
+ {%- endif %}
124
+ {%- if tool_call.arguments is defined %}
125
+ {%- for args_name, args_value in tool_call.arguments|items %}
126
+ {{- '<parameter=' + args_name + '>\n' }}
127
+ {%- set args_value = args_value | tojson | safe if args_value is mapping or (args_value is sequence and args_value is not string) else args_value | string %}
128
+ {{- args_value }}
129
+ {{- '\n</parameter>\n' }}
130
+ {%- endfor %}
131
+ {%- endif %}
132
+ {{- '</function>\n</tool_call>' }}
133
+ {%- endfor %}
134
+ {%- endif %}
135
+ {{- '<|im_end|>\n' }}
136
+ {%- elif message.role == "tool" %}
137
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
138
+ {{- '<|im_start|>user' }}
139
+ {%- endif %}
140
+ {{- '\n<tool_response>\n' }}
141
+ {{- content }}
142
+ {{- '\n</tool_response>' }}
143
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
144
+ {{- '<|im_end|>\n' }}
145
+ {%- elif loop.last %}
146
+ {{- '<|im_end|>\n' }}
147
+ {%- endif %}
148
+ {%- else %}
149
+ {{- raise_exception('Unexpected message role.') }}
150
+ {%- endif %}
151
+ {%- endfor %}
152
+ {%- if add_generation_prompt %}
153
+ {{- '<|im_start|>assistant\n' }}
154
+ {%- if enable_thinking is defined and enable_thinking is false %}
155
+ {{- '<think>\n\n</think>\n\n' }}
156
+ {%- else %}
157
+ {{- '<think>\n' }}
158
+ {%- endif %}
159
+ {%- endif %}
config.json ADDED
@@ -0,0 +1,480 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "InternS2MobiusForConditionalGeneration"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_interns2_mobius.InternS2MobiusConfig",
7
+ "AutoModelForCausalLM": "modeling_interns2_mobius.InternS2MobiusForCausalLM",
8
+ "AutoModel": "modeling_interns2_mobius.InternS2MobiusModel",
9
+ "AutoModelForImageTextToText": "modeling_interns2_mobius.InternS2MobiusForConditionalGeneration",
10
+ "AutoModelForMultimodalLM": "modeling_interns2_mobius.InternS2MobiusForConditionalGeneration"
11
+ },
12
+ "eos_token_id": [
13
+ 248046,
14
+ 248044
15
+ ],
16
+ "image_token_id": 248056,
17
+ "model_type": "interns2_mobius",
18
+ "quantization": {
19
+ "group_size": 64,
20
+ "bits": 4,
21
+ "mode": "affine",
22
+ "model.layers.0.mlp.shared_expert_gate": {
23
+ "group_size": 64,
24
+ "bits": 8
25
+ },
26
+ "model.layers.1.mlp.shared_expert_gate": {
27
+ "group_size": 64,
28
+ "bits": 8
29
+ },
30
+ "model.layers.2.mlp.shared_expert_gate": {
31
+ "group_size": 64,
32
+ "bits": 8
33
+ },
34
+ "model.layers.3.mlp.shared_expert_gate": {
35
+ "group_size": 64,
36
+ "bits": 8
37
+ },
38
+ "model.layers.4.mlp.shared_expert_gate": {
39
+ "group_size": 64,
40
+ "bits": 8
41
+ },
42
+ "model.layers.5.mlp.shared_expert_gate": {
43
+ "group_size": 64,
44
+ "bits": 8
45
+ },
46
+ "model.layers.6.mlp.shared_expert_gate": {
47
+ "group_size": 64,
48
+ "bits": 8
49
+ },
50
+ "model.layers.7.mlp.shared_expert_gate": {
51
+ "group_size": 64,
52
+ "bits": 8
53
+ },
54
+ "model.layers.8.mlp.shared_expert_gate": {
55
+ "group_size": 64,
56
+ "bits": 8
57
+ },
58
+ "model.layers.9.mlp.shared_expert_gate": {
59
+ "group_size": 64,
60
+ "bits": 8
61
+ },
62
+ "model.layers.10.mlp.shared_expert_gate": {
63
+ "group_size": 64,
64
+ "bits": 8
65
+ },
66
+ "model.layers.11.mlp.shared_expert_gate": {
67
+ "group_size": 64,
68
+ "bits": 8
69
+ },
70
+ "model.layers.12.mlp.shared_expert_gate": {
71
+ "group_size": 64,
72
+ "bits": 8
73
+ },
74
+ "model.layers.13.mlp.shared_expert_gate": {
75
+ "group_size": 64,
76
+ "bits": 8
77
+ },
78
+ "model.layers.14.mlp.shared_expert_gate": {
79
+ "group_size": 64,
80
+ "bits": 8
81
+ },
82
+ "model.layers.15.mlp.shared_expert_gate": {
83
+ "group_size": 64,
84
+ "bits": 8
85
+ },
86
+ "model.layers.16.mlp.shared_expert_gate": {
87
+ "group_size": 64,
88
+ "bits": 8
89
+ },
90
+ "model.layers.17.mlp.shared_expert_gate": {
91
+ "group_size": 64,
92
+ "bits": 8
93
+ },
94
+ "model.layers.18.mlp.shared_expert_gate": {
95
+ "group_size": 64,
96
+ "bits": 8
97
+ },
98
+ "model.layers.19.mlp.shared_expert_gate": {
99
+ "group_size": 64,
100
+ "bits": 8
101
+ },
102
+ "model.layers.20.mlp.shared_expert_gate": {
103
+ "group_size": 64,
104
+ "bits": 8
105
+ },
106
+ "model.layers.21.mlp.shared_expert_gate": {
107
+ "group_size": 64,
108
+ "bits": 8
109
+ },
110
+ "model.layers.22.mlp.shared_expert_gate": {
111
+ "group_size": 64,
112
+ "bits": 8
113
+ },
114
+ "model.layers.23.mlp.shared_expert_gate": {
115
+ "group_size": 64,
116
+ "bits": 8
117
+ },
118
+ "model.layers.24.mlp.shared_expert_gate": {
119
+ "group_size": 64,
120
+ "bits": 8
121
+ },
122
+ "model.layers.25.mlp.shared_expert_gate": {
123
+ "group_size": 64,
124
+ "bits": 8
125
+ },
126
+ "model.layers.26.mlp.shared_expert_gate": {
127
+ "group_size": 64,
128
+ "bits": 8
129
+ },
130
+ "model.layers.27.mlp.shared_expert_gate": {
131
+ "group_size": 64,
132
+ "bits": 8
133
+ },
134
+ "model.layers.28.mlp.shared_expert_gate": {
135
+ "group_size": 64,
136
+ "bits": 8
137
+ },
138
+ "model.layers.29.mlp.shared_expert_gate": {
139
+ "group_size": 64,
140
+ "bits": 8
141
+ },
142
+ "model.layers.30.mlp.shared_expert_gate": {
143
+ "group_size": 64,
144
+ "bits": 8
145
+ },
146
+ "model.layers.31.mlp.shared_expert_gate": {
147
+ "group_size": 64,
148
+ "bits": 8
149
+ },
150
+ "model.layers.32.mlp.shared_expert_gate": {
151
+ "group_size": 64,
152
+ "bits": 8
153
+ },
154
+ "model.layers.33.mlp.shared_expert_gate": {
155
+ "group_size": 64,
156
+ "bits": 8
157
+ },
158
+ "model.layers.34.mlp.shared_expert_gate": {
159
+ "group_size": 64,
160
+ "bits": 8
161
+ },
162
+ "model.layers.35.mlp.shared_expert_gate": {
163
+ "group_size": 64,
164
+ "bits": 8
165
+ },
166
+ "model.layers.36.mlp.shared_expert_gate": {
167
+ "group_size": 64,
168
+ "bits": 8
169
+ },
170
+ "model.layers.37.mlp.shared_expert_gate": {
171
+ "group_size": 64,
172
+ "bits": 8
173
+ },
174
+ "model.layers.38.mlp.shared_expert_gate": {
175
+ "group_size": 64,
176
+ "bits": 8
177
+ },
178
+ "model.layers.39.mlp.shared_expert_gate": {
179
+ "group_size": 64,
180
+ "bits": 8
181
+ },
182
+ "model.meta_mlp.0.gate": {
183
+ "group_size": 64,
184
+ "bits": 8
185
+ },
186
+ "model.meta_mlp.1.gate": {
187
+ "group_size": 64,
188
+ "bits": 8
189
+ },
190
+ "model.meta_mlp.2.gate": {
191
+ "group_size": 64,
192
+ "bits": 8
193
+ },
194
+ "model.meta_mlp.3.gate": {
195
+ "group_size": 64,
196
+ "bits": 8
197
+ }
198
+ },
199
+ "quantization_config": {
200
+ "group_size": 64,
201
+ "bits": 4,
202
+ "mode": "affine",
203
+ "model.layers.0.mlp.shared_expert_gate": {
204
+ "group_size": 64,
205
+ "bits": 8
206
+ },
207
+ "model.layers.1.mlp.shared_expert_gate": {
208
+ "group_size": 64,
209
+ "bits": 8
210
+ },
211
+ "model.layers.2.mlp.shared_expert_gate": {
212
+ "group_size": 64,
213
+ "bits": 8
214
+ },
215
+ "model.layers.3.mlp.shared_expert_gate": {
216
+ "group_size": 64,
217
+ "bits": 8
218
+ },
219
+ "model.layers.4.mlp.shared_expert_gate": {
220
+ "group_size": 64,
221
+ "bits": 8
222
+ },
223
+ "model.layers.5.mlp.shared_expert_gate": {
224
+ "group_size": 64,
225
+ "bits": 8
226
+ },
227
+ "model.layers.6.mlp.shared_expert_gate": {
228
+ "group_size": 64,
229
+ "bits": 8
230
+ },
231
+ "model.layers.7.mlp.shared_expert_gate": {
232
+ "group_size": 64,
233
+ "bits": 8
234
+ },
235
+ "model.layers.8.mlp.shared_expert_gate": {
236
+ "group_size": 64,
237
+ "bits": 8
238
+ },
239
+ "model.layers.9.mlp.shared_expert_gate": {
240
+ "group_size": 64,
241
+ "bits": 8
242
+ },
243
+ "model.layers.10.mlp.shared_expert_gate": {
244
+ "group_size": 64,
245
+ "bits": 8
246
+ },
247
+ "model.layers.11.mlp.shared_expert_gate": {
248
+ "group_size": 64,
249
+ "bits": 8
250
+ },
251
+ "model.layers.12.mlp.shared_expert_gate": {
252
+ "group_size": 64,
253
+ "bits": 8
254
+ },
255
+ "model.layers.13.mlp.shared_expert_gate": {
256
+ "group_size": 64,
257
+ "bits": 8
258
+ },
259
+ "model.layers.14.mlp.shared_expert_gate": {
260
+ "group_size": 64,
261
+ "bits": 8
262
+ },
263
+ "model.layers.15.mlp.shared_expert_gate": {
264
+ "group_size": 64,
265
+ "bits": 8
266
+ },
267
+ "model.layers.16.mlp.shared_expert_gate": {
268
+ "group_size": 64,
269
+ "bits": 8
270
+ },
271
+ "model.layers.17.mlp.shared_expert_gate": {
272
+ "group_size": 64,
273
+ "bits": 8
274
+ },
275
+ "model.layers.18.mlp.shared_expert_gate": {
276
+ "group_size": 64,
277
+ "bits": 8
278
+ },
279
+ "model.layers.19.mlp.shared_expert_gate": {
280
+ "group_size": 64,
281
+ "bits": 8
282
+ },
283
+ "model.layers.20.mlp.shared_expert_gate": {
284
+ "group_size": 64,
285
+ "bits": 8
286
+ },
287
+ "model.layers.21.mlp.shared_expert_gate": {
288
+ "group_size": 64,
289
+ "bits": 8
290
+ },
291
+ "model.layers.22.mlp.shared_expert_gate": {
292
+ "group_size": 64,
293
+ "bits": 8
294
+ },
295
+ "model.layers.23.mlp.shared_expert_gate": {
296
+ "group_size": 64,
297
+ "bits": 8
298
+ },
299
+ "model.layers.24.mlp.shared_expert_gate": {
300
+ "group_size": 64,
301
+ "bits": 8
302
+ },
303
+ "model.layers.25.mlp.shared_expert_gate": {
304
+ "group_size": 64,
305
+ "bits": 8
306
+ },
307
+ "model.layers.26.mlp.shared_expert_gate": {
308
+ "group_size": 64,
309
+ "bits": 8
310
+ },
311
+ "model.layers.27.mlp.shared_expert_gate": {
312
+ "group_size": 64,
313
+ "bits": 8
314
+ },
315
+ "model.layers.28.mlp.shared_expert_gate": {
316
+ "group_size": 64,
317
+ "bits": 8
318
+ },
319
+ "model.layers.29.mlp.shared_expert_gate": {
320
+ "group_size": 64,
321
+ "bits": 8
322
+ },
323
+ "model.layers.30.mlp.shared_expert_gate": {
324
+ "group_size": 64,
325
+ "bits": 8
326
+ },
327
+ "model.layers.31.mlp.shared_expert_gate": {
328
+ "group_size": 64,
329
+ "bits": 8
330
+ },
331
+ "model.layers.32.mlp.shared_expert_gate": {
332
+ "group_size": 64,
333
+ "bits": 8
334
+ },
335
+ "model.layers.33.mlp.shared_expert_gate": {
336
+ "group_size": 64,
337
+ "bits": 8
338
+ },
339
+ "model.layers.34.mlp.shared_expert_gate": {
340
+ "group_size": 64,
341
+ "bits": 8
342
+ },
343
+ "model.layers.35.mlp.shared_expert_gate": {
344
+ "group_size": 64,
345
+ "bits": 8
346
+ },
347
+ "model.layers.36.mlp.shared_expert_gate": {
348
+ "group_size": 64,
349
+ "bits": 8
350
+ },
351
+ "model.layers.37.mlp.shared_expert_gate": {
352
+ "group_size": 64,
353
+ "bits": 8
354
+ },
355
+ "model.layers.38.mlp.shared_expert_gate": {
356
+ "group_size": 64,
357
+ "bits": 8
358
+ },
359
+ "model.layers.39.mlp.shared_expert_gate": {
360
+ "group_size": 64,
361
+ "bits": 8
362
+ },
363
+ "model.meta_mlp.0.gate": {
364
+ "group_size": 64,
365
+ "bits": 8
366
+ },
367
+ "model.meta_mlp.1.gate": {
368
+ "group_size": 64,
369
+ "bits": 8
370
+ },
371
+ "model.meta_mlp.2.gate": {
372
+ "group_size": 64,
373
+ "bits": 8
374
+ },
375
+ "model.meta_mlp.3.gate": {
376
+ "group_size": 64,
377
+ "bits": 8
378
+ }
379
+ },
380
+ "text_config": {
381
+ "model_type": "interns2_mobius_text",
382
+ "attention_bias": false,
383
+ "attention_dropout": 0.0,
384
+ "attn_output_gate": true,
385
+ "dtype": "bfloat16",
386
+ "eos_token_id": 248044,
387
+ "full_attention_interval": 4,
388
+ "head_dim": 256,
389
+ "hidden_act": "silu",
390
+ "hidden_size": 2048,
391
+ "initializer_range": 0.02,
392
+ "layer_types": [
393
+ "linear_attention",
394
+ "linear_attention",
395
+ "linear_attention",
396
+ "full_attention",
397
+ "linear_attention",
398
+ "linear_attention",
399
+ "linear_attention",
400
+ "full_attention",
401
+ "linear_attention",
402
+ "linear_attention",
403
+ "linear_attention",
404
+ "full_attention",
405
+ "linear_attention",
406
+ "linear_attention",
407
+ "linear_attention",
408
+ "full_attention",
409
+ "linear_attention",
410
+ "linear_attention",
411
+ "linear_attention",
412
+ "full_attention",
413
+ "linear_attention",
414
+ "linear_attention",
415
+ "linear_attention",
416
+ "full_attention",
417
+ "linear_attention",
418
+ "linear_attention",
419
+ "linear_attention",
420
+ "full_attention",
421
+ "linear_attention",
422
+ "linear_attention",
423
+ "linear_attention",
424
+ "full_attention",
425
+ "linear_attention",
426
+ "linear_attention",
427
+ "linear_attention",
428
+ "full_attention",
429
+ "linear_attention",
430
+ "linear_attention",
431
+ "linear_attention",
432
+ "full_attention"
433
+ ],
434
+ "linear_conv_kernel_dim": 4,
435
+ "linear_key_head_dim": 128,
436
+ "linear_num_key_heads": 16,
437
+ "linear_num_value_heads": 32,
438
+ "linear_value_head_dim": 128,
439
+ "max_position_embeddings": 262144,
440
+ "mlp_only_layers": [],
441
+ "moe_intermediate_size": 512,
442
+ "mtp_num_hidden_layers": 1,
443
+ "mtp_use_dedicated_embeddings": false,
444
+ "mtp_num_experts": 256,
445
+ "mtp_num_experts_per_tok": 8,
446
+ "num_attention_heads": 16,
447
+ "num_blocks": 4,
448
+ "num_experts": 2560,
449
+ "num_experts_per_tok": 8,
450
+ "num_hidden_layers": 40,
451
+ "num_key_value_heads": 2,
452
+ "rms_norm_eps": 1e-06,
453
+ "router_aux_loss_coef": 0.001,
454
+ "shared_expert_intermediate_size": 512,
455
+ "use_cache": true,
456
+ "vocab_size": 251392,
457
+ "mamba_ssm_dtype": "float32",
458
+ "rope_parameters": {
459
+ "mrope_interleaved": true,
460
+ "mrope_section": [
461
+ 11,
462
+ 11,
463
+ 10
464
+ ],
465
+ "rope_type": "default",
466
+ "rope_theta": 10000000,
467
+ "partial_rotary_factor": 0.25
468
+ },
469
+ "pad_token_id": null,
470
+ "bos_token_id": null,
471
+ "tie_word_embeddings": false,
472
+ "output_router_logits": false,
473
+ "partial_rotary_factor": 0.25
474
+ },
475
+ "tie_word_embeddings": false,
476
+ "transformers_version": "5.2.0",
477
+ "video_token_id": 248057,
478
+ "vision_end_token_id": 248054,
479
+ "vision_start_token_id": 248053
480
+ }
configuration_interns2_mobius.py ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2025 InternS2Mobius Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from transformers.configuration_utils import PreTrainedConfig, layer_type_validation
15
+ from transformers.modeling_rope_utils import RopeParameters
16
+
17
+
18
+ class InternS2MobiusVisionConfig(PreTrainedConfig):
19
+ model_type = "interns2_mobius"
20
+ base_config_key = "vision_config"
21
+
22
+ def __init__(
23
+ self,
24
+ depth=27,
25
+ hidden_size=1152,
26
+ hidden_act="gelu_pytorch_tanh",
27
+ intermediate_size=4304,
28
+ num_heads=16,
29
+ in_channels=3,
30
+ patch_size=16,
31
+ spatial_merge_size=2,
32
+ temporal_patch_size=2,
33
+ out_hidden_size=3584,
34
+ num_position_embeddings=2304,
35
+ initializer_range=0.02,
36
+ deepstack_visual_indexes=None,
37
+ **kwargs,
38
+ ):
39
+ super().__init__(**kwargs)
40
+
41
+ self.depth = depth
42
+ self.hidden_size = hidden_size
43
+ self.hidden_act = hidden_act
44
+ self.intermediate_size = intermediate_size
45
+ self.num_heads = num_heads
46
+ self.in_channels = in_channels
47
+ self.patch_size = patch_size
48
+ self.spatial_merge_size = spatial_merge_size
49
+ self.temporal_patch_size = temporal_patch_size
50
+ self.out_hidden_size = out_hidden_size
51
+ self.num_position_embeddings = num_position_embeddings
52
+ self.initializer_range = initializer_range
53
+ self.deepstack_visual_indexes = deepstack_visual_indexes if deepstack_visual_indexes is not None else []
54
+
55
+
56
+ class InternS2MobiusTextConfig(PreTrainedConfig):
57
+ r"""
58
+ This is the configuration class to store the configuration of a [`InternS2MobiusTextModel`]. It is used to instantiate a
59
+ InternS2Mobius model according to the specified arguments, defining the model architecture.
60
+ Instantiating a configuration with the defaults will yield a similar configuration to that of
61
+ InternS2Mobius.
62
+
63
+ Configuration objects inherit from [`PreTrainedConfig`] and can be used to control the model outputs. Read the
64
+ documentation from [`PreTrainedConfig`] for more information.
65
+
66
+
67
+ Args:
68
+ vocab_size (`int`, *optional*, defaults to 248320):
69
+ Vocabulary size of the model. Defines the number of different tokens that can be represented by the
70
+ `inputs_ids`.
71
+ hidden_size (`int`, *optional*, defaults to 2048):
72
+ Dimension of the hidden representations.
73
+ num_hidden_layers (`int`, *optional*, defaults to 40):
74
+ Number of hidden layers in the Transformer encoder.
75
+ num_attention_heads (`int`, *optional*, defaults to 16):
76
+ Number of attention heads for each attention layer in the Transformer encoder.
77
+ num_key_value_heads (`int`, *optional*, defaults to 2):
78
+ This is the number of key_value heads that should be used to implement Grouped Query Attention. If
79
+ `num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
80
+ `num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used. When
81
+ converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
82
+ by meanpooling all the original heads within that group. For more details checkout [this
83
+ paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to `32`.
84
+ hidden_act (`str`, *optional*, defaults to `"silu"`):
85
+ The non-linear activation function in the decoder.
86
+ max_position_embeddings (`int`, *optional*, defaults to 32768):
87
+ The maximum sequence length that this model might ever be used with.
88
+ initializer_range (`float`, *optional*, defaults to 0.02):
89
+ The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
90
+ rms_norm_eps (`float`, *optional*, defaults to 1e-06):
91
+ The epsilon used by the rms normalization layers.
92
+ use_cache (`bool`, *optional*, defaults to `True`):
93
+ Whether or not the model should return the last key/values attentions (not used by all models). Only
94
+ relevant if `config.is_decoder=True`.
95
+ tie_word_embeddings (`bool`, *optional*, defaults to `False`):
96
+ Whether the model's input and output word embeddings should be tied.
97
+ rope_parameters (`RopeParameters`, *optional*):
98
+ Dictionary containing the configuration parameters for the RoPE embeddings. The dictionary should contain
99
+ a value for `rope_theta` and optionally parameters used for scaling in case you want to use RoPE
100
+ with longer `max_position_embeddings`.
101
+ attention_bias (`bool`, *optional*, defaults to `False`):
102
+ Whether to use a bias in the query, key, value and output projection layers during self-attention.
103
+ attention_dropout (`float`, *optional*, defaults to 0.0):
104
+ The dropout ratio for the attention probabilities.
105
+ head_dim (`int`, *optional*, defaults to 256):
106
+ Projection weights dimension in multi-head attention.
107
+ linear_conv_kernel_dim (`int`, *optional*, defaults to 4):
108
+ Kernel size of the convolution used in linear attention layers.
109
+ linear_key_head_dim (`int`, *optional*, defaults to 128):
110
+ Dimension of each key head in linear attention.
111
+ linear_value_head_dim (`int`, *optional*, defaults to 128):
112
+ Dimension of each value head in linear attention.
113
+ linear_num_key_heads (`int`, *optional*, defaults to 16):
114
+ Number of key heads used in linear attention layers.
115
+ linear_num_value_heads (`int`, *optional*, defaults to 32):
116
+ Number of value heads used in linear attention layers.
117
+ moe_intermediate_size (`int`, *optional*, defaults to 512):
118
+ Intermediate size of the routed expert.
119
+ shared_expert_intermediate_size (`int`, *optional*, defaults to 512):
120
+ Intermediate size of the shared expert.
121
+ num_experts_per_tok (`int`, *optional*, defaults to 8):
122
+ Number of selected experts.
123
+ num_experts (`int`, *optional*, defaults to 256):
124
+ Number of routed experts.
125
+ output_router_logits (`bool`, *optional*, defaults to `False`):
126
+ Whether or not the router logits should be returned by the model. Enabling this will also
127
+ allow the model to output the auxiliary loss, including load balancing loss and router z-loss.
128
+ router_aux_loss_coef (`float`, *optional*, defaults to 0.001):
129
+ The aux loss factor for the total loss.
130
+ layer_types (`list[str]`, *optional*):
131
+ Types of each layer (attention or linear).
132
+ pad_token_id (`int`, *optional*):
133
+ Padding token id.
134
+ bos_token_id (`int`, *optional*):
135
+ Beginning of stream token id.
136
+ eos_token_id (`int`, *optional*):
137
+ End of stream token id.
138
+
139
+ ```python
140
+ >>> from transformers import InternS2MobiusTextModel, InternS2MobiusTextConfig
141
+
142
+ >>> # Initializing a InternS2Mobius style configuration
143
+ >>> configuration = InternS2MobiusTextConfig()
144
+
145
+ >>> # Initializing a model from the InternS2Mobius style configuration
146
+ >>> model = InternS2MobiusTextModel(configuration)
147
+
148
+ >>> # Accessing the model configuration
149
+ >>> configuration = model.config
150
+ ```
151
+ """
152
+
153
+ # NOTE: `model_type` is kept as `interns2_mobius_text` to match config.json.
154
+ model_type = "interns2_mobius_text"
155
+ keys_to_ignore_at_inference = ["past_key_values"]
156
+
157
+ base_model_tp_plan = {
158
+ "layers.*.self_attn.q_proj": "colwise",
159
+ "layers.*.self_attn.k_proj": "colwise",
160
+ "layers.*.self_attn.v_proj": "colwise",
161
+ "layers.*.self_attn.o_proj": "rowwise",
162
+ "meta_mlp.*.experts.gate_up_proj": "packed_colwise",
163
+ "meta_mlp.*.experts.down_proj": "rowwise",
164
+ "layers.*.mlp.shared_expert.gate_proj": "colwise",
165
+ "layers.*.mlp.shared_expert.up_proj": "colwise",
166
+ "layers.*.mlp.shared_expert.down_proj": "rowwise",
167
+ }
168
+ base_model_pp_plan = {
169
+ "embed_tokens": (["input_ids"], ["inputs_embeds"]),
170
+ "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
171
+ "norm": (["hidden_states"], ["hidden_states"]),
172
+ }
173
+ base_config_key = "text_config"
174
+
175
+ def __init__(
176
+ self,
177
+ vocab_size=248320,
178
+ hidden_size=2048,
179
+ num_hidden_layers=40,
180
+ num_attention_heads=16,
181
+ num_key_value_heads=2,
182
+ hidden_act="silu",
183
+ max_position_embeddings=32768,
184
+ initializer_range=0.02,
185
+ rms_norm_eps=1e-6,
186
+ use_cache=True,
187
+ tie_word_embeddings=False,
188
+ rope_parameters: RopeParameters | dict[str, RopeParameters] | None = None,
189
+ attention_bias=False,
190
+ attention_dropout=0.0,
191
+ head_dim=256,
192
+ linear_conv_kernel_dim=4,
193
+ linear_key_head_dim=128,
194
+ linear_value_head_dim=128,
195
+ linear_num_key_heads=16,
196
+ linear_num_value_heads=32,
197
+ moe_intermediate_size=512,
198
+ shared_expert_intermediate_size=512,
199
+ num_experts_per_tok=8,
200
+ num_experts=256,
201
+ output_router_logits=False,
202
+ router_aux_loss_coef=0.001,
203
+ num_blocks=4,
204
+ dtype=None,
205
+ layer_types=None,
206
+ pad_token_id: int | None = None,
207
+ bos_token_id: int | None = None,
208
+ eos_token_id: int | None = None,
209
+ **kwargs,
210
+ ):
211
+ kwargs["ignore_keys_at_rope_validation"] = {"mrope_section", "mrope_interleaved"}
212
+ self.num_blocks = num_blocks
213
+ self.dtype = dtype
214
+ self.pad_token_id = pad_token_id
215
+ self.bos_token_id = bos_token_id
216
+ self.eos_token_id = eos_token_id
217
+ self.tie_word_embeddings = tie_word_embeddings
218
+ self.vocab_size = vocab_size
219
+ self.max_position_embeddings = max_position_embeddings
220
+ self.hidden_size = hidden_size
221
+ self.num_hidden_layers = num_hidden_layers
222
+ self.num_attention_heads = num_attention_heads
223
+ self.num_key_value_heads = num_key_value_heads
224
+ self.hidden_act = hidden_act
225
+ self.initializer_range = initializer_range
226
+ self.rms_norm_eps = rms_norm_eps
227
+ self.use_cache = use_cache
228
+ self.attention_bias = attention_bias
229
+ self.attention_dropout = attention_dropout
230
+ self.head_dim = head_dim
231
+ self.rope_parameters = rope_parameters
232
+ kwargs.setdefault("partial_rotary_factor", 0.25) # assign default for BC
233
+
234
+ self.layer_types = layer_types
235
+ if self.layer_types is None:
236
+ interval_pattern = kwargs.get("full_attention_interval", 4)
237
+ self.layer_types = [
238
+ "linear_attention" if bool((i + 1) % interval_pattern) else "full_attention"
239
+ for i in range(self.num_hidden_layers)
240
+ ]
241
+ layer_type_validation(self.layer_types, self.num_hidden_layers)
242
+
243
+ # linear attention part
244
+ self.linear_conv_kernel_dim = linear_conv_kernel_dim
245
+ self.linear_key_head_dim = linear_key_head_dim
246
+ self.linear_value_head_dim = linear_value_head_dim
247
+ self.linear_num_key_heads = linear_num_key_heads
248
+ self.linear_num_value_heads = linear_num_value_heads
249
+ self.moe_intermediate_size = moe_intermediate_size
250
+ self.shared_expert_intermediate_size = shared_expert_intermediate_size
251
+ self.num_experts_per_tok = num_experts_per_tok
252
+ self.num_experts = num_experts
253
+ self.output_router_logits = output_router_logits
254
+ self.router_aux_loss_coef = router_aux_loss_coef
255
+ super().__init__(**kwargs)
256
+
257
+
258
+ class InternS2MobiusConfig(PreTrainedConfig):
259
+ r"""
260
+ This is the configuration class to store the configuration of a [`InternS2MobiusModel`]. It is used to instantiate a
261
+ InternS2Mobius model according to the specified arguments, defining the model architecture. Instantiating a configuration
262
+ with the defaults will yield a similar configuration to that of
263
+ InternS2Mobius.
264
+
265
+ Configuration objects inherit from [`PreTrainedConfig`] and can be used to control the model outputs. Read the
266
+ documentation from [`PreTrainedConfig`] for more information.
267
+
268
+
269
+ Args:
270
+ text_config (`Union[PreTrainedConfig, dict]`, *optional*, defaults to `InternS2MobiusTextConfig`):
271
+ The config object or dictionary of the text backbone.
272
+ vision_config (`Union[PreTrainedConfig, dict]`, *optional*, defaults to `InternS2MobiusVisionConfig`):
273
+ The config object or dictionary of the vision backbone.
274
+ image_token_id (`int`, *optional*, defaults to 248056):
275
+ The image token index to encode the image prompt.
276
+ video_token_id (`int`, *optional*, defaults to 248057):
277
+ The video token index to encode the image prompt.
278
+ vision_start_token_id (`int`, *optional*, defaults to 248053):
279
+ The start token index to encode the image prompt.
280
+ vision_end_token_id (`int`, *optional*, defaults to 248054):
281
+ The end token index to encode the image prompt.
282
+ tie_word_embeddings (`bool`, *optional*, defaults to `False`):
283
+ Whether to tie the word embeddings.
284
+
285
+ ```python
286
+ >>> from transformers import InternS2MobiusForConditionalGeneration, InternS2MobiusConfig
287
+
288
+ >>> # Initializing a InternS2Mobius style configuration
289
+ >>> configuration = InternS2MobiusConfig()
290
+
291
+ >>> # Initializing a model from the InternS2Mobius style configuration
292
+ >>> model = InternS2MobiusForConditionalGeneration(configuration)
293
+
294
+ >>> # Accessing the model configuration
295
+ >>> configuration = model.config
296
+ ```"""
297
+
298
+ model_type = "interns2_mobius"
299
+ sub_configs = {
300
+ "vision_config": InternS2MobiusVisionConfig,
301
+ "text_config": InternS2MobiusTextConfig,
302
+ }
303
+ keys_to_ignore_at_inference = ["past_key_values"]
304
+
305
+ def __init__(
306
+ self,
307
+ text_config=None,
308
+ vision_config=None,
309
+ image_token_id=248056,
310
+ video_token_id=248057,
311
+ vision_start_token_id=248053,
312
+ vision_end_token_id=248054,
313
+ tie_word_embeddings=False,
314
+ **kwargs,
315
+ ):
316
+ if isinstance(vision_config, dict):
317
+ self.vision_config = self.sub_configs["vision_config"](**vision_config)
318
+ elif vision_config is None:
319
+ self.vision_config = self.sub_configs["vision_config"]()
320
+
321
+ if isinstance(text_config, dict):
322
+ self.text_config = self.sub_configs["text_config"](**text_config)
323
+ elif text_config is None:
324
+ self.text_config = self.sub_configs["text_config"]()
325
+
326
+ self.image_token_id = image_token_id
327
+ self.video_token_id = video_token_id
328
+ self.vision_start_token_id = vision_start_token_id
329
+ self.vision_end_token_id = vision_end_token_id
330
+ self.tie_word_embeddings = tie_word_embeddings
331
+ super().__init__(**kwargs)
332
+ self.auto_map = {
333
+ "AutoConfig": "configuration_interns2_mobius.InternS2MobiusConfig",
334
+ "AutoModelForCausalLM": "modeling_interns2_mobius.InternS2MobiusForCausalLM",
335
+ "AutoModel": "modeling_interns2_mobius.InternS2MobiusModel",
336
+ "AutoModelForImageTextToText": "modeling_interns2_mobius.InternS2MobiusForConditionalGeneration",
337
+ "AutoModelForMultimodalLM": "modeling_interns2_mobius.InternS2MobiusForConditionalGeneration",
338
+ }
339
+ self.architectures = ["InternS2MobiusForConditionalGeneration"]
340
+
341
+
342
+ __all__ = ["InternS2MobiusConfig", "InternS2MobiusTextConfig"]
generation_config.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ "transformers_version": "4.57.0.dev0"
13
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model-00001-of-00005.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:37dd751b7b015e46219f3fd714ce9dcaa6b03a9dfbb0540c50bda48177fe73c4
3
+ size 4110204953
model-00002-of-00005.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:024ee248a99d9381dc1b5fabc9fac07dcfc8f7083e4a30262651146dcfeadad4
3
+ size 4535420328
model-00003-of-00005.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be7b3d6066c8d9fce5d6aa4480ea5916348128d41e28cfe62d707d5c9fc26e88
3
+ size 4535420346
model-00004-of-00005.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:52706a81b07a86fb877b6dc68b5b4b265ba46a2ae29ba8069592cc69d509ff73
3
+ size 4535420346
model-00005-of-00005.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6908ed715a14737438f7721e05ffc4028b65b35f0c4b39f5082132c17df056ab
3
+ size 1799557881
model.safetensors.index.json ADDED
The diff for this file is too large to render. See raw diff
 
modeling_interns2_mobius.py ADDED
The diff for this file is too large to render. See raw diff
 
processing_interns2_mobius.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2025 InternS2Mobius Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import numpy as np
15
+
16
+ from transformers.feature_extraction_utils import BatchFeature
17
+ from transformers.image_utils import ImageInput
18
+ from transformers.processing_utils import MultiModalData, ProcessingKwargs, ProcessorMixin, Unpack
19
+ from transformers.tokenization_utils_base import PreTokenizedInput, TextInput
20
+ from transformers.utils import auto_docstring, logging
21
+ from transformers.video_utils import VideoInput
22
+
23
+
24
+ logger = logging.get_logger(__name__)
25
+
26
+
27
+ class InternS2MobiusProcessorKwargs(ProcessingKwargs, total=False):
28
+ _defaults = {
29
+ "text_kwargs": {
30
+ "padding": False,
31
+ "return_token_type_ids": False,
32
+ "return_mm_token_type_ids": False,
33
+ },
34
+ "videos_kwargs": {"return_metadata": True},
35
+ }
36
+
37
+
38
+ @auto_docstring
39
+ class InternS2MobiusProcessor(ProcessorMixin):
40
+ def __init__(self, image_processor=None, tokenizer=None, video_processor=None, chat_template=None, **kwargs):
41
+ self.image_token = "<|image_pad|>" if not hasattr(tokenizer, "image_token") else tokenizer.image_token
42
+ self.video_token = "<|video_pad|>" if not hasattr(tokenizer, "video_token") else tokenizer.video_token
43
+ self.image_token_id = (
44
+ tokenizer.image_token_id
45
+ if getattr(tokenizer, "image_token_id", None)
46
+ else tokenizer.convert_tokens_to_ids(self.image_token)
47
+ )
48
+ self.video_token_id = (
49
+ tokenizer.video_token_id
50
+ if getattr(tokenizer, "video_token_id", None)
51
+ else tokenizer.convert_tokens_to_ids(self.video_token)
52
+ )
53
+ super().__init__(image_processor, tokenizer, video_processor, chat_template=chat_template)
54
+ self.vision_start_token = (
55
+ "<|vision_start|>" if not hasattr(tokenizer, "vision_start_token") else tokenizer.vision_start_token
56
+ )
57
+ self.vision_end_token = (
58
+ "<|vision_end|>" if not hasattr(tokenizer, "vision_end_token") else tokenizer.vision_end_token
59
+ )
60
+ self.vision_start_token_id = (
61
+ tokenizer.vision_start_token_id
62
+ if getattr(tokenizer, "vision_start_token_id", None)
63
+ else tokenizer.convert_tokens_to_ids(self.vision_start_token)
64
+ )
65
+ self.vision_end_token_id = (
66
+ tokenizer.vision_end_token_id
67
+ if getattr(tokenizer, "vision_end_token_id", None)
68
+ else tokenizer.convert_tokens_to_ids(self.vision_end_token)
69
+ )
70
+
71
+ @auto_docstring
72
+ def __call__(
73
+ self,
74
+ images: ImageInput = None,
75
+ text: TextInput | PreTokenizedInput | list[TextInput] | list[PreTokenizedInput] = None,
76
+ videos: VideoInput = None,
77
+ **kwargs: Unpack[InternS2MobiusProcessorKwargs],
78
+ ) -> BatchFeature:
79
+ r"""
80
+ Returns:
81
+ [`BatchFeature`]: A [`BatchFeature`] with the following fields:
82
+
83
+ - **input_ids** -- List of token ids to be fed to a model. Returned when `text` is not `None`.
84
+ - **attention_mask** -- List of indices specifying which tokens should be attended to by the model (when
85
+ `return_attention_mask=True` or if *"attention_mask"* is in `self.model_input_names` and if `text` is not
86
+ `None`).
87
+ - **pixel_values** -- Pixel values to be fed to a model. Returned when `images` is not `None`.
88
+ - **pixel_values_videos** -- Pixel values of videos to be fed to a model. Returned when `videos` is not `None`.
89
+ - **image_grid_thw** -- List of image 3D grid in LLM. Returned when `images` is not `None`.
90
+ - **video_grid_thw** -- List of video 3D grid in LLM. Returned when `videos` is not `None`.
91
+ """
92
+ output_kwargs = self._merge_kwargs(
93
+ InternS2MobiusProcessorKwargs,
94
+ tokenizer_init_kwargs=self.tokenizer.init_kwargs,
95
+ **kwargs,
96
+ )
97
+ if images is not None:
98
+ image_inputs = self.image_processor(images=images, **output_kwargs["images_kwargs"])
99
+ image_grid_thw = image_inputs["image_grid_thw"]
100
+ else:
101
+ image_inputs = {}
102
+ image_grid_thw = None
103
+
104
+ if videos is not None:
105
+ videos_inputs = self.video_processor(videos=videos, **output_kwargs["videos_kwargs"])
106
+ video_grid_thw = videos_inputs["video_grid_thw"]
107
+ # If user has not requested video metadata, pop it
108
+ if not kwargs.get("return_metadata"):
109
+ video_metadata = videos_inputs.pop("video_metadata")
110
+ else:
111
+ video_metadata = videos_inputs["video_metadata"]
112
+ else:
113
+ videos_inputs = {}
114
+ video_grid_thw = None
115
+
116
+ if not isinstance(text, list):
117
+ text = [text]
118
+
119
+ text = text.copy() # below lines change text in-place
120
+
121
+ if image_grid_thw is not None:
122
+ merge_length = self.image_processor.merge_size**2
123
+ index = 0
124
+ for i in range(len(text)):
125
+ while self.image_token in text[i]:
126
+ num_image_tokens = image_grid_thw[index].prod() // merge_length
127
+ text[i] = text[i].replace(self.image_token, "<|placeholder|>" * num_image_tokens, 1)
128
+ index += 1
129
+ text[i] = text[i].replace("<|placeholder|>", self.image_token)
130
+
131
+ if video_grid_thw is not None:
132
+ merge_length = self.video_processor.merge_size**2
133
+ index = 0
134
+ for i in range(len(text)):
135
+ while self.video_token in text[i]:
136
+ metadata = video_metadata[index]
137
+ if metadata.fps is None:
138
+ logger.warning_once(
139
+ "Qwen3VL requires frame timestamps to construct prompts, but the `fps` of the input video could not be inferred. "
140
+ "Probably `video_metadata` was missing from inputs and you passed pre-sampled frames. "
141
+ "Defaulting to `fps=24`. Please provide `video_metadata` for more accurate results."
142
+ )
143
+ metadata.fps = 24 if metadata.fps is None else metadata.fps
144
+
145
+ # if timestamps are not provided, calculate them
146
+ curr_timestamp = self._calculate_timestamps(
147
+ metadata.frames_indices,
148
+ metadata.fps,
149
+ self.video_processor.temporal_patch_size,
150
+ )
151
+
152
+ video_placeholder = ""
153
+ frame_seqlen = video_grid_thw[index][1:].prod() // merge_length
154
+ for frame_idx in range(video_grid_thw[index][0]):
155
+ curr_time = curr_timestamp[frame_idx]
156
+ video_placeholder += f"<{curr_time:.1f} seconds>"
157
+ video_placeholder += (
158
+ self.vision_start_token + "<|placeholder|>" * frame_seqlen + self.vision_end_token
159
+ )
160
+ if f"{self.vision_start_token}{self.video_token}{self.vision_end_token}" in text[i]:
161
+ text[i] = text[i].replace(
162
+ f"{self.vision_start_token}{self.video_token}{self.vision_end_token}", video_placeholder, 1
163
+ )
164
+ else:
165
+ # vllm may input video token directly
166
+ text[i] = text[i].replace(self.video_token, video_placeholder, 1)
167
+ index += 1
168
+
169
+ text[i] = text[i].replace("<|placeholder|>", self.video_token)
170
+
171
+ return_tensors = output_kwargs["text_kwargs"].pop("return_tensors", None)
172
+ return_mm_token_type_ids = output_kwargs["text_kwargs"].pop("return_mm_token_type_ids", None)
173
+ text_inputs = self.tokenizer(text, **output_kwargs["text_kwargs"])
174
+ self._check_special_mm_tokens(text, text_inputs, modalities=["image", "video"])
175
+
176
+ if return_mm_token_type_ids:
177
+ array_ids = np.array(text_inputs["input_ids"])
178
+ mm_token_type_ids = np.zeros_like(text_inputs["input_ids"])
179
+ mm_token_type_ids[array_ids == self.image_token_id] = 1
180
+ text_inputs["mm_token_type_ids"] = mm_token_type_ids.tolist()
181
+
182
+ return BatchFeature(
183
+ data={**text_inputs, **image_inputs, **videos_inputs}, tensor_type=return_tensors
184
+ )
185
+
186
+ def _get_num_multimodal_tokens(self, image_sizes=None, video_sizes=None, **kwargs):
187
+ """
188
+ Computes the number of placeholder tokens needed for multimodal inputs with the given sizes.
189
+ Args:
190
+ image_sizes (`list[list[int]]`, *optional*):
191
+ The input sizes formatted as (height, width) per each image.
192
+ video_sizes (`list[list[int]]`, *optional*):
193
+ The input sizes formatted as (num_frames, height, width) per each video.
194
+ Returns:
195
+ `MultiModalData`: A `MultiModalData` object holding number of tokens per each of the provided
196
+ input modalities, along with other useful data.
197
+ """
198
+
199
+ vision_data = {}
200
+ if image_sizes is not None:
201
+ images_kwargs = InternS2MobiusProcessorKwargs._defaults.get("images_kwargs", {})
202
+ images_kwargs.update(kwargs)
203
+ merge_size = images_kwargs.get("merge_size", None) or self.image_processor.merge_size
204
+
205
+ num_image_patches = [
206
+ self.image_processor.get_number_of_image_patches(*image_size, images_kwargs)
207
+ for image_size in image_sizes
208
+ ]
209
+ num_image_tokens = [(num_patches // merge_size**2) for num_patches in num_image_patches]
210
+ vision_data.update({"num_image_tokens": num_image_tokens, "num_image_patches": num_image_patches})
211
+
212
+ if video_sizes is not None:
213
+ videos_kwargs = InternS2MobiusProcessorKwargs._defaults.get("videos_kwargs", {})
214
+ videos_kwargs.update(kwargs)
215
+ num_video_patches = [
216
+ self.video_processor.get_number_of_video_patches(*video_size, videos_kwargs)
217
+ for video_size in video_sizes
218
+ ]
219
+ num_video_tokens = [(num_patches // merge_size**2) for num_patches in num_video_patches]
220
+ vision_data["num_video_tokens"] = num_video_tokens
221
+
222
+ return MultiModalData(**vision_data)
223
+
224
+ def post_process_image_text_to_text(
225
+ self, generated_outputs, skip_special_tokens=True, clean_up_tokenization_spaces=False, **kwargs
226
+ ):
227
+ """
228
+ Post-process the output of the model to decode the text.
229
+
230
+ Args:
231
+ generated_outputs (`torch.Tensor` or `np.ndarray`):
232
+ The output of the model `generate` function. The output is expected to be a tensor of shape `(batch_size, sequence_length)`
233
+ or `(sequence_length,)`.
234
+ skip_special_tokens (`bool`, *optional*, defaults to `True`):
235
+ Whether or not to remove special tokens in the output. Argument passed to the tokenizer's `batch_decode` method.
236
+ clean_up_tokenization_spaces (`bool`, *optional*, defaults to `False`):
237
+ Whether or not to clean up the tokenization spaces. Argument passed to the tokenizer's `batch_decode` method.
238
+ **kwargs:
239
+ Additional arguments to be passed to the tokenizer's `batch_decode method`.
240
+
241
+ Returns:
242
+ `list[str]`: The decoded text.
243
+ """
244
+ return self.tokenizer.batch_decode(
245
+ generated_outputs,
246
+ skip_special_tokens=skip_special_tokens,
247
+ clean_up_tokenization_spaces=clean_up_tokenization_spaces,
248
+ **kwargs,
249
+ )
250
+
251
+ def _calculate_timestamps(self, indices: list[int] | np.ndarray, video_fps: float, merge_size: int = 2):
252
+ if not isinstance(indices, list):
253
+ indices = indices.tolist()
254
+ if len(indices) % merge_size != 0:
255
+ indices.extend(indices[-1] for _ in range(merge_size - len(indices) % merge_size))
256
+ timestamps = [idx / video_fps for idx in indices]
257
+ # @JJJYmmm frames are merged by self.merge_size, \
258
+ # so we need to average the timestamps between the first/last frame within the temporal patch
259
+ timestamps = [
260
+ (timestamps[i] + timestamps[i + merge_size - 1]) / 2 for i in range(0, len(timestamps), merge_size)
261
+ ]
262
+ return timestamps
263
+
264
+
265
+ __all__ = ["InternS2MobiusProcessor"]
tokenization_interns1.py ADDED
@@ -0,0 +1,1009 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2025 The Intern team and Shanghai AI Lab team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Tokenization classes for InternS1."""
16
+
17
+ import json
18
+ import os
19
+ import unicodedata
20
+ from abc import ABC, abstractmethod
21
+ from typing import Optional, Union
22
+ from functools import lru_cache
23
+
24
+ import regex as re
25
+ import sentencepiece as spm
26
+
27
+ from transformers.tokenization_utils_base import AddedToken, TextInput
28
+ from transformers.utils import logging
29
+ from packaging import version
30
+ import transformers
31
+ if version.parse(transformers.__version__) >= version.parse("5.0.0"):
32
+ from transformers.tokenization_python import PreTrainedTokenizer
33
+ else:
34
+ from transformers.tokenization_utils import PreTrainedTokenizer
35
+
36
+ logger = logging.get_logger(__name__)
37
+
38
+ try:
39
+ from rdkit import Chem, RDLogger
40
+
41
+ RDLogger.DisableLog("rdApp.error")
42
+ RDLogger.DisableLog("rdApp.*")
43
+ RDKIT_AVAILABLE = True
44
+ except ImportError:
45
+ logger.warning_once(
46
+ "If tokenization with SMILES formula is of necessity, please 'pip install RDKit' for better tokenization quality."
47
+ )
48
+ RDKIT_AVAILABLE = False
49
+
50
+ VOCAB_FILES_NAMES = {
51
+ "vocab_file": "vocab.json",
52
+ "merges_file": "merges.txt",
53
+ "sp_model_SMILES": "tokenizer_SMILES.model",
54
+ "sp_model_PROT": "tokenizer_PROT.model",
55
+ "sp_model_XNA": "tokenizer_XNA.model",
56
+ }
57
+
58
+ PRETOKENIZE_REGEX = r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+"""
59
+
60
+
61
+ class InternS1CheckModuleMixin(ABC):
62
+ """
63
+ Basic auto-detection module.
64
+
65
+ Note that short strings are ignored by this module.
66
+ """
67
+
68
+ def __init__(self, *, min_length: int):
69
+ self.min_length = min_length
70
+ self.REGEX = self._build_regex()
71
+ self.all_auto_detect_token_start = ["<SMILES_AUTO_DETECT>", "<PROT_AUTO_DETECT>", "<XNA_AUTO_DETECT>"]
72
+ self.all_auto_detect_token_end = ["</SMILES_AUTO_DETECT>", "</PROT_AUTO_DETECT>", "</XNA_AUTO_DETECT>"]
73
+ self.auto_detect_token = []
74
+ self.truncation = False
75
+
76
+ @abstractmethod
77
+ def _build_regex(self):
78
+ pass
79
+
80
+ @abstractmethod
81
+ def check_legitimacy(self, candidate: str) -> bool:
82
+ pass
83
+
84
+ def re_split(self, texts: Union[str, list[str]]) -> list[str]:
85
+ if isinstance(texts, str):
86
+ texts = [texts]
87
+
88
+ total_results = []
89
+
90
+ no_split_flag = 0
91
+
92
+ for text in texts:
93
+ if text in self.all_auto_detect_token_start:
94
+ total_results.append(text)
95
+ no_split_flag += 1
96
+ continue
97
+ elif text in self.all_auto_detect_token_end:
98
+ total_results.append(text)
99
+ no_split_flag = max(0, no_split_flag - 1)
100
+ continue
101
+
102
+ if no_split_flag > 0:
103
+ total_results.append(text)
104
+ continue
105
+
106
+ results = []
107
+ current_pos = 0
108
+ for match in self.REGEX.finditer(text):
109
+ candidate = match.group(1)
110
+
111
+ if len(candidate) >= self.min_length:
112
+ match_start, match_end = match.span(1)
113
+
114
+ if not self.check_legitimacy(candidate):
115
+ continue
116
+
117
+ if not self.truncation:
118
+ if match_start > 0 and text[match_start - 1].encode("UTF-8").isalpha():
119
+ continue
120
+ if match_end < len(text) and text[match_end].encode("UTF-8").isalpha():
121
+ continue
122
+
123
+ if match_start > current_pos:
124
+ non_candidate_part = text[current_pos:match_start]
125
+ results.append(non_candidate_part)
126
+ else:
127
+ continue
128
+
129
+ results.extend([self.auto_detect_token[0], candidate, self.auto_detect_token[1]])
130
+ current_pos = match_end
131
+
132
+ if current_pos < len(text):
133
+ remaining_part = text[current_pos:]
134
+ results.append(remaining_part)
135
+
136
+ total_results.extend(results)
137
+
138
+ return total_results
139
+
140
+
141
+ class XnaCheckModule(InternS1CheckModuleMixin):
142
+ """
143
+ XNA sequence auto-detection module.
144
+
145
+ Automatically detects XNA sequence using regex patterns.
146
+ """
147
+ def __init__(self, *, min_length: int = 27):
148
+ super().__init__(min_length=min_length)
149
+ self.auto_detect_token = ["<XNA_AUTO_DETECT>", "</XNA_AUTO_DETECT>"]
150
+ self.truncation = True
151
+
152
+ def _build_regex(self):
153
+ return re.compile(r"([ATCGU]{" + str(self.min_length) + r",})")
154
+
155
+ def check_legitimacy(self, candidate: str):
156
+ return True
157
+
158
+
159
+ class ProtCheckModule(InternS1CheckModuleMixin):
160
+ """
161
+ Protein sequence auto-detection module.
162
+
163
+ Automatically detects protein sequence using regex patterns.
164
+ """
165
+ def __init__(self, *, min_length: int = 27):
166
+ super().__init__(min_length=min_length)
167
+ self.auto_detect_token = ["<PROT_AUTO_DETECT>", "</PROT_AUTO_DETECT>"]
168
+ self.truncation = True
169
+ self._xna_pattern = re.compile(r"^[ATCGU]+$")
170
+
171
+ def _build_regex(self):
172
+ return re.compile(r"([A-Z]{" + str(self.min_length) + r",})")
173
+
174
+ def check_legitimacy(self, candidate: str):
175
+ if self._xna_pattern.match(candidate):
176
+ return False
177
+ return True
178
+
179
+
180
+ # fmt: off
181
+ bonds = ["-", "=", "#", ":", "/", "\\", ".", "$"]
182
+ organic_symbols = ["B", "C", "N", "O", "P", "S", "F", "Cl", "Br", "I"]
183
+ other_allows = bonds + ["[", "]", "(", ")", ";"]
184
+ aromatic_symbols = ["b", "c", "n", "o", "s", "p"]
185
+ elements = [
186
+ "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne",
187
+ "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca",
188
+ "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn",
189
+ "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr",
190
+ "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn",
191
+ "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd",
192
+ "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb",
193
+ "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg",
194
+ "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
195
+ "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",
196
+ "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds",
197
+ "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og"
198
+ ]
199
+ # fmt: on
200
+
201
+
202
+ class SmilesCheckModule(InternS1CheckModuleMixin):
203
+ """
204
+ SMILES molecular sequence auto-detection module.
205
+
206
+ Automatically detects and validates SMILES strings in text using regex patterns
207
+ or chemical syntax rules. Uses RDKit for precise validation when available,
208
+ otherwise falls back to rule-based validation.
209
+ """
210
+
211
+ def __init__(self, *, min_length: int = 10):
212
+ super().__init__(min_length=min_length)
213
+ self.auto_detect_token = ["<SMILES_AUTO_DETECT>", "</SMILES_AUTO_DETECT>"]
214
+ self._SQ_BRACKET_BAN_1 = re.compile(r"(?:[A-GI-Z]|[a-z]){3,}")
215
+ self._SQ_BRACKET_BAN_2 = re.compile(r"\d{4,}")
216
+
217
+ def _build_regex(self):
218
+ # fmt: off
219
+ _two_letter_elements = [
220
+ 'Ac', 'Ag', 'Al', 'Am', 'Ar', 'As', 'At', 'Au', 'Ba', 'Be', 'Bh', 'Bi', 'Bk', 'Br', 'Ca', 'Cd',
221
+ 'Ce', 'Cf', 'Cl', 'Cm', 'Cn', 'Co', 'Cr', 'Cs', 'Cu', 'Db', 'Ds', 'Dy', 'Er', 'Es', 'Eu', 'Fe',
222
+ 'Fl', 'Fm', 'Fr', 'Ga', 'Gd', 'Ge', 'He', 'Hf', 'Hg', 'Ho', 'Hs', 'In', 'Ir', 'Kr', 'La', 'Li',
223
+ 'Lr', 'Lu', 'Lv', 'Mc', 'Md', 'Mg', 'Mn', 'Mo', 'Mt', 'Na', 'Nb', 'Nd', 'Ne', 'Nh', 'Ni', 'No',
224
+ 'Np', 'Og', 'Os', 'Pa', 'Pb', 'Pd', 'Pm', 'Po', 'Pr', 'Pt', 'Pu', 'Ra', 'Rb', 'Re', 'Rf', 'Rg',
225
+ 'Rh', 'Rn', 'Ru', 'Sb', 'Sc', 'Se', 'Sg', 'Si', 'Sm', 'Sn', 'Sr', 'Ta', 'Tb', 'Tc', 'Te', 'Th',
226
+ 'Ti', 'Tl', 'Tm', 'Ts', 'Xe', 'Yb', 'Zn', 'Zr'
227
+ ]
228
+ _single_letter_elements = [
229
+ "B", "C", "F", "H", "I", "K", "N", "O", "P", "S", "U", "V", "W", "Y", 'b', 'c', 'n', 'o', 'p', 's'
230
+ ]
231
+ # fmt: on
232
+ all_elements_sorted = sorted(_two_letter_elements + _single_letter_elements, key=lambda x: (-len(x), x))
233
+ elements_pattern_str = "|".join(all_elements_sorted)
234
+
235
+ bracket_atom_pattern_str = r"\[[^\]]+\]"
236
+ other_single_chars_pattern_str = r"[\(\)\.=\-#@\d\$\%\*:\+\-\/\\]"
237
+ smiles_unit_pattern = (
238
+ r"(?:"
239
+ + bracket_atom_pattern_str
240
+ + r"|"
241
+ + elements_pattern_str
242
+ + r"|"
243
+ + other_single_chars_pattern_str
244
+ + r")"
245
+ )
246
+ core_sequence_pattern = rf"(?>{smiles_unit_pattern}){{10,}}"
247
+ constrained_core_sequence_pattern = rf"(?![:.=]){core_sequence_pattern}(?<![:.=])"
248
+
249
+ final_regex_str = rf"({constrained_core_sequence_pattern})"
250
+
251
+ COMPILED_REGEX = re.compile(final_regex_str)
252
+ return COMPILED_REGEX
253
+
254
+ def check_legitimacy_slow(self, candidate: str) -> bool:
255
+ """Check legitimacy with RDKit"""
256
+ if sum(1 for char in candidate if char.encode("UTF-8").isalpha()) < 5:
257
+ return False
258
+
259
+ mol = Chem.MolFromSmiles(candidate)
260
+ if mol is None:
261
+ return False
262
+ else:
263
+ return True
264
+
265
+ def check_legitimacy_fast(self, candidate: str) -> bool:
266
+ """Check legitimacy with hard rules"""
267
+ if sum(1 for char in candidate if char.encode("UTF-8").isalpha()) < 5:
268
+ return False
269
+
270
+ if not self.check_rings_and_brackets(candidate):
271
+ return False
272
+ else:
273
+ return True
274
+
275
+ def check_legitimacy(self, candidate: str) -> bool:
276
+ if RDKIT_AVAILABLE:
277
+ return self.check_legitimacy_slow(candidate)
278
+ else:
279
+ return self.check_legitimacy_fast(candidate)
280
+
281
+ def check_brackets(self, text):
282
+ matches = re.findall(r"\[([^\[\]]*)\]", text)
283
+ for part in matches:
284
+ if "(" in part or ")" in part:
285
+ return False
286
+ if len(part) == 0:
287
+ return False
288
+ if part[0] in elements or part[0] in aromatic_symbols or part[:2] in elements:
289
+ return True
290
+ return True
291
+
292
+ def check_rings_and_brackets(self, text):
293
+ rings = {}
294
+ left_sq_bracket, right_sq_bracket = 0, 0
295
+ left_pt_bracket, right_pt_bracket = 0, 0
296
+ all_lower = True
297
+ digits_cnt = 0
298
+ pos = 0
299
+ while pos < len(text):
300
+ step = 0
301
+ c = text[pos]
302
+ if ord(c) >= 65 and ord(c) <= 90:
303
+ all_lower = False
304
+ if (pos == len(text) - 1 or pos == 0) and c in bonds:
305
+ return False
306
+ if pos > 0 and text[pos - 1] in bonds and text[pos] in bonds:
307
+ return False
308
+ if c == "[":
309
+ step = 1
310
+ left_sq_bracket += 1
311
+ if left_sq_bracket > right_sq_bracket + 1:
312
+ return False
313
+ if pos == len(text) - 1:
314
+ return False
315
+ if "]" not in text[pos + 1 :]:
316
+ return False
317
+ bracket_span = text[pos + 1 : text.find("]")]
318
+
319
+ if self._SQ_BRACKET_BAN_1.search(bracket_span) or self._SQ_BRACKET_BAN_2.search(bracket_span):
320
+ return False
321
+
322
+ matches = re.findall(r"\d+", bracket_span)
323
+ if len(matches) > 2:
324
+ return False
325
+ if c == "]":
326
+ step = 1
327
+ right_sq_bracket += 1
328
+ if right_sq_bracket > left_sq_bracket:
329
+ return False
330
+
331
+ if c == "(":
332
+ step = 1
333
+ left_pt_bracket += 1
334
+ if c == ")":
335
+ step = 1
336
+ right_pt_bracket += 1
337
+ if right_pt_bracket > left_pt_bracket:
338
+ return False
339
+
340
+ if left_sq_bracket == right_sq_bracket:
341
+ if c.isdigit():
342
+ digits_cnt += 1
343
+ step = 1
344
+ if (
345
+ pos == 0
346
+ or (pos == 1 and text[pos - 1] != "%")
347
+ or (pos > 1 and text[pos - 1] != "%" and text[pos - 2] != "%")
348
+ ):
349
+ if c in rings:
350
+ if rings[c] == "unclosed":
351
+ rings[c] = "closed"
352
+ else:
353
+ rings[c] = "unclosed"
354
+ else:
355
+ rings[c] = "unclosed"
356
+ if c == "%":
357
+ if pos >= len(text) - 2 or not text[pos + 1].isdigit() or not text[pos + 2].isdigit():
358
+ return False
359
+ step = 3
360
+ digits_cnt += 1
361
+ num = text[pos + 1 : pos + 3]
362
+ if num in rings:
363
+ if rings[num] == "unclosed":
364
+ rings[num] = "closed"
365
+ else:
366
+ rings[num] = "unclosed"
367
+ else:
368
+ rings[num] = "unclosed"
369
+ if step == 0:
370
+ if (
371
+ pos < len(text) - 1
372
+ and text[pos : pos + 2] in organic_symbols + aromatic_symbols + other_allows
373
+ ):
374
+ step = 2
375
+ elif c in organic_symbols + aromatic_symbols + other_allows:
376
+ step = 1
377
+ else:
378
+ return False
379
+
380
+ if step == 0:
381
+ step = 1
382
+ pos += step
383
+
384
+ if left_sq_bracket != right_sq_bracket or any(v == "unclosed" for v in rings.values()):
385
+ return False
386
+ if all_lower and digits_cnt < 2:
387
+ return False
388
+ return self.check_brackets(text)
389
+
390
+
391
+ @lru_cache
392
+ # Copied from transformers.models.gpt2.tokenization_gpt2.bytes_to_unicode
393
+ def bytes_to_unicode():
394
+ """
395
+ Returns list of utf-8 byte and a mapping to unicode strings. We specifically avoids mapping to whitespace/control
396
+ characters the bpe code barfs on.
397
+
398
+ The reversible bpe codes work on unicode strings. This means you need a large # of unicode characters in your vocab
399
+ if you want to avoid UNKs. When you're at something like a 10B token dataset you end up needing around 5K for
400
+ decent coverage. This is a significant percentage of your normal, say, 32K bpe vocab. To avoid that, we want lookup
401
+ tables between utf-8 bytes and unicode strings.
402
+ """
403
+ bs = (
404
+ list(range(ord("!"), ord("~") + 1)) + list(range(ord("¡"), ord("¬") + 1)) + list(range(ord("®"), ord("ÿ") + 1))
405
+ )
406
+ cs = bs[:]
407
+ n = 0
408
+ for b in range(2**8):
409
+ if b not in bs:
410
+ bs.append(b)
411
+ cs.append(2**8 + n)
412
+ n += 1
413
+ cs = [chr(n) for n in cs]
414
+ return dict(zip(bs, cs))
415
+
416
+
417
+ # Copied from transformers.models.gpt2.tokenization_gpt2.get_pairs
418
+ def get_pairs(word):
419
+ """
420
+ Return set of symbol pairs in a word.
421
+
422
+ Word is represented as tuple of symbols (symbols being variable-length strings).
423
+ """
424
+ pairs = set()
425
+ prev_char = word[0]
426
+ for char in word[1:]:
427
+ pairs.add((prev_char, char))
428
+ prev_char = char
429
+ return pairs
430
+
431
+
432
+ # @requires(backends=("sentencepiece",))
433
+ class InternS1Tokenizer(PreTrainedTokenizer):
434
+ """
435
+ Construct an InternS1 tokenizer. Based on byte-level Byte-Pair-Encoding.
436
+
437
+ Same with GPT2Tokenizer, this tokenizer has been trained to treat spaces like parts of the tokens so a word will
438
+ be encoded differently whether it is at the beginning of the sentence (without space) or not:
439
+
440
+ ```python
441
+ >>> from transformers import AutoTokenizer
442
+
443
+ >>> tokenizer = AutoTokenizer.from_pretrained("InternS1Tokenizer", trust_remote_code=True)
444
+ >>> tokenizer("Hello world")["input_ids"]
445
+ [9707, 1879]
446
+
447
+ >>> tokenizer(" Hello world")["input_ids"]
448
+ [21927, 1879]
449
+ ```
450
+ This is expected.
451
+
452
+ Include custom extension to support better domain-specific text tokenization, leveraging a separately trained tokenizer model.
453
+
454
+ ```python
455
+ >>> from transformers import AutoTokenizer
456
+
457
+ >>> tokenizer = AutoTokenizer.from_pretrained("InternS1Tokenizer", trust_remote_code=True)
458
+ >>> tokenizer.tokenize("Describe <SMILES>C1=CC=C(C=C1)C=O</SMILES> and CC1=CC=CC=C1C=O")
459
+ ["Describe ", "<SMILES>", "C1=CC=C(C=C1)C=O", "</SMILES>", " and ", "<SMILES_AUTO_DETECT>",
460
+ "CC1=CC=CC=C1C=O", "</SMILES_AUTO_DETECT>"]
461
+ >>> token_ids = tokenizer("Describe <SMILES>C1=CC=C(C=C1)C=O</SMILES> and CC1=CC=CC=C1C=O")["input_ids"]
462
+ >>> token_ids
463
+ [74785, 220, 151925, 151854, 151860, 151698, 151707, 151860, 151690, 151726, 151926, 323, 220, 151672, 151860, 151701, 151860, 151854, 151726]
464
+
465
+ >>> tokenizer.convert_ids_to_tokens(token_ids)
466
+ ['Describe', 'Ġ', '<SMILES>', 'C', '1', '=CC=C(', 'C=C', '1', ')C', '=O', '</SMILES>', 'Ġand', 'Ġ', 'CC', '1', '=CC=CC=C', '1', 'C', '=O']
467
+ ```
468
+
469
+ Users should refer to this superclass [`PreTrainedTokenizer`] for more information regarding those overloaded methods
470
+
471
+ Args:
472
+ vocab_file (`str`):
473
+ Path to the vocabulary file.
474
+ merges_file (`str`):
475
+ Path to the merges file.
476
+ errors (`str`, *optional*, defaults to `"replace"`):
477
+ Paradigm to follow when decoding bytes to UTF-8. See
478
+ [bytes.decode](https://docs.python.org/3/library/stdtypes.html#bytes.decode) for more information.
479
+ unk_token (`str`, *optional*, defaults to `"<|endoftext|>"`):
480
+ The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this
481
+ token instead.
482
+ bos_token (`str`, *optional*):
483
+ The beginning of sequence token. Not applicable for this tokenizer.
484
+ eos_token (`str`, *optional*, defaults to `"<|endoftext|>"`):
485
+ The end of sequence token.
486
+ pad_token (`str`, *optional*, defaults to `"<|endoftext|>"`):
487
+ The token used for padding, for example when batching sequences of different lengths.
488
+ clean_up_tokenization_spaces (`bool`, *optional*, defaults to `False`):
489
+ Whether or not the model should cleanup the spaces that were added when splitting the input text during the
490
+ tokenization process. Not applicable to this tokenizer, since tokenization does not add spaces.
491
+ split_special_tokens (`bool`, *optional*, defaults to `False`):
492
+ Whether or not the special tokens should be split during the tokenization process. The default behavior is
493
+ to not split special tokens. This means that if `<|endoftext|>` is the `eos_token`, then `tokenizer.tokenize("<|endoftext|>") =
494
+ ['<|endoftext|>`]. Otherwise, if `split_special_tokens=True`, then `tokenizer.tokenize("<|endoftext|>")` will be give `['<',
495
+ '|', 'endo', 'ft', 'ext', '|', '>']`. This argument is only supported for `slow` tokenizers for the moment.
496
+ """
497
+
498
+ vocab_files_names = VOCAB_FILES_NAMES
499
+ model_input_names = ["input_ids", "attention_mask"]
500
+
501
+ def __init__(
502
+ self,
503
+ vocab_file,
504
+ merges_file,
505
+ errors="replace",
506
+ unk_token="<|endoftext|>",
507
+ bos_token=None,
508
+ eos_token="<|endoftext|>",
509
+ pad_token="<|endoftext|>",
510
+ clean_up_tokenization_spaces=False,
511
+ split_special_tokens=False,
512
+ special_tokens_pattern="none",
513
+ **kwargs,
514
+ ):
515
+ bos_token = (
516
+ AddedToken(bos_token, lstrip=False, rstrip=False, special=True, normalized=False)
517
+ if isinstance(bos_token, str)
518
+ else bos_token
519
+ )
520
+ eos_token = (
521
+ AddedToken(eos_token, lstrip=False, rstrip=False, special=True, normalized=False)
522
+ if isinstance(eos_token, str)
523
+ else eos_token
524
+ )
525
+ unk_token = (
526
+ AddedToken(unk_token, lstrip=False, rstrip=False, special=True, normalized=False)
527
+ if isinstance(unk_token, str)
528
+ else unk_token
529
+ )
530
+ pad_token = (
531
+ AddedToken(pad_token, lstrip=False, rstrip=False, special=True, normalized=False)
532
+ if isinstance(pad_token, str)
533
+ else pad_token
534
+ )
535
+
536
+ with open(vocab_file, encoding="utf-8") as vocab_handle:
537
+ self.encoder = json.load(vocab_handle)
538
+ self.decoder = {v: k for k, v in self.encoder.items()}
539
+ self.errors = errors # how to handle errors in decoding
540
+ self.byte_encoder = bytes_to_unicode()
541
+ self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
542
+ bpe_merges = []
543
+ with open(merges_file, encoding="utf-8") as merges_handle:
544
+ for i, line in enumerate(merges_handle):
545
+ line = line.strip()
546
+ if (i == 0 and line.startswith("#version:")) or not line:
547
+ continue
548
+ bpe_merges.append(tuple(line.split()))
549
+ self.bpe_ranks = dict(zip(bpe_merges, range(len(bpe_merges))))
550
+ # NOTE: the cache can grow without bound and will get really large for long running processes
551
+ # (esp. for texts of language that do not use space between word, e.g. Chinese); technically
552
+ # not a memory leak but appears as one.
553
+ # GPT2Tokenizer has the same problem, so let's be consistent.
554
+ self.cache = {}
555
+
556
+ self.pat = re.compile(PRETOKENIZE_REGEX)
557
+
558
+ if kwargs.get("add_prefix_space", False):
559
+ logger.warning_once(
560
+ f"{self.__class__.__name} does not support `add_prefix_space`, setting it to True has no effect."
561
+ )
562
+
563
+ super().__init__(
564
+ vocab_file=vocab_file,
565
+ merges_file=merges_file,
566
+ errors=errors,
567
+ unk_token=unk_token,
568
+ bos_token=bos_token,
569
+ eos_token=eos_token,
570
+ pad_token=pad_token,
571
+ clean_up_tokenization_spaces=clean_up_tokenization_spaces,
572
+ split_special_tokens=split_special_tokens,
573
+ special_tokens_pattern=special_tokens_pattern,
574
+ **kwargs,
575
+ )
576
+
577
+ self.prepare_extra_tokenizers(vocab_file)
578
+
579
+ @property
580
+ def vocab_size(self) -> int:
581
+ return len(self.encoder)
582
+
583
+ # Copied from transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer.get_vocab
584
+ def get_vocab(self):
585
+ return dict(self.encoder, **self.added_tokens_encoder)
586
+
587
+ # Copied from transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer.bpe
588
+ def bpe(self, token):
589
+ if token in self.cache:
590
+ return self.cache[token]
591
+ word = tuple(token)
592
+ pairs = get_pairs(word)
593
+
594
+ if not pairs:
595
+ return token
596
+
597
+ while True:
598
+ bigram = min(pairs, key=lambda pair: self.bpe_ranks.get(pair, float("inf")))
599
+ if bigram not in self.bpe_ranks:
600
+ break
601
+ first, second = bigram
602
+ new_word = []
603
+ i = 0
604
+ while i < len(word):
605
+ try:
606
+ j = word.index(first, i)
607
+ except ValueError:
608
+ new_word.extend(word[i:])
609
+ break
610
+ else:
611
+ new_word.extend(word[i:j])
612
+ i = j
613
+
614
+ if word[i] == first and i < len(word) - 1 and word[i + 1] == second:
615
+ new_word.append(first + second)
616
+ i += 2
617
+ else:
618
+ new_word.append(word[i])
619
+ i += 1
620
+ new_word = tuple(new_word)
621
+ word = new_word
622
+ if len(word) == 1:
623
+ break
624
+ else:
625
+ pairs = get_pairs(word)
626
+ word = " ".join(word)
627
+ self.cache[token] = word
628
+ return word
629
+
630
+ def prepare_extra_tokenizers(self, vocab_file: str) -> None:
631
+ """
632
+ Prepare domain-specific tokenizers.
633
+
634
+ Define variables/maps here which guide domain-specific tokenization later.
635
+ """
636
+ # Load extra tokenizers with SentencePiece model
637
+ dir_name = os.path.dirname(vocab_file)
638
+
639
+ self.sp_model_SMILES = spm.SentencePieceProcessor()
640
+ self.sp_model_SMILES.Load(os.path.join(dir_name, "tokenizer_SMILES.model"))
641
+ self.sp_model_SMILES.offset = self.init_kwargs["offset_SMILES"]
642
+
643
+ self.sp_model_PROT = spm.SentencePieceProcessor()
644
+ self.sp_model_PROT.Load(os.path.join(dir_name, "tokenizer_PROT.model"))
645
+ self.sp_model_PROT.offset = self.init_kwargs["offset_PROT"]
646
+
647
+ self.sp_model_XNA = spm.SentencePieceProcessor()
648
+ self.sp_model_XNA.Load(os.path.join(dir_name, "tokenizer_XNA.model"))
649
+ self.sp_model_XNA.offset = self.init_kwargs["offset_XNA"]
650
+
651
+ base_mapping = {
652
+ "SMILES": self.sp_model_SMILES,
653
+ "protein": self.sp_model_PROT,
654
+ "dna": self.sp_model_XNA,
655
+ "rna": self.sp_model_XNA,
656
+ }
657
+ auto_detect_mapping = {
658
+ "SMILES": self.sp_model_SMILES,
659
+ "PROT": self.sp_model_PROT,
660
+ "XNA": self.sp_model_XNA,
661
+ }
662
+ # Guiding tokens of domain-specific tokenization
663
+ self.ex_begin_mapping = {f"<{key}>": value for key, value in base_mapping.items()}
664
+ self.ex_end_mapping = {f"</{key}>": value for key, value in base_mapping.items()}
665
+ # Transient markers for auto-detection, these tokens will not be assigned token ids
666
+ self.ex_auto_begin_mapping = {f"<{key}_AUTO_DETECT>": value for key, value in auto_detect_mapping.items()}
667
+ self.ex_auto_end_mapping = {f"</{key}_AUTO_DETECT>": value for key, value in auto_detect_mapping.items()}
668
+ # Token markers to prevent unwanted auto-detection
669
+ self.ex_protect_begin_tokens = ["<MOLFORMULA>"]
670
+ self.ex_protect_end_tokens = ["</MOLFORMULA>"]
671
+ # For simplicity
672
+ self.ex_protect_tokens = self.ex_protect_begin_tokens + self.ex_protect_end_tokens
673
+ self.ex_all_begin_mapping = self.ex_begin_mapping | self.ex_auto_begin_mapping
674
+ self.ex_all_end_mapping = self.ex_end_mapping | self.ex_auto_end_mapping
675
+
676
+ # Update encoder & decoder with extra tokenizers
677
+ for tokenizer_name, sp_model in [
678
+ ("SMILES", self.sp_model_SMILES),
679
+ ("PROT", self.sp_model_PROT),
680
+ ("XNA", self.sp_model_XNA),
681
+ ]:
682
+ self.decoder.update(
683
+ {i + sp_model.offset: sp_model.id_to_piece(i) for i in range(sp_model.get_piece_size())}
684
+ )
685
+ # Not really used, only to fill holes in encoder, to keep methods like `add_tokens` working
686
+ self.encoder.update(
687
+ {
688
+ f"<|{tokenizer_name}_{sp_model.id_to_piece(i)}|>": i + sp_model.offset
689
+ for i in range(sp_model.get_piece_size())
690
+ }
691
+ )
692
+
693
+ # protect-tokens should keep complete temporarily to guide later tokenization
694
+ # it will be segmented later
695
+ for token in self.ex_protect_tokens:
696
+ self.tokens_trie.add(token)
697
+
698
+ self._unk_token = "<unk>" # Fall-back
699
+ self.check_module_list = [SmilesCheckModule(), ProtCheckModule(), XnaCheckModule()]
700
+
701
+ def _pop_logical_sp_token(self, extra_tokenizer_stack: list, mapping_name: str) -> None:
702
+ """Switch tokenizer when it comes to an end sp token"""
703
+ extra_tokenizer = extra_tokenizer_stack.pop()
704
+ if extra_tokenizer != self.ex_all_end_mapping[mapping_name]:
705
+ logger.warning_once(
706
+ f"Encounter incorrect nesting of extra tokenizer: {self.ex_all_end_mapping[mapping_name]} and {extra_tokenizer}"
707
+ )
708
+ logger.warning_once("This may lead to unexpected behaviour of the tokenizer, please check your input.")
709
+
710
+ def tokenize(self, text: TextInput, **kwargs) -> list[str]:
711
+ """
712
+ Converts a string into a sequence of tokens, using the tokenizer.
713
+
714
+ It will switch to domain-specific tokenizer once encountering extra/logical sp tokens.
715
+
716
+ Args:
717
+ text: TextInput
718
+ """
719
+ split_special_tokens = kwargs.pop("split_special_tokens", self.split_special_tokens)
720
+
721
+ text, kwargs = self.prepare_for_tokenization(text, **kwargs)
722
+
723
+ if hasattr(self, "do_lower_case") and self.do_lower_case:
724
+ # convert non-special tokens to lowercase. Might be super slow as well?
725
+ escaped_special_toks = [re.escape(s_tok) for s_tok in (self.all_special_tokens)]
726
+ escaped_special_toks += [
727
+ re.escape(s_tok.content)
728
+ for s_tok in (self._added_tokens_decoder.values())
729
+ if not s_tok.special and s_tok.normalized
730
+ ]
731
+ pattern = r"(" + r"|".join(escaped_special_toks) + r")|" + r"(.+?)"
732
+ text = re.sub(pattern, lambda m: m.groups()[0] or m.groups()[1].lower(), text)
733
+
734
+ if split_special_tokens:
735
+ no_split_token = []
736
+ tokens = [text]
737
+ else:
738
+ no_split_token = self._added_tokens_encoder.keys() # don't split on any of the added tokens
739
+ # "This is something<special_token_1> else"
740
+ tokens = self.tokens_trie.split(text)
741
+
742
+ # ["This is something", "<special_token_1>", " else"]
743
+ for i, token in enumerate(tokens):
744
+ if token in no_split_token:
745
+ tok_extended = self._added_tokens_decoder.get(self._added_tokens_encoder[token], None)
746
+ left = tokens[i - 1] if i > 0 else None
747
+ right = tokens[i + 1] if i < len(tokens) - 1 else None
748
+ if isinstance(tok_extended, AddedToken):
749
+ if tok_extended.rstrip and right:
750
+ # A bit counter-intuitive but we strip the left of the string
751
+ # since tok_extended.rstrip means the special token is eating all white spaces on its right
752
+ tokens[i + 1] = right.lstrip()
753
+ # Strip white spaces on the left
754
+ if tok_extended.lstrip and left:
755
+ tokens[i - 1] = left.rstrip() # Opposite here
756
+ if tok_extended.single_word and left and left[-1] != " ":
757
+ tokens[i - 1] += token
758
+ tokens[i] = ""
759
+ elif tok_extended.single_word and right and right[0] != " ":
760
+ tokens[i + 1] = token + tokens[i + 1]
761
+ tokens[i] = ""
762
+ else:
763
+ raise ValueError(
764
+ f"{tok_extended} cannot be tokenized because it was not properly added"
765
+ f" to the tokenizer. This means that it is not an `AddedToken` but a {type(tok_extended)}"
766
+ )
767
+
768
+ # ["This is something", "<special_token_1>", "else"]
769
+ tokenized_text = []
770
+
771
+ # Codes for automatically detecting domain-specific content
772
+ # All parts that have been marked by domain-specific or protection tokens will not be subject to auto detection
773
+ # See transformers/tests/models/intern_s1/test_tokenization_intern_s1.py::test_auto_detection() for more details
774
+ new_tokens = []
775
+ not_split_flag = 0
776
+ for token in tokens:
777
+ if not token:
778
+ continue
779
+ if token in no_split_token or token in self.ex_protect_tokens:
780
+ new_tokens.append(token)
781
+ if token in self.ex_begin_mapping or token in self.ex_protect_begin_tokens:
782
+ not_split_flag += 1 # In case nested sp tokens
783
+ elif token in self.ex_end_mapping or token in self.ex_protect_end_tokens:
784
+ not_split_flag = max(0, not_split_flag - 1)
785
+ else:
786
+ if not_split_flag:
787
+ new_tokens.append(token)
788
+ else:
789
+ for check_module in self.check_module_list:
790
+ token = check_module.re_split(token)
791
+
792
+ new_tokens.extend(token)
793
+ tokens = new_tokens
794
+
795
+ # Use stack to maintain which tokenizer should be used, considering the possibility of nested extra tokenizer
796
+ extra_tokenizer_stack = []
797
+ for token in tokens:
798
+ # Need to skip eventual empty (fully stripped) tokens
799
+ if not token:
800
+ continue
801
+ # protect-tokens are not assigned token ids, should be segmented here
802
+ if token in self.ex_protect_tokens:
803
+ tokenized_text.extend(self._tokenize(token))
804
+ # push tokenizer to stack when encountering begin token
805
+ elif token in self.ex_all_begin_mapping:
806
+ tokenized_text.append(token)
807
+ extra_tokenizer_stack.append(self.ex_all_begin_mapping[token])
808
+ # pop tokenizer from stack when encountering end token
809
+ elif token in self.ex_all_end_mapping:
810
+ tokenized_text.append(token)
811
+ if extra_tokenizer_stack:
812
+ self._pop_logical_sp_token(extra_tokenizer_stack, token)
813
+ # other special tokens
814
+ elif token in no_split_token:
815
+ tokenized_text.append(token)
816
+ else:
817
+ tokenized_text.extend(self._tokenize(token, extra_tokenizer_stack=extra_tokenizer_stack))
818
+
819
+ # ["This", " is", " something", "<special_token_1>", "else"]
820
+ return tokenized_text
821
+
822
+ def _tokenize(self, text, **kwargs):
823
+ """
824
+ Modified from `transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer._tokenize`.
825
+
826
+ This adaptation supports domain-specific tokenizers.
827
+ """
828
+ extra_tokenizer_stack = kwargs.pop("extra_tokenizer_stack", False)
829
+ if extra_tokenizer_stack:
830
+ tokenized_text = extra_tokenizer_stack[-1].encode(text, out_type=str)
831
+ tokenized_id = extra_tokenizer_stack[-1].encode(text, out_type=int)
832
+ final_tokenized_text = []
833
+ for text_piece, id_piece in zip(tokenized_text, tokenized_id):
834
+ if id_piece == 0:
835
+ final_tokenized_text.extend(self._bpe_tokenize(text_piece))
836
+ else:
837
+ final_tokenized_text.append(text_piece)
838
+ return final_tokenized_text
839
+ else:
840
+ return self._bpe_tokenize(text)
841
+
842
+ def _bpe_tokenize(self, text, **kwargs):
843
+ text = text.replace(
844
+ "▁", " "
845
+ ) # This discrepancy stems from differing whitespace treatment in SentencePiece versus BPE tokenization.
846
+ bpe_tokens = []
847
+ for token in re.findall(self.pat, text):
848
+ token = "".join(
849
+ self.byte_encoder[b] for b in token.encode("utf-8")
850
+ ) # Maps all our bytes to unicode strings, avoiding control tokens of the BPE (spaces in our case)
851
+ bpe_tokens.extend(bpe_token for bpe_token in self.bpe(token).split(" "))
852
+ return bpe_tokens
853
+
854
+ def convert_tokens_to_ids(self, tokens: Union[str, list[str]]) -> Union[int, list[int]]:
855
+ """
856
+ Modified from `transformers.tokenization_utils.PreTrainedTokenzier.convert_tokens_to_ids`.
857
+
858
+ Converts a token string (or a sequence of tokens) in a single integer id (or a sequence of ids), using the
859
+ vocabulary.
860
+
861
+ This adaptation supports domain-specific tokenizers.
862
+
863
+ Args:
864
+ tokens (`str` or `List[str]`): One or several token(s) to convert to token id(s).
865
+
866
+ Returns:
867
+ `int` or `List[int]`: The token id or list of token ids.
868
+ """
869
+ if tokens is None:
870
+ return None
871
+
872
+ if isinstance(tokens, str):
873
+ return self._convert_token_to_id_with_added_voc(tokens)
874
+
875
+ ids = []
876
+ extra_tokenizer_stack = []
877
+
878
+ for token in tokens:
879
+ if token not in self.ex_auto_begin_mapping and token not in self.ex_auto_end_mapping:
880
+ ids.append(
881
+ self._convert_token_to_id_with_added_voc(token, extra_tokenizer_stack=extra_tokenizer_stack)
882
+ )
883
+ if token in self.ex_all_begin_mapping:
884
+ extra_tokenizer_stack.append(self.ex_all_begin_mapping[token])
885
+ elif token in self.ex_all_end_mapping:
886
+ if extra_tokenizer_stack:
887
+ self._pop_logical_sp_token(extra_tokenizer_stack, token)
888
+ return ids
889
+
890
+ def _convert_token_to_id_with_added_voc(self, token, **kwargs):
891
+ """
892
+ Modified from `transformers.tokenization_utils.PreTrainedTokenzier._convert_token_to_id_with_added_voc`.
893
+
894
+ This adaptation supports domain-specific tokenizers.
895
+ """
896
+ if token is None:
897
+ return None
898
+
899
+ if token in self._added_tokens_encoder:
900
+ return self._added_tokens_encoder[token]
901
+ return self._convert_token_to_id(token, **kwargs)
902
+
903
+ def _convert_token_to_id(self, token, **kwargs):
904
+ """
905
+ Modified from `transformers.tokenization_utils.PreTrainedTokenzier._convert_token_to_id`.
906
+
907
+ Converts a token (str) in an id using the vocab.
908
+
909
+ Fall back to original tokenizer once OOV.
910
+ """
911
+ extra_tokenizer_stack = kwargs.pop("extra_tokenizer_stack", False)
912
+ if extra_tokenizer_stack:
913
+ token_id = extra_tokenizer_stack[-1].piece_to_id(token)
914
+ if token_id == extra_tokenizer_stack[-1].unk_id():
915
+ return self.encoder.get(token, self.encoder.get(self._unk_token))
916
+ else:
917
+ return token_id + extra_tokenizer_stack[-1].offset
918
+ else:
919
+ return self.encoder.get(token, self.encoder.get(self._unk_token))
920
+
921
+ # Copied from transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer._convert_id_to_token
922
+ def _convert_id_to_token(self, index):
923
+ """Converts an index (integer) in a token (str) using the vocab."""
924
+ return self.decoder.get(index)
925
+
926
+ def convert_tokens_to_string(self, tokens):
927
+ """Converts a sequence of tokens (string) in a single string."""
928
+ text = "".join(tokens)
929
+ text = text.replace(
930
+ "▁", "Ġ"
931
+ ) # This discrepancy stems from differing whitespace treatment in SentencePiece versus BPE tokenization.
932
+ text = text.replace("\n", "Ċ")
933
+ text = bytearray([self.byte_decoder[c] for c in text]).decode("utf-8", errors=self.errors)
934
+ return text
935
+
936
+ def decode(
937
+ self,
938
+ token_ids,
939
+ skip_special_tokens: bool = False,
940
+ clean_up_tokenization_spaces: Optional[bool] = False,
941
+ spaces_between_special_tokens: bool = False,
942
+ **kwargs,
943
+ ) -> str:
944
+ # `spaces_between_special_tokens` defaults to True for _decode in slow tokenizers
945
+ # and cannot be configured elsewhere, but it should default to False for InternS1Tokenizer
946
+ return super().decode(
947
+ token_ids,
948
+ skip_special_tokens=skip_special_tokens,
949
+ clean_up_tokenization_spaces=clean_up_tokenization_spaces,
950
+ spaces_between_special_tokens=spaces_between_special_tokens,
951
+ **kwargs,
952
+ )
953
+
954
+ def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> tuple[str]:
955
+ """
956
+ Modified from `transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer.save_vocabulary` to support saving custom extension.
957
+ """
958
+ if not os.path.isdir(save_directory):
959
+ logger.error(f"Vocabulary path ({save_directory}) should be a directory")
960
+ return
961
+ vocab_file = os.path.join(
962
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]
963
+ )
964
+ merge_file = os.path.join(
965
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["merges_file"]
966
+ )
967
+ sp_model_smiles = os.path.join(
968
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["sp_model_SMILES"]
969
+ )
970
+ sp_model_prot = os.path.join(
971
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["sp_model_PROT"]
972
+ )
973
+ sp_model_xna = os.path.join(
974
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["sp_model_XNA"]
975
+ )
976
+
977
+ with open(vocab_file, "w", encoding="utf-8") as f:
978
+ f.write(json.dumps(self.encoder, indent=2, sort_keys=True, ensure_ascii=False) + "\n")
979
+
980
+ index = 0
981
+ with open(merge_file, "w", encoding="utf-8") as writer:
982
+ writer.write("#version: 0.2\n")
983
+ for bpe_tokens, token_index in sorted(self.bpe_ranks.items(), key=lambda kv: kv[1]):
984
+ if index != token_index:
985
+ logger.warning(
986
+ f"Saving vocabulary to {merge_file}: BPE merge indices are not consecutive."
987
+ " Please check that the tokenizer is not corrupted!"
988
+ )
989
+ index = token_index
990
+ writer.write(" ".join(bpe_tokens) + "\n")
991
+ index += 1
992
+
993
+ with open(sp_model_smiles, "wb") as f:
994
+ f.write(self.sp_model_SMILES.serialized_model_proto())
995
+
996
+ with open(sp_model_prot, "wb") as f:
997
+ f.write(self.sp_model_PROT.serialized_model_proto())
998
+
999
+ with open(sp_model_xna, "wb") as f:
1000
+ f.write(self.sp_model_XNA.serialized_model_proto())
1001
+
1002
+ return vocab_file, merge_file
1003
+
1004
+ def prepare_for_tokenization(self, text, **kwargs):
1005
+ text = unicodedata.normalize("NFC", text)
1006
+ return (text, kwargs)
1007
+
1008
+
1009
+ __all__ = ["InternS1Tokenizer"]
tokenizer_PROT.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1144f52f86f3ca5a29940d69b037e508c05a89e6eedbe42bea641e226b20dbe0
3
+ size 12118
tokenizer_SMILES.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fba1c97da0353ccbffd368ae78e311ccbc762aa5ba74f9aff8bf2ab363c4d37d
3
+ size 14775
tokenizer_XNA.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:58fc8bfb2af3dfe936a13dad8a9cb28dab7850b70b358db19605d867c133fb35
3
+ size 15451
tokenizer_config.json ADDED
@@ -0,0 +1,508 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ "248077": {
269
+ "content": "<IMG_CONTEXT>",
270
+ "lstrip": false,
271
+ "normalized": false,
272
+ "rstrip": false,
273
+ "single_word": false,
274
+ "special": true
275
+ },
276
+ "248078": {
277
+ "content": "<img>",
278
+ "lstrip": false,
279
+ "normalized": false,
280
+ "rstrip": false,
281
+ "single_word": false,
282
+ "special": true
283
+ },
284
+ "248079": {
285
+ "content": "</img>",
286
+ "lstrip": false,
287
+ "normalized": false,
288
+ "rstrip": false,
289
+ "single_word": false,
290
+ "special": true
291
+ },
292
+ "248080": {
293
+ "content": "<quad>",
294
+ "lstrip": false,
295
+ "normalized": false,
296
+ "rstrip": false,
297
+ "single_word": false,
298
+ "special": true
299
+ },
300
+ "248081": {
301
+ "content": "</quad>",
302
+ "lstrip": false,
303
+ "normalized": false,
304
+ "rstrip": false,
305
+ "single_word": false,
306
+ "special": true
307
+ },
308
+ "248082": {
309
+ "content": "<ref>",
310
+ "lstrip": false,
311
+ "normalized": false,
312
+ "rstrip": false,
313
+ "single_word": false,
314
+ "special": true
315
+ },
316
+ "248083": {
317
+ "content": "</ref>",
318
+ "lstrip": false,
319
+ "normalized": false,
320
+ "rstrip": false,
321
+ "single_word": false,
322
+ "special": true
323
+ },
324
+ "248084": {
325
+ "content": "<box>",
326
+ "lstrip": false,
327
+ "normalized": false,
328
+ "rstrip": false,
329
+ "single_word": false,
330
+ "special": true
331
+ },
332
+ "248085": {
333
+ "content": "</box>",
334
+ "lstrip": false,
335
+ "normalized": false,
336
+ "rstrip": false,
337
+ "single_word": false,
338
+ "special": true
339
+ },
340
+ "248086": {
341
+ "content": "<|action_start|>",
342
+ "lstrip": false,
343
+ "normalized": false,
344
+ "rstrip": false,
345
+ "single_word": false,
346
+ "special": true
347
+ },
348
+ "248087": {
349
+ "content": "<|action_end|>",
350
+ "lstrip": false,
351
+ "normalized": false,
352
+ "rstrip": false,
353
+ "single_word": false,
354
+ "special": true
355
+ },
356
+ "248088": {
357
+ "content": "<|interpreter|>",
358
+ "lstrip": false,
359
+ "normalized": false,
360
+ "rstrip": false,
361
+ "single_word": false,
362
+ "special": true
363
+ },
364
+ "248089": {
365
+ "content": "<|plugin|>",
366
+ "lstrip": false,
367
+ "normalized": false,
368
+ "rstrip": false,
369
+ "single_word": false,
370
+ "special": true
371
+ },
372
+ "248090": {
373
+ "content": "<video>",
374
+ "lstrip": false,
375
+ "normalized": false,
376
+ "rstrip": false,
377
+ "single_word": false,
378
+ "special": true
379
+ },
380
+ "248091": {
381
+ "content": "<|ts|>",
382
+ "lstrip": false,
383
+ "normalized": false,
384
+ "rstrip": false,
385
+ "single_word": false,
386
+ "special": true
387
+ },
388
+ "248092": {
389
+ "content": "<|/ts|>",
390
+ "lstrip": false,
391
+ "normalized": false,
392
+ "rstrip": false,
393
+ "single_word": false,
394
+ "special": true
395
+ },
396
+ "248093": {
397
+ "content": "<TS_CONTEXT>",
398
+ "lstrip": false,
399
+ "normalized": false,
400
+ "rstrip": false,
401
+ "single_word": false,
402
+ "special": true
403
+ },
404
+ "248094": {
405
+ "content": "<SMILES>",
406
+ "lstrip": false,
407
+ "normalized": false,
408
+ "rstrip": false,
409
+ "single_word": false,
410
+ "special": false
411
+ },
412
+ "248095": {
413
+ "content": "</SMILES>",
414
+ "lstrip": false,
415
+ "normalized": false,
416
+ "rstrip": false,
417
+ "single_word": false,
418
+ "special": false
419
+ },
420
+ "248096": {
421
+ "content": "<protein>",
422
+ "lstrip": false,
423
+ "normalized": false,
424
+ "rstrip": false,
425
+ "single_word": false,
426
+ "special": false
427
+ },
428
+ "248097": {
429
+ "content": "</protein>",
430
+ "lstrip": false,
431
+ "normalized": false,
432
+ "rstrip": false,
433
+ "single_word": false,
434
+ "special": false
435
+ },
436
+ "248098": {
437
+ "content": "<dna>",
438
+ "lstrip": false,
439
+ "normalized": false,
440
+ "rstrip": false,
441
+ "single_word": false,
442
+ "special": false
443
+ },
444
+ "248099": {
445
+ "content": "</dna>",
446
+ "lstrip": false,
447
+ "normalized": false,
448
+ "rstrip": false,
449
+ "single_word": false,
450
+ "special": false
451
+ },
452
+ "248100": {
453
+ "content": "<rna>",
454
+ "lstrip": false,
455
+ "normalized": false,
456
+ "rstrip": false,
457
+ "single_word": false,
458
+ "special": false
459
+ },
460
+ "248101": {
461
+ "content": "</rna>",
462
+ "lstrip": false,
463
+ "normalized": false,
464
+ "rstrip": false,
465
+ "single_word": false,
466
+ "special": false
467
+ }
468
+ },
469
+ "audio_bos_token": "<|audio_start|>",
470
+ "audio_eos_token": "<|audio_end|>",
471
+ "audio_token": "<|audio_pad|>",
472
+ "auto_map": {
473
+ "AutoTokenizer": [
474
+ "tokenization_interns1.InternS1Tokenizer",
475
+ null
476
+ ]
477
+ },
478
+ "backend": "custom",
479
+ "bos_token": "<|im_start|>",
480
+ "clean_up_tokenization_spaces": false,
481
+ "eos_token": "<|im_end|>",
482
+ "errors": "replace",
483
+ "image_token": "<|image_pad|>",
484
+ "is_local": true,
485
+ "local_files_only": false,
486
+ "model_max_length": 262144,
487
+ "model_specific_special_tokens": {
488
+ "audio_bos_token": "<|audio_start|>",
489
+ "audio_eos_token": "<|audio_end|>",
490
+ "audio_token": "<|audio_pad|>",
491
+ "image_token": "<|image_pad|>",
492
+ "video_token": "<|video_pad|>",
493
+ "vision_bos_token": "<|vision_start|>",
494
+ "vision_eos_token": "<|vision_end|>"
495
+ },
496
+ "offset_PROT": 249126,
497
+ "offset_SMILES": 248102,
498
+ "offset_XNA": 250150,
499
+ "pad_token": "<|endoftext|>",
500
+ "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+",
501
+ "split_special_tokens": false,
502
+ "tokenizer_class": "InternS1Tokenizer",
503
+ "tool_parser_type": "qwen3_coder",
504
+ "unk_token": null,
505
+ "video_token": "<|video_pad|>",
506
+ "vision_bos_token": "<|vision_start|>",
507
+ "vision_eos_token": "<|vision_end|>"
508
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff