В прошлой части мы поговорили про эволюцию DETR. Сегодня продолжаем обсуждать вариации архитектуры и нюансы их имплементации. Часть 1 Часть 3 DETR предложил новую архитектуру для детекции - с энкодером, декодером, positional queries, двумя типа этеншна. Но ещё одним ключевым нововведением стал уникальный one-to-one matching loss. Вместо матчинга нескольких предсказаний и одной GT-коробки, мы находим оптимальную комбинацию, которая даёт минимальный лосс. Есть ли у этого подхода недостатки? Оказалось, что да. Код 111 цитирований, 412 звёздочек В начале обучения DETR часто выдаёт не очень качественные предсказания и большое количество дубликатов. Это приводит к тому, что оптимальный матчинг между queries и GT-боксами очень нестабилен - небольшое изменение весов сетки может привести к абсолютному другому матчингу. Один и тот же query на двух соседних эпохах может быть заматчен с разными GT-коробками или вообще с бэкграундом, что приводит к нестабильности обучения. Авторы статьи предлагают решить эту проблему так - давайте в качестве вспомогательной задачи кормить сетке зашумлённые GT-боксы (смещённые, увеличенные, уменьшенные) и просить её восстановить оригинальную коробку. Имплементация достаточно проста - давайте создадим N дополнительных queries и разобьём их на m групп, так что в каждой группе окажется k=N/m queries. Каждая группа будет отвечать за денойзинг своего GT-бокса. Чтобы “скормить” GT-бокс своей группе queries, используется идея DAB-DETR, в котором каждый query - это конкретный бокс со своими координатами и размером. Берём коробку, зашумляем её k раз и инциализируем каждый query в группе своей версией шумного бокса. Задача декодера - воссоздать оригинальную коробку, то есть найти такой шифт зашумлённой версии, который вернёт её к истинной коробке. В принципе это всё, но дьявол как всегда кроется в деталях: Наивная имплементация такого дизайна ведёт к двум мощным ликам из-за механизма self-attention в декодере. Оригинальные queries получают доступ к зашумлённым версиям реальных коробок, а denoising queries внутри группы могут смотреть на другие зашумлённые версии самой себя. Что ж, слава богу, в MultiheadAttention есть замечательный аргумент attention_mask. Достаточно аккуратно инициализировать этот тензор, и queries не смогут смотреть, куда им смотреть не следует. Предложенный дизайн никак не использует информацию о классе объекта. Для повышения эффективности метода мы можем заставить сетку осуществлять и label denoising. Для этого мы можем случайным образом поменять истинный лейбл GT-коробки и прогнать его через эмбеддинг-слой. В итоге каждый query в декодере инициализируется как сумма positional-части (проекция синусоидального энкодинга зашумлённой коробки) и content-части (проекция эмбеддинга зашумлённого лейбла). Сетке нужно предсказать не только настоящие координаты и размер коробки, но и её настоящий класс. Почему это всё вообще должно увеличивать стабильность матчинга? Авторы разделяют процесс обучения DETR на две задачи - выучивание хороших энкоров и предсказание хороших оффсетов для этих энкоров. Из-за нестабильности матчинга (особенно на первых эпохах) вторая задача усложняется - ведь каждому query постоянно нужно предсказывать разные оффсеты в зависимости от того, с каким объектом он в этот раз сматчился. Для демонстрации этого эффекта авторы рассчитывают параметр IS (instability). Если query на двух соседних эпохах сматчился с разными объектами - добавляем единичку. Использование denoising queries ведёт к более стабильному матчингу, ведь “хорошим энкором” как раз выступает зашумлённый GT-бокс. Дополнительно решение задачи денойзинга ведёт к тому, что каждый query более расположен к поиску близлежащих объектов. На картинке мы видим, что оффсеты между энкорами и итоговыми предсказанями значительно ниже для DN-DETR, чем для DAB-DETR. Вот такая вот несложная идея, которая сильно забустила метрики и заложила основу для одной из лучших версий DETRа - DINO. Код 162 цитирования, 1.3к звёздочек Идея DN-DETR проста и мощна - мы используем денойзинг шумных GT-коробок как вспомогательную задачу для ускорения обучения. Но умение предсказывать хорошие оффсеты поможет, только если у нас есть хорошие энкоры. А что делать с плохими, рядом с которыми нет никаких GT-объектов? DINO предлагает использовать в задаче денойзинга не только положительные примеры, но и отрицательные. В каждой группе мы можем попросить часть вспомогательных queries денойзить хорошие энкоры, а часть - отвергать энкоры средненького качества. Чтобы сгенерить такие “так себе” энкоры достаточно наложить на центр GT-коробки более сильный шум (на картинке - точки внутри коричневого квадрата). При этом он должен быть не слишком сильным - чтобы энкор был всё ещё близок к объекту, но хуже, чем другие энкоры. В итоге модель в contrastive-манере учится понимать, что вот эти энкоры - хорошие, а вот эти - не очень, и для них нужно предсказать высокую вероятность background. Такой метод позволяет ещё сильнее уменьшить количество дубликатов - когда есть один хороший предикт и несколько посредственных. Особенно это помогает находить хорошие энкоры для маленьких объектов. Второе важное отличие DINO называется mixed query selection. В оригинальном DETR positional queries и инициализация content queries статична в том смысле, что никак не зависит от текущей картинки. Мы просто выучиваем хорошие энкоры и инциализируем content queries как нулевые векторы (картинка a). Некоторые архитектуры (например, two-stage Deformable DETR и Efficient DETR) отказываются от этого и динамически иницализируют энкоры и их content-часть с помощью энкодера (b). В DINO используется смешанный подход - positional-часть использует лучшие пропозалы энкодера, а вот content-часть остаётся независимой. Правда, в данном случае это не нулевые векторы, а выучиваемые эмбеддинги (c). Последняя модификация - это look forward twice. Качество предсказанной коробки на i-ом слое декодера зависит не только от текущего предсказанного оффсета, но и от текущего состояния энкора (positional query). Если энкор хороший - то и оффсет предсказывать легче. При этом, напомню, что в iterative box refinement Deformable DETR мы блокируем градиент между слоями. То есть, мы наказываем сетку за плохо предсказанные оффсеты, но не учитываем при этом качество исходного энкора. В DINO для предсказания промежуточных коробок на слое i используются текущие предсказанные оффсеты и недетачнутая версия референс-точек со слоя i-1. Звучит сложновато, но по факту это четыре символа в коде. DINO стоит на плечах предыдущих достижений - Deformable DETR, DAB DETR и DN DETR, но предложенные модификации позволяют достичь мега-соты. Забавная идея, которая развивает архитектуру DINO. Если в DINO для инициализации queries используется пропозалы из энкодера, то тут для генерации энкоров дополнительно используется ещё и аж целый YOLOv5. Насколько я понял, 800 queries инциализируется как обычно, а 100 из предиктов YOLO.  По факту к этой секции отношения особо не имеет, поскольку главное изменение - это именно YOLO, но ладно уж. Лосс DETRов состоит из трёх комопонентов - бинарная кросс-энтропия, GIoU и L1. На вход кросс-энтропии идут все 100/300/900 queries, а вот локализационные лоссы получают супервижн только от тех queries, которые были сматчены с GT-коробками. Их на каждой картинке обычно не так чтобы очень много. Можем ли мы как-то облегчить для сетки задачу локализации? Конечно, да. Код 19 цитирований, 151 звёздочка Одна из моих любимых статей про DETR - потому что она мега-простая в понимании и имплементации, но при этом эффективная. Раз у нас мало GT-объектов - давайте возьмём и продублируем их, например, 6 раз. За предсказание этих фейковых объектов будут ответственны специально выделенные под эту задачу queries. Конечно, не забываем при этом сгенерировать нужную attention-маску для self-attention, чтобы исключить взаимодействие двух групп queries. Вспомогательные queries на инференсе отбрасываются. Всё! Уложились в один параграф. На выходе получаем улучшенные метрики и ускоренное обучение за счёт роста потребления видеопамяти и небольшого замедления на трейне. На инференсе лишние queries можно отбросить. Код в проекте detrex 3 цитирования Идея очень похожа на предыдущую, только каждая копия GT-объектов матчится к своей выделенной группе queries. Естественно, мы блокируем self-attention между группами. На инференсе используем только одну группу - говорят, что можно брать любую, результаты одинаковые. Во второй версии модели авторы собирают все топовые фишки (group assignment, DINO, ViT как бэкбоун) и получают мега-гига-соту. Код (code will be available soon lol) 5 цитирований, 56 звёздочек Я уже упоминал, что детекторы можно выстраивать из кубиков, выбирать разные компоненты и соединять в хитрые архитектуры. Например, мы можем вместо декодера с positional queries и one-to-one матчингом просто навесить на энкодер другие детекционные головы - например, Faster-RCNN, RetinaNet или FCOS (кстати, тут есть старая запись моего доклада про anchor-free детекторы, сорри за ужасный звук). Зачем бы нам это делать? А затем, что традиционные детекторы используют one-to-many assignment - к примеру, в Faster-RCNN любой предикт, который имеет IoU с GT-коробкой выше порога (обычно 0.5 или 0.7), используется как положительный пример. Благодаря этому мы получаем намного больше примеров для супервизии трансформер-энкодера и бэкбоуна. В Co-DETR энкодер отдаёт фича-мапу одного скейла, затем мы строим из неё пирамиду фичей. Происходит это очень просто - никаких FPN или чего-то хитрого, просто делаем апсэмплинг и даунсэмплинг единственной фича-мапы. На полученную пирамиду мы можем навесить любую любимую детекцию - например, RPN + RCNN из Faster-RCNN. Получаем её предсказания, делим их на foreground и background согласно IoU или другому критерию, накладываем лосс. На этом ребята не останавливаются - хочется ведь помочь и декодеру. Все положительные предсказания из каждой головы можно превратить в positional queries как в DAB-DETR и DN-DETR - координаты и размер коробки энкодятся синусоидально и проецируются в новое пространство. Матчинг для этих queries не нужен, мы уже знаем, какие GT-коробки им соответствуют. Код 2 цитирования, 165 звёздочки А нужен ли вообще one-to-one матчинг, если от него столько проблем? В DETRообразных архитектурах одна из основных его задач - дедубликация предсказаний, которая позволяет отказаться от NMS. А так ли он плох? Авторы статьи берут за основу двухстадийный Deformable DETR и заменяют one-to-one matching на обычный IoU-assignment как в Faster-RCNN и других детекторах. Делается это на обеих стадиях (энкодер и декодер) - сейчас будем разбираться как именно. Напомню, что на стадии энкодера в two-stage Deformable DETR каждый “пиксель” генерит кандидата на хороший пропозал. Это происходит путём предсказания оффсета относительно энкора с фиксированным размером стороны и центром в этом “пикселе”. При IoU-assignment нам сначала нужно определить, а является ли вообще этот энкор положительным или отрицательным. Для этого каждый энкор матчится с GT-объектом, с которым у него наибольший IoU, при этом он должен быть выше порога. Я не знаю, насколько это хорошо будет работать для супер-маленьких объектов, не уверен, что они будут матчиться с энкорами фиксированного размера даже на самых больших фиче-мапах, надо проверять. В любом случае авторы указывают, что можно все назаматченные GT-объекты в итоге связать с ближайшим ещё незаматченным предиктом, и хуже это не сделает. На это всё сверху накладывается обычный бинарный классификационный лосс, как в RPN. Раз несколько предиктов теперь могут соответствовать одному GT-объекту, это неминуемо ведёт к очень похожим пропозалам, так что NMS накладывается уже на этой стадии. Собственно, как и в обычном Faster-RCNN. На второй стадии всё точно так же, только вместо фиксированных энкоров для матчинга используются улучшенные пропозалы из энкодера. Вот тут авторы как раз подмечают, мол, даже если снизить порог IoU с 0.7 до 0.6, у больших и средних объектов будет значительно больше сматченных предиктов, чем у маленьких. Для поддержания баланса можно ограничить количество предиктов, который могут сматчиться с одним и тем же объектом. И, конечно же, не забываем накинуть NMS сверху. В общем-то всё! Оказывается, что можно обучить DETR и без one-to-one матчинга, и метрики получаются даже лучше - ведь как показали H-DETR, Group DETR и Co-DETR, увеличение количества позитивных сэмплов помогает обучению. Из дополнительных плюсов - можно убрать self-attention между queries, из минусов - снова появляется NMS, к которому нужно подбирать IoU-трешхолд под свою задачу. А на каких-то задачах NMS может и вовсе фейлиться. Все упомянутые DETRы решают одинаковую задачу - предсказание координат центра, а также ширины и высоты коробки. Статьи в этой секции предлагают другие формулировки задачи детекции.  Есть такой старый прикольный детектор - CornerNet, он детектит верхние левые и правые нижние углы, и потом связывает их в пары через специальный хитмап эмбеддингов. Если эмбеддинги двух точек похожи - значит, это углы одного объекта. Pair DETR использует похожую формулировку - предсказываем левую верхнюю точку и центр коробки, причём за эти два предсказания ответственны два разных декодера. Центральный декодер ещё и предсказывает класс объекта. Собственно, поэтому здесь и используется не правый нижний угол, а центр, потому что там обычно больше важных для классификации фичей.  Детали дизайна: Фичи из энкодера и выучиваемые positional queries шарятся между двумя декодерами. i-ый query в одном декодере будет соответствовать i-му query во втором, то есть, они должны предсказывать точки одного и того же объекта. Это позволяет нам в духе SimCLR составить N (число queries) позитивных пар точек. Аутпуты декодеров для этих пар мы просим сделать похожими, а в качестве негативных примеров, которые должны отличаться берём остальные 2N - 2 (в статье написано 2N - 1, но я не понял почему) аутпутов декодера. Этот лосс прибавляется к классическим классификационным и регресионным. Остальная архитектура соответствует Conditional DETR. Метрики, вроде бы, повыше, а ещё показывают на примерах, что улучшается детекция объектов, которые сливаются с фоном, маленьких объектов внутри больших объектов и объектов по краям изображения. Код 31 цитирование, 261 звёздочка Строго говоря, статья не подходит в эту категорию, предсказываются в ней всё так же центры и размеры коробок, но одна из идей тут связана со следующей архитектурой SAP-DETR. Итак, авторы утверждают - одна из причин медленной сходимости DETR заключается в том, что в cross-attention Q (object queries) и K (фичи энкодера) оперируют в разных пространствах. Сюда они приплетают сиамские сети - мол они как раз созданы, чтоб переводить Q и K в одно пространство для сходимости. А в DETR Q и K в cross-attention имеют абсолютное разное происхождение. Соответственно, в начале обучения object queries примерно одинаково “размазывают” своё внимание по всем регионам, и требуется какое-то время, чтоб научиться фокусироваться на определённых.  Проблему предлагается решить достаточно необычным способом. По сути, мы просто берём и генерим content queries напрямую из фичей энкодера. Давайте разбираться… В качестве positional queries используются выучиваемые референс-боксы. Эти боксы используются для того, чтобы спулить фичи энкодера, которые предварительно решейпятся обратно в прямоугольник, с помощью старого доброго RoIAlign. По этим фичам предсказываются M координат точек, где M - число attention-голов в cross-attention. Из этих точек с помощью grid_sample забираются фичей наиболее важных точек бокса. Эти фичи и становятся новыми content queries. Возникает разумный вопрос - а нафига нам content queries с предыдущего слоя, если они тупо заменяются фичами из энкодера? Происходит ход конём - с их помощью генерируются веса, на которые домножаются новые content queries. Предсказанные точки также используются для генерации новых positional queries. Трансформируем их внутрикоробочные координаты в глобальные, генерим синусоидальный энкодинг и тоже домножаем на веса, полученные из content queries. В журнальной версии статьи (аж с двумя плюсами) убирается дропаут в трансформерах и добавляется поддержка multi-scale фичей. Первые слои декодера работают с самыми маленькими фичами, следующие два - с картой побольше, и последние два - с самым высоким разрешением. Благодаря описанному выше алгоритму семантического матчинга content queries подстраиваются под фичи того уровня, с которым мы сейчас работаем.  Код 2 цитирования, 18 звёздочек Модификации DETR, которые эксплицитно моделируют референс-точки или боксы, обычно используют центры объектов. Если задуматься, возможно, это не самое лучшее описание объекта с точки зрения задачи детекции - центры пересекающихся объектов часто находятся примерно в одном месте, а ещё это ведёт к тому, что появляется много queries, которые неплохо локализуют объекты, но всё равно попадают в негативные сэмплы после матчинга. А это сильно замедляет обучение. Какие есть альтернативы?  Только что упомянутый SAM-DETR пытался найти внутри бокса наиболее важные точки. Авторы SAP-DETR двигаются дальше - и предлагают в качестве референс-точки использовать наиболее важную для данного объекта точку. Каждый positional query в SAP-DETR состоит из двух частей - референс-точка и четыре расстояния до каждой стороны бокса (как во FCOS). Референс-точки можно равномерно раскидать по всему изображению. Каждый слой декодера предсказывает новые оффсеты для этих четырёх расстояний. Каждый object query стремится предсказывать только боксы, которые включают в себя референс-точку. Это делается с помощью добавления специального лосса, который накладывает штраф, если мы сматчили query с рефренс-точкой вне GT-бокса. Изображение может быть большим, и раскиданные точки могут не покрывать все объекты. Особенно это касается маленьких и удлинённых объектов. Чтобы решить эту проблему, референс-точкам разрешается ездить по картинке, но не слишком далеко. Для этого предсказанное “путешествие” домножается на скейл-фактор, равный единице, делённой на корень из размера грида (на картинке 4). Вот так выглядит движение точек на реальных картинках: Последнее важное изменение касается cross-attention. Визуализация весов этого attention в DETR показывает, что queries обращают внимание на центры и края объектов, что звучит логично. Если у двух queries похожие референс-точки и веса этеншна на края объекта, то начинаются проблемы. SAP-DETR разделяет cross-attention на две карты, которые потом суммируются. Первая называется Side Directed Gaussian и является развитием идеи DETR SMCA. Считается он примерно так: Я даже попытался в ноутбучке поразбираться с тем, как генерируются все эти оффсеты и карты. Суть заключается примерно в следующем. Мы берём нашу референс-точку и сдвигаем её ближе к сторонам коробки - например, вправо и вниз. Направление движения (влево-вправо, вверх-вниз) определяется знаком o_i, который предсказывается по текущему content query. От этой новой точки и разбрасывается гауссианская этеншн-мапа. Таким образом, каждая голова этеншна может больше обращать внимания на тот или иной край объекта. Вторая карта называется Point Enhanced Cross-Attention или PECA. Авторы говорят - посмотрели мы, значит, на визуализацию spatial attention в Conditional DETR, и увидели, что в основном весь этеншн идёт на одну из сторон объекта. В связи с этим предлагается конкатенировать энкодинг координат сторон объекта к Q в Cross-Attention. Итоговая этеншн-мара формируется как сумма SDG и PECA. В общем и целом, не фанат, довольно перегруженная идеями архитектура. Да, есть прирост, но по сравнению с тем же SAM-DETR не гигантский. Конец второй части. Третья часть скоро выйдет на Хабре. Не забудьте подписаться на Варим ML в ТГ!    Head of AI