zhan1206 commited on
Commit
0dafe0f
·
1 Parent(s): 82bba0c

fix(v11): resolve remaining 5 defects (S-NEW-1/2, M-NEW-2/3, MI-NEW-1)

Browse files

SERIOUS:
- S-NEW-1: dashboard token count len(tokens[0]) -> .shape[1] for correct seq_len
- S-NEW-2: dyquant convert() relies on load_model side effect -> check return value

MODERATE:
- M-NEW-2: 4 overlapping data scripts merged into manage_mini_data.py (create|fix|enrich|dedup|all)
- M-NEW-3: replace all emoji in print/logger with ASCII tags for GBK console compatibility

MINOR:
- MI-NEW-1: test_sbla_integration has_sblla typo -> has_sbla

data_pipeline/bilingual_filter.py CHANGED
@@ -61,7 +61,7 @@ class BilingualTrueFilter:
61
  else:
62
  logger.warning("langid not installed, language detection disabled")
63
 
64
- logger.info(f" 初始化 {lang.upper()} 数据过滤器")
65
 
66
  def process(self, data: List[str]) -> List[str]:
67
  """
@@ -73,7 +73,7 @@ class BilingualTrueFilter:
73
  返回:
74
  清洗后的文本列表
75
  """
76
- logger.info(f"📊 开始处理 {len(data)} 条数据...")
77
 
78
  clean_data = []
79
 
@@ -99,7 +99,7 @@ class BilingualTrueFilter:
99
 
100
  clean_data.append(text)
101
 
102
- logger.info(f" 清洗完成:{len(clean_data)}/{len(data)} 条保留")
103
 
104
  return clean_data
105
 
@@ -141,17 +141,17 @@ class BilingualTrueFilter:
141
  """
142
  # 1. 剔除"小编体"
143
  if self._is_xiaobian_style(text):
144
- logger.debug(" 剔除小编体")
145
  return False
146
 
147
  # 2. 剔除机翻内容
148
  if self._is_machine_translation(text):
149
- logger.debug(" 剔除机翻内容")
150
  return False
151
 
152
  # 3. 剔除低质量内容
153
  if self._is_low_quality_chinese(text):
154
- logger.debug(" 剔除低质量内容")
155
  return False
156
 
157
  return True
@@ -166,12 +166,12 @@ class BilingualTrueFilter:
166
  """
167
  # 1. 剔除直译中文语料
168
  if self._is_translated_from_chinese(text):
169
- logger.debug(" 剔除直译中文语料")
170
  return False
171
 
172
  # 2. 剔除低质量内容
173
  if self._is_low_quality_english(text):
174
- logger.debug(" 剔除低质量内容")
175
  return False
176
 
177
  return True
@@ -298,7 +298,7 @@ class BalancedSampler:
298
  self.en_data = en_data
299
  self.zh_ratio = zh_ratio
300
 
301
- logger.info(f"📊 平衡采样器初始化")
302
  logger.info(f" 中文数据:{len(zh_data)} 条")
303
  logger.info(f" 英文数据:{len(en_data)} 条")
304
  logger.info(f" 中文占比:{zh_ratio:.1%}")
@@ -331,7 +331,7 @@ class BalancedSampler:
331
 
332
  random.shuffle(sampled)
333
 
334
- logger.info(f" 采样 {len(sampled)} 条平衡数据")
335
  logger.info(f" 中文:{n_zh} 条,英文:{n_en} 条")
336
 
337
  return sampled
@@ -352,10 +352,10 @@ def process_data_pipeline(
352
  output_path: 输出路径
353
  n_samples: 采样数量
354
  """
355
- logger.info("🚀 启动双母语数据处理管道...")
356
 
357
  # 1. 加载原始数据
358
- logger.info("📦 加载原始数据...")
359
 
360
  with open(zh_raw_path, 'r', encoding='utf-8') as f:
361
  zh_raw = json.load(f)
@@ -367,33 +367,33 @@ def process_data_pipeline(
367
  logger.info(f" 英文原始数据:{len(en_raw)} 条")
368
 
369
  # 2. 清洗中文数据
370
- logger.info("\n🧹 清洗中文数据...")
371
  zh_filter = BilingualTrueFilter(lang="zh")
372
  zh_clean = zh_filter.process(zh_raw)
373
 
374
  # 3. 清洗英文数据
375
- logger.info("\n🧹 清洗英文数据...")
376
  en_filter = BilingualTrueFilter(lang="en")
377
  en_clean = en_filter.process(en_raw)
378
 
379
  # 4. 平衡采样
380
- logger.info("\n⚖️ 平衡采样...")
381
  sampler = BalancedSampler(zh_clean, en_clean, zh_ratio=0.5)
382
  balanced_data = sampler.sample(n_samples)
383
 
384
  # 5. 保存
385
- logger.info(f"\n💾 保存到 {output_path}...")
386
  with open(output_path, 'w', encoding='utf-8') as f:
387
  json.dump(balanced_data, f, ensure_ascii=False, indent=2)
388
 
389
- logger.info(" 数据处理管道完成!")
390
 
391
  return balanced_data
392
 
393
 
394
  if __name__ == "__main__":
395
  # 单元测试(模拟数据)
396
- print("🧪 测试 Bi-Lingual TrueFilter...")
397
 
398
  # 模拟中文数据
399
  zh_test_data = [
@@ -413,16 +413,16 @@ if __name__ == "__main__":
413
  # 测试中文过滤器
414
  zh_filter = BilingualTrueFilter(lang="zh")
415
  zh_clean = zh_filter.process(zh_test_data)
416
- print(f" 中文过滤:{len(zh_clean)}/{len(zh_test_data)} 条保留")
417
 
418
  # 测试英文过滤器
419
  en_filter = BilingualTrueFilter(lang="en")
420
  en_clean = en_filter.process(en_test_data)
421
- print(f" 英文过滤:{len(en_clean)}/{len(en_test_data)} 条保留")
422
 
423
  # 测试平衡采样
424
  sampler = BalancedSampler(zh_clean, en_clean, zh_ratio=0.5)
425
  balanced = sampler.sample(10)
426
- print(f" 平衡采样:{len(balanced)} 条")
427
 
428
- print("\n Bi-Lingual TrueFilter 测试通过!")
 
61
  else:
62
  logger.warning("langid not installed, language detection disabled")
63
 
64
+ logger.info(f"[OK] 初始化 {lang.upper()} 数据过滤器")
65
 
66
  def process(self, data: List[str]) -> List[str]:
67
  """
 
73
  返回:
74
  清洗后的文本列表
75
  """
76
+ logger.info(f"[CHART] 开始处理 {len(data)} 条数据...")
77
 
78
  clean_data = []
79
 
 
99
 
100
  clean_data.append(text)
101
 
102
+ logger.info(f"[OK] 清洗完成:{len(clean_data)}/{len(data)} 条保留")
103
 
104
  return clean_data
105
 
 
141
  """
142
  # 1. 剔除"小编体"
143
  if self._is_xiaobian_style(text):
144
+ logger.debug("[FAIL] 剔除小编体")
145
  return False
146
 
147
  # 2. 剔除机翻内容
148
  if self._is_machine_translation(text):
149
+ logger.debug("[FAIL] 剔除机翻内容")
150
  return False
151
 
152
  # 3. 剔除低质量内容
153
  if self._is_low_quality_chinese(text):
154
+ logger.debug("[FAIL] 剔除低质量内容")
155
  return False
156
 
157
  return True
 
166
  """
167
  # 1. 剔除直译中文语料
168
  if self._is_translated_from_chinese(text):
169
+ logger.debug("[FAIL] 剔除直译中文语料")
170
  return False
171
 
172
  # 2. 剔除低质量内容
173
  if self._is_low_quality_english(text):
174
+ logger.debug("[FAIL] 剔除低质量内容")
175
  return False
176
 
177
  return True
 
298
  self.en_data = en_data
299
  self.zh_ratio = zh_ratio
300
 
301
+ logger.info(f"[CHART] 平衡采样器初始化")
302
  logger.info(f" 中文数据:{len(zh_data)} 条")
303
  logger.info(f" 英文数据:{len(en_data)} 条")
304
  logger.info(f" 中文占比:{zh_ratio:.1%}")
 
331
 
332
  random.shuffle(sampled)
333
 
334
+ logger.info(f"[OK] 采样 {len(sampled)} 条平衡数据")
335
  logger.info(f" 中文:{n_zh} 条,英文:{n_en} 条")
336
 
337
  return sampled
 
352
  output_path: 输出路径
353
  n_samples: 采样数量
354
  """
355
+ logger.info("[GO] 启动双母语数据处理管道...")
356
 
357
  # 1. 加载原始数据
358
+ logger.info("[LOAD] 加载原始数据...")
359
 
360
  with open(zh_raw_path, 'r', encoding='utf-8') as f:
361
  zh_raw = json.load(f)
 
367
  logger.info(f" 英文原始数据:{len(en_raw)} 条")
368
 
369
  # 2. 清洗中文数据
370
+ logger.info("\n[CLEAN] 清洗中文数据...")
371
  zh_filter = BilingualTrueFilter(lang="zh")
372
  zh_clean = zh_filter.process(zh_raw)
373
 
374
  # 3. 清洗英文数据
375
+ logger.info("\n[CLEAN] 清洗英文数据...")
376
  en_filter = BilingualTrueFilter(lang="en")
377
  en_clean = en_filter.process(en_raw)
378
 
379
  # 4. 平衡采样
380
+ logger.info("\n[BALANCE][LOGO] 平衡采样...")
381
  sampler = BalancedSampler(zh_clean, en_clean, zh_ratio=0.5)
382
  balanced_data = sampler.sample(n_samples)
383
 
384
  # 5. 保存
385
+ logger.info(f"\n[SAVE] 保存到 {output_path}...")
386
  with open(output_path, 'w', encoding='utf-8') as f:
387
  json.dump(balanced_data, f, ensure_ascii=False, indent=2)
388
 
389
+ logger.info("[OK] 数据处理管道完成!")
390
 
391
  return balanced_data
392
 
393
 
394
  if __name__ == "__main__":
395
  # 单元测试(模拟数据)
396
+ print("[LOGO] 测试 Bi-Lingual TrueFilter...")
397
 
398
  # 模拟中文数据
399
  zh_test_data = [
 
413
  # 测试中文过滤器
414
  zh_filter = BilingualTrueFilter(lang="zh")
415
  zh_clean = zh_filter.process(zh_test_data)
416
+ print(f"[OK] 中文过滤:{len(zh_clean)}/{len(zh_test_data)} 条保留")
417
 
418
  # 测试英文过滤器
419
  en_filter = BilingualTrueFilter(lang="en")
420
  en_clean = en_filter.process(en_test_data)
421
+ print(f"[OK] 英文过滤:{len(en_clean)}/{len(en_test_data)} 条保留")
422
 
423
  # 测试平衡采样
424
  sampler = BalancedSampler(zh_clean, en_clean, zh_ratio=0.5)
425
  balanced = sampler.sample(10)
426
+ print(f"[OK] 平衡采样:{len(balanced)} 条")
427
 
428
+ print("\n[OK] Bi-Lingual TrueFilter 测试通过!")
data_pipeline/t_kd_distillation.py CHANGED
@@ -47,7 +47,7 @@ class TKDDistiller:
47
  device: 设备(cuda/cpu)
48
  torch_dtype: 数据类型
49
  """
50
- print(f"📚 加载教师模型:{teacher_model}")
51
 
52
  self.device = device
53
  self.tokenizer = AutoTokenizer.from_pretrained(
@@ -64,7 +64,7 @@ class TKDDistiller:
64
 
65
  self.model.eval()
66
 
67
- print(f" 教师模型加载成功")
68
  print(f" 设备:{self.model.device}")
69
  print(f" 参数量:{sum(p.numel() for p in self.model.parameters()) / 1e9:.2f}B")
70
 
@@ -164,7 +164,7 @@ class TKDDistiller:
164
  返回:
165
  蒸馏结果列表
166
  """
167
- print(f"\n📚 开始 T-KD 蒸馏...")
168
  print(f" 主题数:{len(topics)}")
169
  print(f" 数据源:{source_type}")
170
 
@@ -195,7 +195,7 @@ class TKDDistiller:
195
  with open(output_path, 'a', encoding='utf-8') as f:
196
  f.write(json.dumps(result, ensure_ascii=False) + '\n')
197
 
198
- print(f" 完成(生成 {len(text)} 字符)")
199
 
200
  # 避免 GPU 过热
201
  if i % 10 == 0:
@@ -203,10 +203,10 @@ class TKDDistiller:
203
  time.sleep(1)
204
 
205
  except Exception as e:
206
- print(f" 失败:{e}")
207
  continue
208
 
209
- print(f"\n🎉 蒸馏完成!共生成 {len(results)} 个样本")
210
 
211
  return results
212
 
@@ -330,9 +330,9 @@ def main():
330
  output_path=output_path,
331
  )
332
 
333
- print(f"\n {source} 蒸馏完成,结果保存至:{output_path}")
334
 
335
- print(f"\n🎉 所有数据源蒸馏完成!")
336
  print(f" 输出目录:{Path(args.output_path).parent}")
337
 
338
 
 
47
  device: 设备(cuda/cpu)
48
  torch_dtype: 数据类型
49
  """
50
+ print(f"[BOOK] 加载教师模型:{teacher_model}")
51
 
52
  self.device = device
53
  self.tokenizer = AutoTokenizer.from_pretrained(
 
64
 
65
  self.model.eval()
66
 
67
+ print(f"[OK] 教师模型加载成功")
68
  print(f" 设备:{self.model.device}")
69
  print(f" 参数量:{sum(p.numel() for p in self.model.parameters()) / 1e9:.2f}B")
70
 
 
164
  返回:
165
  蒸馏结果列表
166
  """
167
+ print(f"\n[BOOK] 开始 T-KD 蒸馏...")
168
  print(f" 主题数:{len(topics)}")
169
  print(f" 数据源:{source_type}")
170
 
 
195
  with open(output_path, 'a', encoding='utf-8') as f:
196
  f.write(json.dumps(result, ensure_ascii=False) + '\n')
197
 
198
+ print(f"[OK] 完成(生成 {len(text)} 字符)")
199
 
200
  # 避免 GPU 过热
201
  if i % 10 == 0:
 
203
  time.sleep(1)
204
 
205
  except Exception as e:
206
+ print(f"[FAIL] 失败:{e}")
207
  continue
208
 
209
+ print(f"\n[DONE] 蒸馏完成!共生成 {len(results)} 个样本")
210
 
211
  return results
212
 
 
330
  output_path=output_path,
331
  )
