doradream's picture
fix maps download: repo has expansion/*.json not nuscenes/maps/expansion/*.json
5e75f99
Raw
History Blame Contribute Delete
7.91 kB
#!/usr/bin/env python3
"""
HF Space 一次性环境搭建:下载权重 + 生成 BEV 地图缓存
运行一次后文件持久保存在挂载存储上,之后不再需要重复运行。
用法:
python scripts/setup_space.py # 全部下载+生成
python scripts/setup_space.py --check # 只检查状态
"""
import argparse
import os
import subprocess
import sys
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
# ---- 下载清单 ----
DOWNLOAD_TASKS = [
{
"name": "t5",
"repo": "google/t5-v1_1-xxl",
"local": ROOT / "pretrained" / "t5-v1_1-xxl",
"desc": "T5-XXL 文本编码器 (~40 GB)",
},
{
"name": "ckpt",
"repo": "flymin/MagicDriveDiT-stage3-40k-ft",
"local": ROOT / "ckpts" / "MagicDriveDiT-stage3-40k-ft",
"desc": "Stage-3 DiT 扩散模型 (~8 GB)",
},
{
"name": "vae",
"repo": "THUDM/CogVideoX-2b",
"local": ROOT / "pretrained" / "CogVideoX-2b",
"allow_patterns": ["vae/**"],
"desc": "CogVideoX-2b VAE 编码/解码器 (~2 GB)",
},
{
"name": "data_pkl",
"repo": "flymin/MagicDriveDiT-nuScenes-metadata",
"repo_type": "dataset",
"local": ROOT / "data" / "nuscenes_mmdet3d-12Hz",
"allow_patterns": [
"nuscenes_mmdet3d-12Hz/nuscenes_interp_12Hz_infos_val_with_bid.pkl",
],
"desc": "nuScenes 标注 PKL (~430 MB)",
},
{
"name": "ghost_peek",
"repo": "doradream/magicdrive-ghost-peek",
"repo_type": "dataset",
"local": ROOT / "data" / "nuscenes_mmdet3d-12Hz",
"allow_patterns": [
"ghost_peek_s8.pkl",
"ghost_peek_s25.pkl",
],
"desc": "鬼探头场景 PKL (~660 MB, 需先上传到 HF Dataset)",
},
{
"name": "nuscenes_maps",
"repo": "doradream/magicdrive-data",
"repo_type": "dataset",
"local": ROOT / "data" / "nuscenes" / "maps",
"allow_patterns": ["expansion/*.json"],
"desc": "nuScenes 官方地图文件 (~10 MB)",
},
{
"name": "map_json",
"repo": "flymin/MagicDriveDiT-nuScenes-metadata",
"repo_type": "dataset",
"local": ROOT / "data" / "nuscenes" / "interp_12Hz_trainval",
"allow_patterns": ["nuscenes/interp_12Hz_trainval/*.json"],
"desc": "nuScenes 地图 JSON (~50 MB)",
},
]
# ---- 地图缓存生成配置 ----
MAP_CACHE_DIR = ROOT / "data" / "nuscenes_mmdet3d-12Hz" / "nuscenes_map_aux_12Hz"
MAP_CACHE_CONFIG = ROOT / "configs" / "cache_gen" / "map_cache_gen_interp.yaml"
def check_path(path: Path) -> tuple[bool, str]:
"""检查目录/文件是否存在且非空"""
if not path.exists():
return False, "不存在"
files = list(path.rglob("*")) if path.is_dir() else [path]
real_files = [f for f in files if f.is_file()]
if not real_files:
return False, "空目录"
size_gb = sum(f.stat().st_size for f in real_files) / 1e9
return True, f"{len(real_files)} 个文件, {size_gb:.1f} GB"
def download_from_hf(task: dict):
"""从 HuggingFace 下载单个任务"""
from huggingface_hub import snapshot_download
kwargs = dict(
repo_id=task["repo"],
local_dir=str(task["local"]),
repo_type=task.get("repo_type", "model"),
resume_download=True,
max_workers=4,
)
if "allow_patterns" in task:
kwargs["allow_patterns"] = task["allow_patterns"]
print(f" 下载中... ({task['desc']})")
t0 = time.time()
snapshot_download(**kwargs)
elapsed = time.time() - t0
print(f" 完成 ({elapsed / 60:.1f} min)")
def generate_map_cache():
"""调用 prepare_map_aux.py 生成 BEV 地图 h5 缓存"""
print("\n--- 生成 BEV 地图缓存 ---")
# 安装 hydra(如果还没装)
try:
import hydra # noqa
except ImportError:
subprocess.check_call([sys.executable, "-m", "pip", "install", "hydra-core==1.3.0"])
# 生成 train 缓存
for split in ["val"]: # 推理只需要 val
h5_file = ROOT / f"{split}_map_cache.h5"
if h5_file.exists():
print(f" {h5_file} 已存在,跳过")
continue
print(f" 生成 {split} 地图缓存...")
result = subprocess.run(
[
sys.executable, "-u",
str(ROOT / "tools" / "prepare_data" / "prepare_map_aux.py"),
f"+process={split}",
f"subfix=map_cache",
],
cwd=str(ROOT),
capture_output=False,
env={**os.environ, "PYTHONPATH": str(ROOT)},
)
if result.returncode != 0:
print(f" [WARN] {split} 缓存生成失败 (exit {result.returncode}),将回退到实时生成")
else:
# 移动到正确位置
MAP_CACHE_DIR.mkdir(parents=True, exist_ok=True)
h5_file.rename(MAP_CACHE_DIR / h5_file.name)
print(f" [OK] 已保存到 {MAP_CACHE_DIR / h5_file.name}")
def main():
parser = argparse.ArgumentParser(description="HF Space 一次性环境搭建")
parser.add_argument("--check", action="store_true", help="只检查状态,不执行")
parser.add_argument("--skip-download", action="store_true", help="跳过下载")
parser.add_argument("--skip-cache", action="store_true", help="跳过地图缓存生成")
args = parser.parse_args()
os.chdir(str(ROOT))
sys.path.insert(0, str(ROOT))
print("=" * 60)
print("MagicDrive-V2 HF Space 环境检查")
print(f"Root: {ROOT}")
print("=" * 60)
# ---- 检查状态 ----
all_ok = True
print("\n【权重/数据文件】")
for task in DOWNLOAD_TASKS:
ok, msg = check_path(task["local"])
status = "[OK]" if ok else "[MISS]"
if not ok:
all_ok = False
print(f" {status} {task['name']:12s} {msg}")
print("\n【BEV 地图缓存】")
cache_ok, cache_msg = check_path(MAP_CACHE_DIR)
if not cache_ok:
all_ok = False
print(f" {'[OK]' if cache_ok else '[MISS]'} map_cache {cache_msg}")
if args.check:
if all_ok:
print("\n所有文件就绪,可以直接推理!")
else:
print("\n部分文件缺失,运行: python scripts/setup_space.py")
return
# ---- 下载 ----
if not args.skip_download:
print("\n" + "=" * 60)
print("下载权重与数据")
print("=" * 60)
for task in DOWNLOAD_TASKS:
ok, msg = check_path(task["local"])
if ok:
print(f"\n[{task['name']}] 已存在 -> 跳过")
continue
print(f"\n[{task['name']}] {task['desc']}")
try:
download_from_hf(task)
except Exception as e:
print(f" [ERR] 下载失败: {e}")
print(f" 你可以稍后重试: python scripts/setup_space.py")
# ---- 生成地图缓存 ----
if not args.skip_cache:
cache_ok, _ = check_path(MAP_CACHE_DIR)
if cache_ok:
print("\n[BEV 地图缓存] 已存在 -> 跳过")
else:
generate_map_cache()
# ---- 最终状态 ----
print("\n" + "=" * 60)
print("最终状态")
print("=" * 60)
all_ok = True
for task in DOWNLOAD_TASKS:
ok, msg = check_path(task["local"])
if not ok:
all_ok = False
print(f" {'[OK]' if ok else '[MISS]'} {task['name']}")
cache_ok, _ = check_path(MAP_CACHE_DIR)
if not cache_ok:
all_ok = False
print(f" {'[OK]' if cache_ok else '[MISS]'} map_cache")
if all_ok:
print("\n全部就绪!可以运行推理了。")
else:
print("\n有缺失项,请重新运行或检查网络。")
if __name__ == "__main__":
main()