DataDeep

Sapere aude

Обнаружение дорожных знаков при помощи Deep Learning

| Комментарии

Команда блога DataDeep не смогла остаться в стороне от новости об аварии самоуправляемого автомобиля Google, и поэтому я решил написать пост о своём опыте разработки системы для обнаружения дорожных знаков, основанной на машинном обучении. Такую систему вполне можно отнести к компонентам, которые используются как для разработки механизмов автономного упраления автомобилем, так и в современных системах помощи водителю :)

Постановка задачи, описание данных

Итак, мы хотим сделать приложение, которое будет максимально достоверно находить и выделять рамкой (region of interest, ROI) дорожные знаки на изображении, поступившем на вход. Сердцем метода, решающего эту задачу, будет, как не трудно предположить, машинное обучение. Для использования такого подхода необходимы тренировочные данные, в качестве которых будем использовать данные с соревнования The German Traffic Sign Detection Benchmark. Это соревнование по детектированию и определению категории дорожного знака, которое проводилось в 2013 году. В этих данных содержится информация о знаках из нескольких категорий, таких как предупреждающие, приоритета, запрещающие и предписывающие. Парным к нему является соревнование по распознаванию знаков The German Traffic Sign Recognition Benchmark, в котором алгоритм, построенный на основе глубоких нейронных сетей (deep learning), превзошёл по точности распознавания уровень человека.

Данные представляют собой 900 изображений размером $1360 \times 800$ в формате ppm, а также 1213 изображений дорожных знаков, взятых с этих картинок, размером от $16\times16$ до $128\times128$ в формате ppm. Некоторые из больших изображений содержат один и более знак, в то время, как другие не содержат знаков вовсе. ROI задаётся с помощью четырёхмерного вектора с координатами прямоугольной рамки . Для всех 900 изображений заданы правильные ROI. Несколько примеров из данных:

Один дорожный знак:

Два знака:

Без знаков:

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

Обзор state of the art подходов

Начиная примерно с 2012 года, когда на очень известном в сообществе computer vision соревновании по распознаванию изображений ImageNet победила команда университета Торонто под руководством Джеффри Хинтона, показав при этом значительный отрыв в точности от других команд, state of the art методом для распознавания изображений считается использование глубоких свёрточных нейронных сетей (Convolutional neural network, CNN), которые, в свою очередь, являются представителем класса алгоритмов машинного обучения deep learning (глубокое или, если угодно, глубинное обучение). Очень многие лучшие на сегодняшний день системы машинного зрения основаны на CNN, например система распознавания лиц от Facebook (к слову, глава Facebook AI Research Ян Лекун является одним из пионеров в исследовании CNN и deep learning).

В области детектирования предметов на изображении одним из самых эффективных является метод Regions with CNN features или R-CNN, представленный в 2014 году. Этот метод можно разделить на следующие этапы:

  1. Определение областей изображения, которые могут содержать интересующие нас объекты, с помощью алгоритма Selective search;
  2. Выделение из полученных областей признаков, используя свёрточную нейронную сеть;
  3. Эти признаки подаются на вход SVM (support vectors machine), которая классифицирует объект.

Существуют и другие успешные методы детектирования, основанные на CNN, например построение регрессии для нахождения четырёхмерного вектора ROI (т.е. на последнем уровне CNN находятся не вероятности, а целые значения). Однако, идея алгоритма, который мы будем строить, вдохновлена в первую очередь R-CNN, благодаря его простоте и эффективности, и реализует три его этапа, хотя имеет ряд значительных отличий.

Описание метода

Перед тем, как описать структуру метода для обнаружения дорожных знаков на изображении, скажу пару слов о технологиях, которые будут использованы. В качестве языка программирования применяется Python, так как для него есть API всех необходимых библиотек, и в данном случае нам больше важна гибкость и лёгкость прототипирования, чем скорость работы приложения.

Вся работа со свёрточными нейронными сетями ведётся с помощью изумительной библиотеки Caffe. Она позволяет конструировать, обучать и применять CNN, содержит state of the art виды слоёв и методы тренировки сети, обрабатывает данные в различных форматах (в том числе HDF5), позволяет обучать сети на графическом процессоре (GPU) с использованием CUDA, имеет обёртку для Python pycaffe. Для Caffe есть хранилище Model zoo, в котором содержаться обученные модели, которые можно использовать для своих задач. Также хочется отметить хорошие туториалы и большое сообщество. Архитектура нейронных сетей и параметры метода обучения задаются в Caffe в файлах формата prototxt.

