Детекція на практиці

Пʼять тем ми розбирали, як улаштовані детектори. Ця тема про те, що вирішує результат насправді — і це майже ніколи не архітектура. Усі числа нижче здобуті на одному й тому самому детекторі: змінювались тільки дані й рішення навколо них.

Блок закінчується не новою архітектурою. Тема 27 прибрала з детектора останню рукотворну деталь, і на цьому історія конструкцій вичерпалась: далі йдуть варіації. Тепер уяви, що тобі треба зробити детектор для реальної задачі — порахувати ящики на складі, знайти дефекти на платі, помітити людей на камері. Ти обираєш архітектуру за пів години, а потім три місяці займаєшся чимось геть іншим. Ця тема про ті три місяці. І головне її число таке: помилка в розмітці коштувала нам 0.1749 mAP, а найкращий архітектурний винахід усього блоку — 0.1061. Обидва числа зміряні на одній задачі, на одному й тому самому детекторі.

ПостановкаПроєкт, а не модель

У попередніх пʼяти темах задача була вже поставлена: є сцени 64×64, у них кола, квадрати й трикутники, рамки рахуються з масок. Це зручно для навчання й безчесно щодо реальності. У реальній задачі рамок немає ніде. Їх треба спершу придумати, потім намалювати, і обидва кроки коштують дорожче за всю решту.

Тема 02 вже називала ціну другого кроку: близько 15 секунд на одну рамку при уважній роботі. Десять тисяч зображень по три предмети — це 125 годин чистого часу розмітника, тобто місяць роботи однієї людини. Але дорожчий не цей крок, а перший, бо помилки в ньому не видно.

Перше рішення — що вважати предметом. Питання звучить безглуздо, поки не візьмеш конкретну задачу. Рахуємо ящики на складі: ящик, який видно на чверть із-за іншого ящика, — це предмет? А намальований ящик на плакаті? А ящик у дзеркалі? А відкритий ящик без кришки — це той самий клас чи інший? Кожна відповідь має бути записана до того, як перша людина почне розмічати. Інакше відповідей буде стільки, скільки розмітників.

Друге рішення — що робити з частково видимими. Тут теж немає правильної відповіді, є вибір із наслідками. Розмічаєш усе, що видно хоч трохи, — детектор навчиться реагувати на маленькі шматки й даватиме багато хибних спрацювань. Розмічаєш лише те, що видно повністю, — детектор мовчатиме на половині реальних кадрів, бо в житті предмети постійно перекриваються.

Третє — що робити з групами. Двадцять яблук у ящику: двадцять рамок чи одна? Тема 25 показувала, що сітка 7×7 при двадцяти предметах у кадрі втрачає 98.9 % сцен через конфлікт клітинок — тобто відповідь «двадцять рамок» дорого коштує самій моделі, а не лише розмітникові.

Ці три питання не про машинне навчання. Вони про домовленість між тобою, замовником і розмітниками. І кожне з них міняє те, що модель узагалі вважатиме правдою.

ПравилаРозмітка: правила важливіші за виконавців

Типова помилка — думати, що якість розмітки залежить від сумлінності розмітників. Насправді вона залежить від того, чи є в них однозначна інструкція. Двоє однаково сумлінних людей без інструкції розмітять один кадр по-різному, і різниця буде більшою, ніж різниця між двома архітектурами.

Подивись на одну картинку й покрути правила.

Та сама картинка, різні правила — різна істина

Три складні випадки в одній сцені: два предмети, з яких один перекрито; предмет, що наполовину вийшов за кадр; купка дрібних предметів. Перемикачі задають правила розмітки. Праворуч — скільки рамок вийде в еталонній розмітці.

перекриті предмети
предмет на межі кадру
група дрібних
рамок в істині—
предметів на сцені8
Вісім однакових предметів дають від 2 до 8 рамок — залежно від трьох рядків інструкції. Це вчетверо. Жодна архітектура в цьому курсі не давала різниці в чотири рази. Кількість рамок — це ще не ціна; ціну кожного з трьох рядків заміряно далі в темі: −0.1749 mAP за зсунуту рамку (розділ 3), падіння впевненості з 0.4753 до 0.3649 за непідписаний предмет (розділ 4), 0.7771 проти 0.7450 за політику на межі кадру (розділ 6). Найгірше не те, що варіантів багато, а те, що кожен із них правильний — доти, доки не записаний один.

Мінімальна інструкція для детекції — це пʼять відповідей, і всі вони мають бути однозначними до початку роботи.

