94 lines
3.6 KiB
Python
Raw Normal View History

#!/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()