Этот проект включает в себя обучение глубокой нейронной сети распознаванию дорожных знаков, что означает создание аппроксиматора функций, который может сопоставлять пиксели изображений дорожных знаков с их именами. Подход глубокого обучения оказался действительно эффективным, обеспечив точность теста 96%. Эта статья представляет собой документацию о том, как я построил конвейер, а также подробности окончательной архитектуры. Пожалуйста, щелкните здесь, чтобы перейти к репозиторию github.

Мотивация

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

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

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

- http://benchmark.ini.rub.de/

Сводка набора данных

Набор данных GTSRB был интересным, особенно из-за несбалансированности количества примеров для каждого класса. Резюме данных, которые я использовал для этого проекта:

Number of training examples = 34799
Number of testing examples = 12630
Number of validation examples = 4410
Image data shape = (32, 32, 3)
Number of classes = 43

Наблюдения:
1. Распределение данных обучения, тестирования и валидации практически идентично. Это хорошо.
2. Распределение неравномерное, как хотелось бы в идеале. В некоторых классах примеров гораздо больше, чем в других.

Исследовательский анализ

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

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

Выравнивание ванильной гистограммы

Эта техника как раз то, что нам нужно. Нам нужно распределить частоту пикселей примерно на все значения интенсивности в нашем изображении. Но есть проблема! Наши изображения находятся в цветовом пространстве RGB, которое не имеет понятия «интенсивность». Решение состоит в том, чтобы преобразовать изображение из цветового пространства RGB в цветовое пространство, которое имеет понятие интенсивности. Это может быть HSL, HSV, YUV и т. Д. Я выбираю YCbCr без особой причины. После преобразования изображений в цветовое пространство YCbCr мы выполняем выравнивание гистограммы на плоскости «Y». В цветовом пространстве YCrCb «Y» означает яркость, которая является метрикой интенсивности, а Cr и Cb означают разность красного и синего компонентов цветности соответственно. Из Википедии -

Выравнивание гистограммы обычно увеличивает общий контраст многих изображений, особенно когда используемые данные изображения представлены близкими значениями контраста. Благодаря этой настройке можно лучше распределить интенсивности на гистограмме. Это позволяет областям с более низким локальным контрастом получить более высокий контраст. При выравнивании гистограммы это достигается за счет эффективного распределения наиболее частых значений интенсивности.

Давайте применим выравнивание гистограммы к 16 случайным изображениям 5 случайных классов и распечатаем их. Мы предпринимаем следующие шаги:

  1. Преобразование цветового пространства RGB в YCrCb. Я попытался применить эквализацию напрямую, сглаживая каналы RGB, но получил плохие результаты. Это потому, что RGB не является «моделью интенсивности». Кроме того, разделение каналов и выравнивание каждого канала не работает, поскольку выравнивание гистограммы - это нелинейный процесс, предназначенный для работы со значениями интенсивности.
  2. Выровняйте канал «Y» и оставьте каналы «Cr» и «Cb» нетронутыми.
  3. Объедините каналы.
  4. Преобразуйте изображение из YcrCb в RGB и верните его.

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

Из документов Википедии и OpenCV,

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

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

Это намного лучше, а артефакты гораздо менее серьезны, что также следует отнести к операции билинейной интерполяции, примененной к постобработке. Обратите внимание, что вы можете настроить параметры clipLimit и tileSize для получения разных результатов. Я получил наилучшие результаты с clipLimit = 2 и tileSize = 4x4.

Цвет против отсутствия цвета
Я пробовал обучать модель как с цветом, так и без цвета. Удивительно, но без цвета у меня получилась лучшая точность проверки. Когда я говорю «с цветом», изображения, передаваемые в нейронную сеть, были в цветовом пространстве RGB. Когда я говорю «без цвета», изображения, передаваемые в нейронную сеть, были в режиме градаций серого. Обратите внимание, что канал Y YUV или YCrCb эквивалентен режиму шкалы серого, поэтому я использовал именно его.

Один конвейер предварительной обработки:

Затем я применяю этот конвейер для всех наборов данных для обучения, проверки и тестирования.

Увеличение данных

Мы обнаружили, что данные распределяются очень неравномерно, поэтому есть два способа решить эту проблему:
1. Сбалансировать набор данных по среднему значению.
2. Выполнить увеличение для всего набора данных.

Поскольку больше данных никогда не повредит, я решил выполнить аугментацию всего набора данных. Я выполняю 5 аугментаций, описанных ниже:

  1. Размытие по Гауссу со случайным выбором сигмы от 0,25 до 1
  2. Масштабирование по осям X и Y. Масштабный коэффициент, выбранный случайным образом от 1,3 до 1,5.
  3. Вращение, произвольное от -20 градусов до -5 градусов
  4. Вращение, произвольное от -5 градусов до -20 градусов
  5. Срезание в 15 раз

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

Теперь у нас есть 208795 обучающих примеров, что в 5 раз превышает исходный набор данных!

Архитектурный дизайн

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

Единая объективная метрика:
Я использовал данное предложение Udacity для единственной цели метрики, точность более 93% на проверочном наборе. Позже я расскажу, почему это была плохая идея.

Моя последняя модель состоит из 2 сверточных слоев с максимальным объединением и трех полностью связанных скрытых слоев. Я начал с ванильного LeNet просто из-за его простоты, но применил итеративный подход и закончил со следующей конфигурацией.

