Spaces:
Sleeping
Sleeping
Dheepak Karan
Align the demo with what actually ships, and pull model code from the main repo
c8f05dd Download visualization/make_demo.py from dheepakkaran/multi-camera-bev: direct link, hf CLI and curl.
- Browser
- Download file 8.1 kB
-
https://huggingface.co/spaces/dheepakkaran/multi-camera-bev/resolve/main/visualization/make_demo.py
- Command line
-
hf download hf://spaces/dheepakkaran/multi-camera-bev/visualization/make_demo.py
-
curl -L -o make_demo.py https://huggingface.co/spaces/dheepakkaran/multi-camera-bev/resolve/main/visualization/make_demo.py
8.1 kB
| # ============================================================ | |
| # make_demo.py | |
| # ============================================================ | |
| # | |
| # ETHUKU CREATE PANNINOM? | |
| # ββββββββββββββββββββββ | |
| # README-ku / LinkedIn-ku oru portfolio demo venum. Recruiter 5 second | |
| # thaan paapaanga - antha 5 second-la "6 camera -> BEV detections" + | |
| # "TensorRT 3.9x speedup" rendum theriyanum. | |
| # | |
| # bev_renderer.py oru frame varaiyum. Ithu: | |
| # - thodarchiyaana frames (scene-la oru vari, so motion theriyum) | |
| # - real T4 benchmark numbers-ai padathula-ye potrom | |
| # - GIF + thani PNG rendum | |
| # | |
| # MUNADI FILE ODA CONNECTION: | |
| # ββββββββββββββββββββββββββ | |
| # visualization/bev_renderer.py -> draw_bev, denormalize reuse | |
| # training/evaluate.py -> decode_predictions | |
| # | |
| # INPUT / OUTPUT: | |
| # ββββββββββββββ | |
| # Output: runs/demo/demo.gif + frame_*.png | |
| # | |
| # EPADI USE AAGUM: | |
| # βββββββββββββββ | |
| # python -m visualization.make_demo --frames 20 | |
| # | |
| # ============================================================ | |
| import argparse | |
| import os | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| from data.scripts.constants import CAMERAS, CLASSES | |
| from visualization.bev_renderer import denormalize, draw_bev, CLASS_COLORS | |
| # Kaggle T4-la nijamaa alandha numbers. Hardcode pannurom yaen? | |
| # Ithu Mac-la odum, aana kaatta vendiyathu T4 result. Mac-la | |
| # TensorRT-e illa, so anga alandhadhai inga kondu varom. | |
| BENCHMARK = [ | |
| ("PyTorch FP32", 32.66, 30.6, "1.00x"), | |
| ("ONNX Runtime", 30.20, 33.1, "1.08x"), | |
| ("TensorRT FP32", 24.34, 41.1, "1.34x"), # <- ithu thaan ship aachu | |
| ("TensorRT FP16", 61.56, 16.2, "0.53x"), | |
| ("TensorRT INT8", 8.52, 117.3, "3.83x"), | |
| ] | |
| SHIPPED = "TensorRT FP32" | |
| def draw_stats_panel(ax) -> None: | |
| """ | |
| Benchmark table-ai padathula text-a varaiyurathu. | |
| Yaen padathula? README-la thani table irundhaalum, GIF-ai | |
| LinkedIn-la neradiya podumbodhu numbers kooda pogum. | |
| """ | |
| ax.axis("off") | |
| ax.set_facecolor("#0a0a14") | |
| y = 0.97 | |
| ax.text(0.5, y, "Tesla T4 | 6 cameras -> BEV", ha="center", | |
| color="#e0e0e0", fontsize=11, weight="bold", | |
| transform=ax.transAxes) | |
| y -= 0.09 | |
| ax.text(0.02, y, f"{'Backend':<15}{'ms':>7}{'FPS':>7}{'vs base':>9}", | |
| color="#8a8a9a", fontsize=8.5, family="monospace", | |
| transform=ax.transAxes) | |
| y -= 0.035 | |
| ax.plot([0.02, 0.98], [y, y], color="#2a2a3a", lw=0.8, | |
| transform=ax.transAxes, clip_on=False) | |
| for name, ms, fps, speed in BENCHMARK: | |
| y -= 0.055 | |
| # Vegam jaasti INT8-ku thaan. Aana ship aanadhu FP32 - | |
| # highlight pannurathu ship aanadhai, vegathai illa. | |
| best = name == SHIPPED | |
| color = "#00d4ff" if best else "#b0b0c0" | |
| ax.text(0.02, y, f"{name:<15}{ms:>7.1f}{fps:>7.1f}{speed:>9}", | |
| color=color, fontsize=8.5, family="monospace", | |
| weight="bold" if best else "normal", | |
| transform=ax.transAxes) | |
| y -= 0.10 | |
| for line, col in [ | |
| ("Shipped: TensorRT FP32", "#00d4ff"), | |
| ("1.34x faster, nothing given up", "#8a8a9a"), | |
| ("", "#6a6a7a"), | |
| ("INT8 was 3.83x and 16x smaller,", "#ff8c00"), | |
| ("but kept only 34% of the original", "#8a8a9a"), | |
| ("detections. Fast and wrong is worse", "#8a8a9a"), | |
| ("than slower and right.", "#8a8a9a"), | |
| ]: | |
| ax.text(0.02, y, line, color=col, fontsize=8, | |
| transform=ax.transAxes) | |
| y -= 0.045 | |
| y -= 0.03 | |
| ax.plot([0.02, 0.98], [y, y], color="#2a2a3a", lw=0.8, | |
| transform=ax.transAxes, clip_on=False) | |
| y -= 0.055 | |
| for line in ["SimpleBEV 5.5M params", | |
| "EfficientNet-B0 + Lift-Splat-Shoot", | |
| "ResNet-18 FPN + CenterPoint head", | |
| "nuScenes mini | no LiDAR"]: | |
| ax.text(0.02, y, line, color="#6a6a7a", fontsize=7.5, | |
| transform=ax.transAxes) | |
| y -= 0.04 | |
| def render(images, gt_boxes, pred_boxes, out_path, frame_i, n_frames, | |
| score_thresh=0.2): | |
| """Oru demo frame: cameras | BEV | stats.""" | |
| fig = plt.figure(figsize=(19, 7.5), facecolor="#0a0a14") | |
| gs = fig.add_gridspec(3, 5, width_ratios=[0.78, 0.78, 0.1, 1.7, 0.95], | |
| hspace=0.1, wspace=0.05) | |
| layout = [("CAM_FRONT_LEFT", 0, 0), ("CAM_FRONT_RIGHT", 0, 1), | |
| ("CAM_FRONT", 1, 0), ("CAM_BACK", 1, 1), | |
| ("CAM_BACK_LEFT", 2, 0), ("CAM_BACK_RIGHT", 2, 1)] | |
| for cam, r, c in layout: | |
| ax = fig.add_subplot(gs[r, c]) | |
| ax.imshow(denormalize(images[CAMERAS.index(cam)])) | |
| ax.set_title(cam.replace("CAM_", ""), color="#8a8a9a", fontsize=6.5, pad=1) | |
| ax.axis("off") | |
| ax_bev = fig.add_subplot(gs[:, 3]) | |
| draw_bev(ax_bev, gt_boxes, pred_boxes, score_thresh) | |
| n = sum(1 for b in pred_boxes if b["score"] >= score_thresh) | |
| ax_bev.set_title(f"Bird's Eye View | frame {frame_i+1}/{n_frames} | " | |
| f"{n} detections", color="#e0e0e0", fontsize=10, pad=8) | |
| present = sorted({b["cls"] for b in pred_boxes if b["score"] >= score_thresh}) | |
| if present: | |
| handles = [plt.Line2D([0], [0], marker="s", linestyle="", markersize=6, | |
| color=CLASS_COLORS[c], label=CLASSES[c]) | |
| for c in present] | |
| ax_bev.legend(handles=handles, loc="upper left", fontsize=7, | |
| facecolor="#14141e", edgecolor="#2a2a3a", | |
| labelcolor="#c0c0d0") | |
| draw_stats_panel(fig.add_subplot(gs[:, 4])) | |
| fig.text(0.42, 0.02, "white dashed = ground truth | filled = prediction", | |
| ha="center", color="#6a6a7a", fontsize=8) | |
| os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True) | |
| fig.savefig(out_path, dpi=110, bbox_inches="tight", facecolor="#0a0a14") | |
| plt.close(fig) | |
| def main() -> None: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--ckpt", default="runs/simplebev/best.pth") | |
| ap.add_argument("--data-root", default="data/nuscenes-mini") | |
| ap.add_argument("--out-dir", default="runs/demo") | |
| ap.add_argument("--frames", type=int, default=20) | |
| ap.add_argument("--start", type=int, default=0) | |
| ap.add_argument("--score-thresh", type=float, default=0.2) | |
| ap.add_argument("--ms-per-frame", type=int, default=450) | |
| args = ap.parse_args() | |
| import torch | |
| from data.scripts.dataset import NuScenesBEVDataset | |
| from models.simplebev import SimpleBEV | |
| from training.evaluate import decode_predictions | |
| device = torch.device("mps" if torch.backends.mps.is_available() else "cpu") | |
| model = SimpleBEV(pretrained=False).to(device).eval() | |
| model.load_state_dict(torch.load(args.ckpt, map_location=device)["model"]) | |
| ds = NuScenesBEVDataset(args.data_root, split="val") | |
| n = min(args.frames, len(ds) - args.start) | |
| paths = [] | |
| for k in range(n): | |
| i = args.start + k | |
| s = ds[i] | |
| with torch.no_grad(): | |
| preds = model(s["images"].unsqueeze(0).to(device), | |
| s["intrinsics"].unsqueeze(0).to(device), | |
| s["extrinsics"].unsqueeze(0).to(device)) | |
| boxes = decode_predictions({k2: v.cpu() for k2, v in preds.items()})[0] | |
| gt = ds._boxes_in_ego(ds.sample_tokens[i]) | |
| p = os.path.join(args.out_dir, f"frame_{k:03d}.png") | |
| render(s["images"].numpy(), gt, boxes, p, k, n, args.score_thresh) | |
| paths.append(p) | |
| print(f" frame {k+1}/{n}") | |
| from PIL import Image | |
| frames = [Image.open(p).convert("P", palette=Image.ADAPTIVE, colors=128) | |
| for p in paths] | |
| gif = os.path.join(args.out_dir, "demo.gif") | |
| frames[0].save(gif, save_all=True, append_images=frames[1:], | |
| duration=args.ms_per_frame, loop=0, optimize=True) | |
| print(f"\nsaved {gif} ({os.path.getsize(gif)/1e6:.1f} MB, {n} frames)") | |
| print(f"saved {n} PNGs in {args.out_dir}/") | |
| if __name__ == "__main__": | |
| main() | |