后处理 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:
- Returns:
Indices of the kept boxes, in descending-score order.
- Return type:
- class neoruntime_ipc_sdk.postprocess.Postprocessor[source]
Base class for client-side
raw_outputsdecoders.Subclasses take the list of raw output tensors plus the optional
PreprocessMetafrom the matchingPreprocessorcall 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, objectnessplus one class score column. The final score isobjectness * class_score. Same scope limits asYoloV8Postprocessor: 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 ascx, cy, w, hin 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:
- Returns:
Indices of the kept boxes, in descending-score order.
- Return type:
使用示例
模型输出解码后过滤重叠框
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)