Создавать подписи, которые описывают события видео автоматически

ВВЕДЕНИЕ

Задача создания субтитров для видео стала очень популярной в последние годы. Со всеми этими платформами, такими как YouTube, Twitch и короткими видеороликами, такими как Instagram Reels, видеоролики стали очень важным средством общения в нашей повседневной жизни. По данным Forbes, каждый день видео на Facebook смотрят более 500 миллионов человек. Каждую минуту на YouTube загружается 72 часа видео. В связи с тем, что видео набирает такую ​​популярность, продукты искусственного интеллекта для видео стали необходимостью во все времена.

ПРЕДВАРИТЕЛЬНЫЕ ЗНАНИЯ

Для понимания этого поста необходимы концепции LSTM / RNN и основы архитектуры кодировщика-декодера, а также понимание Кераса.

МОТИВАЦИЯ

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

НАСТОЯЩИЕ МИРОВЫЕ ПРИЛОЖЕНИЯ

Сначала мы должны понять, насколько важна эта проблема в реальных сценариях.

  • Более совершенные алгоритмы поиска. Если каждое видео может быть описано автоматически, поисковые алгоритмы будут давать более точные и точные результаты.
  • Системы рекомендаций: мы могли бы легко объединить видео в кластеры на основе их сходства, если бы содержание видео могло быть автоматически описано.

СБОР ДАННЫХ

Для этого исследования я использовал набор данных MSVD от Microsoft. Получить набор данных можно здесь. Этот набор данных содержит 1450 коротких видеороликов YouTube, которые были вручную помечены для обучения, и 100 видеороликов для тестирования.

Каждому видео присвоен уникальный идентификатор, и каждый идентификатор содержит около 15–20 титров.

ПОНИМАНИЕ НАБОР ДАННЫХ

При загрузке набора данных вы найдете папки training_data и testing_data. Каждая из папок содержит подпапку видео, которая содержит видео, которые будут использоваться как для обучения, так и для тестирования. Эти папки также содержат подпапку feat, что является сокращением от функций. Папки feat содержат особенности видео. Также существуют json-файлы training_label и testing_label. Эти файлы json содержат подписи для каждого идентификатора. Мы можем читать файлы json следующим образом:

train_path='training_data'
TRAIN_LABEL_PATH = os.path.join(train_path, 'training_label.json')
# mentioning the train test split
train_split = 0.85
# loading the json file for training
with open(TRAIN_LABEL_PATH) as data_file:    
    y_data = json.load(data_file)

Файл json выглядит следующим образом:

Таким образом, для каждого идентификатора видео существует множество альтернативных титров.

ИЗВЛЕЧЕНИЕ ФУНКЦИЙ ВИДЕО

Создание субтитров для видео - это проект, состоящий из двух частей. В первой части извлекаются особенности видео.

Что такое видео? Можно сказать, что видео - это список изображений, не так ли? Таким образом, для видео в наборе данных каждое изображение, называемое кадром, извлекается из видео.

Код для этого можно увидеть здесь.

Поскольку длина видео разная, количество извлеченных кадров также будет другим. Так что для простоты из каждого видео берутся только 80 кадров. Каждый из 80 кадров проходит через предварительно обученный VGG16, и из каждого кадра извлекается 4096 функций. Эти элементы сложены друг над другом, образуя массив формы (80, 4096). 80 - это количество кадров, а 4096 - это количество извлеченных функций из каждого кадра.

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

ОЧИСТКА И ПРЕДВАРИТЕЛЬНАЯ ОБРАБОТКА CAPTIONS

Теперь мы загрузим все подписи и свяжем их с их идентификаторами видео. Вот что я сделал. Train_list содержит пару подписей и идентификатор видео. Единственная предварительная обработка текста, которую я сделал, - это добавление токенов ‹bos› и ‹eos› до и после каждой подписи соответственно.

  • ‹bos› обозначает начало предложения, поэтому модель знает, что нужно начинать предсказывать отсюда и
  • ‹eos› обозначает конец утверждения, именно здесь модель знает, что нужно остановить прогноз.

Так выглядит train_list.

Train_list разделен на обучение и проверку. Training_list содержит 85% данных, а остальные присутствуют в validation_list.

Dictionary_list содержит только заголовки из списка training_list, потому что для токенизации мы будем использовать только слова в данных обучения. После токенизации мы дополним подписи так, чтобы все предложения были одинаковой длины. В моем проекте я добавил их все, чтобы они состояли из 10 слов. Вы могли заметить, что я также использую только подписи, в которых количество слов составляет от 6 до 10. Вы можете спросить, зачем я это сделал?

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

Теперь я использовал только 1500 верхних слов в качестве словаря для субтитров. Любые сгенерированные вами подписи должны быть частью 1500 слов. Несмотря на то, что количество уникальных слов намного превышает 1500, почему мы используем только 1500 слов для обучения?

Если вы думаете, что большинство слов встречается очень мало, всего 1, 2 или 3 раза, что делает словарь склонным к выбросам. Следовательно, для обеспечения безопасности мы будем использовать только 1500 наиболее часто встречающихся слов.

МОДЕЛЬ ДЛЯ ОБУЧЕНИЯ

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

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

Теперь, когда мы установили, что будем использовать модель кодировщика-декодера, давайте посмотрим, как мы будем ее использовать.

