Cosmos3-Super-Image2Video-4Step-FP8 / repackage_for_hf_i2v4step.py
prometheusAIR's picture
Add single-GPU diffusers serving script and fix usage instructions to reference this repo
5a866f5 verified
Raw
History Blame Contribute Delete
4.41 kB
#!/usr/bin/env python
"""
Re-save the in-memory quantized Cosmos3-Super-Image2Video-4Step transformer in the
ROUND-TRIPPABLE ModelOpt HF format and assemble a complete drop-in diffusers repo
around it. Sibling of repackage_for_hf.py -- identical logic, just imports the
build helpers from serve_cosmos3_i2v4step_diffusers instead (which targets
nvidia/Cosmos3-Super-Image2Video-4Step and drops the scheduler swap this
checkpoint doesn't want -- see that file's docstring).
Run in the ModelOpt venv, from the directory containing serve_cosmos3_i2v4step_diffusers.py:
CUDA_VISIBLE_DEVICES=0 python repackage_for_hf_i2v4step.py --format fp8 \
--serve-dir ./cosmos3-i2v4step-fp8-serve \
--out-dir ./cosmos3-i2v4step-fp8-hf \
[--cache ./cosmos3-i2v4step-cache]
Then verify the result loads + renders:
python -i load_cosmos3_modelopt.py ./cosmos3-i2v4step-fp8-hf
"""
import argparse
import json
import os
import pathlib
import shutil
os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
import torch # noqa: F401 (ensures CUDA init / dtype availability)
from modelopt.torch.opt import enable_huggingface_checkpointing
from serve_cosmos3_i2v4step_diffusers import build_quantized_transformer, try_restore_quantized
QUANT_TYPE = {"fp8": "FP8", "nvfp4": "NVFP4"}
def ensure_loadable_config(transformer_dir: str, fmt: str) -> None:
"""If save_pretrained wrote a quantization_config, make sure diffusers can construct
it: NVIDIAModelOptConfig needs `quant_type`, and a truthy `modelopt_config` avoids the
buggy get_config_from_quant_type() builder. (Structure restore itself comes from
modelopt_state.pth; this just keeps config parsing from crashing on load.)"""
cfg_path = pathlib.Path(transformer_dir) / "config.json"
cfg = json.loads(cfg_path.read_text())
qc = cfg.get("quantization_config")
if isinstance(qc, dict):
qc["quant_type"] = QUANT_TYPE[fmt]
qc.setdefault("weight_only", True)
if not qc.get("modelopt_config"):
qc["modelopt_config"] = {"quant_cfg": {}, "algorithm": "max"}
cfg["quantization_config"] = qc
cfg_path.write_text(json.dumps(cfg, indent=2))
print(f"[patch] quantization_config made loadable (quant_type={qc['quant_type']})")
else:
print("[patch] no embedded quantization_config; relying on modelopt_state.pth for restore")
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--format", choices=["fp8", "nvfp4"], default="fp8")
ap.add_argument("--serve-dir", required=True,
help="existing assembled pipeline dir (source of VAE / tokenizers / model_index.json)")
ap.add_argument("--out-dir", required=True, help="new drop-in repo dir to create")
ap.add_argument("--cache", default=None, help="optional mto cache dir for a faster rebuild")
ap.add_argument("--gpu-mem-fraction", type=float, default=0.85)
args = ap.parse_args()
model = try_restore_quantized(args.format, args.cache) if args.cache else None
if model is None:
model = build_quantized_transformer(args.format, args.gpu_mem_fraction)
enable_huggingface_checkpointing()
tdir = os.path.join(args.out_dir, "transformer")
os.makedirs(tdir, exist_ok=True)
print(f"[save] writing round-trippable transformer (+ modelopt_state.pth) -> {tdir}")
model.save_pretrained(tdir)
state_file = os.path.join(tdir, "modelopt_state.pth")
assert os.path.isfile(state_file), (
f"expected {state_file} to exist -- enable_huggingface_checkpointing() must run "
"before save_pretrained(); without modelopt_state.pth the repo won't load in diffusers"
)
ensure_loadable_config(tdir, args.format)
print(f"[assemble] copying non-transformer components from {args.serve_dir}")
for name in os.listdir(args.serve_dir):
if name == "transformer":
continue
src = os.path.join(args.serve_dir, name)
dst = os.path.join(args.out_dir, name)
if os.path.isdir(src):
shutil.copytree(src, dst, dirs_exist_ok=True)
else:
shutil.copy2(src, dst)
print(f"[done] drop-in repo -> {args.out_dir}")
print(f" verify: python -i load_cosmos3_modelopt.py {args.out_dir}")
if __name__ == "__main__":
main()