| """Split a JointRadiomapCIRModel ckpt into two single-task ckpts suitable for |
| existing V2.2a / D2.2 visualization scripts. |
| |
| Usage: |
| python split_ckpt_for_viz.py \ |
| --joint-ckpt <path>/best.pt \ |
| --out-radiomap-ckpt <path>/best_rm.pt \ |
| --out-csi-ckpt <path>/best_csi.pt |
| """ |
| from __future__ import annotations |
|
|
| import argparse |
| from pathlib import Path |
|
|
| import torch |
|
|
|
|
| def main(): |
| p = argparse.ArgumentParser() |
| p.add_argument("--joint-ckpt", required=True) |
| p.add_argument("--out-radiomap-ckpt", required=True) |
| p.add_argument("--out-csi-ckpt", required=True) |
| args = p.parse_args() |
|
|
| ckpt = torch.load(args.joint_ckpt, map_location="cpu", weights_only=False) |
| sd = ckpt["model_state_dict"] |
|
|
| |
| |
| |
| |
| rm_sd = {k: v for k, v in sd.items() if not k.startswith("csi_head.")} |
| rm_ckpt = { |
| "epoch": ckpt.get("epoch", 0), |
| "step": ckpt.get("step", 0), |
| "tag": "split_from_joint", |
| "metrics": ckpt.get("metrics", {}), |
| "cli_args": ckpt.get("cli_args", {}), |
| "model_state_dict": rm_sd, |
| } |
| Path(args.out_radiomap_ckpt).parent.mkdir(parents=True, exist_ok=True) |
| torch.save(rm_ckpt, args.out_radiomap_ckpt) |
| print(f"✓ Radiomap ckpt: {len(rm_sd)} keys → {args.out_radiomap_ckpt}") |
|
|
| |
| |
| csi_sd = {} |
| for k, v in sd.items(): |
| if k.startswith("csi_head."): |
| csi_sd[k.replace("csi_head.", "head.", 1)] = v |
| elif k.startswith("backbone.") or k.startswith("tx_proj.") or k.startswith("tx_embed."): |
| csi_sd[k] = v |
| |
| |
| |
| num_layers = 0 |
| for k in csi_sd: |
| if k.startswith("head.decoder.layers."): |
| idx = int(k.split(".")[3]) |
| num_layers = max(num_layers, idx + 1) |
| csi_ckpt = { |
| "epoch": ckpt.get("epoch", 0), |
| "step": ckpt.get("step", 0), |
| "tag": "split_from_joint", |
| "metrics": ckpt.get("metrics", {}), |
| "cli_args": ckpt.get("cli_args", {}), |
| "model_state_dict": csi_sd, |
| "model_config": { |
| "channels": 512, |
| "num_queries": 8, |
| "num_decoder_layers": num_layers, |
| "db_low": -115.0, |
| "db_high": -7.5, |
| "delay_max_ns": 15.0, |
| "backbone_kind": "trellis2", |
| }, |
| "trainer_config": { |
| "matcher_backend": "scipy", |
| "no_object_exists_weight": 5.0, |
| }, |
| } |
| Path(args.out_csi_ckpt).parent.mkdir(parents=True, exist_ok=True) |
| torch.save(csi_ckpt, args.out_csi_ckpt) |
| print(f"✓ CIR ckpt: {len(csi_sd)} keys (head.* renamed from csi_head.*) → {args.out_csi_ckpt}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|