后处理 API

Post-processing helpers for raw model outputs — greedy NMS in numpy, plus decode adapters for the common YOLO export shapes.

Streaming inference on the platform applies NMS server-side when the model is registered with NMS parameters, but single-shot infer() results, custom decode heads and app-side re-filtering still need a local implementation. Apps currently hand-roll one whenever scores and boxes arrive separately.

Pure numpy, no accelerator — the vectorised IoU matrix is already memory-bound at the sizes detector heads produce. When ai-runtime exposes its create-time NMS registration over the service layer (see docs/proposals/sdk-hardware-routing.md), prefer that and keep this for client-side filtering.

The YoloV8Postprocessor / YoloV5Postprocessor adapters decode InferenceResult.raw_outputs from models whose postprocess is not handled server-side (generic plugin exports — the ones whose thresholds are baked in at export time and cannot be tuned via update_postprocess_config). Thresholds here are constructor parameters, i.e. tunable at runtime.

from neoruntime_ipc_sdk.postprocess import YoloV8Postprocessor, nms

keep = nms(boxes_xyxy, scores, iou_threshold=0.45, class_ids=cls)
boxes, scores = boxes[keep], scores[keep]

post = YoloV8Postprocessor(labels=["person", "car"], score_threshold=0.3)
objects = post(result.raw_outputs, meta)      # list[DetectedObject]
neoruntime_ipc_sdk.postprocess.nms(boxes, scores, iou_threshold=0.5, class_ids=None)[source]

Greedy non-maximum suppression.

Parameters:
  • boxes (ndarray) – (N, 4) xyxy boxes [x1, y1, x2, y2].

  • scores (ndarray) – (N,) confidence scores.

  • iou_threshold (float) – boxes overlapping a kept box by more than this are suppressed.

  • class_ids (ndarray | None) – optional (N,) class labels — boxes of different classes never suppress each other.

Returns:

Indices of the kept boxes, in descending-score order.

Return type:

list[int]

class neoruntime_ipc_sdk.postprocess.Postprocessor[source]

Base class for client-side raw_outputs decoders.

Subclasses take the list of raw output tensors plus the optional PreprocessMeta from the matching Preprocessor call and return domain objects. Boxes come back in source-frame pixel coordinates whenever a meta is provided; without one they stay in model-input coordinates.

class neoruntime_ipc_sdk.postprocess.YoloV5Postprocessor(labels=None, score_threshold=0.25, iou_threshold=0.45, clip=True)[source]

Decode YOLOv5-family heads (anchor-based, ONNX-standard export).

Expects raw_outputs[0] shaped (1, N, 5+nc) / (N, 5+nc) (or the transposed variant): cx, cy, w, h, objectness plus one class score column. The final score is objectness * class_score. Same scope limits as YoloV8Postprocessor: decoded-grid exports only, float outputs assumed.

class neoruntime_ipc_sdk.postprocess.YoloV8Postprocessor(labels=None, score_threshold=0.25, iou_threshold=0.45, clip=True)[source]

Decode YOLOv8-family heads (anchor-free, ONNX-standard export).

Expects raw_outputs[0] shaped (1, 4+nc, N) / (4+nc, N) (or the transposed variant): boxes as cx, cy, w, h in input-pixel coordinates plus one score column per class, no objectness. Raw anchor-grid heads (pre-decode exports) are out of scope, as are non-dequantised int8 outputs — standard exports dequantise to float.

函数

nms

neoruntime_ipc_sdk.postprocess.nms(boxes, scores, iou_threshold=0.5, class_ids=None)[source]

Greedy non-maximum suppression.

Parameters:
  • boxes (ndarray) – (N, 4) xyxy boxes [x1, y1, x2, y2].

  • scores (ndarray) – (N,) confidence scores.

  • iou_threshold (float) – boxes overlapping a kept box by more than this are suppressed.

  • class_ids (ndarray | None) – optional (N,) class labels — boxes of different classes never suppress each other.

Returns:

Indices of the kept boxes, in descending-score order.

Return type:

list[int]

使用示例

模型输出解码后过滤重叠框

import numpy as np
from neoruntime_ipc_sdk import nms

# 解码后的候选框(xywh)、分数与类别来自模型输出层
keep = nms(boxes, scores, iou_threshold=0.45, class_ids=class_ids)

for i in keep:
    x, y, w, h = boxes[i]
    print(f"{labels[class_ids[i]]} {scores[i]:.2f} @ ({x:.0f},{y:.0f},{w:.0f},{h:.0f})")

配合加速路由(硬件 NMS 就绪后自动切换)

# 当前为软件实现;ai-runtime 暴露 NMS 注册参数后,硬件腿会
# 自动接管(见 docs/proposals/sdk-hardware-routing.md)
from neoruntime_ipc_sdk import get_default_router

keep = get_default_router().run("nms", boxes, scores, iou_threshold=0.45)