Для обработки изображений используется библиотека OpenCV, которая, я думаю, не нуждается в дальнейшем представлении.

Детектор MSER

Приступим непосредственно к методу решения задачи. На первом этапе будем определять области входного изображения, которые потенциально могут содержать дорожный знак. Для этого было рассмотрено несколько детекторов (в частности selective search из R-CNN, который не смог хорошо выделить области со знаками). Метрикой качества служило среднее евкидово расстояние между настоящим ROI на изображениях из тренировочных данных и ближайшим к нему ROI, полученным с помощью детектора. Лучше всего себя показал метод MSER (maximally stable extremal regions). Из выделенных MSER областей отбирались те, в которых длина и ширина лежат в пределах от 16 до 128 и их соотношение не превышает 1.5 (т.е. более-менее близки по форме к квадрату). Таким образом, мы получаем набор областей, в которых может содержаться один дорожный знак.

Main CNN

На следующем этапе алгоритма для определения того, содержит ли область изображения из предыдущего этапа знак, будем применять классификатор. В этом качестве выступит представитель класса методов deep learning — глубокая свёрточная нейронная сеть. Ей на вход будет поступать изображение, а на выходе будут две вероятности, сумма которых равна 1: того, что изображение содержит и не содержит дорожный знак. Архитектура нейронной сети, которую мы будем использовать, сходна c архитектурой весьма эффективной сети Network in network (NIN), которая хорошо себя показала в 2014 году в конкурсе CIFAR-10 (определение, к какой из 10 категорий принадлежит изображение).

На вход нейронная сеть получает RGB изображение размером $32\times32$, которое предварительно преобразуется в такой формат, если нужно. Рассмотрим вкратце слои сети:

  • Свёрточный слой (CONVOLUTION) — как видно из названия, является основной частью CNN. Он реализует обычную операцию свёртки: мы идём по изображению скользящим окном, перемножаем значения в окне с заданными весами (ядром), а затем всё складываем. Наборов весов может быть несколько. Проиллюстрируем то, что делает свёрточный слой (картинка взята с хабра):

  • Rectified linear unit (RELU) — слой, в котором нет какой-то сложной математики и, как следствие, настраиваемых параметров. Он служит для того, чтобы получить нелинейность. К каждому входному значению этого слоя применяется функция:

Это то, что происходит в нейроне, так называемая activasion function. В “классических” нейронных сетях для этого используется сигмоидная функция или тангенс. Однако в последнее время эмпирически было установлено, что простая функция RELU оказывается очень эффективной.

  • Pooling (POOLING) — служит для уменьшения размерности. Входной двумерный массив делится на сектора, в зависимости от параметров, и в каждом из них происходит максимизация (MAX) или усреднение (AVE) (два самых распространённых вида pooling’а).

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

Архитектура всей сети представляет собой 3 больших последовательно соединённых слоя, каждый из которых состоит из [CONVOLUTION -> RELU -> CONVOLUTION -> RELU -> CONVOLUTION -> RELU -> POOLING -> DROPOUT]. На самом последнем слое мы получаем две вероятности. Назовём эту сеть Main CNN.

Структура Main CNN (при наведении на слой отображаются его параметры)

Полное описание свёрточной нейронной сети в формате prototxt, которое применятся для её обучения с помощью Caffe.

Для того, чтобы обучить всю эту сеть, будем использовать стандартный метод оптимизации Batch stochastic gradient descent с уменьшением параметра learning rate в 10 раз каждые 1000 шагов, начальный learning rate — 0.000001. Кроме того, применим метод Momentum Нестерова с параметром 0.9. В качестве регуляризации будем использовать Weight decay с параметром 0.0001. Обучение будет остановлено или при достижении максимального количества итераций, или при малом изменении функции потерь. Prototxt файл со всеми параметрами оптимизации, который используется в Caffe:

Solver
1
2
3
4
5
6
7
8
9
10
11
12
test_iter: 100
test_interval: 1000
base_lr: 0.000001
momentum: 0.9
weight_decay: 0.0001
lr_policy: "step"
gamma: 0.1
stepsize: 1000
display: 100
max_iter: 50000
snapshot: 1000
solver_mode: GPU

Для ускорения обучения будем применять подход Fine-tuning: веса нейронной сети инициализируются предобученными для другой (но похожей) задачи. Мы используем веса, которые были обучены авторами NIN для задачи CIFAR-10.

Features learning CNN

