后处理后端¶
SAHI 的后处理操作(NMS、NMM)可以在三种可互换的后端上运行。合适的后端取决于 您的硬件和已安装的软件包。
后端概览¶
| 后端 | 适用场景 | 额外依赖 |
|---|---|---|
| numpy | 仅使用 CPU 的环境,预测结果数量较少或中等 | 无(始终可用) |
| numba | 使用 CPU 且预测结果数量较多;首次调用需要约 1 秒进行 JIT 预热,之后较快 | pip install numba |
| torchvision | CUDA GPU 可用;处理大型批次时速度最快 | pip install torch torchvision + CUDA |
自动检测(默认)¶
默认情况下,SAHI 会在运行时自动选择最佳可用后端:
- torchvision -- 已安装
torchvision且存在 CUDA GPU 时使用。 - numba -- 已安装
numba软件包时使用。 - numpy -- 始终可用,作为最终兜底方案。
from sahi.postprocess.backends import get_postprocess_backend
# 检查解析出的后端(会触发自动检测)
print(get_postprocess_backend()) # 首次执行后处理操作前为 "auto"
强制指定后端¶
在运行推理前使用 set_postprocess_backend 固定后端:
from sahi.postprocess.backends import set_postprocess_backend
# 强制使用纯 numpy(无额外依赖,可在所有环境中运行)
set_postprocess_backend("numpy")
# 强制使用 numba JIT(安装命令:pip install numba)
set_postprocess_backend("numba")
# 强制使用 torchvision GPU(安装命令:pip install torch torchvision)
set_postprocess_backend("torchvision")
# 恢复自动检测
set_postprocess_backend("auto")
该调用会影响当前进程中后续的所有 NMS/NMM 操作,包括
get_sliced_prediction 内部触发的操作。
示例:为完整推理流程固定后端¶
from sahi import AutoDetectionModel
from sahi.predict import get_sliced_prediction
from sahi.postprocess.backends import set_postprocess_backend
# 在 CUDA 环境中使用 GPU 加速后处理
set_postprocess_backend("torchvision")
detection_model = AutoDetectionModel.from_pretrained(
model_type="ultralytics",
model_path="yolo11n.pt",
confidence_threshold=0.25,
device="cuda:0",
)
result = get_sliced_prediction(
"image.jpg",
detection_model,
slice_height=512,
slice_width=512,
overlap_height_ratio=0.2,
overlap_width_ratio=0.2,
)
直接使用后处理函数¶
三个后端遵循相同的数组约定:使用形状为 (N, 6) 的 numpy 数组,列顺序为
[x1, y1, x2, y2, score, category_id]。
NMS(抑制)¶
import numpy as np
from sahi.postprocess.combine import nms, batched_nms
predictions = np.array([
[100, 100, 200, 200, 0.95, 0],
[105, 105, 205, 205, 0.80, 0],
[300, 300, 400, 400, 0.90, 1],
])
# 全局 NMS:所有类别一起参与比较
keep = nms(predictions, match_metric="IOU", match_threshold=0.5)
print(predictions[keep])
# 按类别执行 NMS:类别 0 和类别 1 分别独立处理
keep = batched_nms(predictions, match_metric="IOU", match_threshold=0.5)
print(predictions[keep])
NMM(合并)¶
NMM 不会丢弃重叠框,而是将其合并:
from sahi.postprocess.combine import greedy_nmm, nmm, batched_greedy_nmm
# 贪心 NMM:每个保留框只合并与其直接相邻的框(速度快,边界框紧凑)
keep_to_merge = greedy_nmm(predictions, match_metric="IOU", match_threshold=0.5)
# {kept_index: [merged_index, ...], ...}
# 完整 NMM:传递式合并(A 合并 B,B 合并 C,则 A 会获得全部三个框)
keep_to_merge = nmm(predictions, match_metric="IOU", match_threshold=0.5)
# 按类别执行贪心 NMM
keep_to_merge = batched_greedy_nmm(predictions, match_threshold=0.5)
IoS 指标¶
NMS 和 NMM 都支持 match_metric="IOS"(Intersection over Smaller area,
交集与较小面积之比)。当一个边界框远小于另一个边界框时,该指标非常实用:
后处理类¶
高级类可以与 SAHI 的 ObjectPrediction 列表集成,并由
get_sliced_prediction 通过 postprocess_type 参数使用:
from sahi.postprocess.combine import NMSPostprocess, NMMPostprocess, GreedyNMMPostprocess
# NMS:保留最佳边界框,丢弃其余边界框
postprocessor = NMSPostprocess(
match_threshold=0.5,
match_metric="IOU",
class_agnostic=True, # False 表示按类别处理
)
filtered = postprocessor(object_prediction_list)
# 贪心 NMM:合并重叠边界框(速度快)
postprocessor = GreedyNMMPostprocess(match_threshold=0.5)
merged = postprocessor(object_prediction_list)
# 完整 NMM:传递式合并
postprocessor = NMMPostprocess(match_threshold=0.5)
merged = postprocessor(object_prediction_list)
传入 class_agnostic=False 后,每个后处理器都会按类别独立运行,因此 "car"
预测结果不会抑制 "person" 预测结果。
API 参考¶
sahi.postprocess.backends
¶
Postprocessing backend selection and auto-detection.
Usage
from sahi.postprocess.backends import set_postprocess_backend, get_postprocess_backend
set_postprocess_backend("numba") # force numba set_postprocess_backend("auto") # auto-detect best available
Functions:¶
get_postprocess_backend()
¶
resolve_backend()
¶
Resolve "auto" to a concrete backend, caching the result.
When the backend is set to "auto", detection follows this priority:
- torchvision -- selected if both torchvision and a CUDA GPU are available (GPU-accelerated NMS).
- numba -- selected if the numba package is installed (JIT-compiled loops, faster than pure numpy for large prediction counts).
- numpy -- always available as the fallback (pure numpy, no extra dependencies).
If the backend was explicitly set via set_postprocess_backend, that
value is returned directly without auto-detection.
Returns:
| Type | Description |
|---|---|
str
|
One of "numpy", "numba", or "torchvision". |
Source code in sahi/postprocess/backends.py
set_postprocess_backend(name)
¶
Set the postprocessing backend.
Call once at startup before running any inference. This function is not thread-safe.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str
|
One of "auto", "numpy", "numba", "torchvision". |
required |
Source code in sahi/postprocess/backends.py
sahi.postprocess.combine
¶
Postprocessing strategies for combining predictions from sliced inference.
Classes¶
GreedyNMMPostprocess
¶
Bases: NMMPostprocess
Postprocessor using Greedy Non-Maximum Merging (NMM).
Similar to NMM but uses a greedy strategy: each kept prediction only merges boxes that directly overlap with it (no transitive merging). This is faster than full NMM and produces tighter merged boxes.
Source code in sahi/postprocess/combine.py
LSNMSPostprocess
¶
Bases: PostprocessPredictions
Postprocessor using Locality-Sensitive NMS from the lsnms package.
Uses a spatial index for fast neighbor lookup, making it efficient for
large numbers of predictions. Only supports IoU metric (not IoS).
Requires the lsnms package (pip install lsnms>0.3.1).
Note
This postprocessor is experimental and not recommended for production use.
Source code in sahi/postprocess/combine.py
Methods:¶
__call__(object_predictions)
¶
Apply Locality-Sensitive NMS to suppress overlapping predictions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
object_predictions
¶ |
list[ObjectPrediction]
|
List of ObjectPrediction instances to suppress. |
required |
Returns:
| Type | Description |
|---|---|
list[ObjectPrediction]
|
List of suppressed ObjectPrediction instances. |
Raises:
| Type | Description |
|---|---|
ModuleNotFoundError
|
If the lsnms package is not installed. |
NotImplementedError
|
If match_metric is not "IOU". |
Source code in sahi/postprocess/combine.py
NMMPostprocess
¶
Bases: PostprocessPredictions
Postprocessor using Non-Maximum Merging (NMM) with transitive merging.
Instead of discarding overlapping detections, merges their bounding boxes, masks, and scores. Uses non-greedy transitive merging: if A overlaps B and B overlaps C, all three are merged even if A does not directly overlap C.
Source code in sahi/postprocess/combine.py
Methods:¶
__call__(object_predictions)
¶
Apply Non-Maximum Merging to merge overlapping predictions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
object_predictions
¶ |
list[ObjectPrediction]
|
List of ObjectPrediction instances to merge. |
required |
Returns:
| Type | Description |
|---|---|
list[ObjectPrediction]
|
List of merged ObjectPrediction instances. |
Source code in sahi/postprocess/combine.py
NMSPostprocess
¶
Bases: PostprocessPredictions
Postprocessor using Non-Maximum Suppression (NMS).
Keeps the highest-scored prediction among overlapping boxes and discards the rest. Does not merge bounding boxes or masks.
Source code in sahi/postprocess/combine.py
Methods:¶
__call__(object_predictions)
¶
Apply Non-Maximum Suppression to suppress overlapping predictions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
object_predictions
¶ |
list[ObjectPrediction]
|
List of ObjectPrediction instances to suppress. |
required |
Returns:
| Type | Description |
|---|---|
list[ObjectPrediction]
|
List of suppressed ObjectPrediction instances. |
Source code in sahi/postprocess/combine.py
PostprocessPredictions
¶
Bases: ABC
Abstract base class for postprocessing object prediction lists.
Subclasses implement a specific strategy (NMS, NMM, greedy NMM, etc.) to reduce overlapping detections produced by sliced inference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
float
|
Minimum overlap value (IoU or IoS) to consider two predictions as matching. |
0.5
|
|
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
|
bool
|
If True, apply postprocessing across all categories. If False, apply per category independently. |
True
|
Source code in sahi/postprocess/combine.py
Methods:¶
__call__(predictions)
abstractmethod
¶
Apply postprocessing to the list of predictions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predictions
¶ |
list[ObjectPrediction]
|
List of ObjectPrediction instances to postprocess. |
required |
Returns:
| Type | Description |
|---|---|
list[ObjectPrediction]
|
List of postprocessed ObjectPrediction instances. |
Source code in sahi/postprocess/combine.py
__init__(match_threshold=0.5, match_metric='IOU', class_agnostic=True)
¶
Initialize the postprocessor with configuration parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
match_threshold
¶ |
float
|
Minimum overlap value (IoU or IoS) to consider two predictions as matching. |
0.5
|
match_metric
¶ |
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
class_agnostic
¶ |
bool
|
If True, apply postprocessing across all categories. If False, apply per category independently. |
True
|
Source code in sahi/postprocess/combine.py
Functions:¶
batched_greedy_nmm(predictions, match_metric='IOU', match_threshold=0.5)
¶
Apply greedy non-maximum merging independently per category.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
ndarray
|
Array of shape (N, 6) with columns [x1, y1, x2, y2, score, category_id]. |
required |
|
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
|
float
|
Minimum overlap to merge a lower-scored box. |
0.5
|
Returns:
| Type | Description |
|---|---|
dict[int, list[int]]
|
Dict mapping each kept index to a list of indices merged into it. |
Source code in sahi/postprocess/combine.py
batched_nmm(predictions, match_metric='IOU', match_threshold=0.5)
¶
Apply non-maximum merging (non-greedy, transitive) independently per category.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
ndarray
|
Array of shape (N, 6) with columns [x1, y1, x2, y2, score, category_id]. |
required |
|
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
|
float
|
Minimum overlap to merge a lower-scored box. |
0.5
|
Returns:
| Type | Description |
|---|---|
dict[int, list[int]]
|
Dict mapping each kept index to a list of indices merged into it. |
Source code in sahi/postprocess/combine.py
batched_nms(predictions, match_metric='IOU', match_threshold=0.5)
¶
Apply non-maximum suppression independently per category.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
ndarray
|
Array of shape (N, 6) with columns [x1, y1, x2, y2, score, category_id]. |
required |
|
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
|
float
|
Minimum overlap to suppress a lower-scored box. |
0.5
|
Returns:
| Type | Description |
|---|---|
list[int]
|
List of indices of the kept predictions, sorted by score descending. |
Source code in sahi/postprocess/combine.py
greedy_nmm(predictions, match_metric='IOU', match_threshold=0.5)
¶
Greedy non-maximum merging for axis-aligned bounding boxes.
Instead of discarding overlapping boxes, merges them into the highest-scored box. Dispatches to the resolved backend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
ndarray
|
Array of shape (N, 6) with columns [x1, y1, x2, y2, score, category_id]. |
required |
|
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
|
float
|
Minimum overlap to merge a lower-scored box. |
0.5
|
Returns:
| Type | Description |
|---|---|
dict[int, list[int]]
|
Dict mapping each kept index to a list of indices merged into it. |
Source code in sahi/postprocess/combine.py
nmm(predictions, match_metric='IOU', match_threshold=0.5)
¶
Non-maximum merging (non-greedy, transitive) for axis-aligned bounding boxes.
Unlike greedy NMM, this variant allows transitive merging: if box A merges with B and B merges with C, all three are merged together. Dispatches to the resolved backend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
ndarray
|
Array of shape (N, 6) with columns [x1, y1, x2, y2, score, category_id]. |
required |
|
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
|
float
|
Minimum overlap to merge a lower-scored box. |
0.5
|
Returns:
| Type | Description |
|---|---|
dict[int, list[int]]
|
Dict mapping each kept index to a list of indices merged into it. |
Source code in sahi/postprocess/combine.py
nms(predictions, match_metric='IOU', match_threshold=0.5)
¶
Non-maximum suppression for axis-aligned bounding boxes.
Dispatches to the resolved backend (numpy, numba, or torchvision).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
ndarray
|
Array of shape (N, 6) with columns [x1, y1, x2, y2, score, category_id]. |
required |
|
str
|
Overlap metric, "IOU" or "IOS". |
'IOU'
|
|
float
|
Minimum overlap to suppress a lower-scored box. |
0.5
|
Returns:
| Type | Description |
|---|---|
list[int]
|
List of indices of the kept predictions, sorted by score descending. |