Попередня тема поставила задачу й дала лінійку. Ми знаємо, що відповідь детектора — це список рамок, знаємо, як зіставити передбачену рамку з істинною через IoU, знаємо, звідки береться середня точність і чому притлумлення немаксимумів іноді викидає справжній предмет. Чого ми досі не знаємо — як детектор узагалі влаштований усередині. Ця тема відповідає на це питання історично: не «ось правильна архітектура», а «ось три спроби, і кожна наступна прибирала рівно одне вузьке місце попередньої». Дивитись треба не на назви, а на числа, бо саме числа щоразу примушували щось міняти.
ПеребірНайпростіша ідея, яка працює
Класифікувати ціле зображення ми вміємо з теми 09. Найкоротший шлях від класифікації до детекції виглядає так: якщо мережа вміє сказати «на цьому шматку — квадрат», то візьмемо всі можливі шматки й спитаємо в неї про кожен. Там, де вона впевнено скаже «квадрат», квадрат і лежить.
Цей прийом зветься ковзним вікном (sliding window). Беремо прямокутник заданого розміру, ставимо його в лівий верхній кут, вирізаємо, класифікуємо, зсуваємо на кілька пікселів праворуч, повторюємо. Дійшли до краю — переходимо на рядок нижче. Пройшли все зображення — беремо вікно іншого розміру, бо предмети бувають різні, і йдемо по колу знову.
Ідея чесна й до появи згорткових мереж працювала: саме так були влаштовані детектори облич і пішоходів, які ми згадували в темі 05. Проблема в кількості. Порахуймо.
Зображення шириною W і висотою H, вікно шириною w і висотою h, зсув на s пікселів. По горизонталі вікно поміститься (W − w) ÷ s + 1 разів, по вертикалі — (H − h) ÷ s + 1. Разом добуток цих двох чисел.
Фотографія 600×1000 — тобто 1000 пікселів завширшки й 600 заввишки; саме такий кадр стоїть у фігурі нижче. Вікно 128×128, крок 4 пікселі. По горизонталі: (1000 − 128) ÷ 4 + 1 = 219. По вертикалі: (600 − 128) ÷ 4 + 1 = 119. Разом 26 061 положень — і це лише для одного розміру вікна.
Предмети бувають різні за величиною, тож потрібно кілька масштабів — візьмімо девʼять, від 32 до 512 пікселів. І різні за формою: людина стоїть вертикально, автобус лежить горизонтально, тож на кожен масштаб три співвідношення сторін.
Помножити 26 061 на 27 не можна: велике вікно поміщається в кадр рідше за мале, тож кожна з 27 комбінацій дає свою кількість положень, і їх треба скласти. На самому лише масштабі 128 три форми разом дають 76 241 положення (це число показує лічильник фігури нижче), а сума по всіх девʼятьох масштабах — 591 415 вікон на один кадр.
Пів мільйона вікон — це пів мільйона запусків класифікатора. Ми заміряли, скільки коштує один такий запуск: ResNet-18 на шматку 224×224 в одному потоці йде 63.2 мс. Множимо — і дістаємо 10.4 години на одну фотографію. Не на датасет, не на відео. На один кадр.
Зменшити крок не можна — навпаки, хочеться менший, бо при кроці 4 пікселі
вікно рідко лягає точно на предмет. Збільшити крок до 16 знижує кількість вікон
до 37 672 — це в 15.7 раза менше. Шістнадцять тут теоретична межа:
учетверо рідше по горизонталі й учетверо по вертикалі дало б рівно 16, але
кількість положень рахується як (W − w) / s + 1, і та одиниця
наприкінці, разом із вікнами, що не влазять у кадр цілком, зʼїдає різницю.
Але навіть повні шістнадцять нічого не рятують: тоді рамка гарантовано зсунута
щодо істини на вісім пікселів, і з таблиці теми 23 ми знаємо, що для предмета сорок пікселів
завширшки це вже втрата IoU нижче 0.75.
Ковзне вікно: скільки разів доведеться спитати мережу
Кадр 1000×600. Перший повзунок задає розмір вікна, яке видно на кадрі; лічильник «усього» підсумовує всі масштаби й три співвідношення сторін на кожен із них. Покрути крок і кількість масштабів — і подивись, як росте число. Ліворуч показано положення вікон (намальовано не всі, щоб не залити кадр суцільним чорним), праворуч — кількість вікон при різних кроках у логарифмічному масштабі.
Висновок цього розділу простий і він же — мотив усієї теми. Ковзне вікно не має вузького місця, яке можна полагодити. Дорого тут усе одразу: і кількість вікон, і ціна одного запуску. Далі історія розгортається як послідовне зняття обох.
КандидатиКандидат-області замість перебору
Перша ідея, яка зрушила справу з місця, звучить майже нахабно: більшість із цих пів мільйона вікон очевидно порожні. Ділянка однорідного неба не містить предмета, і щоб це зрозуміти, класифікатор не потрібен — досить подивитись на пікселі.
Отже, розділімо роботу. Спершу дешевий алгоритм переглядає зображення й пропонує кілька тисяч ділянок, які схожі на окремий предмет — неважливо який. Потім дорога мережа розбирається лише з ними. Такі ділянки звуть кандидат-областями (region proposals), а алгоритм, який їх видає, — генератором кандидатів. У розмові їх часто називають просто кандидатами; далі в темі вживається повна назва, бо саме вона стоїть у глосарії курсу.
Найвідоміший із них — Selective Search. Не заглиблюючись у деталі, його ідея така: спершу зображення ріжеться на дрібні однорідні шматочки за кольором і текстурою, потім найсхожіші сусідні шматочки поступово зливаються в більші, і на кожному кроці злиття народжується рамка-кандидат. Дрібні шматочки дають маленькі рамки, злиті — великі, тож масштаби виходять самі, без окремого перебору.
Важлива тут не механіка, а зміна порядку величин. Selective Search видає близько двох тисяч кандидат-областей на зображення замість пів мільйона вікон — це у 295 разів менше. І кандидат-області не рівномірні: вони ліпляться до країв предметів, а не стоять сіткою.
R-CNNR-CNN і його ціна
R-CNN (regions with CNN features) — це перша архітектура, яка склала докупи згорткову мережу й кандидат-області та вперше показала на детекції результат, помітно кращий за класичні методи. Будова її буквально така, як щойно описано:
Selective Search дає близько 2 000 рамок. Мережа тут не бере участі взагалі — це окремий алгоритм на процесорі.
Кожна з 2 000 ділянок вирізається з картинки, розтягується до фіксованого розміру 224×224 і окремо проганяється крізь згорткову мережу. На виході — вектор ознак для кожної кандидат-області.
По вектору ознак окремий класифікатор (метод опорних векторів) вирішує, що це за клас, а окрема лінійна регресія трохи підправляє координати рамки. Обидва навчаються після мережі й окремо від неї.
Тепер друге речення другого етапу, і саме воно все вирішує. Окремо — означає, що згорткова мережа запускається дві тисячі разів на одне зображення. Кандидат-області перекриваються, іноді на девʼяносто відсотків, і піксель, що лежить у двадцяти кандидат-областях, буде згорнутий двадцять разів. Ознаки одного й того самого місця рахуються знову й знову.
Ми заміряли, скільки це коштує. Один прохід ResNet-18 по шматку 224×224 в одному потоці на процесорі — 63.2 мс.
| Що рахуємо | Скільки |
|---|---|
| прямих проходів на одне зображення | 2 000 |
| час на одне зображення | 126.4 с |
| прямих проходів на 5 000 зображень | 10 000 000 |
| час на 5 000 зображень | 176 год |
Дві хвилини на кадр. Тиждень безперервної роботи, щоб один раз пройти датасет із пʼяти тисяч зображень. На нашій крихітній мережі в 3 828 ваг ті самі дві тисячі проходів займають 0.51 с на кадр і 43 хвилини на датасет — уже не трагедія, але й мережа тут іграшкова.
Fast R-CNNFast R-CNN: один прохід
Вузьке місце названо: ознаки одного місця рахуються стільки разів, скільки кандидат-областей його накрили. Тепер його знімають — і спосіб виявляється майже очевидним заднім числом.
Згортка не переставляє пікселі. Ми знаємо це з теми 07: карта ознак зберігає просторову будову входу, лише в дрібнішій сітці. Якщо мережа має сумарний крок 16, то клітинка карти з координатами (3, 5) відповідає ділянці зображення приблизно навколо точки (48, 80). Отже, не треба вирізати шматок із картинки й гнати його крізь мережу — можна пройти мережею по цілому зображенню один раз, а потім вирізати потрібну ділянку з готової карти ознак.
Це і є Fast R-CNN. Порядок двох дій міняється місцями, і разом із порядком зникає повторний рахунок: скільки б кандидат-областей не було, згорткове тіло працює рівно один раз на кадр. Друга зміна не менш важлива: тепер класифікатор і регресія рамки — це звичайні шари тієї самої мережі, а не окремі моделі. Навчання стає одним, і градієнт від помилки координат доходить аж до першої згортки.
R-CNN проти Fast R-CNN: скільки разів працює тіло мережі
Повзунок задає кількість кандидат-областей. У верхньому ряду кожна кандидат-область вирізається й іде крізь мережу окремо; у нижньому тіло проходить по кадру один раз, а кандидат-області беруть готові ознаки. Смуги внизу — заміряний час у логарифмічному масштабі.
Два висновки з цієї картинки, і другий цікавіший за перший.
Перший: на двох тисячах кандидат-областей виграш становить 74 рази — 126.4 с проти 1.717 с. Це та різниця, після якої задача перестає бути теоретичною.
Другий: подивись, як поводяться дві смуги, коли рухаєш повзунок. Смуга R-CNN росте пропорційно кількості кандидат-областей — від нуля. Смуга Fast R-CNN починається з 576 мс і росте повільно. Отже, у Fast R-CNN зʼявилося нове вузьке місце, якого не було видно раніше: сталий внесок одного проходу тіла. Поки кандидат-областей дві тисячі, головна витрата — усе ще вони (1 141 мс проти 576 мс). Але варто скоротити їх до трьохсот, і картина перевертається: 171 мс на кандидат-області проти 576 мс на тіло. Заміряно на 300 рамках 757 мс, а не 747 — проста сума «тіло плюс лінійна ціна рамки» трохи занижує, і це нормальна похибка такого перерахунку.
Це підказує, куди дивитись далі. І ще одне, чого на цій картинці немає взагалі: сам Selective Search. Він працює на процесорі й коштує близько двох секунд на зображення (число цитоване, ми його не міряли). Тобто у Fast R-CNN генератор кандидат-областей став дорожчим за всю мережу разом узяту.
RoI-пулінгЯк вирізати ділянку з карти ознак
Лишилась технічна деталь, без якої «вирізати з карти ознак» — порожні слова. Кандидат-області мають різні розміри: одна 30×40 пікселів, друга 180×95. А повнозвʼязна голова, яка робить остаточне рішення, вимагає сталої кількості чисел на вході. Треба перетворити прямокутник довільного розміру на сітку сталого розміру — скажімо, 7×7.
Операція, яка це робить, зветься RoI-пулінг (RoI — region of interest, ділянка інтересу). Механіка така:
- Координати рамки з пікселів зображення перераховуються в клітинки карти ознак: ділимо на крок мережі. Рамка 100.3…187.7 при кроці 16 дає 6.27…11.73 клітинки.
- Ділянка карти ділиться на 7×7 однакових комірок.
- У кожній комірці береться максимум (або середнє) — і виходить рівно 49 чисел на канал, скільки б не була завбільшки початкова рамка.
А тепер те, заради чого цей розділ існує. Крок 1 дає дробові координати, а індексувати масив дробовим числом не можна. Класичний RoI-пулінг розвʼязує це найпростішим способом: округлює. 6.27 стає 6, 11.73 стає 12. Потім, коли ділянку ріжуть на 7 комірок, межі комірок теж не потрапляють у цілі клітинки — і їх теж округлюють. Два округлення підряд.
Округлення проти білінійної вибірки
Карта ознак 12×12, крок мережі 16 пікселів; значення клітинки дорівнює її стовпчику, тому колір — це просто координата. Рамка з дробовими координатами повзе праворуч по одному пікселю. Слідкуй за двома вертикальними мітками: суцільна темна — де центр рамки насправді, рожевий пунктир — де його бачить обраний спосіб вирізання.
ops.roi_align, і вони збігаються з нашим заміром.
Округлення дає сходинку: рамка їде, а вирізана ділянка
стоїть на місці, поки координата не перескочить наступне ціле. Модуль зсуву
гуляє від 0.57 до 8.71 пікселя, у середньому 4.64. Білінійна
вибірка тримає 0.00 у всіх шістнадцяти положеннях.Подивись на сходинку уважно, бо вона пояснює, чому це не дрібниця. Округлення — не «трохи неточно». Воно рве звʼязок між координатою рамки й вирізаними ознаками: у діапазоні цілої клітинки різні рамки дають однакові ознаки, а на межі клітинки ознаки стрибають. Голові, яка потім регресує координати, доводиться вгадувати зсув із ознак, які про цей зсув нічого не знають.
Наскільки це шкодить, залежить від кроку мережі й розміру предмета. При кроці 16 половина клітинки — це вісім пікселів. З таблиці теми 23 ми знаємо: щоб утримати IoU 0.75 на рамці сорок пікселів завширшки, її не можна зсувати більш ніж на 5.7 пікселя. Вісім — уже за межею. Для наших сцен 64×64 крок мережі всього 4 пікселі, тож і зсув удесятеро менший, і рятує нас саме дрібна сітка, а не акуратність операції.
RoI-AlignБілінійна інтерполяція замість округлення
Лікування знайшлося пізніше, у роботі про Mask R-CNN, і воно зветься RoI-Align. Ідея в одному реченні: не округлювати нічого.
Якщо потрібне значення карти ознак у точці з дробовими координатами, його не беруть із найближчої клітинки, а обчислюють — як зважене середнє чотирьох сусідніх клітинок, де вага кожної тим більша, чим вона ближча. Це зветься білінійною інтерполяцією і працює так само, як зміна розміру зображення з теми 03, тільки не по пікселях, а по картах ознак.
Хай потрібне значення в точці (y, x) = (2.3, 5.7). Цілі частини дають лівого верхнього сусіда (2, 5). Три інші — (2, 6), (3, 5), (3, 6).
Дробові частини: по вертикалі 0.3, по горизонталі 0.7. Вага сусіда тим більша, чим він ближчий, тож для кожного напрямку беремо або дробову частину, або те, що лишилось до одиниці. Сусід (2, 5) стоїть угорі й ліворуч: (1 − 0.3) × (1 − 0.7) = 0.7 × 0.3 = 0.21. Сусід (2, 6) — угорі й праворуч: (1 − 0.3) × 0.7 = 0.7 × 0.7 = 0.49. Сусід (3, 5) — унизу й ліворуч: 0.3 × (1 − 0.7) = 0.09. Сусід (3, 6) — унизу й праворуч: 0.3 × 0.7 = 0.21. Сума всіх чотирьох ваг завжди рівно 1, і тут вона 0.21 + 0.49 + 0.09 + 0.21 = 1.00.
У кожній із 49 комірок беруть не одну точку, а чотири (сітка 2×2 у середині комірки), рахують у них значення білінійно й усереднюють. Це згладжує результат і робить операцію придатною для навчання: похідна існує в кожній точці, бо ніде немає стрибка.
Що це дало за літературою: у роботі про Mask R-CNN заміна RoI-пулінгу на RoI-Align підняла якість масок приблизно на три пункти AP, причому виграш був тим більший, чим суворіший поріг IoU (число цитоване). Це узгоджується з нашим заміром: зсув у кілька пікселів майже не заважає при порозі 0.5 і стає вирішальним при 0.75.
У torchvision це операція ops.roi_align, і в неї є
аргумент aligned, який коштує окремої уваги. Він відповідає за пів
пікселя: центр нульового пікселя лежить у координаті 0.5, а не 0, і якщо це не
врахувати, уся ділянка зсувається на рівно пів клітинки. Ми заміряли:
при кроці 16 це 8.00 пікселя, стабільно, у будь-якому положенні рамки.
Замовчування — aligned=False, тобто зі зсувом; правильне
значення — True.
aligned=False лишили замовчуванням заради сумісності зі старими
навченими моделями: якщо мережу навчали зі зсувом, то з ним же треба й
запускати, інакше ознаки поїдуть. У новому коді став aligned=True
свідомо. І перевір це заміром на пандусі — це чотири рядки коду, і вони
дають точну відповідь замість здогадки.Faster R-CNNКандидат-області теж вчимо
Порахуймо, що лишилось у Fast R-CNN. Тіло по кадру — 576 мс. Дві тисячі кандидат-областей — 1 141 мс. Selective Search — близько двох секунд на процесорі. Найдорожча частина конвеєра — та єдина, що не є мережею й нічого не вчить.
Далі йде хід, після якого архітектура набуває сучасного вигляду. Карта ознак уже порахована. Вона лежить готова й описує все зображення. То чому б не попросити самі ці ознаки сказати, де тут предмети? Замість чужого алгоритму поставимо ще одну маленьку мережу, яка читає ту саму карту й видає кандидат-області. Вона зветься RPN (region proposal network, мережа кандидат-областей), а архітектура з нею — Faster R-CNN.
Вигода потрійна, і про останню часто забувають:
- Швидкість. RPN — це одна згортка 3×3 і дві згортки 1×1 поверх уже готової карти. Ми порахували її розмір у справжній моделі: 593 935 ваг, тобто 1.42 % від усієї мережі. Дві секунди Selective Search перетворюються на одиниці мілісекунд.
- Менше кандидат-областей. Навчена мережа не сипле кандидатами наосліп. Замість двох тисяч вистачає трьохсот — і саме звідси береться друге прискорення, видиме на попередній картинці.
- Спільні ознаки. RPN і голова другого етапу читають одну й ту саму карту. Тіло навчається під обидві задачі одразу, і кандидат-області підлаштовуються під той детектор, який їх споживатиме.
Лійка кандидатів: що саме прибрав кожен крок
Чотири стани однієї задачі. Смуги — скільки місць доводиться перевіряти на один кадр, у логарифмічному масштабі. Кнопки перемикають крок: праворуч видно, скільки разів працює тіло мережі, скільки це коштує часу і що саме зняв цей крок порівняно з попереднім.
Тепер мережа одна: від пікселів до рамок веде суцільний ланцюг, по якому проходить градієнт. Але щоб RPN узагалі могла щось видати, треба відповісти на незручне питання. Мережа — це функція із фіксованим виходом. Скільки чисел вона має видати, якщо предметів на кадрі може бути нуль, а може сто?
ЯкоріЯкорі: сітка заготовлених рамок
Відповідь називається якорями (anchors), і вона така: мережа не вигадує рамки з нічого. Ми заздалегідь розкладаємо по зображенню фіксований набір рамок-заготовок, а мережа лише каже про кожну дві речі — «тут предмет чи фон» і «наскільки цю заготовку треба посунути й розтягнути».
Центри якорів стоять у центрах клітинок карти ознак. Карта 16×16 дає 256 центрів; карта 38×63 (кадр 600×1000 при кроці 16) — 2 394.
У кожному центрі — кілька рамок різного розміру, бо предмети бувають великі й малі. Типово три.
І кожен розмір — у трьох формах: витягнута вертикально, квадратна, витягнута горизонтально. Типово 1:2, 1:1, 2:1.
Для кожного якоря — одне число впевненості («предмет / фон») і чотири числа зсуву: наскільки посунути центр по горизонталі й вертикалі та у скільки разів змінити ширину й висоту. Вихід має сталий розмір, а предметів на кадрі може бути скільки завгодно — суперечності немає.
Тепер порахуємо. На карті 38×63 із девʼятьма якорями на клітинку виходить
21 546 якорів. Це вже багато, але сучасні детектори працюють не з однією
картою, а з пірамідою карт різної дрібності. Ми взяли справжній генератор якорів
із fasterrcnn_resnet50_fpn і прогнали його на кадрі 800×1216:
| рівень піраміди | карта | клітинок | якорів |
|---|---|---|---|
| P2 (крок 4) | 200×304 | 60 800 | 182 400 |
| P3 (крок 8) | 100×152 | 15 200 | 45 600 |
| P4 (крок 16) | 50×76 | 3 800 | 11 400 |
| P5 (крок 32) | 25×38 | 950 | 2 850 |
| P6 (крок 64) | 13×19 | 247 | 741 |
| разом | — | 80 997 | 242 991 |
fasterrcnn_resnet50_fpn. Це видно й у розборі ваг у розділі 10:
на класифікацію «предмет чи фон» там іде 771 вага, тобто 256 × 3 + 3.Чверть мільйона рамок-кандидатів на один кадр. Проти пів мільйона вікон із першого розділу це не таке вже й полегшення — але тепер жодна з них не проганяється крізь мережу окремо: усі 242 991 обробляються двома згортками 1×1 за один прохід.
Як якір дізнається, що він позитивний
Щоб навчити RPN, потрібна мітка для кожного якоря. Правило просте й спирається на IoU з теми 23:
- IoU з якоюсь істинною рамкою більший за 0.7 — якір позитивний, мережа має сказати «предмет»;
- IoU з усіма істинними менший за 0.3 — якір негативний, «фон»;
- між 0.3 і 0.7 — якір ігнорується, у втрату не входить узагалі.
І окремо — рятівне правило: для кожної істинної рамки найкращий якір оголошується позитивним завжди, хоч би який низький у нього був IoU. Навіщо воно, покаже наступний замір.
Якорі на нашій сцені: скільки їх і скільки з них позитивні
Сцена 64×64 з трьома предметами, карта ознак 16×16 (крок 4). Пунктир — істинні рамки. Рожеві — якорі, які перетнули поріг. Сірі точки — центри якорів; самі якорі малюються не всі, бо їх дві тисячі.
box_iou. Найкращий якір на цій сцені має
IoU 0.694 з кожною з трьох істин, тож при стандартному порозі 0.7
позитивних нуль — без рятівного правила навчати було б нічим.
По 200 сценах картина така сама: 366 позитивних із 460 800
якорів, тобто 0.079 %, і 28.3 % істинних рамок не мають жодного
якоря з IoU понад 0.7.Тут три висновки, і кожен важливий окремо.
Перший: якорів-фону в тисячу разів більше, ніж якорів-предметів. На 200 сценах ми дістали 366 позитивних із 460 800, тобто на один позитивний якір припадає 1 258 негативних. Якщо просто скласти втрату по всіх якорях, мережа вивчить одну відповідь — «фон» — і матиме 99.9 % правильних відповідей при нульовій користі. Це та сама проблема дисбалансу, яку тема 23 показала на клітинках сітки. Faster R-CNN лікує її грубо, але дієво: на кожне зображення береться вибірка приблизно з 256 якорів, у якій позитивних і негативних порівну. Решта у втрату не входить. Тема 26 покаже інший спосіб — переважити втрату замість того, щоб викидати приклади.
Другий: набір якорів має відповідати даним. Перемкни співвідношення сторін і подивись на лічильник. Наші предмети — коло, квадрат і трикутник, і рамка в усіх майже квадратна. Тому при порозі 0.7 витягнуті якорі не дають жодного позитивного: із девʼяти варіантів у нашому замірі спрацювали лише два, обидва квадратні. Сім із девʼяти якорів на кожній клітинці — мертвий вантаж, і вони чесно збільшують час рахунку. На фотографіях вулиці, де є і пішоходи, і автобуси, картина інша — але дізнатися це можна лише замірявши, а не скопіювавши конфігурацію з чужої статті.
Третій: без рятівного правила навчання просто не почалося б. Постав поріг 0.7 і вимкни галочку — позитивних нуль. Це не рідкісний випадок: по 200 сценах 28.3 % істинних рамок не мають жодного якоря, який дотягнувся б до 0.7. Дрібна сітка й дискретний набір розмірів просто не покривають усі можливі положення предмета.
ЗамірRPN на нашій задачі
Тепер зберемо спрощений RPN самі й перевіримо головне: скільки кандидат-областей треба, щоб не втратити предмети. Будова — рівно та, що описана вище: згорткове тіло перетворює сцену 64×64 на карту 16×16, спільна згортка 3×3 готує ознаки, дві згортки 1×1 видають упевненість і зсув для кожного з девʼяти якорів у клітинці.
Далі виходи сортуються за впевненістю, проганяються крізь притлумлення немаксимумів із порогом 0.7, і беруться перші k. Міряємо повноту: яка частка істинних рамок має серед цих k кандидат-областей хоча б одну з достатнім IoU. Три зерна, AdamW, швидкість навчання 3e-3, чотирнадцять епох на 400 сценах — близько 25 секунд на прогін.
Скільки кандидат-областей потрібно
Повнота кандидат-областей залежно від їх кількості. Зелена крива — навчений RPN, сіра — стільки ж якорів, узятих навмання без будь-якого навчання. Вісь кількості логарифмічна.
Головне число теми — тут. При порозі 0.5 навчений RPN дає повноту 0.997 уже на десяти кандидат-областях; випадковим якорям для тієї самої повноти треба тисяча. Це рівно те, за що платять навчанням кандидат-областей: у сто разів менше кандидатів при тій самій повноті. Перекладаючи на конвеєр із четвертого розділу: 0.57 мс на кандидат-область, десять кандидат-областей замість тисячі — це 5.7 мілісекунди замість 570.
Друге, що видно, — стеля. Перемкни поріг на 0.7: повнота росте до 20 кандидат-областей і далі стоїть на 0.955, скільки б їх не додавати. Ще суворіший поріг 0.75 дає 0.861. Отже, додавати кандидат-області понад пʼятдесят на нашій задачі безглуздо — вони не приносять нових предметів, а лише годують другий етап зайвою роботою. Стеля береться не з кількості, а з точності: регресія зсуву здатна підправити якір лише до певної межі.
РозбірСправжня модель по частинах
Досі ми будували все самі й на іграшкових розмірах. Тепер розберемо
справжню fasterrcnn_resnet50_fpn із torchvision.
Її можна зібрати без жодного байта з мережі — weights=None,
weights_backbone=None дає порожню архітектуру з правильною будовою,
і ваги в ній можна перерахувати.
Прогін кадру крізь Faster R-CNN
Шість кроків від пікселів до рамок. Другий повзунок міняє розмір кадру — стеж за двома числами одночасно: скільки ваг у поточному блоці й скільки якорів дає ця сторона кадру.
torchvision: карта P2 — це округлена вгору чверть сторони,
далі кожен рівень удвічі дрібніший, три якорі на клітинку. На кадрі
800×1216 формула дає рівно 242 991 — стільки ж, скільки
видає справжній AnchorGenerator із torchvision у
нашому замірі. Ваги взяті з розбору зібраної моделі.Ось як 41 808 406 ваг розкладаються по частинах:
| частина | ваг | частка |
|---|---|---|
| хребет: тіло ResNet-50 | 23 508 032 | 56.23 % |
| хребет: FPN | 3 344 384 | 8.00 % |
| RPN | 593 935 | 1.42 % |
| голова: fc6 і fc7 | 13 895 680 | 33.24 % |
| голова: клас і рамка | 466 375 | 1.12 % |
| разом | 41 808 406 | 100 % |
Три речі варто прочитати з цієї таблиці окремо.
RPN — найдешевша частина мережі. 593 935 ваг, тобто 1.42 %. З них 590 080 — одна згортка 3×3 з 256 каналів у 256; на класифікацію «предмет чи фон» іде 771 вага, на регресію зсуву — 3 084. Механізм, який замінив дві секунди Selective Search, важить менше відсотка й губиться в таблиці. Це рідкісний випадок, коли ідея, а не обчислення, дає весь виграш.
Другий етап дорожчий за перший у двадцять чотири рази. 14 362 055
проти 593 935. І майже все це — один шар: fc6, повнозвʼязний шар
з 256×7×7 = 12 544 входів у 1 024 виходи, тобто 12 846 080 ваг. Той самий
сюжет, який ми бачили в темі 13:
ваги збираються там, де карта ознак розгортається в один вектор.
Хребет — це дві третини моделі. 26 852 416 із 41 808 406, тобто 64.23 %. Детекторна частина, заради якої вся тема, — це третина. Ось чому перенос навчання з теми 12 для детекції не просто корисний, а обовʼязковий: більшість ваг детектора — це класифікаційна мережа, яку вже хтось навчив.
ЦінаЧим платять два етапи
Двоетапні детектори роками лишалися найточнішими, і причина в самій формі відповіді. Перший етап відповідає на легше питання — «тут узагалі щось є?» — і має право помилятися в бік надлишку. Другий етап дивиться лише на кілька сотень уже відібраних місць, і саме тому може дозволити собі дорогу голову з тринадцятьма мільйонами ваг: 300 разів на кадр, а не 242 991.
Виходить розумний розподіл праці. Дешеве рішення на всіх кандидатах, дороге — на небагатьох. Плюс до того, другий етап бачить рамку після уточнення першим, тобто працює з ознаками, вирізаними з правильнішого місця. Це подвійне уточнення координат і дає перевагу при суворих порогах IoU.
Платять за це двома речами.
Складністю. Порахуй, скільки в цій конструкції рухомих частин: генератор якорів, правило зіставлення з двома порогами й рятівним винятком, вибірка збалансованого мінібатча, притлумлення немаксимумів між етапами, вибір кількості кандидат-областей, друге зіставлення вже для голови, друге притлумлення на виході. Кожна має свої гіперпараметри, і кожну можна налаштувати неправильно. Одноетапний детектор із теми 25 прибирає половину цього списку.
Швидкістю. Другий етап неможливо порахувати «одним махом»: він залежить від того, що видав перший. Конвеєр має точку синхронізації посередині, а вона погано лягає на паралельне залізо. Порівняймо ваги двох сімейств прямо:
Куди йдуть ваги: Faster R-CNN проти RetinaNet
Обидві моделі на тому самому хребті ResNet-50 з FPN. Повзунок міняє кількість класів — і саме на ньому видно різницю між головою, що працює по кількох сотнях кандидат-областей, і головою, що працює по всіх якорях одразу.
Отже, звична фраза «одноетапні детектори легші» справджується лише в звичному діапазоні кількості класів. При 91 класі COCO RetinaNet важить на 7.7 мільйона менше — це вагомо. При пʼятистах класах різниця майже зникає, а десь коло 587 класів перевертається. Причина в тому, де живе голова: у Faster R-CNN вона обробляє 300 векторів по 1 024 числа, у RetinaNet згортка проходить по всіх клітинках піраміди — на кадрі 800×1216 їх 80 997, і в кожній вона передбачає клас для девʼятьох якорів. Дорога дискретизація одноетапної моделі — не в кількості ваг, а в тому, скільки разів ці ваги застосовуються.
ПідсумокТри вузькі місця, три ходи
Уся тема вкладається в одну таблицю, і в ній важливий не список назв, а стовпчик «що саме прибрали».
| Крок | Вузьке місце | Хід |
|---|---|---|
| Ковзне вікно | 591 415 вікон на кадр | — |
| R-CNN | 2 000 проходів мережі на кадр, 126 с | дешевий генератор кандидат-областей замість перебору |
| Fast R-CNN | Selective Search на процесорі, дві секунди | ознаки рахуються раз, вирізаються з карти |
| Faster R-CNN | два етапи: точка синхронізації посередині й сім рухомих частин | кандидат-області теж передбачає мережа |
І окремо — технічна деталь, яка не дає прискорення, зате дає точність: RoI-Align. Округлення координат у RoI-пулінгу зсуває вирізані ознаки на кілька пікселів, білінійна вибірка не зсуває їх зовсім, і різницю видно саме там, де вимога до рамки сувора.
| що заміряно | число |
|---|---|
| вікон на кадр 1000×600, крок 4 | 591 415 |
| R-CNN: час на кадр | 126.4 с |
| Fast R-CNN: час на кадр, 2 000 рамок | 1.717 с |
| Fast R-CNN: час на кадр, 300 рамок | 0.757 с |
| зсув від округлення, крок 16 | 0.57 … 8.71 px |
| зсув RoI-Align | 0.00 px |
| якорів на кадр 800×1216 | 242 991 |
| позитивних якорів на наших сценах | 0.079 % |
| повнота RPN на 10 кандидат-областях | 0.997 |
| повнота випадкових якорів на 10 | 0.052 |
| ваг у RPN справжньої моделі | 593 935 (1.42 %) |
Лишається питання, яке ця тема поставила, але не закрила. Другий етап — це третина ваг і вся складність конвеєра. Він потрібен, бо дає точність. А чи потрібен він обовʼязково? Що станеться, якщо мережа передбачатиме клас і координати відразу для кожного якоря, без відбору й без другого проходу?
Швидкість зросте очевидно. А от точність, як покаже тема 25 «YOLO», впаде не так сильно, як здається, — і головна причина падіння виявиться не в архітектурі, а рівно в тому числі, яке ми щойно заміряли: 0.079 % позитивних якорів. Одноетапний детектор мусить рахувати втрату по всіх кандидатах одразу, і дисбаланс, від якого двоетапний рятувався вибіркою, бʼє по ньому на повну. Як із цим упоралися, розберуть теми 25 і 26.