Введение: зачем обучать ControlNet самостоятельно?
ControlNet решает задачу композиционного контроля в Stable Diffusion. Готовая модель принимает на вход conditioning-изображение: карту глубины, скелет, контур Canny или сегментационную маску. На выходе вы получаете генерацию, которая повторяет заданную структуру. Проблема в том, что публичные ControlNet-модели покрывают ограниченный набор условий. Если ваша задача требует специфической разметки, например, управления мимикой лица по 68 ключевым точкам, готового решения нет. Его нужно обучать.
В этом материале разобран полный цикл: от планирования условия до запуска обучения скриптами diffusers. В качестве практического кейса взята модель Uncanny Faces, обученная для контроля лицевых ориентиров. Вы узнаете, как собрать датасет, сгенерировать капшоны через BLIP, конвертировать разметку в формат ControlNet и подобрать гиперпараметры под GPU с памятью 8, 12 или 16 ГБ. В конце разобраны типичные ошибки, включая переобучение.
Для базового понимания пайплайна рекомендую сначала прочитать гайд по ControlNet в Diffusers. Там разобраны препроцессоры, комбинирование нескольких ControlNet и связка с DreamBooth.
Планирование условия (conditioning) для ControlNet
Conditioning в ControlNet - это изображение или тензор, который задаёт пространственную структуру будущей генерации. Во время обучения модель учится связывать этот сигнал с латентным пространством Stable Diffusion. Выбор условия определяет, что именно вы сможете контролировать на инференсе.
Типы условий и их применение
- Скелетные точки (pose). Подходят для контроля позы человека или животного. Используются в задачах генерации персонажей, анимации, переноса движения.
- Карты глубины (depth). Передают расстояние до объектов. Полезны для архитектурной визуализации, интерьеров, сцен с выраженной перспективой.
- Карты нормалей (normal). Кодируют ориентацию поверхностей. Применяются для детализации рельефа, материалов, 3D-стилизации.
- Сегментационные маски. Размечают области по классам объектов. Удобны для контролируемой замены текстур, фона, отдельных элементов сцены.
- Контуры Canny. Выделяют границы объектов. Хороши для переноса композиции из эскиза или фотографии в новый стиль.
Кейс Uncanny Faces: выбор условия
Для Uncanny Faces выбраны ключевые точки лица, face landmarks. Это 68 координат, описывающих контуры глаз, бровей, носа, губ и овала лица. Такое условие позволяет управлять мимикой и поворотом головы при генерации портретов. Альтернативы вроде карт глубины или Canny дают слишком грубый контроль: они не различают улыбку и нейтральное выражение. Ключевые точки решают эту задачу напрямую.
При выборе условия руководствуйтесь одним критерием: оно должно однозначно кодировать тот аспект изображения, который вы хотите контролировать. Если условие допускает множественные интерпретации, модель будет обучаться дольше и давать менее стабильный результат.
Сбор и подготовка датасета
Датасет для ControlNet состоит из пар: исходное изображение и соответствующее ему conditioning-изображение. Для Uncanny Faces это портреты и heatmap-карты с ключевыми точками лица. Требования к данным: разрешение от 512x512 пикселей, разнообразие ракурсов, освещения и выражений лиц. Однородный датасет из 500 изображений даст лучший результат, чем 5000 почти одинаковых кадров.
Генерация капшенов с помощью BLIP
ControlNet обучается совместно с текстовым энкодером Stable Diffusion, поэтому каждому изображению нужен текстовый капшон. Ручная разметка тысяч изображений непрактична. BLIP автоматизирует этот процесс. Модель принимает изображение и возвращает описание на естественном языке.
from transformers import BlipProcessor, BlipForConditionalGeneration
from PIL import Image
processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base")
image = Image.open("portrait_001.jpg").convert("RGB")
inputs = processor(image, return_tensors="pt")
out = model.generate(**inputs, max_length=75)
caption = processor.decode(out[0], skip_special_tokens=True)
print(caption)
# "a woman with long hair smiling at the camera"Качество капшонов BLIP достаточное для базового обучения, но для тонкого контроля стиля или специфических атрибутов требуется ручная корректировка. В датасете Uncanny Faces часть описаний была отредактирована вручную: добавлены указания на эмоции, ракурс и освещение. Это повысило управляемость модели на инференсе.
Конвертация разметки в формат для обучения
ControlNet ожидает conditioning-изображение в том же разрешении, что и исходное. Координаты ключевых точек необходимо преобразовать в heatmap или скелетное изображение. Для 68 точек лица стандартный подход - отрисовка линий между связанными точками и кругов в позициях точек.
import numpy as np
import cv2
def landmarks_to_heatmap(landmarks, size=(512, 512), radius=3):
heatmap = np.zeros(size, dtype=np.uint8)
connections = [
(0, 1), (1, 2), (2, 3), (3, 4), # контур бровей
(36, 37), (37, 38), (38, 39), (39, 40), (40, 41), (41, 36), # левый глаз
(42, 43), (43, 44), (44, 45), (45, 46), (46, 47), (47, 42), # правый глаз
(48, 49), (49, 50), (50, 51), (51, 52), (52, 53), (53, 54), (54, 55), (55, 56), (56, 57), (57, 48) # губы
]
for start, end in connections:
pt1 = (int(landmarks[start][0] * size[0]), int(landmarks[start][1] * size[1]))
pt2 = (int(landmarks[end][0] * size[0]), int(landmarks[end][1] * size[1]))
cv2.line(heatmap, pt1, pt2, 255, 1)
for point in landmarks:
center = (int(point[0] * size[0]), int(point[1] * size[1]))
cv2.circle(heatmap, center, radius, 255, -1)
return heatmapРезультат сохраняется как одноканальное изображение. На этапе обучения ControlNet сам преобразует его в тензор нужной размерности. Важно, чтобы разметка была консистентной: одинаковые правила отрисовки для всех изображений датасета.
Запуск обучения с помощью diffusers
Библиотека diffusers предоставляет скрипт train_controlnet.py, который покрывает стандартный сценарий обучения. Он поддерживает загрузку датасета из папки или через Hugging Face datasets, автоматическую аугментацию и сохранение чекпоинтов.
accelerate launch train_controlnet.py \
--pretrained_model_name_or_path="runwayml/stable-diffusion-v1-5" \
--output_dir="./controlnet-uncanny-faces" \
--dataset_name="./uncanny_faces_dataset" \
--conditioning_image_column="conditioning_image" \
--image_column="image" \
--caption_column="text" \
--resolution=512 \
--learning_rate=1e-5 \
--train_batch_size=4 \
--gradient_accumulation_steps=4 \
--mixed_precision="fp16" \
--num_train_epochs=50 \
--checkpointing_steps=500Скрипт замораживает веса UNet из Stable Diffusion и обучает только добавленные слои ControlNet. Это снижает требования к памяти и ускоряет сходимость. Базовую модель можно заменить на любую совместимую, например, на сжатую версию. О дистилляции Stable Diffusion с сокращением параметров на 35-55% читайте в разборе Segmind SD-Small и SD-Tiny.
Настройка гиперпараметров для GPU с разным объёмом памяти
Обучение ControlNet на GPU с 8 ГБ памяти возможно, но требует аккуратной настройки. Ниже приведены проверенные конфигурации для трёх типов видеокарт.
| Параметр | 8 ГБ VRAM | 12 ГБ VRAM | 16 ГБ VRAM |
|---|---|---|---|
| train_batch_size | 1 | 2 | 4 |
| gradient_accumulation_steps | 16 | 8 | 4 |
| mixed_precision | fp16 | fp16 | fp16 |
| resolution | 256 | 384 | 512 |
| use_8bit_adam | true | true | false |
| learning_rate | 5e-6 | 1e-5 | 1e-5 |
При 8 ГБ памяти снижение разрешения до 256 пикселей обязательно. Это ухудшает детализацию, но позволяет завершить обучение. Gradient accumulation компенсирует малый batch size: эффективный размер батча остаётся сопоставимым с конфигурацией для 16 ГБ.
Мониторинг обучения и предотвращение переобучения
Переобучение ControlNet проявляется в том, что модель начинает игнорировать текстовый промпт и воспроизводит conditioning-изображение слишком буквально. На кривых потерь это выглядит как продолжающееся снижение train loss при росте validation loss. Отслеживайте обе метрики с первого эпохи.
Для предотвращения переобучения используйте три инструмента. Первый - валидационный набор из 50-100 пар, не участвующих в обучении. Второй - early stopping: останавливайте обучение, если validation loss не улучшается 10 эпох подряд. Третий - dropout в слоях ControlNet. Значение 0.1-0.2 достаточно для датасетов до 1000 изображений. Для больших датасетов регуляризация обычно не требуется.
Кейс Uncanny Faces: от обучения до результата
Модель Uncanny Faces обучалась на датасете из 1200 портретов с разметкой 68 ключевых точек лица. Капшоны сгенерированы BLIP и частично отредактированы вручную. Обучение проходило на GPU с 16 ГБ памяти, разрешение 512 пикселей, batch size 4, gradient accumulation 4, learning rate 1e-5. Полный цикл занял 50 эпох, около 6 часов на одной видеокарте.
После обучения модель стабильно воспроизводит мимику и поворот головы, заданные через heatmap. При промпте «portrait of a woman, neutral expression, studio lighting» и нейтральной разметке генерация соответствует ожиданию. При изменении разметки на улыбку модель меняет выражение лица, сохраняя остальные атрибуты сцены. Ограничение: модель хуже работает с сильными ракурсами, которых было мало в датасете. Для таких случаев требуется расширение обучающей выборки.
Типичные ошибки и как их избежать
Переобучение. Модель копирует conditioning-изображение и игнорирует текст. Решение: валидационный набор, early stopping, dropout 0.1-0.2.
Недостаточное разнообразие датасета. Модель не обобщает на новые ракурсы или освещение. Решение: собирать данные из разных источников, использовать аугментацию по яркости и контрасту.
Неправильная подготовка условия. Разметка не совпадает с изображением или отрисована с разными правилами. Решение: автоматизировать конвертацию, проверять случайные пары вручную.
Нехватка памяти GPU. Ошибки CUDA out of memory при запуске. Решение: снизить разрешение, batch size, включить 8-bit Adam и gradient accumulation.
Слишком высокий learning rate. Потери расходятся на первых эпохах. Решение: начать с 1e-5, при нестабильности снизить до 5e-6.
Заключение: следующие шаги
Обучение собственной ControlNet-модели - это последовательность из четырёх шагов: выбор условия, сбор датасета, запуск обучения, валидация. Кейс Uncanny Faces показывает, что при 1200 изображениях и 6 часах обучения на 16 ГБ GPU можно получить модель, которая точно управляет мимикой лица. Для старта с меньшими ресурсами используйте конфигурацию для 8 ГБ с разрешением 256 пикселей.
Дальнейшие направления: комбинирование нескольких ControlNet для одновременного контроля позы и сегментации, дообучение через LoRA для стилевой адаптации, использование сжатых базовых моделей для ускорения инференса. Если вы работаете с LLM и агентными системами, обратите внимание на Governance-стек для агентной разработки и анализ evaluation awareness в model card.