332
 
333
+ print(f"\n[OK] {source} 蒸馏完成,结果保存至:{output_path}")
334
 
335
+ print(f"\n[DONE] 所有数据源蒸馏完成!")
336
  print(f" 输出目录:{Path(args.output_path).parent}")
337
 
338
 
data_pipeline/t_kd_distillation_train.py CHANGED
@@ -57,7 +57,7 @@ class DistillationDataset(Dataset):
57
  if line.strip():
58
  self.data.append(json.loads(line))
59
 
60
- logger.info(f" 加载数据:{len(self.data)} 条")
61
 
62
  def __len__(self):
63
  return len(self.data)
@@ -127,7 +127,7 @@ class DistillationTrainer:
127
  self.grad_accum_steps = grad_accum_steps
128
 
129
  # 1. 加载教师模型(冻结)
130
- logger.info(f"📚 加载教师模型:{teacher_model_name}")
131
  self.teacher_tokenizer = AutoTokenizer.from_pretrained(
132
  teacher_model_name,
133
  trust_remote_code=True,
@@ -144,10 +144,10 @@ class DistillationTrainer:
144
  for param in self.teacher_model.parameters():
145
  param.requires_grad = False
146
 
147
- logger.info(f" 教师模型加载完成(参数已冻结)")
148
 
149
  # 2. 加载学生模型(可训练)
150
- logger.info(f"🎓 加载学生模型:{student_model_name}")
151
  self.student_tokenizer = AutoTokenizer.from_pretrained(
152
  student_model_name,
153
  trust_remote_code=True,
@@ -162,7 +162,7 @@ class DistillationTrainer:
162
 
163
  self.student_model.train()
164
 
165
- logger.info(f" 学生模型加载完成(可训练)")
166
 
167
  # 3. 优化器 + 学习率调度器
168
  self.optimizer = torch.optim.AdamW(
@@ -171,7 +171,7 @@ class DistillationTrainer:
171
  weight_decay=0.01,
172
  )
173
 
174
- logger.info(f" 优化器初始化完成(lr={learning_rate})")
175
 
176
  def compute_distillation_loss(
177
  self,
@@ -269,7 +269,7 @@ class DistillationTrainer:
269
  )
270
 
271
  # 3. 训练循环
272
- logger.info(f"🚀 开始蒸馏训练...")
273
  logger.info(f" 轮数:{num_epochs}")
274
  logger.info(f" 批次大小:{self.batch_size}")
275
  logger.info(f" 梯度累积:{self.grad_accum_steps}")
@@ -365,7 +365,7 @@ class DistillationTrainer:
365
  self.student_model.save_pretrained(checkpoint_dir)
366
  self.student_tokenizer.save_pretrained(checkpoint_dir)
367
 
368
- logger.info(f" 检查点保存至:{checkpoint_dir}")
369
 
370
  # 4. 保存最终模型
371
  output_path = Path(output_dir) / "final"
@@ -374,7 +374,7 @@ class DistillationTrainer:
374
  self.student_model.save_pretrained(output_path)
375
  self.student_tokenizer.save_pretrained(output_path)
376
 
377
- logger.info(f"🎉 蒸馏训练完成!模型保存至:{output_path}")
378
 
379
  def evaluate(
380
  self,
@@ -390,7 +390,7 @@ class DistillationTrainer:
390
  max_length: 最大序列长度
391
  num_samples: 评估样本数
392
  """
393
- logger.info(f"📊 开始评估...")
394
 
395
  self.student_model.eval()
396
 
@@ -430,7 +430,7 @@ class DistillationTrainer:
430
 
431
  avg_loss = total_loss / max(num_batches, 1)
432
 
433
- logger.info(f" 评估完成")
434
  logger.info(f" Average Loss: {avg_loss:.4f}")
435
  logger.info(f" Perplexity: {torch.exp(torch.tensor(avg_loss)).item():.2f}")
436
 
@@ -547,7 +547,7 @@ def main():
547
  max_length=args.max_length,
548
  )
549
 
550
- logger.info("🎉 蒸馏训练完成!")
551
 
552
 
553
  if __name__ == "__main__":
 
57
  if line.strip():
58
  self.data.append(json.loads(line))
59
 
60
+ logger.info(f"[OK] 加载数据:{len(self.data)} 条")
61
 
62
  def __len__(self):
63
  return len(self.data)
 
127
  self.grad_accum_steps = grad_accum_steps
128
 
129
  # 1. 加载教师模型(冻结)
130
+ logger.info(f"[BOOK] 加载教师模型:{teacher_model_name}")
131
  self.teacher_tokenizer = AutoTokenizer.from_pretrained(
132
  teacher_model_name,
133
  trust_remote_code=True,
 
144
  for param in self.teacher_model.parameters():
145
  param.requires_grad = False
146
 
147
+ logger.info(f"[OK] 教师模型加载完成(参数已冻结)")
148
 
149
  # 2. 加载学生模型(可训练)
150
+ logger.info(f"[GRAD] 加载学生模型:{student_model_name}")
151
  self.student_tokenizer = AutoTokenizer.from_pretrained(
152
  student_model_name,
153
  trust_remote_code=True,
 
162
 
163
  self.student_model.train()
164
 
165
+ logger.info(f"[OK] 学生模型加载完成(可训练)")
166
 
167
  # 3. 优化器 + 学习率调度器
168
  self.optimizer = torch.optim.AdamW(
 
171
  weight_decay=0.01,
172
  )
173
 
174
+ logger.info(f"[OK] 优化器初始化完成(lr={learning_rate})")
175
 
176
  def compute_distillation_loss(
177
  self,
 
269
  )
270
 
271
  # 3. 训练循环
272
+ logger.info(f"[GO] 开始蒸馏训练...")
273
  logger.info(f" 轮数:{num_epochs}")
274
  logger.info(f" 批次大小:{self.batch_size}")
275
  logger.info(f" 梯度累积:{self.grad_accum_steps}")
 
365
  self.student_model.save_pretrained(checkpoint_dir)
366
  self.student_tokenizer.save_pretrained(checkpoint_dir)
367
 
368
+ logger.info(f" [OK] 检查点保存至:{checkpoint_dir}")
369
 
370
  # 4. 保存最终模型
371
  output_path = Path(output_dir) / "final"
 
374
  self.student_model.save_pretrained(output_path)
375
  self.student_tokenizer.save_pretrained(output_path)
376
 
377
+ logger.info(f"[DONE] 蒸馏训练完成!模型保存至:{output_path}")
378
 
379
  def evaluate(
380
  self,
 
390
  max_length: 最大序列长度
391
  num_samples: 评估样本数
392
  """
393
+ logger.info(f"[CHART] 开始评估...")
394
 
395
  self.student_model.eval()
396
 
 
430
 
431
  avg_loss = total_loss / max(num_batches, 1)
432
 
433
+ logger.info(f"[OK] 评估完成")
434
  logger.info(f" Average Loss: {avg_loss:.4f}")
435
  logger.info(f" Perplexity: {torch.exp(torch.tensor(avg_loss)).item():.2f}")
436
 
 
547
  max_length=args.max_length,
548
  )
549
 
550
+ logger.info("[DONE] 蒸馏训练完成!")
551
 
552
 
553
  if __name__ == "__main__":
inference/dashboard.py CHANGED
@@ -252,7 +252,8 @@ class InferenceEngine:
252
  self.kv_cache = outputs.past_key_values
253
 
254
  # Decode only new tokens
255
- new_tokens = generated[len(self._tokenize(prompt)[0]):]
 
256
  return self._detokenize(new_tokens)
257
 
258
  def _generate_stream(self, input_ids, cfg) -> Generator:
 
252
  self.kv_cache = outputs.past_key_values
253
 
254
  # Decode only new tokens
255
+ prompt_len = self._tokenize(prompt).shape[1]
256
+ new_tokens = generated[prompt_len:]
257
  return self._detokenize(new_tokens)
258
 
259
  def _generate_stream(self, input_ids, cfg) -> Generator:
inference/dyquant.py CHANGED
@@ -432,8 +432,10 @@ class DyQuantConverter:
432
 
433
  # 1. 加载模型
434
  if self.model is None:
435
- self.load_model()
436
-
 
 
437
  if self.model is None:
438
  print(f"[DyQuant] 无法加载模型,返回 None")
439
  return None
 
432
 
433
  # 1. 加载模型
434
  if self.model is None:
435
+ result = self.load_model()
436
+ if result is not None:
437
+ self.model = result
438
+
439
  if self.model is None:
440
  print(f"[DyQuant] 无法加载模型,返回 None")
441
  return None
inference/ollama_deploy.py CHANGED
@@ -34,14 +34,14 @@ def check_dependencies():
34
  """
35
  检查依赖项
36
  """
37
- logger.info("🔍 检查依赖项...")
38
 
39
  # 检查 llama.cpp 转换脚本
40
  llama_cpp_dir = os.environ.get("LLAMA_CPP_DIR", "")
41
  convert_script = os.path.join(llama_cpp_dir, "convert-hf-to-gguf.py")
42
 
43
  if not os.path.exists(convert_script):
44
- logger.warning(f"⚠️ 未找到 llama.cpp 转换脚本:{convert_script}")
45
  logger.warning(" 请设置环境变量 LLAMA_CPP_DIR 或手动下载 llama.cpp")
46
  logger.warning(" 下载地址:<ADDRESS_REMOVED>
47
  return False
@@ -54,17 +54,17 @@ def check_dependencies():
54
  text=True,
55
  )
56
  if result.returncode == 0:
57
- logger.info(f" Ollama 已安装:{result.stdout.strip()}")
58
  else:
59
- logger.warning("⚠️ Ollama 未安装或无法运行")
60
  logger.warning(" 请访问 https://ollama.com 安装")
61
  return False
62
  except FileNotFoundError:
63
- logger.warning("⚠️ Ollama 未安装")
64
  logger.warning(" 请访问 https://ollama.com 安装")
65
  return False
66
 
67
- logger.info(" 依赖项检查通过")
68
  return True
69
 
70
 
@@ -81,7 +81,7 @@ def convert_to_gguf(
81
  output_path: 输出路径
82
  quantize: 量化级别(q4_k_m, q5_k_m, q8_0 等)
83
  """
84
- logger.info("🔄 转换为 GGUF 格式...")
85
 
86
  llama_cpp_dir = os.environ.get("LLAMA_CPP_DIR", "")
87
  convert_script = os.path.join(llama_cpp_dir, "convert-hf-to-gguf.py")
@@ -99,14 +99,14 @@ def convert_to_gguf(
99
  result = subprocess.run(cmd, capture_output=True, text=True)
100
 
101
  if result.returncode != 0:
102
- logger.error(f" 转换失败:{result.stderr}")
103
  raise RuntimeError("GGUF 转换失败")
104
 
105
- logger.info(f" GGUF 转换完成:{output_path}")
106
 
107
  # 量化(可选)
108
  if quantize:
109
- logger.info(f"🔧 量化模型({quantize})...")
110
 
111
  quantize_cmd = [
112
  os.path.join(llama_cpp_dir, "llama-quantize"),
@@ -118,11 +118,11 @@ def convert_to_gguf(
118
  result = subprocess.run(quantize_cmd, capture_output=True, text=True)
119
 
120
  if result.returncode != 0:
121
- logger.warning(f"⚠️ 量化失败:{result.stderr}")
122
  logger.warning(" 继续使用未量化模型")
123
  else:
124
  output_path = output_path.replace(".gguf", f"_{quantize}.gguf")
125
- logger.info(f" 量化完成:{output_path}")
126
 
127
  return output_path
128
 
@@ -144,7 +144,7 @@ def create_modelfile(
144
  context_size: 上下文窗口大小
145
  thinking_dial: 是否启用 Thinking Dial
146
  """
147
- logger.info("📝 创建 Modelfile...")
148
 
149
  # Modelfile 内容
150
  content = f"""# Fusion 模型:{model_name}
@@ -189,7 +189,7 @@ TEMPLATE \"\"\"{{ if .System }}<|im_start|>system
189
  with open(modelfile_path, 'w', encoding='utf-8') as f:
190
  f.write(content)
191
 
192
- logger.info(f" Modelfile 创建完成:{modelfile_path}")
193
 
194
 
195
  def create_ollama_model(modelfile_path: str, model_name: str):
@@ -200,7 +200,7 @@ def create_ollama_model(modelfile_path: str, model_name: str):
200
  modelfile_path: Modelfile 路径
201
  model_name: 模型名称
202
  """
203
- logger.info(f"🚀 创建 Ollama 模型:{model_name}...")
204
 
205
  # 删除已存在的模型
206
  subprocess.run(
@@ -216,10 +216,10 @@ def create_ollama_model(modelfile_path: str, model_name: str):
216
  result = subprocess.run(cmd, capture_output=True, text=True)
217
 
218
  if result.returncode != 0:
219
- logger.error(f" 创建失败:{result.stderr}")
220
  raise RuntimeError("Ollama 模型创建失败")
221
 
222
- logger.info(f" Ollama 模型创建成功:{model_name}")
223
  logger.info(f" 运行 `ollama run {model_name}` 开始使用")
224
 
225
 
@@ -242,13 +242,13 @@ def deploy(
242
  context_size: 上下文窗口
243
  thinking_dial: 是否启用 Thinking Dial
244
  """
245
- logger.info("🚀 开始 Ollama 部署流程...")
246
  logger.info(f" 模型路径:{model_path}")
247
  logger.info(f" 模型名称:{model_name}")
248
 
249
  # 1. 检查依赖
250
  if not check_dependencies():
251
- logger.error(" 依赖项检查失败,请先安装所需工具")
252
  return False
253
 
254
  # 2. 创建输出目录
@@ -263,7 +263,7 @@ def deploy(
263
  quantize=quantize,
264
  )
265
  except RuntimeError as e:
266
- logger.error(f" GGUF 转换失败:{e}")
267
  return False
268
 
269
  # 4. 创建 Modelfile
@@ -283,14 +283,14 @@ def deploy(
283
  model_name=model_name,
284
  )
285
  except RuntimeError as e:
286
- logger.error(f" Ollama 模型创建失败:{e}")
287
  return False
288
 
289
  # 6. 生成使用示例
290
  example_path = os.path.join(output_dir, "USAGE.md")
291
  generate_usage_example(model_name, example_path)
292
 
293
- logger.info(" 部署完成!")
294
  logger.info(f" 运行:`ollama run {model_name}`")
295
  logger.info(f" 示例:见 {example_path}")
296
 
@@ -392,7 +392,7 @@ ollama run {model_name} --top_p 0.95
392
  with open(output_path, 'w', encoding='utf-8') as f:
393
  f.write(content)
394
 
395
- logger.info(f"📖 使用示例已生成:{output_path}")
396
 
397
 
398
  def main():
@@ -426,9 +426,9 @@ def main():
426
  )
427
 
428
  if success:
429
- logger.info("🎉 部署成功!")
430
  else:
431
- logger.error(" 部署失败")
432
 
433
 
434
  if __name__ == "__main__":
 
34
  """
35
  检查依赖项
36
  """
37
+ logger.info("[SEARCH] 检查依赖项...")
38
 
39
  # 检查 llama.cpp 转换脚本
40
  llama_cpp_dir = os.environ.get("LLAMA_CPP_DIR", "")
41
  convert_script = os.path.join(llama_cpp_dir, "convert-hf-to-gguf.py")
42
 
43
  if not os.path.exists(convert_script):
44
+ logger.warning(f"[WARN][LOGO] 未找到 llama.cpp 转换脚本:{convert_script}")
45
  logger.warning(" 请设置环境变量 LLAMA_CPP_DIR 或手动下载 llama.cpp")
46
  logger.warning(" 下载地址:<ADDRESS_REMOVED>
47
  return False
 
54
  text=True,
55
  )
56
  if result.returncode == 0:
57
+ logger.info(f"[OK] Ollama 已安装:{result.stdout.strip()}")
58
  else:
59
+ logger.warning("[WARN][LOGO] Ollama 未安装或无法运行")
60
  logger.warning(" 请访问 https://ollama.com 安装")
61
  return False
62
  except FileNotFoundError:
63
+ logger.warning("[WARN][LOGO] Ollama 未安装")
64
  logger.warning(" 请访问 https://ollama.com 安装")
65
  return False
66
 
67
+ logger.info("[OK] 依赖项检查通过")
68
  return True
69
 
70
 
 
81
  output_path: 输出路径
82
  quantize: 量化级别(q4_k_m, q5_k_m, q8_0 等)
83
  """
84
+ logger.info("[SYNC] 转换为 GGUF 格式...")
85
 
86
  llama_cpp_dir = os.environ.get("LLAMA_CPP_DIR", "")
87
  convert_script = os.path.join(llama_cpp_dir, "convert-hf-to-gguf.py")
 
99
  result = subprocess.run(cmd, capture_output=True, text=True)
100
 
101
  if result.returncode != 0:
102
+ logger.error(f"[FAIL] 转换失败:{result.stderr}")
103
  raise RuntimeError("GGUF 转换失败")
104
 
105
+ logger.info(f"[OK] GGUF 转换完成:{output_path}")
106
 
107
  # 量化(可选)
108
  if quantize:
109
+ logger.info(f"[TOOL] 量化模型({quantize})...")
110
 
111
  quantize_cmd = [
112
  os.path.join(llama_cpp_dir, "llama-quantize"),
 
118
  result = subprocess.run(quantize_cmd, capture_output=True, text=True)
119
 
120
  if result.returncode != 0:
121
+ logger.warning(f"[WARN][LOGO] 量化失败:{result.stderr}")
122
  logger.warning(" 继续使用未量化模型")
123
  else:
124
  output_path = output_path.replace(".gguf", f"_{quantize}.gguf")
125
+ logger.info(f"[OK] 量化完成:{output_path}")
126
 
127
  return output_path
128
 
 
144
  context_size: 上下文窗口大小
145
  thinking_dial: 是否启用 Thinking Dial
146
  """
147
+ logger.info("[NOTE] 创建 Modelfile...")
148
 
149
  # Modelfile 内容
150
  content = f"""# Fusion 模型:{model_name}
 
189
  with open(modelfile_path, 'w', encoding='utf-8') as f:
190
  f.write(content)
191
 
192
+ logger.info(f"[OK] Modelfile 创建完成:{modelfile_path}")
193
 
194
 
195
  def create_ollama_model(modelfile_path: str, model_name: str):
 
200
  modelfile_path: Modelfile 路径
201
  model_name: 模型名称
202
  """
203
+ logger.info(f"[GO] 创建 Ollama 模型:{model_name}...")
204
 
205
  # 删除已存在的模型
206
  subprocess.run(
 
216
  result = subprocess.run(cmd, capture_output=True, text=True)
217
 
218
  if result.returncode != 0:
219
+ logger.error(f"[FAIL] 创建失败:{result.stderr}")
220
  raise RuntimeError("Ollama 模型创建失败")
221
 
222
+ logger.info(f"[OK] Ollama 模型创建成功:{model_name}")
223
  logger.info(f" 运行 `ollama run {model_name}` 开始使用")
224
 
225
 
 
242
  context_size: 上下文窗口
243
  thinking_dial: 是否启用 Thinking Dial
244
  """
245
+ logger.info("[GO] 开始 Ollama 部署流程...")
246
  logger.info(f" 模型路径:{model_path}")
247
  logger.info(f" 模型名称:{model_name}")
248
 
249
  # 1. 检查依赖
250
  if not check_dependencies():
251
+ logger.error("[FAIL] 依赖项检查失败,请先安装所需工具")
252
  return False
253
 
254
  # 2. 创建输出目录
 
263
  quantize=quantize,
264
  )
265
  except RuntimeError as e:
266
+ logger.error(f"[FAIL] GGUF 转换失败:{e}")
267
  return False
268
 
269
  # 4. 创建 Modelfile
 
283
  model_name=model_name,
284
  )
285
  except RuntimeError as e:
286
+ logger.error(f"[FAIL] Ollama 模型创建失败:{e}")
287
  return False
288
 
289
  # 6. 生成使用示例
290
  example_path = os.path.join(output_dir, "USAGE.md")
291
  generate_usage_example(model_name, example_path)
292
 
293
+ logger.info("[OK] 部署完成!")
294
  logger.info(f" 运行:`ollama run {model_name}`")
295
  logger.info(f" 示例:见 {example_path}")
296
 
 
392
  with open(output_path, 'w', encoding='utf-8') as f:
393
  f.write(content)
394
 
395
+ logger.info(f"[LOGO] 使用示例已生成:{output_path}")
396
 
397
 
398
  def main():
 
426
  )
427
 
428
  if success:
429
+ logger.info("[DONE] 部署成功!")
430
  else:
431
+ logger.error("[FAIL] 部署失败")
432
 
433
 
434
  if __name__ == "__main__":
models/__init__.py CHANGED
@@ -2,10 +2,10 @@
2
  Fusion 模型架构
3
 
4
  包含:
5
- - fusion_mini.py: 极简可运行版本(用于验证流程) 已实现
6
- - fusion_model.py: 完整 Transformer 模型定义(SBLA + Thinking Dial) 已实现
7
- - sbla_attention.py: SBLA 注意力(滑动分块潜注意力) 已实现
8
- - thinking_dial.py: 动态推理强度调节器(Thinking Dial) 已实现
9
 
10
  使用方法:
11
  # 极简版本(字符级训练验证)
 
2
  Fusion 模型架构
3
 
4
  包含:
5
+ - fusion_mini.py: 极简可运行版本(用于验证流程)[OK] 已实现
6
+ - fusion_model.py: 完整 Transformer 模型定义(SBLA + Thinking Dial)[OK] 已实现
7
+ - sbla_attention.py: SBLA 注意力(滑动分块潜注意力)[OK] 已实现
8
+ - thinking_dial.py: 动态推理强度调节器(Thinking Dial)[OK] 已实现
9
 
10
  使用方法:
11
  # 极简版本(字符级训练验证)
models/fusion_mini.py CHANGED
@@ -481,7 +481,7 @@ class FusionMini(PreTrainedModel):
481
 
482
  if __name__ == "__main__":
483
  # 单元测试
484
- print("🧪 测试 Fusion Mini 模型...")
485
 
486
  # 创建配置
487
  config = FusionMiniConfig(
@@ -492,7 +492,7 @@ if __name__ == "__main__":
492
  intermediate_size=512,
493
  )
494
 
495
- print(f" 配置创建成功")
496
  print(f" 词表大小:{config.vocab_size}")
497
  print(f" 隐层大小:{config.hidden_size}")
498
  print(f" 层数:{config.num_hidden_layers}")
@@ -500,7 +500,7 @@ if __name__ == "__main__":
500
  # 创建模型
501
  model = FusionMini(config)
502
 
503
- print(f"\n 模型创建成功")
504
  print(f" 参数量:{sum(p.numel() for p in model.parameters()) / 1e3:.1f}K")
505
 
506
  # 测试前向传播
@@ -517,7 +517,7 @@ if __name__ == "__main__":
517
  return_dict=True,
518
  )
519
 
520
- print(f"\n 前向传播测试通过")
521
  print(f" Loss: {outputs['loss'].item():.4f}")
522
  print(f" Logits 形状: {outputs['logits'].shape}")
523
 
@@ -527,11 +527,11 @@ if __name__ == "__main__":
527
  max_new_tokens=20,
528
  )
529
 
530
- print(f"\n 生成测试通过")
531
  print(f" 生成形状: {generated.shape}")
532
 
533
- print("\n🎉 Fusion Mini 测试完成!")
534
- print("\n💡 下一步:")
535
  print(" 1. 使用真实数据训练这个 mini 模型")
536
  print(" 2. 验证训练流程")
537
  print(" 3. 然后实现 SBLA 和 Thinking Dial")
 
481
 
482
  if __name__ == "__main__":
483
  # 单元测试
484
+ print("[LOGO] 测试 Fusion Mini 模型...")
485
 
486
  # 创建配置
487
  config = FusionMiniConfig(
 
492
  intermediate_size=512,
493
  )
494
 
495
+ print(f"[OK] 配置创建成功")
496
  print(f" 词表大小:{config.vocab_size}")
497
  print(f" 隐层大小:{config.hidden_size}")
498
  print(f" 层数:{config.num_hidden_layers}")
 
500
  # 创建模型
501
  model = FusionMini(config)
502
 
503
+ print(f"\n[OK] 模型创建成功")
504
  print(f" 参数量:{sum(p.numel() for p in model.parameters()) / 1e3:.1f}K")
505
 
506
  # 测试前向传播
 
517
  return_dict=True,
518
  )
