Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
ControlNet и LoRA: расширения для генеративных моделей
Контекст: почему нужны ControlNet и LoRA
Основные генеративные модели (Stable Diffusion, DALL-E) требуют дорогого обучения или fine-tuning на большом количестве видеокарт. ControlNet и LoRA позволяют адаптировать модели с минимальными ресурсами.
LoRA (Low-Rank Adaptation)
LoRA — это способ эффективного fine-tuning через добавление небольших параметризованных слоёв.
Как работает LoRA
Вместо обновления всех весов модели (огромное количество параметров), LoRA добавляет низкоранговую матрицу к каждому слою:
W' = W + ΔW
где ΔW = A × B^T
A: (d, r), B: (d, r), r << d
Вместо обновления d×d матрицы, обновляем 2×d×r параметров. Если d=10000, r=8, то экономия: 100M параметров → 160K параметров!
import torch
import torch.nn as nn
class LoRALinear(nn.Module):
def __init__(self, in_features, out_features, rank=8):
super().__init__()
self.linear = nn.Linear(in_features, out_features)
# LoRA матрицы
self.lora_A = nn.Linear(in_features, rank, bias=False)
self.lora_B = nn.Linear(rank, out_features, bias=False)
self.scale = 1.0
nn.init.kaiming_uniform_(self.lora_A.weight)
nn.init.zeros_(self.lora_B.weight)
def forward(self, x):
base = self.linear(x)
lora = self.lora_B(self.lora_A(x)) * self.scale
return base + lora
# Использование
model = LoRALinear(10000, 10000, rank=8)
x = torch.randn(32, 10000)
output = model(x)
Применение LoRA в Stable Diffusion
from diffusers import StableDiffusionPipeline
import torch
# Загружаем базовую модель
pipe = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16
).to("cuda")
# Загружаем LoRA адаптер
pipe.load_lora_weights("path/to/lora_weights", weight_name="model.safetensors")
# Генерируем изображение
prompt = "a photo of a cat wearing sunglasses"
image = pipe(prompt, num_inference_steps=50).images[0]
Преимущества LoRA
✓ Экономия памяти: 100x меньше параметров
✓ Быстрое обучение: может обучиться за часы на одной GPU
✓ Лёгкое переключение: один файл ~40-100 MB вместо 4 GB
✓ Комбинируется: несколько LoRA можно использовать одновременно
✓ Портативность: работает со многими моделями
Недостатки
✗ Меньше гибкости чем полный fine-tuning
✗ Требует выбора ранга r
✗ Может работать хуже на очень специфичных задачах
ControlNet
ControlNet — это техника для добавления spatial контроля к генеративным моделям.
Вместо простого текстового prompt, ControlNet позволяет добавить:
- Sketch (силуэт)
- Pose (поза человека)
- Depth map (карта глубины)
- Canny edges (контуры)
- Optical flow и т.д.
Архитектура ControlNet
ControlNet добавляет extra U-Net, которая учит пространственные условия:
Text Prompt → CLIP → Token Embeddings
↓
[U-Net]
↙ ↓ ↘
ControlNet (скопированная U-Net)
↓
Condition Image (sketch/pose/depth)
↓
Spatial Conditioning
↓
Generated Image (управляемое)
Использование ControlNet в Stable Diffusion
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
from PIL import Image
import torch
# Загружаем ControlNet (например, для sketch)
controlnet = ControlNetModel.from_pretrained(
"lllyasviel/sd-controlnet-scribble",
torch_dtype=torch.float16
)
pipe = StableDiffusionControlNetPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
controlnet=controlnet,
torch_dtype=torch.float16
).to("cuda")
# Загружаем изображение с наброском
sketch = Image.open("sketch.png").convert("RGB")
sketch = sketch.resize((512, 512))
# Генерируем с контролем
prompt = "a beautiful landscape oil painting"
image = pipe(
prompt,
image=sketch,
num_inference_steps=50,
guidance_scale=7.5
).images[0]
Типы ControlNet
| Type | Input | Использование |
|---|---|---|
| Scribble | Наброски | Быстрое рисование |
| Pose | Позы людей (KeyPoints) | Контроль позы персонажа |
| Depth | Карта глубины | Контроль композиции |
| Canny | Контуры образов | Архитектура, объекты |
| Normal | Карты нормалей | Текстуры, объёмные объекты |
| Semantic | Семантическая сегментация | Конкретные области |
| Tile | Тайлинг | Генерация больших изображений |
Примеры типов ControlNet
# Пример 1: Pose Control
from controlnet_aux import OpenposeDetector
openpose = OpenposeDetector.from_pretrained(
"lllyasviel/ControlNet-pose",
cache_dir="./pretrained_weights"
)
# Извлекаем позу из эталонного изображения
reference_image = Image.open("person.jpg")
pose = openpose(reference_image)
# Применяем к новому человеку с той же позой
pipe = StableDiffusionControlNetPipeline.from_pretrained(...)
image = pipe(
"a person in stylized anime",
image=pose,
num_inference_steps=50
).images[0]
# Пример 2: Depth Control
from diffusers.utils import load_image
from transformers import DPTImageProcessor, DPTForDepthEstimation
processor = DPTImageProcessor.from_pretrained("Intel/dpt-large")
model = DPTForDepthEstimation.from_pretrained("Intel/dpt-large")
image = load_image("scene.jpg")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
predicted_depth = outputs.predicted_depth
depth_image = predicted_depth[0].unsqueeze(0).unsqueeze(0)
Преимущества ControlNet
✓ Точный пространственный контроль
✓ Может комбинироваться (несколько ControlNet одновременно)
✓ Работает со всеми моделями (не нужен переобучение)
✓ Интуитивно — feed изображение с условием
✓ Высокое качество результатов
Недостатки
✗ Требует подготовки condition images
✗ Вычислительно дороже (extra U-Net)
✗ Требует точности condition (плохой sketch → плохой результат)
Сравнение LoRA и ControlNet
| Параметр | LoRA | ControlNet |
|---|---|---|
| Назначение | Fine-tuning стиля/содержания | Пространственный контроль |
| Входные данные | Текст + веса модели | Текст + изображение условия |
| Параметры | ~100K - 1M | ~10M (дополнительно) |
| Время обучения | Часы на одной GPU | Дни (но дают готовые) |
| Использование | Обучение новых стилей | Направление генерации |
| Комбинирование | Да (несколько LoRA) | Да (несколько Control) |
| Результат | Определённый стиль | Контролируемая форма/поза |
Практический пример: Комбинация LoRA + ControlNet
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import torch
# 1. Загружаем базовую модель + ControlNet (Pose)
controlnet = ControlNetModel.from_pretrained(
"lllyasviel/sd-controlnet-openpose"
)
pipe = StableDiffusionControlNetPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
controlnet=controlnet
)
# 2. Загружаем LoRA (например, стиль аниме)
pipe.load_lora_weights("anime_style_lora")
# 3. Используем оба вместе
pose_image = Image.open("pose.png").resize((512, 512))
image = pipe(
"anime girl, beautiful face, detailed",
image=pose_image,
num_inference_steps=50,
guidance_scale=7.5
).images[0]
# Результат: аниме стиль (LoRA) + контролируемая поза (ControlNet)
Итого
LoRA — лёгкий способ адаптировать модель к новому стилю/содержанию с минимальными ресурсами.
ControlNet — способ добавить пространственный контроль над генерацией (поза, глубина, контуры).
Вместе они позволяют точно контролировать как содержание (стиль), так и форму (геометрию) сгенерированного изображения.
Оба метода революционизировали текст-в-изображение генерацию, сделав её более практичной и управляемой.