В этой статье мы будем использовать машинное обучение с Python для создания подписей для различных изображений.
Подпись к изображению - это процесс присвоения изображению соответствующей подписи. Для человека это кажется легкой задачей, с которой легко справится даже пятилетний ребенок, но как мы можем написать компьютерную программу, которая будет принимать входные данные в виде изображения и генерировать подпись в качестве выходных?
До недавней разработки глубоких нейронных сетей эта проблема была немыслима для самых ярких умов в отрасли, но после появления глубоких нейронных сетей это вполне возможно, если у нас есть необходимый набор данных.
Например, сеть может генерировать любые из следующих заголовков, которые имеют отношение к изображению ниже i, e «Белая собака в траве», « Белая собака с коричневыми пятнами »или даже« Собака на траве и розовых цветах ».
Набор данных
Мы выбрали набор данных «Flickr 8k». Мы выбрали эти данные, потому что они были легкодоступными и имели идеальный размер, который можно было бы обучить на обычном ПК, а также достаточный для правильного обучения сети для создания соответствующих подписей. Данные разделены на три набора, в основном обучающий набор, содержащий 6 тыс. Изображений, набор для разработки, содержащий 1 тыс. Изображений, и тестовый набор, содержащий 1 тыс. Изображений. Каждое изображение содержит 5 подписей. Один из примеров такой:
- Ребенок в розовом платье поднимается по лестнице в подъезде.
- Девушка входит в деревянное здание.
- Маленькая девочка забирается в деревянный домик.
- Маленькая девочка поднимается по лестнице в свой игровой домик.
- Маленькая девочка в розовом платье входит в деревянную хижину.
Очистка данных:
Первым и самым важным шагом любой программы машинного обучения является очистка данных и избавление от любых нежелательных данных. Поскольку мы имеем дело с текстовыми данными в заголовках, мы будем выполнять основные шаги по очистке, такие как преобразование всех букв в нижний регистр, как для компьютера «Привет» и «Привет» - два совершенно разные слова, удаляя специальные символы и знаки препинания, такие как *, (, £, $,% и т. д., и удаляя любые слова, содержащие числа.
Сначала мы создаем словарь для всего уникального в нашем наборе данных, то есть 8000 (количество изображений) * 5 (подписи для каждого изображения) = 40000 подписей. Мы обнаружили, что это значение равно 8763. Но большинство этих слов встречается всего один или два раза, и мы не хотели бы, чтобы они использовались в нашей модели, поскольку это не сделает нашу модель устойчивой к выбросам. Следовательно, мы устанавливаем порог из 10 минимальных вхождений слова, которое должно быть включено в наш словарь, и это оказывается равным 1652 уникальным словам.
Еще мы добавляем два токена к каждому описанию, чтобы указать начало и конец заголовка. Два токена - это ‘startseq’ и ‘endseq’, представляющие начало и конец заголовка соответственно.
Начнем с импорта всех необходимых библиотек:
Давайте определим несколько вспомогательных функций:
Давайте объясним их по порядку:
load_doc
: берет путь к файлу и возвращает содержимое внутри этого файлаload_descriptions
: берет содержимое файла, содержащего описания, и создает словарь с идентификаторами изображений в качестве ключей и описаниями в виде списка значений.clean_descriptions
: очищает описание, делая все буквы строчными, игнорируя числовые символы и знаки препинания, а также слова, состоящие только из одного символа.save_descriptions
: сохраняет словарь описаний в памяти как текстовый файлloads_set
: загружает все уникальные идентификаторы изображений из текстового файла.load_clean_descriptions
: загружает все очищенные описания с использованием уникальных идентификаторов, извлеченных выше.
Предварительная обработка данных:
Затем мы проводим предварительную обработку данных как для изображений, так и для подписей. Изображения в основном являются нашими векторами функций, то есть нашим входом в сеть. Вот почему нам нужно преобразовать их в вектор фиксированного размера, прежде чем передавать в нейронную сеть. Для этого мы используем трансферное обучение из модели Inception V3 (сверточная нейронная сеть), созданной Google Research [3]. Эта модель была обучена на наборе данных ImageNet [4] для выполнения классификации изображений на 1000 изображений, но наша цель не состоит в том, чтобы выполнять классификацию, и поэтому мы удаляем последний слой softmax и извлекаем 2048 фиксированных вектор для каждого изображения, как показано на рисунке ниже:
Подписи - это результат нашей модели, то есть то, что мы должны предсказать. Но предсказание не происходит сразу, мы будем предсказывать наши подписи слово за словом. А для этого нам нужно закодировать каждое из наших слов в вектор фиксированного размера (что будет сделано в следующем разделе). Для этого нам сначала нужно создать два словаря, а именно 'word to index', которые сопоставят каждое слово с индексом, который в нашем случае будет от 1 до 1652, и 'index to word ', который сопоставляет каждый индекс с соответствующим словом. Последнее, что мы должны сделать, это вычислить длину описания, имеющего максимальную длину в нашем наборе данных, чтобы мы могли дополнить все остальные, чтобы поддерживать фиксированную длину. В нашем случае эта длина оказывается равной 34.
Вложения слов:
Как было сказано ранее, мы будем отображать каждое слово в вектор фиксированного размера (например, 200), мы будем использовать предварительно обученную модель GLOVE. Наконец, мы создаем матрицу вложения для всех 1652 слов в нашем словаре, содержащую вектор фиксированного размера для каждого слова в нашем словаре.
Давайте разберем этот фрагмент кода:
- Строка 1–5: извлеките все описания всех обучающих изображений в единый список.
- Строка 9–18: выберите в словаре только те слова, которые встречаются более 10 раз.
- Строка 21–30: Создайте слово для индексации и словарь для индексации слов.
- Строка 33–42: Загрузить вложения перчатки в словарь со словом в качестве ключа и вектором вложений в качестве значения.
- Строка 44–52: Создайте матрицу встраивания для слов из нашего словаря, используя вложения, загруженные выше.
Подготовка данных:
Это один из важнейших аспектов этого проекта. Что касается изображений, нам нужно преобразовать их в вектор фиксированного размера, используя модель Inception V3, как описано ранее.
- Строка 1–22: Загрузите пути поездов и тестовые изображения в отдельные списки.
- Строка 25–53. Прокрутите каждое изображение в обучающем и тестовом наборах, загрузив их в фиксированный размер, предварительно обработав их, извлекая функции с помощью модели InceptionV3 и, наконец, изменяя их форму.
- Строка 56–63: Сохраните извлеченные объекты на диск.
Теперь мы не сможем спрогнозировать нашу подпись сразу, то есть не просто дадим компьютеру изображение и не попросим его сгенерировать для него подпись. Мы бы дали ему вектор признаков изображения, а также первое слово подписи и позволили бы ему предсказать второе слово. Затем мы даем ему первые два слова и позволяем ему угадывать третье слово. Давайте рассмотрим изображение, приведенное в разделе набора данных, и подпись «Девушка входит в деревянное здание». В этом случае следующие значения будут нашими входами (Xi) и выходами (Yi) в каждом случае после добавления токенов ‘startseq’ и ‘endseq’.
После этого мы изменили бы каждое из слов в наших входах и выходах, чтобы сопоставить индекс, используя созданный нами словарь «word to index». Поскольку мы выполняем пакетную обработку, нам нужно, чтобы все последовательности были одинаковой длины, и поэтому мы должны добавлять к каждой последовательности нули, пока они не достигнут максимально возможной длины (34, как вычислено выше). Как можно видеть, это огромный объем данных, и загрузить его в память сразу невозможно, и для этого мы будем использовать генератор данных, который загружает их небольшими порциями, т.е. только то, что нужно и не нужно ». т потребляет всю память.
Приведенный выше код выполняет итерацию по всем изображениям и описаниям и генерирует элементы данных, как в таблице. yield
позволит функции снова запускаться из той же строки и, таким образом, давайте загружать данные партиями
Модельная архитектура и обучение:
Как указывалось ранее, наша модель в каждой точке имеет два входа: один - вектор изображения признака, а другой - частичный заголовок. Сначала мы применяем Dropout 0,5 к вектору изображения, а затем соединяем его со слоем из 256 нейронов. Для частичных подписей мы сначала соединяем их со слоями встраивания с весами матрицы встраивания из Предварительно обученной перчатки, как указано выше. Затем мы применяем Dropout 0,5 и LSTM (Long Short Term Memory). Наконец, мы объединяем их и соединяем со слоем из 256 нейронов и, наконец, слоем softmax, который предсказывает вероятность каждого слова в нашем словаре. Архитектуру высокого уровня можно резюмировать с помощью следующего рисунка:
Ниже приведены гиперпараметры, выбранные во время обучения: потеря была выбрана как «энтропия категориальных потерь», оптимизатор - «Адам». Модель обучалась в общей сложности для 30 эпох, но для первых 20 эпох размер пакета и скорость обучения составляли 0,001 и 3, а для следующих 10 эпох - 0,0001 и 6 соответственно.
Давайте немного поясним код:
- Строка 1-11: Определение архитектуры модели
- Строка 13–14: установите веса слоя внедрения равными матрице внедрения, созданной выше, а также установите
trainable=False
, чтобы слой больше не обучался. - Строка 16–33: Обучите модель в двух отдельных интервалах с гиперпараметрами, как указано выше.
Вывод:
Потери при обучении для первых 20 эпох, а затем для следующих 10 эпох показаны ниже:
Для вывода мы пишем функцию, которая предсказывает следующее слово как слово, имеющее максимальную вероятность в соответствии с нашей моделью (т.е. жадное).
Что вы можете сделать:
Итак, в заключение наша модель без какой-либо обширной настройки гиперпараметров показала довольно хорошие результаты при создании подписей для изображений в тестовом наборе данных. Некоторые из улучшений, о которых мы могли подумать, можно использовать
- Большой набор данных
- Дополнительная настройка гиперпараметров
- Изменение архитектуры модели.
Сообщите мне, если вы попробуете что-либо из этого и получите лучшие результаты. Код проекта можно найти здесь.