ПерекриттяВід якої частки видимості предмет розмічається. Число, а не «на око»: «видно менше третини — не розмічаємо». Ціна вибору: кожен предмет, що не пройшов поріг, стає пропущеною рамкою, а розділ 4 показує, що це коштує: при 30 % пропущених рамок середня впевненість на істинних предметах падає з 0.4753 до 0.3649, і всі три зерна впорядковані однаково.
Тіснота рамкиРамка по видимих пікселях чи по всьому предмету, включно з тим, що за перешкодою. Два різні датасети. Ціна вибору: це систематичний зсув рамки, а розділ 3 міряє його прямо — 2 пікселі коштують 0.0246 mAP, 4 пікселі вже 0.1749.
Межа кадруОбрізаний предмет розмічається чи ні, і якщо так — до краю кадру чи до уявного продовження. Ціна вибору: розділ 6 перебирає всі три політики — 0.7771, 0.7701 і 0.7450 при розкиді від зерна 0.0321, тобто перші дві нерозрізненні, а третя гірша рівно на один розкид.
Відображення й екраниПредмет у дзеркалі, на плакаті, на екрані монітора. Майже завжди «ні», але це треба написати. Ціна вибору: два розмітники з різними відповідями дають ту саму помилку, що й неправильний клас, — 0.0176 mAP при 15 % таких рамок і 0.1095 при 30 % (розділ 3).
ГрупиКоли предметів багато й вони дрібні: кожен окремо, одна рамка на групу, чи окремий клас «група». Ціна вибору: «кожен окремо» бʼє не по розмітникові, а по моделі — сітка 7 × 7 при двадцяти предметах у кадрі має конфлікт клітинок на 98.9 % сцен (тема 25).

Перевірка інструкції теж проста й коштує пів дня: дай двом людям розмітити ті самі 50 зображень і порахуй, у скількох рамках вони збіглися за IoU вище 0.7. Ця частка — стеля твоєї моделі. Модель не може бути точнішою за розмітку, на якій її вчили: у темі 23 ми бачили, що рамка зі стороною 40 пікселів утримує IoU 0.9 лише при зсуві до 2.1 пікселя — тобто розбіжність у два пікселі між двома розмітниками вже зʼїдає весь запас між mAP@0.5 і mAP@0.5:0.95.

ЦінаСкільки коштує помилка розмітки

Досі це були міркування. Тепер замір, і це головний замір теми.

Беремо наш звичний набір — 240 навчальних сцен, 501 істинна рамка — і псуємо тільки навчальну розмітку. Перевірна лишається ідеальною: ми хочемо знати, як зіпсована розмітка впливає на модель, а не як зіпсована метрика впливає на число. Три способи псування, кожен відповідає реальній помилці людини:

  1. зсув рамок на 2 і 4 пікселі у випадковому напрямку — рамку вели поспіхом;
  2. пропущені рамки (5, 15 і 30 %) — предмет на картинці є, підпису немає;
  3. неправильний клас (15 і 30 %) — рамка правильна, підпис ні.

Кожна настройка навчається три рази з різними зернами. Це не формальність: на чистій розмітці три зерна дали mAP 0.8427, 0.8445 і 0.8749, тобто розкид 0.0321 без жодної зміни в даних. (Відняти надруковані краї й дістати 0.0322 — правильно: усі різниці тут пораховані до округлення до чотирьох знаків, тому подекуди розходяться з надрукованим на одиницю в останньому знаку.) Це наша одиниця виміру. Різниця, менша за 0.0321, нічого не доводить — про це докладно тема 18.

що зіпсувалиmAP@0.5втратау розкидах
нічого0.8540——
зсув 2 px0.8294−0.02460.8×
зсув 4 px0.6791−0.17495.4×
пропуск 5 %0.8441−0.00990.3×
пропуск 15 %0.8314−0.02270.7×
пропуск 30 %0.8076−0.04641.4×
клас 15 %0.8364−0.01760.5×
клас 30 %0.7445−0.10953.4×

Два числа тут головні, і обидва — у виділених рядках.

Зсув на 4 пікселі коштує 0.1749. Чотири пікселі — це менше за товщину пальця на екрані. Наші фігури мають рамку близько 17 пікселів завширшки, тож зсунута рамка перекривається з істинною на IoU 0.6111 — вона все ще «приблизно там», але вже не там. Для порівняння, при зсуві на 2 пікселі IoU дорівнює 0.7841, і втрата всемеро менша.

Неправильний клас у 30 % рамок коштує 0.1095. Цікаво, що при 15 % втрата лише 0.0176 — утричі менша, ніж вийшло б за простою пропорцією. Мережа певною мірою терпить рідкісний шум у мітках — доти, доки правильних більше. Але після якоїсь межі терпіння закінчується різко.