519
 
520
+ print(f"\n[OK] 前向传播测试通过")
521
  print(f" Loss: {outputs['loss'].item():.4f}")
522
  print(f" Logits 形状: {outputs['logits'].shape}")
523
 
 
527
  max_new_tokens=20,
528
  )
529
 
530
+ print(f"\n[OK] 生成测试通过")
531
  print(f" 生成形状: {generated.shape}")
532
 
533
+ print("\n[DONE] Fusion Mini 测试完成!")
534
+ print("\n[TIP] 下一步:")
535
  print(" 1. 使用真实数据训练这个 mini 模型")
536
  print(" 2. 验证训练流程")
537
  print(" 3. 然后实现 SBLA 和 Thinking Dial")
scripts/add_depth3_samples.py DELETED
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Add depth=3 samples to mini_data.json for Thinking Dial coverage."""
3
-
4
- import json
5
-
6
- DEPTH_3_SAMPLES = [
7
- {"prompt": "Prove the Pythagorean theorem", "response": "Consider a right triangle with legs a, b and hypotenuse c. Construct a square of side (a+b) and arrange four copies of the triangle inside. The inner quadrilateral is a square of side c, so (a+b)^2 = c^2 + 4*(ab/2), which simplifies to a^2 + b^2 = c^2.", "think_rank": 3},
8
- {"prompt": "Derive the quadratic formula", "response": "Starting from ax^2 + bx + c = 0, divide by a, complete the square: (x + b/2a)^2 = (b^2 - 4ac)/4a^2. Taking the square root gives x = (-b +- sqrt(b^2 - 4ac)) / 2a.", "think_rank": 3},
9
- {"prompt": "Prove that sqrt(2) is irrational", "response": "Assume sqrt(2) = p/q in lowest terms. Then 2q^2 = p^2, so p is even. Write p = 2k, then 2q^2 = 4k^2, so q^2 = 2k^2, meaning q is also even. This contradicts p/q being in lowest terms.", "think_rank": 3},
10
- {"prompt": "Prove there are infinitely many primes", "response": "Suppose finitely many primes p1,...,pn exist. Let N = p1*p2*...*pn + 1. N is not divisible by any pi (remainder 1). So N is either prime itself or has a prime factor not in the list. Contradiction.", "think_rank": 3},
11
- {"prompt": "Derive the derivative of sin(x)", "response": "Using the limit definition: d/dx sin(x) = lim(h->0) [sin(x+h) - sin(x)] / h. Apply the angle addition formula: sin(x+h) = sin(x)cos(h) + cos(x)sin(h). This gives lim [sin(x)(cos(h)-1)/h + cos(x)sin(h)/h] = sin(x)*0 + cos(x)*1 = cos(x).", "think_rank": 3},
12
- {"prompt": "Analyze the time complexity of merge sort", "response": "Merge sort divides the array in half (O(1)), recurses on both halves (2T(n/2)), and merges in O(n). The recurrence T(n) = 2T(n/2) + O(n) solves to O(n log n) by the master theorem (case 2). This holds for worst, average, and best cases.", "think_rank": 3},
13
- {"prompt": "Prove the sum of first n natural numbers is n(n+1)/2", "response": "By induction: Base case n=1: 1 = 1(2)/2 = 1. Inductive step: assume S(k) = k(k+1)/2. Then S(k+1) = S(k) + (k+1) = k(k+1)/2 + (k+1) = (k+1)(k/2 + 1) = (k+1)(k+2)/2. QED.", "think_rank": 3},
14
- {"prompt": "Prove that e^x converges for all x", "response": "The Taylor series e^x = sum(x^n/n!) has ratio test: |a_(n+1)/a_n| = |x|/(n+1) -> 0 as n -> infinity. Since the limit is 0 < 1 for all x, the series converges absolutely for all real x by the ratio test.", "think_rank": 3},
15
- ]
16
-
17
- def main():
18
- with open('data/mini_data.json', 'r', encoding='utf-8') as f:
19
- data = json.load(f)
20
-
21
- old_dist = {}
22
- for item in data:
23
- r = item.get('think_rank', 0)
24
- old_dist[r] = old_dist.get(r, 0) + 1
25
- print(f"Before: {old_dist}")
26
-
27
- data.extend(DEPTH_3_SAMPLES)
28
-
29
- new_dist = {}
30
- for item in data:
31
- r = item.get('think_rank', 0)
32
- new_dist[r] = new_dist.get(r, 0) + 1
33
- print(f"After: {new_dist}")
34
-
35
- with open('data/mini_data.json', 'w', encoding='utf-8') as f:
36
- json.dump(data, f, ensure_ascii=False, indent=2)
37
-
38
- print(f"Total: {len(data)} items")
39
-
40
-
41
- if __name__ == '__main__':
42
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/create_mini_data.py DELETED
@@ -1,126 +0,0 @@
1
- """
2
- 创建 Fusion Mini 训练数据
3
-
4
- 生成极简的训练数据(字符级),用于验证完整训练流程。
5
-
6
- 使用方法:
7
- python tests/create_mini_data.py
8
-
9
- # 会生成 data/mini_data.json
10
-
11
- 作者:zhan1206
12
- 项目:Fusion - 六边形开源大模型
13
- 许可证:Apache 2.0
14
- """
15
-
16
- import json
17
- import random
18
- from pathlib import Path
19
-
20
-
21
- def create_mini_dataset(output_path: str, num_samples: int = 100):
22
- """
23
- 创建 mini 训练数据集
24
-
25
- 参数:
26
- output_path: 输出文件路径
27
- num_samples: 样本数量
28
- """
29
- print("[数据] 创建 mini 训练数据集...")
30
- print(f" 输出路径:{output_path}")
31
- print(f" 样本数量:{num_samples}")
32
-
33
- data = []
34
-
35
- # 预定义一些简单的中文和英文句子
36
- chinese_samples = [
37
- ("你好", "你好!我是 Fusion Mini 模型。"),
38
- ("什么是人工智能", "人工智能是计算机科学的一个分支,致力于创建智能机器。"),
39
- ("解释机器学习", "机器学习是人工智能的子领域,使计算机能够从数据中学习。"),
40
- ("深度学习是什么", "深度学习是机器学习的一个分支,使用多层神经网络模拟人脑。"),
41
- ("什么是自然语言处理", "自然语言处理是AI的一个分支,帮助计算机理解人类语言。"),
42
- ("Python 有什么特点", "Python 是一种简单易学、功能强大的编程语言。"),
43
- ("如何学习编程", "学习编程需要理论与实践相结合,多写代码多思考。"),
44
- ("什么是大数据", "大数据是指规模巨大、类型多样的数据集合。"),
45
- ("云计算的优势", "云计算提供弹性扩展、成本节约、易于维护等优势。"),
46
- ("区块链的原理", "区块链是一种分布式账本技术,确保数据不可篡改。"),
47
- ]
48
-
49
- english_samples = [
50
- ("Hello", "Hello! I am Fusion Mini model."),
51
- ("What is AI", "AI stands for Artificial Intelligence."),
52
- ("Explain machine learning", "Machine learning is a subset of AI."),
53
- ("What is deep learning", "Deep learning uses neural networks with many layers."),
54
- ("What is NLP", "NLP helps computers understand human language."),
55
- ("Python features", "Python is simple, powerful, and versatile."),
56
- ("How to learn coding", "Practice coding regularly and build projects."),
57
- ("What is big data", "Big data refers to extremely large datasets."),
58
- ("Benefits of cloud computing", "Cloud computing offers scalability and cost savings."),
59
- ("How blockchain works", "Blockchain is a distributed ledger technology."),
60
- ]
61
-
62
- # 生成样本
63
- for i in range(num_samples):
64
- # 随机选择中文或英文
65
- if random.random() > 0.5:
66
- prompt, response = random.choice(chinese_samples)
67
- else:
68
- prompt, response = random.choice(english_samples)
69
-
70
- # Assign think_rank based on content depth
71
- if any(kw in prompt for kw in ["Prove", "Derive", "Analyze", "\u8bc1\u660e", "\u63a8\u5bfc", "\u5206\u6790"]):
72
- think_rank = 3
73
- elif any(kw in prompt for kw in ["Explain", "How", "Why", "\u89e3\u91ca", "\u5982\u4f55", "\u4e3a\u4ec0\u4e48"]):
74
- think_rank = 2
75
- elif any(kw in prompt for kw in ["Write", "Implement", "\u5199", "\u5b9e\u73b0"]):
76
- think_rank = 1
77
- else:
78
- think_rank = 0
79
-
80
- data.append({
81
- "prompt": prompt,
82
- "response": response,
83
- "think_rank": think_rank,
84
- })
85
-
86
- # 保存为 JSON
87
- output_file = Path(output_path)
88
- output_file.parent.mkdir(parents=True, exist_ok=True)
89
-
90
- with open(output_file, 'w', encoding='utf-8') as f:
91
- json.dump(data, f, ensure_ascii=False, indent=2)
92
-
93
- print("[完成] 数据集创建成功!")
94
- print(f" 文件路径:{output_path}")
95
- print(f" 样本数量:{len(data)}")
96
-
97
- # 显示几个示例
98
- print("\n[示例] 数据示例:")
99
- for i, item in enumerate(data[:3]):
100
- print(f" [{i+1}] Prompt: {item['prompt']}")
101
- print(f" Response: {item['response'][:50]}...")
102
- print()
103
-
104
-
105
- def main():
106
- print("=" * 60)
107
- print("创建 Fusion Mini 训练数据")
108
- print("=" * 60)
109
-
110
- # 创建输出目录
111
- output_dir = Path("data")
112
- output_dir.mkdir(exist_ok=True)
113
-
114
- # 生成训练数据
115
- output_path = output_dir / "mini_data.json"
116
- create_mini_dataset(output_path, num_samples=100)
117
-
118
- print(f"\n[完成] 数据创建完成!")
119
- print(f"\n下一步:")
120
- print(f" 1. 检查数据文件:{output_path}")
121
- print(f" 2. 开始训练:python train/train_mini.py")
122
- print(f" 3. 或者运行完整测试:python tests/run_tests.py")
123
-
124
-
125
- if __name__ == "__main__":
126
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/dedup_mini_data.py DELETED
@@ -1,120 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Deduplicate and expand mini_data.json to reduce duplication rate.
4
- Target: <20% duplication, >= 80 unique prompts.
5
-
6
- Author: Zhu Zizhan
7
- Project: Fusion-LLM
8
- License: Apache 2.0
9
- """
10
-
11
- import json
12
- import random
13
- from pathlib import Path
14
-
15
- # Diverse samples covering all think_rank levels
16
- NEW_SAMPLES = [
17
- # think_rank=0: Simple Q&A
18
- {"prompt": "Hello", "response": "Hello! How can I help you today?", "think_rank": 0},
19
- {"prompt": "What is Python", "response": "Python is a high-level programming language known for its readability and versatility.", "think_rank": 0},
20
- {"prompt": "Define API", "response": "API stands for Application Programming Interface, a set of rules for software communication.", "think_rank": 0},
21
- {"prompt": "What is HTML", "response": "HTML is the standard markup language for creating web pages.", "think_rank": 0},
22
- {"prompt": "Name a search engine", "response": "Google is the most widely used search engine.", "think_rank": 0},
23
- {"prompt": "What does CPU stand for", "response": "CPU stands for Central Processing Unit, the brain of a computer.", "think_rank": 0},
24
- {"prompt": "What is RAM", "response": "RAM is Random Access Memory, used for temporary data storage during program execution.", "think_rank": 0},
25
- {"prompt": "What is WiFi", "response": "WiFi is a wireless networking technology for internet connectivity.", "think_rank": 0},
26
- {"prompt": "What is a database", "response": "A database is an organized collection of structured data stored electronically.", "think_rank": 0},
27
- {"prompt": "What is an operating system", "response": "An operating system manages hardware and software resources on a computer.", "think_rank": 0},
28
- {"prompt": "What is cloud storage", "response": "Cloud storage saves data on remote servers accessed via the internet.", "think_rank": 0},
29
- {"prompt": "What is encryption", "response": "Encryption converts data into a coded format to prevent unauthorized access.", "think_rank": 0},
30
- {"prompt": "What is a URL", "response": "A URL is a web address that specifies the location of a resource on the internet.", "think_rank": 0},
31
- {"prompt": "What is a browser", "response": "A browser is software for accessing and viewing websites on the internet.", "think_rank": 0},
32
- {"prompt": "What is open source", "response": "Open source software has source code that anyone can inspect, modify, and distribute.", "think_rank": 0},
33
-
34
- # think_rank=1: Writing/implementation tasks
35
- {"prompt": "Write a function to reverse a string", "response": "def reverse_string(s): return s[::-1]", "think_rank": 1},
36
- {"prompt": "Implement a function to check if a number is prime", "response": "def is_prime(n): return n > 1 and all(n % i != 0 for i in range(2, int(n**0.5) + 1))", "think_rank": 1},
37
- {"prompt": "Write a function to calculate factorial", "response": "def factorial(n): return 1 if n <= 1 else n * factorial(n - 1)", "think_rank": 1},
38
- {"prompt": "Implement binary search in Python", "response": "def binary_search(arr, target):\n lo, hi = 0, len(arr) - 1\n while lo <= hi:\n mid = (lo + hi) // 2\n if arr[mid] == target: return mid\n elif arr[mid] < target: lo = mid + 1\n else: hi = mid - 1\n return -1", "think_rank": 1},
39
- {"prompt": "Write a function to sort a list", "response": "def sort_list(lst): return sorted(lst)", "think_rank": 1},
40
- {"prompt": "Implement a stack data structure", "response": "class Stack:\n def __init__(self): self.items = []\n def push(self, item): self.items.append(item)\n def pop(self): return self.items.pop() if self.items else None", "think_rank": 1},
41
- {"prompt": "Write code to read a CSV file", "response": "import csv\nwith open('file.csv') as f:\n reader = csv.reader(f)\n for row in reader: print(row)", "think_rank": 1},
42
- {"prompt": "Implement a linked list node", "response": "class Node:\n def __init__(self, val, next=None):\n self.val = val\n self.next = next", "think_rank": 1},
43
- {"prompt": "Write a function to count words in text", "response": "def count_words(text): return len(text.split())", "think_rank": 1},
44
- {"prompt": "Implement a simple HTTP GET request", "response": "import requests\nresponse = requests.get('https://api.example.com/data')\nprint(response.json())", "think_rank": 1},
45
-
46
- # think_rank=2: Explain/compare/analyze
47
- {"prompt": "Explain how neural networks learn", "response": "Neural networks learn through backpropagation: they compute predictions, measure error using a loss function, calculate gradients of the loss with respect to weights, and update weights using gradient descent to minimize error.", "think_rank": 2},
48
- {"prompt": "Compare REST and GraphQL", "response": "REST uses fixed endpoints returning predetermined data structures. GraphQL uses a single endpoint where clients specify exactly which fields they need, reducing over-fetching but adding query complexity.", "think_rank": 2},
49
- {"prompt": "Explain the difference between SQL and NoSQL", "response": "SQL databases use structured tables with fixed schemas and ACID transactions. NoSQL databases use flexible document/key-value/graph models optimized for scale and schema evolution, often trading consistency for availability.", "think_rank": 2},
50
- {"prompt": "How does garbage collection work in Python", "response": "Python uses reference counting as the primary mechanism and a cyclic garbage collector for detecting and collecting reference cycles. Objects with zero references are freed immediately; cycles are detected periodically.", "think_rank": 2},
51
- {"prompt": "Explain the Transformer attention mechanism", "response": "Self-attention computes queries, keys, and values from input. Attention scores are the dot product of queries and keys, scaled by sqrt(d_k), softmaxed, then multiplied by values. This lets each position attend to all other positions.", "think_rank": 2},
52
- {"prompt": "Why is batch normalization important", "response": "Batch normalization stabilizes training by normalizing layer inputs to zero mean and unit variance. This reduces internal covariate shift, allows higher learning rates, and acts as a regularizer, improving convergence.", "think_rank": 2},
53
- {"prompt": "How does DNS resolution work", "response": "DNS resolution follows a hierarchy: browser cache -> OS cache -> recursive resolver -> root server -> TLD server -> authoritative server. Each step either returns the answer or delegates to the next level.", "think_rank": 2},
54
- {"prompt": "Explain the difference between threads and processes", "response": "Threads share memory within a process, making communication fast but requiring synchronization. Processes have separate memory spaces, providing isolation but slower inter-process communication. Threads are lighter; processes are safer.", "think_rank": 2},
55
- {"prompt": "How does caching improve performance", "response": "Caching stores frequently accessed data in fast-access storage (memory vs disk). This reduces latency, decreases backend load, and improves throughput. Cache invalidation strategies (TTL, LRU) balance freshness with hit rate.", "think_rank": 2},
56
- {"prompt": "Explain how gradient descent optimization works", "response": "Gradient descent iteratively updates parameters in the opposite direction of the gradient of the loss function. Learning rate controls step size. Variants include SGD (mini-batches), Adam (adaptive rates), and momentum (acceleration).", "think_rank": 2},
57
-
58
- # think_rank=3: Prove/derive/complex analysis
59
- {"prompt": "Prove the Pythagorean theorem", "response": "Consider a right triangle with legs a, b and hypotenuse c. Construct a square of side (a+b) with four copies of the triangle. The inner quadrilateral has side c and is a square, so (a+b)^2 = c^2 + 4*(ab/2), yielding a^2 + b^2 = c^2.", "think_rank": 3},
60
- {"prompt": "Derive the quadratic formula", "response": "From ax^2 + bx + c = 0, divide by a, complete the square: (x + b/2a)^2 = (b^2 - 4ac)/4a^2. Taking the square root gives x = (-b +/- sqrt(b^2 - 4ac)) / 2a.", "think_rank": 3},
61
- {"prompt": "Prove that sqrt(2) is irrational", "response": "Assume sqrt(2) = p/q in lowest terms. Then 2q^2 = p^2, so p is even. Write p = 2k, then 2q^2 = 4k^2, so q^2 = 2k^2, meaning q is also even. Contradiction: both p and q are even, not in lowest terms.", "think_rank": 3},
62
- {"prompt": "Prove there are infinitely many primes", "response": "Suppose finitely many primes p1,...,pn. Let N = p1*p2*...*pn + 1. N is not divisible by any pi (remainder 1). So N is prime or has a prime factor not in the list. Either way, contradiction.", "think_rank": 3},
63
- {"prompt": "Derive the derivative of sin(x)", "response": "Using the limit definition: d/dx sin(x) = lim(h->0) [sin(x+h) - sin(x)] / h. Apply angle addition: sin(x+h) = sin(x)cos(h) + cos(x)sin(h). This gives sin(x)(cos(h)-1)/h + cos(x)sin(h)/h -> sin(x)*0 + cos(x)*1 = cos(x).", "think_rank": 3},
64
- {"prompt": "Analyze the time complexity of merge sort", "response": "Merge sort divides the array in half O(1), recurses on both halves 2T(n/2), and merges in O(n). The recurrence T(n) = 2T(n/2) + O(n) solves to O(n log n) by the master theorem case 2. This holds for worst, average, and best cases.", "think_rank": 3},
65
- {"prompt": "Prove that the harmonic series diverges", "response": "Group terms: 1 + 1/2 + (1/3+1/4) + (1/5+...+1/8) + ... Each group >= 1/2 (since each of the 2^k terms in group k is >= 1/2^(k+1)). The partial sums grow without bound, so the series diverges.", "think_rank": 3},
66
- {"prompt": "Derive the normal distribution formula", "response": "The normal distribution maximizes entropy subject to fixed mean and variance. Using Lagrange multipliers on the variational problem with constraints on integral, mean, and variance, we get f(x) = (1/sqrt(2*pi*sigma^2)) * exp(-(x-mu)^2/(2*sigma^2)).", "think_rank": 3},
67
-
68
- # Chinese samples (all ranks)
69
- {"prompt": "你好", "response": "你好!很高兴见到你,有什么可以帮助你的吗?", "think_rank": 0},
70
- {"prompt": "什么是���法", "response": "算法是解决特定问题的一系列明确步骤或规则。", "think_rank": 0},
71
- {"prompt": "什么是互联网", "response": "互联网是全球计算机网络的互联系统,提供信息交流和资源共享。", "think_rank": 0},
72
- {"prompt": "什么是编程", "response": "编程是使用编程语言编写指令,让计算机执行特定任务的过程。", "think_rank": 0},
73
- {"prompt": "什么是数据结构", "response": "数据结构是组织和存储数据的方式,如数组、链表、树和图。", "think_rank": 0},
74
- {"prompt": "什么是人工智能", "response": "人工智能是计算机科学的一个分支,致力于创建智能机器。", "think_rank": 0},
75
- {"prompt": "写一个快速排序函数", "response": "def quicksort(arr):\n if len(arr) <= 1: return arr\n pivot = arr[len(arr)//2]\n left = [x for x in arr if x < pivot]\n middle = [x for x in arr if x == pivot]\n right = [x for x in arr if x > pivot]\n return quicksort(left) + middle + quicksort(right)", "think_rank": 1},
76
- {"prompt": "写一个斐波那契数列函数", "response": "def fibonacci(n):\n if n <= 1: return n\n a, b = 0, 1\n for _ in range(2, n+1):\n a, b = b, a+b\n return b", "think_rank": 1},
77
- {"prompt": "实现一个简单的HTTP服务器", "response": "from http.server import HTTPServer, BaseHTTPRequestHandler\nclass Handler(BaseHTTPRequestHandler):\n def do_GET(self):\n self.send_response(200)\n self.end_headers()\n self.wfile.write(b'Hello')\nHTTPServer(('', 8000), Handler).serve_forever()", "think_rank": 1},
78
- {"prompt": "解释深度学习与传统机器学习的区别", "response": "传统机器学习需要手动特征工程,模型较浅。深度学习使用多层神经网络自动学习特征表示,在图像、语音、文本等任务上表现更优,但需要更多数据和计算资源。", "think_rank": 2},
79
- {"prompt": "为什么需要正则化", "response": "正则化防止模型过拟合训练数据。L1正则化产生稀疏权重(特征选择),L2正则化惩罚大权重(权重衰减)。Dropout是另一种正则化方式,随机屏蔽神经元防止共适应。", "think_rank": 2},
80
- {"prompt": "解释TCP三次握手", "response": "客户端发送SYN包,服务端回复SYN-ACK包,客户端再发送ACK包确认。三次握手确保双方都具备收发能力,防止旧连接请求导致的资源浪费,建立可靠的双向通信通道。", "think_rank": 2},
81
- {"prompt": "证明勾股定理", "response": "构造直角三角形三边为a,b,c。以(a+b)为边构造正方形,内部放置四个全等直角三角形,中心形成边长c的正方形。面积关系:(a+b)^2 = c^2 + 4*(ab/2),化简得a^2+b^2=c^2。", "think_rank": 3},
82
- {"prompt": "推导欧拉公式", "response": "由泰勒展开:e^(ix) = 1 + ix + (ix)^2/2! + (ix)^3/3! + ... = (1-x^2/2!+...) + i(x-x^3/3!+...) = cos(x) + i*sin(x)。令x=pi得e^(i*pi) + 1 = 0。", "think_rank": 3},
83
- ]
84
-
85
-
86
- def main():
87
- data_path = Path("data/mini_data.json")
88
- with open(data_path, 'r', encoding='utf-8') as f:
89
- old_data = json.load(f)
90
-
91
- # Deduplicate by prompt (keep first occurrence)
92
- seen_prompts = set()
93
- deduped = []
94
- for item in old_data:
95
- if item['prompt'] not in seen_prompts:
96
- deduped.append(item)
97
- seen_prompts.add(item['prompt'])
98
-
99
- # Merge deduplicated old data with new diverse samples
100
- data = deduped + list(NEW_SAMPLES)
101
-
102
- # Count
103
- from collections import Counter
104
- prompts = [d['prompt'] for d in data]
105
- counter = Counter(prompts)
106
- dup_rate = (len(prompts) - len(counter)) / len(prompts) * 100
107
- rank_dist = Counter(d['think_rank'] for d in data)
108
-
109
- print(f"Old: {len(old_data)} items, unique: {len(set(d['prompt'] for d in old_data))}")
110
- print(f"New: {len(data)} items, unique: {len(counter)}, dup rate: {dup_rate:.1f}%")
111
- print(f"Think rank distribution: {dict(sorted(rank_dist.items()))}")
112
-
113
- with open(data_path, 'w', encoding='utf-8') as f:
114
- json.dump(data, f, ensure_ascii=False, indent=2)
115
-
116
- print(f"Written {len(data)} items to {data_path}")
117
-
118
-
119
- if __name__ == '__main__':
120
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/fix_mini_data.py DELETED
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Fix mini_data.json: distribute think_rank 0-3 based on prompt content."""
3
-
4
- import json
5
- import re
6
-
7
- # Keywords suggesting different thinking depths
8
- DEPTH_3_KEYWORDS = ['prove', 'theorem', 'proof', 'derive', 'mathematical', 'complex',
9
- 'prove', 'derive', 'calculate', 'analyze deeply',
10
- '\u8bc1\u660e', '\u63a8\u5bfc', '\u5b9a\u7406', '\u590d\u6742', '\u6df1\u5165\u5206\u6790']
11
- DEPTH_2_KEYWORDS = ['explain', 'why', 'how does', 'compare', 'difference',
12
- 'algorithm', 'design', 'optimize',
13
- '\u89e3\u91ca', '\u4e3a\u4ec0\u4e48', '\u5982\u4f55', '\u6bd4\u8f83', '\u7b97\u6cd5', '\u8bbe\u8ba1', '\u4f18\u5316']
14
- DEPTH_1_KEYWORDS = ['write', 'implement', 'code', 'function', 'create',
15
- '\u5199', '\u5b9e\u73b0', '\u7f16\u5199', '\u4ee3\u7801', '\u521b\u5efa']
16
-
17
-
18
- def assign_depth(item):
19
- text = (item.get('prompt', '') + ' ' + item.get('response', '')).lower()
20
- for kw in DEPTH_3_KEYWORDS:
21
- if kw.lower() in text:
22
- return 3
23
- for kw in DEPTH_2_KEYWORDS:
24
- if kw.lower() in text:
25
- return 2
26
- for kw in DEPTH_1_KEYWORDS:
27
- if kw.lower() in text:
28
- return 1
29
- return 0
30
-
31
-
32
- def main():
33
- with open('data/mini_data.json', 'r', encoding='utf-8') as f:
34
- data = json.load(f)
35
-
36
- # Count current distribution
37
- old_dist = {}
38
- for item in data:
39
- r = item.get('think_rank', 0)
40
- old_dist[r] = old_dist.get(r, 0) + 1
41
- print(f"Before fix: {old_dist}")
42
-
43
- # Fix
44
- for item in data:
45
- item['think_rank'] = assign_depth(item)
46
-
47
- # Count new distribution
48
- new_dist = {}
49
- for item in data:
50
- r = item.get('think_rank', 0)
51
- new_dist[r] = new_dist.get(r, 0) + 1
52
- print(f"After fix: {new_dist}")
53
-
54
- with open('data/mini_data.json', 'w', encoding='utf-8') as f:
55
- json.dump(data, f, ensure_ascii=False, indent=2)
56
-
57
- print(f"Fixed {len(data)} items")
58
-
59
-
60
- if __name__ == '__main__':
61
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/manage_mini_data.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Manage mini_data.json: create, fix think_rank, add depth samples, dedup.
3
+
4
+ Usage:
5
+ python manage_mini_data.py create # Create initial dataset
6
+ python manage_mini_data.py fix # Re-assign think_rank by keywords
7
+ python manage_mini_data.py enrich # Add diverse samples for all depths
8
+ python manage_mini_data.py dedup # Remove duplicates
9
+ python manage_mini_data.py all # Run fix + enrich + dedup
10
+ """
11
+
12
+ import json
13
+ import re
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ DATA_PATH = Path("data/mini_data.json")
18
+
19
+ # --- Depth assignment keywords ---
20
+ DEPTH_3_KEYWORDS = ['prove', 'theorem', 'proof', 'derive', 'mathematical', 'complex',
21
+ 'calculate', 'analyze deeply',
22
+ '\u8bc1\u660e', '\u63a8\u5bfc', '\u5b9a\u7406', '\u590d\u6742', '\u6df1\u5165\u5206\u6790']
23
+ DEPTH_2_KEYWORDS = ['explain', 'why', 'how does', 'compare', 'difference',
24
+ 'algorithm', 'design', 'optimize',
25
+ '\u89e3\u91ca', '\u4e3a\u4ec0\u4e48', '\u5982\u4f55', '\u6bd4\u8f83', '\u7b97\u6cd5', '\u8bbe\u8ba1', '\u4f18\u5316']
26
+ DEPTH_1_KEYWORDS = ['write', 'implement', 'code', 'function', 'create',
27
+ '\u5199', '\u5b9e\u73b0', '\u7f16\u5199', '\u4ee3\u7801', '\u521b\u5efa']
28
+
29
+ # --- Extra diverse samples ---
30
+ EXTRA_SAMPLES = [
31
+ # Depth 0 (simple)
32
+ {"prompt": "What is 2+2?", "response": "4", "think_rank": 0},
33
+ {"prompt": "Capital of France?", "response": "Paris", "think_rank": 0},
34
+ {"prompt": "Hello", "response": "Hi! How can I help you?", "think_rank": 0},
35
+ # Depth 1 (coding)
36
+ {"prompt": "Write a function to reverse a string", "response": "def reverse_string(s): return s[::-1]", "think_rank": 1},
37
+ {"prompt": "Write a function to calculate factorial", "response": "def factorial(n): return 1 if n <= 1 else n * factorial(n - 1)", "think_rank": 1},
38
+ {"prompt": "Write a function to sort a list", "response": "def sort_list(lst): return sorted(lst)", "think_rank": 1},
39
+ {"prompt": "Write code to read a CSV file", "response": "import csv\nwith open('file.csv') as f:\n reader = csv.reader(f)\n for row in reader: print(row)", "think_rank": 1},
40
+ {"prompt": "Write a function to count words in text", "response": "def count_words(text): return len(text.split())", "think_rank": 1},
41
+ # Depth 2 (reasoning)
42
+ {"prompt": "Explain how neural networks learn", "response": "Neural networks learn by adjusting weights via backpropagation. The loss function measures prediction error; gradients indicate how each weight affects loss. An optimizer (e.g., SGD, Adam) updates weights in the direction that reduces loss, iteratively improving predictions.", "think_rank": 2},
43
+ {"prompt": "Compare BFS and DFS graph traversal", "response": "BFS explores level by level using a queue (O(V+E)), guaranteeing shortest path in unweighted graphs. DFS goes deep before backtracking using a stack (O(V+E)), useful for topological sort and cycle detection. BFS uses more memory; DFS can be iterative or recursive.", "think_rank": 2},
44
+ {"prompt": "Why does quicksort have O(n^2) worst case?", "response": "Quicksort's worst case occurs when the pivot is consistently the smallest or largest element, creating maximally unbalanced partitions. Each partition takes O(n) and we need n partitions, giving O(n^2). Median-of-three or random pivot selection mitigates this.", "think_rank": 2},
45
+ # Depth 3 (math proof)
46
+ {"prompt": "Prove that sqrt(2) is irrational", "response": "Assume sqrt(2) = p/q in lowest terms. Then 2q^2 = p^2, so p is even. Write p = 2k, then 2q^2 = 4k^2, so q^2 = 2k^2, meaning q is also even. This contradicts p/q being in lowest terms.", "think_rank": 3},
47
+ {"prompt": "Prove there are infinitely many primes", "response": "Suppose finitely many primes p1,...,pn exist. Let N = p1*p2*...*pn + 1. N is not divisible by any pi (remainder 1). So N is either prime itself or has a prime factor not in the list. Contradiction.", "think_rank": 3},
48
+ {"prompt": "Derive the quadratic formula", "response": "Starting from ax^2 + bx + c = 0, divide by a, complete the square: (x + b/2a)^2 = (b^2 - 4ac)/4a^2. Taking the square root gives x = (-b +- sqrt(b^2 - 4ac)) / 2a.", "think_rank": 3},
49
+ {"prompt": "Analyze the time complexity of merge sort", "response": "Merge sort divides the array in half (O(1)), recurses on both halves (2T(n/2)), and merges in O(n). The recurrence T(n) = 2T(n/2) + O(n) solves to O(n log n) by the master theorem (case 2).", "think_rank": 3},
50
+ {"prompt": "Prove the Pythagorean theorem", "response": "Consider a right triangle with legs a, b and hypotenuse c. Construct a square of side (a+b) and arrange four copies of the triangle inside. The inner quadrilateral is a square of side c, so (a+b)^2 = c^2 + 4*(ab/2), which simplifies to a^2 + b^2 = c^2.", "think_rank": 3},
51
+ {"prompt": "Derive the derivative of sin(x)", "response": "Using the limit definition: d/dx sin(x) = lim(h->0) [sin(x+h) - sin(x)] / h. Apply the angle addition formula: sin(x+h) = sin(x)cos(h) + cos(x)sin(h). This gives lim [sin(x)(cos(h)-1)/h + cos(x)sin(h)/h] = sin(x)*0 + cos(x)*1 = cos(x).", "think_rank": 3},
52
+ # Chinese samples
53
+ {"prompt": "Explain the difference between TCP and UDP", "response": "TCP is connection-oriented, reliable, and ordered. UDP is connectionless, unreliable, and unordered. TCP handles retransmission and flow control, UDP does not. TCP is used for web, email; UDP for streaming, DNS.", "think_rank": 2},
54
+ {"prompt": "Implement a simple HTTP server in Python", "response": "from http.server import HTTPServer, BaseHTTPRequestHandler\nclass Handler(BaseHTTPRequestHandler):\n def do_GET(self):\n self.send_response(200)\n self.end_headers()\n self.wfile.write(b'Hello')\nHTTPServer(('', 8000), Handler).serve_forever()", "think_rank": 1},
55
+ ]
56
+
57
+
58
+ def load_data():
59
+ if DATA_PATH.exists():
60
+ with open(DATA_PATH, 'r', encoding='utf-8') as f:
61
+ return json.load(f)
62
+ return []
63
+
64
+
65
+ def save_data(data):
66
+ DATA_PATH.parent.mkdir(parents=True, exist_ok=True)
67
+ with open(DATA_PATH, 'w', encoding='utf-8') as f:
68
+ json.dump(data, f, ensure_ascii=False, indent=2)
69
+ print(f"Saved {len(data)} items to {DATA_PATH}")
70
+
71
+
72
+ def show_dist(data):
73
+ dist = {}
74
+ for item in data:
75
+ r = item.get('think_rank', 0)
76
+ dist[r] = dist.get(r, 0) + 1
77
+ print(f"Distribution: {dict(sorted(dist.items()))}")
78
+
79
+
80
+ def assign_depth(item):
81
+ text = (item.get('prompt', '') + ' ' + item.get('response', '')).lower()
82
+ for kw in DEPTH_3_KEYWORDS:
83
+ if kw.lower() in text:
84
+ return 3
85
+ for kw in DEPTH_2_KEYWORDS:
86
+ if kw.lower() in text:
87
+ return 2
88
+ for kw in DEPTH_1_KEYWORDS:
89
+ if kw.lower() in text:
90
+ return 1
91
+ return 0
92
+
93
+
94
+ def cmd_fix(data):
95
+ for item in data:
96
+ item['think_rank'] = assign_depth(item)
97
+ print("Fixed think_rank distribution:")
98
+ show_dist(data)
99
+ return data
100
+
101
+
102
+ def cmd_enrich(data):
103
+ existing_prompts = {item['prompt'] for item in data}
104
+ added = 0
105
+ for sample in EXTRA_SAMPLES:
106
+ if sample['prompt'] not in existing_prompts:
107
+ data.append(sample)
108
+ existing_prompts.add(sample['prompt'])
109
+ added += 1
110
+ print(f"Added {added} new diverse samples")
111
+ show_dist(data)
112
+ return data
113
+
114
+
115
+ def cmd_dedup(data):
116
+ seen = set()
117
+ deduped = []
118
+ for item in data:
119
+ key = item.get('prompt', '')
120
+ if key not in seen:
121
+ seen.add(key)
122
+ deduped.append(item)
123
+ removed = len(data) - len(deduped)
124
+ print(f"Removed {removed} duplicates")
125
+ return deduped
126
+
127
+
128
+ def cmd_create(data):
129
+ """Create initial mini dataset."""
130
+ print("Creating initial dataset...")
131
+ return EXTRA_SAMPLES.copy()
132
+
133
+
134
+ def cmd_all(data):
135
+ data = cmd_fix(data)
136
+ data = cmd_enrich(data)
137
+ data = cmd_dedup(data)
138
+ return data
139
+
140
+
141
+ COMMANDS = {
142
+ 'create': cmd_create,
143
+ 'fix': cmd_fix,
144
+ 'enrich': cmd_enrich,
145
+ 'dedup': cmd_dedup,
146
+ 'all': cmd_all,
147
+ }
148
+
149
+
150
+ def main():
151
+ if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS:
152
+ print(f"Usage: {sys.argv[0]} [{'|'.join(COMMANDS)}]")
153
+ sys.exit(1)
154
+
155
+ cmd = sys.argv[1]
156
+ data = load_data()
157
+ print(f"Loaded {len(data)} items")
158
+ show_dist(data)
159
+
160
+ result = COMMANDS[cmd](data)
161
+ save_data(result)
162
+
163
+
164
+ if __name__ == '__main__':
165
+ main()
tests/run_tests.py CHANGED
@@ -24,7 +24,7 @@ from pathlib import Path
24
  project_root = Path(__file__).parent.parent
