Более быстрый R-CNN (обнаружение объектов), реализованный Керасом для пользовательских данных из набора данных Google Open Images V4.

Вступление

После некоторого изучения CNN я решил попробовать еще одну важную область компьютерного зрения, обнаружение объектов. В этой области есть несколько популярных методов, в том числе Faster R-CNN, RetinaNet, YOLOv3, SSD и т. Д.. В этой статье я пробовал Faster R-CNN. Здесь я хочу обобщить то, что я узнал, и, возможно, дать вам немного вдохновения, если вам интересна эта тема.

Исходный код Keras версии Faster R-CNN, который я использовал, был написан yhenon (ссылка на ресурс: GitHub). Он использовал наборы данных PASCAL VOC 2007, 2012 и MS COCO. Что касается меня, я только что извлек три класса: Человек, Автомобиль и Мобильный телефон из Открытого набора данных изображений V4 от Google. Я применил конфигурации, отличные от его работы, чтобы соответствовать моему набору данных, и удалил ненужный код. Кстати, чтобы запустить это в Google Colab (для бесплатных вычислений на GPU до 12 часов), я сжал весь код в три записных книжки .ipynb. Извините за беспорядочную структуру.

Для начала, я предполагаю, что вы знаете базовые знания о CNN и о том, что такое обнаружение объектов. Это ссылка на оригинальный документ под названием Более быстрый R-CNN: на пути к обнаружению объектов в реальном времени с помощью региональных сетей. Тем, кто хочет внедрить пользовательские данные из набора данных Google Open Images V4 на Faster R-CNN, следует продолжать читать содержание ниже.

Я прочитал много статей, объясняющих темы, относящиеся к Faster R-CNN. У них есть хорошее понимание и лучшее объяснение по этому поводу. Кстати, если вы уже знаете подробности о Faster R-CNN и вам больше интересен код, вы можете пропустить часть ниже и сразу перейти к части с объяснением кода. Это моя ссылка на GitHub для этого проекта.

Рекомендации к прочтению:

Faster R-CNN: Вниз по кроличьей норе современного обнаружения объектов

Глубокое обучение для обнаружения объектов: всесторонний обзор

Обзор алгоритмов глубокого обучения для обнаружения объектов

Быстрее R-CNN (Краткое объяснение)

R-CNN (R. Girshick et al., 2014) - это первый шаг для Faster R-CNN. Он использует выборочный поиск (J.R.R. Uijlings and al. (2012)) для определения областей интересов и передает их в ConvNet. Он пытается определить области, которые могут быть объектом, объединяя похожие пиксели и текстуры в несколько прямоугольных блоков. В документе R-CNN используются 2000 предложенных областей (прямоугольных рамок) из выборочного поиска. Затем эти 2000 областей передаются в предварительно обученную модель CNN. Наконец, выходные данные (карты характеристик) передаются в SVM для классификации. Вычисляется регрессия между предсказанными ограничивающими прямоугольниками (bboxes) и наземными bbox'ами.

Fast R-CNN (Р. Гиршик (2015)) делает шаг вперед. Вместо того, чтобы применять 2000 раз CNN к предложенным областям, он только один раз передает исходное изображение в предварительно обученную модель CNN. Селективный алгоритм поиска вычисляется на основе выходной карты признаков предыдущего шага. Затем используется уровень объединения ROI для обеспечения стандартного и предварительно определенного размера вывода. Эти допустимые выходные данные передаются на полностью подключенный уровень в качестве входных данных. Наконец, два выходных вектора используются для прогнозирования наблюдаемого объекта с помощью классификатора softmax и адаптации локализации ограничивающего прямоугольника с помощью линейного регрессора.

Более быстрый R-CNN (сокращенно frcnn) делает больший прогресс, чем Fast R-CNN. Процесс выборки поиска заменяется на Сеть предложений региона (RPN). Как следует из названия, RPN - это сеть, предлагающая регионы. Например, после получения выходной карты объектов из предварительно обученной модели (VGG-16), если входное изображение имеет размеры 600x800x3, выходная карта объектов будет иметь размеры 37x50x256.

Каждая точка размером 37x50 считается якорем. Нам нужно определить конкретные соотношения и размеры для каждого якоря (1: 1, 1: 2, 2: 1 для трех соотношений и 128², 256², 512² для трех размеров в исходном изображении).