А тепер порівняння, заради якого все затівалось.
Найбільший виграш від зміни архітектури в усьому блоці 5 — focal loss проти звичайної крос-ентропії, +0.1061 (тема 26). Другий за величиною — anchor-free голова замість якірної, +0.0577. Зсув рамок на чотири пікселі коштує 0.1749, тобто більше за обидва разом. Один недбалий розмітник зʼїдає результат двох винаходів, на які пішли роки.

Розмітка проти архітектури

Перемикач обирає вид помилки розмітки, повзунок — її силу. Червона смуга — втрата від цієї помилки. Бірюзові — виграші від двох архітектурних винаходів блоку. Сіра — розкид від зерна, тобто межа значущості.

вид помилки
mAP настройки—
втрата—
проти найкращої архітектури—
Усі сім червоних значень — це та сама мережа на тих самих 240 сценах. Архітектура не змінювалась жодного разу. Бірюзові смуги взяті з теми 26, де їх міряли так само — трьома зернами на кожну точку.

ПропускПропущена рамка проти відсутнього зображення

Серед трьох помилок розмітки пропущена рамка стоїть окремо, і механізм тут інший. Згадай, як улаштоване навчання детектора з теми 26: кожен якір або відповідає за якийсь предмет, або є фоном. Якщо предмет на картинці є, а рамки в файлі немає, то всі якорі на ньому оголошуються фоном. Мережу штрафують саме за те, що вона правильно побачила предмет.

Просто менша вибірка так не робить. Вона забирає приклади, але нічого не стверджує неправильно. Порівняймо це прямо: «видалили 15 % рамок» проти «видалили 15 % зображень», і те саме на 30 %. Кількість рамок, що лишилась, у цих парах близька, тож порівняння чесне.

що видалилиmAP@0.5впевненість на істинізнайдено при 0.30
нічого0.85400.57020.8596
15 % рамок0.83140.45870.8030
15 % сцен0.84990.52720.8394
30 % рамок0.80760.36490.6775
30 % сцен0.80680.47530.8057

Подивись на другий стовпчик і здивуйся разом зі мною. При 30 % mAP однаковий: 0.8076 проти 0.8068, різниця в четвертому знаку. Якби ми дивились лише на mAP, довелося б сказати «різниці немає» — і це була б неправда.

Різниця є, просто mAP її не бачить. Дивись на передостанній стовпчик: середня впевненість, яку модель дає справжньому предмету, впала з 0.4753 до 0.3649. І це не гра середніх — тут виконується найсильніша умова, яку взагалі можна перевірити на трьох прогонах: усі три зерна «видалили рамки» (0.2840, 0.4042, 0.4064) лежать нижче за всі три зерна «видалили сцени» (0.4308, 0.4910, 0.5040). Купи не перетинаються — так само, як у темі 26 для focal loss.

А ось повноту ми чесно не зміряли.
В останньому стовпчику різниця виглядає велетенською: 0.6775 проти 0.8057, тобто 12.8 пункту. Але розкид усередині «видалили рамки» дорівнює 0.3198 — одне зерно з трьох просто розвалилось (0.4656 проти 0.7854 і 0.7814). Середнє тягне вниз саме воно. Тож напрямок ми показали, а ціну в пунктах повноти на 240 сценах не встановили: для цього потрібно більше зерен або більший набір.
крок 1 · що сталося з даними

З 501 рамки прибрали приблизно 150. Предмети на картинках лишились — зникли тільки їхні підписи.

крок 2 · що побачила мережа

150 разів вона бачила чітку фігуру й отримувала вказівку «тут фон». Це не відсутність сигналу, а сигнал протилежного знаку.

крок 3 · чого вона навчилась

Знижувати впевненість скрізь, де бачить фігуру. Не «не бачити» — саме стишувати: рамка досі на місці, оцінка нижча. Це й видно в замірі впевненості, де всі три зерна впорядковані однаково.

крок 4 · чому mAP мовчить

mAP — площа під кривою точність-повнота, а крива будується перебором усіх порогів. Якщо всі оцінки впали приблизно однаково, порядок передбачень майже не змінився, і площа лишилась тією самою. Впаде тільки той, хто працює з фіксованим порогом. Тобто ти, у продуктиві.

Це, до речі, найкраща ілюстрація до розділу 9 цієї теми: mAP — чесна метрика для порівняння моделей і погана для передбачення того, що відчує користувач. І водночас урок про самі заміри: одна метрика тут нічого не показала, а друга показала занадто багато. Довіряти можна тій, у якої купи зерен не перетинаються.

