Как работает фиксация персонажа под капотом: технический разбор

Технический обзор архитектуры систем character embeddings: извлечение признаков, хранение, синтез negative prompts, conditioning, проверка согласованности и открытые проблемы.

·9 min read·technical

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

Здесь мы пройдёмся по тому, как системы character embedding на самом деле работают в современных AI-видеостеках: архитектура, проектные решения, режимы сбоя и открытые проблемы, которые ещё не решены.

Постановка задачи

Дано: генеративная видеомодель M и персонаж C. Нужна процедура, чтобы для любого промпта p_i из последовательности p_1, p_2, , p_n, ссылающегося на C, сгенерированные выводы сохраняли идентичность C.

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

Нужен способ обуславливать вывод модели на конкретной выученной идентичности, а не просто на описании.

Архитектура

Современная система согласованности персонажей имеет шесть компонентов:

1. Feature extraction       — produce identity embedding from reference
2. Storage                  — persist embedding tied to character_id
3. Negative prompt synthesis — auto-build negative_prompts from drift catalog
4. Conditioning injection   — inject embedding into model conditioning
5. Generation               — diffusion sampling with conditioned model
6. Consistency verification — post-hoc similarity check, regenerate if needed

Пройдёмся по каждому.

1. Извлечение признаков

При загрузке персонажа против референсного изображения запускают несколько специализированных моделей:

Они конкатенируются (или объединяются через attention) в высокоразмерный character embedding e_C. Общая размерность обычно 1500–3000.

Зачем несколько моделей вместо одной? Потому что у идентичности несколько осей, ни одну из которых отдельный энкодер не покрывает полностью. Энкодеры лиц отлично отвечают на вопрос «это то же лицо?», но игнорируют пропорции тела. Парсеры тела игнорируют детали лица. CLIP отлично работает с семантическим внешним видом, но теряет тонкую идентичность. Конкатенация даёт ортогональное покрытие.

Компромисс: более сложный конвейер извлечения означает больше compute при загрузке персонажа (~30–90 секунд в нашей системе). Для потребительских инструментов это нормально. Для высокопроизводительных конвейеров можно один раз предвычислить embeddings при загрузке и ссылаться на них при генерации.

2. Хранение

Каждый персонаж хранится как (character_id, embedding_vector, metadata). Метаданные включают:

Хранилищем обычно служит векторная база (Pinecone, Qdrant, Weaviate) или кастомная индексированная структура. Lookups должны быть быстрыми sub-100ms потому что они происходят на каждой генерации.

Для приватно-чувствительных развёртываний embeddings можно хранить зашифрованными с per-tenant-ключами. Извлечение — это односторонняя функция (восстановить референсное изображение из embedding нельзя), но трактовать embeddings как PII — правильное значение по умолчанию для систем, обрабатывающих реальных людей.

3. Синтез negative prompts

Это неочевидная часть системы и место, где живёт большая часть инженерной работы.

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

Примеры из нашего каталога:

Режим дрейфаФрагмент negative prompt
Сдвиг цвета глаз (карий зелёный)«green eyes, hazel eyes» (когда референс — карий)
Сужение челюсти«narrow jaw, weak chin, soft jawline»
Отступление линии волос«high hairline, thinning hair, receding hairline»
Потепление тона кожи«warm skin tone, golden complexion» (когда референс холодный)
Наползание асимметрии«asymmetric face, uneven features»
Сдвиг расстояния между глазами«wide-set eyes, close-set eyes»

Построение этого каталога требует размеченных данных. Мы разметили ~10 000 генераций из публичных AI-инструментов для видео (Runway, Pika, Sora и др.) с конкретными режимами дрейфа, которые в них появлялись. Кластеризация дала ~30 различных режимов, покрывающих ~85% наблюдаемого дрейфа.

Для каждой генерации система:

  1. Извлекает референсные атрибуты персонажа
  2. Вычисляет «противоположное» каждого атрибута (например, если у референса тёмные глаза, противоположное — светлые)
  3. Строит per-character negative prompt, собирая релевантные drift suppressors

Результат — куда более сильный сигнал conditioning, чем при генерации только по промпту.

4. Внедрение в conditioning

Разные видеомодели принимают conditioning по-разному:

По нашему опыту, API-level injection гораздо эффективнее, чем reference-image-based, но большинство публичных API не открывают такой глубины доступа. Работая с поверхностью, доступной нам, мы обнаружили, что комбинация сильного negative prompt и reference-image-encoded embedding даёт 80–90% эффекта от API-level injection.

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

5. Генерация

Стандартное диффузионное сэмплирование с поправкой, что conditioning теперь — это комбинация:

Стоимость генерации обычно 1.0–1.2× стандартной. Маржинальная стоимость мала.

6. Проверка согласованности

После генерации мы запускаем отдельную identity-модель (обычно тот же face encoder из шага 1) против вывода. Вычисляем cosine similarity между identity embedding вывода и исходным референсным embedding.

Порог: обычно 0.85 cosine similarity. Выше порога — вывод принимается. Ниже — запускается регенерация со более жёстким conditioning (более сильный вес negative prompt, более сильное embedding injection).

Это добавляет ~5–10% стоимости генерации в среднем (большинство кадров проходят с первого раза) и не даёт худшим случаям дрейфа дойти до пользователя.

Что работает хорошо, а что нет

Что работает:

Что сложнее:

Открытые исследовательские проблемы

Если вы работаете в этой области, вот проблемы, решение которых нам было бы интересно увидеть:

  1. Инварианты вариантов формы. Какое правильное выученное представление захватывает инвариантную к идентичности структуру лица, при этом позволяя произвольные трансформации состояния?
  2. Активное обнаружение дрейфа во время сэмплирования. Текущие проверки согласованности — пост-фактум. Можем ли мы обнаруживать дрейф во время диффузии и корректировать в процессе?
  3. Тradeoff явная-vs-неявная идентичность. Когда обучение маленькой LoRA на персонажа превосходит embedding-based conditioning? Где граница?
  4. Моделирование взаимодействия нескольких персонажей. Как захватить не только две зафиксированные идентичности, но и их динамику отношений так, чтобы это держалось между кадрами?
  5. Количественная оценка неопределённости идентичности. Когда модель не уверена в идентичности, может ли она поверхностно показать эту неопределённость, а не выдавать уверенный дрейф?

Если вы работаете над чем-то из этого и хотите сравнить заметки, команде Juying искренне интересно. Пишите.

Практические советы для разработчиков

Если вы рассматриваете построение слоя согласованности персонажей для своего продукта, три совета:

1. Начните с каталога negative prompts. Это самая высокоэффективная и низкозатратная победа. Не нужен API-level доступ к модели; negative prompt открыт каждым публичным API. Потратьте неделю на разметку 1000 генераций, и у вас будет каталог, покрывающий большую часть дрейфа.

2. Не недооценивайте пост-проверку. Простой цикл «регенерируй, если similarity < 0.85» ловит худшие 10% сбоев и драматически улучшает воспринимаемое качество. Это самый дешёвый прирост качества с 90/100 95/100 из доступных.

3. Инвестируйте в хранилище рано. Character embeddings как постоянные ассеты — это архитектурное озарение, которое накапливается. Постройте правильные примитивы один раз, и любая будущая фича (style locks, библиотеки сцен, переиспользование ассетов) расширится естественно.

Связанное чтение

Если вы строите в этой области и хотите пообщаться info@juying.art