Затем RPN подключается к слою Conv с фильтрами 3x3, 1 заполнением, 512 выходными каналами. Выходные данные связаны с двумя сверточными слоями 1x1 для классификации и блочной регрессии (обратите внимание, что классификация здесь предназначена для определения, является ли блок объектом или нет).

Хавьер: Для обучения мы берем все якоря и разделяем их на две разные категории. Те, которые перекрывают объект наземной истинности с пересечением по объединению (IoU) больше 0,5, считаются передним планом, а те, которые не перекрывают ни один объект наземной истинности или имеют менее 0,1 IoU с наземными объектами считаются фоном.

В этом случае каждая привязка имеет 3x3 = 9 соответствующих прямоугольников в исходном изображении, что означает, что в исходном изображении 37x50x9 = 16650 прямоугольников. Мы просто выбираем 256 из этих 16650 блоков в качестве мини-пакета, который содержит 128 передних планов (поз.) И 128 фонов (негр.). В то же время применяется non-maximum suppression, чтобы гарантировать отсутствие перекрытия для предложенных регионов.

RPN завершается после выполнения вышеуказанных шагов. Затем переходим ко второму этапу frcnn. Подобно Fast R-CNN, для этих предложенных регионов (ROI) используется объединение ROI. На выходе получается 7x7x512. Затем мы выравниваем этот слой несколькими полностью связанными слоями. Последний шаг - функция softmax для классификации и линейной регрессии, чтобы зафиксировать положение ящиков.

Объяснение кода

Часть 1. Извлечение аннотации для пользовательских классов из набора данных Google Open Images v4 (ограничивающие рамки)

Скачайте и загрузите три файла .csv

На официальном веб-сайте вы можете загрузить class-descriptions-boxable.csv, щелкнув красное поле в нижней части изображения под названием Class Names. Затем перейдите в Download from Figure Eight и загрузите два других файла.

На веб-сайте с рисунком восемь я загрузил train-annotaion-bbox.csv и train-images-boxable.csv, как показано на картинке ниже.

Скачав их, давайте теперь посмотрим, что внутри этих файлов. train-images-boxable.csv содержит имя изображения в коробке и его URL-ссылку. class-descriptions-boxable.csv содержит имя класса, соответствующее их классу LabelName. train-annotations-bbox.csv есть дополнительная информация. Каждая строка в train-annotations-bbox.csv содержит координаты одного ограничивающего прямоугольника (сокращенно bbox) для одного изображения, а также имеет LabelName этого bbox и идентификатор текущего изображения (ImageID + ’. Jpg’ = Image_name). XMin, YMin - это верхняя левая точка этого bbox, а XMax, YMax - нижняя правая точка этого bbox. Обратите внимание, что эти значения координат нормализованы и при необходимости должны быть вычислены для реальных координат.

Получить подмножество всего набора данных

Весь набор данных Open Images Dataset V4, содержащий 600 классов, для меня слишком велик. Поэтому я извлекаю 1000 изображений для трех классов: Человек, Мобильный телефон и Автомобиль соответственно.

После загрузки этих 3000 изображений я сохранил полезную аннотационную информацию в файле .txt. Каждая строка имеет следующий формат: путь_файла, x1, y1, x2, y2, имя_класса (без пробела, просто запятая между двумя значениями), где путь_файла - это абсолютный путь к файлу для этого изображения, (x1, y1) и (x2, y2) представляют верхнюю левую и нижнюю правую реальные координаты исходного изображения, class_name - это имя класса текущего ограничивающего прямоугольника. Я использовал 80% изображений для обучения и 20% изображений для тестирования. Ожидаемое количество обучающих изображений и тестовых изображений должно составлять 3x800 - ›2400 и 3x200 -› 600. Однако могут быть некоторые перекрывающиеся изображения, которые появляются в двух или трех классах одновременно. Например, изображение может быть человеком, идущим по улице, а на улице несколько машин. Таким образом, количество bbox-ов для обучающих изображений составляет 7236, а количество bbox-ов для тестовых образов - 1931.

Часть 2: более быстрый код R-CNN