Пропущена рамка проти відсутнього зображення

Дві криві: скільки коштує видалити частку рамок і скільки — видалити стільки ж зображень. Перемикач міняє метрику. За mAP криві майже збігаються, за впевненістю на істинних предметах — розходяться, і саме там висновок витримує перевірку зернами.

метрика
видалили рамки—
видалили сцени—
різниця—
Та сама пара моделей, три різні погляди на неї. За mAP на 30 % різниця дорівнює 0.0008 — усередині будь-якого шуму. За впевненістю на істинних предметах — 0.1104, і там купи зерен не перетинаються. Крива повноти показує той самий напрямок, але з розкидом 0.3198 усередині однієї настройки, тож за нею робити висновок не можна. Метрика вирішує, чи побачиш ти проблему — і чи не побачиш зайвого.

ОбсягСкільки даних треба

Найчастіше запитання й найгірша відповідь на нього — число. «Тисяча зображень на клас» гуляє форумами років десять і не означає нічого, бо кількість — не та величина, від якої залежить результат. Залежить від різноманіття.

Тисяча кадрів з однієї камери, знятих за одну годину при одному освітленні, — це приблизно одне зображення, повторене тисячу разів. Сто кадрів із десяти різних камер у різну погоду навчать більшого. Правило, яке справді працює, звучить так: додавай не кількість, а різновид. Нова камера, нове освітлення, новий ракурс, новий фон, нова відстань до предмета.

Перевірити, чи вистачає даних, можна без здогадів — кривою навчання. Навчи модель на чверті даних, на половині, на трьох чвертях і на всіх, по три зерна на кожну точку, і подивись на приріст. Якщо остання чверть даних дала приріст, менший за розкид від зерна, — нові дані того самого типу вже нічого не додадуть. Техніку побудови таких кривих ми розбирали в темі 11; тут вона застосовується без змін, просто по осі стоїть mAP.

Практичні орієнтири, з якими не соромно починати: сотні зображень достатньо, щоб побачити, чи задача взагалі розвʼязна; тисячі — щоб отримати робочу якість на вузькій задачі з одного джерела; десятки тисяч потрібні там, де багато класів або дуже різні умови зйомки. Але жоден із цих орієнтирів не замінює криву навчання на твоїх даних, бо між «ящики на одному складі» й «ящики взагалі» різниця в кілька порядків.

І ще одне, що добре видно з розділу 3: менше й акуратніше краще, ніж більше й недбало. Скорочення набору на 30 % опустило mAP з 0.8540 до 0.8068, а зсув рамок на чотири пікселі — аж до 0.6791. Якщо вибір стоїть між «розмітити вдвічі більше сяк-так» і «розмітити стільки ж уважно», числа однозначно за друге.

АугментаціяАугментація з рамками

Аугментацію ми проходили в темі 10, але там задачею була класифікація, і мітка при перетворенні не мінялась: перевернув картинку — це все ще кіт. У детекції мітка геометрична, і її треба перетворювати разом із зображенням. Помилитись тут легко, а помітити помилку майже неможливо: код не падає, картинки виглядають нормально, модель просто гірша.

Тому кожне перетворення пишеться парою «зображення + рамки» і звіряється з маскою. Ідея звірки проста. У синтетичних даних ми знаємо маску фігури; отже, можна перетворити саму маску тим самим перетворенням і порахувати рамку з неї заново. Якщо формула правильна, два числа збігаються точно. Для горизонтального дзеркала формула така:

рамка′ = [ W − x2,   y1,   W − x1,   y2 ]

Тут W — ширина зображення, а x₁, y₁, x₂, y₂ — ліва, верхня, права й нижня координати рамки. Зверни увагу, що x₁ і x₂ міняються місцями: після дзеркала лівий край стає правим. Це і є та помилка, яку роблять найчастіше — переставити координати забувають, і рамка стає «вивернутою», з відʼємною шириною. Тому формулу перевіряють assert-ом проти рамки, порахованої з дзеркальної маски, — і так само для зсуву й масштабу.

Рамка їде разом із предметом — або не їде

Ліворуч оригінал, праворуч перетворена сцена. Перемикач обирає перетворення, другий — чи перетворили рамки. Пунктир показує, де рамка мала б бути насправді.

перетворення
рамки
IoU рамки з предметом—
mAP такого набору—
Заміряно на маленькій базі з 80 сцен, куди додали два аугментовані проходи. Без аугментації — 0.3589. З аугментацією й правильними рамками — 0.8018. З тими самими картинками, але забутими рамками — 0.6580. Забута строчка зʼїдає 0.1438 із 0.4429 виграшу, тобто третину.