25
  sys.path.insert(0, str(project_root))
26
 
27
- print("🧪 Fusion 项目单元测试")
28
  print("=" * 50)
29
 
30
 
@@ -54,7 +54,7 @@ class TestSBLAAttention(unittest.TestCase):
54
  output, _ = attn(hidden_states=x, attention_mask=attention_mask)
55
 
56
  self.assertEqual(output.shape, (batch_size, seq_len, hidden_size))
57
- print(" SBLA 前向传播测试通过")
58
 
59
  def test_long_sequence(self):
60
  """测试长序列处理"""
@@ -75,7 +75,7 @@ class TestSBLAAttention(unittest.TestCase):
75
  output, _ = attn(hidden_states=x, attention_mask=attention_mask)
76
 
77
  self.assertEqual(output.shape, (1, 8192, 256))
78
- print(" SBLA 长序列测试通过")
79
 
80
 
81
  class TestThinkingDial(unittest.TestCase):
@@ -92,7 +92,7 @@ class TestThinkingDial(unittest.TestCase):
92
 
93
  self.assertEqual(depth, 2)
94
  self.assertEqual(clean, "证明勾股定理")
95
- print(" Thinking Dial 解析测试通过")
96
 
97
  def test_inject_token(self):
98
  """测试注入控制 token"""
