Non-Maximum Suppression (NMS)
Подавление немаксимумов (NMS) удаляет дублирующиеся перекрывающиеся рамки, оставляя для каждого объекта одну детекцию. Разбираем принцип работы, настройку и модели без NMS.
Подавление немаксимумов (NMS) — этап постобработки, который преобразует исходные перекрывающиеся прогнозы детектора в одну рамку на объект. Плотная модель обнаружения объектов оценивает тысячи возможных ограничивающих рамок на изображении, и несколько соседних вариантов обычно срабатывают на одном и том же объекте, немного различаясь положением и оценками. NMS оставляет рамку с наибольшей уверенностью в каждой группе перекрывающихся рамок и подавляет остальные, используя пересечение над объединением (IoU), чтобы определить, достаточно ли рамки перекрываются и считать ли их дубликатами.
Как работает подавление немаксимумов#
Жадный NMS, стандартный вариант алгоритма, сначала удаляет кандидатов с оценкой ниже порога уверенности и сортирует остальные по оценке. Затем он оставляет рамку с наибольшей оценкой, удаляет все оставшиеся рамки, у которых IoU с ней превышает порог IoU, и повторяет шаги со следующей рамкой с наибольшей оценкой, пока не останется кандидатов. Обычно детекторы запускают алгоритм отдельно для каждого класса, поэтому рамка человека не подавляет перекрывающуюся рамку велосипеда.
nms из torchvision реализует жадный NMS для одного класса и возвращает индексы оставленных рамок, отсортированные по оценке.
import torch
from torchvision.ops import nms
# Кандидатные рамки в формате [x1, y1, x2, y2], каждая с одной оценкой уверенности
boxes = torch.tensor(
[
[100, 100, 200, 200], # A
[105, 105, 195, 195], # B: почти дубликат A (IoU 0.81)
[300, 300, 400, 400], # C: отдельный объект
],
dtype=torch.float32,
)
scores = torch.tensor([0.90, 0.80, 0.95])
# Подавить любую рамку, IoU которой с рамкой с более высокой оценкой и оставленной рамкой превышает 0.5
keep = nms(boxes, scores, iou_threshold=0.5)
print(keep.tolist())Результат — [2, 0]: первой остаётся рамка C, поскольку у неё самая высокая оценка; рамка A остаётся, поскольку не перекрывается с C; рамка B удаляется, поскольку её IoU с A равен 0.81.
Настройка порогов#
Порог уверенности удаляет слабых кандидатов до начала подавления. Порог IoU задаёт величину перекрытия, при которой рамки считаются дубликатами. Если он слишком низкий, два реальных объекта, стоящих близко друг к другу, например люди в толпе, сливаются в одно обнаружение, и полнота падает. Если он слишком высокий, сохраняются рамки-дубликаты, и точность падает. NMS без учёта классов позволяет любой рамке подавлять другую независимо от класса, что устраняет дублирующиеся метки, если модель присвоила одному объекту два похожих класса, например «автомобиль» и «грузовик».
Ограничения NMS#
- Переполненные сцены: Один фиксированный порог IoU не позволяет отличить рамку-дубликат от второго объекта, который действительно перекрывает первый, поэтому сильно закрытые объекты подавляются.
- Фиксированная эвристика: Порог выбирают вручную, он находится вне обученной сети и не выводится из данных.
- Задержка и развёртывание: Жадный цикл запускается после сети, а его стоимость растёт вместе с числом кандидатов, что увеличивает задержку инференса. Форматы экспорта, которые не могут включить NMS в граф модели, выдают исходные варианты, и приложение должно запускать NMS самостоятельно.
Варианты NMS и обнаружение без NMS#
Soft-NMS не удаляет перекрывающиеся рамки, а снижает их оценки в зависимости от степени перекрытия, благодаря чему в толпе удаётся восстановить больше объектов. DIoU-NMS, предложенный вместе с функцией потерь Distance-IoU, также учитывает расстояние между центрами рамок, поэтому рамки с далеко расположенными центрами реже подавляются.
Сквозные детекторы полностью устраняют этот этап. DETR обучается с использованием венгерского алгоритма, сопоставляющего предсказания с метками один к одному, поэтому каждому объекту соответствует ровно одно предсказание, а YOLOv10 добавила голову для сопоставления один к одному в модели YOLO для работы в реальном времени. YOLO26 обучает оба типа голов и по умолчанию применяет NMS, поскольку голова YOLO26 с сопоставлением один ко многим показывает немного более высокий результат по метрике mAP50-95 на COCO для YOLO26n: 40.9 против 40.1. При передаче nms=False выбирается голова с сопоставлением один к одному, которая выдаёт не более 300 итоговых рамок на изображение без этапа NMS.