Найпідступніше тут те, що варіант із забутими рамками усе одно кращий за відсутність аугментації: 0.6580 проти 0.3589. Метрика виросла, ти зрадів і пішов далі. Помилка, яка робить гірше, знаходиться за годину; помилка, яка робить краще, ніж було, живе в проєкті роками.

Що безпечно, а що ні

Перетворення діляться на три купи, і критерій простий: чи буває таке в реальних даних.

перетворенняколи безпечно
Горизонтальне дзеркаломайже завжди: у світі немає «правильного» боку. Виняток — текст, дорожні знаки, цифри
Зсув і обрізаннязавжди, але потребує рішення про рамки на межі — див. нижче
Масштабзавжди; найкорисніше, бо предмети в житті бувають на різній відстані
Яскравість і контрастзавжди, якщо клас не визначається кольором
Поворот на малий кутобережно: рамка після повороту перестає бути тісною, бо вона завжди по осях
Вертикальне дзеркалорідко: у більшості задач є низ і верх

Останній рядок вартий окремого слова, бо його регулярно вмикають «за компанію» з горизонтальним. У нашому наборі є трикутник, і він завжди стоїть вістрям угору. Перевернувши сцену вертикально, ми отримуємо фігуру, якої в перевірній вибірці не буває ніколи, і витрачаємо на неї третину навчального часу. У реальних задачах те саме: перевернута машина, перевернута людина, перевернутий дорожній знак — усе це або не трапляється, або означає щось інше. Правило просте: вмикай перетворення тільки тоді, коли можеш назвати кадр із реального життя, який на нього схожий.

Рамка на межі кадру

Обрізання ставить питання, у якого немає очевидної відповіді: що робити з рамкою, яка після обрізання наполовину вийшла за кадр? Є три відповіді, і всі три використовуються.

Три політики для рамки на межі

Повзунок рухає вікно обрізання, перемикач обирає політику. Ліворуч — повна сцена з вікном, праворуч — те, що потрапить у навчання.

рамка на межі
рамок у навчанні—
торкнулось межі—
mAP цієї політики—
Заміряно на 240 сценах, з яких обрізано половину вікном 48×48. Межі торкнулись 135 рамок із 501. Політика «викинути» лишає 366 рамок і дає 0.7771, «обрізати» — 498 рамок і 0.7701, «лишити» — 498 рамок і 0.7450. Чому 498, а не 501: три рамки після обрізання опинились за вікном цілком, і їх не рятує жодна з трьох політик.

Читай ці числа обережно. Різниця між «викинути» й «обрізати» — 0.0070, тобто вчетверо з половиною менша за розкид від зерна: ці дві політики нерозрізненні на наших даних. А от «лишити» гірше за «викинути» на 0.0321 — рівно на один розкид, тобто на самій межі значущості. Причина зрозуміла: політика «лишити» вчить регресор передбачати координати, яких на картинці не видно, і це єдина з трьох, яка вимагає від мережі неможливого.

Зверни увагу й на інше: політика «викинути» робить те саме, що пропущена рамка з розділу 4 — предмет видно, підпису немає. На наших даних вона від цього не постраждала, бо викидає лише рамки з обрізаної половини набору. Але якщо обрізати всі кадри, ця політика перетворюється на фабрику пропущених рамок, і розділ 4 пояснює, чим це закінчиться.

ПоділПоділ вибірки

Найтихіша помилка з усіх. Якщо кадри одного відео потрапили і в навчання, і в перевірку, модель на перевірці впізнає майже ті самі картинки, які бачила під час навчання. Метрика виходить завищеною, і ти дізнаєшся про це вже на реальних даних — тобто найдорожчим можливим способом.

Змоделюймо це чесно. Робимо 60 серій по 4 схожі кадри: та сама компоновка предметів, центри дрижать на ±1 піксель, шум щоразу новий. Це модель кадрів з одного відео, знятих підряд. Ділимо 240 кадрів на 180 навчальних і 60 перевірних двома способами — випадково й за серіями. При випадковому поділі 42 серії з 60 опиняються по обидва боки.

А потім міряємо кожну модель двічі: на своїй перевірці й на цілком незалежному наборі, згенерованому іншим зерном.

поділсвоя перевірканезалежний набірілюзія
випадковий0.81730.7279+0.0893
за серіями0.75270.7237+0.0291

Дивись на другий стовпчик — він тут головний. Обидві моделі однаково добрі насправді: 0.7279 і 0.7237, різниця усемеро менша за розкид від зерна. Уся різниця першого стовпчика — 0.8173 проти 0.7527 — це не якість, а ілюзія. Випадковий поділ обіцяє 0.8173 там, де насправді 0.7279: він завищує оцінку на 0.0893, тобто майже на три розкиди.

