Останні три теми були про те, як із детектора по черзі викидали рукотворні деталі. Тема 24 прибрала окремий етап пошуку кандидат-областей, тема 26 — якорі, тобто набір заготовлених рамок, які доводилось вгадувати під датасет. Лишилась одна деталь, і вона стоїть у самому кінці конвеєра: NMS. Мережа видає сотні рамок, серед них купа дублікатів, і окремий алгоритм прибирає зайві за жорстким порогом. Він не вчиться, він не знає нічого про картинку, і — найгірше — він регулярно викидає не дублікат, а справжній другий предмет. Ця тема прибирає й NMS. Не хитрішим фільтром, а зміною самого питання, на яке відповідає мережа.
ЗалишокЩо ще лишилось рукотворного
Зберемо докупи, що саме прибрали попередні теми, і чого це коштувало.
| деталь | хто прибрав і чим замінив |
|---|---|
| кандидат-області | тема 24 показала, чому їх виносили в окремий етап; тема 25 прибрала цей етап зовсім — вся сцена обробляється за один прохід |
| якорі | тема 26: замість заготовлених рамок позиція передбачає чотири відстані до країв предмета. Голова стала втричі легшою, а mAP зріс із 0.8610 до 0.9187 |
| вибірка негативних | тема 26: focal loss тлумить легкі приклади замість того, щоб їх викидати |
| NMS | нічим |
Чому NMS узагалі потрібен, зрозуміло: щільна голова питає про предмет у кожній позиції карти ознак, тож сусідні позиції описують той самий предмет і дають майже однакові рамки. Наш anchor-free детектор із теми 26 на перевірному наборі видає 7.91 передбачення на сцену з оцінкою не нижчою за 0.3 — при тому що предметів у сцені в середньому 2.06. Пар передбачень, які накривають одне одного з IoU більшим за 0.7, у нього 10.63 на сцену: дублікати не виняток, а норма. NMS зрізає ці 7.91 до 2.25 і залишає нуль таких пар.
Здавалося б, працює. Але подивись на ціну. NMS діє за одним-єдиним правилом: узяти найвпевненішу рамку, викинути всі, що перекриваються з нею сильніше за поріг, повторити. Правило нічого не знає про те, чи перекриті рамки описують один предмет, чи два різні. Тема 23 заміряла це прямо: дві рамки 60 × 120, зсунуті на 10 пікселів, мають IoU 0.7143 — і при будь-якому з трьох звичних порогів (0.3, 0.5, 0.7) з двох рамок лишається одна. Це не крайній випадок: так виглядає будь-яка вулична сцена, де людина стоїть за людиною або машина за машиною.
Отже, проблема не в порозі, а в тому, що дублікати взагалі зʼявляються. І тут напрошується інша думка: а що, як їх не породжувати?
МножинаДетекція як передбачення множини
Усі детектори, які ми розібрали, відповідають на питання «що в цій позиції?» — і повторюють це питання для кожної позиції сітки, кожного якоря, кожної кандидат-області. Відповідь виходить довгим списком оцінок, який потім треба причісувати.
DETR (detection transformer, 2020) ставить питання інакше: назви всі предмети
сцени одразу, як один набір. Не «чи є предмет у клітинці (3, 5)», а «ось сцена —
перелічи, що на ній є». Вихід мережі — не карта оцінок, а фіксований список із
N позицій, кожна з яких або називає предмет із рамкою, або каже
«порожньо».
Це звучить як косметична зміна формулювання, але з неї одразу випливає технічна проблема, якої не було раніше. Множина не має порядку. Якщо мережа сказала «коло ліворуч, квадрат праворуч», а розмітка каже «квадрат праворуч, коло ліворуч» — це та сама відповідь. Але функція втрати працює з числами, і якщо порівнювати передбачення з розміткою попарно за індексом (перше з першим, друге з другим), та сама правильна відповідь дістане різну втрату залежно від того, у якому порядку її записали. Мережа почне вчити не «що на сцені», а «в якому порядку про це звітувати».
Множина не має порядку, а втрата за індексом — має
Ліворуч сцена: дві істинні рамки й чотири передбачення. Кнопки міняють лише порядок передбачень у списку — самі рамки не рухаються. Праворуч дві втрати: наївна попарно за індексом і та, що спершу зіставляє.
Висновок із цієї картинки й є ключем до всієї теми. Щоб навчати мережу на множині, потрібна втрата, яка не залежить від порядку. Такі втрати будують так: спершу знайти найкращу відповідність між передбаченнями й істинами, потім штрафувати вже знайдені пари. Перший крок і зветься зіставленням (matching).
ЗапитиФіксований набір запитів
Скільки позицій має бути у списку? Предметів на сцені може бути один, а може двадцять. Мережа з виходом змінної довжини — річ незручна: тензори фіксованого розміру доводиться десь обрізати або доповнювати.
DETR робить простіше: список завжди однакової довжини N. Ця
N — гіперпараметр, і вона свідомо береться з запасом, більшою за
максимальну кількість предметів у сцені. В оригінальній статті на COCO вона дорівнює
100. У нашій маленькій моделі предметів у сцені щонайбільше три, тож ми беремо
N = 10.
Кожна з N позицій називається запитом (query). Запит — це
навчуваний вектор, з яким мережа приходить до карти ознак і питає: «а що тут для
мене?». Запитів рівно N, вони однакові для всіх картинок, і кожен віддає
одну відповідь: клас плюс рамка.
Але предметів же менше, ніж запитів. Куди дівати зайві? До списку класів додають ще один, службовий — «порожньо» (в оригіналі ∅, no object). Запит, якому нічого не дісталось, каже «порожньо», і його рамка нікого не цікавить.
Скільки «порожньо» має бути — видно з простої арифметики, ще до всякого
навчання. Запитів десять, а предметів у нашій сцені в середньому 2.06, тож
навіть бездоганна модель мусила б відповідати «порожньо» приблизно
(10 − 2.06) ÷ 10 = 79.4 % разів. Часте «порожньо» — це
властивість постановки із запасом, а не ознака невдалого навчання: чим
більший запас N, тим більша ця частка, і в оригінальній DETR зі ста
запитами вона ще вища.
Наша DETR на 120 перевірних сценах видає 1 200 рішень, і 49.4 % із них — «порожньо»: найчастіша з чотирьох можливих відповідей, хоч і не більшість. Кожен із десяти запитів мовчить у 37-62 % сцен; жоден не мовчить завжди й жоден не говорить завжди. Не-порожніх відповідей виходить 5.06 на сцену при 2.06 істинних рамках — тобто модель говорить частіше за ідеал, а не рідше: перестраховується, але помірно. Щільна голова з теми 26 при порозі 0.3 віддає 7.91 передбачення, а до порога — усі 64 позиції.
ЗіставленняУгорське зіставлення
Задача звучить так. Є N передбачень і M істинних рамок,
причому M зазвичай набагато менше. Треба кожній істині призначити рівно
одне передбачення так, щоб сумарно вийшло якнайкраще. «Якнайкраще» треба чимось
міряти — для кожної пари «передбачення i, істина j» рахують число, яке
називають вартістю: чим воно менше, тим краще пара пасує одна одній. З цих
чисел складається таблиця N × M — матриця вартості.
Розберімо руками. Три передбачення, дві істини, вартості такі (менше — краще):
Найочевидніший спосіб — жадібний: знайти в усій таблиці найменше число, зафіксувати
цю пару, викреслити її рядок і стовпець, повторити. Найменше тут — 0.30
у клітинці П1-І1. Викреслюємо перший рядок і перший стовпець. У тому, що лишилось,
найменше — 0.90 у П2-І2. Сума: 0.30 + 0.90 = 1.20.
А тепер спробуймо інакше: П1 віддамо другій істині (0.40), а першу
візьме П2 (0.35). Сума: 0.75. Це на 0.45 дешевше — і
жодного хитрого прийому тут немає, просто жадібний алгоритм на першому кроці забрав
П1 собі, не подивившись, що П1 — єдиний, хто взагалі непогано пасує до І2.
Потрібне призначення: набір пар, у якому кожне передбачення бере щонайбільше одну істину, кожна істина дістає рівно одне передбачення, а сума вартостей вибраних пар мінімальна.
При N = 10 і M = 3 варіантів
10 × 9 × 8 = 720 — ще можна. Але на COCO N = 100, і
навіть при M = 7 варіантів уже 80 678 106 432 000 — вісімдесят
трильйонів. І це для однієї картинки з партії.
Задача про призначення розвʼязується точно й швидко — за час, що росте як
куб від розміру таблиці. Метод відомий із 1955 року й зветься
угорським алгоритмом (Hungarian algorithm, метод Мункреса). У Python він
лежить у scipy.optimize.linear_sum_assignment.
Ідея алгоритму пояснюється без формул. Якщо відняти те саме число від усіх елементів одного рядка, оптимальне призначення не зміниться: у будь-якому призначенні з цього рядка береться рівно одна клітинка, тож уся сума просто впаде на це число. Те саме для стовпця. Алгоритм користується цим, щоб зробити в таблиці якомога більше нулів, а потім знайти набір нулів, які не ділять між собою жодного рядка чи стовпця. Такий набір і є оптимальним призначенням — дешевше за нуль у невідʼємній таблиці бути не може.
Матриця вартості: жадібно проти оптимально
Клітинки таблиці можна міняти повзунком. Перемикач обирає спосіб зіставлення; підсвічені клітинки — обрані пари, число внизу — сумарна вартість.
Наскільки часто це трапляється насправді? Міряємо двічі — спершу на вигаданих матрицях, потім на справжніх.
Замір перший, вигадані матриці. Беремо 2 000 випадкових матриць
вартості розміру 10 × M: десять рядків — стільки ж, скільки запитів у
нашій моделі, M стовпців — стільки, скільки істин на сцені. На них
жадібний спосіб розходиться з оптимальним у 6.5 % випадків, переплачуючи в
середньому 0.026, а в найгіршому випадку 1.72.
Замір другий, справжні матриці — по одній на кожну зі 120 перевірних сцен, знята з нашої DETR. Тут картина цікавіша:
| матриці вартості | розійшлись | сер. переплата | найгірша |
|---|---|---|---|
| свіжа мережа | 14 зі 120 (11.7 %) | 0.0394 | 0.7557 |
| навчена мережа | 0 зі 120 (0.0 %) | 0.0000 | 0.0000 |
Читається це так: зіставлення важливе саме тоді, коли мережа ще нічого не вміє. У свіжої мережі всі передбачення схожі одне на одне, вартості близькі, і жадібний вибір легко промахується — на кожній девʼятій сцені. У навченої мережі кожна істина має свого явного фаворита, і будь-який розумний спосіб дає ту саму відповідь. Але навченою вона стане тільки в тому разі, якщо на початку навчання її вели правильно.
Угорський алгоритм по кроках
Та сама таблиця 3 × 2, доповнена до квадратної третім стовпцем «порожньо». Кнопка «крок» веде алгоритм: віднімання по рядках, віднімання по стовпцях, вибір нулів. Кнопка «спочатку» повертає таблицю у вихідний стан.
Нашу власну реалізацію угорського алгоритму звірено з
scipy.optimize.linear_sum_assignment на 300 випадкових матрицях різного
розміру: розбіжностей нуль. Усередині бібліотеки магії немає — там ті самі
віднімання по рядках і стовпцях, тільки акуратно запаковані.
ВартістьЗ чого складається вартість
Матрицю вартості ми досі брали з неба. Тепер розберімо, звідки беруться її числа. Пара «передбачення — істина» пасує одна одній тим краще, чим більше збігаються дві речі: клас і рамка. Тому вартість складають із трьох доданків.
Беремо ймовірність, яку передбачення дає саме тому класу, що стоїть в істині, і ставимо її зі знаком мінус. Упевнене влучання в клас — велика ймовірність — робить вартість меншою.
L1 — це сума модулів різниць по чотирьох числах рамки. Координати
беруть нормованими: поділеними на розмір картинки, тобто в межах від 0 до 1.
Без нормування та сама помилка в пікселях важила б по-різному на великих і малих
картинках.
1 − GIoU, де GIoU — узагальнений IoU. Про нього
докладніше нижче.
Навіщо третій доданок, якщо є другий? L1 має ваду, яку легко
проґавити: одна й та сама його величина означає різне для великих і малих
рамок. Промах у 4 пікселі на рамці 40 × 40 — це майже точне влучання, IoU
дорівнює 0.82. Той самий промах на рамці 8 × 8 дає IoU 0.33 — тобто не проходить
навіть наймʼякшого порога. Наші
предмети мають бік від 13 до 21 пікселя, тобто розкид у півтора раза, і на COCO цей
розкид на порядки більший.
IoU цієї вади не має — він відносний за побудовою. Але в нього є своя:
коли рамки не перетинаються, IoU дорівнює нулю й перестає щось казати. Рамка
поруч і рамка на іншому кінці картинки дістануть однакову оцінку 0, а отже, однаковий
градієнт — тобто ніякий. Саме це й лікує GIoU: до IoU додається штраф за
порожнє місце в найменшому прямокутнику, який накриває обидві рамки.
Словами: якщо рамки збігаються, накривний прямокутник дорівнює обʼєднанню, штраф
нульовий і GIoU = IoU = 1. Якщо рамки далеко, обʼєднання займає малу
частку накривного прямокутника, штраф великий, і GIoU йде в мінус. Ось що
виходить для двох рамок 10 × 10, які розʼїжджаються по діагоналі — на однаковий зсув
по кожній з осей:
| зсув по кожній осі | IoU | GIoU |
|---|---|---|
| 12 px | 0.0000 | −0.5868 |
| 20 px | 0.0000 | −0.7778 |
| 30 px | 0.0000 | −0.8750 |
| 40 px | 0.0000 | −0.9200 |
IoU у всіх чотирьох рядках однаковий і мовчить. GIoU
монотонно спадає — тобто дає напрямок «наближайся» навіть там, де перетину ще немає.
Готова функція лежить у torchvision.ops.generalized_box_iou; числа вище
пораховані власною реалізацією й звірені з нею — розбіжність нуль до
останнього біта.
Три доданки складають із вагами. Канонічні значення зі статті:
1 для класу, 5 для L1, 2 для
GIoU.
Ваги вартості вирішують, хто кому дістанеться
Сцена з двома істинами й трьома передбаченнями. П2 має ідеальну рамку для І2, але майже не вірить у її клас; П3 — навпаки. Повзунки міняють ваги трьох доданків; лінії показують поточне зіставлення.
ВтратаВтрата після зіставлення
Зіставлення знайдено — тепер із нього роблять функцію втрати. Тут є приємна деталь: втрата рахується майже за тією самою формулою, що й вартість. Різниця у двох речах.
Перше. Вартість рахують, не знаючи, хто з ким стане в пару, тому в неї беруть величини, зручні для порівняння: імовірність класу як є. У втраті замість імовірності стоїть звичайна крос-ентропія — вона дає кращі градієнти. Зіставлення при цьому рахують без градієнта: воно вже знайдене, це просто список пар.
Друге, і важливіше. Втрата стосується всіх N запитів, а не лише
зіставлених M. Запити, яким не дісталося істини, мусять навчитися казати
«порожньо». І тут повертається знайома біда: якщо N = 100, а предметів
сім, то 93 зі 100 доданків втрати — це «порожньо». Той самий дисбаланс, заради якого
в темі 26 вигадали focal loss.
DETR лікує його простіше: класу «порожньо» дають меншу вагу у крос-ентропії.
В оригінальній статті — 0.1, тобто вдесятеро менше за звичайний клас.
Наша модель бере те саме число. Це грубіше за focal loss, зате не додає жодного
показника, який треба підбирати кривими.
Геометричні доданки ділять на кількість пар, а не на N: інакше сцена
з одним предметом і сцена з трьома давали б градієнт різної величини просто через
кількість предметів.
АрхітектураЩо всередині DETR
Тепер зберімо мережу. Вона складається з чотирьох частин, і три з них нам уже знайомі.
| частина | що робить |
|---|---|
| тіло (backbone) | звичайна згорткова мережа. Сцену 64 × 64 стискає до карти ознак 8 × 8 на 64 канали — те саме тіло, що в темах 23, 25 і 26 |
| позиційне кодування | карту ознак розгортають у послідовність із 64 векторів. Порядок при цьому губиться, тому до кожного вектора додають позиційний — як у темі 20 |
| енкодер | кілька шарів self-attention із теми 19. Кожна позиція карти дивиться на всі інші |
| декодер | N запитів. Кожен шар декодера має self-attention між запитами й крос-увагу від запитів до карти ознак |
Прогін сцени крізь DETR: що з чого йде і якої воно форми
Верхній ряд — шлях картинки, нижній — шлях запитів. Дві операції декодера намальовані окремо, бо роблять різні речі: одна дивиться на картинку, друга — на сусідні запити.
Дві операції декодера роблять різні речі, і саме з їхнього поділу росте вся поведінка DETR.
Крос-увага — це те, як запит дивиться на картинку. Механіка та сама, що в
темі 19: softmax(QKT/√d)V, тільки запити
Q беруться з N запитів, а ключі K і значення
V — із карти ознак. Запит отримує зважену суму ознак тих місць, які його
цікавлять. Ніхто не наказує йому, куди дивитися: ваги вчаться.
Розберімо запис по символах, бо він тут працює, а не прикрашає.
QKT — це таблиця скалярних добутків «кожен
запит проти кожної позиції карти»: десять рядків на 64 стовпці, і кожне число каже,
наскільки це місце цікавить цей запит. d — довжина одного вектора; у
нашій моделі карта має 64 канали, тож d = 64 і √d = 8.
Ділення на √d потрібне тому, що скалярний добуток — це сума
d доданків, і з ростом d вона розганяється: без ділення
softmax отримав би на вхід завеликі числа й майже всю вагу віддавав би одній
позиції, тобто градієнт для решти був би нульовий. softmax перетворює
рядок таких чисел на частки, що дають у сумі одиницю, а множення на V
складає ознаки місць саме з цими частками.
Self-attention між запитами — це те, як запити домовляються. Кожен запит бачить, що збираються відповісти інші, і може врахувати це у власній відповіді. Ось тут і зникає джерело дублікатів: якщо один запит уже впевнено взяв предмет, іншому вигідно взяти інший предмет або сказати «порожньо». Дублікат не викидають — його просто немає причини породжувати.
N однакових
нульових запитів дали б N однакових відповідей. Щоб запити були різними,
кожен із них — окремий навчуваний вектор. Різниця між ними — єдине, що взагалі
дозволяє їм спеціалізуватися.СпеціалізаціяЗапити спеціалізуються
Найкрасивіше, що відбувається в DETR, ніхто не програмував. Запити нічим не відрізняються один від одного за призначенням: усі десять мають однакову форму, ті самі шари, ту саму втрату. Але після навчання вони ділять між собою сцену.
Замір простий. Для кожного запиту беремо всі перевірні сцени, де він сказав не «порожньо», і рахуємо середній центр його рамки та середній розмір. Ось що вийшло в нашої моделі:
| запит | сцен, де говорить | середній центр x | середній центр y | середній бік |
|---|---|---|---|---|
| 0 | 55 | 36.2 | 17.1 | 16.6 |
| 1 | 75 | 25.4 | 36.8 | 19.1 |
| 2 | 62 | 43.8 | 19.6 | 17.6 |
| 3 | 54 | 45.2 | 27.7 | 17.7 |
| 4 | 76 | 19.0 | 41.8 | 16.6 |
| 5 | 59 | 44.6 | 40.4 | 16.5 |
| 6 | 65 | 22.0 | 29.5 | 18.8 |
| 7 | 69 | 22.4 | 21.5 | 16.3 |
| 8 | 46 | 46.0 | 46.1 | 15.8 |
| 9 | 46 | 31.5 | 46.8 | 16.0 |
Середні центри розкидані по x від 19.0 до 46.0, по y —
від 17.1 до 46.8. Полотно має 64 пікселі, тобто запити розібрали між собою майже
половину його ширини й висоти. Запит 4 сидить у лівому низу, запит 8 — у правому
низу, запит 0 — угорі посередині.
Щоб число мало сенс, його треба з чимось порівняти. Усередині одного запиту центр гуляє від сцени до сцени зі стандартним відхиленням 7.4 пікселя — це природно, бо предмети щоразу в різних місцях. А розмах середніх між запитами — 27.0 і 29.7 пікселя, тобто вчетверо більший. Отже, різниця між запитами не тоне в розкиді всередині запиту: вони справді дивляться в різні місця.
Карта запитів
Кожна точка — один запит, поставлений у свій середній центр; діаметр точки пропорційний середньому боку рамки. Перемикач показує або карту центрів, або частку сцен, де запит мовчить.
Звідки береться ця спеціалізація? Її ніхто не задає — вона наслідок зіставлення. Якщо запит 4 випадково частіше опинявся найдешевшим для предметів у лівому низу, йому частіше діставались саме вони, він на них учився, ставав для них ще дешевшим — і так далі. Це те, що зазвичай зветься самозакріпленням: маленька початкова перевага росте сама.
А тепер найважливіше: що буде, якщо зіставлення прибрати. Уявімо наївний варіант — хай кожна істина тягне до себе всі запити одразу, без розподілу відповідальності. Навчимо таку модель 12 епох і зміряймо розкид середніх центрів між запитами:
| як навчали | розкид центрів між запитами | mAP@0.5 |
|---|---|---|
| без зіставлення | 0.18 px | 0.0120 |
| зі зіставленням | 9.16 px | 0.0306 |
0.18 пікселя — це нуль. Усі десять запитів злиплися в одну точку й передбачають, по суті, ту саму рамку: коли кожну істину тягнуть усі, найкраще, що може зробити запит, — стати посередині між ними. Мережа з десятьма запитами перетворюється на мережу з одним. Отже, однозначність зіставлення — не технічна дрібниця для зручності, а те, без чого вся конструкція вироджується.
Своя DETRСвоя маленька DETR
Зберімо все й перевірмо на тих самих сценах 64 × 64, що в темах 23, 25 і 26. Тіло —
те саме, далі позиційне кодування, два шари енкодера, два шари декодера з
N = 10 запитами, дві голови: клас (три класи плюс «порожньо») і рамка
(cx, cy, w, h через сигмоїду).
Навчання — AdamW, 36 епох, три зерна, як і в суперника.
| модель | параметрів | mAP@0.5 | розкид по зернах | mAP@0.5:0.95 |
|---|---|---|---|---|
| DETR | 237 416 | 0.3869 | 0.0636 | 0.1520 |
| anchor-free (тема 26) | 64 615 | 0.9380 | 0.0784 | 0.5213 |
Одна засторога, перш ніж читати таблицю. 0.9380 — це наш власний прогін anchor-free голови поруч із DETR, на тих самих 36 епохах і тих самих трьох зернах. Тема 26 для тієї самої голови називає 0.9187 — там її вчили своїм розкладом. Різниця 0.0193 менша за розкид по зернах у кожному з двох замірів (0.0784 тут, 0.0383 там), тобто це не суперечність, а два прогони однієї моделі. Порівнювати DETR треба з числом із цієї таблиці: воно зняте в тих самих умовах.
Прочитаймо це чесно. Наша DETR при однаковому бюджеті епох сильно програє — 0.3869 проти 0.9380, і це при тому, що параметрів у неї майже вчетверо більше. Три зерна дали 0.4189, 0.3866 і 0.3553, тобто розкид не пояснює розриву. Це не наша помилка збірки й не випадковість: так DETR і поводиться, і причину ми розберемо в наступному розділі.
Але тепер поміряймо те, заради чого DETR узагалі вигадали. Порахуємо, скільки пар передбачень із IoU більшим за 0.7 віддає кожна модель до будь-якого NMS.
| модель | передбачень ≥ 0.3 на сцену | пар IoU > 0.7 | сцен із дублікатами |
|---|---|---|---|
| DETR | 6.53 | 0.40 | 33 % |
| щільна голова | 7.91 | 10.63 | 98 % |
| щільна голова + NMS(0.5) | 2.25 | 0.00 | 0 % |
Різниця в 26.6 раза. Щільна голова дає дублікати практично на кожній сцені — 98 % проти 33 %. І звертай увагу: кількість передбачень у двох моделей майже однакова (6.53 і 7.91), різна саме їхня структура. DETR теж перестраховується, але її зайві передбачення розкидані по сцені, а не складені стосом на одному предметі.
Дублікати до NMS
Скільки пар передбачень накривають одне одного сильніше за поріг. Перемикач обирає модель, повзунок — поріг IoU, за яким пару вважають дублікатом. Обидва ряди заміряні на тих самих 120 перевірних сценах.
Тепер головна перевірка теми. Тема 23 показала сцену, на якій NMS ламається: два справжні предмети, чиї рамки перекриваються з IoU 0.714, і при звичайному порозі 0.5 один із них зникає назавжди. Побудуймо таку сцену в нашому світі: два предмети одного класу, зсунуті рівно так, щоб IoU їхніх істинних рамок дорівнював заданому. По 60 сцен на кожне значення, обидві навчені моделі, повнота при IoU 0.5.
| IoU істинних рамок | DETR (без NMS) | щільна + NMS(0.5) | щільна без NMS |
|---|---|---|---|
| 0.199 | 0.958 | 0.950 | 1.000 |
| 0.408 | 0.958 | 0.842 | 1.000 |
| 0.542 | 0.983 | 0.617 | 1.000 |
| 0.703 | 0.983 | 0.500 | 1.000 |
Так, DETR цю сцену розвʼязує. На перекритті 0.703 — практично тому самому, що в темі 23, — DETR знаходить 98.3 % предметів, а щільний детектор із NMS рівно половину. Половина — це не «майже», це буквально: з кожної пари виживає один.
А тепер найважливіший рядок таблиці, останній. Щільна голова без NMS знаходить обидва предмети в 100 % випадків. Тобто мережа їх бачила. Її передбачення були правильні. Їх знищив фільтр, дописаний після мережі, який за означенням не вміє відрізнити другий предмет від дубліката першого. Це і є та ціна, яку DETR не платить — не тому, що краще бачить, а тому, що в її конвеєрі цього кроку немає.
Сцена, на якій NMS помиляється
Два предмети одного класу з заданим перекриттям. Ліворуч — сцена й рамки, праворуч — повнота трьох варіантів конвеєра. Повзунки міняють перекриття істинних рамок і поріг NMS.
ЦінаЦіна: збіжність
Повернімося до розриву в mAP. Ось криві навчання обох моделей —
середнє по трьох зернах, той самий датасет, той самий оптимізатор, та сама кількість
епох.
| епоха | DETR | anchor-free |
|---|---|---|
| 3 | 0.0041 | 0.0455 |
| 6 | 0.0110 | 0.5897 |
| 9 | 0.0393 | 0.7767 |
| 12 | 0.0509 | 0.9165 |
| 18 | 0.1612 | 0.9407 |
| 24 | 0.2744 | 0.9359 |
| 30 | 0.3824 | 0.9564 |
| 36 | 0.3869 | 0.9380 |
Anchor-free детектор виходить на 0.92 вже на дванадцятій епосі й далі лише дрібно коливається. DETR на дванадцятій епосі має 0.0509 — у вісімнадцять разів менше — і ще росте на тридцять шостій. Ми обірвали навчання не там, де крива вийшла на полицю, а там, де скінчився наш бюджет на навчання.
Це не властивість нашої маленької збірки, а відома вада DETR, названа в самій статті: оригінальна DETR навчалась 500 епох на COCO, тоді як Faster R-CNN у стандартному розкладі — 12. Різниця більш ніж у сорок разів. Ми дістали ту саму картину на іграшковій задачі й за лічені хвилини замість тижнів.
Зіставлення нестабільне на початку. Поки мережа нічого не вміє, вартості близькі одна до одної, і той самий запит на сусідніх кроках дістає то один предмет, то інший. Ми це поміряли: на свіжій мережі навіть жадібний і оптимальний способи розходяться на 11.7 % сцен. Запит отримує суперечливі вказівки й довго не може ні на чому зупинитися.
На один предмет — один градієнт. У щільної голови кожен предмет навчають десятки позицій одразу: сигнал приходить із багатьох місць. У DETR предмет дістається рівно одному запиту, решта девʼять учаться казати «порожньо». Корисного сигналу на крок у рази менше.
Крос-увага спершу дивиться всюди. На старті ваги уваги майже рівномірні, тож запит бачить розмиту суму всієї карти. Щоб він навчився дивитись у конкретне місце, потрібно багато кроків — і саме це прискорили наступні роботи.
ДрібніДрібні предмети
Друга вада виходить із першої частини архітектури. Енкодер працює на одній карті ознак — найглибшій і найгрубішій. У нашій моделі це 8 × 8, тобто одна клітинка на 8 пікселів сцени. Предмет із боком 6 пікселів займає менш ніж клітинку, і всі подробиці його форми вже усереднені.
У темі 26 ця біда вже виникала, і там її лікували FPN — пірамідою карт різної дрібності, де дрібні предмети шукають на детальнішому рівні. DETR цього не робить: карта одна. Причина проста й неприємна — ціна уваги. Self-attention рахує вагу для кожної пари позицій, тож витрати ростуть як квадрат їхньої кількості. Карта 8 × 8 — це 64 позиції й 4 096 пар. Карта 64 × 64 — це 4 096 позицій і 16 мільйонів пар: у чотири тисячі разів більше. Взяти детальнішу карту неможливо не через принцип, а через арифметику.
Розвʼязок знайшли за рік. Deformable DETR замінює повну увагу на розріджену: кожен запит дивиться не на всі позиції, а на кілька десятків точок, які сам собі обирає. Витрати перестають рости квадратично, і тоді вже можна взяти кілька карт різної дрібності, як у FPN. Заявлений результат: збіжність за 50 епох замість 500 і помітно кращі дрібні предмети. Далі йшли Conditional DETR і DAB-DETR, які додали запиту явну привʼязку до місця, і DINO, що звів усе докупи.
СпадокЩо з цього лишилось
DETR у чистому вигляді не витіснила згорткові детектори — вона надто дорога й надто повільно вчиться. Але її головна ідея розійшлася далеко за межі трансформерів.
- YOLOv10 прибрала NMS зі звичайного згорткового детектора: під час навчання працюють дві голови, і та, що йде в роботу, навчається однозначному зіставленню — рівно так, як DETR;
- сегментація: Mask2Former описує і семантичні області, і окремі екземпляри однаково — як множину запитів із маскою в кожного, і зіставляє їх із розміткою тим самим угорським алгоритмом;
- трекінг: у сімействі TrackFormer і MOTR запит переживає кадр і йде далі — те, що тримало предмет на кадрі t, шукає його на кадрі t + 1, і траєкторія виходить сама, без окремого алгоритму зшивання;
- сама операція
linear_sum_assignmentтепер стоїть у втратах задач, які до детекції стосунку не мають: розпізнавання поз, читання таблиць, передбачення молекулярних структур.
ПідсумокПідсумок і місток далі
| ідея | у чому суть |
|---|---|
| Множина замість списку | наївна попарна втрата міняється в девʼять разів від самої лише перестановки передбачень (2.72 … 24.59); після зіставлення вона стала |
| Фіксовані N запитів | у нашій моделі 10; 49.4 % рішень — «порожньо», не-порожніх відповідей 5.06 на сцену при 2.06 істинних рамках |
| Угорське зіставлення | жадібний спосіб розходиться з оптимальним на 11.7 % сцен свіжої мережі; на навченій — на 0 % |
| Однозначність обовʼязкова | без неї запити злипаються: розкид центрів між запитами 0.18 px замість 9.16 |
| GIoU крім L1 | L1 не знає масштабу, IoU мовчить без перетину: 0.0000 на всіх відстанях проти GIoU від −0.59 до −0.92 |
| NMS не потрібен | дублікатів 0.40 пари на сцену проти 10.63 у щільної голови — у 26.6 раза менше |
| Ціна | 0.3869 проти 0.9380 при однаковому бюджеті; на 12-й епосі 0.0509 проти 0.9165 |
Головна пара чисел теми — 0.983 і 0.500. Це повнота на сценах, де два предмети одного класу перекриваються з IoU 0.703 — рівно тому випадку, який тема 23 назвала провалом NMS. І ключ до цієї пари в останньому стовпці тієї таблиці: 1.000. Щільна голова знаходить обидва предмети. Втрачає їх не мережа, а жорсткий фільтр після неї.
Але не читай тему як «DETR перемогла». На нашій задачі вона програє anchor-free
детектору більш ніж удвічі за mAP і має майже вчетверо більше параметрів.
Правильний висновок інший: детекція як передбачення множини — це постановка, а не
архітектура. Постановка виявилась настільки вдалою, що її перенесли в згорткові
детектори, у сегментацію й у трекінг, а від самого трансформера в багатьох із них
нічого не лишилось.
На цьому блок про детекцію закінчено. Ми пройшли всі підходи: двоетапні з кандидат-областями, одноетапні з сіткою й якорями, anchor-free і, нарешті, множинні. Кожен наступний прибирав рукотворну деталь попереднього — і жоден не виявився «правильним» на всі випадки.
Наступна тема — про вибір. Який детектор брати під конкретну задачу, скільки даних йому треба, як їх розмічати, що робити з рідкісними класами й де в реальному конвеєрі ховаються помилки, яких немає в жодній статті.