Опять что за видео? Мы можем назвать это последовательностью изображений, верно? Для всего, что связано с последовательностью, мы всегда предпочитаем использовать RNN или LSTM. В нашем случае мы будем использовать LSTM. Чтобы понять LSTM, перейдите по этой ссылке.

Теперь, когда мы будем использовать LSTM для кодировщика, давайте посмотрим на декодер. Декодер сгенерирует подписи. Подписи - это в основном последовательность слов, поэтому мы также будем использовать LSTM в декодере.

Здесь, на картинке, характеристики первого кадра передаются в 1-ю ячейку LSTM кодера. Далее следуют особенности второго кадра, и это продолжается до 80-го кадра. Для этой проблемы нас интересует только конечное состояние кодировщика, поэтому все остальные выходные данные кодировщика отбрасываются. Теперь конечное состояние кодера LSTM действует как начальное состояние для декодера LSTM. Здесь в первом декодере LSTM ‹bos› действует как ввод для начала предложения. Каждое слово подписи из обучающих данных вводится одно за другим до ‹eos›.

Итак, в приведенном выше примере, если фактическая подпись - женщина что-то готовит, декодер начинает с ‹bos› в первом декодере LSTM. В следующей ячейке следующее слово из фактического заголовка женщина кормит, а затем что-то готовит. Это заканчивается токеном ‹eos›.

Временные шаги для кодировщика - это количество ячеек LSTM, которое мы будем использовать для кодировщика, равное 80. Токены кодировщика - это количество функций видео, которое в нашем случае составляет 4096. Временные шаги для декодера - это количество ячеек LSTM для декодера, равное 10, а количество токенов - это длина словаря, равная 1500.

Давайте посмотрим на код модели.

Посмотрим на архитектуру.

ЗАГРУЗКА НАБОРА ДАННЫХ

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

Количество точек обучающих данных составляет около 14 КБ, что определенно вызовет проблемы с оперативной памятью. Чтобы избежать такой проблемы, я использовал генератор данных. Я использовал размер пакета 320. Так как есть два входа для обучения. Я конвертирую его в список, а затем скармливаю их вместе как вход кодировщика, который содержит функции видео в качестве входа и входа декодера, которые представляют собой подписи, которые были токенизированы и дополнены, преобразованы в категориальные функции с 1500 метками, поскольку это длина словарь, который мы будем использовать, или, как я уже упоминал, количество токенов декодера. Я использую оператор yield, чтобы вернуть результат. Заявления о доходности используются для создания генераторов. Здесь я использовал собственный генератор, потому что у нас было два входа. Я уже загрузил все функции в виде словаря, чтобы быстрее загружать одни и те же массивы снова и снова.

ОБУЧЕНИЕ

Я тренировал модель 150 эпох. На обучение одной эпохи ушло около 40 секунд. Я использовал бесплатную версию colab для обучения на Tesla T4.

МОДЕЛЬ ДЛЯ ВЫВОДА

В отличие от большинства нейронных сетей модели обучения и тестирования для кодировщика-декодера различны. Мы не сохраняем модель целиком после обучения. Мы сохраняем модель кодировщика и часть декодера по-разному. Теперь давайте посмотрим на модель вывода.

Сначала мы будем использовать модель кодировщика. В модель передаются элементы из всех 80 кадров. Эта часть модели такая же, как и для обучения. Модель кодировщика дает нам прогнозы. Здесь нас снова интересует состояние конечного выхода, поэтому все остальные выходы кодировщика будут отброшены. Конечное состояние кодировщика передается в декодер как начальное состояние вместе с токеном ‹bos›, так что декодер предсказывает следующее слово.

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

Теперь, если модель обучена правильно, как вы можете видеть выше, она должна предсказать женщину в качестве токена. Помните, как при обучении следующий ввод всегда был следующим словом в подписи. Поскольку здесь нет подписей, следующее слово - это результат предыдущей ячейки LSTM. Затем выходной женщина передается в следующую ячейку вместе с состоянием предыдущей ячейки. Это позволяет предсказать следующее слово равно. Так продолжается до тех пор, пока модель не предсказывает ‹eos›. Нам больше не нужны прогнозы, потому что предложение закончено.

ПОЛУЧЕННЫЕ РЕЗУЛЬТАТЫ

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

Сейчас было бы неправильно показывать только соответствующие результаты. Вот некоторые из не совсем правильных результатов.

Модель путает байк с велосипедом.

Как-то модель путает кошку с собакой и вместо того, чтобы размахивать лапами, думает, что это танцует. Этот заголовок грамматически не имеет большого смысла.

ЗАКЛЮЧЕНИЕ

Спасибо, что дочитали до этого места. Пожалуйста, обратитесь к моему Github для получения более подробной информации.

Еще один способ улучшить обучение - это перетасовка данных. Добавление видео из разных доменов.

Важный момент

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

БУДУЩАЯ РАБОТА

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

ИСПОЛЬЗОВАННАЯ ЛИТЕРАТУРА

Https://github.com/CryoliteZ/Video2Text

Https://github.com/PacktPublishing/Intelligent-Projects-Using-Python/tree/master/Chapter05





Хотите больше контента AI? Следуйте за мной в LinkedIn, чтобы получать ежедневные обновления.

Спасибо за чтение. Если вам понравилась эта статья, дайте ей несколько аплодисментов 👏. Надеюсь, у вас впереди отличный день!