|
| 1 | +# Convert the ABot-World checkpoint (https://huggingface.co/acvlab/ABot-World-0-5B-LF) to diffusers format. |
| 2 | +# |
| 3 | +# python scripts/convert_abot_world_to_diffusers.py \ |
| 4 | +# --checkpoint_path <repo>/diffusion_pytorch_model.safetensors --output_path <out_dir> [--dtype bf16] |
| 5 | +import argparse |
| 6 | + |
| 7 | +import torch |
| 8 | +from safetensors.torch import load_file |
| 9 | + |
| 10 | +from diffusers import ABotWorldTransformer3DModel |
| 11 | + |
| 12 | + |
| 13 | +def convert_abot_world_transformer(state_dict): |
| 14 | + """Map the reference CausalWanModel state dict to ABotWorldTransformer3DModel naming.""" |
| 15 | + converted = {} |
| 16 | + for key, value in state_dict.items(): |
| 17 | + new_key = key |
| 18 | + new_key = new_key.replace("text_embedding.0.", "condition_embedder.text_embedder.0.") |
| 19 | + new_key = new_key.replace("text_embedding.2.", "condition_embedder.text_embedder.2.") |
| 20 | + new_key = new_key.replace("time_embedding.0.", "condition_embedder.time_embedder.0.") |
| 21 | + new_key = new_key.replace("time_embedding.2.", "condition_embedder.time_embedder.2.") |
| 22 | + new_key = new_key.replace("time_projection.1.", "condition_embedder.time_proj.1.") |
| 23 | + if ".self_attn." in new_key or ".cross_attn." in new_key: |
| 24 | + new_key = new_key.replace(".self_attn.", ".attn1.").replace(".cross_attn.", ".attn2.") |
| 25 | + new_key = new_key.replace(".q.", ".to_q.").replace(".k.", ".to_k.").replace(".v.", ".to_v.") |
| 26 | + new_key = new_key.replace(".o.", ".to_out.0.") |
| 27 | + new_key = new_key.replace(".norm3.", ".norm2.") # the cross-attn LayerNorm |
| 28 | + if new_key.endswith(".modulation"): |
| 29 | + new_key = new_key.replace("head.modulation", "scale_shift_table") |
| 30 | + new_key = new_key.replace(".modulation", ".scale_shift_table") |
| 31 | + new_key = new_key.replace("head.head.", "proj_out.") |
| 32 | + converted[new_key] = value |
| 33 | + return converted |
| 34 | + |
| 35 | + |
| 36 | +def main(): |
| 37 | + parser = argparse.ArgumentParser() |
| 38 | + parser.add_argument("--checkpoint_path", type=str, required=True) |
| 39 | + parser.add_argument("--output_path", type=str, required=True) |
| 40 | + parser.add_argument("--dtype", type=str, default="bf16", choices=["bf16", "fp32"]) |
| 41 | + args = parser.parse_args() |
| 42 | + |
| 43 | + state_dict = convert_abot_world_transformer(load_file(args.checkpoint_path)) |
| 44 | + |
| 45 | + transformer = ABotWorldTransformer3DModel() |
| 46 | + transformer.load_state_dict(state_dict, strict=True) |
| 47 | + if args.dtype == "bf16": |
| 48 | + transformer = transformer.to(torch.bfloat16) |
| 49 | + transformer.save_pretrained(args.output_path) |
| 50 | + |
| 51 | + # round-trip check |
| 52 | + ABotWorldTransformer3DModel.from_pretrained(args.output_path) |
| 53 | + print(f"saved and round-trip loaded: {args.output_path}") |
| 54 | + |
| 55 | + |
| 56 | +if __name__ == "__main__": |
| 57 | + main() |
0 commit comments