Глубокое обучение

Распознавание дорожных знаков с использованием сверточных нейронных сетей (CNN)

Немецкий проект классификации дорожных знаков инженера по беспилотным автомобилям Nano Degree Term 1, демонстрирующий использование CNN в задачах классификации

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

Подробные инструкции вместе с кодом проекта можно найти в моем репозитории GitHub, указанном ниже.



Краткое описание проекта

Цели проекта приведены ниже:

  1. Загрузка набора данных, т. е. набора данных о дорожных знаках Германии.
  2. Изучение, обобщение и визуализация набора данных.
  3. Разработка и обучение архитектуры модели.
  4. Оценка производительности модели на тестовом наборе данных.
  5. Использование обученной модели для предсказания новых изображений.

Введение

Глубокие нейронные сети (DNN) обладают большими возможностями для распознавания образов изображений и широко используются в алгоритмах Computer Vision. Кроме того, Сверточная нейронная сеть (CNN или ConvNet) — это класс DNN (глубоких нейронных сетей), который чаще всего применяется для анализа визуальных образов. Классификация и обнаружение дорожных знаков являются одной из основных задач в автономном вождении, поскольку они дают информацию о том, какой знак находится на изображении, для принятия решений.

Распознавание дорожных знаков (TSR) – это технология, с помощью которой транспортное средство может распознавать дорожные знаки, установленные на дороге, например, дорожные знаки. "ограничение скорости" или "дети" или "повернуть вперед". Это часть функций под общим названием ADAS. Технология разрабатывается различными автомобильными поставщиками. Он использует методы обработки изображений для обнаружения дорожных знаков. Методы обнаружения в целом можно разделить на методы на основе цвета, формы и обучения.

Используемый набор данных

Используемый набор данных — это Набор данных о дорожных знаках Германии, который содержит изображения формы (32x32x3), то есть изображения RGB. Я использовал библиотеку Numpy для расчета сводной статистики набора данных дорожных знаков, приведенного ниже:

  • Размер обучающей выборки: 34799.
  • Размер проверочного набора: 4410.
  • Размер тестового набора: 12630.
  • Форма изображения дорожного знака: (32, 32, 3).
  • Количество уникальных классов/ярлыков в наборе данных: 43.

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



Исследовательская визуализация набора данных

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

Архитектура модели

В качестве первого шага я решил перетасовать свои X_train, y_train. Затем я использовал нормализацию как один из методов предварительной обработки. В котором набор данных (X_train, X_test, X_valid) передается в функцию нормализации (x_label), которая преобразует все данные и возвращает нормализованные. Код Python, выполняющий этот шаг, приведен ниже:

import tensorflow as tf
from sklearn.utils import shuffle
X_train, y_train = shuffle(X_train, y_train)
EPOCHS = 20
BATCH_SIZE = 128
def normalization(x_label):
    return x_label / 255 * 0.8 + 0.1
X_train =  normalization(X_train)
X_test =  normalization(X_test)
X_valid = normalization(X_valid)

Для обучения модели я использовал: EPOCHS = 20, BATCH_SIZE = 128, rate = 0,001, mu = 0, sigma = 0,1. Я использовал ту же архитектуру модели LeNet, что и состоит из двух сверточных слоев и трех полносвязных слоев. Входные данные — это изображение размером (32x32x3), а выходные данные — 43, т. е. общее количество различных классов. В середине я использовал функцию активации RELU после каждого сверточного слоя, а также первых двух полносвязных слоев.

Flatten используется для преобразования вывода 2-го сверточного слоя после объединения, т.е. 5x5x16 в 400. Объединение также выполняется между 1-м и 2-м сверточными слоями. Моя окончательная модель состояла из следующих слоев:

Модель LeNet, разработанная и представленная LeCun et al. в 1998 году в основном использовался для оптического распознавания символов, набора данных MNIST и т. д. Более подробную информацию о модели LeNet можно найти ниже:



Ниже приведен снимок фактического кода, описывающего архитектуру моей модели.

def LeNet(x):    
    mu = 0
    sigma = 0.1
    
    # Layer 1: Convolutional. Input = 32x32x3. Output = 28x28x6.
    weights_layer_1 = tf.Variable(tf.truncated_normal(shape=(5,5,3,6), mean = mu, stddev = sigma))
    bias_layer_1 = tf.Variable(tf.zeros(6))
    output_layer_1 = tf.nn.conv2d(x, weights_layer_1, strides=[1, 1, 1, 1], padding='VALID')
    output_layer_1 = tf.nn.bias_add(output_layer_1, bias_layer_1)
    # Activation.
    output_layer_1 = tf.nn.relu(output_layer_1)
    # Pooling. Input = 28x28x6. Output = 14x14x6.
    output_layer_1 = tf.nn.max_pool(output_layer_1, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = 'VALID')
    
    # Layer 2: Convolutional. Output = 10x10x16.
    weights_layer_2 = tf.Variable(tf.truncated_normal(shape=(5,5,6,16), mean = mu, stddev = sigma))
    bias_layer_2 = tf.Variable(tf.zeros(16))
    output_layer_2 = tf.nn.conv2d(output_layer_1, weights_layer_2, strides=[1, 1, 1, 1], padding='VALID')
    output_layer_2 = tf.nn.bias_add(output_layer_2, bias_layer_2)
    # Activation.
    output_layer_2 = tf.nn.relu(output_layer_2)
    # Pooling. Input = 10x10x16. Output = 5x5x16.
    output_layer_2 = tf.nn.max_pool(output_layer_2, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = 'VALID')
