mapvggt / scripts /av2_pipeline.py
ChenmingWu's picture
Upload folder using huggingface_hub
8cf92b3 verified
Raw
History Blame Contribute Delete
4.96 kB
#!/usr/bin/env python3
"""Stream Argoverse 2 Sensor -> unified clips, conserving disk.
For each log: selectively download (3 front cameras + lidar timestamps + map +
calibration + annotations + poses, ~0.5 GB vs 1.1 GB full), convert to unified,
then delete the raw log. Resumable (tracks processed log ids) and disk-guarded.
python scripts/av2_pipeline.py --split train --n-logs 100 \
--out data/unified/av2 --store-longside 1024 --min-free-gb 15
"""
import argparse
import os
import shutil
import subprocess
import time
from mapgs.config import load_config
from mapgs.data.convert import convert_argoverse2
BUCKET = "s3://argoverse/datasets/av2/sensor"
NEEDED_DIRS = ["calibration", "map", "sensors/lidar"]
FRONT = ["ring_front_left", "ring_front_center", "ring_front_right"]
FILES = ["annotations.feather", "city_SE3_egovehicle.feather"]
def s5(s5cmd, *args):
subprocess.run([s5cmd, "--no-sign-request", *args], check=False,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def list_logs(s5cmd, split):
out = subprocess.run([s5cmd, "--no-sign-request", "ls", f"{BUCKET}/{split}/"],
capture_output=True, text=True).stdout
return [ln.split()[-1].rstrip("/") for ln in out.splitlines() if "DIR" in ln]
def download_log(s5cmd, split, lid, raw_root):
base = f"{BUCKET}/{split}/{lid}"
dst = os.path.join(raw_root, split, lid)
for d in NEEDED_DIRS:
os.makedirs(os.path.join(dst, d), exist_ok=True)
s5(s5cmd, "cp", f"{base}/{d}/*", os.path.join(dst, d) + "/")
for c in FRONT:
os.makedirs(os.path.join(dst, "sensors/cameras", c), exist_ok=True)
s5(s5cmd, "cp", f"{base}/sensors/cameras/{c}/*", os.path.join(dst, "sensors/cameras", c) + "/")
for f in FILES:
s5(s5cmd, "cp", f"{base}/{f}", dst + "/")
return dst
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--config", default="configs/base.yaml")
ap.add_argument("--override", nargs="*", default=["data.num_frames=20"])
ap.add_argument("--split", default="train")
ap.add_argument("--n-logs", type=int, default=100)
ap.add_argument("--out", default="data/unified/av2")
ap.add_argument("--raw-tmp", default="/mnt/william/_av2_stream")
ap.add_argument("--s5cmd", default="/tmp/s5cmd")
ap.add_argument("--store-longside", type=int, default=1024)
ap.add_argument("--max-clips-per-log", type=int, default=None)
ap.add_argument("--min-free-gb", type=float, default=15.0)
ap.add_argument("--keep-raw", action="store_true")
ap.add_argument("--shard", type=int, default=0, help="this worker's shard index")
ap.add_argument("--num-shards", type=int, default=1, help="total parallel workers")
args = ap.parse_args()
cfg = load_config(args.config, args.override)
args.raw_tmp = os.path.join(args.raw_tmp, f"shard{args.shard}") # isolate each worker's scratch
out_split = os.path.join(args.out, args.split)
os.makedirs(out_split, exist_ok=True)
# per-shard processed file (avoids concurrent-append races between workers)
processed_path = os.path.join(args.out, f"processed_{args.split}_{args.shard}of{args.num_shards}.txt")
processed = set(open(processed_path).read().split()) if os.path.exists(processed_path) else set()
all_logs = list_logs(args.s5cmd, args.split)
shard_logs = all_logs[args.shard::args.num_shards] # disjoint slice for this worker
logs = [l for l in shard_logs if l not in processed]
print(f"[shard {args.shard}/{args.num_shards}] {len(logs)} logs to process "
f"(of {len(shard_logs)} in shard, {len(processed)} done); target {args.n_logs}")
done = 0
for lid in logs:
if done >= args.n_logs:
break
free_gb = shutil.disk_usage(args.out).free / 1e9
if free_gb < args.min_free_gb:
print(f"stopping: only {free_gb:.1f} GB free (< {args.min_free_gb})")
break
t = time.time()
try:
download_log(args.s5cmd, args.split, lid, args.raw_tmp)
convert_argoverse2(args.raw_tmp, args.out, cfg, split=args.split, only_logs=[lid],
store_longside=args.store_longside, max_clips_per_log=args.max_clips_per_log)
except Exception as e:
print(f"[skip {lid[:8]}] {type(e).__name__}: {e}")
finally:
if not args.keep_raw:
shutil.rmtree(os.path.join(args.raw_tmp, args.split, lid), ignore_errors=True)
with open(processed_path, "a") as fh:
fh.write(lid + "\n")
done += 1
n_clips = len([d for d in os.listdir(out_split) if d.startswith(args.split)])
print(f"[{done}/{args.n_logs}] {lid[:8]} done in {time.time()-t:.0f}s | "
f"{n_clips} clips total | {shutil.disk_usage(args.out).free/1e9:.1f} GB free")
print(f"pipeline finished: {done} logs processed")
if __name__ == "__main__":
main()