Как работает фиксация персонажа под капотом: технический разбор
Технический обзор архитектуры систем character embeddings: извлечение признаков, хранение, синтез negative prompts, conditioning, проверка согласованности и открытые проблемы.
Эта статья для инженеров — исследователей, 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. Извлечение признаков
При загрузке персонажа против референсного изображения запускают несколько специализированных моделей:
- Face encoder: ArcFace, FaceNet или аналог. Выдаёт 512-мерный identity embedding, оптимизированный для распознавания лиц. Захватывает инвариантные к идентичности признаки.
- Body parser: PIFu или Sapiens для пропорций тела и осанки. Низкоразмерный вектор, кодирующий рост, телосложение, осанку.
- Appearance encoder: CLIP image encoder для цвета волос, тона кожи, стиля одежды. 768-мерный семантический embedding.
- Style classifier: отдельно кодирует, является ли референс реалистичным, стилизованным, анимированным и т. д. Маленький категориальный вектор.
Они конкатенируются (или объединяются через attention) в высокоразмерный character embedding e_C. Общая размерность обычно 1500–3000.
Зачем несколько моделей вместо одной? Потому что у идентичности несколько осей, ни одну из которых отдельный энкодер не покрывает полностью. Энкодеры лиц отлично отвечают на вопрос «это то же лицо?», но игнорируют пропорции тела. Парсеры тела игнорируют детали лица. CLIP отлично работает с семантическим внешним видом, но теряет тонкую идентичность. Конкатенация даёт ортогональное покрытие.
Компромисс: более сложный конвейер извлечения означает больше compute при загрузке персонажа (~30–90 секунд в нашей системе). Для потребительских инструментов это нормально. Для высокопроизводительных конвейеров можно один раз предвычислить embeddings при загрузке и ссылаться на них при генерации.
2. Хранение
Каждый персонаж хранится как (character_id, embedding_vector, metadata). Метаданные включают:
- Исходное референсное изображение (для отладки и переэкстракции)
- Привязка к владельцу / проекту
- Указатели на под-варианты (подробнее в разделе про варианты формы)
- Style anchors (для кросс-стилевой работы)
- Override-список режимов дрейфа (кастомизации на персонажа)
Хранилищем обычно служит векторная база (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% наблюдаемого дрейфа.
Для каждой генерации система:
- Извлекает референсные атрибуты персонажа
- Вычисляет «противоположное» каждого атрибута (например, если у референса тёмные глаза, противоположное — светлые)
- Строит per-character negative prompt, собирая релевантные drift suppressors
Результат — куда более сильный сигнал conditioning, чем при генерации только по промпту.
4. Внедрение в conditioning
Разные видеомодели принимают conditioning по-разному:
- Reference-image-based-модели (большинство публичных API): можно передать референсное изображение; мы кодируем embedding обратно в «синтетическое референсное изображение» через выученную проекцию и передаём его.
- Text-only conditioning: передаём выученную soft-prompt-проекцию embedding.
- API-level доступ к модели (когда доступен): внедряем embedding напрямую в cross-attention-слои, аналогично IP-Adapter conditioning.
По нашему опыту, API-level injection гораздо эффективнее, чем reference-image-based, но большинство публичных API не открывают такой глубины доступа. Работая с поверхностью, доступной нам, мы обнаружили, что комбинация сильного negative prompt и reference-image-encoded embedding даёт 80–90% эффекта от API-level injection.
Отчасти поэтому строить слой согласованности персонажей имеет смысл, даже когда вы не контролируете нижележащую модель — в поверхности conditioning, уже открытой публичными API, есть значительный запас.
5. Генерация
Стандартное диффузионное сэмплирование с поправкой, что conditioning теперь — это комбинация:
- Исходного промпта (сцена, действие, кадрирование)
- Character embedding (внедрённого через механизм выше)
- Negative prompt (автосинтезированного)
- Style anchor (если применимо для сегмента)
Стоимость генерации обычно 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% стоимости генерации в среднем (большинство кадров проходят с первого раза) и не даёт худшим случаям дрейфа дойти до пользователя.
Что работает хорошо, а что нет
Что работает:
- 30+ кадров одного персонажа с высокой согласованностью на стандартных вариациях сцены
- Переиспользование библиотеки персонажей между проектами (одна экстракция, бесконечное переиспользование)
- Кросс-платформенная согласованность (тот же character_id, та же идентичность в разных сценах/стилях в разумных пределах)
- Сцены с несколькими персонажами с различимыми чертами (разный возраст, пол, этничность)
Что сложнее:
- Варианты формы: тот же персонаж, но раненый, постаревший, в другой одежде. Используем sub-embeddings, ключевые относительно мастера, где мастер кодирует инвариантную идентичность, а sub — дельту. Работает для умеренной вариации; ломается на крупных трансформациях (например, 8-летняя версия того же персонажа).
- Смешивание идентичностей в многоперсонажных сценах: когда два зафиксированных персонажа делят кадр и имеют похожие черты (обе 30-летние азиатские женщины, например), около 10% генераций показывают частичное смешивание признаков.
- Кросс-стилевая согласованность: зафиксированный реалистичный персонаж в стилизованном «акварельном» сегменте. Решается частично через per-segment style anchors, но деградация заметна.
- Животные / нечеловеческие персонажи: та же архитектура применима, но качество face encoder резко падает за пределами человеческих лиц.
- Согласованность длинной формы за пределами ~3 минут: подавление дрейфа работает покадрово, но накопленные тонкие различия на 50+ кадрах могут давать минорные видимые несоответствия для внимательного зрителя.
Открытые исследовательские проблемы
Если вы работаете в этой области, вот проблемы, решение которых нам было бы интересно увидеть:
- Инварианты вариантов формы. Какое правильное выученное представление захватывает инвариантную к идентичности структуру лица, при этом позволяя произвольные трансформации состояния?
- Активное обнаружение дрейфа во время сэмплирования. Текущие проверки согласованности — пост-фактум. Можем ли мы обнаруживать дрейф во время диффузии и корректировать в процессе?
- Тradeoff явная-vs-неявная идентичность. Когда обучение маленькой LoRA на персонажа превосходит embedding-based conditioning? Где граница?
- Моделирование взаимодействия нескольких персонажей. Как захватить не только две зафиксированные идентичности, но и их динамику отношений так, чтобы это держалось между кадрами?
- Количественная оценка неопределённости идентичности. Когда модель не уверена в идентичности, может ли она поверхностно показать эту неопределённость, а не выдавать уверенный дрейф?
Если вы работаете над чем-то из этого и хотите сравнить заметки, команде Juying искренне интересно. Пишите.
Практические советы для разработчиков
Если вы рассматриваете построение слоя согласованности персонажей для своего продукта, три совета:
1. Начните с каталога negative prompts. Это самая высокоэффективная и низкозатратная победа. Не нужен API-level доступ к модели; negative prompt открыт каждым публичным API. Потратьте неделю на разметку 1000 генераций, и у вас будет каталог, покрывающий большую часть дрейфа.
2. Не недооценивайте пост-проверку. Простой цикл «регенерируй, если similarity < 0.85» ловит худшие 10% сбоев и драматически улучшает воспринимаемое качество. Это самый дешёвый прирост качества с 90/100 → 95/100 из доступных.
3. Инвестируйте в хранилище рано. Character embeddings как постоянные ассеты — это архитектурное озарение, которое накапливается. Постройте правильные примитивы один раз, и любая будущая фича (style locks, библиотеки сцен, переиспользование ассетов) расширится естественно.
Связанное чтение
- Согласованность персонажей в AI-видео: полное руководство 2026
- Что такое дрейф персонажа в AI-видео?
- Runway против Pika против Sora против Juying: сравнение инструментов
Если вы строите в этой области и хотите пообщаться — info@juying.art