Представьте, что вы находитесь в стране, не имеющей выхода к морю, и распространилась инфекция. Правительство пало, и повстанцы бродят по стране. Если в этом сценарии вы являетесь военнослужащими, как вы принимаете решения в этой среде? Как вы можете полностью понять сложившуюся ситуацию?

Несколько месяцев назад НАТО организовало инновационный вызов, который поставил именно этот сценарий и эти самые вопросы. Мы решили принять вызов, чтобы найти инновационные решения в области фильтрации / объединения данных, визуализации и прогнозной аналитики.

Для тех, кто не знает, НАТО - это межправительственный военный альянс между 29 странами Северной Америки и Европы. Он представляет собой систему коллективной защиты, в соответствии с которой его независимые государства-члены соглашаются на взаимную защиту в ответ на нападение любой внешней стороны.

НАТО не предоставило никаких данных по вызову, поэтому нам пришлось искать его самим. В конечном итоге решение, которое мы придумали, использовало множество различных методов, включая компьютерное зрение на аэрофотоснимках, обработку естественного языка в прессе и социальных сетях, обработку геоданных и, конечно же, причудливые графики.

В этом посте (изначально опубликованном в Dataiku's blo g) мы сосредоточимся на самой технической части: обнаружении объектов для аэрофотоснимков, просмотре того, какие данные мы использовали, какая архитектура использовалась и как работает решение, и наконец наши результаты. Если вам интересно взглянуть на проект на более высоком уровне, то это здесь.

1. Набор данных

Для части проекта по обнаружению объектов мы использовали набор данных Cars Overhead With Context (COWC), предоставленный Ливерморской национальной лабораторией Лоуренса. Он содержит аэрофотоснимки, сделанные в шести разных местах:

  • Торонто, Канада
  • Селвин, Новая Зеландия
  • Потсдам и Файхинген *, Германия
  • Колумбус (Огайо) * и Юта, США

* В конечном итоге мы не использовали данные Колумбуса и Файхингена, потому что изображения были в оттенках серого.

Этот набор данных предлагает большие изображения (до 4 квадратных километров) с хорошим разрешением (15 см на пиксель) с центральным расположением каждого автомобиля. Как было предложено в этом среднем сообщении, мы предположили, что средний размер автомобилей составляет 3 метра. Мы создали коробки, расположенные вокруг каждого автомобильного центра, чтобы достичь нашей конечной цели - прогнозирования местоположения коробок (т. Е. Автомобилей) на невидимых изображениях.

2. Архитектура

Для обнаружения автомобилей на этих больших аэрофотоснимках мы использовали архитектуру RetinaNet. Эта статья, опубликованная в 2017 году на Facebook FAIR, выиграла лучшую студенческую работу ICCV 2017.

Архитектуры обнаружения объектов делятся на две категории: одноэтапные и двухступенчатые.

Двухэтапные архитектуры сначала разделяют потенциальные объекты на два класса: передний план и задний план. Затем все потенциальные объекты переднего плана классифицируются по более мелким классам: кошки, собаки, автомобили и т. Д. Этот двухэтапный метод очень медленный, но также и, конечно же, обеспечивает наилучшую точность. Самая известная двухступенчатая архитектура - Faster-RCNN.

С другой стороны, одноэтапные архитектуры не имеют этого этапа предварительного выбора потенциальных объектов переднего плана. Обычно они менее точны, но они также быстрее. Одноступенчатая архитектура RetinaNet является исключением: она обеспечивает двухступенчатую производительность при одноступенчатой ​​скорости!

На рисунке 2 ниже вы можете увидеть сравнение различных архитектур обнаружения объектов.

RetinaNet состоит из нескольких компонентов. Мы постараемся описать, как данные преобразуются на каждом этапе.

2.1. Сверточная сеть

Прежде всего, это ResNet -50. Как и любая сверточная нейронная сеть (CNN), она принимает изображение в качестве входных данных и обрабатывает его через несколько ядер свертки. Результатом каждого ядра является карта характеристик - первые карты функций фиксируют высокоуровневые характеристики (такие как линия или цвет). Чем дальше мы опускаемся в сети, тем меньше становятся карты функций из-за слоев объединения. Хотя они меньше, они также представляют более мелкую информацию (например, глаз, собачье ухо и т. Д.). Входное изображение имеет три канала (красный, синий, зеленый), но каждая последующая карта функций содержит десятки каналов! Каждый из них представляет собой особенность, которую он захватил.

Общий классификатор берет последние карты функций ResNet (формы (7, 7, 2048)), применяет средний пул на каждом канале (в результате получается (1, 1, 2048)) и передает его на полностью связанный слой с softmax.

2.2. Сеть пирамид функций

Вместо добавления классификатора после ResNet, RetinaNet добавляет Сеть пирамид функций (FPN). Выбирая карты объектов на разных уровнях из ResNet, он предоставляет богатые и многомасштабные функции.

Однако первые карты функций ResNet могут быть слишком грубыми, чтобы извлекать какую-либо полезную информацию. Как вы можете видеть на рисунке 4, более мелкие и более точные карты функций сочетаются с более крупными картами функций. Сначала мы повышаем дискретизацию меньших, а затем суммируем с более крупными. Существует несколько методов повышения дискретизации; здесь повышающая дискретизация выполняется методом ближайшего соседа.

Каждый уровень FPN кодирует различный вид информации в разном масштабе. Таким образом, каждый из них должен участвовать в задаче обнаружения объекта. FPN принимает на вход выход третьего (512 channels), четвертого (1024 channels) и пятого (2048 channels) блоков ResNet. Третий размер вдвое меньше четвертого, а четвертый - половину пятого.

Мы применили точечную свертку (свертку с ядром 1x1), чтобы унифицировать количество каналов каждого уровня до 256. Затем мы увеличили дискретизацию меньших уровней в два раза, чтобы они соответствовали размеру больших уровней.

2.3. Якоря

На каждом уровне FPN несколько привязок перемещаются по картам функций FPN. Якорь - это прямоугольник с разными размерами и соотношениями, например:

Эти якоря являются базовой позицией потенциальных объектов. Существуют пять размеров и три соотношения, поэтому существует 15 уникальных якорей. Эти якоря также масштабируются в соответствии с размером уровней FPN. Эти уникальные якоря дублируются на всех возможных позициях на картах функций. В результате получается K якорей.

Давайте пока отложим эти якоря.

2.4. Регрессия и классификация

Уровень каждой FPN передается в две полностью сверточные сети (FCN), которые представляют собой нейронные сети, состоящие только из сверток и объединения. Чтобы полностью использовать тот факт, что каждый уровень FPN содержит различную информацию, два FCN используются на всех уровнях! Слои свертки не зависят от размера ввода; имеет значение только размер их ядра. Таким образом, хотя карты характеристик каждой FPN имеют разные размеры, все они могут быть переданы в одни и те же FCN.

Первый FCN - это ветвь регрессии. Он прогнозирует значения K x 4 (x1, y1, x2, y2 для каждой привязки). Эти значения представляют собой дельты, которые немного изменяют исходные привязки, чтобы они лучше соответствовали потенциальным объектам. Все потенциальные объекты теперь будут иметь координаты типа:

(x1 + dx1, y1 + dy1, x2 + dx2, y2 + dy2)

С x? и y?, фиксированные координаты якорей, и dx?, dy?, дельты, созданные ветвью регрессии.

Теперь у нас есть окончательные координаты для всех объектов, то есть всех потенциальных объектов. Они еще не классифицируются как фоновые или легковые, грузовые и т. Д.

Второй FCN - это ветвь классификации. Это проблема с несколькими метками, когда классификатор предсказывает K x N (N число классов) потенциальных объектов с сигмоидом.

2.5. Удаление дубликатов

На данный момент у нас есть K x 4 координат и K x N успеваемость. Теперь у нас есть проблема: для одного и того же класса часто обнаруживается несколько ящиков для одного и того же объекта!

Таким образом, для каждого класса (даже если это не самый высокий класс) мы применяем Подавление без максимальных значений. Tensorflow предоставляет для этого функцию:

tf.image.non_max_suppression(boxes, scores, max_output_size, iou_threshold)

Основная суть этого метода заключается в том, что он удаляет перекрывающиеся блоки (например, на рисунке 6), чтобы оставить только один. Он также использует scores, чтобы сохранить наиболее вероятную коробку.

Общий комментарий к входному параметру метода Tensorflow выше: max_output_size соответствует максимальному количеству ящиков, которое мы хотим в конце - скажем, 300. iou_threshold - это плавающее значение между 0 и 1, описывающее максимальное соотношение перекрытия, которое принято.

2.6. Сохранение наиболее вероятного класса

Дубликаты ящиков для одного и того же класса в одном месте теперь удалены. Для каждого из оставшихся боксов мы оставляем только самый высокий класс (легковой, грузовой и т. Д.). Если ни один из классов не имеет оценки выше фиксированного порога (мы использовали 0.4), это считается частью фона.

2.7. Потеря фокуса

Все это может показаться сложным, но в этом нет ничего нового - недостаточно иметь хорошую точность. Настоящее улучшение от RetinaNet - это потеря: Focal Loss. Одноэтапные архитектуры, в которых отсутствует потенциальный предварительный выбор объектов, перегружены высокой частотой фоновых объектов. Focal Loss справляется с этим путем присвоения небольшого веса хорошо классифицированным примерам, обычно фоновым.

На рисунке 8 мы определяем Pt, уверенность в правильности бинарной классификации.

На рисунке 9 мы модулируем потерю перекрестной энтропии -log(Pt) на коэффициент (1 — Pt)^y. Здесь y - коэффициент модуляции, колеблющийся между 0 и 5. Хорошо классифицированные примеры имеют высокий Pt и, следовательно, низкий коэффициент. Следовательно, потери для хорошо классифицированных примеров очень малы и заставляют модель учиться на более сложных примерах. На Рисунке 10 видно, насколько сильно это сказывается на потерях.

3. Реализация

Мы использовали отличную Keras реализацию RetinaNet от Fizyr. Мы также написали новый генератор, использующий DataFrames Pandas вместо файлов CSV.

Как видите, изображения без аннотаций остаются на этапе обучения. Они по-прежнему помогают в обучении нашего алгоритма, поскольку заставляют алгоритм не видеть автомобили повсюду (даже там, где их нет). .

Мы использовали предварительно обученную сеть RetinaNet на COCO, а затем настроили ее для набора данных COWC. Только две FCN переобучаются для этой новой задачи, в то время как магистраль ResNet и FPN заморожены.

В блоке кода 2 ниже вы можете увидеть, как загрузить RetinaNet и скомпилировать его. Обратите внимание, что при загрузке грузов важно добавить skip_mismatch=True! Веса были созданы на COCO с 80 классами, но в нашем случае у нас есть только 1 класс, поэтому количество якорей не то же самое.

Нам еще нужно разобраться с огромным весом каждого изображения. Изображения из набора данных COWC имеют размер до 4 квадратных километров или 13k пикселей в ширину и в высоту. Эти большие изображения весят 300 МБ. Нецелесообразно загружать такие большие изображения в нашу сеть RetinaNet. Поэтому мы разрезаем изображения на участки размером 1000x1000 пикселей (или 150x150 метров).

Однако было бы глупо пропустить машины, потому что они были разрезаны между двумя заплатами. Чтобы избежать этой проблемы, мы сделали скользящее окно размером 1000x1000 пикселей, которое перемещается с шагом 800 пикселей. Таким образом, между двумя соседними участками будет перекрытие шириной 200 пикселей.

Это приводит к другой проблеме: мы можем обнаруживать автомобили дважды. Чтобы удалить дубликаты, мы применили подавление без максимума при связывании небольших участков. В самом деле, это означает, что у нас есть подавление без максимума дважды: после RetinaNet и при связывании небольших участков. Для второго подавления non-max мы использовали версию Numpy от PyImageSearch:

Имея дело с аэрофотоснимками, мы можем использовать множество дополнений к данным. Прежде всего, мы можем перевернуть горизонтальную ось и вертикальную ось. Мы также можем повернуть изображение на любой угол. Если масштаб изображения неоднороден (расстояние от дрона до земли может быть непостоянным), также полезно произвольно увеличивать и уменьшать масштаб изображения.

4. Результаты

Вы можете увидеть на рисунках 11 и 12 ниже, как наша сеть RetinaNet ведет себя на этом невидимом изображении Солт-Лейк-Сити.

5. У нас все хорошо?

Как мы можем оценить нашу работу?

Точности не хватило; нам нужно увидеть, сколько ложных срабатываний и ложных отрицаний мы получаем. Если мы обнаруживаем автомобили повсюду, у нас будет много ложных срабатываний, но если мы пропустим большинство машин, это будет много ложных срабатываний.

отзыв измеряет первое, а точность - второе. Наконец, f1-score представляет собой комбинацию этих двух показателей.

Однако мы не ожидаем, что наш RetinaNet обнаружит автомобили в точных правильных пикселях. Поэтому мы вычисляем индекс Жаккарда обнаруженных автомобилей и достоверных автомобилей, и если он превышает выбранный порог, мы считаем, что автомобиль был обнаружен правильно. Обратите внимание, что индекс Жаккара часто также (мягко говоря) называется Пересечение по объединению (IoU):

Вы можете увидеть образец на рисунке 13, где нанесены истинные положительные, ложноположительные и ложноотрицательные результаты.

Обратите внимание, что среди четырех ложных срабатываний два из них являются мусорными баками, один - дубликатом, а один - фактически… автомобилем! В самом деле, как и в любом наборе данных, в аннотациях достоверных данных могут быть некоторые ошибки.

На рисунке 12 показатель f1 равен 0,91. Обычно в городских условиях показатель f1 составляет около 0,95. Основная ошибка нашей модели заключается в том, что вентиляционные шахты на крышах зданий считаются машинами. В защиту модели, не зная о строительстве, это довольно трудно увидеть.

6. Заключение

Для решения задачи НАТО мы не только использовали обнаружение автомобилей по аэрофотоснимкам, но это была основная техническая часть проекта.

О… Мы забыли сообщить вам результаты испытания?

Были присуждены три премии: приз НАТО (с поездкой в ​​Норфолк), приз Франции (25 тысяч долларов) и приз Германии (с поездкой в ​​Берлин).

Мы выиграли приз как НАТО, так и Франции!

Вы можете прочитать более подробную информацию о проекте (включая все использованные нами данные и методологию) здесь.

Первоначально опубликовано в блоге Dataiku Data From The Trenches 22 июня 2018 г. [ссылка]. Эта статья была написана во время моего стажировки в Dataiku Lab. Этот проект был одним из многих, в которых я работал ведущим техническим специалистом.