Привет, Хабр! Меня зовут Максим, я студент РТУ МИРЭА. Это продолжение статьи «Мелкие дефекты теряются, а метрика молчит». В ней я сравнивал Mask R-CNN и YOLO на 1812 производственных снимках с повреждениями автомобилей и закончил на тайлинге: если снимок резать на куски, мелкие объекты не будут ужиматься вместе со всем кадром.
До тайлинга я в итоге добрался, и прямой дороги не получилось. Почти каждая попытка что-то чинила и одновременно что-то ломала. Ниже рассказ о том, какие шаги я делал, где ошибался и какие выводы из этого вынес.
Почему мелкое теряется
Снимки в наборе небольшие, в медиане около 714×479, и перед подачей в сеть их ещё уменьшают. Скол краски, который на исходной фотографии занимает несколько пикселей, после ресайза съёживается до размеров, где на самой подробной карте признаков FPN от него остаётся одна-две клетки. Цифру я уже приводил в прошлой статье: при входе 512 около 41% дефектов становятся меньше 8 пикселей, а у деталей кузова таких всего 1,6%.
Если посчитать AP отдельно по размерам объектов, у обычной модели получается лестница: чем крупнее объект, тем выше качество, а на самых мелких почти ноль. Общая метрика выглядит прилично только потому, что её вытягивают крупные детали кузова. Отсюда и мысль: раз сеть не видит мелкое, надо показать ей его крупнее.
Схема из учебника
Идея тайлинга проще некуда:
-
порезать снимок на фрагменты;
-
каждый фрагмент растянуть до входного размера сети;
-
искать объекты на фрагментах;
-
вернуть найденное в координаты исходного снимка и убрать дубли;
-
отдельно прогнать снимок целиком, чтобы не потерять крупные объекты.
Сама схема давно описана в литературе. Самое трудное здесь в двух вопросах: на каких данных обучать модель и как потом собирать вместе то, что нашлось на разных масштабах.
Что про это уже известно
SAHI (Akyon и др., 2022) нарезает изображение на перекрывающиеся куски уже на инференсе, и подойдёт любой детектор. Авторы проверяли на VisDrone и xView: без переобучения нарезка добавила 5,1–6,8% AP детекторам FCOS, VFNet и TOOD, а с дообучением на нарезанных данных 12,7–14,5%.
SNIP (Singh, Davis, 2018) показывает, что смена масштаба между обучением и тестом детекторам вредит. Поэтому обучение и тест там идут на одних и тех же масштабах пирамиды, а градиент на каждом масштабе дают только объекты подходящего для сети размера.
SNIPER (Singh и др., 2018) развивает это дальше: вместо целых изображений сеть учится на чипах вокруг объектов, и пикселей на это уходит лишь немногим больше, чем при обычном одномасштабном обучении.
Шаг 0. Режем только тестовые снимки
Самый дешёвый эксперимент: модель оставляем как есть, а режем только тестовые снимки. AP на мелких объектах вырос на 9,4%, mIoU на 8,8%. Цена: снимок теперь обрабатывается в 3–4 раза дольше, потому что модель прогоняется по каждому фрагменту отдельно. Результат вполне вписывается в то, что сообщают авторы SAHI, хотя данные и метрика у нас разные, так что сравнивать цифры напрямую нельзя.
Дальше я дообучил модель на фрагментах. С нарезкой на тесте она стала лучше, а на целом кадре оказалась хуже исходной. Этот урок потом повторялся на каждом шаге: если учили на одном масштабе, проверять надо на нём же. Модель, привыкшая к фрагментам, на целом кадре теряется.
Бывает и наоборот. В препринте про дефекты печатных плат (arXiv:2605.24726) YOLO12n, обученный на целых снимках, при тайловом инференсе почти ничего не находил, а версия, обученная на фрагментах, работала нормально. У меня Mask R-CNN, обученный на целых кадрах, нарезку на тесте перенёс спокойно. Детекторы и данные разные, поэтому вывод у меня один: в какую сторону и насколько бьёт рассогласование масштабов, надо проверять на своей модели.
Попытка 1. Увеличить всё посильнее
Фрагмент в нативном разрешении увеличивает объекты примерно вдвое по сравнению с ужатым целым кадром. Сколам в несколько пикселей этого мало. Тогда я решил резать совсем мелкие куски, увеличивать их в несколько раз и учить модель почти только на них.
Получился провал. На целом кадре общий AP упал примерно на треть, а полнота вдвое. Нарезка на тесте тоже не спасла: результат остался хуже базы.
Задним числом понятно почему. Целых кадров и крупных объектов в нормальном масштабе модель почти не видела. Её внутренние статистики подстроились под мир сильно увеличенных кусков, и обычный снимок стал для неё чужим доменом. Сильнее всего пострадали крупные классы: отсутствующая деталь кузова в маленький фрагмент просто не помещается.
Попытка 2. Смешать масштабы
Следующий шаг напрашивался: учить на смеси. В обучение пошли целые кадры, фрагменты в нативном разрешении и сильно увеличенные фрагменты вперемешку.
Провал по целому кадру почти закрылся, а с нарезкой на тесте получился лучший на тот момент результат. Объекты размером 10–20 пикселей заметно прибавили, на мелких дефектах качество выросло почти вдвое.
Радость закончилась, когда я разложил дефекты по размерам: качество на крупных дефектах просело примерно вдвое. Общий AP при этом вырос, и без разбивки по размерам я бы этого не заметил.
Объяснение простое. Большая вмятина или разбитая деталь при нарезке попадает во фрагменты по частям. Модель учится на обрывках, разметка обрывка не похожа на целый объект, а на тесте один дефект рассыпается на несколько частичных детекций. Мелкому сколу увеличение помогает, а большой вмятине вредит: во фрагменте от неё остаётся кусок без краёв.
Потом я нашёл способ вернуть крупные дефекты и при этом не потерять мелкие. Полный алгоритм и готовую библиотеку я опишу в отдельной статье позже.
Почему крупный дефект распадается на части
Про распад крупного дефекта при слиянии стоит поговорить отдельно. Обычное слияние через NMS или NMM с порогом IoU с ним справляется плохо. Авторы работы про Spatial Mask Merging (MDPI Mathematics, 2025) пишут, что порог по IoU не склеивает куски, которые почти не пересекаются. Они соединяют соседние маски одного класса в граф, находят кластеры корреляционной кластеризацией и сливают каждый кластер в одну маску, а R-дерево отсекает лишние сравнения.
В препринте про печатные платы подход другой: если детекцию у края фрагмента подтверждает соседний фрагмент, её вес повышается. Выигрыш там скромный, а слишком агрессивные настройки даже ухудшили метрику.
Прежде чем городить сложное слияние, распад стоит измерить. Берёте крупные дефекты из разметки и для каждого считаете, сколько предсказанных масок того же класса на него ложится. Доля дефектов, покрытых двумя и более масками, покажет, сколько качества на крупных теряется именно из-за фрагментации, а сколько из-за ошибок классификации. Сам я такой замер пока не делал.
Ограничения
-
Средний AP по восьми дефектным классам пока не выше базы. Общая метрика растёт в основном за счёт деталей кузова и мелких объектов, а на части крупных дефектов обычная модель всё ещё сильнее.
-
Редкие классы шумят. Крупных трещин в тесте единицы, и по AP этого класса выводов я не делаю. На самых мелких объектах разброс между запусками сравним с самим эффектом.
-
Нарезка обходится дороже в разы. Без нарезки на тесте выигрыш пропадает, а с ней снимок обрабатывается в несколько раз дольше. Для офлайн-дефектовки это терпимо, для потока в реальном времени без оптимизации нет.
-
На наборах с крупными объектами смысла почти нет. Я проверял на открытом датасете, где объектов, исчезающих при ресайзе, почти нет, и там обычная модель по целому кадру осталась лучшей. Нарезка выигрывает только на мелком.
Что проверить на своих данных
-
По одной разметке, ещё до обучения, посчитайте, какая доля объектов после ресайза до входа сети становится меньше нескольких пикселей. Если таких единицы процентов, нарезка, скорее всего, навредит.
-
Начните с нарезки только на тесте поверх уже обученной модели. Переобучать ничего не нужно, а потенциал виден сразу.
-
Если дообучаете на фрагментах, проверяйте модель в том же режиме, в каком учили, и отдельно посмотрите обратное направление на своём детекторе.
-
Не выкидывайте из обучения целые кадры. Модель, которая видела только увеличенные куски, на целом снимке беспомощна.
-
Считайте AP по размерам объектов. Одна общая цифра легко прячет регресс на крупных.
-
Если дубли склеиваются по IoU, посчитайте, какая доля крупных объектов получила две и более масок.
-
Если фрагменты перекрываются, полноту у границ фрагментов смотрите отдельно. В препринте про печатные платы перекрытие заметно подняло полноту для дефектов у края.
-
Обучайте несколько независимых запусков и сравнивайте парными тестами. На небольшом тесте разница в несколько тысячных AP часто оказывается шумом.
Вопросы к читателям
Каждый раз, улучшая мелкое, я что-то теряю на крупном. Если вы решали похожую задачу, расскажите: вы разводили модели по размеру объектов (одна на крупное, другая на мелкое) или вытягивали всё одной моделью? Как в проде вы сводите результаты разных масштабов, чтобы крупный дефект не рассыпался на несколько масок? И считал ли кто-нибудь долю фрагментации отдельной метрикой?
Источники
-
Akyon F. C., Altinuc S. O., Temizel A. Slicing Aided Hyper Inference and Fine-tuning for Small Object Detection, 2022.
-
Singh B., Davis L. S. An Analysis of Scale Invariance in Object Detection: SNIP, CVPR 2018.
-
Singh B., Najibi M., Davis L. S. SNIPER: Efficient Multi-Scale Training, NeurIPS 2018.
-
Enhancing Instance Segmentation in High-Resolution Images Using Slicing-Aided Hyper Inference and Spatial Mask Merging Optimized via R-Tree Indexing, Mathematics 13(19), 2025.
-
From Full Boards to Tiny Defects: Scale-Aware Tile Inference, препринт.
ссылка на оригинал статьи https://habr.com/ru/articles/1102908/