Введение

Компьютер - потрясающая машина (без сомнения), и я действительно очарован тем фактом, что компьютеры могут изучать и классифицировать изображения. Классификация изображений имеет свои преимущества и применяется по-разному, например, мы можем купить дозатор корма для домашних животных в зависимости от того, какой вид (кошка или собака) к нему приближается. Я знаю, что это странная идея, что они в конечном итоге съедят всю пищу, но система может управляться по времени и может быть выдана только один раз. В любом случае, давайте двигаться дальше, прежде чем отвлекаться, и продолжим обсуждение. Итак, после того, как я получил новые знания о нейронных сетях с глубоким обучением, я подумал о том, чтобы создать такую ​​сам. Итак, здесь я собираюсь рассказать о создании сверточной нейронной сети Alexnet для 6 различных классов, созданных с нуля с использованием Keras и закодированных на Python.

Обзор AlexNet

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

AlexNet [1] - это классический тип сверточной нейронной сети, появившийся после конкурса ImageNet в 2012 году. Сетевая архитектура представлена ​​ниже:

Объяснение модели: Входные данные для этой модели имеют размеры 227x227x3, за которыми следует сверточный слой с 96 фильтрами размером 11x11, с одинаковым заполнением и шагом 4. Результирующие выходные размеры представлены как :

floor (((n + 2 * padding - filter) / stride) + 1) * floor (((n + 2 * padding - filter) / stride) + 1)

Примечание. Эта формула предназначена для ввода квадрата с высотой = ширина = n.

Объясняя первый слой с входом 227x227x3 и сверточный слой с 96 фильтрами 11x11, «допустимое» заполнение и шаг = 4, выходная яркость будет

= этаж (((227 + 0–11) / 4) + 1) * этаж (((227 + 0–11) / 4) + 1)

= этаж ((216/4) + 1) * этаж ((216/4) + 1)

= этаж (54 + 1) * этаж (54 + 1)

= 55 * 55

Так как количество фильтров = 96, то вывод первого слоя будет: 55x55x96.

Продолжая, у нас есть слой MaxPooling (3, 3) с шагом 2, уменьшающий выходной размер до 27x27x96, за которым следует еще один сверточный слой с 256, (5,5) фильтрами и 'одинаковыми' заполнениями, то есть выход высота и ширина сохраняются, как в предыдущем слое, таким образом, вывод этого слоя составляет 27x27x256. Затем у нас снова есть MaxPooling, уменьшая размер до 13x13x256. Другая сверточная операция с фильтрами 384, (3,3), имеющими одинаковое заполнение, применяется дважды, давая результат как 13x13x384, за которым следует другой сверточный слой с 256, (3,3) фильтрами и тем же заполнением, что приводит к выходу 13x13x256. Это MaxPooled, и размеры уменьшены до 6x6x256. Далее слой выравнивается и создаются 2 полностью связанных слоя по 4096 единиц в каждом, которые дополнительно подключаются к слою softmax на 1000 единиц. Сеть используется для классификации большого количества классов согласно нашим требованиям. Однако в нашем случае мы сделаем выходной слой softmax с 6 единицами, поскольку мы должны классифицировать по 6 классам. Слой softmax дает нам вероятности для каждого класса, к которому может принадлежать входное изображение.

Реализация AlexNet с использованием Keras

Keras - это API для Python, построенный на основе Tensorflow 2.0, который масштабируется и адаптируется к возможностям развертывания Tensorflow [3]. Мы будем создавать слои с нуля на Python, используя Keras API.

Во-первых, давайте импортируем библиотеки самого необходимого.

import numpy as np
from keras import layers
from keras.layers import Input, Dense, Activation,BatchNormalization, Flatten, Conv2D, MaxPooling2D
from keras.models import Model
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
import keras.backend as K
K.set_image_data_format(‘channels_last’)
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow

В этой статье мы будем использовать генератор изображений для создания классификатора. Затем мы импортируем данные с помощью Image Data Generator. Перед этим давайте разберемся с данными. Набор данных можно найти здесь.

Эти данные содержат около 25k изображений размером 150x150, распределенных по 6 категориям, а именно: «здания», «лес», «ледник», «горы», «море», «улица». В обучающем наборе 14К изображений, 3К в тестовом наборе и 7К в наборе прогнозов.

Изображения данных для всех категорий разделены на соответствующие каталоги, что упрощает вывод ярлыков в соответствии с документацией keras [4].

Аргументы:

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

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

Затем мы импортируем набор данных, как показано ниже:

path = 'C:\\Users\\Username\\Desktop\\folder\\seg_train\\seg_train'
train_datagen = ImageDataGenerator(rescale=1. / 255)
train = train_datagen.flow_from_directory(path, target_size=(227,227), class_mode='categorical')

Вывод

Found 14034 images belonging to 6 classes.

Как объяснялось выше, размер ввода для AlexNet составляет 227x227x3, поэтому мы изменим целевой размер на (227 227). По умолчанию размер пакета равен 32. Давайте посмотрим тип train и train_datagen.

Тип keras.preprocessing.image.DirectoryIterator - это итератор, способный читать изображения из каталога на диске [5]. Keras.preprocessing.image.ImageDataGenerator генерирует пакеты данных тензорного изображения с увеличением данных в реальном времени. По умолчанию batch_size равен 32.

Затем давайте проверим размеры первого изображения и связанных с ним выходных данных в первом пакете.

print("Batch Size for Input Image : ",train[0][0].shape)
print("Batch Size for Output Image : ",train[0][1].shape)
print("Image Size of first image : ",train[0][0][0].shape)
print("Output of first image : ",train[0][1][0].shape)

Вывод:

Batch Size for Input Image :  (32, 227, 227, 3)
Batch Size for Output Image :  (32, 6)
Image Size of first image :  (227, 227, 3)
Output of first image :  (6,)

Давайте посмотрим на несколько примеров из набора данных:

fig , axs = plt.subplots(2,3 ,figsize = (10,10))
axs[0][0].imshow(train[0][0][12])
axs[0][0].set_title(train[0][1][12])
axs[0][1].imshow(train[0][0][10])
axs[0][1].set_title(train[0][1][10])
axs[0][2].imshow(train[0][0][5])
axs[0][2].set_title(train[0][1][5])
axs[1][0].imshow(train[0][0][20])
axs[1][0].set_title(train[0][1][20])
axs[1][1].imshow(train[0][0][25])
axs[1][1].set_title(train[0][1][25])
axs[1][2].imshow(train[0][0][3])
axs[1][2].set_title(train[0][1][3])

Это закодированные примеры, показывающие по одному рисунку для каждой категории в 1-м пакете. Результаты могут отличаться в зависимости от перетасовки, выполненной на вашем компьютере.

Вывод:

Теперь приступим к построению модели. Следующий блок кода создаст вашу сеть глубокого обучения AlexNet:

def AlexNet(input_shape):
    
    X_input = Input(input_shape)
    
    X = Conv2D(96,(11,11),strides = 4,name="conv0")(X_input)
    X = BatchNormalization(axis = 3 , name = "bn0")(X)
    X = Activation('relu')(X)
    
    X = MaxPooling2D((3,3),strides = 2,name = 'max0')(X)
    
    X = Conv2D(256,(5,5),padding = 'same' , name = 'conv1')(X)
    X = BatchNormalization(axis = 3 ,name='bn1')(X)
    X = Activation('relu')(X)
    
    X = MaxPooling2D((3,3),strides = 2,name = 'max1')(X)
    
    X = Conv2D(384, (3,3) , padding = 'same' , name='conv2')(X)
    X = BatchNormalization(axis = 3, name = 'bn2')(X)
    X = Activation('relu')(X)
    
    X = Conv2D(384, (3,3) , padding = 'same' , name='conv3')(X)
    X = BatchNormalization(axis = 3, name = 'bn3')(X)
    X = Activation('relu')(X)
    
    X = Conv2D(256, (3,3) , padding = 'same' , name='conv4')(X)
    X = BatchNormalization(axis = 3, name = 'bn4')(X)
    X = Activation('relu')(X)
    
    X = MaxPooling2D((3,3),strides = 2,name = 'max2')(X)
    
    X = Flatten()(X)
    
    X = Dense(4096, activation = 'relu', name = "fc0")(X)
    
    X = Dense(4096, activation = 'relu', name = 'fc1')(X) 
    
    X = Dense(6,activation='softmax',name = 'fc2')(X)
    
    model = Model(inputs = X_input, outputs = X, name='AlexNet')
return model

Далее мы вызовем функцию, которая вернет модель. Мы передали форму как форму нашего изображения, которое мы уже изменили до размера 227x227.

alex = AlexNet(train[0][0].shape[1:])

Модель можно резюмировать с помощью команды

alex.summary()

Вывод:

Затем мы скомпилируем модель с помощью оптимизатора Адама и выберем потерю как category_crossentropy с метриками точности. Вы можете узнать о потерях в keras здесь [6], а быстрое изучение оптимизаторов в Keras можно сделать здесь [7].

alex.compile(optimizer = 'adam' , loss = 'categorical_crossentropy' , metrics=['accuracy'])