Найнеприємніше в цій помилці — що вона не заважає. Модель із витоком навчається нормально, метрики ростуть, графіки красиві. Вона просто бреше про майбутнє.

Правило: ділимо за групами, а не за кадрами.
Група — це все, що знято разом і схоже одне на одне: кадри одного відео, знімки однієї сесії, фотографії одного предмета з різних боків, зображення від одного клієнта. Ідентифікатор групи треба зберігати поруч з іменем файлу від самого початку: придумати його після того, як дані вже поділені, майже неможливо.

Той самий принцип стосується перевірної вибірки в іншому сенсі. Якщо ти вибирав пороги (розділ 8) за перевірною вибіркою, то ця вибірка вже перестала бути чесною оцінкою: ти підганяв під неї рішення. Для остаточного числа потрібен третій набір, якого не бачив ані оптимізатор, ані ти.

ПорогиПороги — це рішення, а не константи

У детектора є два пороги, і обидва зазвичай беруть із чужого коду не думаючи: поріг упевненості (нижче якої оцінки передбачення викидаємо) і поріг NMS (наскільки сильно рамки мають перекриватись, щоб вважатись дублікатами). Стандартні 0.5 і 0.5 — це не константи природи. Це два налаштування, які треба обрати під ціну помилки у твоїй задачі.

Помилки бувають двох видів, і вони коштують по-різному. Пропуск — предмет був, детектор промовчав. Хибне спрацювання — детектор показав те, чого немає. Пошук зброї в аеропорту: пропуск катастрофічний, хибне спрацювання — зайва перевірка валізи. Автоматичне блокування рахунку: хибне спрацювання бʼє по клієнту, пропуск означає ще один прохід ручної перевірки. Ті самі дві помилки, протилежні ціни.

Запишімо це формулою — вона тут проста настільки, що майже не є формулою:

вартість на кадр = ( cпропуск · FN + cхибне · FP ) ÷ кадрів

FN — кількість пропусків (від false negative), FP — кількість хибних спрацювань (false positive), c — ціна однієї такої помилки в будь-яких одиницях: гривнях, хвилинах роботи оператора, чому завгодно. Важливе тут не абсолютне значення, а відношення двох цін.

Далі — перебір. Беремо навчений детектор, будуємо сітку з девʼяти порогів упевненості на шість порогів NMS, у кожній клітинці рахуємо TP, FP і FN на 120 перевірних кадрах і шукаємо найдешевшу клітинку.

Оптимум переїжджає разом із ціною помилки

Теплова карта: по вертикалі поріг упевненості, по горизонталі поріг NMS, колір — вартість на кадр (світліше дешевше). Перемикач міняє ціну помилки; бірюзова рамка показує оптимум.

що дорожче
поріг упевненості—
поріг NMS—
вартість на кадр—
TP / FP / FN—
Модель одна й та сама, набір один і той самий — переїжджає тільки оптимум. Коли дорогий пропуск, вигідно 0.25 і 0.40: детектор говорить багато, 124 хибні спрацювання на 120 кадрів — прийнятна плата за 24 пропуски. Коли дорогі хибні, вигідно 0.65 і 0.20: одне хибне спрацювання на весь набір ціною 118 пропусків.

Тепер найважливіше число цього розділу. Візьмімо пороги, оптимальні для «дорогого пропуску», і порахуймо, скільки вони коштують у світі, де дорогі хибні спрацювання: 10.533 проти 1.067, тобто в 9.9 раза дорожче. У зворотний бік трохи мʼякше, але теж боляче: 9.842 проти 3.033, у 3.2 раза.

А знамените «0.5 і 0.5» з чужого коду? Найближча до нього клітинка сітки — 0.55 і 0.50 — дає 7.025 там, де оптимум 3.033 (у 2.3 раза дорожче), і 3.425 там, де оптимум 1.067 (у 3.2 раза дорожче). Тобто замовчування програє в обох світах, і це природно: воно не було обране ні під один із них.

Пороги обираються на окремій вибірці.
Перебравши 54 клітинки й обравши найкращу, ти підігнав два числа під перевірний набір. Оцінка, отримана на тому самому наборі, вже завищена — рівно з тієї самої причини, що й у розділі 7. Пороги добирай на одній частині даних, а остаточну цифру називай на іншій.

ОцінкаОцінка, зрозуміла замовникові

