Обзор

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

Создать проект распознавания дорожных знаков

Цели/этапы этого проекта следующие:

  • Загрузите набор данных
  • Исследуйте, обобщайте и визуализируйте набор данных
  • Проектировать, обучать и тестировать архитектуру модели
  • Используйте модель, чтобы делать прогнозы для новых изображений
  • Проанализируйте вероятности softmax новых изображений
  • Подведите итоги в письменном отчете

Сводка и исследование набора данных

Маринованные данные представляют собой словарь с 4 парами ключ/значение:

  • 'features' – это четырехмерный массив, содержащий необработанные пиксельные данные изображений дорожных знаков (количество примеров, ширина, высота, каналы).
     – 'labels' – это 1D-массив, содержащий идентификатор метки/класса дорожного знака. . Файл `signnames.csv` содержит сопоставления id -> name для каждого идентификатора.
    - 'sizes' - это список, содержащий кортежи (ширина, высота), представляющие исходную ширину и высоту изображения.
    - 'coords' - это список, содержащий кортежи (x1, y1, x2, y2), представляющие координаты ограничивающей рамки вокруг знака на изображении. (ЭТИ КООРДИНАТЫ ПРЕДПОЛАГАЮТСЯ ИСХОДНОМУ ИЗОБРАЖЕНИЮ. ИЗМЕНЕННЫЕ ДАННЫЕ СОДЕРЖАТ ИЗМЕНЕННЫЕ РАЗМЕРЫ (32 на 32) ЭТИХ ИЗОБРАЖЕНИЙ)

Я использовал библиотеку pandas для расчета сводной статистики набора данных дорожных знаков:

Гистограмма изображений набора данных дорожных знаков (данные обучения, данные испытаний и данные проверки) показана ниже. Это указывает на то, что набор данных содержит 43 уникальных класса сигналов дорожных знаков.

Предварительная обработка данных

  1. Перемешивание: начальный этап предварительной обработки данных — перемешивание данных. Очень важно перетасовать обучающие данные, иначе порядок данных может оказать огромное влияние на тенденции сети (обучение нейронной сети).
  2. Нормализация. Данные изображения должны быть нормализованы, чтобы данные имели нулевое среднее значение и равную дисперсию. Для данных изображения `(пиксель — pixel_mean)/(max_pixel-min_pixel)` используется для нормализации данных. После нормализации значения пикселей будут в диапазоне от -1 до +1.
    Другой метод, который можно использовать для нормализации данных, это (пиксель — 128)/128.

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

Архитектура LeNet используется для построения модели классификатора дорожных знаков. Он включает в себя три сверточных слоя и два полносвязных слоя.

Размерность. Количество нейронов каждого слоя в нашей CNN можно рассчитать по приведенной ниже формуле:

output_height = [(input_height - filter_height + 2 * padding) / vertical_stride] + 1
output_width = [(input_width - filter_width + 2 * padding) / vertical_stride] + 1
output_depth = number of filters

Архитектура LeNet:

Layer 1: Convolutional Layer. 
Input = 32x32x3. Output = 28x28x6.
5X5 filter is used with an input depth of 3 and output depth of 6. 
output_height = [(32–5+2*0)/1]+1 = 28.
 output_width = [(32–5+2*0)/1]+1 = 28.
 output_depth = filter_depth = 6
Activation: ReLU activation function is used to activate the output of Convolutional Layer.

Pooling: Input = 28x28x6. Output = 14x14x6.
Pool the output using 2x2 kernel with a 2x2 stride.
output_height = 28/2 = 14.
output_width = 28/2 = 14.
output_depth = 6
Layer 2: Convolutional Layer.
Input = 14x14x6. Output = 10x10x16.
output_height = [(14-5+2*0)/1]+1 = 10.
output_width = [(14-5+2*0)/1]+1 = 10.
output_depth = filter_depth = 16
Activation: ReLU activation function is used to activate the output of Convolutional Layer.

Pooling: Input = 10x10x16. Output = 5x5x16.
Pool the output using 2x2 kernel with a 2x2 stride 
output_height = 10/2 = 5.
output_width = 10/2 = 5.
output_depth = 16
Flatten: Flatten the output shape of the final pooling layer such that it's 1D instead of 3D. 
Input = 5x5x16. Output=5x5x16=400.

Layer 3: Fully Connected. Input = 400. Output = 120.

Activation: ReLU activation function is used to activate the output of Fully Connected Layer.

Layer 4: Fully Connected. Input = 120. Output = 84.

Activation: ReLU activation function is used to activate the output of Fully Connected Layer.

Layer 5: Fully Connected. Input = 84. Output = 43.
Set the output with a width equal to number of classes in our label set. These outputs are called as logits.

Output: Return the result of the 3rd fully connected layer.

Обучение моделей

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

  • Переменная EPOCH используется, чтобы сообщить TensorFlow, сколько раз нужно запускать наши обучающие данные через сеть. Большее количество EPOCHS приводит к лучшему обучению модели, но для обучения сети требуется больше времени.
  • Переменная BATCH_SIZE используется, чтобы сообщить TensorFlow, сколько обучающих изображений нужно запускать по сети одновременно. Если BATCH_SIZE больше, модель обучается быстрее, но у нашего процессора может быть ограничение памяти на то, насколько большой пакет он может запустить. Значения EPOCH и BATCH SIZE влияют на скорость обучения и точность модели.
  • Скорость обучения сообщает TensorFlow, как быстро обновлять веса сети.

