zhan1206 commited on
Commit
b12f6c3
·
1 Parent(s): 04c7011

Feat: Add actual training (100 steps) + documentation (tutorial + API)

Browse files
Files changed (4) hide show
  1. data/prepare_training_data.py +110 -0
  2. docs/API.md +679 -0
  3. docs/tutorial.md +356 -0
  4. train/train_real.py +212 -0
data/prepare_training_data.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 创建伪真实训练数据(用于实际模型训练)
3
+ 使用简单的英文句子作为训练数据
4
+ """
5
+ import os
6
+ import torch
7
+ from pathlib import Path
8
+
9
+ def create_training_data():
10
+ """创建训练数据"""
11
+ print("[DATA] 创建训练数据...")
12
+
13
+ # 简单的英文句子(用于训练)
14
+ sentences = [
15
+ "The cat sits on the mat.",
16
+ "A dog runs in the park.",
17
+ "Birds fly in the sky.",
18
+ "Fish swim in the sea.",
19
+ "Children play in the garden.",
20
+ "The sun is shining brightly.",
21
+ "It is raining heavily today.",
22
+ "Snow falls in winter.",
23
+ "Flowers bloom in spring.",
24
+ "Leaves fall in autumn.",
25
+ "I love reading books.",
26
+ "She writes a letter.",
27
+ "He cooks dinner for us.",
28
+ "We watch a movie together.",
29
+ "They sing a beautiful song.",
30
+ "The car moves fast on the road.",
31
+ "A plane flies in the air.",
32
+ "Ships sail on the ocean.",
33
+ "Trains travel across the country.",
34
+ "Bicycles are good for health.",
35
+ "Apple is a delicious fruit.",
36
+ "Water is essential for life.",
37
+ "The house has a big garden.",
38
+ "Music brings joy to people.",
39
+ "Learning is a lifelong journey.",
40
+ ]
41
+
42
+ # 重复句子以增加数据量
43
+ all_sentences = sentences * 10 # 250 个句子
44
+
45
+ # 保存到文件
46
+ data_path = Path("data/training_data.txt")
47
+ data_path.parent.mkdir(exist_ok=True)
48
+
49
+ with open(data_path, "w", encoding="utf-8") as f:
50
+ for sentence in all_sentences:
51
+ f.write(sentence + "\n")
52
+
53
+ print(f" 保存路径: {data_path}")
54
+ print(f" 句子数量: {len(all_sentences)}")
55
+ print(" 训练数据创建成功")
56
+ print()
57
+
58
+ return data_path
59
+
60
+
61
+ def create_tokenizer_from_data(data_path):
62
+ """从训练数据创建 tokenizer"""
63
+ print("[TOKENIZER] 创建 tokenizer...")
64
+
65
+ # 简单字符级 tokenizer(用于演示)
66
+ # 在实际应用中,应该使用 SentencePiece 或 BPE
67
+
68
+ # 读取所有文本
69
+ with open(data_path, "r", encoding="utf-8") as f:
70
+ text = f.read()
71
+
72
+ # 创建字符词汇表
73
+ chars = sorted(list(set(text)))
74
+ vocab_size = len(chars) + 3 # +3 for [PAD], [UNK], [CLS]
75
+
76
+ # 保存词汇表
77
+ vocab_path = Path("tokenizers/char_vocab.txt")
78
+ vocab_path.parent.mkdir(exist_ok=True)
79
+
80
+ with open(vocab_path, "w", encoding="utf-8") as f:
81
+ f.write("[PAD]\n")
82
+ f.write("[UNK]\n")
83
+ f.write("[CLS]\n")
84
+ for char in chars:
85
+ f.write(char + "\n")
86
+
87
+ print(f" 词汇表大小: {vocab_size}")
88
+ print(f" 保存路径: {vocab_path}")
89
+ print(" Tokenizer 创建成功")
90
+ print()
91
+
92
+ return vocab_path, vocab_size
93
+
94
+
95
+ if __name__ == "__main__":
96
+ print("=" * 60)
97
+ print("Fusion-LLM 创建训练数据")
98
+ print("=" * 60)
99
+ print()
100
+
101
+ # 1. 创建训练数据
102
+ data_path = create_training_data()
103
+
104
+ # 2. 创建 tokenizer
105
+ vocab_path, vocab_size = create_tokenizer_from_data(data_path)
106
+
107
+ print("[DONE] 训练数据准备完成")
108
+ print(f" 训练数据: {data_path}")
109
+ print(f" Tokenizer: {vocab_path}")
110
+ print(f" 词汇表大小: {vocab_size}")
docs/API.md ADDED
@@ -0,0 +1,679 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Fusion-LLM API 文档
2
+
3
+ ## 模型 API
4
+
5
+ ### FusionMini
6
+
7
+ `FusionMini` 是 Fusion-LLM 的迷你模型实现。
8
+
9
+ #### 类定义
10
+
11
+ ```python
12
+ class FusionMini(nn.Module):
13
+ """
14
+ Fusion-LLM 迷你模型
15
+
16
+ Args:
17
+ config (FusionMiniConfig): 模型配置
18
+ """
19
+ ```
20
+
21
+ #### 方法
22
+
23
+ ##### `__init__(config)`
24
+
25
+ 初始化 FusionMini 模型。
26
+
27
+ **参数**:
28
+ - `config` (FusionMiniConfig): 模型配置对象
29
+
30
+ **示例**:
31
+ ```python
32
+ from models.fusion_mini import FusionMini, FusionMiniConfig
33
+
34
+ config = FusionMiniConfig(
35
+ vocab_size=1000,
36
+ hidden_size=128,
37
+ num_hidden_layers=2,
38
+ )
39
+ model = FusionMini(config)
40
+ ```
41
+
42
+ ##### `forward(input_ids, attention_mask=None, labels=None, past_key_values=None, use_cache=False, return_dict=True)`
43
+
44
+ 模型前向传播。
45
+
46
+ **参数**:
47
+ - `input_ids` (torch.Tensor): 输入 token IDs,形状为 `(batch_size, sequence_length)`
48
+ - `attention_mask` (torch.Tensor, optional): 注意力掩码,形状为 `(batch_size, sequence_length)`
49
+ - `labels` (torch.Tensor, optional): 标签,形状为 `(batch_size, sequence_length)`
50
+ - `past_key_values` (tuple, optional): 过去的键值缓存
51
+ - `use_cache` (bool): 是否使用 KV 缓存
52
+ - `return_dict` (bool): 是否返回字典格式
53
+
54
+ **返回**:
55
+ - 如果 `return_dict=True`:返回字典,包含:
56
+ - `loss` (torch.Tensor): 损失值(如果提供了 labels)
57
+ - `logits` (torch.Tensor): 逻辑值,形状为 `(batch_size, sequence_length, vocab_size)`
58
+ - `past_key_values` (tuple): 更新的键值缓存(如果 `use_cache=True`)
59
+ - 如果 `return_dict=False`:返回元组
60
+
61
+ **示例**:
62
+ ```python
63
+ # 训练模式
64
+ outputs = model(
65
+ input_ids=input_ids,
66
+ labels=labels,
67
+ return_dict=True,
68
+ )
69
+ loss = outputs["loss"]
70
+ logits = outputs["logits"]
71
+
72
+ # 推理模式(使用 KV 缓存)
73
+ outputs = model(
74
+ input_ids=input_ids,
75
+ use_cache=True,
76
+ return_dict=True,
77
+ )
78
+ logits = outputs["logits"]
79
+ past_key_values = outputs["past_key_values"]
80
+ ```
81
+
82
+ ##### `generate(input_ids, max_length=50, temperature=1.0, top_k=50, top_p=0.95)`
83
+
84
+ 生成文本(简易接口)。
85
+
86
+ **参数**:
87
+ - `input_ids` (torch.Tensor): 输入 token IDs
88
+ - `max_length` (int): 最大生成长度
89
+ - `temperature` (float): 温度参数
90
+ - `top_k` (int): Top-K 采样参数
91
+ - `top_p` (float): Top-P 采样参数
92
+
93
+ **返回**:
94
+ - `torch.Tensor`: 生成的 token IDs
95
+
96
+ **示例**:
97
+ ```python
98
+ generated = model.generate(
99
+ input_ids=input_ids,
100
+ max_length=50,
101
+ temperature=0.8,
102
+ )
103
+ ```
104
+
105
+ ##### `save_pretrained(save_directory)`
106
+
107
+ 保存模型和配置。
108
+
109
+ **参数**:
110
+ - `save_directory` (str): 保存目录
111
+
112
+ **示例**:
113
+ ```python
114
+ model.save_pretrained("output/my_model")
115
+ ```
116
+
117
+ ##### `from_pretrained(pretrained_model_name_or_path)`
118
+
119
+ 从预训练路径加载模型。
120
+
121
+ **参数**:
122
+ - `pretrained_model_name_or_path` (str): 预训练模型路径
123
+
124
+ **返回**:
125
+ - `FusionMini`: 加载的模型
126
+
127
+ **示例**:
128
+ ```python
129
+ model = FusionMini.from_pretrained("output/my_model")
130
+ ```
131
+
132
+ ---
133
+
134
+ ### FusionMiniConfig
135
+
136
+ `FusionMiniConfig` 是 FusionMini 模型的配置类。
137
+
138
+ #### 类定义
139
+
140
+ ```python
141
+ class FusionMiniConfig(PretrainedConfig):
142
+ """
143
+ FusionMini 模型配置
144
+
145
+ Args:
146
+ vocab_size (int): 词汇表大小
147
+ hidden_size (int): 隐藏层大小
148
+ num_hidden_layers (int): 隐藏层数量
149
+ num_attention_heads (int): 注意力头数量
150
+ intermediate_size (int): 中间层大小
151
+ max_position_embeddings (int): 最大位置编码
152
+ num_key_value_heads (int, optional): KV 头数量(用于 GQA)
153
+ window_size (int, optional): SBLA 窗口大小
154
+ ...
155
+ """
156
+ ```
157
+
158
+ #### 属性
159
+
160
+ | 属性 | 类型 | 默认值 | 描述 |
161
+ |------|------|--------|------|
162
+ | `vocab_size` | int | 50257 | 词汇表大小 |
163
+ | `hidden_size` | int | 768 | 隐藏层大小 |
164
+ | `num_hidden_layers` | int | 12 | 隐藏层数量 |
165
+ | `num_attention_heads` | int | 12 | 注意力头数量 |
166
+ | `intermediate_size` | int | 3072 | 中间层大小 |
167
+ | `max_position_embeddings` | int | 1024 | 最大位置编码 |
168
+ | `num_key_value_heads` | int | None | KV 头数量(GQA) |
169
+ | `window_size` | int | 16 | SBLA 窗口大小 |
170
+
171
+ #### 方法
172
+
173
+ ##### `__init__(**kwargs)`
174
+
175
+ 初始化配置。
176
+
177
+ **示例**:
178
+ ```python
179
+ config = FusionMiniConfig(
180
+ vocab_size=1000,
181
+ hidden_size=128,
182
+ num_hidden_layers=2,
183
+ num_attention_heads=2,
184
+ )
185
+ ```
186
+
187
+ ---
188
+
189
+ ## 注意力 API
190
+
191
+ ### SBLAttention
192
+
193
+ `SBLAttention` 是 SBLA(Sliding Block Latent Attention)注意力实现。
194
+
195
+ #### 类定义
196
+
197
+ ```python
198
+ class SBLAttention(nn.Module):
199
+ """
200
+ SBLA 注意力层
201
+
202
+ Args:
203
+ hidden_size (int): 隐藏层大小
204
+ num_heads (int): 注意力头数量
205
+ window_size (int): 窗口大小
206
+ num_key_value_heads (int, optional): KV 头数量(用于 GQA)
207
+ """
208
+ ```
209
+
210
+ #### 方法
211
+
212
+ ##### `__init__(hidden_size, num_heads, window_size, num_key_value_heads=None)`
213
+
214
+ 初始化 SBLA 注意力层。
215
+
216
+ ##### `forward(hidden_states, attention_mask=None, past_key_value=None, use_cache=False, output_attentions=False)`
217
+
218
+ 前向传播。
219
+
220
+ **参数**:
221
+ - `hidden_states` (torch.Tensor): 隐藏状态,形状为 `(batch_size, sequence_length, hidden_size)`
222
+ - `attention_mask` (torch.Tensor, optional): 注意力掩码
223
+ - `past_key_value` (tuple, optional): 过去的键值缓存
224
+ - `use_cache` (bool): 是否使用 KV 缓存
225
+ - `output_attentions` (bool): 是否输出注意力权重
226
+
227
+ **返回**:
228
+ - `tuple`: (output, past_key_value, attentions)
229
+
230
+ **示例**:
231
+ ```python
232
+ from models.sbla_attention import SBLAttention
233
+
234
+ attention = SBLAttention(
235
+ hidden_size=128,
236
+ num_heads=2,
237
+ window_size=16,
238
+ )
239
+
240
+ hidden_states = torch.randn(1, 32, 128)
241
+ output, past_key_value, _ = attention(hidden_states)
242
+ print(output.shape) # torch.Size([1, 32, 128])
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Thinking Dial API
248
+
249
+ ### ThinkingDialProcessor
250
+
251
+ `ThinkingDialProcessor` 是 Thinking Dial(动态推理强度控制)处理器。
252
+
253
+ #### 类定义
254
+
255
+ ```python
256
+ class ThinkingDialProcessor:
257
+ """
258
+ Thinking Dial 处理器
259
+
260
+ 用于处理 think token,动态控制推理强度。
261
+ """
262
+ ```
263
+
264
+ #### 方法
265
+
266
+ ##### `process(text)`
267
+
268
+ 处理文本,注入 think token。
269
+
270
+ **参数**:
271
+ - `text` (str): 输入文本(可能包含 `<|think_depth_N|>`)
272
+
273
+ **返回**:
274
+ - `str`: 处理后的文本
275
+
276
+ **示例**:
277
+ ```python
278
+ from models.thinking_dial import ThinkingDialProcessor
279
+
280
+ processor = ThinkingDialProcessor()
281
+
282
+ text = "<|think_depth_2|> 这是一个需要深入思考的问题。"
283
+ processed_text = processor.process(text)
284
+ print(processed_text) # 处理后的文本
285
+ ```
286
+
287
+ ##### `get_think_depth(text)`
288
+
289
+ 获取 think token 的深度。
290
+
291
+ **参数**:
292
+ - `text` (str): 输入文本
293
+
294
+ **返回**:
295
+ - `int`: think 深度(0-3)
296
+
297
+ **示例**:
298
+ ```python
299
+ depth = processor.get_think_depth(text)
300
+ print(depth) # 2
301
+ ```
302
+
303
+ ---
304
+
305
+ ## 量化 API
306
+
307
+ ### DyQuant
308
+
309
+ `DyQuant` 是动态混合精度量化器(4/8/16-bit)。
310
+
311
+ #### 类定义
312
+
313
+ ```python
314
+ class DyQuant:
315
+ """
316
+ 动态混合精度量化器
317
+
318
+ 支持 4-bit、8-bit、16-bit 量化。
319
+ """
320
+ ```
321
+
322
+ #### 方法
323
+
324
+ ##### `quantize(model, bits=8)`
325
+
326
+ 量化模型。
327
+
328
+ **参数**:
329
+ - `model` (nn.Module): 要量化的模型
330
+ - `bits` (int): 量化位数(4/8/16)
331
+
332
+ **返回**:
333
+ - `nn.Module`: 量化后的模型
334
+
335
+ **示例**:
336
+ ```python
337
+ from inference.dyquant import DyQuant
338
+
339
+ quantizer = DyQuant()
340
+ quantized_model = quantizer.quantize(model, bits=8)
341
+ ```
342
+
343
+ ##### `save(model, path)`
344
+
345
+ 保存量化模型。
346
+
347
+ **参数**:
348
+ - `model` (nn.Module): 量化模型
349
+ - `path` (str): 保存路径
350
+
351
+ **示例**:
352
+ ```python
353
+ quantizer.save(quantized_model, "output/quantized_model")
354
+ ```
355
+
356
+ ##### `load(path)`
357
+
358
+ 加载量化模型。
359
+
360
+ **参数**:
361
+ - `path` (str): 模型路径
362
+
363
+ **返回**:
364
+ - `nn.Module`: 加载的量化模型
365
+
366
+ **示例**:
367
+ ```python
368
+ loaded_model = quantizer.load("output/quantized_model")
369
+ ```
370
+
371
+ ---
372
+
373
+ ## 训练 API
374
+
375
+ ### FullFinetuner
376
+
377
+ `FullFinetuner` 是全量微调器。
378
+
379
+ #### 类定义
380
+
381
+ ```python
382
+ class FullFinetuner:
383
+ """
384
+ 全量微调器
385
+
386
+ 用于全量微调 Fusion-LLM 模型。
387
+ """
388
+ ```
389
+
390
+ #### 方法
391
+
392
+ ##### `train(model, train_dataset, eval_dataset=None, num_epochs=3, batch_size=4)`
393
+
394
+ 训练模型。
395
+
396
+ **参数**:
397
+ - `model` (nn.Module): 要训练的模型
398
+ - `train_dataset` (Dataset): 训练数据集
399
+ - `eval_dataset` (Dataset, optional): 评估数据集
400
+ - `num_epochs` (int): 训练轮数
401
+ - `batch_size` (int): 批次大小
402
+
403
+ **示例**:
404
+ ```python
405
+ from train.full_finetune import FullFinetuner
406
+
407
+ finetuner = FullFinetuner()
408
+
409
+ finetuner.train(
410
+ model=model,
411
+ train_dataset=train_dataset,
412
+ eval_dataset=eval_dataset,
413
+ num_epochs=3,
414
+ batch_size=4,
415
+ )
416
+ ```
417
+
418
+ ---
419
+
420
+ ## 评估 API
421
+
422
+ ### ModelEvaluator
423
+
424
+ `ModelEvaluator` 是模型评估器。
425
+
426
+ #### 类定义
427
+
428
+ ```python
429
+ class ModelEvaluator:
430
+ """
431
+ 模型评估器
432
+
433
+ 用于评估模型性能(Perplexity、Loss、Accuracy 等)。
434
+ """
435
+ ```
436
+
437
+ #### 方法
438
+
439
+ ##### `evaluate(model, eval_data, metrics=["perplexity", "loss", "accuracy"])`
440
+
441
+ 评估模型。
442
+
443
+ **参数**:
444
+ - `model` (nn.Module): 要评估的模型
445
+ - `eval_data` (Dataset): 评估数据集
446
+ - `metrics` (List[str]): 评估指标列表
447
+
448
+ **返回**:
449
+ - `EvaluationMetrics`: 评估结果
450
+
451
+ **示例**:
452
+ ```python
453
+ from evaluation.metrics import ModelEvaluator
454
+
455
+ evaluator = ModelEvaluator()
456
+
457
+ metrics = evaluator.evaluate(
458
+ model=model,
459
+ eval_data=eval_dataset,
460
+ metrics=["perplexity", "loss", "accuracy"],
461
+ )
462
+
463
+ print(f"Perplexity: {metrics.perplexity:.2f}")
464
+ print(f"Loss: {metrics.loss:.4f}")
465
+ print(f"Accuracy: {metrics.accuracy:.4f}")
466
+ ```
467
+
468
+ ---
469
+
470
+ ## 部署 API
471
+
472
+ ### OllamaDeployer
473
+
474
+ `OllamaDeployer` 是 Ollama 部署器。
475
+
476
+ #### 类定义
477
+
478
+ ```python
479
+ class OllamaDeployer:
480
+ """
481
+ Ollama 部署器
482
+
483
+ 用于将 Fusion-LLM 模型部署到 Ollama。
484
+ """
485
+ ```
486
+
487
+ #### 方法
488
+
489
+ ##### `deploy(model_path, output_path)`
490
+
491
+ 部署模型到 Ollama。
492
+
493
+ **参数**:
494
+ - `model_path` (str): 模型路径
495
+ - `output_path` (str): 输出路径
496
+
497
+ **示例**:
498
+ ```python
499
+ from inference.ollama_deploy_v2 import OllamaDeployer
500
+
501
+ deployer = OllamaDeployer()
502
+
503
+ deployer.deploy(
504
+ model_path="output/real_model",
505
+ output_path="output/ollama_model",
506
+ )
507
+ ```
508
+
509
+ ---
510
+
511
+ ## 数据集 API
512
+
513
+ ### TextDataset
514
+
515
+ `TextDataset` 是文本数据集。
516
+
517
+ #### 类定义
518
+
519
+ ```python
520
+ class TextDataset(Dataset):
521
+ """
522
+ 文本数据集
523
+
524
+ 用于加载文本数据并进行编码。
525
+ """
526
+ ```
527
+
528
+ #### 方法
529
+
530
+ ##### `__init__(tokenizer, file_path, block_size=128)`
531
+
532
+ 初始化数据集。
533
+
534
+ **参数**:
535
+ - `tokenizer`: Tokenizer
536
+ - `file_path` (str): 文件路径
537
+ - `block_size` (int): 块大小
538
+
539
+ **示例**:
540
+ ```python
541
+ from torch.utils.data import Dataset
542
+
543
+ class TextDataset(Dataset):
544
+ def __init__(self, tokenizer, file_path, block_size=128):
545
+ # ...
546
+ pass
547
+ ```
548
+
549
+ ---
550
+
551
+ ## 完整示例
552
+
553
+ ### 训练完整流程
554
+
555
+ ```python
556
+ import torch
557
+ from models.fusion_mini import FusionMini, FusionMiniConfig
558
+ from train.full_finetune import FullFinetuner
559
+ from evaluation.metrics import ModelEvaluator
560
+
561
+ # 1. 创建模型
562
+ config = FusionMiniConfig(
563
+ vocab_size=1000,
564
+ hidden_size=128,
565
+ num_hidden_layers=2,
566
+ )
567
+ model = FusionMini(config)
568
+
569
+ # 2. 创建训练器
570
+ finetuner = FullFinetuner()
571
+
572
+ # 3. 训练
573
+ finetuner.train(
574
+ model=model,
575
+ train_dataset=train_dataset,
576
+ eval_dataset=eval_dataset,
577
+ num_epochs=3,
578
+ batch_size=4,
579
+ )
580
+
581
+ # 4. 评估
582
+ evaluator = ModelEvaluator()
583
+ metrics = evaluator.evaluate(
584
+ model=model,
585
+ eval_data=eval_dataset,
586
+ )
587
+
588
+ print(f"Perplexity: {metrics.perplexity:.2f}")
589
+ print(f"Loss: {metrics.loss:.4f}")
590
+ ```
591
+
592
+ ### 推理完整流程
593
+
594
+ ```python
595
+ import torch
596
+ from models.fusion_mini import FusionMini
597
+
598
+ # 1. 加载模型
599
+ model = FusionMini.from_pretrained("output/real_model")
600
+ model.eval()
601
+
602
+ # 2. 创建输入
603
+ input_ids = torch.tensor([[1, 2, 3, 4, 5]])
604
+
605
+ # 3. 推理
606
+ with torch.no_grad():
607
+ outputs = model(
608
+ input_ids=input_ids,
609
+ return_dict=True,
610
+ )
611
+
612
+ logits = outputs["logits"]
613
+ print(f"Logits shape: {logits.shape}")
614
+
615
+ # 4. 生成
616
+ generated = model.generate(
617
+ input_ids=input_ids,
618
+ max_length=50,
619
+ )
620
+ print(f"Generated: {generated}")
621
+ ```
622
+
623
+ ---
624
+
625
+ ## 常见问题
626
+
627
+ ### 1. 如何自定义模型配置?
628
+
629
+ 使用 `FusionMiniConfig`:
630
+
631
+ ```python
632
+ config = FusionMiniConfig(
633
+ vocab_size=2000, # 更大的词汇表
634
+ hidden_size=256, # 更大的隐藏层
635
+ num_hidden_layers=4, # 更深的模型
636
+ num_attention_heads=4, # 更多的注意力头
637
+ )
638
+ ```
639
+
640
+ ### 2. 如何使用 GQA?
641
+
642
+ 在配置中设置 `num_key_value_heads`:
643
+
644
+ ```python
645
+ config = FusionMiniConfig(
646
+ num_attention_heads=8, # 8 个查询头
647
+ num_key_value_heads=2, # 2 个 KV 头(GQA)
648
+ )
649
+ ```
650
+
651
+ ### 3. 如何启用 KV 缓存?
652
+
653
+ 在推理时使用 `use_cache=True`:
654
+
655
+ ```python
656
+ outputs = model(
657
+ input_ids=input_ids,
658
+ use_cache=True,
659
+ return_dict=True,
660
+ )
661
+ past_key_values = outputs["past_key_values"]
662
+ ```
663
+
664
+ ### 4. 如何量化模型?
665
+
666
+ 使用 `DyQuant`:
667
+
668
+ ```python
669
+ from inference.dyquant import DyQuant
670
+
671
+ quantizer = DyQuant()
672
+ quantized_model = quantizer.quantize(model, bits=8)
673
+ ```
674
+
675
+ ---
676
+
677
+ ## 许可证
678
+
679
+ Fusion-LLM API 文档采用 Apache 2.0 许可证。
docs/tutorial.md ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Fusion-LLM 使用教程
2
+
3
+ ## 简介
4
+
5
+ Fusion-LLM 是一个开源大语言模型项目,采用 Apache 2.0 许可证,核心理念为用户主权、纯本地训练推理。
6
+
7
+ ### 核心特性
8
+ - **SBLA 注意力**:滑动分块潜注意力(Sliding Block Latent Attention)
9
+ - **Thinking Dial**:动态推理强度控制
10
+ - **纯本地**:无需云端,完全本地训练和推理
11
+ - **用户主权**:数据完全由用户控制
12
+
13
+ ---
14
+
15
+ ## 安装
16
+
17
+ ### 环境要求
18
+ - Python 3.8+
19
+ - PyTorch 2.0+
20
+ - CUDA 11.7+ (可选,用于 GPU 加速)
21
+
22
+ ### 安装步骤
23
+
24
+ #### 1. 克隆仓库
25
+ ```bash
26
+ git clone https://github.com/zhan1206/fusion-llm.git
27
+ cd fusion-llm
28
+ ```
29
+
30
+ #### 2. 安装依赖
31
+ ```bash
32
+ pip install -r requirements.txt
33
+ ```
34
+
35
+ #### 3. 验证安装
36
+ ```bash
37
+ python tests/test_tiny.py
38
+ ```
39
+
40
+ 如果看到 `[PASS] 测试通过`,说明安装成功!
41
+
42
+ ---
43
+
44
+ ## 快速开始
45
+
46
+ ### 1. 最小训练测试(验证安装)
47
+
48
+ 运行最小训练测试(1-2 步,快速验证训练功能):
49
+
50
+ ```bash
51
+ python train/test_train_mini.py
52
+ ```
53
+
54
+ 预期输出:
55
+ ```
56
+ [TRAIN] 开始最小训练(1-2 步)...
57
+ [5] 训练 2 步...
58
+ Step 1: Loss = 4.5879
59
+ Step 2: Loss = 4.5768
60
+ 训练完成
61
+ [6] 验证损失下降...
62
+ [PASS] Loss 下降: 4.5879 -> 4.5768
63
+ 训练有效!
64
+
65
+ [PASS] 训练测试通过
66
+ ```
67
+
68
+ ### 2. 小训练测试(10 步)
69
+
70
+ 运行小训练测试(10 步,验证损失持续下降):
71
+
72
+ ```bash
73
+ python train/train_10steps.py
74
+ ```
75
+
76
+ 预期输出:
77
+ ```
78
+ [TRAIN] 开始小训练(10 步)...
79
+ [5] 训练 10 步...
80
+ Step 1: Loss = 6.9452
81
+ Step 2: Loss = 6.8520
82
+ ...
83
+ Step 10: Loss = 6.3993
84
+ 训练完成
85
+ [6] 验证损失下降...
86
+ [PASS] Loss 持续下降
87
+ 训练有效!
88
+
89
+ [PASS] 训练测试通过
90
+ ```
91
+
92
+ ### 3. 实际模型训练(100 步)
93
+
94
+ 运行实际模型训练(100 步,生成模型权重):
95
+
96
+ ```bash
97
+ python train/train_real.py
98
+ ```
99
+
100
+ 预期输出:
101
+ ```
102
+ [TRAIN] 开始实际模型训练(100 步)...
103
+ [6] 训练 100 步...
104
+ Step 10: Loss = 3.5885 (Avg: 4.0321)
105
+ ...
106
+ Step 100: Loss = 1.7501 (Avg: 1.9562)
107
+ 训练完成
108
+ [7] 验证损失下降...
109
+ [PASS] Loss 持续下降
110
+ 训练有效!
111
+
112
+ [8] 保存模型...
113
+ 模型保存路径: output/real_model
114
+ 模型保存成功
115
+
116
+ [PASS] 训练测试通过
117
+ ```
118
+
119
+ 训练完成后,模型权重将保存到 `output/real_model/` 目录。
120
+
121
+ ---
122
+
123
+ ## 模型推理
124
+
125
+ ### 1. 基本推理测试
126
+
127
+ 运行基本推理测试:
128
+
129
+ ```bash
130
+ python tests/test_inference_basic.py
131
+ ```
132
+
133
+ ### 2. 使用训练好的模型进行推理
134
+
135
+ ```python
136
+ import torch
137
+ from models.fusion_mini import FusionMini, FusionMiniConfig
138
+
139
+ # 加载模型
140
+ model = FusionMini.from_pretrained("output/real_model")
141
+ model.eval()
142
+
143
+ # 创建输入
144
+ input_ids = torch.tensor([[1, 2, 3, 4, 5]])
145
+
146
+ # 推理
147
+ with torch.no_grad():
148
+ outputs = model(
149
+ input_ids=input_ids,
150
+ return_dict=True,
151
+ )
152
+
153
+ logits = outputs["logits"]
154
+ print(f"Logits shape: {logits.shape}")
155
+ ```
156
+
157
+ ---
158
+
159
+ ## 高级功能
160
+
161
+ ### 1. Thinking Dial(动态推理强度控制)
162
+
163
+ Thinking Dial 允许动态控制模型的推理强度。
164
+
165
+ ```python
166
+ from models.thinking_dial import ThinkingDialProcessor
167
+
168
+ # 创建处理器
169
+ processor = ThinkingDialProcessor()
170
+
171
+ # 注入 think token
172
+ text = "<|think_depth_2|> 这是一个需要深入思考的问题。"
173
+ processed_text = processor.process(text)
174
+
175
+ print(processed_text)
176
+ ```
177
+
178
+ ### 2. SBLA 注意力
179
+
180
+ SBLA(Sliding Block Latent Attention)是 Fusion-LLM 的核心注意力机制。
181
+
182
+ ```python
183
+ from models.sbla_attention import SBLAttention
184
+
185
+ # 创建 SBLA 注意力层
186
+ attention = SBLAttention(
187
+ hidden_size=128,
188
+ num_heads=2,
189
+ window_size=16,
190
+ )
191
+
192
+ # 前向传播
193
+ hidden_states = torch.randn(1, 32, 128)
194
+ output = attention(hidden_states)
195
+ print(f"Output shape: {output.shape}")
196
+ ```
197
+
198
+ ### 3. 动态量化(DyQuant)
199
+
200
+ DyQuant(Dynamic Quantization)提供动态混合精度量化(4/8/16-bit)。
201
+
202
+ ```python
203
+ from inference.dyquant import DyQuant
204
+
205
+ # 创建量化器
206
+ quantizer = DyQuant()
207
+
208
+ # 量化模型
209
+ quantized_model = quantizer.quantize(model, bits=8)
210
+
211
+ # 保存量化模型
212
+ quantizer.save(quantized_model, "output/quantized_model")
213
+ ```
214
+
215
+ ---
216
+
217
+ ## 训练配置
218
+
219
+ ### 1. 使用配置文件
220
+
221
+ 创建配置文件 `configs/my_config.json`:
222
+
223
+ ```json
224
+ {
225
+ "vocab_size": 1000,
226
+ "hidden_size": 128,
227
+ "num_hidden_layers": 2,
228
+ "num_attention_heads": 2,
229
+ "intermediate_size": 256,
230
+ "max_position_embeddings": 64
231
+ }
232
+ ```
233
+
234
+ 使用配置文件训练:
235
+
236
+ ```bash
237
+ python train/full_finetune.py --config configs/my_config.json
238
+ ```
239
+
240
+ ### 2. LoRA 微调
241
+
242
+ 使用 LoRA 进行参数高效微调:
243
+
244
+ ```bash
245
+ python train/lora_finetune.py \
246
+ --model_name_or_path output/real_model \
247
+ --lora_r 8 \
248
+ --lora_alpha 16 \
249
+ --train_epochs 3
250
+ ```
251
+
252
+ ---
253
+
254
+ ## 评估与指标
255
+
256
+ ### 1. 使用评估指标
257
+
258
+ ```python
259
+ from evaluation.metrics import EvaluationMetrics, ModelEvaluator
260
+
261
+ # 创��评估器
262
+ evaluator = ModelEvaluator()
263
+
264
+ # 评估模型
265
+ metrics = evaluator.evaluate(
266
+ model=model,
267
+ eval_data=eval_dataset,
268
+ metrics=["perplexity", "loss", "accuracy"],
269
+ )
270
+
271
+ print(f"Perplexity: {metrics.perplexity:.2f}")
272
+ print(f"Loss: {metrics.loss:.4f}")
273
+ print(f"Accuracy: {metrics.accuracy:.4f}")
274
+ ```
275
+
276
+ ### 2. 生成模型卡片
277
+
278
+ ```bash
279
+ python evaluation/model_card.py \
280
+ --model_path output/real_model \
281
+ --output_path output/model_card.json
282
+ ```
283
+
284
+ ---
285
+
286
+ ## 部署
287
+
288
+ ### 1. Ollama 部署
289
+
290
+ 使用 Ollama 部署模型:
291
+
292
+ ```bash
293
+ python inference/ollama_deploy_v2.py \
294
+ --model_path output/real_model \
295
+ --output_path output/ollama_model
296
+ ```
297
+
298
+ ### 2. 量化部署
299
+
300
+ 使用动态量化减小模型大小:
301
+
302
+ ```bash
303
+ python inference/dyquant.py \
304
+ --model_path output/real_model \
305
+ --bits 8 \
306
+ --output_path output/quantized_model
307
+ ```
308
+
309
+ ---
310
+
311
+ ## 常见问题
312
+
313
+ ### 1. 训练时 Loss 不下降?
314
+
315
+ **可能原因**:
316
+ - 学习率太大或太小
317
+ - 数据量太少
318
+ - 模型太小
319
+
320
+ **解决方案**:
321
+ - 调整学习率(尝试 1e-4 到 5e-4)
322
+ - 增加训练数据量
323
+ - 增大模型配置(hidden_size、num_layers)
324
+
325
+ ### 2. 推理时出现 NaN?
326
+
327
+ **可能原因**:
328
+ - 注意力掩码错误
329
+ - 梯度爆炸
330
+
331
+ **解决方案**:
332
+ - 检查注意力掩码格式
333
+ - 使用梯度裁剪(`torch.nn.utils.clip_grad_norm_`)
334
+
335
+ ### 3. 训练速度太慢?
336
+
337
+ **可能原因**:
338
+ - SBLA 注意力计算量大
339
+ - 没有使用 GPU
340
+
341
+ **解决方案**:
342
+ - 使用更小的配置(hidden_size=32, num_layers=1)
343
+ - 使用 GPU 训练
344
+ - 启用混合精度训练(FP16/BF16)
345
+
346
+ ---
347
+
348
+ ## 贡献
349
+
350
+ 欢迎贡献!请查看 `CONTRIBUTING.md` 了解详情。
351
+
352
+ ---
353
+
354
+ ## 许可证
355
+
356
+ Fusion-LLM 采用 Apache 2.0 许可证。查看 `LICENSE` 文件了解详情。
train/train_real.py ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 实际模型训练 - 训练 100 步(使用真实数据)
3
+ """
4
+ import sys
5
+ import torch
6
+ import torch.optim as optim
7
+ from pathlib import Path
8
+ import json
9
+
10
+ sys.path.insert(0, '.')
11
+
12
+ from models.fusion_mini import FusionMini, FusionMiniConfig
13
+
14
+
15
+ def train_real():
16
+ """实际训练(100 步)"""
17
+ print("[TRAIN] 开始实际模型训练(100 步)...")
18
+ print()
19
+
20
+ # 1. 创建小配置(实际使用)
21
+ print("[1] 创建模型配置...")
22
+ config = FusionMiniConfig(
23
+ vocab_size=100, # 小词表(匹配 tokenizer)
24
+ hidden_size=128, # 小隐层
25
+ num_hidden_layers=2, # 2 层
26
+ num_attention_heads=2, # 2 个注意力头
27
+ intermediate_size=256,
28
+ max_position_embeddings=64,
29
+ )
30
+ print(f" 词汇表大小: {config.vocab_size}")
31
+ print(f" 隐藏层大小: {config.hidden_size}")
32
+ print(f" 层数: {config.num_hidden_layers}")
33
+ print()
34
+
35
+ # 2. 创建模型
36
+ print("[2] 创建模型...")
37
+ model = FusionMini(config)
38
+ model.train() # 训练模式
39
+ param_count = sum(p.numel() for p in model.parameters()) / 1e3
40
+ print(f" 参数量: {param_count:.1f}K")
41
+ print(" 模型创建成功")
42
+ print()
43
+
44
+ # 3. 创建优化器
45
+ print("[3] 创建优化器...")
46
+ optimizer = optim.AdamW(
47
+ model.parameters(),
48
+ lr=5e-4,
49
+ weight_decay=0.01,
50
+ )
51
+ print(" 优化器创建成功")
52
+ print()
53
+
54
+ # 4. 加载训练数据
55
+ print("[4] 加载训练数据...")
56
+ data_path = Path("data/training_data.txt")
57
+
58
+ if not data_path.exists():
59
+ print(f" [ERROR] 训练数据不存在: {data_path}")
60
+ return False
61
+
62
+ with open(data_path, "r", encoding="utf-8") as f:
63
+ sentences = [line.strip() for line in f if line.strip()]
64
+
65
+ print(f" 句子数量: {len(sentences)}")
66
+ print(" 训练数据加载成功")
67
+ print()
68
+
69
+ # 5. 准备训练数据(简单编码)
70
+ print("[5] 准备训练数据...")
71
+
72
+ # 简单字符级编码
73
+ chars = sorted(list(set("".join(sentences))))
74
+ char_to_idx = {ch: i+3 for i, ch in enumerate(chars)} # +3 for [PAD], [UNK], [CLS]
75
+ char_to_idx["[PAD]"] = 0
76
+ char_to_idx["[UNK]"] = 1
77
+ char_to_idx["[CLS]"] = 2
78
+
79
+ # 编码句子
80
+ encoded_sentences = []
81
+ for sent in sentences:
82
+ encoded = [char_to_idx.get(ch, 1) for ch in sent] # 1 = [UNK]
83
+ encoded_sentences.append(encoded)
84
+
85
+ print(f" 词汇表大小: {len(char_to_idx)}")
86
+ print(f" 编码句子数量: {len(encoded_sentences)}")
87
+ print(" 训练数据准备成功")
88
+ print()
89
+
90
+ # 6. 训练 100 步
91
+ print("[6] 训练 100 步...")
92
+ losses = []
93
+ batch_size = 4
94
+ seq_len = 32
95
+
96
+ for step in range(100):
97
+ # 随机选择句子
98
+ indices = torch.randint(0, len(encoded_sentences), (batch_size,))
99
+
100
+ # 创建批次
101
+ batch_input = []
102
+ batch_labels = []
103
+
104
+ for idx in indices:
105
+ encoded = encoded_sentences[idx]
106
+
107
+ # 截断或填充到 seq_len
108
+ if len(encoded) > seq_len:
109
+ encoded = encoded[:seq_len]
110
+ else:
111
+ encoded = encoded + [0] * (seq_len - len(encoded))
112
+
113
+ batch_input.append(encoded[:-1]) # 输入:除最后一个 token
114
+ batch_labels.append(encoded[1:]) # 标签:除第一个 token
115
+
116
+ input_ids = torch.tensor(batch_input)
117
+ labels = torch.tensor(batch_labels)
118
+
119
+ # 清零梯度
120
+ optimizer.zero_grad()
121
+
122
+ # 前向传播
123
+ outputs = model(
124
+ input_ids=input_ids,
125
+ labels=labels,
126
+ return_dict=True,
127
+ )
128
+
129
+ loss = outputs["loss"]
130
+ losses.append(loss.item())
131
+
132
+ # 反向传播
133
+ loss.backward()
134
+
135
+ # 更新参数
136
+ optimizer.step()
137
+
138
+ # 每 10 步打印一次
139
+ if (step + 1) % 10 == 0:
140
+ avg_loss = sum(losses[-10:]) / min(10, len(losses))
141
+ print(f" Step {step+1:3d}: Loss = {loss.item():.4f} (Avg: {avg_loss:.4f})")
142
+
143
+ print(" 训练完成")
144
+ print()
145
+
146
+ # 7. 验证损失下降
147
+ print("[7] 验证损失下降...")
148
+ initial_loss = losses[0]
149
+ final_loss = losses[-1]
150
+ is_decreasing = final_loss < initial_loss
151
+
152
+ print(f" 初始 Loss: {initial_loss:.4f}")
153
+ print(f" 最终 Loss: {final_loss:.4f}")
154
+ print(f" Loss 变化: {final_loss - initial_loss:+.4f}")
155
+ print()
156
+
157
+ if is_decreasing:
158
+ print(" [PASS] Loss 持续下降")
159
+ print(" 训练有效!")
160
+ else:
161
+ print(" [WARN] Loss 未下降")
162
+ print(" 可能的问题:学习率太大 / 数据太少 / 模型太小")
163
+ print()
164
+
165
+ # 8. 保存模型
166
+ print("[8] 保存模型...")
167
+ output_dir = Path("output/real_model")
168
+ output_dir.mkdir(parents=True, exist_ok=True)
169
+
170
+ # 保存模型权重
171
+ torch.save(model.state_dict(), output_dir / "model.pt")
172
+
173
+ # 保存配置
174
+ config_dict = {
175
+ "vocab_size": config.vocab_size,
176
+ "hidden_size": config.hidden_size,
177
+ "num_hidden_layers": config.num_hidden_layers,
178
+ "num_attention_heads": config.num_attention_heads,
179
+ "intermediate_size": config.intermediate_size,
180
+ "max_position_embeddings": config.max_position_embeddings,
181
+ }
182
+
183
+ with open(output_dir / "config.json", "w") as f:
184
+ json.dump(config_dict, f, indent=2)
185
+
186
+ print(f" 模型保存路径: {output_dir}")
187
+ print(" 模型保存成功")
188
+ print()
189
+
190
+ print("[TRAIN] 实际模型训练完成")
191
+ return is_decreasing
192
+
193
+
194
+ if __name__ == "__main__":
195
+ print("=" * 60)
196
+ print("Fusion-LLM 实际模型训练(100 步)")
197
+ print("=" * 60)
198
+ print()
199
+
200
+ try:
201
+ success = train_real()
202
+ if success:
203
+ print()
204
+ print("[PASS] 训练测试通过")
205
+ except Exception as e:
206
+ print()
207
+ print(f"[FAIL] 训练测试出错: {e}")
208
+ import traceback
209
+ traceback.print_exc()
210
+ sys.exit(1)
211
+
212
+ sys.exit(0)