Я объясню некоторые основные функции в кодах. Полные комментарии для каждой функции записаны в записных книжках .jpynb. Обратите внимание, что я сохраняю размер изображения 300 для более быстрого обучения вместо 600, как я объяснил в Части 1.

Восстановите структуру VGG-16 и загрузите предварительно обученную модель (nn_base)

Подготовьте обучающие данные и обучающие метки (get_anchor_gt)

Входные данные взяты из файла annotation.txt, который содержит набор изображений с информацией об их ограничивающих прямоугольниках. Нам нужно использовать метод RPN для создания предлагаемых bbox.

  • Аргументы в этой функции
    all_img_data: list (путь к файлу, ширина, высота, список (bboxes))
    C: config
    img_length_calc_function: функция для расчета размера карты объектов конечного слоя (базовой модели) в соответствии с размером входного изображения
    mode: 'train' или 'test'; Режим «тренировка» нуждается в дополнении
  • Возвращает значение в этой функции
    x_img: данные изображения после изменения размера и масштабирования (наименьший размер = 300 пикселей)
    Y: [y_rpn_cls, y_rpn_regr]
    img_data_aug: данные дополненного изображения (исходное изображение с дополнением)
    debug_img: показать изображение для отладки
    num_pos: показать количество положительных якорей для отладки

Рассчитайте rpn для каждого изображения (calc_rpn)

Если карта объектов имеет форму 18x25 = 450 и размеры якорей = 9, потенциальных якорей будет 450x9 = 4050. Первоначальный статус для каждого якоря - «отрицательный». Затем мы устанавливаем якорь на положительный, если долговая расписка составляет ›0,7. Если долговая расписка составляет ›0,3 и‹ 0,7, это неоднозначно и не входит в цель. Одна из проблем заключается в том, что в RPN гораздо больше отрицательных, чем положительных регионов, поэтому мы отключаем некоторые из отрицательных регионов. Мы также ограничиваем общее количество положительных и отрицательных регионов до 256. y_is_box_valid показывает, есть ли у этого якоря объект. y_rpn_overlap показывает, перекрывается ли этот якорь с ограничивающей рамкой наземной истины.

Для «положительного» якоря y_is_box_valid = 1, y_rpn_overlap = 1.
Для «нейтрального» якоря y_is_box_valid = 0, y_rpn_overlap = 0.
Для «отрицательной» привязки y_is_box_valid = 1, y_rpn_overlap = 0.

  • Аргументы в этой функции
    C: config
    img_data: расширенные данные изображения
    width: исходная ширина изображения (например, 600)
    height: исходная высота изображения (например, 800)
    resized_width: ширина изображения изменена в соответствии с C.im_size (например, 300) < br /> resized_height: высота изображения изменена в соответствии с C.im_size (например, 400)
    img_length_calc_function: функция для расчета размера карты объектов конечного слоя (базовой модели) в соответствии с размером входного изображения
  • Возвращает значение в этой функции
    y_rpn_cls: list (num_bboxes, y_is_box_valid + y_rpn_overlap)
    y_is_box_valid: 0 или 1 (0 означает, что поле недействительно, 1 означает, что поле действительное)
    y_rpn_overlap: 0 или 1 (0 означает, что поле не является объектом, 1 означает, что поле является объектом)
    y_rpn_regr : list (num_bboxes, 4 * y_rpn_overlap + y_rpn_regr)
    y_rpn_regr: координаты боксов объединения x1, y1, x2, y2

Форма y_rpn_cls - (1, 18, 25, 18). 18x25 - это размер карты объектов. Каждая точка на карте функций имеет 9 привязок, и каждая привязка имеет 2 значения для y_is_box_valid и y_rpn_overlap соответственно. Итак, четвертая фигура 18 - это 9x2.

Форма y_rpn_regr - (1, 18, 25, 72). 18x25 - это размер карты объектов. Каждая точка на карте функций имеет 9 привязок, и каждая привязка имеет 4 значения для tx, ty, tw и th соответственно. Обратите внимание, что эти 4 значения имеют свои собственные y_is_box_valid и y_rpn_overlap. Итак, четвертая форма 72 - это 9x4x2.