Параметры, с которыми я в основном играл, были:

  1. Cliplimit и tileize для ограничения контраста с адаптивным выравниванием гистограммы, я пробовал широкий диапазон значений и нашел лучшие результаты, когда установил cliplimit и размер плитки на 2 и 4x4 соответственно.
  2. Типы увеличения изображения. Я добился успеха с размытием по Гауссу, масштабированием и тремя разными поворотами. Вместо того, чтобы жестко кодировать значения для них, я определил диапазон, чтобы добавить разнообразия. Например, я выбрал сигму от 0,25 до 1 для размытия по Гауссу.
  3. Количество эпох, хотя я заметил, что хорошая модель покажет многообещающие результаты точности проверки в первые 10 эпох.
  4. Вероятность отсева. Я нашел успех в 0,6 и даже 0,7 за 0,5. Причина может заключаться в том, что максимальное объединение после свертки приводит к потере информации, что приводит к недостаточному соответствию.

Гиперпараметры

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

Оптимизатор Адама

Я использовал метод оптимизации Адама вместо простого градиентного спуска, «импульс» в оптимизаторе Адама обеспечивает гораздо более быструю сходимость. Это также означает, что мне не нужно активно настраивать скорость обучения.

Представление

Я обучил свою модель на экземпляре AWS g2.2xlarge ec2. На это ушло минут пять.

EPOCH 1 ...
Validation Accuracy = 0.893

EPOCH 2 ...
Validation Accuracy = 0.938

EPOCH 3 ...
Validation Accuracy = 0.947

EPOCH 4 ...
Validation Accuracy = 0.953

EPOCH 5 ...
Validation Accuracy = 0.955
...
...
EPOCH 36 ...
Validation Accuracy = 0.982

EPOCH 37 ...
Validation Accuracy = 0.977

EPOCH 38 ...
Validation Accuracy = 0.979

EPOCH 39 ...
Validation Accuracy = 0.979

EPOCH 40 ...
Validation Accuracy = 0.978

Model saved

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

Тестирование модели

Этот код был запущен только один раз после разработки модели для определения точности теста.

with tf.Session() as sess:
    saver.restore(sess, tf.train.latest_checkpoint('.'))
    test_accuracy = evaluate(X_test_normalized, y_test)
    print("Test Accuracy = {:.3f}".format(test_accuracy))
Test Accuracy = 0.960

Вот и все! Точность теста 96,0%, намного лучше, чем я ожидал. Это означает, что модель не была слишком переоборудована и не слишком переоборудована.

Тестирование модели на случайных картинках из сети

Я погуглил "немецкие дорожные знаки" и скачал пять знаков. Я использовал OpenCV для изменения размера каждого изображения до 32x32x3.

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

Затем я вывожу вероятности softmax для каждого изображения.

Best 5 guesses:
No entry : 99.999%
Turn left ahead : 0.001%
Stop : 0.001%
Keep right : 0.000%
Keep left : 0.000%

Best 5 guesses:
Road narrows on the right : 52.745%
Children crossing : 42.357%
Beware of ice/snow : 2.129%
Bicycles crossing : 0.748%
Pedestrians : 0.718%

Best 5 guesses:
Priority road : 99.999%
Yield : 0.001%
No passing : 0.000%
No vehicles : 0.000%
Speed limit (60km/h) : 0.000%

Best 5 guesses:
Yield : 100.000%
Priority road : 0.000%
Keep left : 0.000%
Ahead only : 0.000%
Keep right : 0.000%

Best 5 guesses:
Slippery road : 99.998%
Wild animals crossing : 0.002%
Double curve : 0.000%
Beware of ice/snow : 0.000%
Right-of-way at the next intersection : 0.000%

Отражение:

  1. Если мы посчитаем точность теста для новых 5 изображений из Интернета, она составит всего 80%. Сравните это с точностью 96%, которую мы получили на тестовом наборе данных. Что здесь происходит?
  2. Точность не является хорошей метрикой для несбалансированных наборов данных, поскольку очень вероятно, что производительность прогнозирования меньших классов будет затенена производительностью любого большего класса. Можно использовать, например, расхождение Кульбака-Лейблера, чтобы измерить, как распределение данных сравнивается с равномерным распределением вероятностей, и решить, является ли точность правильной метрикой.
  3. Изображение «Пересечение детей», которое мы тестировали с помощью нашего классификатора, было недостаточно представлено в обучающих данных (как мы можем видеть на столбчатой ​​диаграмме). Установление исходного уровня с другой метрикой оценки, такой как балл F-1, было бы лучшим выбором. Тогда мы будем оптимизировать что-то, что дало бы лучшую точность и запоминаемость.

Заключение

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

  1. Настройка гиперпараметров. Я не особо экспериментировал с широким диапазоном значений большинства гиперпараметров. Обладая достаточной вычислительной мощностью, я хотел бы воспользоваться подходом Caviar и параллельно обучать множество моделей вместо того, чтобы надолго присматривать за одной моделью.
  2. Различные сетевые архитектуры. Я ограничился крошечными случайными вариациями LeNet.
  3. Полностью удалите объединяющие слои и вместо этого используйте выпадение с keep_prob = ~0.9 в сверточных слоях для другого эффекта регуляризации.
  4. Добавьте пакетную нормализацию.
  5. Выровняйте распределение обучающих данных с помощью еще более тщательного увеличения. Это оправдало бы использование нами точности как единственной объективной метрики.

Ссылка на репозиторий github:
https://github.com/sashankaryal/Traffic-signs-classifier