Buckets:
| """cwm3/data/extract_pose_causal_routes.py — ROUTE-LEVEL causal driver pose at 10 Hz for every s12 route (causal replacement of | |
| s8_pose/cache/pose10hz, whose 400×400 crop was a whole-route median = non-causal). | |
| Time base: frame/20 as s8_pose/extract_pose.py (fi = 2k, t = k/10; never container fps). Frames are decoded with cv2 seek+grab | |
| (bit-identical to decord, verified 2026-09-10) in worker processes and resized aspect-preserving to width 640 (like the old | |
| 640-wide decode); coordinates are stored NORMALISED (x/W, y/H), so the decode size is irrelevant to the output. | |
| Spans: union over the route's s12 anchors of [t − 8.2, t + 5.2] (8 s history + 5 s future + 0.2 s), merged when gaps ≤ 10 s, | |
| clipped to the video (the old cache used [t − 4.2, t]). | |
| 1. Causal driver box. YOLO11x-pose (ultralytics, imgsz 384, half, conf 0.3) on every 10 Hz frame; persons with area < 2 % of the | |
| frame ignored (driver_roi v2 rule). Driver = the candidate nearest the device's driver-side prior cx (|Δcx| ≤ 0.18 = v2 cluster | |
| gap); prior = per-dongle median of person_cx_norm over the ROI mirror's solo-occupant pose_detector clips (results/roi, ≥ 3 clips), | |
| else cwm2/private/person_diag.json['dside'], else BOOTSTRAPPED CAUSALLY inside the route (v2/extract_full analogue): solo-person | |
| frames' cx are accumulated and become the prior after 30 of them; before that the largest-area candidate is taken (flag). | |
| Once ≥ 30 frames were selected the reference cx becomes the running median of the selected cx. | |
| box(t) = per-coordinate median over selected boxes on MOVING frames ≤ t (vEgo > 2 m/s from s14 grid10, column recovered by AST | |
| from grid_s14.py + canspec.FEATURES, nearest 0.1 s; NaN vEgo = not moving); before any moving frame: median over all selected | |
| frames so far (fallback); stage 1 (warm-up) until 30 s (300) of moving frames, stage 2 (expanding) until 60 s (600) of moving | |
| frames, then FROZEN (stage 3, box_frozen_from_t). The box trajectory is stored per route (native px). | |
| 2. RTMW-x-l (rtmlib 'balanced' pose ONNX, onnxruntime CUDA, detection-free) on box(t) expanded by 10 % (same code path and | |
| HALPE-136 mapping as extract_pose_causal.py) → results/pose_causal_routes/<uid>.npz: | |
| t f32[N], frame_idx i64[N], kpts f16[N,136,3] (x/W, y/H, conf; NaN where no box), mask[N,136] (finite ∧ conf ≥ 0.3), | |
| box f32[N,4] native px (NaN undefined), box_stage u8[N] {0 none,1 warm-up,2 expanding,3 frozen}, box_frozen_from_t, | |
| driver_det[N], n_persons[N], moving[N], dside_prior, dside_source, decode_wh, native_wh, spans, model_ids, video_source. | |
| v2 (--population-prior auto, --out-dir): routes whose device has no prior use the POPULATION driver-side prior (median cx over the | |
| mirror-prior dongles) instead of the largest-area fallback — causal and route-independent. Block-level checkpointing was NOT added | |
| (tracker state + in-flight decode futures would need serialising; not a small change). | |
| GPU: ≤ 6 GB by construction (YOLO fp16 batch ≤ 24 + ORT arena limit); usable without the GPU lock only if decode-bound (bench). | |
| Resumable (existing npz skipped; --max-minutes stops starting new routes). Exit 3 = work remaining, 0 = done.""" | |
| import argparse, ast, json, math, shutil, sys, time | |
| import multiprocessing as mp | |
| from concurrent.futures import ProcessPoolExecutor | |
| from pathlib import Path | |
| import numpy as np | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT / "common")); sys.path.insert(0, str(ROOT / "data")) | |
| from extract_pose_causal import box_geometry, crop_input, wb133_to_halpe136, Pose, resolve_video, MODEL_ID as RTMW_ID, SCORE_TH, MARGIN, IN_W, IN_H # noqa: E402 | |
| EXPLORE = Path("/home/USER/explore"); S12R = EXPLORE / "s12_wm" / "results"; GRID10 = EXPLORE / "s14_corr" / "cache" / "grid10" | |
| LEAVES = ROOT / "results" / "baton_leaves.json"; OUT = ROOT / "results" / "pose_causal_routes"; ROI = ROOT / "results" / "roi" | |
| CLIP_MAP = EXPLORE / "cwm2" / "private" / "clip_map_full.json"; PERSON_DIAG = EXPLORE / "cwm2" / "private" / "person_diag.json" | |
| YOLO_W = Path("/home/USER/Drive/explore/yolo11x-pose.pt") | |
| FPS, HZ, DEC_W = 20, 10, 640 | |
| PAD_PRE, PAD_POST, MERGE_GAP = 8.2, 5.2, 10.0 | |
| MIN_AREA, GAP_CX, V_MOVE = 0.02, 0.18, 2.0 | |
| N_PRIOR_BOOT, N_REF, N_WARM, N_FREEZE = 30, 30, 300, 600 | |
| YOLO_ID = "yolo11x-pose.pt (ultralytics 8.4.66), imgsz 384, half, conf 0.3, persons area >= 2 %" | |
| def leaf_of(uid): | |
| p = uid.split("__"); return "/".join(p[:3]) + "/" + "__".join(p[3:]) | |
| def vego_col(): | |
| sys.path.insert(0, str(EXPLORE / "s3_can_baseline")); import canspec | |
| tree = ast.parse((EXPLORE / "s14_corr" / "grid_s14.py").read_text()); lists = {} | |
| for node in tree.body: | |
| if isinstance(node, ast.Assign) and len(node.targets) == 1 and isinstance(node.targets[0], ast.Name) and node.targets[0].id in ("DCOLS", "PCOLS", "RCOLS"): | |
| lists[node.targets[0].id] = [ast.literal_eval(e) for e in node.value.elts] | |
| cols = lists["DCOLS"] + lists["PCOLS"] + list(canspec.FEATURES) + lists["RCOLS"]; return cols.index("vEgo") | |
| def dside_priors(): | |
| """per-dongle driver-side cx prior: ROI mirror (solo-occupant pose_detector clips, >= 3) else person_diag; cached.""" | |
| cache = OUT / "dside_prior.json" | |
| if cache.exists(): return json.load(open(cache)) | |
| cm = json.load(open(CLIP_MAP)); by = {} | |
| for p in ROI.glob("*.json"): | |
| r = json.load(open(p)) | |
| if r.get("roi_source") == "pose_detector" and r.get("n_persons_max") == 1 and r.get("person_cx_norm") is not None: | |
| by.setdefault(cm[r["clip_id"]]["dongle"], []).append(r["person_cx_norm"]) | |
| pri = {d: dict(cx=float(np.median(v)), n=len(v), source="roi_mirror_solo_median") for d, v in by.items() if len(v) >= 3} | |
| diag = json.load(open(PERSON_DIAG)).get("dside", {}) if PERSON_DIAG.exists() else {} | |
| for d, cx in diag.items(): | |
| if d not in pri: pri[d] = dict(cx=float(cx), n=None, source="person_diag_dside") | |
| OUT.mkdir(parents=True, exist_ok=True); cache.write_text(json.dumps(pri, indent=1)); return pri | |
| def anchors_by_uid(): | |
| A = {} | |
| for reg in ("manual", "engaged"): | |
| for sp in ("train", "val", "test"): | |
| z = np.load(S12R / f"targets_{reg}_{sp}.npz", allow_pickle=True) | |
| for u, t in zip(z["uid"], z["t"]): A.setdefault(u, []).append(float(t)) | |
| return {u: np.sort(np.array(v)) for u, v in A.items()} | |
| def spans_of(ts, dur): | |
| a, b = np.maximum(ts - PAD_PRE, 0.0), np.minimum(ts + PAD_POST, dur); o = np.argsort(a); a, b = a[o], b[o]; out = []; ca, cb = a[0], b[0] | |
| for x, y in zip(a[1:], b[1:]): | |
| if x > cb + MERGE_GAP: out.append((ca, cb)); ca, cb = x, y | |
| else: cb = max(cb, y) | |
| out.append((ca, cb)); return out | |
| def decode_block(job): | |
| """worker: (vpath, fi_list, dec_w, dec_h) -> uint8 [n, dec_h, dec_w, 3] BGR (grab every frame from fi[0]..fi[-1], retrieve the 10 Hz ones).""" | |
| import cv2; cv2.setNumThreads(2) | |
| vpath, fis, dw, dh = job; t = time.time() | |
| cap = cv2.VideoCapture(vpath); cap.set(cv2.CAP_PROP_N_THREADS, 2); cap.set(cv2.CAP_PROP_POS_FRAMES, int(fis[0])); want = {int(f): i for i, f in enumerate(fis)} # 2 ffmpeg threads/worker: no oversubscription | |
| out = np.zeros((len(fis), dh, dw, 3), np.uint8); got = np.zeros(len(fis), bool); n_grab = 0 | |
| for i in range(int(fis[0]), int(fis[-1]) + 1): | |
| if not cap.grab(): break | |
| n_grab += 1 | |
| if i in want: | |
| ok, fr = cap.retrieve() | |
| if not ok: break | |
| out[want[i]] = cv2.resize(fr, (dw, dh), interpolation=cv2.INTER_AREA); got[want[i]] = True | |
| cap.release(); return dict(frames=out, got=got, n_grab=n_grab, secs=time.time() - t) | |
| def infer_batched(pose, crops_u8, center, scale, chunk=96): | |
| """RTMW on a batch of crops with per-frame (center, scale): same maths as extract_pose_causal.Pose.infer, vectorised.""" | |
| from extract_pose_causal import MEAN, STD | |
| x = np.ascontiguousarray(((crops_u8.astype(np.float32) - MEAN) / STD).transpose(0, 3, 1, 2)) | |
| locs, vals = [], [] | |
| for i in range(0, len(x), chunk): | |
| sx_, sy_ = pose.sess.run(pose.outs, {pose.inp: x[i:i + chunk]}); l, v = pose.simcc(sx_, sy_); locs.append(l); vals.append(v) | |
| locs = np.concatenate(locs); vals = np.concatenate(vals) | |
| kp = locs / 2.0 / np.array([IN_W, IN_H], np.float32) * scale[:, None, :] + center[:, None, :] - scale[:, None, :] / 2 | |
| kp[locs[..., 0] < 0] = np.nan | |
| return np.concatenate([kp, vals[..., None]], -1).astype(np.float32) | |
| class DriverTracker: | |
| """causal driver selection + expanding-median box (decode-frame coordinates).""" | |
| def __init__(self, prior_cx, dw, dh): | |
| self.prior = prior_cx; self.dw, self.dh = dw, dh; self.boot = []; self.sel_cx = []; self.mov = [[], [], [], []]; self.all = [[], [], [], []] | |
| self.n_mov = 0; self.frozen = None; self.stage = 0; self.uncertain = 0 | |
| def _ref(self): | |
| if len(self.sel_cx) >= N_REF: return float(np.median(self.sel_cx)) | |
| if self.prior is not None: return self.prior | |
| if len(self.boot) >= N_PRIOR_BOOT: self.prior = float(np.median(self.boot)); return self.prior | |
| return None | |
| def step(self, cands, moving): | |
| """cands: list of (cx_norm, area_norm, box_xyxy_dec) -> (box_dec or None, selected bool)""" | |
| sel = None; ref = self._ref() | |
| if cands: | |
| if ref is not None: | |
| c = min(cands, key=lambda z: abs(z[0] - ref)) | |
| if abs(c[0] - ref) <= GAP_CX: sel = c | |
| else: | |
| if len(cands) == 1: self.boot.append(cands[0][0]); sel = cands[0] | |
| else: sel = max(cands, key=lambda z: z[1]); self.uncertain += 1 | |
| if sel is not None: | |
| self.sel_cx.append(sel[0]) | |
| if self.frozen is None: | |
| for j in range(4): self.all[j].append(float(sel[2][j])) | |
| if moving: | |
| for j in range(4): self.mov[j].append(float(sel[2][j])) | |
| self.n_mov += 1 | |
| if self.frozen is not None: self.stage = 3; return self.frozen, sel is not None | |
| if self.n_mov >= N_FREEZE: | |
| self.frozen = np.array([np.median(v) for v in self.mov], np.float32); self.stage = 3; return self.frozen, sel is not None | |
| if self.n_mov > 0: | |
| self.stage = 1 if self.n_mov < N_WARM else 2; return np.array([np.median(v) for v in self.mov], np.float32), sel is not None | |
| if len(self.all[0]) > 0: | |
| self.stage = 1; return np.array([np.median(v) for v in self.all], np.float32), sel is not None | |
| self.stage = 0; return None, False | |
| def main(): | |
| ap = argparse.ArgumentParser(); ap.add_argument("--uids", default=""); ap.add_argument("--all", action="store_true"); ap.add_argument("--limit", type=int, default=0) | |
| ap.add_argument("--max-minutes", type=float, default=20.0); ap.add_argument("--decode-workers", type=int, default=6); ap.add_argument("--block", type=int, default=300, help="10 Hz frames per decode block") | |
| ap.add_argument("--yolo-batch", type=int, default=48); ap.add_argument("--ort-mem-gb", type=float, default=2.0); ap.add_argument("--bench-out", default=""); ap.add_argument("--force", action="store_true") | |
| ap.add_argument("--out-dir", default="", help="versioned output dir (default results/pose_causal_routes)"); ap.add_argument("--population-prior", default="", help="'auto' = median driver-side cx over the mirror-prior dongles, or a float; used ONLY for routes whose device has no prior (replaces the largest-area fallback)") | |
| ap.add_argument("--vram-check-gb", type=float, default=0.0, help="abort unless at least this much GPU memory is free before loading models") | |
| a = ap.parse_args(); t_start = time.time() | |
| global OUT | |
| PRIOR_DIR = OUT # dside_prior.json / s12_uids.txt always come from the v1 location | |
| if a.out_dir: OUT = Path(a.out_dir) | |
| OUT.mkdir(parents=True, exist_ok=True) | |
| from runmeta import write_run_json | |
| import cv2, torch, psutil | |
| if a.vram_check_gb > 0: | |
| free_b, total_b = torch.cuda.mem_get_info(); print(f"VRAM free {free_b/1e9:.1f} / {total_b/1e9:.1f} GB (need {a.vram_check_gb})", flush=True) | |
| if free_b < a.vram_check_gb * 1e9: print("VRAM_CHECK_FAILED", flush=True); sys.exit(4) | |
| from ultralytics import YOLO | |
| uids = [l.strip() for l in open(a.uids) if l.strip()] if a.uids else [] | |
| if a.all: uids += [l.strip() for l in open(PRIOR_DIR / "s12_uids.txt") if l.strip()] | |
| seen = set(); uids = [u for u in uids if not (u in seen or seen.add(u))] | |
| if a.limit: uids = uids[:a.limit] | |
| todo = [u for u in uids if a.force or not (OUT / f"{u}.npz").exists()] | |
| leaves = json.load(open(LEAVES)); pri = json.load(open(PRIOR_DIR / "dside_prior.json")) if (PRIOR_DIR / "dside_prior.json").exists() else dside_priors(); VCOL = vego_col(); A = anchors_by_uid() | |
| pop_prior = None | |
| if a.population_prior: | |
| pop_prior = float(np.median([v["cx"] for v in pri.values() if v.get("source") == "roi_mirror_solo_median"])) if a.population_prior == "auto" else float(a.population_prior) | |
| print(f"population driver-side prior cx = {pop_prior:.4f} (causal, route-independent; used only where the device has no prior)", flush=True) | |
| print(f"routes requested {len(uids)} todo {len(todo)}; dside priors {len(pri)}; vEgo col {VCOL}", flush=True) | |
| yolo = YOLO(str(YOLO_W)); pose = Pose(gpu_mem_limit=a.ort_mem_gb * 1e9) | |
| pool = ProcessPoolExecutor(max_workers=a.decode_workers, mp_context=mp.get_context("spawn")) | |
| stats = dict(download_bytes=0, download_secs=0.0, n_downloads=0, download_leaves=[]); recs, fails = [], []; budget_hit = False | |
| for u in todo: | |
| if time.time() - t_start > a.max_minutes * 60: budget_hit = True; break | |
| leaf = leaf_of(u); tr0 = time.time() | |
| try: | |
| vpath, src = resolve_video(leaf, leaves, stats) | |
| cap = cv2.VideoCapture(vpath); W, H, n_frames = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)), int(cap.get(cv2.CAP_PROP_FRAME_COUNT)); cap.release() | |
| if n_frames <= 0 or W <= 0: raise RuntimeError("cannot read video header") | |
| dw = DEC_W; dh = int(round(H * DEC_W / W)); sx, sy = W / dw, H / dh | |
| dur = n_frames / FPS; ts = A.get(u) | |
| if ts is None: raise RuntimeError("no s12 anchors") | |
| spans = spans_of(ts, dur) | |
| ks = np.unique(np.concatenate([np.arange(int(math.floor(a0 * HZ)), int(math.ceil(b0 * HZ)) + 1) for a0, b0 in spans])); fis = 2 * ks; keep = fis < n_frames; ks, fis = ks[keep], fis[keep] | |
| N = len(ks); tt = (ks / HZ).astype(np.float32) | |
| g = np.load(GRID10 / f"{u}.npz"); gt, gv = g["t"], g["G"][:, VCOL] | |
| gi = np.clip(np.round(tt * 10).astype(np.int64) - int(round(gt[0] * 10)), 0, len(gt) - 1); moving = np.nan_to_num(gv[gi], nan=-1.0) > V_MOVE | |
| dongle = u.split("__")[1]; pr = pri.get(dongle); prior_cx = pr["cx"] if pr else None | |
| if prior_cx is None and pop_prior is not None: prior_cx = pop_prior; pr = dict(cx=pop_prior, source="population_median_cx") | |
| trk = DriverTracker(prior_cx, dw, dh) | |
| kpts = np.full((N, 136, 3), np.nan, np.float32); box = np.full((N, 4), np.nan, np.float32); stage = np.zeros(N, np.uint8); det = np.zeros(N, bool); npers = np.zeros(N, np.uint8); frozen_t = np.nan | |
| blocks = [np.arange(i, min(i + a.block, N)) for i in range(0, N, a.block)] | |
| futs = []; bi = 0; t_dec = t_yolo = t_rtmw = 0.0; n_grab = 0; n_yolo = 0; n_rtmw = 0 | |
| def submit_upto(n): | |
| nonlocal bi | |
| while bi < len(blocks) and len(futs) < n: | |
| b = blocks[bi]; futs.append(pool.submit(decode_block, (vpath, fis[b], dw, dh))); bi += 1 | |
| submit_upto(2 * a.decode_workers) | |
| for b in blocks: | |
| res = futs.pop(0).result(); submit_upto(2 * a.decode_workers); t_dec += res["secs"]; n_grab += res["n_grab"] | |
| frames = res["frames"]; got = res["got"] | |
| # YOLO on the block | |
| t1 = time.time(); cands_all = [] | |
| for i0 in range(0, len(b), a.yolo_batch): | |
| rs = yolo.predict(list(frames[i0:i0 + a.yolo_batch]), imgsz=384, half=True, conf=0.3, verbose=False, classes=[0]) | |
| for r in rs: | |
| cc = [] | |
| if r.boxes is not None and len(r.boxes): | |
| bx = r.boxes.xyxy.cpu().numpy() | |
| for x0, y0, x1, y1 in bx: | |
| area = (x1 - x0) * (y1 - y0) / (dw * dh) | |
| if area >= MIN_AREA: cc.append(((x0 + x1) / 2 / dw, area, (x0, y0, x1, y1))) | |
| cands_all.append(cc) | |
| t_yolo += time.time() - t1; n_yolo += len(b) | |
| # causal tracker + crops | |
| crops = []; idx_ok = [] | |
| for j, i in enumerate(b): | |
| if not got[j]: cands_all[j] = [] | |
| bx, s_ = trk.step(cands_all[j], bool(moving[i])); det[i] = s_; npers[i] = min(len(cands_all[j]), 255); stage[i] = trk.stage | |
| if trk.frozen is not None and np.isnan(frozen_t): frozen_t = float(tt[i]) | |
| if bx is not None and got[j]: | |
| box[i] = [bx[0] * sx, bx[1] * sy, bx[2] * sx, bx[3] * sy] | |
| x0, y0, x1, y1 = bx; w, h = x1 - x0, y1 - y0 | |
| used = [max(0, x0 - MARGIN * w), max(0, y0 - MARGIN * h), min(dw, x1 + MARGIN * w), min(dh, y1 + MARGIN * h)] | |
| c, s = box_geometry(used); crops.append((crop_input(frames[j], c, s), c, s)); idx_ok.append(i) | |
| if crops: | |
| t2 = time.time() | |
| # one CUDA batch per block with PER-FRAME geometry (box changes every frame while the median expands) | |
| imgs = np.stack([c_[0] for c_ in crops]); cen = np.stack([c_[1] for c_ in crops]).astype(np.float32); scl = np.stack([c_[2] for c_ in crops]).astype(np.float32) | |
| k133 = infer_batched(pose, imgs, cen, scl) | |
| h136 = wb133_to_halpe136(k133); h136[..., 0] *= sx / W; h136[..., 1] *= sy / H # decode px -> native px -> normalised | |
| kpts[idx_ok] = h136 | |
| t_rtmw += time.time() - t2; n_rtmw += len(crops) | |
| k16 = kpts.astype(np.float16); mask = np.isfinite(k16).all(-1) & (np.nan_to_num(k16[..., 2].astype(np.float32)) >= SCORE_TH) | |
| np.savez_compressed(OUT / f"{u}.npz", t=tt, frame_idx=fis.astype(np.int64), kpts=k16, mask=mask, box=box, box_stage=stage, box_frozen_from_t=np.float32(frozen_t), driver_det=det, n_persons=npers, moving=moving, | |
| dside_prior=np.float32(prior_cx if prior_cx is not None else np.nan), dside_source=str(pr["source"] if pr else ("route_bootstrap" if trk.prior is not None else "none_largest_area")), | |
| n_uncertain_largest_area=int(trk.uncertain), decode_wh=np.array([dw, dh], np.int32), native_wh=np.array([W, H], np.int32), spans=np.array(spans, np.float32), n_video_frames=n_frames, | |
| model_ids=np.array([YOLO_ID, RTMW_ID]), kpt_order="halpe136", score_th=SCORE_TH, margin=MARGIN, video_source=src, time_base="frame/20: t=k/10, frame_idx=2k", v_move_mps=V_MOVE, | |
| box_rule=np.array("per-coordinate median of selected driver boxes on moving frames <= t; warm-up <300 moving frames, expanding <600, then frozen")) | |
| wall = time.time() - tr0 | |
| recs.append(dict(uid=u, n_frames_10hz=int(N), n_grab=int(n_grab), span_cover=float(sum(b0 - a0 for a0, b0 in spans) / dur), wall_s=round(wall, 1), decode_worker_s=round(t_dec, 1), yolo_s=round(t_yolo, 1), rtmw_s=round(t_rtmw, 1), | |
| n_rtmw=int(n_rtmw), det_rate=float(det.mean()), moving_frac=float(moving.mean()), box_frozen_from_t=frozen_t, dside_source=str(pr["source"] if pr else "bootstrap/none"), video_source=src, | |
| mask_body_rate=float(mask[:, :17].mean()), gpu_peak_torch_GB=round(torch.cuda.max_memory_reserved() / 1e9, 2))) | |
| print(f"{u[:60]} N={N} wall {wall:.0f}s dec {t_dec:.0f}s(worker) yolo {t_yolo:.0f}s rtmw {t_rtmw:.0f}s det {det.mean():.3f} frozen@{frozen_t} rss {psutil.Process().memory_info().rss/1e9:.1f}GB", flush=True) | |
| if src == "remote_download": shutil.rmtree(Path(vpath).parent, ignore_errors=True) | |
| except Exception as e: | |
| fails.append(dict(uid=u, err=repr(e)[:300])); print(f"FAIL {u[:60]}: {repr(e)[:200]}", flush=True) | |
| pool.shutdown(wait=True) | |
| remaining = len(todo) - len(recs) - len(fails); wall = time.time() - t_start | |
| summ = dict(n_requested=len(uids), n_todo=len(todo), n_done=len(recs), n_failed=len(fails), n_remaining=max(0, remaining), budget_hit=budget_hit, wall_s=round(wall, 1), decode_workers=a.decode_workers, yolo_batch=a.yolo_batch) | |
| if recs: | |
| fr = sum(r["n_frames_10hz"] for r in recs); w_no_dl = wall - stats["download_secs"] | |
| gpu_s = sum(r["yolo_s"] + r["rtmw_s"] for r in recs) | |
| summ.update(frames_10hz=fr, frames_grabbed=sum(r["n_grab"] for r in recs), yolo_ms_per_frame=round(1000 * sum(r["yolo_s"] for r in recs) / fr, 3), rtmw_ms_per_frame=round(1000 * sum(r["rtmw_s"] for r in recs) / max(sum(r["n_rtmw"] for r in recs), 1), 3), | |
| worker_decode_fps=round(sum(r["n_grab"] for r in recs) / max(sum(r["decode_worker_s"] for r in recs), 1e-9), 1), aggregate_decode_fps=round(sum(r["n_grab"] for r in recs) / max(w_no_dl, 1e-9), 1), | |
| frames_10hz_per_s=round(fr / max(w_no_dl, 1e-9), 1), gpu_busy_frac=round(gpu_s / max(w_no_dl, 1e-9), 3), decode_bound=bool(gpu_s / max(w_no_dl, 1e-9) < 0.5), | |
| det_rate_mean=round(float(np.mean([r["det_rate"] for r in recs])), 4), gpu_peak_torch_GB=max(r["gpu_peak_torch_GB"] for r in recs), ort_mem_limit_GB=a.ort_mem_gb, | |
| download=dict(n=stats["n_downloads"], bytes=stats["download_bytes"], secs=round(stats["download_secs"], 1), MBps=round(stats["download_bytes"] / 1e6 / stats["download_secs"], 1) if stats["download_secs"] else None)) | |
| # projection over all s12 routes: 10 Hz frames in spans (local videos measured; remote estimated from bytes) | |
| try: | |
| tot10 = json.load(open(OUT / "span_frames_total.json"))["frames_10hz_total"] | |
| except Exception: tot10 = None | |
| if tot10: summ["projection_all_routes"] = dict(frames_10hz_total=tot10, wall_h=round(tot10 / summ["frames_10hz_per_s"] / 3600, 2), gpu_h=round(tot10 * (summ["yolo_ms_per_frame"] + summ["rtmw_ms_per_frame"]) / 3.6e6, 2)) | |
| if a.bench_out: Path(a.bench_out).write_text(json.dumps(dict(utc=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), summary=summ, routes=recs, fails=fails), indent=1)) | |
| write_run_json(OUT, "extract_pose_causal_routes", [Path(__file__), ROOT / "data" / "extract_pose_causal.py"], [LEAVES], None, t_start, extra=dict(summary=summ, fails_head=fails[:20]), input_listing=False) | |
| print(("BUDGET_EXIT " if budget_hit else "ALL_DONE ") + json.dumps({k: summ[k] for k in ("n_done", "n_failed", "n_remaining", "wall_s")}), flush=True) | |
| sys.exit(3 if (budget_hit or remaining > 0) else 0) | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 23.3 kB
- Xet hash:
- e1deb3f2e38611c47d255e86710bb08eff731bc675e63ed2c1e1d236c348c0f3
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.