В предыдущем посте я говорил о классификации изображений с помощью нейронных сетей, но сегодня я хочу подробнее остановиться на этом. Итак, давайте посмотрим, как работает CNN и как вы реализуете его самостоятельно.
Данные
Прежде всего, давайте кратко рассмотрим данные, которые я использовал для этого проекта:
- Мода MNIST: этот набор данных содержит 70 000 черно-белых изображений различных предметов одежды, от обуви и сумок до платьев и рубашек. Эти изображения имеют размеры 28x28 и отображаются в оттенках серого. (Данные можно найти здесь.)
- Смайлики: содержит почти 2500 изображений нарисованных от руки смайликов, эти изображения имеют размер 32x32 5 различных типов смайликов. Этот набор данных был «сплющен», но его можно довольно легко снова «раздуть».
Си-Эн-Эн
Теперь вы, возможно, слышали о популярности CNN для обработки изображений или аудио, но вам также может быть интересно: «Что такое CNN вообще?»
CNN имеет 4 основных типа слоев:
- Слои свертки: используются для извлечения характеристик из изображений (таких как границы, изменение цвета и т. д.) путем применения сверток.
- Объединение слоев: используется для уменьшения количества характеристик, извлекаемых из сверточных слоев.
- Слои ReLu: иногда используются для добавления нелинейности в сеть.
- Полносвязные слои: MLP, используемый для классификации.
Первые три из этих слоев в основном используются для изучения признаков, а MLP используется для классификации (со слоем SoftMax в качестве выходного слоя). Вы можете задаться вопросом, зачем вообще использовать три слоя для того, что кажется предварительной обработкой данных. Дело в том, что эти три слоя действительнохороши для получения информации и ее обработки без потери важных частей — они способны определить, как каждый пиксель связан с другим и когда это важно сохранить, чтобы получить хороший прогноз. Другими словами, это позволяет извлекать масштабируемые функции для огромных объемов данных.
Свертка:
Теперь, как работает слой свертки? Ну, во-первых, этот слой загружается изображениями и их размерами. Итак, давайте сначала разделим наши данные на наборы для обучения и тестирования и посмотрим на их размеры:
(f_x_train, f_y_train), (f_x_test, f_y_test) = datasets.fashion_mnist.load_data() f_x_train = f_x_train.astype("float32") / 255 f_x_test = f_x_test.astype("float32") / 255 f_x_train, f_x_val, f_y_train, f_y_val = train_test_split(f_x_train, f_y_train, test_size=0.15) print(f_x_train.shape, f_x_val.shape, f_x_test.shape) >>(51000, 28, 28) (9000, 28, 28) (10000, 28, 28)
Здесь, поскольку мы используем набор данных Fashion MNIST, мы видим, что это 28x28x1 (высота x ширина x канал RGB), поэтому они передаются в сеть следующим образом:
model = Sequential([ Conv2D(64, kernel_size=(3, 3), activation='relu',padding='same', input_shape=(28, 28, 1)), #image dimensions BatchNormalization(), Conv2D(64, kernel_size=(3, 3), activation='relu'), BatchNormalization(), MaxPooling2D(pool_size=(2, 2)), #Pooling Layer Flatten(), #Flattening to pass to Fully Connected Layer Dense(1024, activation='relu'), Dense(512, activation='relu'), Dense(10, activation='softmax') #Output Layer ])
Здесь мы можем увидеть с небольшой визуальной помощью, как работает свертка. По сути, у вас есть ядро, которое перемещается по исходной матрице и получает один элемент для формирования новой матрицы и, таким образом, извлечения признаков. Обычно первая свертка используется для извлечения признаков низкого уровня, а добавление дополнительных слоев означает извлечение признаков высокого уровня. В этом ядре есть две переменные: Padding и Stride. В зависимости от значений, которые вы установили для каждого из них, выходные данные будут различаться. Посмотреть на это здесь можно поближе.
Объединение:
Слои пула, как показано выше, уменьшают количество получаемых данных, вычисляя либо максимальные, либо средние значения части изображения. Это имеет двойную функциональность в случае Max Pooling, поскольку уменьшает объем работы (уменьшение размерности) и помогает с проблемами переобучения (удаление шума).
ReLu и полносвязные слои:
Наконец, данные выравниваются и передаются в MLP со слоями ReLu и выходным слоем Softmax. Давайте посмотрим на результат, который мы получили после компиляции модели и ее обучения:
#Compiling Model adam = Adam(lr=0.001, decay=1e-6) model.compile(optimizer=adam, loss='sparse_categorical_crossentropy', metrics=['accuracy']) history = model.fit(f_x_train, f_y_train, validation_data=(f_x_val, f_y_val) , epochs=10, batch_size=32) #Results print("\nEvaluating...", flush=True) print('Training data:', flush=True) loss, acc = model.evaluate(f_x_train, f_y_train, verbose=1) print(" Training : loss %.3f - acc %.3f" % (loss, acc)) print('Cross-validation data:', flush=True) loss, acc = model.evaluate(f_x_val, f_y_val, verbose=1) print(" Cross-val: loss %.3f - acc %.3f" % (loss, acc)) print('Test data:', flush=True) loss, acc = model.evaluate(f_x_test, f_y_test, verbose=1) print(" Testing : loss %.3f - acc %.3f" % (loss, acc)) >>Evaluating... >>Training data: >>1594/1594 [==============================] - 12s 7ms/step - loss: >>0.0518 - accuracy: 0.9815 >> Training : loss 0.052 - acc 0.981 >>Cross-validation data: >>282/282 [==============================] - 2s 7ms/step - loss: >>0.3860 - accuracy: 0.9194 >> Cross-val: loss 0.386 - acc 0.919 >>Test data: >>313/313 [==============================] - 2s 8ms/step - loss: >>0.3981 - accuracy: 0.9189 >> Testing : loss 0.398 - acc 0.919
Полученные результаты:
Теперь давайте подробнее рассмотрим наши результаты:
Мода MNIST: 0,919
Смайликов: 0,964
В целом, результаты, которые мы получаем с CNN, поразительны! Они намного лучше, чем результат, полученный нами в предыдущем посте (кроме Fashion MNIST MLP). Вот результаты, полученные тогда:
LDA — мода MNIST: 0,8325 ; Смайлик: 0,6506
KNN — мода MNIST: 0,8326 ; Смайлик: 0,6532
MLP — мода MNIST: 0,9789; Эмоджи: 0,8329
Что примечательно, так это то, что классические методы, такие как LDA и KNN, кажется, прекрасно работают для базы данных Fashion, и здесь мы должны задать вопрос: действительно необходимо использовать глубокое обучение для этой проблемы? Однако для базы данных Emoji это очевидно — классические методы не достигли точности даже 0,7, и в этом случае я бы сказал, что подход глубокого обучения очень необходим.
С другой стороны, CNN делают именно то, чего мы пытались добиться в посте ранее, уменьшая размерность, но намного лучше. Поэтому, если вы хотите уменьшить размер ваших данных, я определенно рекомендую подход глубокого обучения (например, первые два уровня, которые мы обсуждали здесь), а не подход, основанный на дескрипторах.
Я оставлю исходник здесь, вы также сможете найти пример эмодзи: