From 91e6d240be0bb2d620d7194aa417270a7a3d32bb Mon Sep 17 00:00:00 2001 From: George Pearse Date: Mon, 29 Dec 2025 22:06:06 -0500 Subject: [PATCH 1/3] docs: batch FiftyOne inference example --- docs/user-guide/inference.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/inference.md b/docs/user-guide/inference.md index ac92779..cc2cfa0 100644 --- a/docs/user-guide/inference.md +++ b/docs/user-guide/inference.md @@ -92,10 +92,16 @@ dataset.compute_metadata() # populates sample.metadata.width/height classes = model.dataset_meta.get("classes", []) score_thr = 0.3 -# 3) Run inference and attach detections -for sample in dataset.iter_samples(progress=True): - data_sample = inference_detector(model, sample.filepath) +# 3) Run batched inference and attach detections +# (Batching is important for performance, and required for multi-GPU inference) +filepaths = dataset.values("filepath") +batch_size = 8 +predictions = [] +for i in range(0, len(filepaths), batch_size): + predictions.extend(inference_detector(model, filepaths[i : i + batch_size])) + +for sample, data_sample in zip(dataset.iter_samples(progress=True), predictions, strict=True): pred = data_sample.pred_instances pred = pred[pred.scores > score_thr] @@ -107,7 +113,7 @@ for sample in dataset.iter_samples(progress=True): pred.bboxes.cpu().numpy(), pred.labels.cpu().numpy(), pred.scores.cpu().numpy(), - strict=False, + strict=True, ): x1, y1, x2, y2 = bbox.tolist() From b22591867b655e01ceaf5addcb309b3bd722c067 Mon Sep 17 00:00:00 2001 From: George Pearse Date: Mon, 29 Dec 2025 22:10:10 -0500 Subject: [PATCH 2/3] docs: update inference guide to visdet APIs --- docs/user-guide/inference.md | 66 ++++++++++++++++++++---------------- visdet/apis/__init__.py | 3 +- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/docs/user-guide/inference.md b/docs/user-guide/inference.md index cc2cfa0..13d1242 100644 --- a/docs/user-guide/inference.md +++ b/docs/user-guide/inference.md @@ -7,35 +7,39 @@ This guide covers running inference with trained models. Run inference on a single image: ```python -from mmdet.apis import init_detector, inference_detector +from visdet.apis import inference_detector, init_detector -config_file = 'configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' -checkpoint_file = 'checkpoints/faster_rcnn_r50_fpn_1x_coco.pth' +config_file = "configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py" +checkpoint_file = "checkpoints/faster_rcnn_r50_fpn_1x_coco.pth" # Build the model from config and checkpoint -model = init_detector(config_file, checkpoint_file, device='cuda:0') +model = init_detector(config_file, checkpoint_file, device="cuda:0") # Run inference on an image -result = inference_detector(model, 'demo/demo.jpg') +result = inference_detector(model, "demo/demo.jpg") ``` ## Visualization -Display results: - -```python -from mmdet.apis import show_result_pyplot - -# Show the results -show_result_pyplot(model, 'demo/demo.jpg', result, score_thr=0.3) -``` - Save results to file: ```python -from mmdet.apis import show_result_pyplot - -model.show_result('demo/demo.jpg', result, out_file='result.jpg', score_thr=0.3) +from visdet.cv import imread +from visdet.visualization import DetLocalVisualizer + +# DetLocalVisualizer expects RGB images +image = imread("demo/demo.jpg", channel_order="rgb") + +visualizer = DetLocalVisualizer() +visualizer.dataset_meta = model.dataset_meta +visualizer.add_datasample( + "result", + image, + data_sample=result, + draw_gt=False, + out_file="result.jpg", + pred_score_thr=0.3, +) ``` ## Batch Inference @@ -44,16 +48,18 @@ Process multiple images: ```python import glob -from mmdet.apis import inference_detector + +from visdet.apis import inference_detector # Get all images in a directory -image_files = glob.glob('path/to/images/*.jpg') +image_files = glob.glob("path/to/images/*.jpg") -for image_file in image_files: - result = inference_detector(model, image_file) - # Process result... +# Run as a batch for better performance +results = inference_detector(model, image_files) ``` +`results` is a list of `DetDataSample` objects (one per input image). + ### Multi-GPU Inference To run inference on multiple GPUs in a single process, pass multiple CUDA devices to `init_detector` and then infer a batch (a list) of images: @@ -159,20 +165,20 @@ bash tools/dist_test.sh ${CONFIG_FILE} ${CHECKPOINT_FILE} ${GPU_NUM} --eval bbox Create a custom inference pipeline: ```python -from mmdet.apis import init_detector -from mmcv import Config +from visdet.apis import inference_detector, init_detector +from visdet.engine.config import Config # Load config -cfg = Config.fromfile('config.py') +cfg = Config.fromfile("config.py") # Modify config if needed cfg.model.test_cfg.score_thr = 0.5 # Initialize model -model = init_detector(cfg, 'checkpoint.pth', device='cuda:0') +model = init_detector(cfg, "checkpoint.pth", device="cuda:0") # Run inference -result = inference_detector(model, 'image.jpg') +result = inference_detector(model, "image.jpg") ``` ### Async Inference @@ -181,10 +187,12 @@ For high-throughput scenarios: ```python import asyncio -from mmdet.apis import init_detector, async_inference_detector + +from visdet.apis import init_detector +from visdet.apis.inference import async_inference_detector async def async_process(): - model = init_detector(config_file, checkpoint_file, device='cuda:0') + model = init_detector(config_file, checkpoint_file, device="cuda:0") tasks = [async_inference_detector(model, img) for img in images] results = await asyncio.gather(*tasks) return results diff --git a/visdet/apis/__init__.py b/visdet/apis/__init__.py index 5b68195..dcffb8b 100644 --- a/visdet/apis/__init__.py +++ b/visdet/apis/__init__.py @@ -4,10 +4,11 @@ from visdet import models as _ # noqa: F401 from visdet.apis.det_inferencer import DetInferencer -from visdet.apis.inference import inference_detector, init_detector +from visdet.apis.inference import async_inference_detector, inference_detector, init_detector __all__ = [ "DetInferencer", + "async_inference_detector", "inference_detector", "init_detector", ] From de3f0cdc8501cf907d88519059ecbd05838b5779 Mon Sep 17 00:00:00 2001 From: George Pearse Date: Mon, 29 Dec 2025 22:12:10 -0500 Subject: [PATCH 3/3] docs: stream FiftyOne inference in batches --- docs/user-guide/inference.md | 79 +++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/docs/user-guide/inference.md b/docs/user-guide/inference.md index 13d1242..9e46d39 100644 --- a/docs/user-guide/inference.md +++ b/docs/user-guide/inference.md @@ -98,46 +98,51 @@ dataset.compute_metadata() # populates sample.metadata.width/height classes = model.dataset_meta.get("classes", []) score_thr = 0.3 -# 3) Run batched inference and attach detections +# 3) Run streaming batched inference and attach detections # (Batching is important for performance, and required for multi-GPU inference) -filepaths = dataset.values("filepath") +import itertools batch_size = 8 -predictions = [] -for i in range(0, len(filepaths), batch_size): - predictions.extend(inference_detector(model, filepaths[i : i + batch_size])) - -for sample, data_sample in zip(dataset.iter_samples(progress=True), predictions, strict=True): - pred = data_sample.pred_instances - pred = pred[pred.scores > score_thr] - - width = sample.metadata.width - height = sample.metadata.height - - dets = [] - for bbox, label_id, score in zip( - pred.bboxes.cpu().numpy(), - pred.labels.cpu().numpy(), - pred.scores.cpu().numpy(), - strict=True, - ): - x1, y1, x2, y2 = bbox.tolist() - - dets.append( - { - "label": classes[int(label_id)] if classes else str(int(label_id)), - "bounding_box": [ - x1 / width, - y1 / height, - (x2 - x1) / width, - (y2 - y1) / height, - ], - "confidence": float(score), - } - ) - - sample["predictions"] = detections_to_fiftyone(dets) - sample.save() +sample_iter = dataset.iter_samples(progress=True) + +while True: + sample_batch = list(itertools.islice(sample_iter, batch_size)) + if not sample_batch: + break + + data_samples = inference_detector(model, [s.filepath for s in sample_batch]) + + for sample, data_sample in zip(sample_batch, data_samples, strict=True): + pred = data_sample.pred_instances + pred = pred[pred.scores > score_thr] + + width = sample.metadata.width + height = sample.metadata.height + + dets = [] + for bbox, label_id, score in zip( + pred.bboxes.cpu().numpy(), + pred.labels.cpu().numpy(), + pred.scores.cpu().numpy(), + strict=True, + ): + x1, y1, x2, y2 = bbox.tolist() + + dets.append( + { + "label": classes[int(label_id)] if classes else str(int(label_id)), + "bounding_box": [ + x1 / width, + y1 / height, + (x2 - x1) / width, + (y2 - y1) / height, + ], + "confidence": float(score), + } + ) + + sample["predictions"] = detections_to_fiftyone(dets) + sample.save() # 4) Visualize in the FiftyOne App session = fo.launch_app(dataset)