Выбрано: EPOCH = 50, BATCH_SIZE = 128, Learning_rate = 0,001.

Канал обучения:

  1. Передайте входные данные функции LeNet для вычисления наших логитов.
  2. Функция «tf.nn.softmax_cross_entropy_with_logits» используется для сравнения логитов с наземными метками обучения правды и вычисления перекрестной энтропии. Перекрестная энтропия — это всего лишь мера того, насколько логиты отличаются от наземных меток обучения правде.
  3. Функция tf.reduce_mean усредняет перекрестную энтропию по всем обучающим изображениям.
  4. Adam Optimizer использует алгоритм Адама для минимизации функции потерь с использованием скорости обучения.
  5. Запустите функцию минимизации в оптимизаторе, который использует обратное распространение для обновления сети и минимизации наших потерь при обучении.
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 = learning_rate)
training_operation = optimizer.minimize(loss_operation)                  

Оценка модели

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

# Measure whether given prediction is correct by comparing logit prediction to the one-hot encoded ground truth label.
correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(one_hot_y, 1))
# Calculte the model's overall accuracy by averaging the individual prediction accuracies.
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
    total_loss = 0
    sess = tf.get_default_session()
    # Break the training data into batches and train the model on each batch.
    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] # batch the dataset
        loss, accuracy = sess.run([loss_operation, accuracy_operation], feed_dict={x: batch_x, y: batch_y}) # run through evaluation pipeline
        total_accuracy += (accuracy * len(batch_x)) # Calculate the avarage accuracy of each batch to calculate the total accuracy of the model
        total_loss += (loss * len(batch_x))
    return total_accuracy/num_examples
  1. Пропустите обучающие данные через обучающий конвейер, чтобы обучить модель.
  2. Перед каждой эпохой тренировочный набор перемешивается, чтобы убедиться, что наше обучение не смещено из-за порядка изображений.
  3. Разбейте обучающие данные на пакеты и обучите модель на каждом пакете.
  4. В конце каждой эпохи мы оцениваем модель на наших проверочных данных.
  5. Как только мы полностью обучили модель, сохраните ее. Мы можем загрузить его позже, изменить или оценить нашу модель на тестовом наборе данных.
# Create TensorFlow session and initialize variables
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    num_examples = len(X_train)
    
    print("Training...")
    print()
    # Train over 'N' number of epochs
    for i in range(EPOCHS):
        # Before each epoch shuffle the training set.
        X_train, y_train = shuffle(X_train, y_train)
        # Break the training data into batches and train the model on each batch.
        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})
        
        # At the end of each epoch, we evaluate the model on our validation data
        validation_accuracy = evaluate(X_valid, y_valid)
        print("EPOCH {} ...".format(i+1))
        print("Validation Accuracy = {:.3f}".format(validation_accuracy))
        print()
    
    # Save the model after the completion of training.
    saver.save(sess, './lenet')
    print("Model saved")

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

Training...

EPOCH 1 ...
Validation Accuracy = 0.701

EPOCH 2 ...
Validation Accuracy = 0.814

EPOCH 3 ...
Validation Accuracy = 0.850

EPOCH 4 ...
Validation Accuracy = 0.874

EPOCH 5 ...
Validation Accuracy = 0.888

EPOCH 6 ...
Validation Accuracy = 0.896

......


EPOCH 48 ...
Validation Accuracy = 0.922

EPOCH 49 ...
Validation Accuracy = 0.934

EPOCH 50 ...
Validation Accuracy = 0.937

Model saved

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

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

Точность теста = 0,925 получается, когда модель тестируется в тестовом наборе данных.

Протестируйте модель на новых изображениях

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

Вот результаты прогноза:

11 -- Right-of-way at the next intersection
12 -- Priority road
1 -- Speed limit (30km/h)
25 -- Road work
38 -- Keep right

Модель смогла правильно угадать 5 из 5 дорожных знаков, что дает точность 100%.

True Label is -->    11:Right-of-way at the next intersection

   11: Right-of-way at the next intersection 100.000%
   30: Beware of ice/snow             0.000%
   21: Double curve                   0.000%
    7: Speed limit (100km/h)          0.000%
   31: Wild animals crossing          0.000%
##############################################
##############################################
True Label is -->    12:Priority road                 

   12: Priority road                  100.000%
   10: No passing for vehicles over 3.5 metric tons 0.000%
   42: End of no passing by vehicles over 3.5 metric tons 0.000%
    5: Speed limit (80km/h)           0.000%
   11: Right-of-way at the next intersection 0.000%
##############################################
##############################################
True Label is -->     1:Speed limit (30km/h)          

    2: Speed limit (50km/h)           100.000%
    1: Speed limit (30km/h)           0.000%
    3: Speed limit (60km/h)           0.000%
    0: Speed limit (20km/h)           0.000%
    4: Speed limit (70km/h)           0.000%
##############################################
##############################################
True Label is -->    25:Road work                     

   25: Road work                      100.000%
   20: Dangerous curve to the right   0.000%
   24: Road narrows on the right      0.000%
   11: Right-of-way at the next intersection 0.000%
    3: Speed limit (60km/h)           0.000%
##############################################
##############################################
True Label is -->    38:Keep right                    

   38: Keep right                     100.000%
   34: Turn left ahead                0.000%
   36: Go straight or right           0.000%
   32: End of all speed and passing limits 0.000%
   20: Dangerous curve to the right   0.000%