@@ -104,7 +104,7 @@ class TestThinkingDial(unittest.TestCase):
104
  )
105
 
106
  self.assertIn("<|think_depth_1|>", result)
107
- print(" Thinking Dial 注入测试通过")
108
 
109
 
110
  class TestBilingualFilter(unittest.TestCase):
@@ -126,7 +126,7 @@ class TestBilingualFilter(unittest.TestCase):
126
  "量子纠缠是量子力学中的一种现象,指两个或多个粒子之间存在一种特殊的关联。"
127
  ))
128
 
129
- print(" 中文过滤器测试通过")
130
 
131
  def test_english_filter(self):
132
  """测试英文质量过滤"""
@@ -139,7 +139,7 @@ class TestBilingualFilter(unittest.TestCase):
139
  "Quantum entanglement is a phenomenon in quantum mechanics."
140
  ))
141
 
142
- print(" 英文过滤器测试通过")
143
 
144
 
145
  class TestFusionModel(unittest.TestCase):
@@ -159,7 +159,7 @@ class TestFusionModel(unittest.TestCase):
159
  model = FusionModel(config)
160
 
161
  self.assertIsNotNone(model)
162
- print(" Fusion 模型创建测试通过")
163
 
164
  def test_forward_pass(self):
165
  """测试前向传播"""