mAP — правильна метрика для порівняння моделей і погана для розмови з людиною, яка не інженер. І це не питання простоти пояснення. Проблема глибша: mAP усереднює по класах і по всіх порогах упевненості, тобто описує модель у всіх режимах одразу, включно з тими, у яких її ніхто ніколи не запустить. Розділ 4 показав це на живому прикладі: дві моделі з однаковим mAP (0.8076 і 0.8068) і різною впевненістю на істинних предметах (0.3649 і 0.4753) — тобто з різною поведінкою на будь-якому фіксованому порозі.

Замовникові потрібні числа, які описують той режим, у якому система працює. Два таких числа рахуються за пʼять рядків коду:

Порахуймо їх для шести моделей із цієї теми — при одному робочому порозі 0.30.

Одна метрика — один переможець

Шість моделей із цієї теми — по одному прогону кожної (зерно 0), а не середнє з трьох, тому числа тут не збігаються з таблицею розділу 3. Перемикач міняє метрику, і порядок перебудовується. Найкраща за одним числом опиняється останньою за іншим.

метрика
переможець—
його місце за mAP—
Найгірша модель набору стає найкращою, щойно метрика дивиться лише на хибні спрацювання. «Аугментація без рамок» має найнижчий mAP (0.6231) і найнижчу повноту (0.377) — і рівно тому дає найменше хибних спрацювань (0.33 на кадр). Вона просто мовчить. І окремо про перший рядок: на цьому одному зерні «пропуск 15 %» стоїть вище за чисту розмітку (0.8572 проти 0.8427), хоча в розділі 3, де середнє з трьох зерен, усе навпаки (0.8314 проти 0.8540). Різниця 0.0145 менша за розкид від зерна 0.0321 — ось як виглядає «різниця, менша за шум», коли дивишся на один прогін.

Звідси головне правило розмови із замовником: одне число не буває чесним. Мінімальний чесний набір — пара: скільки знаходимо і скільки вигадуємо. Один показник без другого завжди можна виграти, зіпсувавши систему в потрібний бік.

І ще: обидва числа мають бути порахованими на тому порозі, який стоятиме в продуктиві. Оцінка «в середньому по всіх порогах» описує модель, якої не існує.

ПасткиТипові пастки

Шість помилок, кожна з яких коштувала комусь тижня. Усі мовчазні: код не падає, повідомлень немає.

пасткаяк виглядає й що робити
Формат координатРамку записують трьома способами: xyxy, xywh (кут і розмір), cxcywh (центр і розмір) — усі три розібрані в темі 23. Переплутав — IoU виходить майже нулем, а помилки немає. Ліки: torchvision.ops.box_convert і надрукувати одну рамку очима перед першим розрахунком
Пікселі проти частокОдні формати зберігають координати в пікселях, інші — нормованими від 0 до 1. Рамка [0.1, 0.2, 0.3, 0.4] на зображенні 640×480 — це або крихітний квадратик у кутку, або чверть кадру
model.eval()Забув перемкнути режим — батчнорм рахує статистики по перевірній партії, і результат залежить від того, що лежало поруч у батчі. Механізм і ціна — у темі 11
Клас фонуОдні бібліотеки віддають нульовий індекс фону й нумерують класи з одиниці, інші — ні. Зсув на одиницю дає модель, яка стабільно називає кола квадратами
Порядок класівСписок імен класів при навчанні береться з тек, а при виведенні — з конфігу. Достатньо, щоб хтось відсортував його інакше. Ліки: зберігати відповідність «індекс → імʼя» поруч із вагами й читати звідти
Рамка нульової площіПісля обрізання рамка може стати смужкою в один піксель. log(ширина) у кодуванні зсувів дає −inf, і навчання розвалюється. Ліки: викидати рамки, тонші за два пікселі

Спільна риса всіх шести — жодну не ловить ані компілятор, ані тест «код запустився». Ловить тільки одне: надрукувати проміжний результат і подивитись на нього очима. Одна намальована сцена з рамками, узятими з реального завантажувача даних, знаходить пʼять із шести цих помилок за хвилину — усі, крім model.eval(): режим мережі в картинці з даними не видно взагалі.

ВибірЩо обирати

Тепер, коли весь блок позаду, можна відповісти на питання «яку архітектуру брати» — і зробити це числами, а не смаком.

