Akahsizrr commited on
Commit
db021f5
·
verified ·
1 Parent(s): dd051b1

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
chat_template.jinja ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- bos_token -}}
2
+ {%- set preserve_thinking = preserve_thinking | default(false) -%}
3
+
4
+ {%- macro format_arg_value(arg_value) -%}
5
+ {%- if arg_value is string -%}
6
+ {{- "'" + (arg_value | replace("\\", "\\\\") | replace("'", "\\'") | replace("\n", "\\n") | replace("\r", "\\r")) + "'" -}}
7
+ {%- elif arg_value is mapping or arg_value is iterable -%}
8
+ {{- arg_value | tojson -}}
9
+ {%- else -%}
10
+ {{- arg_value | string -}}
11
+ {%- endif -%}
12
+ {%- endmacro -%}
13
+
14
+ {%- macro parse_content(content) -%}
15
+ {%- if content is string -%}
16
+ {{- content -}}
17
+ {%- elif content is mapping -%}
18
+ {{- content | tojson -}}
19
+ {%- elif content is iterable -%}
20
+ {%- set _ns = namespace(result="") -%}
21
+ {%- for item in content -%}
22
+ {%- if item is string -%}
23
+ {%- set _ns.result = _ns.result + item -%}
24
+ {%- elif item is mapping and item.get("type") == "image" -%}
25
+ {%- set _ns.result = _ns.result + "<image>" -%}
26
+ {%- elif item is mapping and item.get("type") == "text" -%}
27
+ {%- set _ns.result = _ns.result + ((item.get("text") or "") | string) -%}
28
+ {%- else -%}
29
+ {%- set _ns.result = _ns.result + (item | tojson) -%}
30
+ {%- endif -%}
31
+ {%- endfor -%}
32
+ {{- _ns.result -}}
33
+ {%- endif -%}
34
+ {%- endmacro -%}
35
+
36
+ {%- macro render_tool_calls(tool_calls) -%}
37
+ {%- set tool_calls_ns = namespace(tool_calls=[]) -%}
38
+ {%- for tool_call in tool_calls -%}
39
+ {%- set func = tool_call["function"] if "function" in tool_call else tool_call -%}
40
+ {%- set func_name = func["name"] -%}
41
+ {%- set func_args = func.get("arguments") -%}
42
+ {%- set args_ns = namespace(arg_strings=[]) -%}
43
+ {%- if func_args is mapping -%}
44
+ {%- for arg_name, arg_value in func_args.items() -%}
45
+ {%- set args_ns.arg_strings = args_ns.arg_strings + [arg_name + "=" + format_arg_value(arg_value)] -%}
46
+ {%- endfor -%}
47
+ {%- elif func_args is string and (func_args | trim) not in ["", "{}", "null"] -%}
48
+ {{- raise_exception("Tool call arguments must be a mapping, got a JSON-encoded string: parse arguments with json.loads() before applying the chat template") -}}
49
+ {%- endif -%}
50
+ {%- set tool_calls_ns.tool_calls = tool_calls_ns.tool_calls + [func_name + "(" + (args_ns.arg_strings | join(", ")) + ")"] -%}
51
+ {%- endfor -%}
52
+ {{- "<|tool_call_start|>[" + (tool_calls_ns.tool_calls | join(", ")) + "]<|tool_call_end|>" -}}
53
+ {%- endmacro -%}
54
+
55
+ {%- set ns = namespace(system_prompt="", last_user_index=-1) -%}
56
+ {%- if messages and messages[0]["role"] == "system" -%}
57
+ {%- if messages[0].get("content") -%}
58
+ {%- set ns.system_prompt = parse_content(messages[0]["content"]) -%}
59
+ {%- endif -%}
60
+ {%- set messages = messages[1:] -%}
61
+ {%- endif -%}
62
+ {%- if tools -%}
63
+ {%- set ns.system_prompt = ns.system_prompt + ("\n" if ns.system_prompt else "") + "List of tools: [" -%}
64
+ {%- for tool in tools -%}
65
+ {%- if tool is not string -%}
66
+ {%- set tool = tool | tojson -%}
67
+ {%- endif -%}
68
+ {%- set ns.system_prompt = ns.system_prompt + tool -%}
69
+ {%- if not loop.last -%}
70
+ {%- set ns.system_prompt = ns.system_prompt + ", " -%}
71
+ {%- endif -%}
72
+ {%- endfor -%}
73
+ {%- set ns.system_prompt = ns.system_prompt + "]" -%}
74
+ {%- endif -%}
75
+ {%- if ns.system_prompt -%}
76
+ {{- "<|im_start|>system\n" + ns.system_prompt + "<|im_end|>\n" -}}
77
+ {%- endif -%}
78
+ {%- for message in messages -%}
79
+ {%- if message["role"] == "user" -%}
80
+ {%- set ns.last_user_index = loop.index0 -%}
81
+ {%- endif -%}
82
+ {%- endfor -%}
83
+ {%- for message in messages -%}
84
+ {{- "<|im_start|>" + message.role + "\n" -}}
85
+ {%- if message.role == "assistant" -%}
86
+ {%- generation -%}
87
+ {%- set keep_thinking = preserve_thinking or loop.index0 > ns.last_user_index -%}
88
+ {%- set thinking = message.thinking or message.reasoning or message.reasoning_content -%}
89
+ {%- set thinking = thinking if thinking is string else "" -%}
90
+ {%- if thinking and keep_thinking -%}
91
+ {{- "<think>" + thinking + "</think>" -}}
92
+ {%- endif -%}
93
+ {%- set _cfm_tag = "CONTINUE_FINAL_MESSAGE_TAG " -%}
94
+ {%- set _has_cfm = false -%}
95
+ {%- set content = "" -%}
96
+ {%- if message.get("content") -%}
97
+ {%- set content = parse_content(message.content) -%}
98
+ {%- endif -%}
99
+ {%- if not keep_thinking and "</think>" in content -%}
100
+ {%- set content = content.split("</think>")[-1] | trim -%}
101
+ {%- endif -%}
102
+ {%- if content.endswith(_cfm_tag) -%}
103
+ {%- set _has_cfm = true -%}
104
+ {%- set _trunc_len = (content | length) - (_cfm_tag | length) -%}
105
+ {%- set content = content[:_trunc_len] -%}
106
+ {%- endif -%}
107
+ {{- content -}}
108
+ {%- if message.tool_calls -%}
109
+ {{- render_tool_calls(message.tool_calls) -}}
110
+ {%- endif -%}
111
+ {%- if _has_cfm -%}
112
+ {{- _cfm_tag -}}
113
+ {%- endif -%}
114
+ {{- "<|im_end|>\n" -}}
115
+ {%- endgeneration -%}
116
+ {%- else %}
117
+ {%- if message.get("content") -%}
118
+ {{- parse_content(message["content"]) -}}
119
+ {%- endif -%}
120
+ {{- "<|im_end|>\n" -}}
121
+ {%- endif %}
122
+ {%- endfor -%}
123
+ {%- if add_generation_prompt -%}
124
+ {{- "<|im_start|>assistant\n<think>" -}}
125
+ {%- endif -%}
config.json ADDED
@@ -0,0 +1,1104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Fuse3ForCausalLM"
4
+ ],
5
+ "block_auto_adjust_ff_dim": false,
6
+ "block_dim": 2048,
7
+ "block_ffn_dim_multiplier": 1.0,
8
+ "block_mlp_init_scale": 1.0,
9
+ "block_multiple_of": 256,
10
+ "block_norm_eps": 1e-05,
11
+ "block_out_init_scale": 1.0,
12
+ "block_use_swiglu": true,
13
+ "block_use_xavier_init": true,
14
+ "bos_token_id": 124894,
15
+ "coding_enabled": true,
16
+ "conv_L_cache": 3,
17
+ "conv_bias": false,
18
+ "conv_dim": 2048,
19
+ "conv_use_xavier_init": true,
20
+ "dtype": "bfloat16",
21
+ "eos_token_id": 124900,
22
+ "expert_intermediate_size": 512,
23
+ "expert_scale_init": -5.0,
24
+ "experts_per_layer": {
25
+ "0": [
26
+ 62,
27
+ 75,
28
+ 174,
29
+ 231,
30
+ 211,
31
+ 36,
32
+ 134,
33
+ 159,
34
+ 92,
35
+ 70,
36
+ 81,
37
+ 188,
38
+ 144,
39
+ 138,
40
+ 232,
41
+ 241,
42
+ 123,
43
+ 254,
44
+ 191,
45
+ 128,
46
+ 78,
47
+ 37,
48
+ 223,
49
+ 187,
50
+ 11,
51
+ 124,
52
+ 142,
53
+ 48,
54
+ 117,
55
+ 226,
56
+ 77,
57
+ 116
58
+ ],
59
+ "1": [
60
+ 193,
61
+ 254,
62
+ 51,
63
+ 33,
64
+ 80,
65
+ 235,
66
+ 107,
67
+ 66,
68
+ 169,
69
+ 141,
70
+ 13,
71
+ 120,
72
+ 209,
73
+ 75,
74
+ 133,
75
+ 25,
76
+ 40,
77
+ 96,
78
+ 48,
79
+ 153,
80
+ 222,
81
+ 167,
82
+ 162,
83
+ 217,
84
+ 214,
85
+ 55,
86
+ 23,
87
+ 101,
88
+ 74,
89
+ 17,
90
+ 121,
91
+ 185
92
+ ],
93
+ "2": [
94
+ 217,
95
+ 39,
96
+ 115,
97
+ 92,
98
+ 20,
99
+ 216,
100
+ 169,
101
+ 164,
102
+ 223,
103
+ 111,
104
+ 252,
105
+ 182,
106
+ 207,
107
+ 191,
108
+ 193,
109
+ 90,
110
+ 153,
111
+ 157,
112
+ 36,
113
+ 10,
114
+ 150,
115
+ 149,
116
+ 34,
117
+ 42,
118
+ 167,
119
+ 103,
120
+ 145,
121
+ 22,
122
+ 128,
123
+ 187,
124
+ 176,
125
+ 41
126
+ ],
127
+ "3": [
128
+ 196,
129
+ 6,
130
+ 69,
131
+ 224,
132
+ 201,
133
+ 199,
134
+ 149,
135
+ 163,
136
+ 251,
137
+ 17,
138
+ 36,
139
+ 43,
140
+ 212,
141
+ 154,
142
+ 92,
143
+ 166,
144
+ 119,
145
+ 56,
146
+ 197,
147
+ 75,
148
+ 126,
149
+ 221,
150
+ 109,
151
+ 81,
152
+ 113,
153
+ 93,
154
+ 183,
155
+ 22,
156
+ 31,
157
+ 173,
158
+ 255,
159
+ 100
160
+ ],
161
+ "4": [
162
+ 175,
163
+ 253,
164
+ 152,
165
+ 90,
166
+ 28,
167
+ 38,
168
+ 143,
169
+ 36,
170
+ 8,
171
+ 221,
172
+ 189,
173
+ 228,
174
+ 148,
175
+ 160,
176
+ 134,
177
+ 121,
178
+ 157,
179
+ 6,
180
+ 195,
181
+ 235,
182
+ 44,
183
+ 187,
184
+ 140,
185
+ 206,
186
+ 65,
187
+ 46,
188
+ 132,
189
+ 70,
190
+ 156,
191
+ 161,
192
+ 216,
193
+ 94
194
+ ],
195
+ "5": [
196
+ 153,
197
+ 58,
198
+ 251,
199
+ 50,
200
+ 70,
201
+ 22,
202
+ 177,
203
+ 60,
204
+ 218,
205
+ 0,
206
+ 77,
207
+ 222,
208
+ 159,
209
+ 210,
210
+ 163,
211
+ 19,
212
+ 146,
213
+ 8,
214
+ 53,
215
+ 42,
216
+ 74,
217
+ 111,
218
+ 172,
219
+ 137,
220
+ 61,
221
+ 64,
222
+ 7,
223
+ 108,
224
+ 136,
225
+ 164,
226
+ 185,
227
+ 122
228
+ ],
229
+ "6": [
230
+ 26,
231
+ 12,
232
+ 102,
233
+ 159,
234
+ 210,
235
+ 125,
236
+ 30,
237
+ 212,
238
+ 238,
239
+ 64,
240
+ 168,
241
+ 34,
242
+ 195,
243
+ 249,
244
+ 196,
245
+ 79,
246
+ 90,
247
+ 92,
248
+ 169,
249
+ 186,
250
+ 209,
251
+ 237,
252
+ 43,
253
+ 72,
254
+ 120,
255
+ 60,
256
+ 126,
257
+ 218,
258
+ 105,
259
+ 69,
260
+ 113,
261
+ 202
262
+ ],
263
+ "7": [
264
+ 185,
265
+ 78,
266
+ 245,
267
+ 175,
268
+ 227,
269
+ 80,
270
+ 92,
271
+ 49,
272
+ 233,
273
+ 120,
274
+ 174,
275
+ 244,
276
+ 3,
277
+ 142,
278
+ 5,
279
+ 12,
280
+ 104,
281
+ 226,
282
+ 246,
283
+ 132,
284
+ 184,
285
+ 183,
286
+ 240,
287
+ 81,
288
+ 39,
289
+ 160,
290
+ 131,
291
+ 108,
292
+ 75,
293
+ 26,
294
+ 140,
295
+ 187
296
+ ],
297
+ "8": [
298
+ 133,
299
+ 72,
300
+ 148,
301
+ 23,
302
+ 53,
303
+ 16,
304
+ 145,
305
+ 224,
306
+ 188,
307
+ 233,
308
+ 85,
309
+ 76,
310
+ 181,
311
+ 195,
312
+ 180,
313
+ 95,
314
+ 121,
315
+ 71,
316
+ 164,
317
+ 249,
318
+ 98,
319
+ 41,
320
+ 22,
321
+ 193,
322
+ 162,
323
+ 1,
324
+ 171,
325
+ 73,
326
+ 99,
327
+ 192,
328
+ 240,
329
+ 151
330
+ ],
331
+ "9": [
332
+ 99,
333
+ 207,
334
+ 1,
335
+ 186,
336
+ 161,
337
+ 255,
338
+ 130,
339
+ 81,
340
+ 229,
341
+ 188,
342
+ 68,
343
+ 172,
344
+ 254,
345
+ 32,
346
+ 28,
347
+ 114,
348
+ 137,
349
+ 54,
350
+ 179,
351
+ 199,
352
+ 225,
353
+ 120,
354
+ 95,
355
+ 61,
356
+ 251,
357
+ 178,
358
+ 176,
359
+ 233,
360
+ 140,
361
+ 164,
362
+ 20,
363
+ 168
364
+ ],
365
+ "10": [
366
+ 116,
367
+ 132,
368
+ 217,
369
+ 156,
370
+ 12,
371
+ 207,
372
+ 233,
373
+ 146,
374
+ 165,
375
+ 134,
376
+ 234,
377
+ 242,
378
+ 190,
379
+ 148,
380
+ 147,
381
+ 250,
382
+ 149,
383
+ 126,
384
+ 205,
385
+ 176,
386
+ 172,
387
+ 184,
388
+ 23,
389
+ 124,
390
+ 248,
391
+ 137,
392
+ 61,
393
+ 38,
394
+ 108,
395
+ 54,
396
+ 135,
397
+ 14
398
+ ],
399
+ "11": [
400
+ 60,
401
+ 44,
402
+ 141,
403
+ 97,
404
+ 32,
405
+ 204,
406
+ 223,
407
+ 130,
408
+ 107,
409
+ 222,
410
+ 37,
411
+ 63,
412
+ 142,
413
+ 15,
414
+ 218,
415
+ 220,
416
+ 230,
417
+ 134,
418
+ 153,
419
+ 170,
420
+ 10,
421
+ 213,
422
+ 98,
423
+ 180,
424
+ 139,
425
+ 33,
426
+ 20,
427
+ 71,
428
+ 215,
429
+ 214,
430
+ 162,
431
+ 143
432
+ ],
433
+ "12": [
434
+ 116,
435
+ 250,
436
+ 176,
437
+ 161,
438
+ 163,
439
+ 143,
440
+ 157,
441
+ 10,
442
+ 21,
443
+ 38,
444
+ 244,
445
+ 196,
446
+ 1,
447
+ 15,
448
+ 50,
449
+ 137,
450
+ 189,
451
+ 2,
452
+ 39,
453
+ 186,
454
+ 128,
455
+ 14,
456
+ 166,
457
+ 67,
458
+ 63,
459
+ 211,
460
+ 240,
461
+ 17,
462
+ 13,
463
+ 145,
464
+ 55,
465
+ 115
466
+ ],
467
+ "13": [
468
+ 93,
469
+ 212,
470
+ 45,
471
+ 145,
472
+ 219,
473
+ 165,
474
+ 14,
475
+ 83,
476
+ 208,
477
+ 180,
478
+ 183,
479
+ 252,
480
+ 42,
481
+ 120,
482
+ 0,
483
+ 248,
484
+ 151,
485
+ 232,
486
+ 170,
487
+ 166,
488
+ 58,
489
+ 202,
490
+ 66,
491
+ 100,
492
+ 194,
493
+ 34,
494
+ 92,
495
+ 98,
496
+ 158,
497
+ 19,
498
+ 174,
499
+ 144
500
+ ],
501
+ "14": [
502
+ 204,
503
+ 44,
504
+ 132,
505
+ 253,
506
+ 73,
507
+ 194,
508
+ 51,
509
+ 164,
510
+ 202,
511
+ 90,
512
+ 248,
513
+ 214,
514
+ 96,
515
+ 166,
516
+ 189,
517
+ 54,
518
+ 21,
519
+ 64,
520
+ 165,
521
+ 17,
522
+ 225,
523
+ 117,
524
+ 187,
525
+ 113,
526
+ 198,
527
+ 67,
528
+ 179,
529
+ 115,
530
+ 63,
531
+ 163,
532
+ 88,
533
+ 167
534
+ ],
535
+ "15": [
536
+ 147,
537
+ 12,
538
+ 139,
539
+ 14,
540
+ 169,
541
+ 235,
542
+ 206,
543
+ 238,
544
+ 18,
545
+ 1,
546
+ 98,
547
+ 170,
548
+ 114,
549
+ 145,
550
+ 228,
551
+ 195,
552
+ 50,
553
+ 165,
554
+ 242,
555
+ 227,
556
+ 148,
557
+ 74,
558
+ 134,
559
+ 248,
560
+ 3,
561
+ 215,
562
+ 28,
563
+ 90,
564
+ 21,
565
+ 240,
566
+ 81,
567
+ 0
568
+ ],
569
+ "16": [
570
+ 72,
571
+ 172,
572
+ 117,
573
+ 191,
574
+ 183,
575
+ 252,
576
+ 56,
577
+ 112,
578
+ 130,
579
+ 28,
580
+ 59,
581
+ 104,
582
+ 189,
583
+ 155,
584
+ 230,
585
+ 247,
586
+ 160,
587
+ 234,
588
+ 171,
589
+ 195,
590
+ 53,
591
+ 228,
592
+ 25,
593
+ 35,
594
+ 74,
595
+ 116,
596
+ 47,
597
+ 147,
598
+ 209,
599
+ 37,
600
+ 190,
601
+ 5
602
+ ],
603
+ "17": [
604
+ 89,
605
+ 69,
606
+ 38,
607
+ 1,
608
+ 185,
609
+ 152,
610
+ 233,
611
+ 20,
612
+ 19,
613
+ 98,
614
+ 209,
615
+ 100,
616
+ 8,
617
+ 58,
618
+ 44,
619
+ 21,
620
+ 62,
621
+ 222,
622
+ 140,
623
+ 219,
624
+ 125,
625
+ 204,
626
+ 117,
627
+ 217,
628
+ 135,
629
+ 223,
630
+ 189,
631
+ 9,
632
+ 54,
633
+ 4,
634
+ 126,
635
+ 169
636
+ ],
637
+ "18": [
638
+ 77,
639
+ 91,
640
+ 176,
641
+ 138,
642
+ 43,
643
+ 139,
644
+ 175,
645
+ 126,
646
+ 116,
647
+ 225,
648
+ 69,
649
+ 212,
650
+ 144,
651
+ 245,
652
+ 93,
653
+ 152,
654
+ 236,
655
+ 204,
656
+ 66,
657
+ 171,
658
+ 209,
659
+ 146,
660
+ 92,
661
+ 64,
662
+ 108,
663
+ 13,
664
+ 224,
665
+ 241,
666
+ 54,
667
+ 123,
668
+ 163,
669
+ 223
670
+ ],
671
+ "19": [
672
+ 212,
673
+ 59,
674
+ 122,
675
+ 75,
676
+ 115,
677
+ 35,
678
+ 101,
679
+ 88,
680
+ 164,
681
+ 143,
682
+ 203,
683
+ 226,
684
+ 61,
685
+ 95,
686
+ 60,
687
+ 137,
688
+ 99,
689
+ 33,
690
+ 219,
691
+ 183,
692
+ 22,
693
+ 114,
694
+ 116,
695
+ 47,
696
+ 85,
697
+ 248,
698
+ 67,
699
+ 133,
700
+ 231,
701
+ 221,
702
+ 11,
703
+ 25
704
+ ],
705
+ "20": [
706
+ 133,
707
+ 72,
708
+ 23,
709
+ 148,
710
+ 53,
711
+ 195,
712
+ 181,
713
+ 224,
714
+ 71,
715
+ 171,
716
+ 145,
717
+ 95,
718
+ 233,
719
+ 76,
720
+ 85,
721
+ 41,
722
+ 98,
723
+ 188,
724
+ 249,
725
+ 99,
726
+ 1,
727
+ 172,
728
+ 192,
729
+ 197,
730
+ 240,
731
+ 116,
732
+ 173,
733
+ 206,
734
+ 193,
735
+ 151,
736
+ 234,
737
+ 121
738
+ ],
739
+ "21": [
740
+ 207,
741
+ 99,
742
+ 186,
743
+ 1,
744
+ 188,
745
+ 81,
746
+ 251,
747
+ 130,
748
+ 229,
749
+ 95,
750
+ 172,
751
+ 255,
752
+ 68,
753
+ 254,
754
+ 137,
755
+ 32,
756
+ 199,
757
+ 114,
758
+ 179,
759
+ 225,
760
+ 140,
761
+ 20,
762
+ 28,
763
+ 233,
764
+ 54,
765
+ 72,
766
+ 243,
767
+ 193,
768
+ 178,
769
+ 164,
770
+ 183,
771
+ 211
772
+ ],
773
+ "22": [
774
+ 116,
775
+ 156,
776
+ 124,
777
+ 132,
778
+ 12,
779
+ 40,
780
+ 148,
781
+ 217,
782
+ 147,
783
+ 233,
784
+ 134,
785
+ 149,
786
+ 207,
787
+ 165,
788
+ 109,
789
+ 172,
790
+ 205,
791
+ 126,
792
+ 137,
793
+ 250,
794
+ 190,
795
+ 242,
796
+ 234,
797
+ 65,
798
+ 77,
799
+ 182,
800
+ 184,
801
+ 163,
802
+ 135,
803
+ 146,
804
+ 160,
805
+ 108
806
+ ],
807
+ "23": [
808
+ 60,
809
+ 204,
810
+ 141,
811
+ 32,
812
+ 44,
813
+ 223,
814
+ 222,
815
+ 107,
816
+ 37,
817
+ 63,
818
+ 213,
819
+ 134,
820
+ 193,
821
+ 142,
822
+ 220,
823
+ 218,
824
+ 15,
825
+ 10,
826
+ 130,
827
+ 61,
828
+ 153,
829
+ 230,
830
+ 139,
831
+ 143,
832
+ 121,
833
+ 59,
834
+ 20,
835
+ 64,
836
+ 162,
837
+ 80,
838
+ 117,
839
+ 170
840
+ ],
841
+ "24": [
842
+ 1,
843
+ 116,
844
+ 163,
845
+ 176,
846
+ 250,
847
+ 157,
848
+ 55,
849
+ 143,
850
+ 244,
851
+ 39,
852
+ 50,
853
+ 166,
854
+ 68,
855
+ 10,
856
+ 137,
857
+ 196,
858
+ 161,
859
+ 2,
860
+ 211,
861
+ 38,
862
+ 199,
863
+ 167,
864
+ 14,
865
+ 67,
866
+ 21,
867
+ 158,
868
+ 186,
869
+ 93,
870
+ 238,
871
+ 217,
872
+ 240,
873
+ 99
874
+ ],
875
+ "25": [
876
+ 93,
877
+ 145,
878
+ 165,
879
+ 45,
880
+ 208,
881
+ 42,
882
+ 219,
883
+ 212,
884
+ 14,
885
+ 0,
886
+ 47,
887
+ 101,
888
+ 183,
889
+ 202,
890
+ 83,
891
+ 252,
892
+ 166,
893
+ 120,
894
+ 100,
895
+ 232,
896
+ 151,
897
+ 180,
898
+ 155,
899
+ 203,
900
+ 248,
901
+ 58,
902
+ 251,
903
+ 34,
904
+ 170,
905
+ 66,
906
+ 243,
907
+ 233
908
+ ],
909
+ "26": [
910
+ 166,
911
+ 204,
912
+ 214,
913
+ 132,
914
+ 194,
915
+ 90,
916
+ 73,
917
+ 202,
918
+ 44,
919
+ 248,
920
+ 54,
921
+ 96,
922
+ 164,
923
+ 67,
924
+ 137,
925
+ 17,
926
+ 64,
927
+ 165,
928
+ 21,
929
+ 117,
930
+ 253,
931
+ 189,
932
+ 78,
933
+ 88,
934
+ 163,
935
+ 113,
936
+ 225,
937
+ 198,
938
+ 38,
939
+ 115,
940
+ 179,
941
+ 94
942
+ ],
943
+ "27": [
944
+ 147,
945
+ 139,
946
+ 98,
947
+ 206,
948
+ 12,
949
+ 18,
950
+ 114,
951
+ 169,
952
+ 14,
953
+ 85,
954
+ 1,
955
+ 28,
956
+ 50,
957
+ 242,
958
+ 170,
959
+ 182,
960
+ 240,
961
+ 228,
962
+ 235,
963
+ 195,
964
+ 145,
965
+ 215,
966
+ 134,
967
+ 3,
968
+ 99,
969
+ 70,
970
+ 238,
971
+ 74,
972
+ 183,
973
+ 150,
974
+ 190,
975
+ 103
976
+ ],
977
+ "28": [
978
+ 72,
979
+ 152,
980
+ 247,
981
+ 183,
982
+ 191,
983
+ 56,
984
+ 130,
985
+ 59,
986
+ 117,
987
+ 234,
988
+ 172,
989
+ 28,
990
+ 155,
991
+ 112,
992
+ 228,
993
+ 104,
994
+ 74,
995
+ 165,
996
+ 35,
997
+ 252,
998
+ 116,
999
+ 171,
1000
+ 230,
1001
+ 53,
1002
+ 166,
1003
+ 37,
1004
+ 179,
1005
+ 54,
1006
+ 210,
1007
+ 80,
1008
+ 212,
1009
+ 238
1010
+ ],
1011
+ "29": [
1012
+ 89,
1013
+ 1,
1014
+ 38,
1015
+ 69,
1016
+ 185,
1017
+ 19,
1018
+ 125,
1019
+ 248,
1020
+ 98,
1021
+ 152,
1022
+ 100,
1023
+ 222,
1024
+ 117,
1025
+ 9,
1026
+ 4,
1027
+ 54,
1028
+ 204,
1029
+ 91,
1030
+ 209,
1031
+ 140,
1032
+ 44,
1033
+ 233,
1034
+ 167,
1035
+ 155,
1036
+ 238,
1037
+ 219,
1038
+ 79,
1039
+ 192,
1040
+ 21,
1041
+ 58,
1042
+ 150,
1043
+ 236
1044
+ ]
1045
+ },
1046
+ "full_attn_idxs": null,
1047
+ "hidden_size": 2048,
1048
+ "initializer_range": 0.02,
1049
+ "intermediate_size": 10752,
1050
+ "layer_types": [
1051
+ "conv",
1052
+ "conv",
1053
+ "full_attention",
1054
+ "conv",
1055
+ "conv",
1056
+ "full_attention",
1057
+ "conv",
1058
+ "conv",
1059
+ "conv",
1060
+ "full_attention",
1061
+ "conv",
1062
+ "conv",
1063
+ "conv",
1064
+ "full_attention",
1065
+ "conv",
1066
+ "conv",
1067
+ "conv",
1068
+ "full_attention",
1069
+ "conv",
1070
+ "conv",
1071
+ "conv",
1072
+ "full_attention",
1073
+ "conv",
1074
+ "conv",
1075
+ "full_attention",
1076
+ "conv",
1077
+ "conv",
1078
+ "full_attention",
1079
+ "conv",
1080
+ "conv"
1081
+ ],
1082
+ "load_balance_coef": 0.001,
1083
+ "max_position_embeddings": 131072,
1084
+ "model_type": "fuse3",
1085
+ "norm_eps": 1e-05,
1086
+ "num_attention_heads": 32,
1087
+ "num_augmented_layers": 30,
1088
+ "num_heads": 32,
1089
+ "num_hidden_layers": 30,
1090
+ "num_key_value_heads": 8,
1091
+ "pad_token_id": 124893,
1092
+ "rope_parameters": {
1093
+ "rope_theta": 10000000.0,
1094
+ "rope_type": "default"
1095
+ },
1096
+ "router_init_scale": -2.0,
1097
+ "swiglu_limit": 10.0,
1098
+ "tie_word_embeddings": true,
1099
+ "top_k_experts": 8,
1100
+ "transformers_version": "5.14.1",
1101
+ "use_cache": false,
1102
+ "use_pos_enc": true,
1103
+ "vocab_size": 128000
1104
+ }
fuse3_model.py ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Fuse-3 model: LFM2-2.6B host + Qwen3.6-35B-A3B coding experts.
2
+
3
+ Architecture: per-layer FFN augmentation with Qwen3.6 MoE experts.
4
+ At each augmented host layer, coding experts from Qwen3.6 are added
5
+ alongside the host's native SwiGLU FFN. A learned router decides which
6
+ experts fire.
7
+
8
+ Key design differences from Fuse-2:
9
+ - NO bridges needed: LFM2 hidden_size (2048) == Qwen3.6 expert input (2048).
10
+ Experts are 2048->512->2048, directly operating on host hidden states.
11
+ - LFM2 is NOT a Qwen model. Lfm2ForCausalLM has a hybrid conv+attention
12
+ architecture with 22 short-conv layers + 8 GQA layers.
13
+ - The augmented layer splits LFM2's forward into attention/conv + FFN,
14
+ then adds expert output as a parallel path to the dense FFN.
15
+ - expert_scale zero-init -> model starts as exact LFM2-2.6B
16
+ - Router initialized to low activation -> coding path fires rarely at first
17
+ - Frozen host, frozen experts -> only router + scale train
18
+ - use_cache = False initially (correctness first)
19
+ - Optional SwiGLU clamping (limit=10.0) for Qwen3.6 expert stability
20
+ """
21
+ from __future__ import annotations
22
+
23
+ import math
24
+ from typing import Iterator
25
+
26
+ import torch
27
+ import torch.nn as nn
28
+ import torch.nn.functional as F
29
+ from transformers import Lfm2Config, Lfm2ForCausalLM
30
+
31
+
32
+ class Fuse3Config(Lfm2Config):
33
+ """LFM2 config extended with Fuse-3 MoE coding expert parameters."""
34
+
35
+ model_type = "fuse3"
36
+
37
+ def __init__(
38
+ self,
39
+ # Expert configuration
40
+ expert_intermediate_size: int = 512, # Qwen3.6 expert intermediate
41
+ experts_per_layer: dict | None = None, # layer_idx -> list of expert IDs
42
+ num_augmented_layers: int = 0,
43
+ top_k_experts: int = 8, # Qwen3.6 uses 8 routed
44
+ # Router configuration
45
+ router_init_scale: float = -2.0, # low initial activation
46
+ load_balance_coef: float = 0.001,
47
+ # Expert stability
48
+ swiglu_limit: float = 10.0, # clamp expert activations (from fuse-2 lessons)
49
+ coding_enabled: bool = True,
50
+ # Scale
51
+ expert_scale_init: float = -5.0, # softplus(-5)≈0.007, small but active
52
+ **kwargs,
53
+ ):
54
+ super().__init__(**kwargs)
55
+ self.expert_intermediate_size = expert_intermediate_size
56
+ self.experts_per_layer = experts_per_layer or {}
57
+ self.num_augmented_layers = num_augmented_layers
58
+ self.top_k_experts = top_k_experts
59
+ self.router_init_scale = router_init_scale
60
+ self.load_balance_coef = load_balance_coef
61
+ self.swiglu_limit = swiglu_limit
62
+ self.coding_enabled = coding_enabled
63
+ self.expert_scale_init = expert_scale_init
64
+ self.use_cache = False
65
+ self.architectures = ["Fuse3ForCausalLM"]
66
+
67
+
68
+ class SwiGLUExpert(nn.Module):
69
+ """A single Qwen3.6 MoE expert (SwiGLU FFN).
70
+
71
+ gate_proj: (intermediate, hidden) — w1
72
+ up_proj: (intermediate, hidden) — w3
73
+ down_proj: (hidden, intermediate) — w2
74
+
75
+ Input: (..., hidden_size)
76
+ Output: (..., hidden_size)
77
+ """
78
+
79
+ def __init__(self, hidden_size: int, intermediate_size: int, swiglu_limit: float = 0.0):
80
+ super().__init__()
81
+ self.gate_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
82
+ self.up_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
83
+ self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
84
+ self.swiglu_limit = swiglu_limit
85
+
86
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
87
+ gate = self.gate_proj(x)
88
+ up = self.up_proj(x)
89
+ act = F.silu(gate) * up
90
+ if self.swiglu_limit > 0:
91
+ act = act.clamp(-self.swiglu_limit, self.swiglu_limit)
92
+ return self.down_proj(act)
93
+
94
+
95
+ class Fuse3Router(nn.Module):
96
+ """Per-layer router for coding experts.
97
+
98
+ Uses sqrtsoftplus scoring (matching Qwen3.5 MoE's approach) with
99
+ top-k selection and optional load balancing.
100
+ """
101
+
102
+ def __init__(
103
+ self,
104
+ input_dim: int,
105
+ num_experts: int,
106
+ top_k: int = 8,
107
+ init_scale: float = -2.0,
108
+ ):
109
+ super().__init__()
110
+ self.num_experts = num_experts
111
+ self.top_k = min(top_k, num_experts)
112
+ self.gate = nn.Linear(input_dim, num_experts, bias=False)
113
+ nn.init.normal_(self.gate.weight, mean=0.0, std=0.01)
114
+ self.init_scale = init_scale
115
+
116
+ def forward(
117
+ self,
118
+ hidden_states: torch.Tensor,
119
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
120
+ """Route tokens to experts.
121
+
122
+ Args:
123
+ hidden_states: (batch*seq, hidden_size)
124
+
125
+ Returns:
126
+ router_weights: (batch*seq, top_k) — normalized weights for selected experts
127
+ expert_indices: (batch*seq, top_k) — which experts were selected
128
+ router_logits: (batch*seq, num_experts) — raw logits for load balancing
129
+ """
130
+ logits = self.gate(hidden_states)
131
+ scores = F.softplus(logits).sqrt()
132
+ topk_weights, topk_indices = scores.topk(self.top_k, dim=-1)
133
+ topk_weights = topk_weights / (topk_weights.sum(dim=-1, keepdim=True) + 1e-8)
134
+ return topk_weights, topk_indices, logits
135
+
136
+
137
+ class Fuse3AugmentedLayer(nn.Module):
138
+ """One LFM2 layer augmented with Qwen3.6 coding experts.
139
+
140
+ Forward flow (mirrors Lfm2DecoderLayer but with MoE added to FFN):
141
+ 1. Attention or ShortConv (frozen host, same as LFM2)
142
+ 2. Dense FFN (frozen host SwiGLU)
143
+ 3. Router: select top-k coding experts from FFN input
144
+ 4. Experts: parallel SwiGLU computation (frozen, from Qwen3.6)
145
+ 5. expert_scale * expert_output added to residual
146
+ 6. No bridge needed — hidden_size matches on both sides
147
+
148
+ The model starts as exact LFM2 (expert_scale=0) and learns to
149
+ incorporate coding experts through router + scale training.
150
+ """
151
+
152
+ def __init__(
153
+ self,
154
+ host_layer: nn.Module,
155
+ hidden_size: int,
156
+ expert_intermediate: int,
157
+ num_experts: int,
158
+ top_k: int = 8,
159
+ swiglu_limit: float = 10.0,
160
+ router_init_scale: float = -2.0,
161
+ coding_enabled: bool = True,
162
+ expert_scale_init: float = 0.0,
163
+ ):
164
+ super().__init__()
165
+ self.host_layer = host_layer
166
+ self.coding_enabled = coding_enabled
167
+ self.num_experts = num_experts
168
+ self.top_k = min(top_k, num_experts)
169
+ self.hidden_size = hidden_size
170
+
171
+ # Expose host layer attributes needed by the LFM2 model forward pass
172
+ self.is_attention_layer = getattr(host_layer, "is_attention_layer", False)
173
+
174
+ # Router (operates on hidden_size directly — no bridge)
175
+ self.router = Fuse3Router(
176
+ hidden_size, num_experts, top_k, router_init_scale
177
+ )
178
+
179
+ # Experts (frozen, loaded from Qwen3.6)
180
+ self.experts = nn.ModuleList([
181
+ SwiGLUExpert(hidden_size, expert_intermediate, swiglu_limit)
182
+ for _ in range(num_experts)
183
+ ])
184
+
185
+ # Scale factor for expert output (zero-init = exact LFM2)
186
+ self.expert_scale = nn.Parameter(torch.tensor(expert_scale_init))
187
+
188
+ # Store last router logits for load balancing loss
189
+ self._last_router_logits: torch.Tensor | None = None
190
+
191
+ def forward(
192
+ self,
193
+ hidden_states: torch.Tensor,
194
+ position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
195
+ attention_mask: torch.Tensor | None = None,
196
+ position_ids: torch.LongTensor | None = None,
197
+ past_key_values=None,
198
+ cache_position: torch.LongTensor | None = None,
199
+ **kwargs,
200
+ ) -> torch.Tensor:
201
+ # ── 1. Run the original host layer (attention/conv + FFN) ──
202
+ # This delegates to the original Lfm2DecoderLayer.forward, ensuring
203
+ # perfect compatibility with the host model's conv/attention impl.
204
+ layer_output = self.host_layer(
205
+ hidden_states,
206
+ position_embeddings=position_embeddings,
207
+ attention_mask=attention_mask,
208
+ position_ids=position_ids,
209
+ past_key_values=past_key_values,
210
+ cache_position=cache_position,
211
+ **kwargs,
212
+ )
213
+
214
+ # If coding disabled or no experts, return original output unchanged
215
+ if not self.coding_enabled or self.num_experts == 0:
216
+ return layer_output
217
+
218
+ # ── 2. Always run router (for load balancing gradients) ──
219
+ original_shape = layer_output.shape
220
+ h_flat = layer_output.reshape(-1, original_shape[-1])
221
+
222
+ topk_weights, expert_indices, router_logits = self.router(h_flat)
223
+ self._last_router_logits = router_logits
224
+
225
+ # Skip expert computation if scale is effectively zero
226
+ # (router still ran, so LB loss gradients flow)
227
+ scale = F.softplus(self.expert_scale)
228
+ if scale.item() < 1e-4:
229
+ return layer_output
230
+
231
+ # ── 3. Compute expert outputs (sparse) ──
232
+ # Detach expert inputs/outputs — experts are frozen, so no gradients
233
+ # need to flow through the expert weights. Gradients only flow through
234
+ # topk_weights (router) and scale (expert_scale).
235
+ # Use index_add (out-of-place) to avoid in-place op autograd issues.
236
+ expert_output = torch.zeros_like(h_flat)
237
+
238
+ for k in range(self.top_k):
239
+ indices = expert_indices[:, k]
240
+ weights = topk_weights[:, k]
241
+
242
+ for eid in range(self.num_experts):
243
+ token_mask = indices == eid
244
+ if not token_mask.any():
245
+ continue
246
+ expert_in = h_flat[token_mask].detach()
247
+ expert_out = self.experts[eid](expert_in).detach()
248
+ weighted_out = weights[token_mask].unsqueeze(-1) * expert_out
249
+ token_indices = torch.where(token_mask)[0]
250
+ expert_output = expert_output.index_add(
251
+ 0, token_indices, weighted_out
252
+ )
253
+
254
+ # ── 4. Normalize expert output to match host activation scale ──
255
+ # The experts come from Qwen3.6 which has different activation
256
+ # distributions. Rescale to match host std, but clamp the ratio
257
+ # to prevent amplification of sparse outputs.
258
+ host_std = layer_output.std().detach() + 1e-6
259
+ expert_std = expert_output.std().detach() + 1e-6
260
+ ratio = torch.clamp(host_std / expert_std, max=2.0)
261
+ expert_output = expert_output * ratio
262
+
263
+ # ── 5. Scale and add to residual ──
264
+ # Clamp scale to prevent runaway
265
+ scale = torch.clamp(scale, max=0.1)
266
+ expert_delta = scale * expert_output
267
+ expert_delta = expert_delta.reshape(original_shape)
268
+
269
+ return layer_output + expert_delta
270
+
271
+ def get_router_logits(self) -> torch.Tensor | None:
272
+ return self._last_router_logits
273
+
274
+
275
+ class Fuse3ForCausalLM(Lfm2ForCausalLM):
276
+ """LFM2-2.6B host + Qwen3.6-35B-A3B coding experts.
277
+
278
+ The model starts as an exact LFM2-2.6B (expert_scale=0) and learns
279
+ to incorporate coding experts through router and scale training.
280
+ """
281
+
282
+ config_class = Fuse3Config
283
+ _no_split_modules = ["Lfm2DecoderLayer", "Fuse3AugmentedLayer"]
284
+
285
+ def __init__(self, config: Fuse3Config):
286
+ super().__init__(config)
287
+
288
+ # Replace specified layers with augmented versions
289
+ experts_per_layer = config.experts_per_layer or {}
290
+ augmented_count = 0
291
+
292
+ for layer_idx_str, expert_ids in experts_per_layer.items():
293
+ layer_idx = int(layer_idx_str)
294
+ if layer_idx >= len(self.model.layers):
295
+ raise ValueError(
296
+ f"Layer {layer_idx} out of range "
297
+ f"(model has {len(self.model.layers)} layers)"
298
+ )
299
+
300
+ num_experts = len(expert_ids)
301
+ if num_experts == 0:
302
+ continue
303
+
304
+ original_layer = self.model.layers[layer_idx]
305
+ self.model.layers[layer_idx] = Fuse3AugmentedLayer(
306
+ host_layer=original_layer,
307
+ hidden_size=config.hidden_size,
308
+ expert_intermediate=config.expert_intermediate_size,
309
+ num_experts=num_experts,
310
+ top_k=min(config.top_k_experts, num_experts),
311
+ swiglu_limit=config.swiglu_limit,
312
+ router_init_scale=config.router_init_scale,
313
+ coding_enabled=config.coding_enabled,
314
+ expert_scale_init=config.expert_scale_init,
315
+ )
316
+ augmented_count += 1
317
+
318
+ config.num_augmented_layers = augmented_count
319
+
320
+ def set_coding_enabled(self, enabled: bool) -> None:
321
+ for layer in self.model.layers:
322
+ if isinstance(layer, Fuse3AugmentedLayer):
323
+ layer.coding_enabled = enabled
324
+
325
+ def get_augmented_layers(self) -> list[tuple[int, Fuse3AugmentedLayer]]:
326
+ return [
327
+ (i, layer)
328
+ for i, layer in enumerate(self.model.layers)
329
+ if isinstance(layer, Fuse3AugmentedLayer)
330
+ ]
331
+
332
+ def get_trainable_params(self) -> dict[str, nn.Parameter]:
333
+ trainable = {}
334
+ for name, param in self.named_parameters():
335
+ if any(key in name for key in ("router", "expert_scale")):
336
+ trainable[name] = param
337
+ return trainable
338
+
339
+ def freeze_host_and_experts(self) -> None:
340
+ for name, param in self.named_parameters():
341
+ if any(key in name for key in ("router", "expert_scale")):
342
+ param.requires_grad = True
343
+ else:
344
+ param.requires_grad = False
345
+
346
+ def get_all_router_logits(self) -> list[torch.Tensor]:
347
+ """Collect router logits from all augmented layers after forward pass."""
348
+ logits = []
349
+ for layer in self.model.layers:
350
+ if hasattr(layer, '_last_router_logits') and layer._last_router_logits is not None:
351
+ logits.append(layer._last_router_logits)
352
+ return logits
353
+
354
+ def get_expert_scales(self) -> list[float]:
355
+ """Get current effective expert scale (softplus) from all augmented layers."""
356
+ import torch.nn.functional as F
357
+ scales = []
358
+ for layer in self.model.layers:
359
+ if hasattr(layer, 'expert_scale'):
360
+ scales.append(F.softplus(layer.expert_scale).item())
361
+ return scales
362
+
363
+ def reset_router_logits(self) -> None:
364
+ """Clear stored router logits (call before each forward pass during training)."""
365
+ for layer in self.model.layers:
366
+ if hasattr(layer, '_last_router_logits'):
367
+ layer._last_router_logits = None
368
+
369
+ def count_parameters(self) -> dict[str, int]:
370
+ counts = {
371
+ "host": 0, "experts": 0, "routers": 0, "scale": 0,
372
+ "total": 0, "trainable": 0,
373
+ }
374
+ for name, param in self.named_parameters():
375
+ n = param.numel()
376
+ counts["total"] += n
377
+ if param.requires_grad:
378
+ counts["trainable"] += n
379
+ if "router" in name:
380
+ counts["routers"] += n
381
+ elif "expert_scale" in name:
382
+ counts["scale"] += n
383
+ elif "experts" in name:
384
+ counts["experts"] += n
385
+ else:
386
+ counts["host"] += n
387
+ return counts
388
+
389
+ def forward(
390
+ self,
391
+ input_ids: torch.LongTensor | None = None,
392
+ attention_mask: torch.Tensor | None = None,
393
+ position_ids: torch.LongTensor | None = None,
394
+ past_key_values=None,
395
+ inputs_embeds: torch.FloatTensor | None = None,
396
+ labels: torch.LongTensor | None = None,
397
+ use_cache: bool | None = None,
398
+ **kwargs,
399
+ ):
400
+ # Delegate to Lfm2ForCausalLM.forward with original args.
401
+ # The augmented layers handle expert computation internally;
402
+ # KV cache works because Fuse3AugmentedLayer delegates to the
403
+ # original host layer's forward for attention/conv.
404
+ return super().forward(
405
+ input_ids=input_ids,
406
+ attention_mask=attention_mask,
407
+ position_ids=position_ids,
408
+ past_key_values=past_key_values,
409
+ inputs_embeds=inputs_embeds,
410
+ labels=labels,
411
+ use_cache=use_cache,
412
+ **kwargs,
413
+ )
414
+
415
+
416
+ def load_expert_weights(
417
+ model: Fuse3ForCausalLM,
418
+ expert_dir: str,
419
+ expert_mapping: dict[int, list[int]],
420
+ ) -> dict:
421
+ """Load extracted Qwen3.6 expert weights into the Fuse3 model.
422
+
423
+ Args:
424
+ model: Fuse3 model with augmented layers
425
+ expert_dir: directory containing expert safetensors
426
+ expert_mapping: layer_idx -> list of expert IDs (matching selection order)
427
+
428
+ Returns:
429
+ Manifest of loaded tensors with hash verification
430
+ """
431
+ from safetensors.torch import load_file
432
+ import glob
433
+
434
+ shard_files = sorted(glob.glob(f"{expert_dir}/experts-*.safetensors"))
435
+ if not shard_files:
436
+ raise FileNotFoundError(f"No expert shards found in {expert_dir}")
437
+
438
+ all_tensors = {}
439
+ for shard in shard_files:
440
+ all_tensors.update(load_file(shard))
441
+
442
+ loaded = {}
443
+ for layer_idx, expert_ids in expert_mapping.items():
444
+ if layer_idx >= len(model.model.layers):
445
+ continue # skip out-of-range layers
446
+ augmented = model.model.layers[layer_idx]
447
+ if not isinstance(augmented, Fuse3AugmentedLayer):
448
+ continue # skip non-augmented layers
449
+
450
+ for local_idx, global_eid in enumerate(expert_ids):
451
+ prefix = f"layer{layer_idx:02d}_expert{global_eid:03d}"
452
+
453
+ for pname in ("gate_proj.weight", "up_proj.weight", "down_proj.weight"):
454
+ key = f"{prefix}.{pname}"
455
+ if key not in all_tensors:
456
+ raise KeyError(f"Missing expert tensor: {key}")
457
+
458
+ tensor = all_tensors[key]
459
+ parts = pname.split(".")
460
+ module = augmented.experts[local_idx]
461
+ for part in parts[:-1]:
462
+ module = getattr(module, part)
463
+ param = getattr(module, parts[-1])
464
+ param.data.copy_(tensor.to(param.dtype))
465
+
466
+ loaded[key] = {
467
+ "shape": list(tensor.shape),
468
+ "destination": f"layers.{layer_idx}.experts.{local_idx}.{pname}",
469
+ }
470
+
471
+ return loaded
generation_config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 124894,
4
+ "do_sample": true,
5
+ "eos_token_id": [
6
+ 124900
7
+ ],
8
+ "output_attentions": false,
9
+ "output_hidden_states": false,
10
+ "pad_token_id": 124893,
11
+ "repetition_penalty": 1.1,
12
+ "temperature": 0.1,
13
+ "top_k": 50,
14
+ "transformers_version": "5.14.1",
15
+ "use_cache": true
16
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:233662cf2cbf7a93b6fdbf60068de0d8f122c51f0f36147a2319a597f2e99d56
3
+ size 11438511844
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0b124e06b0d81002864892c3ebb866effe115aa1d5fbe8e6e9e23254655354a8
3
+ size 17905696
tokenizer_config.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|startoftext|>",
4
+ "clean_up_tokenization_spaces": false,
5
+ "eos_token": "<|im_end|>",
6
+ "is_local": false,
7
+ "legacy": false,
8
+ "local_files_only": false,
9
+ "model_max_length": 1000000000000000019884624838656,
10
+ "pad_token": "<|pad|>",
11
+ "tokenizer_class": "TokenizersBackend",
12
+ "use_default_system_prompt": false
13
+ }