Download scripts/convert_to_hf.py from LIJINGHAI111/DomSense: direct link, hf CLI and curl.
- Browser
- Download file 3.91 kB
-
https://huggingface.co/LIJINGHAI111/DomSense/resolve/main/scripts/convert_to_hf.py
- Command line
-
hf download hf://LIJINGHAI111/DomSense/scripts/convert_to_hf.py
-
curl -L -o convert_to_hf.py https://huggingface.co/LIJINGHAI111/DomSense/resolve/main/scripts/convert_to_hf.py
3.91 kB
| """把 DomSense 训练 checkpoint 转换为 Hugging Face 标准格式并导出。 | |
| 用法: | |
| python scripts/convert_to_hf.py | |
| --ckpt ../outputs/rlcd_mdp_run1/best_model.pt | |
| --out ./saved_model | |
| 产出(HF 标准目录): | |
| saved_model/ | |
| config.json # SystemOneConfig 序列化 | |
| model.safetensors # 转换后的权重(自动去掉 base_model_prefix "core.") | |
| tokenizer.json # DomSenseTokenizer | |
| 导出后,可这样加载: | |
| import sys; sys.path.insert(0, "repo_root") | |
| from huggingface_repo import SystemOneModelForDecision, DomSenseTokenizer | |
| m = SystemOneModelForDecision.from_pretrained("saved_model_dir") | |
| """ | |
| import argparse | |
| import sys | |
| from pathlib import Path | |
| import torch | |
| REPO_ROOT = Path(__file__).resolve().parent.parent.parent | |
| sys.path.insert(0, str(REPO_ROOT)) | |
| from huggingface_repo import SystemOneModelForDecision, DomSenseTokenizer | |
| from huggingface_repo.configuration_domsense import SystemOneConfig | |
| def convert(ckpt_path: str, out_dir: str): | |
| print(f"[1/4] 读取 checkpoint: {ckpt_path}") | |
| ckpt = torch.load(ckpt_path, map_location="cpu") | |
| state_dict = ckpt["model_state_dict"] | |
| # 兼容两种 checkpoint:扁平 dict 或 {model: {...}} 嵌套 | |
| raw_cfg = ckpt.get("config", {}) | |
| if isinstance(raw_cfg, dict) and "model" in raw_cfg: | |
| raw_cfg = raw_cfg["model"] | |
| cfg_kwargs = { | |
| k: v | |
| for k, v in raw_cfg.items() | |
| if v is not None and not isinstance(v, dict) | |
| } | |
| # 用权重形状自动修正关键结构维度,避免 config 与 checkpoint 不一致 | |
| if "mdp_head.action_embed_table.weight" in state_dict: | |
| cfg_kwargs["max_actions"] = state_dict[ | |
| "mdp_head.action_embed_table.weight" | |
| ].shape[0] | |
| # 领域数量由权重推断;领域名优先从 config 保留(若有),否则自动命名 | |
| if "domain_moe.gate.2.weight" in state_dict: | |
| n_slots = state_dict["domain_moe.gate.2.weight"].shape[0] | |
| n_domains = n_slots - 1 | |
| cfg_kwargs["use_domain_experts"] = n_domains > 0 | |
| if "domains" not in cfg_kwargs or not cfg_kwargs["domains"]: | |
| cfg_kwargs["domains"] = [f"domain_{i}" for i in range(n_domains)] | |
| # 确保领域列表长度与权重匹配 | |
| if len(cfg_kwargs["domains"]) != n_domains: | |
| cfg_kwargs["domains"] = [f"domain_{i}" for i in range(n_domains)] | |
| cfg = SystemOneConfig(**cfg_kwargs) | |
| print(f"[2/4] 构建 HF 模型;hidden_dim={cfg.hidden_dim}, " | |
| f"num_bellman_steps={cfg.num_bellman_steps}, " | |
| f"use_domain_experts={cfg.use_domain_experts}") | |
| model = SystemOneModelForDecision(cfg) | |
| print("[3/4] 加载权重到内核 core.*(strict=False)") | |
| missing, unexpected = model.core.load_state_dict(state_dict, strict=False) | |
| if missing: | |
| print(f" - missing {len(missing)} keys: {missing[:10]}") | |
| if unexpected: | |
| print(f" - unexpected {len(unexpected)} keys: {unexpected[:10]}") | |
| total, trainable = model.count_parameters() | |
| print(f" 总参数量: {total:,} | 可训练: {trainable:,}") | |
| out = Path(out_dir) | |
| out.mkdir(parents=True, exist_ok=True) | |
| print(f"[4/4] 导出 HF 格式到: {out}") | |
| # save_pretrained 基于 base_model_prefix 自动存储(保存去 core.,加载加回) | |
| model.save_pretrained(str(out)) | |
| DomSenseTokenizer().save_pretrained(str(out)) | |
| print("完成!现在可以从该目录加载:") | |
| print(f' from huggingface_repo import SystemOneModelForDecision, DomSenseTokenizer') | |
| print(f' m = SystemOneModelForDecision.from_pretrained("{out}")') | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--ckpt", default="../outputs/rlcd_mdp_run1/best_model.pt") | |
| parser.add_argument("--out", default="./saved_model") | |
| args = parser.parse_args() | |
| convert(args.ckpt, args.out) | |