беремоколи й чому
Одноетапний
(RetinaNet, FCOS, YOLO)
Замовчування. Одноетапна постановка дала прискорення у 18 разів при однаковій ємності (тема 25), а focal loss закрив розрив у точності: +0.1061 над звичайною крос-ентропією, причому купи зерен не перетинаються (тема 26). Anchor-free голова додає ще +0.0577 і втричі легша
Двоетапний
(Faster R-CNN)
Коли потрібні найточніші рамки й багато дрібних предметів, а час є. RPN дає повноту 0.997 усього на десяти кандидат-областях (тема 24) — другий етап уточнює рамки на вже відібраних місцях
DETR і його нащадкиКоли предмети стоять щільно і NMS стає вузьким місцем. Числа з теми 27 красномовні: щільна голова знаходить усі предмети (повнота 1.000), а NMS із порогом 0.5 зрізає її до 0.500 — половину предметів знищує фільтр, а не мережа. Ціна — повільна збіжність

А тепер поверни це в масштаб. Найбільша різниця між архітектурами в таблиці — 0.1061. Зсув рамок на чотири пікселі коштує 0.1749. Витік через поділ вибірки завищує оцінку на 0.0893. Чужі пороги множать вартість помилок до 9.9 раза.

Отже, порядок дій у реальному проєкті зворотний до порядку тем у цьому блоці. Спершу правила розмітки, поділ за групами, аугментація з перевіреними рамками й пороги під ціну помилки. Архітектуру бери з першого рядка таблиці й не думай про неї, поки все інше не зроблено чесно.

БлокПідсумок блоку 5

Шість тем тому ми не вміли навіть сформулювати задачу. Ось що змінилось.

темаголовне число
23 · ПостановкаВідповідь стає списком, а метрика — окремою наукою: mAP@0.5 = 0.9393 і mAP@0.5:0.95 = 0.4900 на тій самій моделі. І NMS назавжди губить один із двох справжніх предметів, що стоять поруч із IoU 0.714
24 · ДвоетапніКандидат-області замість перебору: R-CNN потребував 176 годин на 5000 зображень, Fast R-CNN пришвидшив це у 74 рази. Якорі — заготовка, яка не підходить: 0.079 % позитивних і 28.3 % істинних рамок без жодного якоря
25 · YOLOІнша постановка, а не швидший конвеєр: 18× прискорення. Ціна — конфлікт сітки: 8.95 % втрачених предметів на звичайних сценах і 98.9 % при двадцяти предметах на сітці 7×7
26 · Focal lossХвороба була у втраті, а не в архітектурі. Множник (1−p)γ дає +0.1061, і всі три зерна кращі за всі три зерна крос-ентропії. Ініціалізація одного зсуву міняє втрату першого кроку з 72.190 на 2.255. Anchor-free — ще +0.0577 при втричі легшій голові
27 · DETRДетекція як передбачення множини: угорське зіставлення прибирає NMS. Повнота щільної голови 1.000 без NMS проти 0.500 з ним — доказ, що дублікати краще не породжувати, ніж фільтрувати
28 · ПрактикаІ все це важить менше, ніж розмітка: зсув рамок на 4 пікселі — −0.1749, тобто більше за будь-який архітектурний виграш блоку. А витік через поділ вибірки додає до оцінки +0.0893, яких немає

Дуга блоку виглядає так. Спершу ми навчились питати: де саме предмет і як виміряти відповідь. Потім три теми поспіль прибирали з детектора рукотворні деталі — перебір вікон, потім якорі, потім NMS. Кожен крок замінював людське припущення на щось, що вчиться з даних.

А остання тема показала, куди ці припущення насправді переїхали. Вони не зникли — вони вийшли з моделі назовні, у правила розмітки, у поділ вибірки, у пороги, у вибір метрики. Там їх не видно в коді архітектури й не описано в жодній статті, і саме тому вони тепер вирішують більше.

ДаліМісток далі

Рамка — груба відповідь. Вона каже, де предмет, і навіть це каже приблизно: прямокутник по осях описує людину, що йде, чи автомобіль на повороті з величезним запасом порожнечі всередині. У розділі про аугментацію ми вже наткнулись на наслідок — після повороту рамка перестає бути тісною, бо вона завжди по осях.

Але є питання, на яке рамка не відповідає в принципі: які саме пікселі належать предмету, а які — фону за ним. Порахувати площу листка на знімку, відділити пухлину від здорової тканини, замінити фон на відеозвʼязку, зрозуміти, де закінчується дорога й починається тротуар — усе це потребує відповіді для кожного пікселя, а не для прямокутника.

Саме це й робить наступний блок — сегментація. Він міняє форму відповіді востаннє: замість списку прямокутників мережа видає карту, у якій кожен піксель підписаний. Усе, що ми навчились сьогодні про правила розмітки, поділ вибірки й пороги, лишається чинним — тільки розмічати стане ще дорожче, бо обвести предмет контуром довше, ніж накрити рамкою.