@@ -186,7 +186,7 @@ class TestFusionModel(unittest.TestCase):
186
 
187
  self.assertIn("loss", outputs)
188
  self.assertIn("logits", outputs)
189
- print(" Fusion 模型前向传播测试通过")
190
 
191
 
192
  class TestDataPipeline(unittest.TestCase):
@@ -212,7 +212,7 @@ class TestDataPipeline(unittest.TestCase):
212
  self.assertIn("think_rank", item)
213
  self.assertIn(item["think_rank"], [0, 1, 2, 3])
214
 
215
- print(" 示例数据格式测试通过")
216
 
217
 
218
  def run_all_tests():
@@ -258,9 +258,9 @@ def run_all_tests():
258
  success = result.wasSuccessful()
259
 
260
  if success:
261
- print("\n🎉 所有测试通过!")
262
  else:
263
- print("\n 部分测试失败,请检查代码")
264
 
265
  return success
266
 
 
24
  project_root = Path(__file__).parent.parent
25
  sys.path.insert(0, str(project_root))
26
 
27
+ print("[LOGO] Fusion 项目单元测试")
28
  print("=" * 50)
29
 
30
 
 
54
  output, _ = attn(hidden_states=x, attention_mask=attention_mask)
55
 
56
  self.assertEqual(output.shape, (batch_size, seq_len, hidden_size))