Рассчитать интересующую область по RPN (rpn_to_roi)

  • Аргументы в этой функции (num_anchors = 9)
    rpn_layer: выходной слой для классификации rpn
    shape (1, feature_map.height, feature_map.width, num_anchors)
    Могут быть (1, 18, 25, 9), если размер изображения составляет 400 ширины и 300
    regr_layer: выходной слой для регрессии rpn
    shape (1, feature_map.height, feature_map. width, num_anchors * 4)
    Может быть (1, 18, 25, 36), если размер изображения составляет 400 ширины и 300
    C: config
    use_regr: использовать ли регрессию bboxes в rpn
    max_boxes: максимальное количество bboxes для подавления без максимального значения (NMS)
    overlap_thresh : Если iou в NMS больше этого порога, отпустите поле
  • Возвращает значение в этой функции
    result: блоки из не-максимального подавления (shape = (300, 4))
    боксы: координаты для блоков bbox (на карте характеристик)

Для 4050 якорей из вышеуказанного шага нам нужно выделить max_boxes (300 в коде) количество ящиков в качестве области интересов и передать их на уровень классификатора (второй этап frcnn). В функции мы сначала удаляем блоки, которые выходят за пределы исходного изображения. Затем мы используем подавление без максимума с пороговым значением 0,7.

Слой RoIPooling и слой классификатора (RoiPoolingConv, classifier_layer)

Уровень RoIPooling - это функция обработки roi до определенного размера путем максимального объединения. Каждая входная рентабельность инвестиций разделена на несколько подъячеек, и мы применили максимальное объединение к каждой подъячейке. Количество подъячеек должно соответствовать размеру выходной формы.

Слой классификатора - это последний слой всей модели, расположенный сразу за слоем RoIPooling. Он используется для прогнозирования имени класса для каждой входной привязки и регрессии их ограничивающего прямоугольника.

  • Аргументы в этой функции
    base_layers: vgg
    input_rois: `(1, num_rois, 4)` список rois с упорядочением (x, y, w, h)
    num_rois: number of rois обрабатываться за один раз (здесь 4)
  • Возвращает значение в этой функции
    list (out_class, out_regr)
    out_class: вывод уровня классификатора
    out_regr: вывод уровня регрессии

Сначала выравнивается объединяющий слой.
Затем следуют два полностью связанных слоя и 0,5 выпадающих слоев.
Наконец, есть два выходных уровня.
# out_class: функция активации softmax для классификации имени класса объекта
# out_regr: функция линейной активации для регрессии координат bboxes

Набор данных

Опять же, мой набор данных извлечен из набора данных Google Open Images V4. Выбраны три класса «Автомобиль», «Человек» и «Мобильный телефон». Каждый класс содержит около 1000 изображений. Количество ограничивающих рамок для «Автомобиль», «Мобильный телефон» и «Человек» составляет 2383, 1108 и 3745 соответственно.

Параметры

  • Значение измененного размера (im_size) - 300.
  • Количество якорей - 9.
  • Максимальное количество не-макс-подавлений - 300.
  • Количество RoI для обработки в модели - 4 (я не пробовал использовать больший размер, который может ускорить расчет, но требуется больше памяти)
  • Адам используется для оптимизации, и скорость обучения составляет 1e-5. Все могло бы работать иначе, если бы мы применили решение из исходной бумаги. Они использовали скорость обучения 0,001 для 60 тыс. Мини-партий и 0,0001 для следующих 20 тыс. Мини-партий в наборе данных PASCAL VOC.
  • Для увеличения изображения я включаю horizontal_flips, vertical_flips и поворот на 90 градусов.

Среда

Google Colab с ускорением графического процессора Tesla K80 для обучения.

Время тренировки

Длина каждой эпохи, которую я выбираю, равна 1000. Обратите внимание, что каждый пакет обрабатывает здесь только одно изображение. Общее количество эпох, которые я тренировал, составляет 114. Каждая эпоха проводит в этой среде около 700 секунд, что означает, что общее время на тренировку составляет около 22 часов. Если вы, как и я, используете графический процессор Colab, вам необходимо повторно подключить сервер и загрузить веса, когда он автоматически отключается, чтобы продолжить обучение, потому что у него есть ограничение по времени для каждого сеанса.

Результат

