- BrainTools - https://www.braintools.ru -
— Расскажи нам, папа, сказочку… — Ой, да когда мне вам рассказывать, у меня работы невпроворот. Послушайте лучше аудиокнижку. — Аудиокнижки скучные. Вот если бы нам их лисичка почитала… или там Айвенго, или Мэри Поппинс. А так — сиди и слушай…
Вот с этого примерно и началось.
Задача казалась простой: взять картинку персонажа, взять аудио — и получить видео, где персонаж говорит. Технология-то должна существовать, мы живём в эпоху искусственного интеллекта [1], ChatGPT рисует котиков и пишет диссертации.
Технология существовала. Но работала в десять раз медленнее реального времени. На игровой видеокарте.
Wav2Lip, SadTalker, FasterLivePortrait — всё это отличные штуки. Серьёзные модели, годы исследований, впечатляющие демо. Но когда доходит до практики, выясняется несколько неприятных вещей.
GPU обязателен. Без него — слайдшоу. С ним — всё равно тормоза: десять секунд обработки на секунду видео. Мы хотели рендерить аудиокниги в реальном времени, а получали очередь на рендерферму.
Помимо скорости — артефакты. Нейросеть придумывает движения губ. Иногда придумывает странно: мыльные губы, плывущие зубы, лицо которое как будто немного не то. Модель не знает, как именно этот персонаж двигает ртом — она галлюцинирует правдоподобно, но не точно.
И тут возникла мысль: а почему, собственно, надо каждый раз генерировать мимику? Что если записать её один раз — пусть даже медленно, пусть даже с GPU — а потом воспроизводить быстро?
Граммофон вместо синтезатора.
Синтезатор может сыграть любую ноту в любой момент — но звучит синтетически. Граммофон воспроизводит то, что записал живой исполнитель — и звучит живо, потому что так оно и есть.
Снимаем человека на видео — несколько минут речи, желательно фонетически разнообразной, чтобы покрыть все основные звуки языка. Нарезаем видео на короткие перекрывающиеся сегменты: десять кадров, ~0.4 секунды, шаг два кадра. Для каждого сегмента вычисляем акустические признаки аудио — 16-мерный вектор: MFCC-коэффициенты, энергия, спектральный центроид.
Получается библиотека: вот этот кусочек видео соответствует вот такому звуку.
При рендере новой аудиодорожки мы просто ищем в этой библиотеке подходящие кусочки и склеиваем их. Никакого inference. Никаких весов. Человек всегда выглядит как человек — потому что мы показываем настоящего человека, а не нейросетевую фантазию о нём.
Лисичка из детской книжки не может прийти на съёмку. Айвенго тоже недоступен — он вообще персонаж романа двухсотлетней давности. А заказчику нужен именно он, а не актёр в рыцарских доспехах.
Здесь на сцену выходит FasterLivePortrait — и уже в совершенно другой роли. Не как инструмент рендера (он для этого слишком медленный, мы помним), а как инструмент подготовки данных.
Берём картинку персонажа. Запускаем FLP — он генерирует видео, где персонаж произносит специально подобранный текст: фонетически разнообразный, покрывающий все основные звуки. Да, это занимает время. Да, тут нужен GPU. Но это происходит один раз.
Дальше — тот же пайплайн: нарезаем на сегменты, вычисляем признаки, строим библиотеку. И рендерим любое количество видео с любым аудио без всякого GPU.
FLP здесь — не костыль и не противоречие. Это поставщик обучающих данных. Медленный, дорогой, но одноразовый.
Лисичка читает про трёх поросят. Айвенго рассказывает про турниры. Чингачгук — про прерии. Каждый своим лицом, своей мимикой. Достаточно, чтобы лицо было антропоморфным — глаза, нос, рот более-менее на своих местах. Совсем абстрактные персонажи пока не работают, но лисички из детских книжек — вполне.
Это главная техническая проблема. Два кусочка видео, выбранные из разных мест библиотеки, могут сильно отличаться по положению лица на стыке. Наивная склейка даёт рывок.
Сначала — выбрать правильный кусочек. Планировщик смотрит вперёд на две секунды, берёт среднее по будущим акустическим признакам и ищет сегмент под будущую фонетику — не под текущую. Это lookahead, и он заметно улучшает синхронизацию: сегмент подобран под то, что будет звучать, а не под то, что уже прозвучало.
Из всей библиотеки берём топ-20 по акустическому сходству. Дальше выбираем лучший стык: у каждого сегмента хранятся миниатюры первого и последнего кадра (64×64 пикселя). Считаем пиксельное расстояние между концом текущего сегмента и началом каждого из двадцати кандидатов. Берём ближайший. Быстро — никаких полных кадров, только крошечные картинки.
Даже лучший кандидат даст небольшой рывок. Между сегментами строим переход через двунаправленный поток Фарнебека:
flow_AB = Farneback(последний_кадр_A, первый_кадр_B)
flow_BA = Farneback(первый_кадр_B, последний_кадр_A)
for t in [0, 1/N, 2/N, ...]: warped_A = remap(A, flow_AB * t) warped_B = remap(B, flow_BA * (1-t)) output = blend(warped_A, warped_B, t)
Почему двунаправленный? Простой crossfade размывает — пиксели в середине перехода буквально усредняются, получается каша. Двунаправленный поток двигает каждый пиксель по траектории из A в B и одновременно из B в A, а потом смешивает. Переход выглядит как движение, а не как растворение.
Длина морфа адаптивная: чем сильнее отличаются кадры — тем дольше переход, от 5 до 12 кадров. Планировщик минимизирует разницу, поэтому большинство переходов укладываются в 5–7 кадров и почти незаметны.
Персонаж молчит, а мы должны что-то показывать. Случайный сегмент из речевой библиотеки — рот будет двигаться без звука, жуть. Заморозить последний кадр — неестественно.
Решение: отдельная библиотека для пауз. При построении модели генерируем короткое видео, где анимируются только глаза — моргание, движения взгляда, рот закрыт. Во время пауз персонаж переключается на эти сегменты и просто естественно моргает.
Каждый шаг намеренно выбран так, чтобы не требовать GPU:
Косинусный поиск по тысячам сегментов — умножение 16-мерных векторов, мгновенно
Выбор лучшего стыка — MAD по 20 картинкам 64×64, ~80 тысяч операций
Оптический поток Фарнебека — классический CV-алгоритм, OpenCV считает на CPU без вопросов
Декодирование JPEG и remap — пиксельные операции
Самое тяжёлое — предвычисление оптических потоков между всеми соседними кадрами — можно вынести в отдельный этап подготовки модели. Тогда рендер только применяет готовые карты.
Итог: реальное время, обычный ноутбук, GPU не нужен.
Две проблемы — одно решение.
Нейросети медленные? Записываем мимику один раз, воспроизводим быстро. Человека нет? FasterLivePortrait генерирует обучающее видео из картинки — один раз, медленно, с GPU. Дальше тот же быстрый retrieval.
Retrieval вместо generation. Граммофон вместо синтезатора.
Лисичка читает сказки. Дети довольны. Папа может вернуться к работе.
Автор: akk025
Источник [2]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/28627
URLs in this post:
[1] интеллекта: http://www.braintools.ru/article/7605
[2] Источник: https://habr.com/ru/articles/1022110/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1022110
Нажмите здесь для печати.