Поиск изображений на основе содержимого, также известный как «Запрос по содержимому изображения», основан на применении методов компьютерного зрения к задаче поиска изображений. Он включает в себя извлечение визуально похожих изображений из базы данных изображений на заданное изображение запроса. В этой статье проблема поиска изображений на основе контента решается с использованием неконтролируемых методов машинного обучения, то есть автокодировщиков.

Мы будем использовать набор данных изображений CIFAR10, содержащий цветные изображения 32x32 из 10 классов. Модель была разработана с использованием python, numpy, pandas, Keras API.

Автокодировщики

Автокодировщики — это разновидность нейронных сетей, используемых для неконтролируемых задач, целью которых является копирование входных данных на выходные. Он имеет скрытый слой z, который описывает код, используемый для представления входных данных. Автокодировщики состоят из двух частей; кодер, z = f(x),эта часть сети отвечает за кодирование входных данных в представление в скрытом пространстве. Декодер стремится восстановить входные данные из представления в скрытом пространстве, r = g(z).

Мы разработаем автокодировщик как две последовательные модели keras: кодировщик и декодер соответственно. Мы будем использовать символический API для применения и обучения этих моделей.

encoder = keras.models.Sequential()
decoder = keras.models.Sequential()

Кодировщик

Мы складываем сверточные слои и слои объединения и заканчиваем плотным слоем, чтобы получить представление желаемого размера (code_size). Мы используем активацию «elu» для всех сверточных и плотных слоев.

encoder.add(L.InputLayer(img_shape))
    encoder.add(L.Conv2D(filters=32, kernel_size=(3, 3), activation='elu', padding='same'))
    encoder.add(L.MaxPooling2D(pool_size=(2, 2)))
    encoder.add(L.Conv2D(filters=64, kernel_size=(3, 3), activation='elu', padding='same'))
    encoder.add(L.MaxPooling2D(pool_size=(2, 2)))
    encoder.add(L.Conv2D(filters=128, kernel_size=(3, 3), activation='elu', padding='same'))
    encoder.add(L.MaxPooling2D(pool_size=(2, 2)))
    encoder.add(L.Conv2D(filters=256, kernel_size=(3, 3), activation='elu', padding='same'))
    encoder.add(L.MaxPooling2D(pool_size=(2, 2)))
    encoder.add(L.Flatten())         #flatten image to vector
    encoder.add(L.Dense(code_size))

Декодер

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

decoder.add(L.InputLayer((code_size,)))
decoder.add(L.Dense(2*2*256))  #actual decoder, height*width*3 units
    decoder.add(L.Reshape((2,2,256)))
    decoder.add(L.Conv2DTranspose(filters=128, kernel_size=(3, 3), strides=2, activation='elu', padding='same'))
    decoder.add(L.Conv2DTranspose(filters=64, kernel_size=(3, 3), strides=2, activation='elu', padding='same'))
    decoder.add(L.Conv2DTranspose(filters=32, kernel_size=(3, 3), strides=2, activation='elu', padding='same'))
    decoder.add(L.Conv2DTranspose(filters=3, kernel_size=(3, 3), strides=2, activation=None, padding='same'))

Сеть обучается с использованием оптимизатора «adamax» и потери среднеквадратичной ошибки.

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

Мы хотим найти ближайших соседей нашего изображения в скрытом пространстве (код кодировщика). Для простоты мы будем вычислять ближайших соседей методом грубой силы.

images = X_train
codes = encoder.predict(images)
from sklearn.neighbors.unsupervised import NearestNeighbors
nei_clf = NearestNeighbors(metric="euclidean")
nei_clf.fit(codes)

Вот некоторые результаты.

Улучшения

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

Заключение

В этой статье мы рассмотрели поиск изображений на основе контента с использованием нейронных сетей, называемых автоэнкодерами. Мы также рассмотрели использование сверточных слоев, транспонированной свертки и слоев объединения для кодирования и декодирования представления изображений. Мы применили эту сеть к задаче поиска изображений с помощью алгоритма ближайшего соседа, чтобы найти похожие изображения в скрытом пространстве, разделенном евклидовым расстоянием. Ссылку на блокнот jupyter можно найти здесь.

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