pstan commited on
Commit
9247354
·
verified ·
1 Parent(s): 7ec965a

Add files using upload-large-folder tool

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ figures/benchmark.jpeg filter=lfs diff=lfs merge=lfs -text
chat_template.jinja ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {# ---------- special token variables ---------- #}
2
+ {%- set ns_token = ']<]minimax[>[' -%}
3
+ {%- set bod_token = ']~!b[' -%}
4
+ {%- set bos_token = ']~b]' -%}
5
+ {%- set eos_token = '[e~[' -%}
6
+ {%- set toolcall_begin_token = ns_token ~ '<tool_call>' -%}
7
+ {%- set toolcall_end_token = ns_token ~ '</tool_call>' -%}
8
+ {%- set think_begin_token = '<mm:think>' -%}
9
+ {%- set think_end_token = '</mm:think>' -%}
10
+ {%- set image_token = ']<]image[>[' -%}
11
+ {%- set video_token = ']<]video[>[' -%}
12
+ {#- Thinking mode: "enabled" / "disabled" / "adaptive" / not defined -#}
13
+ {#- Recursive XML renderer for tool_call arguments ======================== -#}
14
+ {#- None values are intentionally skipped in mapping iteration so that
15
+ `<key>null</key>` (which would round-trip to the literal string "null")
16
+ never appears in the rendered tool_call. The convention is: omit the
17
+ field entirely. The top-level `_args` loop applies the same rule.
18
+ The `val is none` branch below is a safety net only — upstream cleaning
19
+ (drop_none_in_tool_arguments) should ensure no None ever reaches here. -#}
20
+ {%- macro to_xml(val, ns) -%}
21
+ {%- if val is mapping -%}
22
+ {%- for k, v in val.items() if v is not none -%}
23
+ {{ ns }}<{{ k }}>{{ to_xml(v, ns) }}{{ ns }}</{{ k }}>
24
+ {%- endfor -%}
25
+ {%- elif val is iterable and val is not string -%}
26
+ {%- for item in val -%}
27
+ {{ ns }}<item>{{ to_xml(item, ns) }}{{ ns }}</item>
28
+ {%- endfor -%}
29
+ {%- elif val is none -%}
30
+ {#- Should be unreachable when upstream cleaning is applied. -#}
31
+ {%- elif val is boolean -%}
32
+ {{ val | tojson }}
33
+ {%- else -%}
34
+ {{ val }}
35
+ {%- endif -%}
36
+ {%- endmacro -%}
37
+ {#- Tool Rendering Functions ============================================== -#}
38
+ {%- macro render_tool_namespace(namespace_name, tool_list) -%}
39
+ {%- for tool in tool_list -%}
40
+ <tool>{{ tool.function | tojson(ensure_ascii=False) }}</tool>
41
+ {% endfor -%}
42
+ {%- endmacro -%}
43
+ {%- macro visible_text(content) -%}
44
+ {%- if content is string -%}
45
+ {{ content }}
46
+ {%- elif content is iterable and content is not mapping -%}
47
+ {%- for item in content -%}
48
+ {%- if item is mapping and item.type == 'text' -%}
49
+ {{- item.text }}
50
+ {%- elif item is mapping and item.type == 'image' -%}
51
+ {{- image_token }}
52
+ {%- elif item is mapping and item.type == 'video' -%}
53
+ {{- video_token}}
54
+ {%- elif item is string -%}
55
+ {{- item }}
56
+ {%- endif -%}
57
+ {%- endfor -%}
58
+ {%- elif content is none -%}
59
+ {{- '' }}
60
+ {%- else -%}
61
+ {{- content }}
62
+ {%- endif -%}
63
+ {%- endmacro -%}
64
+ {#- System Message Construction ============================================ -#}
65
+ {%- macro build_system_message(system_message) -%}
66
+ {%- if system_message and system_message.content -%}
67
+ {{- visible_text(system_message.content) }}
68
+ {%- else -%}
69
+ {{- 'Your model version is MiniMax-M3, developed by MiniMax. Knowledge cutoff: January 2026. Founded in early 2022, MiniMax is a global AI foundation model company committed to advancing the frontiers of AI towards AGI.' }}
70
+ {%- endif -%}
71
+
72
+ {#- Thinking mode instructions -#}
73
+ {{- '\n\n<thinking_instructions>\n' }}
74
+ {{- 'You have a thinking capability that allows you to reason step by step before responding. When thinking is enabled, wrap your reasoning in ' ~ think_begin_token ~ think_end_token ~ ' tags before your response. When thinking is disabled, begin your response directly after the ' ~ think_end_token ~ ' prefix. When thinking is adaptive, decide on your own whether to think for the current turn.\n' }}
75
+ {%- if thinking_mode is defined -%}
76
+ {%- if thinking_mode == "enabled" -%}
77
+ {{- 'Current thinking mode: enabled. You MUST think step by step before every response, including after receiving function/tool results.\n' }}
78
+ {%- elif thinking_mode == "disabled" -%}
79
+ {{- 'Current thinking mode: disabled. Do not output any thinking process.\n' }}
80
+ {%- elif thinking_mode == "adaptive" -%}
81
+ {{- 'Current thinking mode: adaptive. You are encouraged to think for complex decision-making, multi-step reasoning, or when analyzing function/tool results.\n' }}
82
+ {%- endif -%}
83
+ {%- else -%}
84
+ {{- 'Current thinking mode: adaptive. You are encouraged to think for complex decision-making, multi-step reasoning, or when analyzing function/tool results.\n' }}
85
+ {%- endif -%}
86
+ {{- '</thinking_instructions>' }}
87
+ {%- endmacro -%}
88
+ {%- macro build_developer_message(developer_message) -%}
89
+ {%- if developer_message and developer_message.content -%}
90
+ {{- visible_text(developer_message.content) }}
91
+ {%- else -%}
92
+ {%- if model_identity is not defined -%}
93
+ {%- set model_identity = "You are a helpful assistant." -%}
94
+ {%- endif -%}
95
+ {{- model_identity }}
96
+ {%- endif -%}
97
+ {%- endmacro -%}
98
+ {#- Main Template Logic ================================================= -#}
99
+ {#- Role mapping: root -> system sp (high priority), system/developer -> developer sp (low priority) -#}
100
+ {%- set system_message = none -%}
101
+ {%- set developer_message = none -%}
102
+ {%- set conversation_messages = messages -%}
103
+ {%- if messages and messages[0].role == "root" -%}
104
+ {%- set system_message = messages[0] -%}
105
+ {%- set conversation_messages = messages[1:] -%}
106
+ {%- if conversation_messages and conversation_messages[0].role in ["system", "developer"] -%}
107
+ {%- set developer_message = conversation_messages[0] -%}
108
+ {%- set conversation_messages = conversation_messages[1:] -%}
109
+ {%- endif -%}
110
+ {%- elif messages and messages[0].role in ["system", "developer"] -%}
111
+ {%- set developer_message = messages[0] -%}
112
+ {%- set conversation_messages = messages[1:] -%}
113
+ {%- endif -%}
114
+ {#- Render system sp (higher priority, root role only) -#}
115
+ {{- bod_token ~ bos_token ~ 'system' ~ '\n' }}
116
+ {{- build_system_message(system_message) }}
117
+ {{- eos_token ~ '\n' }}
118
+
119
+ {#- Render developer sp (lower priority: system/developer role + tools) -#}
120
+ {{- bos_token ~ 'developer' ~ '\n' }}
121
+ {{- build_developer_message(developer_message) }}
122
+ {%- if tools -%}
123
+ {{- '\n\n' ~ '# Tools' ~ '\n' ~ 'You may call one or more tools to assist with the user query.\nHere are the tools available in JSONSchema format:' ~ '\n' }}
124
+ {{- '\n' ~ '<tools>' ~ '\n' }}
125
+ {{- render_tool_namespace("functions", tools) }}
126
+ {{- '</tools>' ~ '\n\n' }}
127
+ {{- 'To call tools, wrap all invocations in a single ' ~ toolcall_begin_token ~ toolcall_end_token ~ ' block. Parameter values containing nested objects or arrays are recursively expanded into XML elements. Example:\n' }}
128
+ {{- '\n' ~ toolcall_begin_token ~ '\n' }}
129
+ {{- ns_token + '<invoke name="tool-name-1">' }}
130
+ {{- ns_token + '<param-1>value-1' + ns_token + '</param-1>' }}
131
+ {{- ns_token + '<param-2>' }}
132
+ {{- ns_token + '<item>' }}
133
+ {{- ns_token + '<key-a>val-a' + ns_token + '</key-a>' }}
134
+ {{- ns_token + '<key-b>val-b' + ns_token + '</key-b>' }}
135
+ {{- ns_token + '</item>' }}
136
+ {{- ns_token + '</param-2>' }}
137
+ {{- ns_token + '</invoke>\n' }}
138
+ {{- ns_token + '<invoke name="tool-name-2">' }}
139
+ {{- ns_token + '<param-1>value-1' + ns_token + '</param-1>' }}
140
+ {{- ns_token + '</invoke>\n' }}
141
+ {{- toolcall_end_token }}
142
+ {%- endif -%}
143
+ {{- eos_token ~ '\n' }}
144
+
145
+ {#- Render messages -#}
146
+ {%- set last_tool_call = namespace(name=none) -%}
147
+ {%- for message in conversation_messages -%}
148
+ {%- if message.role == 'assistant' -%}
149
+ {{- bos_token ~ 'ai' ~ '\n' }}
150
+
151
+ {%- set reasoning_content = '' %}
152
+ {%- set content = visible_text(message.content) %}
153
+ {%- if message.reasoning_content is string %}
154
+ {%- set reasoning_content = message.reasoning_content %}
155
+ {%- else %}
156
+ {%- if think_end_token in content %}
157
+ {%- set reasoning_content = content.split(think_end_token)[0].strip('\n').split(think_begin_token)[-1].strip('\n') %}
158
+ {%- set content = content.split(think_end_token)[-1].strip('\n') %}
159
+ {%- endif %}
160
+ {%- endif %}
161
+
162
+ {%- if reasoning_content -%}
163
+ {#- Render thinking for every assistant turn (all-turn visible) -#}
164
+ {{- think_begin_token ~ reasoning_content ~ think_end_token }}
165
+ {%- else -%}
166
+ {#- No thinking rendered → prefix with think_end_token -#}
167
+ {{- think_end_token }}
168
+ {%- endif -%}
169
+
170
+ {%- if content -%}
171
+ {{- content }}
172
+ {%- endif -%}
173
+ {%- if message.tool_calls -%}
174
+ {{- toolcall_begin_token ~ '\n' }}
175
+
176
+ {%- for tool_call in message.tool_calls -%}
177
+ {%- if tool_call.function -%}
178
+ {%- set tool_call = tool_call.function -%}
179
+ {%- endif -%}
180
+ {{- ns_token + '<invoke name="' + tool_call.name + '">' }}
181
+ {%- set _args = tool_call.arguments -%}
182
+ {%- for k, v in _args.items() if v is not none %}
183
+ {{- ns_token + '<' + k + '>' -}}
184
+ {{- to_xml(v, ns_token) -}}
185
+ {{- ns_token + '</' + k + '>' }}
186
+ {%- endfor -%}
187
+ {{- ns_token + '</invoke>' ~ '\n' }}
188
+ {%- endfor -%}
189
+
190
+ {{- toolcall_end_token }}
191
+ {%- if message.tool_calls[-1].function -%}
192
+ {%- set last_tool_call.name = message.tool_calls[-1].function.name -%}
193
+ {%- else -%}
194
+ {%- set last_tool_call.name = message.tool_calls[-1].name -%}
195
+ {%- endif -%}
196
+ {%- else -%}
197
+ {%- set last_tool_call.name = none -%}
198
+ {%- endif -%}
199
+ {{- eos_token ~ '\n' }}
200
+
201
+ {%- elif message.role == 'tool' -%}
202
+ {%- if last_tool_call.name is none -%}
203
+ {{- raise_exception("Message has tool role, but there was no previous assistant message with a tool call!") }}
204
+ {%- endif -%}
205
+ {%- if loop.first or (conversation_messages[loop.index0 - 1].role != 'tool') -%}
206
+ {{- bos_token ~ 'tool' }}
207
+ {%- endif -%}
208
+ {{- '\n<response>' }}
209
+ {%- if message.content is string -%}
210
+ {{- message.content }}
211
+ {%- else -%}
212
+ {%- for tr in message.content -%}
213
+ {%- if tr is mapping and tr.type is defined and tr.type == 'image' -%}
214
+ {{- image_token }}
215
+ {%- elif tr is mapping and tr.type is defined and tr.type == 'video' -%}
216
+ {{- video_token }}
217
+ {%- else -%}
218
+ {{- tr.output if tr.output is defined else (tr.text if tr.type == 'text' and tr.text is defined else tr) }}
219
+ {%- endif -%}
220
+ {%- endfor -%}
221
+ {%- endif -%}
222
+ {{- '</response>' }}
223
+ {%- if loop.last or (conversation_messages[loop.index0 + 1].role != 'tool') -%}
224
+ {{- eos_token ~ '\n' -}}
225
+ {%- endif -%}
226
+
227
+ {%- elif message.role == 'user' -%}
228
+ {{- bos_token ~ 'user' ~ '\n' }}
229
+ {{- visible_text(message.content) }}
230
+ {{- eos_token ~ '\n' }}
231
+ {%- endif -%}
232
+ {%- endfor -%}
233
+
234
+ {#- Generation prompt -#}
235
+ {%- if add_generation_prompt -%}
236
+ {{- bos_token ~ 'ai' ~ '\n' }}
237
+ {%- if thinking_mode is defined and thinking_mode == "disabled" -%}
238
+ {{- think_end_token }}
239
+ {%- elif thinking_mode is defined and thinking_mode == "adaptive" -%}
240
+ {#- adaptive: no prefix, let model decide -#}
241
+ {%- elif thinking_mode is defined and thinking_mode == "enabled" -%}
242
+ {#- enabled or not defined: default to think -#}
243
+ {{- think_begin_token }}
244
+ {%- else -%}
245
+ {#- adaptive: no prefix, let model decide -#}
246
+ {%- endif -%}
247
+ {%- endif -%}
config.json ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "MiniMaxM3SparseForConditionalGeneration"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_minimax_m3_vl.MiniMaxM3VLConfig"
7
+ },
8
+ "image_grid_pinpoints": "[(336, 336), (336, 672), (336, 1008), (336, 1344), (336, 1680), (336, 2016), (672, 336), (672, 672), (672, 1008), (672, 1344), (672, 1680), (672, 2016), (1008, 336), (1008, 672), (1008, 1008), (1008, 1344), (1008, 1680), (1008, 2016), (1344, 336), (1344, 672), (1344, 1008), (1344, 1344), (1344, 1680), (1344, 2016), (1680, 336), (1680, 672), (1680, 1008), (1680, 1344), (1680, 1680), (1680, 2016), (2016, 336), (2016, 672), (2016, 1008), (2016, 1344), (2016, 1680), (2016, 2016)]",
9
+ "image_seq_length": 576,
10
+ "image_token_index": 200025,
11
+ "img_token_compression_config": {
12
+ "image_token_compression_method": "patch_merge",
13
+ "spatial_merge_size": 2,
14
+ "temporal_patch_size": 2
15
+ },
16
+ "model_type": "minimax_m3_vl",
17
+ "multimodal_projector_bias": true,
18
+ "num_reward_heads": 0,
19
+ "process_image_mode": "dynamic_res",
20
+ "projector_hidden_act": "gelu",
21
+ "projector_hidden_size": 6144,
22
+ "quantization_config": {
23
+ "config_groups": {
24
+ "config_group_0": {
25
+ "format": "float-quantized",
26
+ "input_activations": {
27
+ "actorder": null,
28
+ "block_structure": null,
29
+ "dynamic": true,
30
+ "group_size": null,
31
+ "num_bits": 8,
32
+ "observer": null,
33
+ "observer_kwargs": {},
34
+ "scale_dtype": null,
35
+ "strategy": "token",
36
+ "symmetric": true,
37
+ "type": "float",
38
+ "zp_dtype": null
39
+ },
40
+ "output_activations": null,
41
+ "targets": [
42
+ "Linear"
43
+ ],
44
+ "weights": {
45
+ "actorder": null,
46
+ "block_structure": null,
47
+ "dynamic": false,
48
+ "group_size": null,
49
+ "num_bits": 8,
50
+ "observer": "memoryless_minmax",
51
+ "observer_kwargs": {},
52
+ "scale_dtype": null,
53
+ "strategy": "channel",
54
+ "symmetric": true,
55
+ "type": "float",
56
+ "zp_dtype": null
57
+ }
58
+ }
59
+ },
60
+ "format": "float-quantized",
61
+ "global_compression_ratio": null,
62
+ "ignore": [
63
+ "re:.*lm_head$",
64
+ "re:.*embed_tokens$",
65
+ "re:.*vision_tower.*",
66
+ "re:.*multi_modal_projector.*",
67
+ "re:.*multimodal_projector.*",
68
+ "re:.*patch_merge_mlp.*",
69
+ "re:.*block_sparse_moe\\.gate$"
70
+ ],
71
+ "kv_cache_scheme": null,
72
+ "quant_method": "compressed-tensors",
73
+ "quantization_status": "compressed",
74
+ "transform_config": {},
75
+ "version": "0.17.0"
76
+ },
77
+ "text_config": {
78
+ "architectures": [
79
+ "MiniMaxM3SparseForCausalLM"
80
+ ],
81
+ "attention_output_gate": false,
82
+ "dense_intermediate_size": 12288,
83
+ "head_dim": 128,
84
+ "hidden_act": "swigluoai",
85
+ "hidden_size": 6144,
86
+ "intermediate_size": 3072,
87
+ "max_position_embeddings": 1048576,
88
+ "moe_layer_freq": [
89
+ 0,
90
+ 0,
91
+ 0,
92
+ 1,
93
+ 1,
94
+ 1,
95
+ 1,
96
+ 1,
97
+ 1,
98
+ 1,
99
+ 1,
100
+ 1,
101
+ 1,
102
+ 1,
103
+ 1,
104
+ 1,
105
+ 1,
106
+ 1,
107
+ 1,
108
+ 1,
109
+ 1,
110
+ 1,
111
+ 1,
112
+ 1,
113
+ 1,
114
+ 1,
115
+ 1,
116
+ 1,
117
+ 1,
118
+ 1,
119
+ 1,
120
+ 1,
121
+ 1,
122
+ 1,
123
+ 1,
124
+ 1,
125
+ 1,
126
+ 1,
127
+ 1,
128
+ 1,
129
+ 1,
130
+ 1,
131
+ 1,
132
+ 1,
133
+ 1,
134
+ 1,
135
+ 1,
136
+ 1,
137
+ 1,
138
+ 1,
139
+ 1,
140
+ 1,
141
+ 1,
142
+ 1,
143
+ 1,
144
+ 1,
145
+ 1,
146
+ 1,
147
+ 1,
148
+ 1
149
+ ],
150
+ "n_shared_experts": 1,
151
+ "num_attention_heads": 64,
152
+ "num_experts_per_tok": 4,
153
+ "num_hidden_layers": 60,
154
+ "num_key_value_heads": 4,
155
+ "num_local_experts": 128,
156
+ "num_mtp_modules": 7,
157
+ "num_nextn_predict_layers": 1,
158
+ "partial_rotary_factor": 0.5,
159
+ "qk_norm_type": "per_head",
160
+ "rms_norm_eps": 1e-06,
161
+ "rope_theta": 5000000,
162
+ "rotary_dim": 64,
163
+ "routed_scaling_factor": 2.0,
164
+ "scoring_func": "sigmoid",
165
+ "shared_intermediate_size": 3072,
166
+ "sparse_attention_config": {
167
+ "sparse_attention_freq": [
168
+ 0,
169
+ 0,
170
+ 0,
171
+ 1,
172
+ 1,
173
+ 1,
174
+ 1,
175
+ 1,
176
+ 1,
177
+ 1,
178
+ 1,
179
+ 1,
180
+ 1,
181
+ 1,
182
+ 1,
183
+ 1,
184
+ 1,
185
+ 1,
186
+ 1,
187
+ 1,
188
+ 1,
189
+ 1,
190
+ 1,
191
+ 1,
192
+ 1,
193
+ 1,
194
+ 1,
195
+ 1,
196
+ 1,
197
+ 1,
198
+ 1,
199
+ 1,
200
+ 1,
201
+ 1,
202
+ 1,
203
+ 1,
204
+ 1,
205
+ 1,
206
+ 1,
207
+ 1,
208
+ 1,
209
+ 1,
210
+ 1,
211
+ 1,
212
+ 1,
213
+ 1,
214
+ 1,
215
+ 1,
216
+ 1,
217
+ 1,
218
+ 1,
219
+ 1,
220
+ 1,
221
+ 1,
222
+ 1,
223
+ 1,
224
+ 1,
225
+ 1,
226
+ 1,
227
+ 1
228
+ ],
229
+ "sparse_block_size": 128,
230
+ "sparse_disable_index_value": [
231
+ 0,
232
+ 0,
233
+ 0,
234
+ 1,
235
+ 1,
236
+ 1,
237
+ 1,
238
+ 1,
239
+ 1,
240
+ 1,
241
+ 1,
242
+ 1,
243
+ 1,
244
+ 1,
245
+ 1,
246
+ 1,
247
+ 1,
248
+ 1,
249
+ 1,
250
+ 1,
251
+ 1,
252
+ 1,
253
+ 1,
254
+ 1,
255
+ 1,
256
+ 1,
257
+ 1,
258
+ 1,
259
+ 1,
260
+ 1,
261
+ 1,
262
+ 1,
263
+ 1,
264
+ 1,
265
+ 1,
266
+ 1,
267
+ 1,
268
+ 1,
269
+ 1,
270
+ 1,
271
+ 1,
272
+ 1,
273
+ 1,
274
+ 1,
275
+ 1,
276
+ 1,
277
+ 1,
278
+ 1,
279
+ 1,
280
+ 1,
281
+ 1,
282
+ 1,
283
+ 1,
284
+ 1,
285
+ 1,
286
+ 1,
287
+ 1,
288
+ 1,
289
+ 1,
290
+ 1
291
+ ],
292
+ "sparse_index_dim": 128,
293
+ "sparse_init_block": 0,
294
+ "sparse_local_block": 1,
295
+ "sparse_num_index_heads": 4,
296
+ "sparse_score_type": "max",
297
+ "sparse_topk_blocks": 16,
298
+ "use_sparse_attention": true
299
+ },
300
+ "swiglu_alpha": 1.702,
301
+ "swiglu_limit": 7.0,
302
+ "tie_word_embeddings": false,
303
+ "use_gemma_norm": true,
304
+ "use_qk_norm": true,
305
+ "use_routing_bias": true,
306
+ "vocab_size": 200064
307
+ },
308
+ "torch_dtype": "bfloat16",
309
+ "transformers_version": "4.52.4",
310
+ "video_token_index": 200026,
311
+ "vision_config": {
312
+ "attention_dropout": 0.0,
313
+ "hidden_act": "gelu",
314
+ "hidden_size": 1280,
315
+ "image_size": 2016,
316
+ "img_token_compression_config": {
317
+ "image_token_compression_method": "patch_merge",
318
+ "spatial_merge_size": 2,
319
+ "temporal_patch_size": 2
320
+ },
321
+ "initializer_factor": 1.0,
322
+ "initializer_range": 0.02,
323
+ "intermediate_size": 5120,
324
+ "layer_norm_eps": 1e-05,
325
+ "model_type": "clip_vision_model",
326
+ "num_attention_heads": 16,
327
+ "num_channels": 3,
328
+ "num_hidden_layers": 32,
329
+ "patch_size": 14,
330
+ "position_embedding_type": "rope",
331
+ "projection_dim": 6144,
332
+ "rope_mode": "3d",
333
+ "rope_theta": 10000.0,
334
+ "vision_segment_max_frames": 4,
335
+ "vocab_size": 32000
336
+ },
337
+ "vision_feature_layer": -1,
338
+ "vision_feature_select_strategy": "full"
339
+ }
figures/efficiency_gqa_vs_msa.png ADDED
figures/logo.svg ADDED
image_processor.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2024 SGLang Team
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ """
4
+ MiniMax VL family HuggingFace-compatible Processor, ImageProcessor, VideoProcessor.
5
+ """
6
+ import math
7
+ from typing import List, Tuple
8
+
9
+ import torch
10
+ from torchvision.transforms import InterpolationMode
11
+ from transformers import BatchFeature
12
+ from transformers.image_processing_utils_fast import (
13
+ BaseImageProcessorFast,
14
+ group_images_by_shape,
15
+ reorder_images,
16
+ )
17
+ from transformers.image_utils import PILImageResampling, SizeDict
18
+ from transformers.processing_utils import (
19
+ ImagesKwargs,
20
+ Unpack,
21
+ )
22
+ from transformers.utils import TensorType
23
+
24
+ MAX_RATIO = 200
25
+
26
+
27
+ def round_by_factor(number: int, factor: int) -> int:
28
+ return round(number / factor) * factor
29
+
30
+
31
+ def ceil_by_factor(number: int, factor: int) -> int:
32
+ return math.ceil(number / factor) * factor
33
+
34
+
35
+ def floor_by_factor(number: int, factor: int) -> int:
36
+ return math.floor(number / factor) * factor
37
+
38
+
39
+ def smart_resize(
40
+ height: int,
41
+ width: int,
42
+ factor: int = 28,
43
+ min_pixels: int = 4 * 28 * 28,
44
+ max_pixels: int = 451584,
45
+ ) -> tuple[int, int]:
46
+ if max(height, width) / min(height, width) > MAX_RATIO:
47
+ raise ValueError(
48
+ f"absolute aspect ratio must be smaller than {MAX_RATIO}, "
49
+ f"got {max(height, width) / min(height, width)}"
50
+ )
51
+ h_bar = max(factor, round_by_factor(height, factor))
52
+ w_bar = max(factor, round_by_factor(width, factor))
53
+ if h_bar * w_bar > max_pixels:
54
+ beta = math.sqrt((height * width) / max_pixels)
55
+ h_bar = floor_by_factor(height / beta, factor)
56
+ w_bar = floor_by_factor(width / beta, factor)
57
+ elif h_bar * w_bar < min_pixels:
58
+ beta = math.sqrt(min_pixels / (height * width))
59
+ h_bar = ceil_by_factor(height * beta, factor)
60
+ w_bar = ceil_by_factor(width * beta, factor)
61
+ return h_bar, w_bar
62
+
63
+
64
+ # ==============================================================================
65
+ # MiniMax M3 VL Image Processor Fast (Fast Mode - Torch based)
66
+ # ==============================================================================
67
+
68
+
69
+ class MiniMaxM3VLImageProcessorKwargs(ImagesKwargs, total=False):
70
+ patch_size: int
71
+ temporal_patch_size: int
72
+ merge_size: int
73
+ max_pixels: int
74
+
75
+
76
+ class MiniMaxM3VLImageProcessor(BaseImageProcessorFast):
77
+ do_resize = True
78
+ resample = PILImageResampling.BICUBIC
79
+ size = {"height": 672, "width": 672} # required by base class validation, not used as resize bound
80
+ default_to_square = False
81
+ do_rescale = True
82
+ rescale_factor = 1 / 255
83
+ do_normalize = True
84
+ image_mean = [0.48145466, 0.4578275, 0.40821073]
85
+ image_std = [0.26862954, 0.26130258, 0.27577711]
86
+ do_convert_rgb = True
87
+ patch_size = 14
88
+ temporal_patch_size = 2
89
+ merge_size = 2
90
+ max_pixels = 451584 # 672*672
91
+ valid_kwargs = MiniMaxM3VLImageProcessorKwargs
92
+ model_input_names = ["pixel_values", "image_grid_thw"]
93
+
94
+ def __init__(self, **kwargs: Unpack[MiniMaxM3VLImageProcessorKwargs]):
95
+ super().__init__(**kwargs)
96
+
97
+ def preprocess(
98
+ self, images, **kwargs: Unpack[MiniMaxM3VLImageProcessorKwargs]
99
+ ) -> BatchFeature:
100
+ return super().preprocess(images, **kwargs)
101
+
102
+ def _preprocess(
103
+ self,
104
+ images: List[torch.Tensor],
105
+ do_resize: bool,
106
+ size: SizeDict,
107
+ resample: PILImageResampling | InterpolationMode | int | None,
108
+ do_rescale: bool,
109
+ rescale_factor: float,
110
+ do_normalize: bool,
111
+ image_mean: float | List[float] | None,
112
+ image_std: float | List[float] | None,
113
+ patch_size: int,
114
+ temporal_patch_size: int,
115
+ merge_size: int,
116
+ max_pixels: int,
117
+ disable_grouping: bool | None,
118
+ return_tensors: str | TensorType | None,
119
+ **kwargs,
120
+ ) -> BatchFeature:
121
+ grouped_images, grouped_images_index = group_images_by_shape(
122
+ images, disable_grouping=disable_grouping
123
+ )
124
+ resized_images_grouped = {}
125
+ factor = patch_size * merge_size
126
+ for shape, stacked_images in grouped_images.items():
127
+ height, width = stacked_images.shape[-2:]
128
+ if do_resize:
129
+ resized_height, resized_width = smart_resize(
130
+ height, width, factor=factor,
131
+ max_pixels=max_pixels,
132
+ )
133
+ stacked_images = self.resize(
134
+ stacked_images,
135
+ size=SizeDict(height=resized_height, width=resized_width),
136
+ resample=resample,
137
+ )
138
+ resized_images_grouped[shape] = stacked_images
139
+
140
+ resized_images = reorder_images(resized_images_grouped, grouped_images_index)
141
+
142
+ grouped_images, grouped_images_index = group_images_by_shape(
143
+ resized_images, disable_grouping=disable_grouping
144
+ )
145
+ processed_images_grouped = {}
146
+ processed_grids = {}
147
+
148
+ for shape, stacked_images in grouped_images.items():
149
+ resized_height, resized_width = stacked_images.shape[-2:]
150
+
151
+ patches = self.rescale_and_normalize(
152
+ stacked_images,
153
+ do_rescale,
154
+ rescale_factor,
155
+ do_normalize,
156
+ image_mean,
157
+ image_std,
158
+ )
159
+ if patches.ndim == 4:
160
+ patches = patches.unsqueeze(1)
161
+
162
+ if patches.shape[1] % temporal_patch_size != 0:
163
+ repeats = patches[:, -1:].repeat(
164
+ 1,
165
+ temporal_patch_size - (patches.shape[1] % temporal_patch_size),
166
+ 1,
167
+ 1,
168
+ 1,
169
+ )
170
+ patches = torch.cat([patches, repeats], dim=1)
171
+
172
+ batch_size, grid_t, channel = patches.shape[:3]
173
+ grid_t = grid_t // temporal_patch_size
174
+ grid_h, grid_w = resized_height // patch_size, resized_width // patch_size
175
+
176
+ patches = patches.view(
177
+ batch_size,
178
+ grid_t,
179
+ temporal_patch_size,
180
+ channel,
181
+ grid_h // merge_size,
182
+ merge_size,
183
+ patch_size,
184
+ grid_w // merge_size,
185
+ merge_size,
186
+ patch_size,
187
+ )
188
+ patches = patches.permute(0, 1, 4, 7, 5, 8, 3, 2, 6, 9)
189
+
190
+ flatten_patches = patches.reshape(
191
+ batch_size,
192
+ grid_t * grid_h * grid_w,
193
+ channel * temporal_patch_size * patch_size * patch_size,
194
+ )
195
+
196
+ processed_images_grouped[shape] = flatten_patches
197
+ processed_grids[shape] = [[grid_t, grid_h, grid_w]] * batch_size
198
+
199
+ processed_images = reorder_images(
200
+ processed_images_grouped, grouped_images_index
201
+ )
202
+ processed_grids = reorder_images(processed_grids, grouped_images_index)
203
+
204
+ pixel_values = torch.cat(processed_images, dim=0)
205
+ image_grid_thw = torch.tensor(processed_grids, dtype=torch.long)
206
+
207
+ return BatchFeature(
208
+ data={"pixel_values": pixel_values, "image_grid_thw": image_grid_thw},
209
+ tensor_type=return_tensors,
210
+ )
211
+
212
+ def get_number_of_image_patches(self, height: int, width: int, images_kwargs=None):
213
+ images_kwargs = images_kwargs or {}
214
+ patch_size = images_kwargs.get("patch_size", self.patch_size)
215
+ merge_size = images_kwargs.get("merge_size", self.merge_size)
216
+ max_pixels = images_kwargs.get("max_pixels", self.max_pixels)
217
+
218
+ resized_height, resized_width = smart_resize(
219
+ height, width, factor=patch_size * merge_size,
220
+ max_pixels=max_pixels,
221
+ )
222
+ grid_h, grid_w = resized_height // patch_size, resized_width // patch_size
223
+ return grid_h * grid_w
model-00006-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b9bb01cda86bad457fde876d672c2543d208d8cfbd2dfd75185fbc0af724a74f
3
+ size 8044892000
model-00017-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2dfb57ca656062dbef4bbf7a7ded68d244d48ae27796e6e58230eff04f9f7ce5
3
+ size 8044892800
model-00021-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:41279c49f3ed78ac6f2a4ad2999e769cba431ce7b332fde9fe812b7ae0d1b269
3
+ size 8044892800
model-00022-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:39c1cd7431ee20d91e0392eb34429fd92a3c0b9791415a63e4ddf1445d288b00
3
+ size 8044892800
model-00025-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c4958ab4cb570c0cc8583643cd3d0315c295dcf2f1a074225de2c4d35572af37
3
+ size 2625510192
model-00032-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8b629570fe950f1286d3132082583c557d53f74caf89c8c6b1cf03ab19977c5d
3
+ size 7421757928
model-00034-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d0299a66467735075cf883bc56870771134924ec68962243ebfa5de7fa331f61
3
+ size 7421757928
model-00039-of-00059.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:198ec891f57ecc349904edaa6c9c5ef48ebfb79d8acd037a59724852f37cd0a3
3
+ size 6798623072
model.safetensors.index.json ADDED
The diff for this file is too large to render. See raw diff
 
processing_minimax.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2024 SGLang Team
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ """
4
+ MiniMax VL family HuggingFace-compatible Processor, ImageProcessor, VideoProcessor.
5
+ """
6
+
7
+ import math
8
+ import re
9
+ from typing import List, Optional, Tuple, Union
10
+
11
+ import torch
12
+ import torchvision
13
+ from torchvision.transforms import InterpolationMode
14
+ from transformers import BatchFeature
15
+ from transformers.image_processing_utils_fast import (
16
+ BaseImageProcessorFast,
17
+ group_images_by_shape,
18
+ reorder_images,
19
+ )
20
+ from transformers.image_utils import PILImageResampling, SizeDict
21
+ from transformers.processing_utils import (
22
+ ImagesKwargs,
23
+ ProcessingKwargs,
24
+ ProcessorMixin,
25
+ Unpack,
26
+ VideosKwargs,
27
+ )
28
+ from transformers.utils import TensorType
29
+ from transformers.video_processing_utils import BaseVideoProcessor
30
+ from transformers.video_utils import group_videos_by_shape, reorder_videos
31
+
32
+
33
+ class MiniMaxVLProcessorKwargs(ProcessingKwargs, total=False):
34
+ _defaults = {
35
+ "videos_kwargs": {
36
+ "do_resize": False,
37
+ "return_metadata": True,
38
+ },
39
+ }
40
+
41
+
42
+ class MiniMaxVLProcessor(ProcessorMixin):
43
+ IMAGE_TOKEN = "]<]image[>["
44
+ VIDEO_TOKEN = "]<]video[>["
45
+ VISION_START_TOKEN = "]<]start of image[>["
46
+ VISION_END_TOKEN = "]<]end of image[>["
47
+
48
+ def __init__(
49
+ self, image_processor=None, tokenizer=None, video_processor=None, **kwargs
50
+ ):
51
+ self.image_token_id = tokenizer.convert_tokens_to_ids(self.IMAGE_TOKEN)
52
+ self.video_token_id = tokenizer.convert_tokens_to_ids(self.VIDEO_TOKEN)
53
+ super().__init__(image_processor, tokenizer, video_processor)
54
+ # Video expansion also uses image start/end tokens. Separate video
55
+ # start/end tokens exist in the tokenizer, but the original MiniMax
56
+ # serving path did not use them; keep that behavior for compatibility.
57
+ self.vision_start_token_id = tokenizer.convert_tokens_to_ids(
58
+ self.VISION_START_TOKEN
59
+ )
60
+ self.vision_end_token_id = tokenizer.convert_tokens_to_ids(
61
+ self.VISION_END_TOKEN
62
+ )
63
+
64
+ def _prune_video_tokens(
65
+ self,
66
+ input_text: str,
67
+ video_segments: List[int],
68
+ video_token: str,
69
+ ) -> str:
70
+ """
71
+ Prune video tokens by temporal_patch_size (e.g., 2:1).
72
+
73
+ Expects the prompt to carry exactly sum(video_segments) video
74
+ tokens — i.e. one token per *sampled* frame. Then drops token.
75
+
76
+ Args:
77
+ input_text: prompt with N video_tokens per segment
78
+ video_segments: actual sampled frame count per video segment
79
+ video_token: the video token string, e.g. ']<]video[>['
80
+
81
+ Returns:
82
+ Pruned input_text with ~N/temporal_patch_size tokens per segment.
83
+ """
84
+ # If no videos or temporal_patch_size <= 1, no pruning needed
85
+ if not video_segments or self.video_processor.temporal_patch_size <= 1:
86
+ return input_text
87
+
88
+ # Split while keeping delimiters
89
+ special_tokens = [video_token] # , image_token]
90
+ pattern = "|".join(map(re.escape, special_tokens))
91
+ parts = re.split(f"({pattern})", input_text)
92
+
93
+ def is_timestamp(text: str) -> bool:
94
+ """Check if text ends with timestamp format like ']<]0.0 seconds[>['"""
95
+ return (
96
+ text.endswith("seconds[>[")
97
+ or text.endswith("seconds[>[ ")
98
+ or text.endswith("seconds [>[")
99
+ or text.endswith("seconds [>[ ")
100
+ )
101
+
102
+ def extract_timestamp(text: str) -> str:
103
+ """Extract timestamp text from the end, starting from ']<]'"""
104
+ start_index = text.rfind("]<]")
105
+ if start_index == -1:
106
+ raise ValueError(f"Failed to extract timestamp: {text}")
107
+ return text[start_index:]
108
+
109
+ # Build new text with pruned video tokens
110
+ final_parts = []
111
+ current_seg_idx = 0 # Which video segment we're in
112
+ frame_in_seg = 0 # Frame index within current segment
113
+ last_timestamp_len = 0 # Length of timestamp to potentially remove
114
+
115
+ for part in parts:
116
+ if part == video_token:
117
+ if current_seg_idx < len(video_segments):
118
+ if frame_in_seg % self.video_processor.temporal_patch_size == 0:
119
+ # Keep this video token
120
+ final_parts.append(part)
121
+ frame_in_seg += 1
122
+ if frame_in_seg >= video_segments[current_seg_idx]:
123
+ current_seg_idx += 1
124
+ frame_in_seg = 0
125
+ last_timestamp_len = 0
126
+ else:
127
+ # Skip this video token
128
+ frame_in_seg += 1
129
+ if frame_in_seg >= video_segments[current_seg_idx]:
130
+ current_seg_idx += 1
131
+ frame_in_seg = 0
132
+ # Remove the timestamp that was already appended
133
+ if last_timestamp_len > 0:
134
+ # Truncate the last part to remove timestamp
135
+ assert len(final_parts) > 0
136
+ final_parts[-1] = final_parts[-1][:-last_timestamp_len]
137
+ last_timestamp_len = 0
138
+ else:
139
+ # No more video segments, keep as is
140
+ final_parts.append(part)
141
+ last_timestamp_len = 0
142
+ else:
143
+ # Text part
144
+ final_parts.append(part)
145
+ # Check if this text ends with a timestamp
146
+ if is_timestamp(part):
147
+ last_timestamp_len = len(extract_timestamp(part))
148
+ else:
149
+ last_timestamp_len = 0
150
+
151
+ return "".join(final_parts)
152
+
153
+ def __call__(
154
+ self,
155
+ images=None,
156
+ text=None,
157
+ videos=None,
158
+ **kwargs: Unpack[MiniMaxVLProcessorKwargs],
159
+ ) -> BatchFeature:
160
+ output_kwargs = self._merge_kwargs(
161
+ MiniMaxVLProcessorKwargs,
162
+ tokenizer_init_kwargs=self.tokenizer.init_kwargs,
163
+ **kwargs,
164
+ )
165
+
166
+ if images is not None:
167
+ images_kwargs = output_kwargs["images_kwargs"]
168
+ image_inputs = self.image_processor(images=images, **images_kwargs)
169
+ image_grid_thw = image_inputs["image_grid_thw"]
170
+
171
+ else:
172
+ image_inputs = {}
173
+ image_grid_thw = None
174
+
175
+ if videos is not None:
176
+ videos_kwargs = output_kwargs["videos_kwargs"]
177
+ video_inputs = self.video_processor(videos=videos, **videos_kwargs)
178
+ video_grid_thw = video_inputs["video_grid_thw"]
179
+ if not kwargs.get("return_metadata"):
180
+ video_metadata = video_inputs.pop("video_metadata")
181
+ else:
182
+ video_metadata = video_inputs["video_metadata"]
183
+ else:
184
+ video_inputs = {}
185
+ video_grid_thw = None
186
+
187
+ if not isinstance(text, list):
188
+ text = [text]
189
+ text = text.copy()
190
+
191
+ # Expand image tokens
192
+ if image_grid_thw is not None:
193
+ merge_length = self.image_processor.merge_size**2
194
+ placeholder = "]<]placeholder[>["
195
+ index = 0
196
+ for i in range(len(text)):
197
+ while self.IMAGE_TOKEN in text[i]:
198
+ num_tokens = image_grid_thw[index].prod() // merge_length
199
+ text[i] = text[i].replace(
200
+ self.IMAGE_TOKEN,
201
+ self.VISION_START_TOKEN
202
+ + placeholder * num_tokens
203
+ + self.VISION_END_TOKEN,
204
+ 1,
205
+ )
206
+ index += 1
207
+ text[i] = text[i].replace(placeholder, self.IMAGE_TOKEN)
208
+
209
+ # Expand video tokens
210
+ if video_grid_thw is not None:
211
+ merge_length = self.image_processor.merge_size**2
212
+ placeholder = "]<]placeholder[>["
213
+ index = 0
214
+ for i in range(len(text)):
215
+ while self.VIDEO_TOKEN in text[i]:
216
+ metadata = video_metadata[index]
217
+ grid_t = video_grid_thw[index][0]
218
+ frame_seqlen = video_grid_thw[index][1:].prod() // merge_length
219
+
220
+ video_placeholder = ""
221
+ for frame_idx in range(grid_t):
222
+ if (
223
+ metadata.fps is not None
224
+ and metadata.frames_indices is not None
225
+ ):
226
+ ts = (
227
+ metadata.frames_indices[
228
+ min(
229
+ frame_idx
230
+ * self.video_processor.temporal_patch_size,
231
+ len(metadata.frames_indices) - 1,
232
+ )
233
+ ]
234
+ / metadata.fps
235
+ )
236
+ video_placeholder += f"]<]{ts:.1f} seconds[>["
237
+ video_placeholder += (
238
+ self.VISION_START_TOKEN
239
+ + placeholder * frame_seqlen
240
+ + self.VISION_END_TOKEN
241
+ )
242
+
243
+ text[i] = text[i].replace(self.VIDEO_TOKEN, video_placeholder, 1)
244
+ index += 1
245
+ text[i] = text[i].replace(placeholder, self.VIDEO_TOKEN)
246
+
247
+ # Tokenize
248
+ return_tensors = output_kwargs["text_kwargs"].pop("return_tensors", None)
249
+ text_inputs = self.tokenizer(text, **output_kwargs["text_kwargs"])
250
+
251
+ return BatchFeature(
252
+ data={**text_inputs, **image_inputs, **video_inputs},
253
+ tensor_type=return_tensors,
254
+ )
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,501 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "200000": {
5
+ "content": "]!p~[",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "200001": {
13
+ "content": "<fim_prefix>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "200002": {
21
+ "content": "<fim_middle>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "200003": {
29
+ "content": "<fim_suffix>",
30
+ "lstrip": false,
31
+ "normalized": false,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "200004": {
37
+ "content": "<fim_pad>",
38
+ "lstrip": false,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ },
44
+ "200005": {
45
+ "content": "<reponame>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false,
50
+ "special": true
51
+ },
52
+ "200006": {
53
+ "content": "<filename>",
54
+ "lstrip": false,
55
+ "normalized": false,
56
+ "rstrip": false,
57
+ "single_word": false,
58
+ "special": true
59
+ },
60
+ "200007": {
61
+ "content": "<gh_stars>",
62
+ "lstrip": false,
63
+ "normalized": false,
64
+ "rstrip": false,
65
+ "single_word": false,
66
+ "special": true
67
+ },
68
+ "200008": {
69
+ "content": "<issue_start>",
70
+ "lstrip": false,
71
+ "normalized": false,
72
+ "rstrip": false,
73
+ "single_word": false,
74
+ "special": true
75
+ },
76
+ "200009": {
77
+ "content": "<issue_comment>",
78
+ "lstrip": false,
79
+ "normalized": false,
80
+ "rstrip": false,
81
+ "single_word": false,
82
+ "special": true
83
+ },
84
+ "200010": {
85
+ "content": "<issue_closed>",
86
+ "lstrip": false,
87
+ "normalized": false,
88
+ "rstrip": false,
89
+ "single_word": false,
90
+ "special": true
91
+ },
92
+ "200011": {
93
+ "content": "<jupyter_start>",
94
+ "lstrip": false,
95
+ "normalized": false,
96
+ "rstrip": false,
97
+ "single_word": false,
98
+ "special": true
99
+ },
100
+ "200012": {
101
+ "content": "<jupyter_text>",
102
+ "lstrip": false,
103
+ "normalized": false,
104
+ "rstrip": false,
105
+ "single_word": false,
106
+ "special": true
107
+ },
108
+ "200013": {
109
+ "content": "<jupyter_code>",
110
+ "lstrip": false,
111
+ "normalized": false,
112
+ "rstrip": false,
113
+ "single_word": false,
114
+ "special": true
115
+ },
116
+ "200014": {
117
+ "content": "<jupyter_output>",
118
+ "lstrip": false,
119
+ "normalized": false,
120
+ "rstrip": false,
121
+ "single_word": false,
122
+ "special": true
123
+ },
124
+ "200015": {
125
+ "content": "<empty_output>",
126
+ "lstrip": false,
127
+ "normalized": false,
128
+ "rstrip": false,
129
+ "single_word": false,
130
+ "special": true
131
+ },
132
+ "200016": {
133
+ "content": "<commit_before>",
134
+ "lstrip": false,
135
+ "normalized": false,
136
+ "rstrip": false,
137
+ "single_word": false,
138
+ "special": true
139
+ },
140
+ "200017": {
141
+ "content": "<commit_msg>",
142
+ "lstrip": false,
143
+ "normalized": false,
144
+ "rstrip": false,
145
+ "single_word": false,
146
+ "special": true
147
+ },
148
+ "200018": {
149
+ "content": "<commit_after>",
150
+ "lstrip": false,
151
+ "normalized": false,
152
+ "rstrip": false,
153
+ "single_word": false,
154
+ "special": true
155
+ },
156
+ "200019": {
157
+ "content": "]~b]",
158
+ "lstrip": false,
159
+ "normalized": false,
160
+ "rstrip": false,
161
+ "single_word": false,
162
+ "special": true
163
+ },
164
+ "200020": {
165
+ "content": "[e~[",
166
+ "lstrip": false,
167
+ "normalized": false,
168
+ "rstrip": false,
169
+ "single_word": false,
170
+ "special": true
171
+ },
172
+ "200021": {
173
+ "content": "]!d~[",
174
+ "lstrip": false,
175
+ "normalized": false,
176
+ "rstrip": false,
177
+ "single_word": false,
178
+ "special": true
179
+ },
180
+ "200022": {
181
+ "content": "<function_call>",
182
+ "lstrip": false,
183
+ "normalized": false,
184
+ "rstrip": false,
185
+ "single_word": false,
186
+ "special": true
187
+ },
188
+ "200023": {
189
+ "content": "<code_interpreter>",
190
+ "lstrip": false,
191
+ "normalized": false,
192
+ "rstrip": false,
193
+ "single_word": false,
194
+ "special": true
195
+ },
196
+ "200024": {
197
+ "content": "]<]speech[>[",
198
+ "lstrip": false,
199
+ "normalized": false,
200
+ "rstrip": false,
201
+ "single_word": false,
202
+ "special": true
203
+ },
204
+ "200025": {
205
+ "content": "]<]image[>[",
206
+ "lstrip": false,
207
+ "normalized": false,
208
+ "rstrip": false,
209
+ "single_word": false,
210
+ "special": true
211
+ },
212
+ "200026": {
213
+ "content": "]<]video[>[",
214
+ "lstrip": false,
215
+ "normalized": false,
216
+ "rstrip": false,
217
+ "single_word": false,
218
+ "special": true
219
+ },
220
+ "200027": {
221
+ "content": "]<]start of speech[>[",
222
+ "lstrip": false,
223
+ "normalized": false,
224
+ "rstrip": false,
225
+ "single_word": false,
226
+ "special": true
227
+ },
228
+ "200028": {
229
+ "content": "]<]end of speech[>[",
230
+ "lstrip": false,
231
+ "normalized": false,
232
+ "rstrip": false,
233
+ "single_word": false,
234
+ "special": true
235
+ },
236
+ "200029": {
237
+ "content": "]<]start of image[>[",
238
+ "lstrip": false,
239
+ "normalized": false,
240
+ "rstrip": false,
241
+ "single_word": false,
242
+ "special": true
243
+ },
244
+ "200030": {
245
+ "content": "]<]end of image[>[",
246
+ "lstrip": false,
247
+ "normalized": false,
248
+ "rstrip": false,
249
+ "single_word": false,
250
+ "special": true
251
+ },
252
+ "200031": {
253
+ "content": "]<]start of video[>[",
254
+ "lstrip": false,
255
+ "normalized": false,
256
+ "rstrip": false,
257
+ "single_word": false,
258
+ "special": true
259
+ },
260
+ "200032": {
261
+ "content": "]<]end of video[>[",
262
+ "lstrip": false,
263
+ "normalized": false,
264
+ "rstrip": false,
265
+ "single_word": false,
266
+ "special": true
267
+ },
268
+ "200033": {
269
+ "content": "]<]vision pad[>[",
270
+ "lstrip": false,
271
+ "normalized": false,
272
+ "rstrip": false,
273
+ "single_word": false,
274
+ "special": true
275
+ },
276
+ "200034": {
277
+ "content": "]~!b[",
278
+ "lstrip": false,
279
+ "normalized": false,
280
+ "rstrip": false,
281
+ "single_word": false,
282
+ "special": true
283
+ },
284
+ "200035": {
285
+ "content": "<jupyter_error>",
286
+ "lstrip": false,
287
+ "normalized": false,
288
+ "rstrip": false,
289
+ "single_word": false,
290
+ "special": true
291
+ },
292
+ "200036": {
293
+ "content": "<add_file>",
294
+ "lstrip": false,
295
+ "normalized": false,
296
+ "rstrip": false,
297
+ "single_word": false,
298
+ "special": true
299
+ },
300
+ "200037": {
301
+ "content": "<delete_file>",
302
+ "lstrip": false,
303
+ "normalized": false,
304
+ "rstrip": false,
305
+ "single_word": false,
306
+ "special": true
307
+ },
308
+ "200038": {
309
+ "content": "<rename_file>",
310
+ "lstrip": false,
311
+ "normalized": false,
312
+ "rstrip": false,
313
+ "single_word": false,
314
+ "special": true
315
+ },
316
+ "200039": {
317
+ "content": "<edit_file>",
318
+ "lstrip": false,
319
+ "normalized": false,
320
+ "rstrip": false,
321
+ "single_word": false,
322
+ "special": true
323
+ },
324
+ "200040": {
325
+ "content": "<commit_message>",
326
+ "lstrip": false,
327
+ "normalized": false,
328
+ "rstrip": false,
329
+ "single_word": false,
330
+ "special": true
331
+ },
332
+ "200041": {
333
+ "content": "<empty_source_file>",
334
+ "lstrip": false,
335
+ "normalized": false,
336
+ "rstrip": false,
337
+ "single_word": false,
338
+ "special": true
339
+ },
340
+ "200042": {
341
+ "content": "<repo_struct>",
342
+ "lstrip": false,
343
+ "normalized": false,
344
+ "rstrip": false,
345
+ "single_word": false,
346
+ "special": true
347
+ },
348
+ "200043": {
349
+ "content": "<code_context>",
350
+ "lstrip": false,
351
+ "normalized": false,
352
+ "rstrip": false,
353
+ "single_word": false,
354
+ "special": true
355
+ },
356
+ "200044": {
357
+ "content": "<file_content>",
358
+ "lstrip": false,
359
+ "normalized": false,
360
+ "rstrip": false,
361
+ "single_word": false,
362
+ "special": true
363
+ },
364
+ "200045": {
365
+ "content": "<source_files>",
366
+ "lstrip": false,
367
+ "normalized": false,
368
+ "rstrip": false,
369
+ "single_word": false,
370
+ "special": true
371
+ },
372
+ "200046": {
373
+ "content": "<pr_start>",
374
+ "lstrip": false,
375
+ "normalized": false,
376
+ "rstrip": false,
377
+ "single_word": false,
378
+ "special": true
379
+ },
380
+ "200047": {
381
+ "content": "<review_comment>",
382
+ "lstrip": false,
383
+ "normalized": false,
384
+ "rstrip": false,
385
+ "single_word": false,
386
+ "special": true
387
+ },
388
+ "200048": {
389
+ "content": "<filepath>",
390
+ "lstrip": false,
391
+ "normalized": false,
392
+ "rstrip": false,
393
+ "single_word": false,
394
+ "special": true
395
+ },
396
+ "200049": {
397
+ "content": "<file_sep>",
398
+ "lstrip": false,
399
+ "normalized": false,
400
+ "rstrip": false,
401
+ "single_word": false,
402
+ "special": true
403
+ },
404
+ "200050": {
405
+ "content": "<think>",
406
+ "lstrip": false,
407
+ "normalized": false,
408
+ "rstrip": false,
409
+ "single_word": false,
410
+ "special": false
411
+ },
412
+ "200051": {
413
+ "content": "</think>",
414
+ "lstrip": false,
415
+ "normalized": false,
416
+ "rstrip": false,
417
+ "single_word": false,
418
+ "special": false
419
+ },
420
+ "200052": {
421
+ "content": "<tool_call>",
422
+ "lstrip": false,
423
+ "normalized": false,
424
+ "rstrip": false,
425
+ "single_word": false,
426
+ "special": false
427
+ },
428
+ "200053": {
429
+ "content": "</tool_call>",
430
+ "lstrip": false,
431
+ "normalized": false,
432
+ "rstrip": false,
433
+ "single_word": false,
434
+ "special": false
435
+ },
436
+ "200054": {
437
+ "content": "]<]frame[>[",
438
+ "lstrip": false,
439
+ "normalized": false,
440
+ "rstrip": false,
441
+ "single_word": false,
442
+ "special": true
443
+ },
444
+ "200055": {
445
+ "content": "]<]start of frame[>[",
446
+ "lstrip": false,
447
+ "normalized": false,
448
+ "rstrip": false,
449
+ "single_word": false,
450
+ "special": true
451
+ },
452
+ "200056": {
453
+ "content": "]<]end of frame[>[",
454
+ "lstrip": false,
455
+ "normalized": false,
456
+ "rstrip": false,
457
+ "single_word": false,
458
+ "special": true
459
+ },
460
+ "200057": {
461
+ "content": "<|content_altered_placeholder|>",
462
+ "lstrip": false,
463
+ "normalized": false,
464
+ "rstrip": false,
465
+ "single_word": false,
466
+ "special": true
467
+ },
468
+ "200058": {
469
+ "content": "]<]minimax[>[",
470
+ "lstrip": false,
471
+ "normalized": false,
472
+ "rstrip": false,
473
+ "single_word": false,
474
+ "special": false
475
+ },
476
+ "200059": {
477
+ "content": "<mm:think>",
478
+ "lstrip": false,
479
+ "normalized": false,
480
+ "rstrip": false,
481
+ "single_word": false,
482
+ "special": false
483
+ },
484
+ "200060": {
485
+ "content": "</mm:think>",
486
+ "lstrip": false,
487
+ "normalized": false,
488
+ "rstrip": false,
489
+ "single_word": false,
490
+ "special": false
491
+ }
492
+ },
493
+ "bos_token": "]~b]",
494
+ "clean_up_tokenization_spaces": false,
495
+ "eos_token": "[e~[",
496
+ "pad_token": "]!p~[",
497
+ "model_max_length": 40960000,
498
+ "tokenizer_class": "PreTrainedTokenizerFast",
499
+ "unk_token": "[e~["
500
+ }
501
+
video_processor.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2024 SGLang Team
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ """
4
+ MiniMax VL family HuggingFace-compatible VideoProcessor.
5
+ """
6
+
7
+ import math
8
+ from typing import List, Optional, Tuple, Union
9
+
10
+ import torch
11
+ import torchvision
12
+ from torchvision.transforms import InterpolationMode
13
+ from transformers import BatchFeature
14
+ from transformers.image_utils import PILImageResampling, SizeDict
15
+ from transformers.processing_utils import (
16
+ Unpack,
17
+ VideosKwargs,
18
+ )
19
+ from transformers.utils import TensorType
20
+ from transformers.video_processing_utils import BaseVideoProcessor
21
+ from transformers.video_utils import group_videos_by_shape, reorder_videos
22
+
23
+ MAX_RATIO = 200
24
+
25
+
26
+ def round_by_factor(number: int, factor: int) -> int:
27
+ return round(number / factor) * factor
28
+
29
+
30
+ def ceil_by_factor(number: int, factor: int) -> int:
31
+ return math.ceil(number / factor) * factor
32
+
33
+
34
+ def floor_by_factor(number: int, factor: int) -> int:
35
+ return math.floor(number / factor) * factor
36
+
37
+
38
+ def smart_resize(
39
+ height: int,
40
+ width: int,
41
+ factor: int = 28,
42
+ min_pixels: int = 4 * 28 * 28,
43
+ max_pixels: int = 451584,
44
+ ) -> tuple[int, int]:
45
+ if max(height, width) / min(height, width) > MAX_RATIO:
46
+ raise ValueError(
47
+ f"absolute aspect ratio must be smaller than {MAX_RATIO}, "
48
+ f"got {max(height, width) / min(height, width)}"
49
+ )
50
+ h_bar = max(factor, round_by_factor(height, factor))
51
+ w_bar = max(factor, round_by_factor(width, factor))
52
+ if h_bar * w_bar > max_pixels:
53
+ beta = math.sqrt((height * width) / max_pixels)
54
+ h_bar = floor_by_factor(height / beta, factor)
55
+ w_bar = floor_by_factor(width / beta, factor)
56
+ elif h_bar * w_bar < min_pixels:
57
+ beta = math.sqrt(min_pixels / (height * width))
58
+ h_bar = ceil_by_factor(height * beta, factor)
59
+ w_bar = ceil_by_factor(width * beta, factor)
60
+ return h_bar, w_bar
61
+
62
+
63
+ class MiniMaxM3VLVideoProcessorKwargs(VideosKwargs, total=False):
64
+ patch_size: int
65
+ temporal_patch_size: int
66
+ merge_size: int
67
+ min_pixels: int
68
+ max_pixels: int
69
+ total_pixels: int
70
+ min_frames: int
71
+ max_frames: int
72
+ fps: float | int
73
+
74
+
75
+ class MiniMaxM3VLVideoProcessor(BaseVideoProcessor):
76
+ do_resize = True
77
+ resample = PILImageResampling.BICUBIC
78
+ size = {"height": 672, "width": 672}
79
+ default_to_square = False
80
+ do_rescale = True
81
+ rescale_factor = 1 / 255
82
+ do_normalize = True
83
+ image_mean = [0.48145466, 0.4578275, 0.40821073]
84
+ image_std = [0.26862954, 0.26130258, 0.27577711]
85
+ do_convert_rgb = True
86
+ do_sample_frames = False
87
+ patch_size = 14
88
+ temporal_patch_size = 2
89
+ merge_size = 2
90
+ min_pixels = 4 * 28 * 28
91
+ max_pixels = 768 * 28 * 28 # 602,112
92
+ total_pixels = int(64000 * 28 * 28 * 0.9) # ~45M, ~64k tokens budget
93
+ fps = 1.0
94
+ min_frames = 4
95
+ max_frames = 768
96
+ valid_kwargs = MiniMaxM3VLVideoProcessorKwargs
97
+ model_input_names = ["pixel_values_videos", "video_grid_thw"]
98
+
99
+ def __init__(self, **kwargs: Unpack[MiniMaxM3VLVideoProcessorKwargs]):
100
+ super().__init__(**kwargs)
101
+
102
+ def _preprocess(
103
+ self,
104
+ videos: List[torch.Tensor],
105
+ do_convert_rgb: bool,
106
+ do_resize: bool,
107
+ size: SizeDict,
108
+ resample: PILImageResampling | InterpolationMode | int | None,
109
+ do_rescale: bool,
110
+ rescale_factor: float,
111
+ do_normalize: bool,
112
+ image_mean: float | List[float] | None,
113
+ image_std: float | List[float] | None,
114
+ patch_size: int,
115
+ temporal_patch_size: int,
116
+ merge_size: int,
117
+ min_pixels: int,
118
+ max_pixels: int,
119
+ return_tensors: str | TensorType | None = None,
120
+ **kwargs,
121
+ ) -> BatchFeature:
122
+ grouped_videos, grouped_videos_index = group_videos_by_shape(videos)
123
+ resized_videos_grouped = {}
124
+ factor = patch_size * merge_size
125
+ for shape, stacked_videos in grouped_videos.items():
126
+ batch_size, num_frames, channels, height, width = stacked_videos.shape
127
+ resized_height, resized_width = height, width
128
+ if do_resize:
129
+ resized_height, resized_width = smart_resize(
130
+ height, width, factor=factor,
131
+ min_pixels=min_pixels, max_pixels=max_pixels,
132
+ )
133
+ stacked_videos = stacked_videos.view(
134
+ batch_size * num_frames, channels, height, width
135
+ )
136
+ stacked_videos = self.resize(
137
+ stacked_videos,
138
+ size=SizeDict(height=resized_height, width=resized_width),
139
+ resample=resample,
140
+ )
141
+ stacked_videos = stacked_videos.view(
142
+ batch_size,
143
+ num_frames,
144
+ channels,
145
+ resized_height,
146
+ resized_width,
147
+ )
148
+ resized_videos_grouped[shape] = stacked_videos
149
+ resized_videos = reorder_videos(resized_videos_grouped, grouped_videos_index)
150
+
151
+ grouped_videos, grouped_videos_index = group_videos_by_shape(resized_videos)
152
+ processed_videos_grouped = {}
153
+ processed_grids = {}
154
+ for shape, stacked_videos in grouped_videos.items():
155
+ resized_height, resized_width = stacked_videos.shape[-2:]
156
+ patches = self.rescale_and_normalize(
157
+ stacked_videos,
158
+ do_rescale,
159
+ rescale_factor,
160
+ do_normalize,
161
+ image_mean,
162
+ image_std,
163
+ )
164
+
165
+ if pad := -patches.shape[1] % temporal_patch_size:
166
+ repeats = patches[:, -1:].expand(-1, pad, -1, -1, -1)
167
+ patches = torch.cat([patches, repeats], dim=1)
168
+
169
+ batch_size, grid_t, channels = patches.shape[:3]
170
+ grid_t = grid_t // temporal_patch_size
171
+ grid_h, grid_w = resized_height // patch_size, resized_width // patch_size
172
+
173
+ patches = patches.view(
174
+ batch_size,
175
+ grid_t,
176
+ temporal_patch_size,
177
+ channels,
178
+ grid_h // merge_size,
179
+ merge_size,
180
+ patch_size,
181
+ grid_w // merge_size,
182
+ merge_size,
183
+ patch_size,
184
+ )
185
+ patches = patches.permute(0, 1, 4, 7, 5, 8, 3, 2, 6, 9)
186
+ flatten_patches = patches.reshape(
187
+ batch_size,
188
+ grid_t * grid_h * grid_w,
189
+ channels * temporal_patch_size * patch_size * patch_size,
190
+ )
191
+
192
+ processed_videos_grouped[shape] = flatten_patches
193
+ processed_grids[shape] = [[grid_t, grid_h, grid_w]] * batch_size
194
+
195
+ processed_videos = reorder_videos(
196
+ processed_videos_grouped, grouped_videos_index
197
+ )
198
+ processed_grids = reorder_videos(processed_grids, grouped_videos_index)
199
+ pixel_values_videos = torch.cat(processed_videos, dim=0)
200
+ video_grid_thw = torch.tensor(processed_grids, dtype=torch.long)
201
+
202
+ return BatchFeature(
203
+ data={
204
+ "pixel_values_videos": pixel_values_videos,
205
+ "video_grid_thw": video_grid_thw,
206
+ },
207
+ tensor_type=return_tensors,
208
+ )
vocab.json ADDED
The diff for this file is too large to render. See raw diff