Итак, с помощью описанной выше CNN мы отберём области изображения, скорее всего содержащие знак (т.е. те, для которых вероятность наличия знака, выданная сетью, больше порога 0.5). Для того, чтобы улучшить качество распознавания, построим поверх нейронной сети ещё один классификатор. Для этого будем использовать CNN, аналогичную той, которую мы уже построили, только без последних двух слоёв pooling’а и вероятностей. Если посмотреть на параметры в описании архитектуры используемой CNN, то от туда можно понять, что новая сеть будет выдавать на выходе вектор размерности 128. Назовём её Features learning CNN. В качестве весов она использует натренированные веса Main CNN. Features learning CNN мы будем применять к областям изображений, которые по мнению Main CNN содержат дорожный знак. Мы получим 128-размерный вектор признаков, который будем “скармливать” машине опорных векторов (SVM) с полиномиальным ядром степени 2 и параметром регуляризации 0.1.

Таким образом, полный алгоритм представляет собой ансамбль:

Bootstrap

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

Применение метода

Теперь опишем то, как обучался алгоритм и что из этого вышло. Прежде всего, нам необходимы тренировочные данные для Main CNN. Разделим имеющиеся в нашем распоряжении 900 изображений на 600 тренировочных и 300 тестовых. В исходных данных уже есть изображения дорожных знаков, т.е. положительные прецеденты, однако нет отрицательных, т.е. изображений без знаков. Для того, чтобы получить эти данные, используем следующую процедуру: к каждому изображению из тренировочных данных применяется MSER и отбираются те его области, которые похожи по размерам на ROI (см. выше), не пересекаются с настоящим ROI, но при этом лежат относительно “не далеко” от него. Последний пункт нужен, т.к. CNN будет хорошо “отличать” дорожный знак от, например, неба или асфальта, но плохо от окна, фары машины, листвы и т.д., т.е. от объектов, которые на изображении находятся достаточно близко к знаку. Таким образом, если мы будем брать любые области, не пересекающиеся с ROI, то большинство из них будет содержать небо, дорожное покрытие, стены домов и т.п., что негативно отразится на качестве классификации. Всего таких отрицательных прецедентов отберём около 2000, чтобы выборка для обучения Main CNN была сбалансированной.

Примеры положительных прецедентов:

Примеры отрицательных прецедентов:

Чтобы улучшить качество распознавания дорожных знаков с помощью Main CNN будем использовать трюк, который является формой boosting’а:

  1. Обучим Main CNN на полученных нами на предыдущем этапе тренировочных данных;
  2. Определим, на каких отрицательных прецедентах Main CNN ошибается;
  3. Сформируем из них и положительных прецедентов новую тренировочную выборку;
  4. Продолжим обучение Main CNN с помощью Fine-tuning, где в качестве начальных весов используются веса, полученные в пункте 1;
  5. Повторим пункты 1–4 три раза.

Примеры новых отрицательных прецедентов:

При обучении SVM на изначальных тренировочных данных Main CNN результаты следующие: F1-score — 0.85, точность — 0.85.

После тренировки всех частей ансамбля алгоритмов мы можем применить их к тестовым данным. В качестве метрики точности для изображений, содержащих дорожные знаки, возьмём наименьшее евклидово расстояние между векторами, описывающими ROI. Это не самая точная метрика, однако она даёт представление о качестве работы метода. Результаты на тестовых данных (300 изображений): 39.9; число случаев, когда алгоритм не показал ROI, а они есть (False negative): 33; число случаев, когда алгоритм показал ROI, а их нет (False positive): 5. Ниже представлено несколько характерных примеров работы алгоритма.

Все знаки правильно обнаружены:

Алгоритм может ошибаться, принимая такие объекты, как фара машины, за знак:

Иногда алгоритм находит не все знаки:

False positive:

Заключение

Подводя итог, можно сказать, что был разработан несложный, но вполне рабочий алгоритм, основанный на deep learning для обнаружения дорожных знаков на изображении. В силу того, что обучение происходило на машине с относительно слабой конфигурацией (8 Гб оперативной памяти, GPU: GeForce 730, 2Гб памяти), увеличение вычислительных мощностей и добавление дополнительных данных приведёт к улучшению качества работы как свёрточной нейронной сети, так и SVM.

В статье мы рассмотрели использование CNN, коснулись ReLU, Pooling, Dropout и других понятий, входящих в такую область машинного обучения, как deep learning. Для того, чтобы больше узнать об этом стремительно набирающем в последние несколько лет популярность направлении, в дальнейшем будет сделан цикл статьей по теории и практике глубоких нейронных сетей, благо название блога обязывает!

Ссылки

  1. Статья с описанием метода команды университета Торонто
  2. Regions with CNN features
  3. Network in network
  4. Код на github

Комментарии