Далее мы обучим модель с помощью fit_generator с помощью команды:

alex.fit_generator(train,epochs=50)

Вывод:

Epoch 50/50
439/439 [==============================] - 96s 219ms/step - loss: 0.0550 - accuracy: 0.9833

Чтобы узнать больше о fit_generator и его отличиях от fit, посетите этот сайт. После запуска нашей модели точность обучения составила 98,33%. Затем мы загрузим тестовые данные, чтобы получить точность теста:

path_test = 'C:\\Users\\Username\\Desktop\\folder2\\seg_test\\seg_test'
test_datagen = ImageDataGenerator(rescale=1. / 255)
test = test_datagen.flow_from_directory(path_test, target_size=(227,227), class_mode='categorical')

Вывод

Found 3000 images belonging to 6 classes.

Далее мы оценим нашу модель на тестовых данных.

preds = alex.evaluate_generator(test)
print ("Loss = " + str(preds[0]))
print ("Test Accuracy = " + str(preds[1]))

Вывод:

Loss = 0.1878412961959839
Test Accuracy = 0.871999979019165

Мы получили точность теста 87,2%. Далее мы запустим модель по прогнозируемым изображениям.

path_test = 'C:\\Users\\username\\Desktop\\folder3\\seg_pred\\'
predict_datagen = ImageDataGenerator(rescale=1. / 255)
predict = predict_datagen.flow_from_directory(path_test, target_size=(227,227), batch_size = 1,class_mode='categorical')

Вывод:

Found 7301 images belonging to 1 classes

Запустите на нем pred_generator

predictions = alex.predict_generator(predict)

Давайте проверим некоторые предсказанные изображения:

imshow(predict[700][0][0])

Чтобы получить его прогноз, мы сделаем:

print(predictions[700])

Вывод:

[9.9999893e-01 1.2553875e-08 7.1486659e-07 4.0256100e-07 1.3809868e-08
 8.5458379e-10]

Это результат нашей модели, поскольку мы использовали softmax на последнем слое, модель возвращает вероятности для каждой категории для этого конкретного входного изображения. Как видно выше, модель прогнозирует изображение как «здание» с вероятностью 0,99999893.

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

import os 
def get_category(predicted_output):
    path ="C:\\Users\\Username\\Desktop\\folder\\seg_train\\seg_train"
    return os.listdir(path)[np.argmax(abc)]

Мы будем называть функцию как:

print(get_category(predictions[700]))

Вывод:

buildings

Таким образом, вывод некоторых других изображений показан ниже:

fig , axs = plt.subplots(2,3 ,figsize = (10,10))
axs[0][0].imshow(predict[1002][0][0])
axs[0][0].set_title(get_category(predictions[1002]))
axs[0][1].imshow(predict[22][0][0])
axs[0][1].set_title(get_category(predictions[22]))
axs[0][2].imshow(predict[1300][0][0])
axs[0][2].set_title(get_category(predictions[1300]))
axs[1][0].imshow(predict[3300][0][0])
axs[1][0].set_title(get_category(predictions[3300]))
axs[1][1].imshow(predict[7002][0][0])
axs[1][1].set_title(get_category(predictions[7002]))
axs[1][2].imshow(predict[512][0][0])
axs[1][2].set_title(get_category(predictions[512]))

Записную книжку Python для этой модели можно клонировать / скачать с моего гитхаба здесь. Я надеюсь, вам понравится эта статья, и я надеюсь, что вы сможете построить свою собственную модель с другим набором данных и / или с пользовательскими слоями вместо того, чтобы следовать классической сети CNN.

Я надеюсь, что эта статья сможет дать вам представление об AlexNet. Также стоит попробовать более качественные сети, такие как VGG16, VGG19, ResNets и т. Д. Я надеюсь, что вы найдете эту статью интересной и обязательно попробуете некоторые другие классические модели CNN по проблеме классификации. Не стесняйтесь делиться своими результатами в поле для комментариев. Хлопайте по статье, если она вам нравится, поскольку она мотивирует меня писать больше постов. Найдите меня в Linked’In и Instagram и поделитесь своими отзывами.

Ссылки

[1] Крижевский, Алекс и Суцкевер, Илья и Хинтон, Джеффри. (2012). Классификация ImageNet с глубокими сверточными нейронными сетями. Системы обработки нейронной информации. 25. 10.1145 / 3065386.

[2] https://coursera.org/share/1fe2c4b8b8d1e3039ca6ae359b8edb30

[3] https://keras.io/

[4] https://keras.io/api/preprocessing/image/

[5] https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/DirectoryIterator

[6] https://keras.io/api/losses/

[7] https://keras.io/api/optimizers/