![](https://habrastorage.org/getpro/habr/upload_files/bac/e0c/05e/bace0c05e06157894da83373d8633c9a.png)
У нас было 4 нейросети, 2 опенсорсных датасета, 8 000 неразмеченных изображений, 5 333 аугментаций, 392 класса и 4 аккаунта на Roboflow. Не то, чтобы все это было категорически необходимо на проекте, но если уж начал анализировать телевизионное вещание, то к делу надо подходить серьезно. Единственное, что меня беспокоило — это Tesseract.
Меня зовут Саша Аксёнов, я — директор питерской студии разработки Unistory. Вместе с нашим разработчиком Данилой, а потом вместе с ML-инженерами Иваном и Юрой мы пустились в увлекательный трип.
Если после этой статьи у вас не произойдет окончательный разрыв дипломатических отношений между телом и мозгом — заглядывайте за подробностями в мой телеграм-канал.
Зачем нужен этот проект? Кому? В чем идея?
Один из наших клиентов захотел расширить линейку своих продуктов и обратился за помощью к нам. Суть нового продукта — анализ видео на YouTube. Анализировать нужно было, какие бренды упоминают блогеры в своих роликах, какие предметы попадают в кадр, что говорят люди на видео, какую инфу транслируют.
![После таких видео грех не показать пользователю рекламу ваших новых кроссовок После таких видео грех не показать пользователю рекламу ваших новых кроссовок](https://habrastorage.org/getpro/habr/upload_files/1d9/5e5/6fb/1d95e56fbcdd53996f26095fbc2992fd.jpg)
Зачем это все заказчику? Все очень просто, заказчик — разработчик маркетинговых сервисов. Ребята решили дать европейским маркетологам возможность анализировать, какой контент смотрел пользователь. И на основе этого показывать ему персональную рекламу в следующие полчаса.
Например, если вы посмотрели видео об автомобилях, система будет показывать вам рекламные ролики про покупку авто. Если смотрели передачу на тему моды — в течение получаса после этого увидите рекламу одежды.
Чтобы выполнить задачу, мы решили подключить несколько разных моделей AI. Компьютерное зрение, speech-to-text, OCR, LLM — нам понадобилось всё.
От YouTube до телевидения
Глобальная идея проекта сменилась на ходу. Мы шли к тому, чтобы анализировать YouTube-видео. В один момент заказчик понял, что не сможет подключить наш сервис к видеохостингу. Изначальная идея (скачать видео, проанализировать, показать пользователям рекламу) противоречила бы правилам YouTube.
К счастью, вместе с заказчиком пришли к новому видению проекта: решили анализировать телевизионное вещание. Для этого будем расширять гейтвей и подключать веб-сокет, который даст возможность анализировать TV-эфир.
![Лицо наших нейросетей, когда они увидят, что показывают по телевизору Лицо наших нейросетей, когда они увидят, что показывают по телевизору](https://habrastorage.org/getpro/habr/upload_files/f3d/840/2c5/f3d8402c5513a27c97f37a7b3a1db196.gif)
Как это будет работать:
Заказчик, владелец сервиса, заключает контракт с телекоммуникационной компанией
Наш API анализирует вещание в режиме реального времени
Система подбирает предложения для пользователей на основании контента, который они смотрели
Пользователь видит эти рекламные ролики
Такая схема дает большие бизнес-возможности. Например, сервисы с нашим API можно будет продавать по подписке. В этой картине мира каждый маркетолог сможет показывать людям таргетированную рекламу на основе тех передач, которые они посмотрели полчаса назад.
![](https://habrastorage.org/getpro/habr/upload_files/31f/463/6c0/31f4636c016efb1a20fc2e2ba88cfabb.png)
Что мы решили анализировать и какие нейросети использовали
Видео — контент, который состоит из нескольких потоков информации. Здесь и аудиодорожка, и видеодорожка, и субтитры, и надписи в кадре. Аудиодорожка может содержать только музыку, а может включать в себя речь.
Если мы попытаемся решить задачу анализа видео только с помощью компьютерного зрения, то можем важные вещи, о которых говорят ведущие на TV.
Поэтому мы решили анализировать все составные части видео по отдельности:
Появление логотипов в кадре. На протяжении всего видео, на любом фоне.
Какие объекты попадают в кадр. Одежда, автомобили, еда — вообще всё.
Текст, который появляется в кадре, в том числе вшитые субтитры.
Что говорят в тот момент, когда логотип появляется на экране.
Сентимент в речи: определяем, что говорит спикер на видео, что-то позитивное или негативное.
![](https://habrastorage.org/getpro/habr/upload_files/871/47b/df4/87147bdf44e2cf402c768a2d961da11a.jpg)
Какие нейросети все это делают:
Первая YoloV8 находит в кадре предметы
Вторая YoloV8, обученная отдельно от первой, находит логотипы в кадре
Rev AI анализирует, какой был язык в аудиофрагменте, а затем транскрибирует речь
Tesseract распознает статичный текст в кадре
Расшифровка текста, сделанная через Rev AI, попадает в Chat GPT, который анализирует ее на позитив / негатив
Какую информацию получает пользователь (читай: маркетолог):
Результат визуального анализа. Какие предметы, какие логотипы появлялись в кадре, в каких временных промежутках и как часто.
Результат речевого анализа. Имена селебрити и мест (городов, стран), которые были названы. Позитивные и негативные характеристики, которые ведущий давал людям, предметам и брендам.
Результат анализа статичного текста. Опять же, позитив / негатив, какие бренды упоминались.
Сейчас пользователь видит результаты анализа в формате JSON-файла. Не слишком презентабельно, но вполне достаточно, чтобы потом встроить API проекта, к примеру, в мобильное приложение.
JSON с результатами речевого анализа, например, выглядит так:
"transcription": {
"text": "I say German brands correctly. Adidas, Adidas, Volkswagen, Volkswagen, Mercedes-Benz, Mercedes-Benz, Birkenstock.",
"contentItems": [
{
"value": "Adidas",
"contentType": "Positive",
"itemType": "BrandName",
"timeRanges": [
{
"startTime": "00:00:02.9349990",
"endTime": "00:00:03.3550000"
},
{
"startTime": "00:00:04.1750000",
"endTime": "00:00:04.5949990"
}
]
},
{
"value": "Volkswagen",
"contentType": "Positive",
"itemType": "BrandName",
"timeRanges": [
{
"startTime": "00:00:05.3550000",
"endTime": "00:00:05.8350000"
},
{
"startTime": "00:00:07.3949990",
"endTime": "00:00:07.8750000"
}
]
},
{
"value": "Mercedes-Benz",
"contentType": "Positive",
"itemType": "BrandName",
"timeRanges": [
{
"startTime": "00:00:09.1949990",
"endTime": "00:00:09.8750000"
},
{
"startTime": "00:00:10.9149990",
"endTime": "00:00:11.5150000"
}
]
},
{
"value": "Birkenstock",
"contentType": "Positive",
"itemType": "BrandName",
"timeRanges": [
{
"startTime": "00:00:12.1049990",
"endTime": "00:00:12.7950000"
}
]
}
]
Одновременный анализ миллиона кадров
На одном из этапов разработки поняли, что есть нереальная просадка по производительности. Что-то было не так, анализ каждого ролика забирал у системы слишком много ресурсов.
Оказалось, написали код без учета количества кадров, которые проходят одновременный анализ. Система сразу забирала в анализ ВСЕ кадры ролика. Происходила перегрузка и ничего не работало.
Решили проблему просто: поставили ограничение на одновременную обработку не более 30 кадров.
![](https://habrastorage.org/getpro/habr/upload_files/97d/950/d99/97d950d9961bcadaa14c0a38ae02d125.jpg)
Как долго идет анализ контента
Никакого фронта в продукте нет, только бэкенд. Заказчик планирует использовать продукт как API в разных приложениях и сервисах.
Сейчас со стороны пользователя проект работает следующим образом. Загружаешь видос в виде файла, система его анализирует. На 10-минутное видео уйдет в среднем 5-6 минут. На время анализа влияет множество факторов, в том числе — количество кадров в секунду. Чем их больше, тем дольше будет идти обработка.
Со временем трудно предсказать: зависит не только от нашего сервера, но и от сторонних серверов, за использование которых мы платим. У них есть свои временные рамки, которые мы не можем контролировать.
У пользователя нет ограничений, сколько роликов загружать в систему, но есть ограничение пропускной способности сети. Если загрузить слишком много контента, можно забить память сервера.
Нарезаем видосы на кусочки
Были проблемы и с длинными видеороликами. Во время тестов заказчик спокойно мог загрузить 10-часовой файл. Такой файл легко мог положить сервер.
Оказалось, дело было в утилите для получения транскрипций. Чтобы она корректно работала, подключили нарезку файла на небольшие отрезки. Процесс проходит на сервере перед анализом — специально написали софт для этой задачи.
«Нарезка» происходит незаметно для пользователя. Человек загружает видео и просто ждет результатов анализа, даже если ролик длится 30 минут минут и весит несколько гигабайт.
Как устроен проект: чуть-чуть архитектуры и микросервисов
Как видите, обработка видео может идти довольно долго. Но мы предусмотрели этот момент на уровне архитектуры и сделали продукт масштабируемым.
![](https://habrastorage.org/getpro/habr/upload_files/1b6/d42/ae1/1b6d42ae1d3d979450658899d9324246.jpg)
Все дело в микросервисной архитектуре. Благодаря ей в будущем можно будет подключать все больше сервисов, которые будут давать возможность одновременного анализа нескольких видео.
Какие сервисы работают сейчас внутри проекта:
Один загружает видео
Второй формирует очередь из роликов
Третий производит анализ
Каждый сервис — независимое веб-приложение, которое взаимодействует с другими с помощью очереди сообщений. Каждый сервис имеет свою базу данных и общее временное хранилище видеофайлов.
Если случится ошибка на сервисе анализа, загруженные пользователем видео никуда не пропадут. Они останутся в очереди, просто их анализ начнется чуть позже.
Где мы взяли датасеты для поиска логотипов и товаров
Наша система должна была находить в видео много всего, но важнее всего были обычные предметы (на языке маркетологов — товары!) и логотипы. Именно объекты и логотипы в кадре позволяют эффективнее всего определить тематику трансляции, а значит — более прицельно предлагать зрителю рекламу.
Поэтому максимум внимания на проекте — компьютерному зрению.
Взяли YoloV8 — для нее много библиотек в открытом доступе, а значит, удобнее работать. Высокая производительность — тоже хорошо, учитывая, какой объем данных мы собирались анализировать.
![Обучили первую YoloV8 на датасете COCO. Простой датасет с простыми объектами: кошка, автомобиль, бутылка, мяч и т. д. Обучили первую YoloV8 на датасете COCO. Простой датасет с простыми объектами: кошка, автомобиль, бутылка, мяч и т. д.](https://habrastorage.org/getpro/habr/upload_files/99c/861/ea4/99c861ea4998b63c90821cbbf1f6ff75.png)
Датасет для объектов, предметов, товаров. Мы должны были добиться того, чтобы система находила в кадре самые разные предметы. Например, кастрюли, машины, мебель, обувь. Для этого подошел датасет COCO.
Как работает обученная нейросеть, можно посмотреть на видео ниже. Как видите, прекрасно находит зонтик и автомобиль — а значит, сможет помочь маркетологам, которые хотят продать людям зонты и машины (ну вдруг!).
Можно придумать что-нибудь более хитрое — например, если человек смотрел видео, где люди ходят под зонтом, показать ему рекламу новых брендовых дождевиков.
Датасет для логотипов. Большинство опенсорсных датасетов с логотипами были устаревшими и плохо размеченными. Лучше всего подошел OpenLogo, правда, здесь мы тоже определились не сразу. Долго выбирали среди разных версий датасета, пока не нашли самый подходящий. В нем были материалы для того, чтобы натренировать модель на обнаружение 352 логотипов.
На видео ниже — демонстрация, как Yolo находит логотипы на видео.
В итоге сервис выдает данные по визуальному анализу примерно так:
{
"id": 1,
"fileName": "4221495b-6323-4cc1-b67b-1653575510c5.mp4",
"originalFileName": "foo.mp4",
"detectionItemsResult": {
"videoDurationInSec": 16,
"detectionItems": [
{
"name": "person",
"objectId": 0,
"timeRanges": [
{
"startTime": "00:00:00.3333330",
"endTime": "00:00:15"
}
]
},
{
"name": "laptop",
"objectId": 63,
"timeRanges": [
{
"startTime": "00:00:10.3333330",
"endTime": "00:00:10.3333330"
}
]
},
{
"name": "mercedesbenz",
"objectId": 47,
"timeRanges": [
{
"startTime": "00:00:09",
"endTime": "00:00:12"
}
]
},
{
"name": "traffic light",
"objectId": 9,
"timeRanges": [
{
"startTime": "00:00:13.3333330",
"endTime": "00:00:13.6666660"
}
]
},
{
"name": "volkswagen text",
"objectId": 344,
"timeRanges": [
{
"startTime": "00:00:05.3333330",
"endTime": "00:00:08.6666660"
}
]
},
{
"name": "adidas",
"objectId": 28,
"timeRanges": [
{
"startTime": "00:00:02.6666660",
"endTime": "00:00:05"
}
]
},
{
"name": "volkswagen",
"objectId": 146,
"timeRanges": [
{
"startTime": "00:00:05.3333330",
"endTime": "00:00:08.6666660"
}
]
}
],
Аугментировали, балансировали, префиксы расставляли
Здесь хороший момент, чтобы рассказать подробнее, как мы работали с датасетом OpenLogo. Внутри датасета 352 класса логотипов — отлично, кто-то уже выполнил за нас большой объем работы. Бери и пользуйся.
Но не тут-то было: хоть заказчику набор логотипов и понравился, его нужно было расширить. Заказчик составил для нас внушительный список брендов, которые мы должны были добавить в датасет.
Каждый логотип в датасете представлен размеченными изображениями. Один класс логотипов, то есть одно новое лого — это один новый класс в датасете. В готовом датасете было 352 логотипа, 352 класса, 27 000 размеченных изображений.
![](https://habrastorage.org/getpro/habr/upload_files/eac/0ca/85f/eac0ca85f0ebb5fd6ec3fe4f44e4dac6.png)
Чтобы наша система отвечала требованиям заказчика, расширили опенсорсный OpenLogo на 40 дополнительных классов. Для этого понадобилось добавить 8000 размеченных изображений с логотипами.
Для добавления нового логотипа в датасет нужно было найти минимум 50 изображений с ним. Затем — аугментировать их, увеличить количество в три раза.
Пришлось не только добавить новые классы логотипов, но и поработать с изначальным датасетом.
Так, классы некоторых логотипов изначально были больше других. Считаем: в дефолтном датасете было 352 класса, в целом 27 000 изображений. Значит, в каждом классе должно быть 76 изображений — но это только среднее число. На самом деле, у некоторых логотипов было всего 20 картинок, а на другие могло приходиться по 150 и больше.
Такая неравномерность плохо сказывается на том, как будет работать обученная на этом датасете модель компьютерного зрения. Нейросеть может начать искать и находить те логотипы, которые лучше знает — и в итоге мы получили бы галлюцинации.
![](https://habrastorage.org/getpro/habr/upload_files/301/e4d/ce5/301e4dce57c5d9c3c12bfa03e4cbbcf2.png)
Поэтому мы поработали над балансом датасета. Заранее, до обучения, узнали, в каких классах меньше данных, чем в других. Во время обучения сильнее штрафовали модель, если она пропускала те логотипы, по которым было меньше размеченных изображений.
Чтобы справиться с этим, правили исходный код библиотеки, которую использовали для обучения Yolo. Библиотека Ultralytics, готовый фреймворк для обучения Yolo.
Адидас или Ориджиналс?
Среди логотипов, которые должна была уметь детектить модель, было много логотипов с префиксом. Самый стандартный пример, который приходит в голову — Adidas и Adidas Originals.
Для модели компьютерного зрения это абсолютно разные бренды. Поэтому приходилось отдельно искать данные по таким логотипам с префиксом, отдельно их размечать и балансировать.
![Когда вы делаете очередной редизайн, где-то в будущем плачет один дата сайентист Когда вы делаете очередной редизайн, где-то в будущем плачет один дата сайентист](https://habrastorage.org/getpro/habr/upload_files/196/303/8e0/1963038e0d862eec38310ffd20a3d1d2.png)
Может ли Tesseract распознать логотип?
Не все логотипы представляют собой милые рисунки и мудреные шрифтовые композиции. Иногда бренды используют в качестве лого надписи, набранные абсолютно нормальным шрифтом.
Вот их мы решили распознавать как текст, а не как изображение — и отдать эту задачу на Tesseract. В нашем JSON'е результат анализа текста внутри видео выглядит так:
"textToVideoResult": {
"textToVideoItems": [
{
"text": "German Brands\nCORRECTLY V\n\ntae Y\n",
"time": "00:00:01"
},
{
"text": "German Brands\nCORRECTLY V\n\nq\n",
"time": "00:00:02"
},
{
"text": "wha\nadidas\n\nLS ea\nnn\n=\n\n",
"time": "00:00:04"
},
{
"text": "wha\n| adidas\n\nm\n\n=\na am\n\n",
"time": "00:00:05"
},
{
"text": "W))\n\nVolkswagen\n\n",
"time": "00:00:07"
},
{
"text": "Volkswagen\n\n",
"time": "00:00:08"
},
{
"text": "&\n\nMercedes-Benz\n\nWass\n",
"time": "00:00:10"
},
{
"text": "BIRKENSTOCK®\n_| BIRKENSTOCK:\n\n",
"time": "00:00:15"
}
],
Как видите, работает Tesseract ни идеально. Залезали в исходный код модели, чтобы исправить ситуацию, но пока серьезных улучшений не добились. Если есть идеи, на что заменить Tesseract — пишите в комментариях!
Еще есть много логотипов, где слева расположено само лого, а справа от него обычным шрифтом — название компании. В этом случае наша разметка затрагивала только логотип, без надписи — этого было достаточно, чтобы распознать бренд.
Выехали на бесплатной версии Roboflow
Для наших целей потребовался бы самый дорогой тариф Roboflow. В стремлении сэкономить бюджет заказчика мы решили пользоваться бесплатной версией сервиса.
![Зачем тратить, если можно не тратить Зачем тратить, если можно не тратить](https://habrastorage.org/getpro/habr/upload_files/626/4f4/5e2/6264f45e20f5fb031c486dad41bde57d.jpg)
Ограничение бесплатного аккаунта — можно загрузить до 10 000 изображений. Поэтому пришлось повозиться и заводить 4 аккаунта, а потом скачивать все с каждого аккаунта и собирать в единый датасет.
Аугментацию делали локально — опять же, чтобы не оплачивать Roboflow.
На какой стадии сейчас проект. И что будет дальше
От изначальной идеи анализа YouTube-видео мы отказались, но заказчик вовремя разрешил ситуацию и предложил альтернативное видение проекта — анализ телевизионного вещания.
![](https://habrastorage.org/getpro/habr/upload_files/cf0/e08/d94/cf0e08d9499e8e20b07829153cabe65b.jpg)
Сейчас мы обучили две YoloV8 (одну для объектов, другую для логотипов), подключили Rev AI и Chat GPT. Собрали все это в единую рабочую систему. Осталось расширить гейтвей и подключить веб-сокет, чтобы добиться возможности анализа TV-трансляций.
Если хотите узнать дальнейшую судьбу проекта — подписывайтесь на мой Telegram-канал.
Здесь я делюсь техническими подробностями наших кейсов, а еще выкладываю вакансии для разработчиков, менеджеров, дизайнеров и просто талантливых чуваков.
Комментарии (8)
AigizK
22.08.2024 11:11анализируете каждый кадр? или применяете какие то оптимизации, например анализ только i-frames
как получаете данные от ТВ
unistory Автор
22.08.2024 11:11+1Cистема умеет работать в двух режимах: анализ каждого кадра; анализ каждого кратному переданному числу кадра.
Cуществует наш внутренний сервис, ответственный за это. Мы подключаемся к нему по UDP и получаем данные от TV.
MisterClever
22.08.2024 11:11Если не секрет, подскажите пожалуйста, какой нейросетью вы пользовались, когда создавали обложку и арты внутри статьи с отсылками на Страх и ненависть в Лас Вегасе?))) Они просто до мурашек атмосферны и захатывающи)
unistory Автор
22.08.2024 11:11+1Спасибо) все банально, Midjourney. Писал промпты вроде « picture in the style of the movie fear and loathing in las vegas, three guys in a car surrounded by bats. »
Еще хотел для конца статьи сделать такую картинку: терминатор-скелет вылезает из телевизора, при этом у него длинные черные волосы как у Самары из «Звонка». Выдало лютую крипоту.
Потом отказался от этой идеи и решил просто сделать Самару из «Звонка», вылезающую из телевизора, но милую. Верный способ сделать что-то милое в Midjourney — добавить в промпт «pixar style». В итоге картинки выглядели примерно так: очень милая голова девочки без шеи и тела. Лежит на полу. Оригинал потерял, но вот что-то похожее.
pagin
А почему не CLIP/DINO/Yolo-world? Для задачи "Определить всё" явно лучше. Ну и как бы получается one-stage. И учить не нужно - берем из коробки.
unistory Автор
Нам была важна специфичная настройка различных сторон анализа и асинхронность при обработке из-за потенциально огромного количества видео. Поэтому решили не использовать универсальное решение.