1. Введение:
В этом проекте я создал классификатор распознавания дорожных знаков с использованием сверточной нейронной сети и тензорного потока. Кроме того, я точно настроил гиперпараметры, чтобы достичь точности не менее 93% в Наборе данных о дорожных знаках Германии.
- Найдите исходный код со ссылкой на Github: Traffic_Sign_Classifier.ipynb
- Доступна html-версия: Traffic_Sign_Classifier.html
Примечание: размер html-файла составляет 1,9 МБ, поэтому Github не может его отобразить. Загрузите и откройте его с помощью Chrome или IE в вашем регионе.
2. Сводка и исследование набора данных
На этом этапе я изучил и проанализировал набор данных, чтобы лучше манипулировать им в этом проекте. Я сделал четыре шага, чтобы рассчитать сводку дорожного знака в этом наборе данных:
- Основное резюме
Я использую numpy и pandas для вычисления базовой статистической информации, такой как количество обучающих выборок, количество тестовых выборок, форма изображения (т. е. np.shape(image)) и уникальные метки (т. е. np.unique). Результат:
Number of training examples = 34799 Number of testing examples = 12630 Image data shape = (32, 32, 3) Number of classes = 43
Обратите внимание, что фигура изображения имеет 3 измерения: каждое изображение имеет ширину = 32 пикселя, высоту = 32 пикселя и 3 цветовых канала (т. е. красный, зеленый, синий).
- Исследовательская визуализация
Всего в наборе данных 43 различных типа дорожных знаков. Я построил по одному образцу изображения для каждой категории, как показано ниже. Обратите внимание, что заголовок представляет собой «название категории дорожных знаков» в качестве ссылки.
Наблюдение: некоторые изображения повернуты, размыты, искажены или темнее других. Например, изображение «Скользкая дорога» в 6-м ряду от самого правого столбца еще труднее распознать человеку! Эти факторы действительно влияют на точность распознавания в дальнейшем и требуют дополнительной работы для тщательного рассмотрения.
- Распространение
Я начертил распределение изображений для этих образцов дорожных знаков, чтобы показать, сколько изображений для каждой категории. Распределение для обучающей выборки следующее:
X: индекс категории дорожных знаков
Y: количество образцов изображения в этой категории
Я также построил распределение набора проверки следующим образом:
Наблюдение: и обучающая, и проверочная выборки имеют одинаковое распределение образцов дорожных знаков. Это очень важно, потому что мы обучаем модель на тренировочном наборе и применяем ту же модель на проверочном наборе. Мы неявно предполагаем, что оба набора данных взяты из одного и того же распределения и имеют общие черты.
- Подсчитать общее количество изображений в каждой категории
Я подсчитал общее количество образцов изображений для каждой категории. Ниже я показываю небольшую часть резюме.
3. Проектирование и тестирование архитектуры модели
Предварительно обработайте данные изображения
- Оттенки серого. В качестве первого шага я использую прямое вычисление для преобразования изображения RGB с 3 каналами в изображение в градациях серого с одним единственным каналом.
Использование изображения в градациях серого имеет несколько преимуществ:
- небольшое использование памяти: для каждого пикселя RGB имеет 3 канала, и каждому каналу требуется 8-битное хранилище, в то время как оттенки серого используют 8-бит только для одного канала.
- цветовая инвариантность: классификатор дорожных знаков не зависит от цвета, что означает, что ему нужно только обнаруживать края внутри изображения, а информация о цвете не помогает.
- сложность визуализации: оттенками серого легче манипулировать и визуализировать, поскольку они имеют два пространственных измерения и одно измерение яркости. Напротив, RGB имеет два пространственных измерения и три цветовых измерения.
- скорость обработки: изображение в градациях серого содержит меньше данных, что ускоряет его обработку. В частности, это может сэкономить огромное количество времени при обработке видео, если вы представляете видео как длинную последовательность изображений.
2. Масштабирование или нормализация: вторым шагом является масштабирование или нормализация каждого изображения. Этот шаг изменяет диапазон интенсивности пикселей, чтобы все изображения могли иметь одинаковый диапазон значений пикселей.
Здесь мы используем линейное преобразование «(пиксель — 128)/128» для каждого пикселя для простоты на изображениях в градациях серого. Это может быть улучшено для лучших результатов позже.
Причина нормализации следующая:
- растяжение контраста:изображения могут иметь очень разный контраст из-за бликов, изменения интенсивности освещения и т. д. Это делает изображения либо очень яркими, либо слишком темными, что трудно распознать.
- Стабильность модели: искаженные значения пикселей вредны, поскольку наша модель будет умножать веса и добавлять смещения к этим пикселям изображения. Если задействованы чрезвычайно большие или малые значения, обе операции могут усилить асимметрию и вызвать большую ошибку.
- улучшить расчет градиента: модель должна рассчитывать градиенты при обратном распространении. С перекошенными значениями пикселей вычисление градиента может выйти из-под контроля, что является кошмаром…
3. Интенсивность масштабирования. В качестве эксперимента я обнаружил, что простое линейное преобразование можно дополнительно улучшить с помощью метода «exposure.rescale_intensity» из библиотеки skimage. Он равномерно масштабировал интенсивность изображения, чтобы значения пикселей находились в согласованном диапазоне, и достигал лучших результатов.
Вот общий поток нашей предварительной обработки.
Архитектура модели
Я использую аналогичную модель LeNet, представленную в курсе. Он включает в себя два сверточных слоя и три полносвязных слоя. Общая архитектура показана ниже. Фигура обозначает размер вывода этого слоя. Мы используем Relu в качестве функции активации.
Примечание:
(1) после каждого сверточного слоя есть relu и max_pool.
(2) существует только связь между полносвязными слоями.
(3) НЕТ операции после линейного преобразования в последнем выходном слое.
(4) max_pooling каждый раз будет уменьшать размер изображения вдвое, потому что:
- мы используем окна 2x2 (размер ядра = [1, 2, 2, 1])
- перемещаем 2 пикселя в пространственном направление каждый раз (шаги = [1, 2, 2, 1]).
размер ядра = [размер_пакета, высота, ширина, канал]
размер шага = [размер_пакета, высота, ширина, канал]
Обучение модели
Во время обучения этой модели я использую следующие гиперпараметры:
скорость обучения = 0,001
EPOCHS = 50
BATCH_SIZE = 256
- определить функцию потерь: поскольку наша оценка и цель являются массивами, мы можем использовать «soft_max_cross_entropy_with_logits», чтобы измерить их несоответствие. Кроме того, функция потерь определяется как среднее значение элементов в перекрестной энтропии, которая является достойным скалярным представлением всего массива.
- определить оптимизатор: мы используем «оптимизатор Адама», чтобы минимизировать функцию потерь, используя скорость обучения = 0,001. Вместо классического алгоритма стохастического градиентного спуска (SGD) мы используем здесь метод Адама для повышения производительности, поскольку метод Адама итеративно обновляет веса на основе обучающих данных.
- Обучение модели: весь набор данных разделен на несколько пакетов, и каждый пакет содержит 256 изображений. Код фреймворка показан ниже.
(1) В каждую эпоху мы перемешивали все обучающие изображения, чтобы изображения в каждом пакете могли лучше представлять весь набор обучающих данных.
(2) оптимизатор работает над пакеты обучающих изображений для минимизации функции потерь (используйте функцию «training_operation») для обновления весов и смещения в нашей модели.
(3) После того, как оптимизатор будет выполнен для всех данных обучения, мы применяем модель к набору данных проверки и оцениваем производительность нашей модели.
(4) Процесс продолжается до итерации следующей эпохи, пока мы не достигнем ›93% точности проверки.
Подход к поиску решения
Мои окончательные результаты модели были:
Validation Accuracy = 0.95 Test Accuracy = 0.933
Я выбрал известную архитектуру, созданную Яном Лекуном в 1998 году. Эта исходная модель включает в себя два сверточных слоя и полносвязный слой, как показано ниже.
Он отлично справляется с распознаванием изображений, в частности, с рукописными числами (например, распознавание цифр MNIST).
Поскольку наша задача (распознавание дорожных знаков) очень похожа на распознавание рукописного текста, обе пытаются обнаружить шаблоны на изображениях и сопоставить их с размеченными обучающими данными. Я считаю, что подобная модель будет очень хорошо работать в нашем проекте.
Первоначальный результат плохой с архитектурой LeNet:
EPOCH 1 … точность проверки = 0,054
EPOCH 2 … точность проверки = 0,048
EPOCH 3 … точность проверки = 0,048
EPOCH 4 … точность проверки = 0,048
EPOCH 5 … точность проверки = 0,054
Я сделал несколько настроек гиперпараметров для повышения точности. Но самые важные гиперпараметры — это скорость обучения, эпоха и глубина сверточных слоев!
Здесь я показываю некоторые настройки в качестве примера:
- Добавить отсев в полносвязном слое → все еще не очень хорошо
EPOCH 1 ...Validation Accuracy = 0.048 EPOCH 2 ...Validation Accuracy = 0.048 EPOCH 3 ...Validation Accuracy = 0.054 EPOCH 4 ...Validation Accuracy = 0.054 EPOCH 5 ...Validation Accuracy = 0.054
- Уменьшите скорость обучения с 0,1 до 0,001 → большое улучшение!
EPOCH 1 ...Validation Accuracy = 0.433 loss = 1.822 EPOCH 2 ...Validation Accuracy = 0.676 loss = 0.929 EPOCH 3 ...Validation Accuracy = 0.765 loss = 0.690 EPOCH 4 ...Validation Accuracy = 0.792 loss = 0.405 EPOCH 5 ...Validation Accuracy = 0.835 loss = 0.536
- Снижайте скорость обучения с 0,001 до 0,0001 → становится хуже!
EPOCH 1 ...Validation Accuracy = 0.065 loss = 3.528 EPOCH 2 ...Validation Accuracy = 0.097 loss = 3.338 EPOCH 3 ...Validation Accuracy = 0.170 loss = 3.002 EPOCH 4 ...Validation Accuracy = 0.263 loss = 2.683 EPOCH 5 ...Validation Accuracy = 0.329 loss = 2.320
- Увеличьте количество эпох с 5 до 10 → намного лучше!
EPOCH 1 ...Validation Accuracy = 0.362 loss = 2.073 EPOCH 2 ...Validation Accuracy = 0.638 loss = 1.035 EPOCH 3 ...Validation Accuracy = 0.731 loss = 0.705 EPOCH 4 ...Validation Accuracy = 0.794 loss = 0.564 EPOCH 5 ...Validation Accuracy = 0.818 loss = 0.513 EPOCH 6 ...Validation Accuracy = 0.823 loss = 0.267 EPOCH 7 ...Validation Accuracy = 0.839 loss = 0.247 EPOCH 8 ...Validation Accuracy = 0.857 loss = 0.312 EPOCH 9 ...Validation Accuracy = 0.860 loss = 0.326 EPOCH 10 ...Validation Accuracy = 0.868 loss = 0.208
- Исследование перетасовки в каждую эпоху → незначительное влияние на проверку
- Измените значение «сигма» для начальных значений веса → 0,1 лучше!
- Используйте другую функцию активации (например, программный знак) → без больших последствий
- Используйте «rescale_intensity» для повышения контрастности → большое улучшение!
EPOCH 1 ...Validation Accuracy = 0.573 loss = 1.256 EPOCH 2 ...Validation Accuracy = 0.735 loss = 0.732 EPOCH 3 ...Validation Accuracy = 0.798 loss = 0.480 EPOCH 4 ...Validation Accuracy = 0.832 loss = 0.400 EPOCH 5 ...Validation Accuracy = 0.850 loss = 0.360
- … (много других работ по настройке)
- Наконец, увеличьте глубину сверточных слоев → большое улучшение!
Когда я вижу, что точность проверки остается на уровне 0,923, и модель больше не может ее улучшить, я попытался изменить глубину сверточных слоев следующим образом:
сверточный слой 1: глубина изменена с 8 до 16
сверточный слой 2: глубина изменена с 16 до 32
Затем точность проверки можно повысить до 0,948!
Можем ли мы сделать лучше? Я пробовал следующее:
глубина сверточного слоя 1 = 64
глубина сверточного слоя 2=128
Я чувствую, что вычисления стали медленнее, чем раньше, но точность можно повысить до более 96% всего за 20 эпох!
Training... EPOCH 1 ... validation accuracy = 0.855 loss = 0.255 EPOCH 2 ... validation accuracy = 0.896 loss = 0.156 EPOCH 3 ... validation accuracy = 0.922 loss = 0.073 EPOCH 4 ... validation accuracy = 0.916 loss = 0.036 EPOCH 5 ... validation accuracy = 0.928 loss = 0.023 EPOCH 6 ... validation accuracy = 0.919 loss = 0.015 EPOCH 7 ... validation accuracy = 0.924 loss = 0.020 EPOCH 8 ... validation accuracy = 0.926 loss = 0.003 EPOCH 9 ... validation accuracy = 0.930 loss = 0.002 EPOCH 10 ... validation accuracy = 0.930 loss = 0.006 EPOCH 11 ... validation accuracy = 0.939 loss = 0.004 EPOCH 12 ... validation accuracy = 0.931 loss = 0.018 EPOCH 13 ... validation accuracy = 0.942 loss = 0.014 EPOCH 14 ... validation accuracy = 0.926 loss = 0.003 EPOCH 15 ... validation accuracy = 0.938 loss = 0.004 EPOCH 16 ... validation accuracy = 0.938 loss = 0.010 EPOCH 17 ... validation accuracy = 0.958 loss = 0.003 EPOCH 18 ... validation accuracy = 0.959 loss = 0.010 EPOCH 19 ... validation accuracy = 0.959 loss = 0.000 EPOCH 20 ... validation accuracy = 0.961 loss = 0.000 EPOCH 21 ... validation accuracy = 0.960 loss = 0.000 EPOCH 22 ... validation accuracy = 0.960 loss = 0.000 EPOCH 23 ... validation accuracy = 0.960 loss = 0.000 EPOCH 24 ... validation accuracy = 0.961 loss = 0.000
Однако большее значение глубины для сверточных слоев приводит к большему количеству гиперпараметров, и в конечном итоге я сталкиваюсь с проблемой переобучения для новых изображений ниже.
Точность теста составляет всего 80%! Знак стоп распознается неправильно.
Для борьбы с этим я уменьшил гиперпараметры глубины до следующих:
глубина сверточного слоя 1 = 64
глубина сверточного слоя 2 = 32
Таким образом, точность тестирования новых изображений повышается до 100 %!
4. Тестовая модель на новых изображениях
Новые изображения из Интернета
- Я нашел пять изображений дорожных знаков Германии из поиска Google. Я фактически вырезаю их из больших изображений.
- первое изображение — знак «ухабистая дорога». Он имеет жалюзийные изменения на поверхности знака, что может привести к тому, что наша модель сделает неправильное определение.
2. второе изображение — знак «главная дорога». У него есть небо и облака в качестве фона. Это может быть трудно классифицировать, потому что часть знака белая и очень близка к фону. Таким образом, знак может легко смешать знак с облаком сзади вместе.
3. третье изображение – знак «автомобилям запрещено». В правом нижнем углу есть человек в красной куртке. Это очень близко к внешнему красному кругу знака. Это может привести к ошибке для нашего классификатора.
4. четвертое изображение – это знак «поверните направо». Этот образ не обращен к нам прямо. Он был наклонен в правую сторону. Это может вызвать проблемы для нашего классификатора, когда обучающие данные являются идеально прямыми.
5. пятое изображение – знак «стоп». У него более темный фон, а края знака перемешаны с фоном силовой башни. Это может вызвать трудности с правильной классификацией знака остановки.
Результат проверки на новых изображениях
В моем тестировании все новые изображения могут быть правильно классифицированы с нашей моделью. На следующих изображениях показан результат прогнозирования нашей модели по сравнению с истинная метка от данного.
Кроме того, мы показываем пять лучших прогнозов для каждого изображения следующим образом.
- Каждая группа — это прогнозы для каждого изображения (ярлык выделен жирным шрифтом);
- В каждой строке показана предполагаемая вероятность каждой категории из модели.
- Категория с самой высокой вероятностью является результатом прогноза.
Например, для изображения «Ухабистая дорога» наша модель предсказала, что это изображение относится к категории «Ухабистая дорога» с вероятностью 99,8%. Поэтому модель считает этот образ знаком «Ухабистая дорога».
------------------------------------------------------------ True Label is: = 22:Bumpy road 22: Bumpy road 99.812% 29: Bicycles crossing 0.101% 24: Road narrows on the right 0.087% 31: Wild animals crossing 0.000% 26: Traffic signals 0.000% ------------------------------------------------------------ ------------------------------------------------------------ True Label is: = 12:Priority road 12: Priority road 100.000% 40: Roundabout mandatory 0.000% 26: Traffic signals 0.000% 38: Keep right 0.000% 42: End of no passing by vehicles over 3.5 metric tons 0.000% ------------------------------------------------------------ ------------------------------------------------------------ True Label is: = 15:No vehicles 15: No vehicles 99.993% 2: Speed limit (50km/h) 0.005% 3: Speed limit (60km/h) 0.002% 5: Speed limit (80km/h) 0.000% 1: Speed limit (30km/h) 0.000% ------------------------------------------------------------ ------------------------------------------------------------ True Label is: = 33:Turn right ahead 33: Turn right ahead 100.000% 3: Speed limit (60km/h) 0.000% 35: Ahead only 0.000% 39: Keep left 0.000% 1: Speed limit (30km/h) 0.000% ------------------------------------------------------------ ------------------------------------------------------------ True Label is: = 14:Stop 14: Stop 100.000% 17: No entry 0.000% 38: Keep right 0.000% 34: Turn left ahead 0.000% 32: End of all speed and passing limits 0.000% ------------------------------------------------------------
5. Резюме и заключение
В этом проекте мы создали классификатор дорожных знаков с использованием сверточной нейронной сети и тензорного потока. Это отличный и вдохновляющий проект для практики этих методов, и действительно, он помогает мне лучше понять концепцию нейронной сети, слоев, relu, max_pooling и т. д.
В процессе обучения я обнаружил, что несколько параметров очень важны для точности, таких как скорость обучения, количество эпох, перетасовка в каждой эпохе, сигма инициализации веса и выбор глубины слоя.
Наоборот, некоторые другие параметры или операции не помогают, например операция отсева и методы заполнения «ДЕЙСТВИТЕЛЬНО»/«ТАК ЖЕ». Может быть, я смогу попробовать их в будущем проекте и увидеть их влияние.
В целом, это отличный опыт обучения. Я узнал так много знаний за последние несколько недель. Спасибо за организацию занятий и подготовку материала!
Счастливого дня благодарения! :-)✌️
Оригинал: 26 ноября 2017 г., 15:03
Обновлено: 4 декабря 2017 г., 22:32.