# Flatten. Input = 5x5x16. Output =400.
    output_layer_2 = flatten(output_layer_2)
    
    # Layer 3: Fully Connected. Input = 400. Output = 120.
    weights_fully_3 = tf.Variable(tf.truncated_normal(shape=(400, 120), mean = mu, stddev = sigma))
    bias_fully_3 = tf.Variable(tf.zeros(120))
    output_layer_3 =  tf.add(tf.matmul(output_layer_2, weights_fully_3), bias_fully_3)
    # Activation.
    output_layer_3 = tf.nn.relu(output_layer_3)
    
    # Layer 4: Fully Connected. Input = 120. Output = 84.
    weights_fully_4 = tf.Variable(tf.truncated_normal(shape=(120, 84), mean = mu, stddev = sigma))
    bias_fully_4 = tf.Variable(tf.zeros(84))
    output_layer_4 =  tf.add(tf.matmul(output_layer_3, weights_fully_4), bias_fully_4)
    # Activation.
    output_layer_4 = tf.nn.relu(output_layer_4)
    
    # Layer 5: Fully Connected. Input = 84. Output = 43.
    weights_fully_5 = tf.Variable(tf.truncated_normal(shape=(84, 43), mean = mu, stddev = sigma))
    bias_fully_5 = tf.Variable(tf.zeros(43))
    logits =  tf.add(tf.matmul(output_layer_4, weights_fully_5), bias_fully_5)
    
    return logits

Обучение, проверка и тестирование модели

Обучение — это этап машинного обучения, когда модель постепенно оптимизируется, или модель изучает набор данных. Цель состоит в том, чтобы узнать достаточно о структуре обучающего набора данных, чтобы делать прогнозы относительно невидимых данных.

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

x = tf.placeholder(tf.float32, (None, 32, 32, 3))
y = tf.placeholder(tf.int32, (None))
one_hot_y = tf.one_hot(y, 43)
rate = 0.001
logits = LeNet(x)
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=one_hot_y, logits=logits)
loss_operation = tf.reduce_mean(cross_entropy)
optimizer = tf.train.AdamOptimizer(learning_rate = rate)
training_operation = optimizer.minimize(loss_operation)

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

correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(one_hot_y, 1))
accuracy_operation = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
saver = tf.train.Saver()
def evaluate(X_data, y_data):
    num_examples = len(X_data)
    total_accuracy = 0
    sess = tf.get_default_session()
    for offset in range(0, num_examples, BATCH_SIZE):
        batch_x, batch_y = X_data[offset:offset+BATCH_SIZE], y_data[offset:offset+BATCH_SIZE]
        accuracy = sess.run(accuracy_operation, feed_dict={x: batch_x, y: batch_y})
        total_accuracy += (accuracy * len(batch_x))
    return total_accuracy / num_examples

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

Приведенный ниже код является типичным способом запуска процесса обучения и проверки в Tensorflow. Точность проверки после 20 эпох составляет 0,975.

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    num_examples = len(X_train)
    
    print("Training...")
    print()
    for i in range(EPOCHS):
        X_train, y_train = shuffle(X_train, y_train)
        for offset in range(0, num_examples, BATCH_SIZE):
            end = offset + BATCH_SIZE
            batch_x, batch_y = X_train[offset:end], y_train[offset:end]
            sess.run(training_operation, feed_dict={x: batch_x, y: batch_y})
            
        validation_accuracy = evaluate(X_valid, y_valid)
        print("EPOCH {} ...".format(i+1))
        print("Validation Accuracy = {:.3f}".format(validation_accuracy))
        print()
        
    saver.save(sess, './lenet')
    print("Model saved")

Тестирование модели на новых изображениях

Ниже приведены восемь немецких дорожных знаков, которые я использовал для тестирования на новых изображениях, отличных от тестового набора. Далее работоспособность модели проверяется на свежих данных из интернета. Каждое изображение имеет разное разрешение и размер. В целях тестирования каждое изображение изменено на 32x32. Немецкие дорожные знаки после изменения их размера до 32x32:

Модель смогла правильно угадать 5 из 8 дорожных знаков. Точность теста на новых загруженных изображениях = 0,625.

Результаты

Моя окончательная модель имела точность набора проверки 0,975.

Я использовал нормализованные изображения для обучения модели и количество EPOCHS=20 и BATCH_SIZE=128. С использованием определенных гиперпараметров точность набора проверки составляет 0,975, что больше, чем мой предыдущий тест 0,93. Кроме того, модель имеет точность 0,625 на восьми изображениях немецких дорожных знаков, загруженных из Интернета.

использованная литература

  1. Классификация пород собак с использованием колбы


Классификация пород собак с использованием Flask
Веб-приложение «Классификатор пород собак
, демонстрирующее использование трансферного обучения с ResNet-50sawhney-prateek97.medium.com»



Это все, что касается распознавания дорожных знаков с помощью CNN. Спасибо, что прочитали и последовали за нами. Надеюсь, вы хорошо провели время, читая и изучая. Большое спасибо за прочтение!

Мое Портфолио и Linkedin :)