57
+ print("[OK] SBLA 前向传播测试通过")
58
 
59
  def test_long_sequence(self):
60
  """测试长序列处理"""
 
75
  output, _ = attn(hidden_states=x, attention_mask=attention_mask)
76
 
77
  self.assertEqual(output.shape, (1, 8192, 256))
78
+ print("[OK] SBLA 长序列测试通过")
79
 
80
 
81
  class TestThinkingDial(unittest.TestCase):
 
92
 
93
  self.assertEqual(depth, 2)
94
  self.assertEqual(clean, "证明勾股定理")
95
+ print("[OK] Thinking Dial 解析测试通过")
96
 
97
  def test_inject_token(self):
98
  """测试注入控制 token"""
 
104
  )
105
 
106
  self.assertIn("<|think_depth_1|>", result)
107
+ print("[OK] Thinking Dial 注入测试通过")
108
 
109
 
110
  class TestBilingualFilter(unittest.TestCase):
 
126
  "量子纠缠是量子力学中的一种现象,指两个或多个粒子之间存在一种特殊的关联。"
127
  ))
128
 
129
+ print("[OK] 中文过滤器测试通过")
130
 
131
  def test_english_filter(self):
132
  """测试英文质量过滤"""
 
139
  "Quantum entanglement is a phenomenon in quantum mechanics."
