from __future__ import annotations import argparse from collections import OrderedDict import json from pathlib import Path import sys import torch _THIS_DIR = Path(__file__).resolve().parent _REPO_ROOT = _THIS_DIR.parent.parent if str(_REPO_ROOT) not in sys.path: sys.path.insert(0, str(_REPO_ROOT)) from mmgp import safetensors2 from models.magi_human.checkpoint_schema import convert_transformer_state_dict_to_split_experts, preprocess_magi_lora_state_dict def _load_state_dict_and_metadata(path: str): with safetensors2.safe_open(path, framework="pt", device="cpu", writable_tensors=False) as reader: metadata = reader.metadata() or {} state_dict = OrderedDict((key, reader.get_tensor(key)) for key in reader.keys()) return state_dict, metadata def _load_sharded_state_dict_and_metadata(index_path: str): with open(index_path, "r", encoding="utf-8") as reader: index_data = json.load(reader) shard_to_keys = OrderedDict() for key, shard_name in index_data["weight_map"].items(): shard_to_keys.setdefault(shard_name, []).append(key) state_dict = OrderedDict() metadata = dict(index_data.get("metadata") or {}) base_dir = Path(index_path).resolve().parent for shard_name, keys in shard_to_keys.items(): shard_path = base_dir / shard_name with safetensors2.safe_open(str(shard_path), framework="pt", device="cpu", writable_tensors=False) as reader: if not metadata: metadata.update(reader.metadata() or {}) for key in keys: state_dict[key] = reader.get_tensor(key) return state_dict, metadata def _resolve_input_path(path: str): input_path = Path(path) if input_path.is_dir(): index_path = input_path / "model.safetensors.index.json" if index_path.exists(): return str(index_path) safetensors_path = input_path / "model.safetensors" if safetensors_path.exists(): return str(safetensors_path) return str(input_path) def _cast_state_dict_dtype(state_dict: Mapping[str, object], dtype: torch.dtype | None): if dtype is None: return OrderedDict(state_dict.items()) casted = OrderedDict() for key, value in state_dict.items(): if torch.is_tensor(value) and value.is_floating_point() and value.dtype != dtype: casted[key] = value.to(dtype) else: casted[key] = value return casted def _load_any_state_dict_and_metadata(path: str, dtype: torch.dtype | None = None): resolved_path = _resolve_input_path(path) if resolved_path.endswith(".index.json"): state_dict, metadata = _load_sharded_state_dict_and_metadata(resolved_path) else: state_dict, metadata = _load_state_dict_and_metadata(resolved_path) return _cast_state_dict_dtype(state_dict, dtype), metadata def convert_transformer_checkpoint(input_path: str, output_path: str, dtype: torch.dtype | None = torch.bfloat16) -> None: state_dict, metadata = _load_any_state_dict_and_metadata(input_path, dtype=dtype) config = metadata.get("config") converted = convert_transformer_state_dict_to_split_experts(state_dict) safetensors2.torch_write_file(converted, output_path, config=config) def convert_lora_checkpoint(input_path: str, output_path: str, dtype: torch.dtype | None = None) -> None: state_dict, metadata = _load_any_state_dict_and_metadata(input_path, dtype=dtype) converted = preprocess_magi_lora_state_dict(state_dict) extra_meta = {k: v for k, v in metadata.items() if k not in {"config", "format"}} safetensors2.torch_write_file(converted, output_path, config=metadata.get("config"), extra_meta=extra_meta or None) def main() -> None: parser = argparse.ArgumentParser(description="Convert Magi Human checkpoints or LoRAs to the split-expert schema.") parser.add_argument("input", type=str, help="Source safetensors path") parser.add_argument("output", type=str, help="Converted safetensors path") parser.add_argument("--kind", choices=("transformer", "lora"), default="transformer") parser.add_argument("--dtype", choices=("keep", "bf16", "fp16"), default="bf16") args = parser.parse_args() Path(args.output).parent.mkdir(parents=True, exist_ok=True) dtype = None if args.dtype == "keep" else (torch.bfloat16 if args.dtype == "bf16" else torch.float16) if args.kind == "transformer": convert_transformer_checkpoint(args.input, args.output, dtype=dtype) else: convert_lora_checkpoint(args.input, args.output, dtype=dtype if args.dtype != "keep" else None) if __name__ == "__main__": main()