2026-05-10 13:12:44 +08:00

94 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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