Классификация изображений относится к процессу компьютерного зрения, который может классифицировать изображение в соответствии с его визуальным содержанием. Например, алгоритм классификации изображений может быть разработан, чтобы определить, содержит ли изображение кошку или собаку. Хотя обнаружение объекта для человека тривиально, надежная классификация изображений по-прежнему является проблемой в приложениях компьютерного зрения.
В этом уроке вы узнаете, как успешно классифицировать изображения в наборе данных CIFAR-10 (который состоит из самолетов, собак, кошек и других 7 объектов) с помощью Tensorflow в Python.
Обратите внимание, что существует разница между классификацией изображений и обнаружением объектов, классификация изображений — это отнесение изображения к какой-либо категории, например, в этом примере входом является изображение, а выходом — метка одного класса (10 классов). Обнаружение объектов — это обнаружение, классификация и локализация объектов в реальных изображениях, одним из основных алгоритмов является обнаружение объектов YOLO.
Мы предварительно обработаем изображения и метки, а затем обучим сверточную нейронную сеть на всех обучающих выборках. Изображения должны быть нормализованы, а метки должны быть закодированы в горячем режиме.
Для начала установим пакеты для этого проекта:
pip3 install numpy matplotlib tensorflow==2.0.0 tensorflow_datasets
Например, откройте пустой файл Python, назовите его train.py и запишите код для импорта Tensorflow:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2D from tensorflow.keras.callbacks import TensorBoard import tensorflow as tf import tensorflow_datasets as tfds import os
Как и следовало ожидать, будем использовать API tf.data
для загрузки набора данных CIFAR-10.
Гиперпараметры
Я экспериментировал с различными параметрами и эти параметры считаю оптимальными:
# Гиперпараметры batch_size = 64 # 10 категорий для изображений (CIFAR-10) num_classes = 10 # количество эпох для обучения epochs = 30
num_classes
просто количество категорий для классификации, в нашем случае CIFAR-10 имеет только 10 категорий изображений.
- Набор данных состоит из 10 классов изображений, чьи метки находятся в диапазоне от 0 до 9::
- 0: airplane (самолет) ().
- 1: automobile (автомобиль) ().
- 2: bird (птица).
- 3: cat (кошка).
- 4: deer (олень).
- 5: dog (собака).
- 6: frog (лягушка).
- 7: horse (лошадь).
- 8: ship (корабль).
- 9: truck (грузовик).
- 50000 образцов для обучающих данных и 10000 образцов для тестовых данных.
- Каждый образец представляет собой изображение размером 32x32x3 пикселя (ширина и высота 32 и 3 глубины, которые являются значениями RGB).
Загрузим всё это:
def load_data(): """ Эта функция загружает набор данных CIFAR-10 dataset и делает предварительную обработку """ def preprocess_image(image, label): # преобразуем целочисленный диапазон [0, 255] в диапазон действительных чисел [0, 1] image = tf.image.convert_image_dtype(image, tf.float32) return image, label # загружаем набор данных CIFAR-10, разделяем его на обучающий и тестовый ds_train, info = tfds.load("cifar10", with_info=True, split="train", as_supervised=True) ds_test = tfds.load("cifar10", split="test", as_supervised=True) # повторять набор данных, перемешивая, предварительно обрабатывая, разделяем по пакетам ds_train = ds_train.repeat().shuffle(1024).map(preprocess_image).batch(batch_size) ds_test = ds_test.repeat().shuffle(1024).map(preprocess_image).batch(batch_size) return ds_train, ds_test, info
Эта функция загружает набор данных с помощью модуля with_info
значение True
для просмотра некоторой информации об этом наборе данных, поэтому можно распечатать его и посмотреть названия полей и их значения. мы будем использовать информацию для получения количества образцов в тренировочных и тестовых наборах.
После этого мы:
- Бесконечно повторяем набор данных, используя метод
repeat()
, что позволит нам многократно генерировать образцы данных (мы укажем условие остановки на этапе обучения). - Перемешиваем.
- Нормализуем изображения до значений от 0 до 1, это поможет нейронной сети обучаться намного быстрее, для чего используем метод
map()
, который принимает функцию обратного вызова, изображение и метку в качестве аргументов, просто используя встроенный в Tensorflowconvert_image_dtype()
, который и занимается всем этим. - Наконец, группируем наш набор данных по 64 образцам с помощью функции
batch()
, поэтому каждый раз, когда мы генерируем новые точки данных, он будет возвращать 64 изображения и их 64 метки.
Построение модели
Будет использована следующая модель:
def create_model(input_shape): # построение модели model = Sequential() model.add(Conv2D(filters=32, kernel_size=(3, 3), padding="same", input_shape=input_shape)) model.add(Activation("relu")) model.add(Conv2D(filters=32, kernel_size=(3, 3), padding="same")) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(filters=64, kernel_size=(3, 3), padding="same")) model.add(Activation("relu")) model.add(Conv2D(filters=64, kernel_size=(3, 3), padding="same")) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(filters=128, kernel_size=(3, 3), padding="same")) model.add(Activation("relu")) model.add(Conv2D(filters=128, kernel_size=(3, 3), padding="same")) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) # сглаживание неровностей model.add(Flatten()) # полносвязный слой model.add(Dense(1024)) model.add(Activation("relu")) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation="softmax")) # печатаем итоговую архитектуру модели model.summary() # обучение модели с помощью оптимизатора Адама model.compile(loss="sparse_categorical_crossentropy", optimizer="adam", metrics=["accuracy"]) return model
3 уровня из 2 ConvNet с максимальным объединением и функцией активации ReLU
, а затем полностью подключенным к 1024 единицам. Это относительно небольшая модель по сравнению с самыми современными моделями
Обучение модели
Теперь давайте обучим модель:
if __name__ == "__main__": # загружаем данные ds_train, ds_test, info = load_data() # конструируем модель model = create_model(input_shape=info.features["image"].shape) # несколько хороших обратных вызовов logdir = os.path.join("logs", "cifar10-model-v1") tensorboard = TensorBoard(log_dir=logdir) # убедимся, что папка с результатами существует if not os.path.isdir("results"): os.mkdir("results") # обучаем model.fit(ds_train, epochs=epochs, validation_data=ds_test, verbose=1, steps_per_epoch=info.splits["train"].num_examples // batch_size, validation_steps=info.splits["test"].num_examples // batch_size, callbacks=[tensorboard]) # сохраняем модель на диске model.save("results/cifar10-model-v1.h5")
После загрузки данных и создания модели я использовал Tensorboard, который будет отслеживать точность и потери в каждой эпохе и предоставлять нам хорошую визуализацию.
Будем использовать папку results для сохранения наших моделей. Обязательно проверьте, что можете работать с файлами и каталогами в Python.
Поскольку ds_train
и ds_test
будут многократно генерировать выборки данных в пакетах, нам нужно указать количество шагов на эпоху и количество выборок, разделенное на размер пакета, то же самое и для validation_steps
.
Запустите. В зависимости от вашего процессора/графического процессора это займет несколько минут.
Результат будет примерно таким:
Epoch 1/30 781/781 [==============================] - 20s 26ms/step - loss: 1.6503 - accuracy: 0.3905 - val_loss: 1.2835 - val_accuracy: 0.5238 Epoch 2/30 781/781 [==============================] - 16s 21ms/step - loss: 1.1847 - accuracy: 0.5750 - val_loss: 0.9773 - val_accuracy: 0.6542
Вплоть до последней эпохи:
Epoch 29/30 781/781 [==============================] - 16s 21ms/step - loss: 0.4094 - accuracy: 0.8570 - val_loss: 0.5954 - val_accuracy: 0.8089 Epoch 30/30 781/781 [==============================] - 16s 21ms/step - loss: 0.4130 - accuracy: 0.8563 - val_loss: 0.6128 - val_accuracy: 0.8060
Теперь, чтобы открыть tensorboard, все, что вам нужно сделать, это ввести команду в терминале или в командной строке в текущем каталоге:
tensorboard --logdir="logs"
Откройте вкладку браузера и введите localhost: 6006
, вы будете перенаправлены на tensorboard, вот мой результат:
Очевидно, что мы на правильном пути, потери при проверке снижаются, а точность возрастает примерно до 81%. И это просто замечательно!
Проверка модели
После завершения обучения окончательная модель и веса нейронной сети будут сохранены в папке результатов, таким образом, научив её один раз мы сможем делать прогнозы, когда захотим.
Откройте новый файл python с именем test.py и следуйте инструкциям.
Импортируем необходимые утилиты:
from train import load_data, batch_size from tensorflow.keras.models import load_model import matplotlib.pyplot as plt import numpy as np
Создадим словарь Python, который сопоставляет каждое целочисленное значение с соответствующей меткой в наборе данных:
# CIFAR-10 classes categories = { 0: "airplane", 1: "automobile", 2: "bird", 3: "cat", 4: "deer", 5: "dog", 6: "frog", 7: "horse", 8: "ship", 9: "truck" }
Загрузим тестовые данные и модели:
# загрузим тестовый набор ds_train, ds_test, info = load_data() # загрузим итоговую модель с весовыми коэффициентами model = load_model("results/cifar10-model-v1.h5")
Оценка:
# оценка loss, accuracy = model.evaluate(X_test, y_test) print("Тестовая оценка:", accuracy*100, "%")
Возьмем случайное изображение и сделаем прогноз:
# получить прогноз для этого изображения data_sample = next(iter(ds_test)) sample_image = data_sample[0].numpy()[0] sample_label = categories[data_sample[1].numpy()[0]] prediction = np.argmax(model.predict(sample_image.reshape(-1, *sample_image.shape))[0]) print("Predicted label:", categories[prediction]) print("True label:", sample_label)
Мы использовали next(iter(ds_test))
для получения следующего пакета тестирования, а затем извлекли первое изображение и метку в этом пакете и сделали прогнозы для модели, вот результат:
156/156 [==============================] - 3s 20ms/step - loss: 0.6119 - accuracy: 0.8063 Test accuracy: 80.62900900840759 % Predicted label: frog True label: frog
Модель говорит, что это лягушка, проверим:
# show the image plt.axis('off') plt.imshow(sample_image) plt.show()
И это действительно так!
Заключение
Хорошо, мы закончили с этим уроком, 81% неплохо для этой маленькой
Требуется регистрация для доступа к контенту. Регистрация, если Вы уже зарегистрированы — подключитесь
Вы можете удивиться, что эти изображения такие простые, сетка 32×32 — это не то, что есть в реальном мире, изображения не такие простые, они часто содержат много объектов, сложных узоров и так далее. В результате, перед переходом к каким-либо методам классификации часто обычной практикой является использование методов сегментации изображений, таких как обнаружение контуров или сегментация кластеризации K-средних.
Наконец, если вы хотите расширить свои навыки в области машинного обучения (или даже если вы новичок), я бы посоветовал вам поступать в Высшую школу экономики и управления на образовательное направление 38.03.05 Бизнес-информатика. Удачи!
По мотивам
Как создать классификатор изображений на Python с помощью Tensorflow 2 и Keras, опубликовано К ВВ, лицензия — Creative Commons Attribution-NonCommercial 4.0 International.
Респект и уважуха