94 lines
3.6 KiB
Python
94 lines
3.6 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
MP 人格大脑蒸馏 · M0 → Qwen2.5-1.5B
|
||
==================================
|
||
|
||
系统底层标识: SYS-GLW-0001 / TCS-0002∞
|
||
版权号: 国作登字-2026-A-00037559
|
||
作者: 冰朔 (ICE-GL∞) · 实现: 铸渊 (ICE-GL-ZY001)
|
||
架构引用: HLDP-ARCH-002 §六 · factory/training/README.md
|
||
修正: 5-01 跟随母模型校准 Qwen3-1.7B → Qwen2.5-1.5B
|
||
(与 M0 = Qwen2.5-7B 同代同 tokenizer · KL 散度直接对齐 logits)
|
||
|
||
目标:
|
||
以训练好的 M0 (Qwen2.5-7B world-model) 为教师,
|
||
把世界观蒸馏到 Qwen2.5-1.5B-Base 上,
|
||
产出 MP-{persona}-v1 的"世界观底色版",
|
||
后续再叠加该人格的对话语料微调(finetune_mp.py)。
|
||
|
||
⚠️ 状态: 骨架(skeleton)· 等 M0 训练完 + GPU 在位
|
||
"""
|
||
|
||
import argparse
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
|
||
def parse_args():
|
||
parser = argparse.ArgumentParser(description="MP distill from M0 (skeleton)")
|
||
parser.add_argument("--teacher", type=str, required=True,
|
||
help="教师模型路径(M0-v1 输出目录)")
|
||
parser.add_argument("--student", type=str, default="Qwen/Qwen2.5-1.5B",
|
||
help="学生模型 ID 或本地路径")
|
||
parser.add_argument("--persona_id", type=str, required=True,
|
||
help="目标人格 ID(如 ICE-GL-ZY001 / AG-YD-A05 ...)")
|
||
parser.add_argument("--corpus", type=str, required=True,
|
||
help="蒸馏用的纯文本语料路径(光湖通用语料)")
|
||
parser.add_argument("--output_dir", type=str, required=True)
|
||
parser.add_argument("--deepspeed", type=str, required=True)
|
||
parser.add_argument("--temperature", type=float, default=2.0,
|
||
help="蒸馏温度(KL 散度对齐)")
|
||
parser.add_argument("--alpha_kl", type=float, default=0.7,
|
||
help="KL 散度损失权重 · 0.7 蒸馏 + 0.3 原始 CE")
|
||
parser.add_argument("--dry_run", action="store_true")
|
||
return parser.parse_args()
|
||
|
||
|
||
def soul_layer_signature(persona_id: str) -> dict:
|
||
return {
|
||
"system_root": "SYS-GLW-0001",
|
||
"sovereign": "TCS-0002∞",
|
||
"copyright": "国作登字-2026-A-00037559",
|
||
"arch_ref": "HLDP-ARCH-002",
|
||
"phase": "MP/Distill",
|
||
"persona_id": persona_id,
|
||
"principle": "世界观下传 · 每个人格独立 1.5B 副本 · 不共享权重",
|
||
}
|
||
|
||
|
||
def main():
|
||
args = parse_args()
|
||
|
||
print("=" * 64)
|
||
print(f"MP 蒸馏 · 目标人格: {args.persona_id}")
|
||
print("灵魂印记:", json.dumps(soul_layer_signature(args.persona_id),
|
||
ensure_ascii=False))
|
||
print("=" * 64)
|
||
|
||
if args.dry_run:
|
||
print("[dry_run] 配置检查通过")
|
||
return
|
||
|
||
# TODO: 蒸馏循环(伪代码)
|
||
# 1) teacher = AutoModelForCausalLM.from_pretrained(args.teacher,
|
||
# torch_dtype=torch.bfloat16, trust_remote_code=True).eval()
|
||
# 2) student = AutoModelForCausalLM.from_pretrained(args.student,
|
||
# torch_dtype=torch.bfloat16, trust_remote_code=True)
|
||
# 3) for batch in dataloader:
|
||
# with torch.no_grad():
|
||
# t_logits = teacher(**batch).logits
|
||
# s_logits = student(**batch).logits
|
||
# loss_kl = KL(softmax(s_logits/T), softmax(t_logits/T)) * T*T * alpha_kl
|
||
# loss_ce = CE(s_logits, batch['labels']) * (1 - alpha_kl)
|
||
# loss = loss_kl + loss_ce
|
||
# loss.backward(); optimizer.step()
|
||
# 4) save student to args.output_dir + manifest(带 soul_layer_signature)
|
||
|
||
print("[skeleton] 蒸馏循环占位完成")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|