Уяви дві більярдні кулі на зеленому сукні. Вони торкаються боками. Ти дивишся на фотографію й без жодних зусиль кажеш: тут дві кулі. Мережа з теми 30 цього не скаже. Вона підпише кожен піксель словом «куля» — усі до одного правильно — і на цьому її робота закінчиться. Питання «скільки їх?» для неї не існує: у семантичної маски немає поняття окремого предмета.
Ця тема про те, як це поняття туди повернути, і скільки воно коштує. Спойлер: коштує воно не одним новим шаром, а новою постановкою задачі — і саме тому тема потрібна окремо.
ПроблемаДві кулі на столі
Почнемо із заміру, а не з означення. У нас є наскрізні сцени блоку: полотно 64 на 64 пікселі, від одного до кількох предметів трьох класів — коло, квадрат, трикутник. Маски в цих сценах істинні за побудовою: саме з них у блоці 5 виводились рамки.
Візьмімо 120 сцен і порахуймо дві речі. Перша — яка частка предметів торкається іншого предмета того самого класу. Друга — скільки звʼязних плям дає семантична маска проти справжньої кількості предметів. Звʼязна пляма (або звʼязна компонента, connected component) — це група пікселів одного класу, яку можна обійти, ходячи тільки по сусідніх пікселях і не відриваючись.
Канонічні сцени блоку кидають на полотно від одного до трьох предметів. Тема 25 вже попереджала, що на таких сценах проба замала, тож зробимо ще один набір — щільний, до шести предметів. У генераторі змінилося рівно одне число: скільки фігур кидати. Правило «не дозволяти новій фігурі перекрити стару більше ніж на 45 % її площі» лишилось незмінним.
| на 120 сценах | рідкі (до 3) | щільні (до 6) |
|---|---|---|
| предметів | 247 | 420 |
| торкається предмета свого класу | 24 (9.7 %) | 105 (25.0 %) |
| торкається будь-якого предмета | 83 (33.6 %) | 245 (58.3 %) |
| звʼязних плям у семантичній масці | 236 | 364 |
| сцен, де кількість плям збіглася | 107 (89.2 %) | 79 (65.8 %) |
Читаємо таблицю знизу вгору. На щільних сценах кожен четвертий предмет злипається із сусідом свого класу, і семантична маска бачить 364 плями там, де предметів 420. Порахувати предмети по плямах не можна навіть теоретично: у третині сцен відповідь буде хибна.
Останній рядок називає це прямо: кількість плям збіглася з кількістю предметів у 107 сценах зі 120 на рідких (89.2 %) і в 79 зі 120 на щільних (65.8 %). Тобто навіть на рідких сценах, де дотиків усього 9.7 %, кожна девʼята сцена вже дає хибне число.
Але важливіше зрозуміти не «як часто», а коли саме підрахунок по плямах бреше. Випадків три, і всі три можна викликати в інтерактиві нижче:
- Дві фігури одного класу торкаються. Пікселі зливаються в одну пляму, і плям стає менше, ніж предметів. Це головний і найчастіший випадок — саме він дає 364 плями на 420 предметів.
- Фігура іншого класу лягла впоперек. Вона розрізає нижню фігуру на дві частини, і плям стає більше, ніж предметів. Помилка в інший бік, але теж помилка: одну фігуру порахують за дві, а іноді й за три.
- Обидві помилки на одній сцені. Одна пара злиплась, одну фігуру розрізало — і лічильники зійшлись. Число правильне, розбір хибний, і жодна перевірка кількості цього не помітить.
Через третій випадок 89.2 % — це верхня межа частки правильно розібраних сцен, а не сама частка. Саме тому нижче ми міряємо не збіг кількостей, а збіг кожної плями з її предметом.
Одна пляма чи два предмети
Дві фігури на полотні 64×64. Повзунок розсуває їх; перемикач робить їх різними класами. Праворуч — семантична маска й лічильник звʼязних плям.
ПостановкаВихід — список невідомої довжини
Сформулюймо різницю точно, бо вона тонша, ніж здається.
Вхід — зображення. Вихід — масив того самого розміру, у кожній клітинці якого стоїть номер класу. Форма виходу відома наперед: 64×64 чисел.
Вхід той самий. Вихід — список: для кожного предмета своя маска, свій клас і своя впевненість. Довжина списку наперед невідома і в кожного зображення своя.
Це та сама неприємність, що і в детекції. Тема 23 уже проходила її з рамками: мережа має видати змінну кількість відповідей, а звичайний тензор фіксованої форми цього не вміє. Там знайшлися два обходи — кандидат-області з теми 24 і фіксована сітка позицій із теми 26, після якої зайве прибирає NMS.
Є й друга частина неприємності, і вона глибша. У списку предметів немає природного порядку. Якщо мережа видала маску кола зліва першою, а кола справа другою — це та сама відповідь, що й навпаки. Отже, і втрату не можна рахувати «перший вихід проти першої істини»: спершу треба вирішити, який вихід кому відповідає. Тема 27 розвʼязувала рівно цю задачу угорським зіставленням у DETR. Тут вона повертається слово в слово, тільки зіставляти доводиться маски, а не рамки.
НаївнеНаївне лікування: звʼязні компоненти
Перше, що спадає на думку: у нас же вже є семантична маска. Розберімо її на звʼязні плями — і кожна пляма стане предметом. Це чесна базова лінія, і її треба поміряти, перш ніж будувати щось складніше.
Алгоритм є в OpenCV одним рядком: cv2.connectedComponents.
Запускаємо його окремо для кожного класу — інакше коло, що торкається
квадрата, стане однією плямою.
Результат на наших сценах. Ми питаємо: для скількох істинних предметів
знайшлася пляма, що збігається з ним хоча б на IoU ≥ 0.5 — та сама
міра збігу, що в темі 29,
тільки рахована по масках.
| відновлено предметів | рідкі сцени | щільні сцени |
|---|---|---|
| усі предмети | 0.951 | 0.836 |
| ті, що ні з ким не торкаються | 1.000 | 1.000 |
| ті, що торкаються свого класу | 0.500 | 0.343 |
Тут видно все. Предмет, який ні з ким не торкається, звʼязні компоненти відновлюють ідеально — усі до одного. Предмет, що торкається сусіда свого класу, вони відновлюють у половині випадків на рідких сценах і в третині — на щільних. Половина береться просто: коли дві фігури злиплись, спільна пляма ще може випадково збігтись із більшою з них, і тоді більша зараховується, а менша губиться. Чому на щільних сценах це падає ще нижче, до 0.343, ми окремо не міряли; найпростіше пояснення — там злипаються не лише пари, а й ланцюжки з трьох, а спільна пляма трьох фігур не схожа вже на жодну з них.
Отже, звʼязні компоненти — це не поганий метод. Це метод, який працює рівно доти, доки задача не почалась. Він розвʼязує все, крім єдиного випадку, заради якого існує instance segmentation.
Компоненти проти істини
Сцена з керованою щільністю. Перемикач показує або істинні предмети (кожен своїм кольором), або звʼязні плями семантичної маски. Табло рахує окремо, скільки предметів злилось із сусідом і скільки розрізало навпіл чужою фігурою.
Метрикаmask AP: чим міряти маски предметів
Перш ніж будувати модель, потрібна метрика. І тут гарна новина: винаходити нічого не треба. mask AP — це точнісінько box AP із теми 23, у якій IoU рахується не по рамках, а по масках. Уся інша механіка та сама.
IoU двох масок — це кількість спільних пікселів, поділена на кількість пікселів, зайнятих хоч однією з них. Символ ∩ означає «спільні», ∪ — «усі разом».
Рахуємо руками. Коло радіуса 5 займає 81 піксель. Його рамка — квадрат 11×11, тобто 121 піксель. Коло цілком лежить усередині рамки, тож спільних пікселів 81, а разом їх 121. IoU = 81 ÷ 121 = 0.669.
Прогнози сортуємо за спаданням упевненості. Кожен по черзі забирає собі найкращу ще вільну істину, якщо збіг не менший за поріг. Забрана істина більше нікому не дістанеться — саме тому дублікат другої рамки на тому самому предметі рахується помилкою.
Далі — площа під огинальною кривої точність-повнота, окремо для кожного класу, і середнє по класах. Жодної відмінності від теми 23 тут немає.
Тепер найцікавіше: наскільки різні числа дають дві метрики на тих самих передбаченнях. Візьмімо передбачення, у якому рамки ідеальні, а маска кожного предмета — це просто весь прямокутник його рамки. Так поводиться детектор без гілки маски, якщо змусити його видати маску.
| передбачення | box AP@0.5 | box@0.75 | box [.50:.95] | mask AP@0.5 | mask@0.75 | mask [.50:.95] |
|---|---|---|---|---|---|---|
| ідеальні маски | 1.0000 | 1.0000 | 1.0000 | 1.0000 | 1.0000 | 1.0000 |
| маска = вся рамка | 1.0000 | 1.0000 | 1.0000 | 0.8943 | 0.2912 | 0.4360 |
| зсув форми на 1 px | 0.9967 | 0.6455 | 0.5747 | 0.9701 | 0.4134 | 0.4872 |
| зсув форми на 2 px | 0.9675 | 0.0000 | 0.2659 | 0.6966 | 0.0000 | 0.1599 |
| звʼязні компоненти | 0.7640 | 0.6553 | 0.6768 | 0.8144 | 0.6727 | 0.7021 |
Другий рядок — головний. Рамки ідеальні до пікселя, тому box AP дорівнює рівно одиниці при будь-якому порозі: кращого передбачення рамок не буває. А mask AP при суворому порозі падає до 0.2912, і в середньому по порогах дає 0.4360. Одне й те саме передбачення: за рамками — бездоганне, за масками — менш ніж половина від бездоганного.
Чому саме так, видно з геометрії. Прямокутник рамки збігається з фігурою по-різному залежно від того, що це за фігура:
| фігура | IoU «маска = рамка» | звідки |
|---|---|---|
| квадрат | 0.9453 | квадрат майже і є своя рамка |
| коло | 0.6731 | коло не заповнює кутів рамки — те саме 81 ÷ 121 = 0.669, що ми порахували вище |
| трикутник | 0.4969 | трикутник — рівно половина рамки |
Трикутник займає половину своєї рамки, тож його «маска-прямокутник» має IoU 0.4969 — нижче за поріг 0.5, і при порозі 0.75 такий прогноз не зараховується взагалі. Ось звідки береться падіння: рамка не бачить форми, а маска — тільки форму й бачить.
Та сама відповідь, дві метрики
Перемикач обирає, як зіпсовано передбачення. Смуги — box AP і mask AP при трьох порогах. Заміряно на 120 щільних сценах.
Зверху внизЗверху вниз: спершу рамка, потім маска
Розвʼязків історично два сімейства, і вони протилежні за напрямком думки.
| підхід | порядок дій | звідки береться кількість предметів |
|---|---|---|
| зверху вниз top-down | знайти предмет рамкою, потім намалювати маску всередині цієї рамки | з детектора: скільки рамок, стільки предметів |
| знизу вгору bottom-up | підписати кожен піксель, потім згрупувати пікселі в предмети | з групування: скільки груп, стільки предметів |
Класичний представник першого сімейства — Mask R-CNN (2017). Ідея в одному реченні: візьми готовий детектор Faster R-CNN із теми 24 й додай до нього третю гілку, яка для кожної знайденої рамки малює маску.
Чому це працює, хоч і виглядає як обхідний маневр? Тому що всередині рамки задача знову стає семантичною. Рамка вже виділила один предмет; усередині неї треба відповісти лише «цей піксель належить предметові чи ні»: сусід залишився за краєм рамки або принаймні не «головний». Важку частину — розділити предмети — виконав детектор, а маску малює маленька мережа тієї самої форми, що U-Net із теми 30, тільки на крихітному вході.
Слабке місце теж видно одразу. Якщо детектор предмет проґавив, маски не буде нізвідки: гілка маски працює тільки в межах уже знайденої рамки. Стеля підходу зверху вниз дорівнює якості детектора.
ГілкаМаска як окрема гілка
Побудуймо це самі — на найменшому детекторі, який у нас є. Беремо anchor-free голову з теми 26: карта 8×8, у кожній позиції три числа класу, чотири відстані до країв рамки й одне число centerness. Нічого в ній не міняємо. Додаємо третю гілку:
Це Mask R-CNN у мініатюрі: ділянка карти ознак під рамкою, кілька згорток, одне подвоєння роздільності й окремий канал на кожен клас. Навчаємо на істинних рамках (так само, як у статті), а на перевірці подаємо гілці ті рамки, які видав сам детектор. Три зерна, AdamW, 240 щільних сцен.
| частина | параметрів |
|---|---|
| тіло | 60 576 |
| голова рамок (клас + відстані + centerness) | 4 616 |
| голова масок, канал на клас | 22 723 |
| голова масок, один канал на всіх | 22 657 |
| усього | 87 915 |
Результат на 120 щільних перевірних сценах. Знак ± тут і далі означає розкид — відстань між найгіршим і найкращим із трьох зерен, а не половину від неї: ±0.2779 читається як «найкращий прогін на 0.2779 вищий за найгірший».
| гілка масок | box AP@0.5 | mask AP@0.5 | mask AP[.50:.95] |
|---|---|---|---|
| канал на клас | 0.8810 ±0.0979 | 0.8678 ±0.0874 | 0.4622 |
| один канал | 0.8076 ±0.2779 | 0.8725 ±0.0476 | 0.4484 |
Перше й головне: маска працює. mask AP 0.8678 на сценах, де кожен четвертий предмет із кимось злипся, — це помітно більше за 0.8144 у звʼязних компонент, і, що важливіше, це число тепер росте разом із детектором, а не впирається в геометрію плям.
Друге: перевіримо себе на рідких сценах. Візьмімо одну модель — ту, що з зерна 0, — і прожену її крізь обидва набори. На щільних сценах вона дає box AP 0.9053 і mask AP 0.8807, на рідких — box AP 0.9372 і mask AP 0.9190. У темі 26 та сама anchor-free голова — без гілки маски й без centerness — дала на рідких сценах 0.9187. Числа не можна прикладати одне до одного впритул, бо голови трохи різні, але висновок із них однозначний: гілка маски рамкам не зашкодила, а просідання дають саме щільні сцени, а не маска.
Третє, і воно теж не збіглося з очікуванням. Різниця між «каналом на клас» і «одним каналом» у mask AP дорівнює −0.0047 при розкиді 0.0874. Різниці немає взагалі — вона у вісімнадцять разів менша за розкид, та ще й у «неправильний» бік. І це логічно: у нас три класи простих фігур, які мережа розрізняє впевнено, тож розчіплювати клас і форму нема від чого. Виграш від окремих каналів зʼявляється там, де класи схожі за формою й модель у них плутається, — а це COCO з вісімдесятьма класами, а не три геометричні фігури. Правильне формулювання: канал на клас коштує майже нічого (66 ваг у нас, 0.05 % у Mask R-CNN) і не шкодить, тому його беруть за замовчуванням, — але доводити його користь треба на складному датасеті, а не на нашому.
СтеляРоздільність маски: стеля без навчання
Mask R-CNN передбачає маску розміру 28×28 — і цей розмір не залежить від того, наскільки великий предмет. Маска слона й маска мурахи однаково складаються з 784 чисел, які потім розтягуються під розмір рамки.
Скільки на цьому втрачається, можна порахувати без жодного навчання. Беремо істинну маску, стискаємо її до 14×14, 28×28 або 56×56, розтягуємо назад під розмір рамки й міряємо IoU з оригіналом. Це стеля методу: краще за це не вийде навіть у бездоганної мережі.
| сторона предмета | маска 7×7 | 14×14 | 28×28 | 56×56 |
|---|---|---|---|---|
| 16 px | 0.9113 | 1.0000 | 1.0000 | 1.0000 |
| 28 px | 0.9224 | 0.9784 | 1.0000 | 1.0000 |
| 56 px | 0.9326 | 0.9643 | 0.9925 | 1.0000 |
| 112 px | 0.9336 | 0.9694 | 0.9829 | 0.9970 |
| 224 px | 0.9357 | 0.9695 | 0.9852 | 0.9918 |
Перше, що впадає в око: колонки не спадають. Від 56 до 224 пікселів сторона предмета росте вчетверо, а втрата на масці 28×28 лишається того самого порядку: 1 − 0.9925 = 0.8 %, потім 1.7 %, потім 1.5 %. Вона не подвоюється разом із предметом і взагалі не має напрямку — гуляє в межах одного відсотка. Причина проста, і її варто проговорити: помилка стискання живе на смузі вздовж межі фігури, і ширина цієї смуги росте разом із фігурою. Відносна втрата від цього лишається приблизно сталою.
Отже, для гладкої опуклої фігури 28×28 — не обмеження, а розумний компроміс. Обмеження зʼявляється в іншому місці.
Де 28×28 справді ламається
Візьмімо фігуру з тонкою деталлю сталої ширини — гребінець із зубцями завширшки 3 пікселі. Коли гребінець невеликий, три пікселі — це багато клітинок маски. Коли гребінець великий, три пікселі перетворюються на частку клітинки.
| гребінець | зубців | маска 14×14 | 28×28 | 56×56 |
|---|---|---|---|---|
| 28 px | 4 | 0.9463 | 1.0000 | 1.0000 |
| 56 px | 9 | 0.5756 | 0.9955 | 1.0000 |
| 112 px | 18 | 0.5421 | 0.5526 | 0.9873 |
| 224 px | 37 | 0.5604 | 0.5336 | 0.5474 |
Ось воно. Доки предмет не більший за 56 пікселів, маска 28×28 тримає 0.9955. На предметі 112 пікселів вона провалюється до 0.5526: одна клітинка маски накриває чотири пікселі, а зубець завширшки три — зубці зливаються в суцільну пластину. І 56×56 рятує лише на крок, до наступного подвоєння розміру.
На наших сценах предмети маленькі — сторона рамки від 3 до 21 пікселя, у середньому 16.7. Тому:
Тобто на наших сценах 28×28 не коштує нічого: предмет менший за маску, і стискати нема чого. Саме тому таблиці вище рахувались на штучних фігурах різного розміру: стеля методу залежить від розміру предмета, а на дрібних предметах її просто немає.
Скільки маска втрачає при стисканні
Ліворуч — істинна фігура, праворуч — вона ж після стискання до маски R×R і розтягування назад. Число рахується просто зараз, тим самим двопрохідним білінійним перетворенням, що й у таблицях вище. У таблиці гладких фігур числа усереднені по трьох фігурах, тут — по одній обраній, тож вони не мусять збігатися до знака; таблиця гребінця, навпаки, збігається з цією фігурою клітинка в клітинку.
ВирівнюванняRoI-Align: маска і є геометрія
Тема 24 уже показувала різницю між RoI-пулінгом і RoI-Align: перший округлює координати рамки до цілих клітинок карти ознак, другий читає значення в дробових координатах через білінійну інтерполяцію. Там ішлося про ознаки, і зсув у пів пікселя виглядав дрібницею.
Для маски це не дрібниця, а суть справи. Маска — це і є геометрія. Якщо ділянка, з якої читає голова, зсунута відносно рамки, у яку маску потім вклеюють, то маска приїде зсунутою — і це видно на кожному пікселі межі.
Поміряймо. Для кожного предмета беремо його рамку, зсунуту на δ пікселів (справжній детектор ніколи не видає цілих координат), витягуємо маску 28×28 двома способами й порівнюємо з еталоном, порахованим руками: значення істинної маски в центрі кожної з 28×28 клітинок.
| зсув рамки δ | RoI-Align | RoI-пулінг | різниця |
|---|---|---|---|
| 0.00 px | 0.9617 | 0.8354 | +0.1263 |
| 0.25 px | 0.9543 | 0.8788 | +0.0755 |
| 0.50 px | 0.9570 | 0.7738 | +0.1832 |
| 0.75 px | 0.9546 | 0.8082 | +0.1464 |
Читаємо. Колонка RoI-Align рівна: 0.954-0.962 при будь-якому зсуві. Колонка RoI-пулінгу стрибає між 0.77 і 0.88 залежно від того, куди саме округлились координати. Це і є головна ознака квантування: результат залежить не від якості моделі, а від того, чи пощастило рамці лягти близько до цілого числа.
Різниця розкладається на дві частини, і корисно бачити обидві:
- Округлення координат. Рамка з
x = 12.6читається якx = 13. Це прямий зсув маски. Видно з того, що при δ = 0.5 пулінг падає найнижче: округлювати ніде так не боляче, як рівно посередині. - Максимум замість середнього. RoI-пулінг бере в кожній клітинці максимум, і на бінарній масці максимум означає «є хоч один піксель предмета». Маска від цього роздувається. Саме тому навіть при цілій рамці (δ = 0) пулінг дає лише 0.8354, а не одиницю.
round(0.5) дорівнює 0, а не 1: вбудоване округлення
банкірське, «до парного». У C, у JavaScript і всередині roi_pool
округлення інше — «половина вгору», тобто 1. Половини — це рівно ті значення, що
виникають при квантуванні координат, тож своя реалізація на Python і бібліотечна
розійдуться саме там, де це найпомітніше. Пиши math.floor(x + 0.5)
явно.Звідки читає кожен спосіб
Рамка предмета зсунута на дробову величину. Сітка показує, де саме беруться значення: RoI-Align — у дробових точках, RoI-пулінг — у клітинках округленої рамки.
ЦінаСкільки коштує маска в Mask R-CNN
Тепер розберемо справжню модель. У torchvision є і детектор, і його
версія з масками, тож ціну гілки маски можна дістати прямим відніманням. Обидві
збираємо офлайн, без ваг:
А тепер розкладемо Mask R-CNN на частини:
| частина | параметрів | частка | що робить |
|---|---|---|---|
| тіло ResNet-50 | 23 508 032 | 52.9 % | перетворює картинку на карти ознак |
| FPN | 3 344 384 | 7.5 % | зшиває карти різних масштабів |
| RPN | 593 935 | 1.3 % | пропонує кандидат-області |
| голова рамок | 14 362 055 | 32.3 % | клас і уточнення рамки |
| голова масок | 2 646 107 | 6.0 % | маска 28×28 у кожній рамці |
| усього | 44 454 513 | 100 % |
Три висновки, і жоден не очевидний наперед.
Перший: різниця між двома моделями дорівнює голові масок точно, до одиниці.
44 454 513 − 41 808 406 = 2 646 107, і це рівно
mask_head (2 360 320) плюс mask_predictor (285 787).
Тобто Mask R-CNN — це буквально Faster R-CNN плюс одна гілка; тіло, FPN, RPN і
голова рамок не змінились жодним параметром.
Другий: маска коштує 6.0 % моделі, а рамки — 32.3 %. Голова рамок у 5.4 раза важча за голову масок. Причина в тому, що голова рамок починається з двох повнозвʼязних шарів на 1024 нейрони, а голова масок — суцільно згорткова. Це, до речі, і пояснює, чому маска зберігає геометрію: у ній немає жодного шару, який перемішав би пікселі між собою.
Третій: маска передбачається для кожного класу окремо, і це майже безкоштовно.
Останній шар голови масок — Conv2d(256, 91, 1): 91 канал на
91 клас COCO. Кожен клас коштує 257 ваг (256 множень плюс зсув), усі 91 разом —
23 387. З 44 мільйонів це 0.05 %. Для порівняння, у голові рамок клас коштує
5125 ваг — у 20 разів дорожче.
Із чого складається Mask R-CNN
Перемикач прибирає гілку масок і показує чистий Faster R-CNN. Повзунок міняє кількість класів у датасеті — і видно, яка голова від цього росте, а яка ні.
named_children() справжньої моделі.
Зсунь повзунок класів до одиниці: голова масок схудне на 23 130 ваг, а
голова рамок — на 461 250. Клас у масці в 20 разів дешевший за клас у рамці,
бо маска — це один канал 28×28, а рамка — чотири числа й повнозвʼязний шар.Знизу вгоруЗнизу вгору: пікселі голосують за центр
Другий шлях думки: не шукати предмет цілком, а попросити кожен піксель сказати, до кого він належить. Найпростіший спосіб це виразити — хай кожен піксель показує стрілкою на центр свого предмета.
Два виходи того самого розміру, що й картинка. Перший — клас пікселя, як у семантичній сегментації. Другий — два числа на піксель: наскільки треба зсунутись праворуч і вниз, щоб потрапити в центр свого предмета.
Для кожного пікселя предмета додаємо його координати й передбачений зсув — виходить голос за точку. Пікселі одного предмета голосують приблизно за ту саму точку, пікселі різних — за різні.
Зводимо голоси в сітку 64×64, злегка розмиваємо й беремо локальні максимуми — це й будуть центри предметів. Далі кожен піксель приписуємо до найближчого до його голосу центра. Скільки центрів — стільки предметів.
Зверни увагу на головне: кількість предметів тут ніхто не задавав. Вона випала з даних — стільки, скільки виявилось піків. Це і є відповідь на питання з розділу 2 про список невідомої довжини, тільки з іншого боку, ніж у детекції.
Мережа — маленький U-Net на два рівні стискання, зі скіпами (тема 30 показала, що при двох рівнях скіпи ще майже нічого не дають, але вони й не коштують). 118 710 параметрів, вісім епох, три зерна.
| спосіб | щільні: mask AP@0.5 | щільні: AP[.50:.95] | рідкі: mask AP@0.5 | рідкі: AP[.50:.95] |
|---|---|---|---|---|
| звʼязні плями | 0.8144 | 0.7021 | 0.9515 | 0.8855 |
| зверху вниз | 0.8678 ±0.0874 | 0.4622 | 0.9190 | 0.5705 |
| знизу вгору | 0.9553 ±0.0189 | 0.7600 | 0.9611 ±0.0384 | 0.8355 |
Розкид у таблиці — по трьох зернах. У звʼязних плям його немає, бо там нічого не навчається; у рядку «зверху вниз» на рідких сценах його теж немає, бо там працює один і той самий детектор, навчений на щільних сценах, — ми просто подивились, як він поводиться на легших даних.
На щільних сценах групування дає 0.9553 проти 0.8678 при розкиді 0.0874 у підходу зверху вниз — тобто виграш рівно на межі розкиду, і саме так це й треба назвати. А от при суворому усередненні по порогах різниця стає безсоромною: 0.7600 проти 0.4622, тобто в 1.6 раза, і жодним розкидом її вже не пояснити.
Звідки такий розрив саме на суворих порогах? Ось причина, і вона пояснює половину теми. Зверху вниз малює маску не на зображенні, а всередині рамки. Маска народжується як клаптик 28×28, потім розтягується під рамку, потім вклеюється. Кожен із цих кроків додає похибку в один-два пікселі на межі — і при порозі 0.5 це нікого не турбує, а при порозі 0.9 зʼїдає все. Знизу вгору працює прямо на пікселях: маска предмета складається з тих самих пікселів, які мережа й підписувала, тому її межа точна за побудовою.
Той самий механізм пояснює й дивний рядок «звʼязні плями»: там, де вони не злиплись, вони точні до пікселя — і тому при суворих порогах обходять навчений детектор.
Три способи на одній сцені
Та сама сцена, три різні способи знайти предмети. Стовпчики — mask AP із наших замірів, по три навчання на кожен навчений спосіб.
ВибірКоли що працює
Зберімо все в одну таблицю, з якої можна вибирати.
| спосіб | бери, коли | ламається на |
|---|---|---|
| звʼязні плями | предмети фізично не можуть торкатись: клітини на розрідженому мазку, деталі на конвеєрі, будинки на аерознімку | будь-якому дотику двох предметів свого класу |
| зверху вниз Mask R-CNN | предмети різнорідні за формою й розміром, є готовий детектор, потрібна проста й передбачувана схема | пропущеній рамці — маски не буде; точності межі; сильному перекритті, коли в одну рамку влазять два предмети |
| знизу вгору групування | предметів багато, вони дрібні, схожі й торкаються; потрібна точна межа | предметах без очевидного центра: довгих, вигнутих, кільцевих, розірваних на частини |
І одне практичне правило понад таблицею. Спершу поміряй, скільки предметів
у тебе взагалі злипається. Ми почали тему саме з цього числа й не випадково:
на рідких сценах усі три способи дають 0.92-0.96 і вибирати майже нема з чого,
а на щільних вони розʼїжджаються на 0.14 за AP@0.5 і на 0.30 за AP[.50:.95]. Якщо в твоєму датасеті дотиків 2 %, то
instance segmentation тобі, найімовірніше, не потрібна — вистачить семантичної
маски й cv2.connectedComponents.
ПідсумокПідсумок і місток далі
Що варто забрати з теми.
- Різниця в питанні, а не в архітектурі. Семантична сегментація питає «якого класу цей піксель», instance — «якому предмету». Друге питання робить вихід списком невідомої довжини, а це та сама складність, що в детекції (тема 23) і в DETR (тема 27).
- Головне число теми — скільки предметів злипається. У нас 9.7 % на рідких сценах і 25.0 % на щільних. Від нього залежить, чи потрібна тема взагалі.
- Звʼязні плями — чесна база, а не солома. Вони відновлюють 1.000 предметів, що ні з ким не торкаються, і 0.343 тих, що торкаються. Твоя модель має вигравати саме в цього числа.
- mask AP — це box AP з іншим IoU. На тих самих ідеальних рамках із маскою-прямокутником box AP дорівнює 1.0000, а mask AP [.50:.95] — 0.4360. Але суворість не однобічна: на злиплих плямах mask AP вища за box AP.
- Маска 28×28 губить деталь, вужчу за клітинку сітки маски. Гладка фігура втрачає 0.8-1.7 % на предметах від 56 до 224 px, і втрата не росте разом із предметом; гребінець із зубцями 3 px падає з 0.9955 до 0.5526, щойно предмет переростає 56 пікселів.
- RoI-Align для маски критичніший, ніж для ознак. 0.954-0.962 проти 0.774-0.879, і головне — стало проти стрибків.
- Маска коштує 6.0 % ваг Mask R-CNN, а окремий канал на кожен клас — 0.05 %.
- Спосіб, що працює прямо на пікселях, точніший на межі. Групування знизу вгору дало AP[.50:.95] = 0.7600 проти 0.4622 у підходу зверху вниз, хоч при порозі 0.5 вони майже рівні.
І тепер про те, чого ми досі не вміємо. У нас є дві різні відповіді на одну картинку. Семантична мережа з теми 29 добре фарбує фон — небо, дорогу, траву, — але не рахує предметів. Модель цієї теми добре знаходить предмети, але фон її не цікавить зовсім: вона видає список масок, і те, що між ними, лишається нічиїм. Гірше: маски двох предметів можуть перекриватись, і питання «а цей піксель чий?» відповіді не має.
Виходить, щоб описати одну картинку повністю, треба запустити дві різні моделі і якось зшити їхні відповіді. Тема 32 береться саме за це: одна відповідь, у якій кожен піксель має і клас, і номер предмета, — і сегментація за підказкою, де предмет узагалі не треба називати наперед.