140
  ))
141
 
142
+ print("[OK] 英文过滤器测试通过")
143
 
144
 
145
  class TestFusionModel(unittest.TestCase):
 
159
  model = FusionModel(config)
160
 
161
  self.assertIsNotNone(model)
162
+ print("[OK] Fusion 模型创建测试通过")
163
 
164
  def test_forward_pass(self):
165
  """测试前向传播"""
 
186
 
187
  self.assertIn("loss", outputs)
188
  self.assertIn("logits", outputs)
189
+ print("[OK] Fusion 模型前向传播测试通过")
190
 
191
 
192
  class TestDataPipeline(unittest.TestCase):
 
212
  self.assertIn("think_rank", item)
213
  self.assertIn(item["think_rank"], [0, 1, 2, 3])
214
 
215
+ print("[OK] 示例数据格式测试通过")
216
 
217
 
218
  def run_all_tests():
 
258
  success = result.wasSuccessful()
259
 
260
  if success:
261
+ print("\n[DONE] 所有测试通过!")
262
  else:
263
+ print("\n[FAIL] 部分测试失败,请检查代码")
264
 
265
  return success
266
 
tests/test_sbla_integration.py CHANGED
@@ -44,8 +44,8 @@ print()
44
 
45
  # 4. 验证 SBLA 是否使用
46
  print("[4] 验证 SBLA 注意力...")
47
- has_sblla = any("SBLAttention" in str(module) for module in model.modules())
48
- if has_sblla:
49
  print(" SBLA 注意力已集成到模型中")
50
  else:
51
  print(" 未检测到 SBLA 注意力(可能使用了标准注意力)")
 
44
 
45
  # 4. 验证 SBLA 是否使用
46
  print("[4] 验证 SBLA 注意力...")
47
+ has_sbla = any("SBLAttention" in str(module) for module in model.modules())
48
+ if has_sbla:
49
  print(" SBLA 注意力已集成到模型中")
50
  else:
51
  print(" 未检测到 SBLA 注意力(可能使用了标准注意力)")