У попередній темі одноетапна
постановка дала вісімнадцятикратне прискорення при однаковій ємності мережі. Здавалось
би, питання закрито: одна схема швидша й простіша, отже, перемогла. Але кілька років
поспіль найточнішими лишались двоетапні детектори, а одноетапні відставали на
пʼять-десять пунктів mAP. Причина не в тому, що вони «менше думають» — і
не в тому, що їм бракує другого проходу. Причина в одному числі, яке ми зараз
порахуємо: скільки фону припадає на один предмет. Виправлення виявилось не
архітектурним, а арифметичним — переписали функцію втрати. А потім із детектора зникла
ще й ціла сутність, яку доти вважали обовʼязковою.
ХворобаЧому одноетапні детектори програвали
Різниця між двома схемами не в кількості проходів, а в тому, що бачить голова. Двоетапний детектор із теми 24 має фільтр: перший етап відбирає кількасот кандидат-областей, і лише вони йдуть на класифікацію. Серед відібраних місць співвідношення «предмет проти фону» ще стерпне, бо відбір навмисне тягне туди, де щось є. Одноетапна голова фільтра не має: вона застосовується до кожної позиції карти ознак, і кожна позиція мусить відповісти. Порахуймо, скільки їх.
Тіло мережі зменшує сцену 64 × 64 до карти ознак 8 × 8 — це 64 позиції,
та сама сітка, що в темах 23 і 25. У кожній позиції стоять три квадратні якорі
зі сторонами 12, 18 і 26 пікселів: разом 64 × 3 = 192 якорі.
Про кожен якір голова каже окремо для кожного класу: «це коло?», «це квадрат?», «це трикутник?».
Замір по всіх 240 навчальних сценах: позитивних рішень у середньому
4.05 на сцену, тобто 0.703 % від 576. На один позитивний
припадає 141 негативний — (576 − 4.05) ÷ 4.05 = 141.2.
Число 141 варте того, щоб стати поруч із двома вже відомими. Тема 23 дістала 85.4 % чистого фону серед клітинок сітки, тема 24 на дрібнішій карті й із суворішим порогом — 1 258 фонових якорів на один позитивний. Наші 141 — те саме явище на легшій конфігурації: більша клітинка, мʼякший поріг, якорі підібрані під наші предмети. Хвороба та сама, різна лише температура.
| де | що рахують за одне «рішення» | коли воно позитивне | їх на сцену | фон |
|---|---|---|---|---|
| тема 23 | клітинка сітки 8 × 8 | центр клітинки лежить у рамці — таких по 4.52 на предмет | 64 | 85.4 % |
| тема 25 | рамка YOLO, дві на клітинку | центр предмета впав у цю клітинку — рівно одна рамка на предмет | 128 | 98.4 % |
| тема 26 | якір × клас, 3 × 3 у клітинці | IoU якоря з рамкою вищий за 0.5, і клас той самий | 576 | 99.3 % |
Тобто зростання 85.4 → 98.4 → 99.3 — це не «фону побільшало». Фону стільки самого: сцена та сама, предмети ті самі. Побільшало питань про той самий фон (одне на клітинку, потім два, потім девʼять) і суворішим став поріг (у темі 23 позитивною ставала кожна клітинка, що зачепила предмет; тут — лише той якір, що на нього схожий). Обидві зміни працюють в один бік: кожне зайве питання про порожнє місце — це ще один голос у хорі, який співає «мене немає».
Скільки фону дивиться одноетапна голова
Сцена 64×64 з якорями. Повзунок міняє кількість предметів, кнопка — саму сцену. Праворуч рахується те саме, що й у таблиці вище: скільки рішень позитивні й скільки негативних припадає на один позитивний.
Тепер головне уточнення. Дисбаланс шкодить не тим, що метрика стає безглуздою — це ми проходили в темі 23. Він шкодить тим, що керує градієнтом: мережа рухається туди, куди тягне сума похідних, а ця сума майже цілком складається з фонових доданків. Порахуймо це на свіжій, ще не навченій мережі.
| звідки втрата | сума | частка |
|---|---|---|
| фон | 9 286.319 | 99.72 % |
| предмети | 26.146 | 0.28 % |
| разом | 9 312.465 | 100 % |
99.72 % втрати — це фон. І тут потрібне те саме застереження, що й вище, тільки з іншого боку: 85.4 % теми 23 — це частка порожніх клітинок, а 99.72 % — частка втрати. Дві різні величини, і плутати їх не можна: сітка може бути порожньою на 85 %, а втрата від неї — на всі 99, бо кожна порожня позиція кричить окремо і за кожен клас.
Пряма пара для порівняння одна: у темі 25 частка втрати від фону на свіжій YOLO-подібній голові з рівними вагами дорівнювала 92.3 %, і вже тоді здавалася великою. Обидва числа заміряні однаково — сира сума доданків до першого кроку навчання, — тож їх можна ставити поруч. Різниця в знаменнику з таблиці вище: YOLO питає про предмет двічі на клітинку, щільна голова — девʼять разів, окремо про кожен якір і кожен клас. У 4.5 раза більше запитань про те саме порожнє місце — і 92.3 % перетворюються на 99.72 %. Кожен наступний винахід у цій темі бореться саме з цим множником, а не з архітектурою.
МилиціСпроби, які не спрацювали
До 2017 року дисбаланс лікували вибіркою: не давати мережі всі негативні приклади, а відібрати частину. Способів було три, і всі три живі досі.
| спосіб | як працює | де стояв |
|---|---|---|
| Збалансований мінібатч | із зображення береться близько 256 якорів, половина позитивних; решта у втрату не входить | RPN у Faster R-CNN |
| Жорсткий добір негативних (OHEM, hard negative mining) | рахуємо втрату по всіх негативних і лишаємо найважчі | SSD, Fast R-CNN |
| Співвідношення 1 : 3 | на кожен позитивний беремо три найважчі негативні | SSD |
Порахуймо ціну третього способу. Позитивних рішень 4.05, негативних лишається
3 × 4.05 = 12.15, разом у втраті 16.20 рішень із 576.
Мережа не отримує градієнта від 97.2 % того, що бачить. І це не «зайві» дані, а весь фон, який вона щойно правильно вгадала, — той самий сигнал «так, тут нічого немає, тримайся цієї думки».
Проти вибірки є три заперечення, і кожне варте свого рядка.
- Зʼявляється гіперпараметр, якого не було. Чому 1 : 3, а не 1 : 5? Це число нізвідки не виводиться — його підібрали на конкретному наборі даних.
- «Найважчий» негативний часто просто зіпсований — це помилка розмітки або предмет, якого розмітник не позначив. OHEM за побудовою тягне саме такі приклади й підсилює шум.
- Рішення дискретне. Порядковий номер у відсортованому списку вирішує все: 256-й негативний увійшов, 257-й ні, хоча втрата в них однакова до третього знака.
Звідси питання: а чи обовʼязково вибирати? Може, лишити всі приклади, але дати їм різну вагу — не руками, а за правилом, яке само залежить від того, наскільки приклад легкий.
Focal lossFocal loss: не викидати, а стишити
Крос-ентропія для бінарного рішення — це −log p, де p —
ймовірність, яку модель дала правильній відповіді. Знак log — це
натуральний логарифм; нам важлива одна його властивість: коли p
наближається до одиниці, −log p наближається до нуля.
Нехай мережа впевнено бачить фон: p = 0.9, тобто
−log 0.9 = 0.105. Дрібниця. Тепер згадаймо, скільки таких дрібниць:
на навченій мережі партія з 32 сцен дає 17 541 легке фонове рішення проти
129 позитивних. Помножимо — і дрібниця перестає бути дрібницею.
Focal loss розвʼязує це одним множником — до крос-ентропії дописується
множник тлумлення (1 − p)γ.
Потрібна величина, яка близька до нуля для впевнених прикладів і близька до
одиниці для невпевнених. Найпростіша така величина — це 1 − p:
при p = 0.9 вона дорівнює 0.1, при p = 0.1 — 0.9.
Одного множника (1 − p) замало: він тлумить занадто мʼяко. Піднімемо
його до степеня γ (гамма) — тоді сила тлумлення стає ручкою.
0.12 = 0.01, тобто вдесятеро сильніше, ніж
0.1.
Окремо додається α (альфа) — стала вага: одна для позитивних
прикладів, інша (1 − α) для фону. Вона не залежить від упевненості
й робить іншу роботу — про це наступний розділ.
При γ = 0 множник дорівнює одиниці, і формула перетворюється на
звичайну зважену крос-ентропію. Тобто focal loss не замінює її, а узагальнює.
Тепер підставимо числа. Ось втрата одного прикладу залежно від упевненості
p і від γ — кожну клітинку можна перерахувати
калькулятором за формулою −(1 − p)γ · log p.
Множник α тут не беремо, щоб не заважав.
| p | CE (γ = 0) | γ = 0.5 | γ = 1 | γ = 2 | γ = 5 | тлумлення при γ=2 |
|---|---|---|---|---|---|---|
| 0.9 | 0.10536 | 0.03332 | 0.01054 | 0.00105 | 0.00000 | 100.0× |
| 0.7 | 0.35667 | 0.19536 | 0.10700 | 0.03210 | 0.00087 | 11.1× |
| 0.5 | 0.69315 | 0.49013 | 0.34657 | 0.17329 | 0.02166 | 4.0× |
| 0.3 | 1.20397 | 1.00732 | 0.84278 | 0.58995 | 0.20235 | 2.0× |
| 0.1 | 2.30259 | 2.18442 | 2.07233 | 1.86509 | 1.35965 | 1.2× |
Читаємо останню колонку. Легкий приклад із p = 0.9 при
γ = 2 стає в 100 разів тихішим, важкий із p = 0.1 —
лише в 1.2 раза. Ось уся ідея в двох числах: тлумлення тим сильніше, чим менше
приклад може навчити.
Криві втрати й сила тлумлення
Втрата одного прикладу залежно від упевненості. Сіра крива — звичайна крос-ентропія, малинова — focal loss при обраному γ. Повзунок міняє γ, другий повзунок ставить точку, для якої рахується тлумлення.
p не є особливим.p > 0.9 у втрату не входять». Це знову вибірка з усіма трьома її
вадами: приклад із p = 0.9001 зникає, а з p = 0.8999
важить повністю; число 0.9 треба звідкись узяти; і межа стрибає, поки мережа
вчиться. Степенева функція робить те саме плавно.
Своя реалізація проти бібліотечної
Формула коротка, тож напишімо її самі й звірмо з готовою — у
torchvision вона зветься
torchvision.ops.sigmoid_focal_loss. Тут чекає пастка: пряма
реалізація «порахуй p через сигмоїду, потім візьми логарифм»
не збігається з бібліотечною.
| реалізація | найбільше розходження | np.allclose |
|---|---|---|
| наївна, буквально за формулою | 0.00489 | False |
| через binary_cross_entropy_with_logits | 9.54 · 10⁻⁷ | True |
Причина суто арифметична. Логіт детектора легко доходить до 12, сигмоїда від нього
дає p = 0.9999938, а різниця 1 − p — це
6.1 · 10⁻⁶. Віднімання майже рівних чисел у float32 зʼїдає
значущі цифри, і логарифм від зіпсованого числа дає похибку близько 0.005 на
кожному з десятків тисяч фонових прикладів.
binary_cross_entropy_with_logits рахує ту саму величину, не переходячи
через p. Це не прискіпливість: у детекторі великі логіти саме там, де
прикладів найбільше.
γ і αЩо робить γ і що робить α
Два параметри роблять дві різні роботи, і плутати їх не можна.
| параметр | що вирівнює | чи залежить від прикладу |
|---|---|---|
| γ (гамма) | легкі проти важких | так — через упевненість p |
| α (альфа) | предмети проти фону | ні — стала для всього класу |
α відома задовго до focal loss: помножити втрату рідкісного класу на
більше число. γ — це нове: вага залежить від того, як модель поводиться
саме зараз, і міняється по ходу навчання. На початку майже всі приклади важкі,
множник близький до одиниці, і focal loss майже дорівнює крос-ентропії. Що далі, то
більше прикладів переходить у розряд легких і замовкає.
α
має бути велика для рідкісного класу. Насправді в RetinaNet узято
α = 0.25, тобто предметам дають меншу вагу, ніж фону (0.75):
γ = 2 вже прибрав фон із гри, і піднімати предмети означало б перегнути
в другий бік. Ці два параметри добирають разом — у статті сказано, що найкраще
α падає, коли γ росте. Число 0.25 цитоване, не наш замір.
Що дає γ на наших даних
Тепер замір. Той самий детектор, ті самі епохи, той самий AdamW — міняється лише
γ, і кожна настройка навчена з трьох зерен.
| γ | зерно 0 | зерно 1 | зерно 2 | середнє | розкид |
|---|---|---|---|---|---|
| 0 | 0.8067 | 0.6646 | 0.7935 | 0.7549 | 0.1420 |
| 1 | 0.7988 | 0.6984 | 0.8479 | 0.7817 | 0.1495 |
| 2 | 0.8805 | 0.8361 | 0.8662 | 0.8610 | 0.0444 |
| 5 | 0.5930 | 0.5970 | 0.5069 | 0.5656 | 0.0902 |
Три висновки, і третій — найважливіший.
Перший: різницю між γ = 0 і γ = 2 самими середніми не довести. Виграш —
0.8610 − 0.7549 = 0.1061, а розкид усередині настройки γ = 0
дорівнює 0.1420, тобто більший за виграш. Якби ми зупинились на середніх, чесна
відповідь була б «не знаємо» — саме так закінчився замір ваг втрати в темі 25.
Другий: але тут є сильніше твердження. Найгірше зерно при γ = 2
дало 0.8361, а найкраще зерно при γ = 0 — 0.8067. Усі три
прогони з focal loss кращі за всі три прогони без неї. Це порівняння не
залежить від того, наскільки великий розкид усередині кожної купи, і воно переконливіше
за різницю середніх.
Третій: focal loss зменшила сам розкид — із 0.1420 до 0.0444, тобто втричі.
Коли градієнт не залежить від того, скільки випадкового фону трапилось у партії,
навчання стає передбачуваним: мережа з γ = 0 на одному зерні виїжджає, на
іншому провалюється до 0.66.
І окремо — γ = 5. Середній mAP падає до 0.5656,
тобто на 0.2953 нижче за γ = 2. Цей провал більший за будь-який розкид у
таблиці, тож перетлумити можна. При γ = 5 приклад із
p = 0.5 важить у 32 рази менше за звичайний — а це вже не «легкий фон»,
це якраз те місце, де мережа вагається й де їй треба вчитись.
Хто дає втрату при різних γ
Стовпчики — фактичні складники втрати навченого детектора на партії з 32 сцен, поділені на три купи. Числа під стовпчиками — частки. Суми складників заміряні; перемикач обирає γ.
ЗсувІніціалізація зсуву: деталь, без якої нічого не працює
Тепер про річ, якої майже немає в переказах статті, зате вона є в коді кожної
реалізації. Останній шар голови класифікації — це згортка, і в неї є зсув
(bias), який torch за замовчуванням ініціалізує близько нуля.
Сигмоїда від нуля дорівнює 0.5. Тобто свіжа мережа, яка ще нічого не бачила,
вважає, що предмет є всюди — у кожному з 576 місць кожної сцени з упевненістю
50 %. Кожен фоновий приклад голосно помиляється, і сума їхніх втрат величезна.
Ліки прості: поставити зсув так, щоб початкова ймовірність предмета дорівнювала
маленькому числу π. У RetinaNet узято π = 0.01.
Сигмоїда перетворює число z на ймовірність за формулою
p = 1 ÷ (1 + e−z), де e — стала
2.71828… Нам треба навпаки: знаючи бажану p = π, знайти
z. Розвʼязуємо рівняння й дістаємо:
При π = 0.01 дріб дорівнює 0.99 ÷ 0.01 = 99,
натуральний логарифм від 99 — це 4.5951, зі знаком мінус — −4.5951.
Перевірка: сигмоїда від −4.5951 дає рівно 0.0100.
Тепер замір. Одна й та сама мережа, одна й та сама партія, різниця лише в одному числі — початковому зсуві.
| зсув | p на старті | втрата, γ = 0 | втрата, γ = 2 |
|---|---|---|---|
| нульовий (як у torch) | 0.4918 | 72.190 | 19.698 |
| −4.5951 (π = 0.01) | 0.0103 | 2.255 | 1.152 |
| у скільки разів менше | — | 32.0× | 17.1× |
Різниця в тридцять два рази — і це втрата до першого оновлення ваг. Більша втрата означає більший градієнт: перший же крок оптимізатора зриває ваги в бік «мовчи скрізь», і мережа може звідти не повернутись. Саме тому в статті про RetinaNet цю ініціалізацію названо необхідною для стабільності на початку навчання, а не косметичною деталлю.
retinanet_resnet50_fpn і fcos_resnet50_fpn без ваг і
подивись на зсув їхнього останнього шару класифікації. В обох стоїть −4.5951,
тобто рівно −log(99). Дві різні архітектури, одна й та сама константа,
зашита в конструктор.
Початкова ймовірність і втрата першого кроку
Повзунок задає π — ймовірність предмета, яку мережа має на старті. Крива показує втрату першого кроку, стовпчики — з чого вона складається. Перемикач міняє γ.
RetinaNetRetinaNet: де живе focal loss
Focal loss придумали не саму по собі, а разом із детектором, який мав довести, що одноетапна схема здатна на точність двоетапної. Він зветься RetinaNet і влаштований прозоро — усе цікаве в ньому вже описано в попередніх темах.
| частина | що робить | звідки знайома |
|---|---|---|
| Тіло (backbone) | ResNet-50 або ResNet-101 рахує карти ознак | тема 14 |
| Шия: FPN | зводить карти пʼяти рівнів до однакової товщини 256 каналів | розділ 07 нижче |
| Голова класифікації | чотири згортки 3×3, потім згортка на A · C виходів | тема 24, якорі |
| Голова регресії | такі самі чотири згортки, потім згортка на A · 4 виходів | тема 24, зсуви |
Тут A — кількість якорів у позиції (девʼять: три розміри × три
пропорції), C — кількість класів. Дві голови не мають спільних ваг:
класифікація й локалізація — різні задачі. У темі 25 ми бачили, як та сама ідея
повернулась у YOLOv8 під назвою «розділена голова».
А от між рівнями піраміди ваги спільні: одна голова проходить по всіх пʼяти картах. Це не заощадження, а твердження про світ — предмет, зменшений удвічі й поданий на вдвічі дрібнішу карту, має виглядати для голови однаково. Якби кожен рівень мав свою голову, кожна вчилась би на впʼятеро меншій кількості прикладів.
Ось ваги retinanet_resnet50_fpn по частинах — модель зібрано
офлайн, без завантаження навчених ваг, тож ці числа задає сама архітектура:
| частина | параметрів |
|---|---|
| хребет: ResNet-50 + FPN | 27 376 704 |
| голова класифікації | 4 248 115 |
| голова регресії | 2 443 300 |
| разом | 34 068 119 |
Голова класифікації майже вдвічі важча за голову регресії, хоча згортки в них
однакові: різниця в останньому шарі, який видає 9 × 91 = 819 чисел проти
9 × 4 = 36.
FPNFPN: чому дрібним предметам потрібен свій рівень
Одна карта ознак не може обслуговувати і слона, і мураху. Причина в рецептивному полі — області входу, яка впливає на одну клітинку карти. Ми рахували його в темі 09: із глибиною воно росте, і на пізніх шарах одна клітинка «бачить» сотні пікселів.
Звідси наслідок. Для великого предмета глибока карта чудова: клітинка бачить його цілком. Для предмета в 15 пікселів та сама клітинка бачить його разом із половиною кадру, і сигнал тоне в контексті. А рання карта бачить дрібний предмет добре, зате не має складних ознак: там ще немає нічого, крім меж і плям.
Піраміда ознак (FPN, feature pyramid network) розвʼязує цей конфлікт, не вибираючи між рівнями. Вона будується у два ходи.
Беремо найглибшу, найдрібнішу карту — багату на зміст, бідну на роздільність — і збільшуємо її вдвічі інтерполяцією.
Додаємо карту того самого розміру з ранішого шару, стиснуту згорткою 1×1 до 256 каналів. Виходить карта, у якої й роздільність рання, і зміст глибокий.
Крок за кроком спускаємось до найбільшої карти. Кожен рівень має однакову товщину 256 каналів — саме тому одна голова може ходити по всіх.
Рівні звуться P3…P7: у P3 крок 8 пікселів,
у P7 — 128, і кожен відповідає за свій діапазон розмірів. Ось скільки
позицій дає така піраміда на кадрі 800 × 1216:
| рівень | крок | карта | позицій | частка |
|---|---|---|---|---|
| P3 | 8 | 100 × 152 | 15 200 | 75.0 % |
| P4 | 16 | 50 × 76 | 3 800 | 18.7 % |
| P5 | 32 | 25 × 38 | 950 | 4.7 % |
| P6 | 64 | 13 × 19 | 247 | 1.2 % |
| P7 | 128 | 7 × 10 | 70 | 0.3 % |
| разом | — | — | 20 267 | 100 % |
Три чверті всієї роботи піраміди — це найдрібніший рівень, і там же живе майже весь фон. Отже, дисбаланс із розділу 01 — не просто спільна властивість одноетапних детекторів, а насамперед властивість найдрібнішого рівня. Focal loss рятує саме його.
Хто з рівнів відповідає за предмет
Повзунок задає розмір предмета — точніше, найбільшу відстань від його центра до сторони рамки. Підсвічується рівень, який за нього відповідає, і показується, яку частку всіх позицій піраміди цей рівень тримає.
torchvision, а не з памʼяті.
Правило там таке: P3 бере все, що менше за
крок × 8 = 64; далі кожен рівень бере від крок × 4
включно до крок × 8 невключно, а P7 — усе, що від
512 і більше. Межу віддано старшому рівню, тому рівно 64 px — це вже
P4. Розміри карт рахуються діленням із округленням угору, як у
самій мережі.ЯкоріЩо не так із якорями
З дисбалансом розібрались. Тепер друга частина теми — про сутність, яку прибрали цілком.
Тема 24 вже показала два незручні числа. На її сцені 28.3 % істинних рамок не мали жодного якоря з IoU понад 0.7 — тобто майже для кожної третьої рамки не існувало заготовки, достатньо схожої на неї. І з девʼяти варіантів якоря (три розміри × три пропорції) на її даних спрацювали два, обидва квадратні. Сім із девʼяти — мертвий вантаж, який чесно множив час рахунку.
Порахуймо, скільки рішень мусить ухвалити людина, перш ніж якірний детектор почне вчитись:
- скільки розмірів якоря брати й які саме (у нас 12, 18, 26 пікселів);
- які пропорції сторін (у нас лише квадрат — бо наші фігури квадратні);
- поріг IoU для позитивного якоря (у нас 0.5);
- поріг IoU для негативного (у нас 0.4) і що робити з проміжком між ними;
- чи вмикати рятівне правило «найкращий якір кожної істини позитивний завжди».
Пʼять рішень, і жодне не виводиться з даних. Наші три розміри взяті не зі стелі: рамка фігури радіусом 6-10 пікселів має сторону 12-21, і числа 12, 18, 26 її накривають. Якби ми скопіювали конфігурацію з чужої статті — скажімо, розміри 32, 64, 128 із RetinaNet для COCO, — жоден якір не перетнув би поріг, і рятівне правило лишилось би єдиним джерелом позитивних прикладів.
Anchor-freeAnchor-free: чотири відстані замість заготовки
Ідея, до якої дійшли одночасно кілька груп, звучить майже нахабно: а навіщо
взагалі заготовка? Нехай кожна позиція передбачає рамку прямо — не зсув
від чогось, а саму рамку. Найпростіший спосіб це записати придумали в детекторі
FCOS: у кожній позиції мережа видає чотири відстані від центра позиції
до лівого, верхнього, правого й нижнього краю рамки. Їх позначають l,
t, r, b — від left, top, right, bottom.
Тут x, y — координати центра позиції в пікселях, а
відстані передбачаються в одиницях кроку карти, щоб числа були близькі до одиниці.
Чотири невідʼємні числа — і рамка готова. Зіставлення теж спрощується до одного
речення: позиція позитивна, якщо її центр лежить усередині істинної рамки;
якщо всередині кількох — беремо рамку з найменшою площею.
Порівняймо дві голови на одній задачі. Те саме тіло, ті самі епохи, той самий
γ = 2, ті самі три зерна.
| що міряємо | якірна | anchor-free |
|---|---|---|
| чисел на позицію | 21 | 7 |
| параметрів у голові | 12 117 | 4 039 |
| параметрів усього | 72 693 | 64 615 |
| mAP@0.5, середнє з 3 зерен | 0.8610 | 0.9187 |
| розкид по зернах | 0.0444 | 0.0383 |
| прохід по сцені, мс | ≈ 1.7 | ≈ 1.7 |
| гіперпараметрів зіставлення | пʼять | жодного |
Голова схудла втричі, а mAP виріс на 0.0577 — більше
за розкид обох настройок, тож різниця справжня.
А от час проходу не змінився: у двох прогонах того самого коду виходило 1.67 проти 1.65 мілісекунди й 1.71 проти 1.83, тобто різниця тоне в шумі машини. Голова не є вузьким місцем — час визначає тіло, яке в обох випадках однакове. Anchor-free виграє не швидкістю, а простотою й відсутністю гіпотез.
Що передбачає одна позиція
Перемикач обирає схему. Ліворуч — одна позиція карти ознак і те, що з неї виходить. Повзунок міняє кількість класів: видно, як росте голова в кожній схемі.
CenternessCenterness: чому крайові позиції дають гірші рамки
У схеми «чотири відстані» є вроджена нерівність. Позиція в центрі передбачає чотири приблизно однакові невеликі відстані — задача легка. Позиція біля краю мусить сказати «до лівого краю 1 піксель, до правого 19», і помилка на довгому плечі коштує дорожче; до того ж крайова позиція бачить переважно фон. Перевірмо, чи це правда, перш ніж лікувати: беремо навчений anchor-free детектор і для кожної позитивної позиції рахуємо IoU тієї рамки, яку вона побудувала.
| наскільки позиція центральна | позицій | середній IoU рамки |
|---|---|---|
| 0.0 … 0.2 (край) | 253 | 0.743 |
| 0.2 … 0.4 | 367 | 0.782 |
| 0.4 … 0.6 | 215 | 0.798 |
| 0.6 … 0.8 | 111 | 0.806 |
| 0.8 … 1.0 (центр) | 23 | 0.857 |
Передумова підтвердилась: IoU росте монотонно від краю до центра, різниця між крайніми купами — 0.115. FCOS лікує це третьою гілкою голови — centerness, одним числом на позицію, яке відповідає на питання «наскільки я в центрі». Формула бере відношення меншої відстані до більшої по кожній осі:
Прочитаймо словами. Якщо позиція рівно в центрі, l = r і
t = b, обидва дроби дорівнюють одиниці, корінь з одиниці — теж одиниця.
Якщо позиція біля лівого краю, перший дріб близький до нуля — і все значення падає.
Корінь потрібен, щоб спад був не надто різким.
| зсув від центра рамки 20×20 | l | r | centerness |
|---|---|---|---|
| 0 px | 10.0 | 10.0 | 1.000 |
| 2 px | 12.0 | 8.0 | 0.816 |
| 4 px | 14.0 | 6.0 | 0.655 |
| 6 px | 16.0 | 4.0 | 0.500 |
| 8 px | 18.0 | 2.0 | 0.333 |
Гілка навчається окремою втратою, а під час передбачення оцінка рамки множиться
на неї: оцінка = √(ймовірність класу × centerness). Сенс — опустити рамки
з крайових позицій нижче, щоб NMS викидав саме їх.
Що це дало нам: чесний результат
| варіант | mAP@0.5 | розкид |
|---|---|---|
| гілки centerness немає взагалі | 0.9187 | 0.0383 |
| гілка є, оцінка без множника | 0.8173 | 0.1932 |
| гілка є, оцінка × centerness | 0.7938 | 0.2629 |
На наших даних centerness не дає нічого — навпаки, забирає. І це при тому, що сама гілка навчилась чудово: кореляція між її передбаченням і її ціллю дорівнює 0.903. Мережа зрозуміла завдання, а завдання виявилось некорисним.
Чому так — видно з попередніх чисел. Кореляція між centerness позиції й IoU її рамки лише 0.191: тенденція є, та слабка, і різниця в 0.115 IoU не перекриває розкид усередині купи. Наші предмети маленькі — сторона 12-21 піксель при кроці карти 8, тобто чотири позиції на предмет, і крайових серед чотирьох мало. На фотографії, де предмет накриває сотню позицій, картина інша, але це вже твердження про інші дані, і ми його не міряли.
Позиція, її centerness і якість рамки
Рамка предмета й позиція всередині неї. Повзунки рухають позицію по горизонталі й вертикалі; праворуч — чотири відстані, значення centerness і заміряна якість рамки для цього рівня центральності.
ЗіставленняЗіставлення без якорів: хто відповідає за предмет
Прибравши якорі, ми прибрали й старе правило зіставлення, яке спиралося на IoU з заготовкою. Потрібне нове, і воно виявилось окремою темою для досліджень.
Правило FCOS складається з трьох умов, і всі три читаються прямо в коді
torchvision:
Центр позиції має лежати всередині істинної рамки. Це те саме правило, з якого ми починали розділ 09.
Мало бути всередині — треба бути біля центра: не далі ніж
1.5 × крок від центра рамки по кожній осі. Так відсікаються ті самі
крайові позиції, заради яких вигадували centerness — тільки тут вони не
зважуються, а просто не стають позитивними.
Найбільша з чотирьох відстаней має потрапити у вікно свого рівня піраміди: від
крок × 4 до крок × 8. Так anchor-free детектор розводить
предмети по рівнях — без жодних заготовок.
Якщо після трьох умов позиція підходить кільком предметам, береться той, у якого рамка найменша за площею: у великого предмета позицій багато, у малого мало.
Наступний крок цієї історії — відмова від фіксованих порогів узагалі. Метод
ATSS (adaptive training sample selection) для кожної істинної рамки бере кілька
найближчих кандидатів, рахує середнє й стандартне відхилення їхніх IoU і
оголошує порогом середнє + відхилення. Поріг рахується з даних окремо для
кожної рамки: дрібний предмет, для якого всі кандидати погані, дістає низький поріг і
не лишається без позитивних прикладів; великий — високий.
СпадокЩо з цього стоїть у сучасних детекторах
Обидва винаходи теми пережили свої архітектури: RetinaNet і FCOS сьогодні майже не запускають, а от їхні частини стоять усюди.
| ідея | де живе зараз |
|---|---|
| Focal loss | усі щільні детектори; у варіантах (quality focal loss, varifocal loss) ціллю є не одиниця, а якість рамки |
| Ініціалізація зсуву π = 0.01 | −4.5951 у RetinaNet і FCOS з torchvision, те саме в ultralytics |
| Anchor-free голова | YOLOv6, YOLOv7, YOLOv8, YOLOX, DETR і його нащадки |
| Розділена голова | YOLOv8: окрема гілка для рамки, окрема для класів |
| Динамічне зіставлення | ATSS, SimOTA, TaskAlignedAssigner у YOLOv8 |
| Centerness | здебільшого замінено: якість рамки вбудували в саму ціль класифікації |
Тема 25 уже показала це на числах: у голові
YOLOv8 немає окремої впевненості, є дві окремі гілки й немає жодного якоря. Тепер
видно, звідки кожна риса взялася. Порівняймо дві моделі torchvision,
зібрані офлайн:
| частина | RetinaNet | FCOS |
|---|---|---|
| хребет: ResNet-50 + FPN | 27 376 704 | 27 376 704 |
| голова класифікації | 4 248 115 | 2 572 123 |
| голова регресії | 2 443 300 | 2 373 893 |
| разом | 34 068 119 | 32 322 720 |
Хребет у них однаковий до останнього числа. Уся різниця — 1 745 399
параметрів — сидить у головах, і майже вся вона в останній згортці класифікації: у
RetinaNet це Conv2d(256, 819), бо 819 = 9 якорів × 91 клас,
у FCOS — Conv2d(256, 91), бо позиція одна. У голові регресії FCOS, крім
чотирьох відстаней, є ще й bbox_ctrness — та сама centerness окремою
згорткою.
ПідсумокПідсумок і місток далі
| ідея | у чому суть |
|---|---|
| Дисбаланс у втраті | 576 рішень на сцену, 4.05 позитивні; фон дає 99.72 % втрати свіжої мережі |
| Милиці не годяться | вибірка 1 : 3 викидає 97.2 % рішень і додає гіперпараметр |
| Focal loss | множник (1−p)γ: приклад із p = 0.9 стає в 100 разів тихішим, із p = 0.1 — у 1.2 раза |
| γ вирішує | усі три зерна при γ = 2 кращі за всі три при γ = 0; при γ = 5 mAP падає до 0.5656 |
| Ініціалізація зсуву | 72.19 проти 2.25 на першому кроці — та сама мережа, різний один зсув |
| Anchor-free | чотири відстані замість заготовки: голова легша втричі, mAP 0.9187 проти 0.8610 |
| Centerness | передумова істинна (IoU 0.743 на краю проти 0.857 у центрі), а виграшу на наших даних немає |
Головна пара чисел теми — 72.19 і 2.25: втрата на першому кроці однієї й тієї самої мережі, у якої відрізняється лише початкове значення одного зсуву. Тридцять два рази за рядок коду, якого немає в жодному переказі статті.
А головна думка не про числа. Обидва винаходи цієї теми прибрали рукотворні деталі: focal loss — правило «які приклади брати в навчання», anchor-free — набір заготовок, який доводилось вгадувати під датасет. Детектор ставав дедалі менше конструкцією з налаштувань і дедалі більше однією функцією, яку вчать наскрізно.
Але один рукотворний вузол ми так і не чіпали. Детектор досі видає тисячі рамок, серед яких повно дублікатів, і досі прибирає їх окремим алгоритмом — NMS. Це не частина мережі: його не навчають, у нього свій поріг, і в темі 23 ми бачили, як він назавжди губить один із двох предметів, що стоять поруч із IoU 0.714. Усе інше вже вчиться з даних, а останній крок конвеєра лишився жорстко запрограмованим.
Наступна тема прибирає і його — змінивши не голову, а саме поняття відповіді: замість оцінки для кожної позиції — фіксований набір запитів, кожен з яких відповідає щонайбільше за один предмет. Дублікатів не буде, бо їх не буде звідки взяти.