Мы применили две функции потерь как к модели RPN, так и к модели классификатора. Как мы упоминали ранее, модель RPN имеет два выхода. Один предназначен для классификации объекта, а другой - для регрессии координат ограничивающих прямоугольников. Из рисунка ниже видно, что он очень быстро обучался в первые 20 эпох. Затем он стал медленнее для слоя классификатора, в то время как уровень регрессии все еще продолжает снижаться. Причина этого может быть в том, что точность объектности уже высока на раннем этапе нашего обучения, но в то же время точность координат ограничивающих прямоугольников все еще низкая, и требуется больше времени для изучения.

Аналогичный процесс обучения показан в модели классификатора. По сравнению с двумя графиками регрессии bboxes они показывают аналогичную тенденцию и даже одинаковую величину потерь. Я думаю, это потому, что они предсказывают довольно похожее значение с небольшой разницей в структуре их слоев. По сравнению с двумя графиками для классификации, мы видим, что предсказать объектность проще, чем предсказать имя класса bbox.

Эта общая потеря представляет собой сумму четырех потерь, указанных выше. Имеет тенденцию к снижению. Однако MAP (средняя средняя точность) не увеличивается при уменьшении потерь. MAP составляет 0,15, когда количество эпох составляет 60. MAP составляет 0,19, когда количество эпох составляет 87. MAP составляет 0,13, когда количество эпох составляет 114. Я думаю, это из-за небольшого количества обучающих изображений, что приводит переобучению модели.

Другие вещи, которые мы могли настроить

  1. Для более короткого тренировочного процесса. Я выбираю 300 как im_size для изображений с измененным размером вместо 600 в исходном коде (и исходной бумаге). Поэтому я выбираю меньший anchor_size [64, 128, 256] вместо [128, 256, 512].
  2. Я выбрал VGG-16 в качестве базовой модели, потому что он имеет более простую конструкцию. Однако такая модель, как ResNet-50, может иметь лучший результат из-за лучшей производительности при классификации изображений.
  3. В модели много порогов. Я использовал большинство из них, как и исходный код. rpn_max_overlap=0.7 и rpn_min_overla=0.3 - это диапазон различения «положительных», «нейтральных» и «отрицательных» для каждого якоря. overlap_thresh=0.7 - это порог для подавления, отличного от максимального.

Тест на изображениях

В блокноте я разделил процесс обучения и процесс тестирования на две части. Перед запуском тестовой записной книжки .ipynb сбросьте все среды выполнения, как показано ниже. И, возможно, вам нужно закрыть учебную записную книжку при запуске тестовой записной книжки, потому что использование памяти почти вышло за пределы ограничений.

Наконец

Чтобы развлечься, вы можете создать свой собственный набор данных, который не входит в набор данных Google Open Images V4, и обучить их. Для изображения на обложке, которое я использую в этой статье, это три монаха, изготовленные из фарфора, сделанные из Китая. Я просто назвал их по выражению лица (не уверен насчет сонного). Они не включены в набор данных Open Images V4. Поэтому я использую RectLabel для аннотирования самостоятельно. Я потратил около 3 часов на то, чтобы перетащить коробки достоверных данных для 6 классов с 465 изображениями (включая 'Apple Pen', 'Lipbalm', 'Scissor ',' Sleepy Monk ',' Upset Monk 'и' Happy Monk '). Для anchor_scaling_size я выбрал [32, 64, 128, 256], потому что бальзам для губ обычно мало на изображении. Найти эти маленькие квадратные бальзамы для губ. Я добавил меньший размер якоря для более сильной модели. Учитывая, что Apple Pen длинный и тонкий, anchor_ratio может использовать 1: 3 и 3: 1 или даже 1: 4 и 4: 1, но я не пробовал. Время тренировки было недолгим, да и выступление было неплохим. Думаю, это из-за относительно простого фона и простой сцены. На самом деле, я обнаружил, что сложнее не аннотировать этот набор данных, а подумать о том, как их сфотографировать, чтобы сделать набор данных более надежным.

Хорошо, это все для этой статьи. Спасибо за просмотр. Это моя ссылка на GitHub для этого проекта. Идите вперед и обучите свой собственный детектор объектов. Если у вас возникли проблемы, оставьте, пожалуйста, свой отзыв. Рад вас слышать :)