# ControlNet

Овладейте ControlNet для точного контроля генерации изображений ИИ.

{% hint style="success" %}
Все примеры можно запускать на GPU-серверах, арендуемых через [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Аренда на CLORE.AI

1. Посетите [CLORE.AI Marketplace](https://clore.ai/marketplace)
2. Отфильтруйте по типу GPU, объему VRAM и цене
3. Выберите **On-Demand** (фиксированная ставка) или **Spot** (цена по ставке)
4. Настройте ваш заказ:
   * Выберите Docker-образ
   * Установите порты (TCP для SSH, HTTP для веб-интерфейсов)
   * Добавьте переменные окружения при необходимости
   * Введите команду запуска
5. Выберите способ оплаты: **CLORE**, **BTC**, или **USDT/USDC**
6. Создайте заказ и дождитесь развертывания

### Доступ к вашему серверу

* Найдите данные для подключения в **Моих заказах**
* Веб-интерфейсы: используйте URL HTTP-порта
* SSH: `ssh -p <port> root@<proxy-address>`

## Что такое ControlNet?

ControlNet добавляет условный контроль к Stable Diffusion:

* **Canny** - Обнаружение краев
* **Depth** - 3D-карты глубины
* **Pose** - Пози человека
* **Scribble** - Черновые наброски
* **Segmentation** - Семантические маски
* **Line Art** - Чистые линии
* **IP-Adapter** - Перенос стиля

## Требования

| Тип контроля         | Мин. VRAM | Рекомендуется |
| -------------------- | --------- | ------------- |
| Один ControlNet      | 8GB       | RTX 3070      |
| Несколько ControlNet | 12GB      | RTX 3090      |
| SDXL ControlNet      | 16GB      | RTX 4090      |

## Быстрое развертывание с A1111

**Команда:**

```bash
cd /workspace/stable-diffusion-webui && \
cd extensions && \
git clone https://github.com/Mikubill/sd-webui-controlnet && \
cd .. && \
python launch.py --listen --enable-insecure-extension-access
```

### Загрузка моделей

```bash
cd /workspace/stable-diffusion-webui/extensions/sd-webui-controlnet/models

# ControlNet для SD 1.5
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_canny.pth
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11f1p_sd15_depth.pth
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_openpose.pth
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_scribble.pth
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_lineart.pth
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_softedge.pth
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_seg.pth

# ControlNet для SDXL
wget https://huggingface.co/diffusers/controlnet-canny-sdxl-1.0/resolve/main/diffusion_pytorch_model.safetensors -O controlnet-canny-sdxl.safetensors
```

## Python с Diffusers

### Контроль краев Canny

```python
import torch
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
from diffusers.utils import load_image
from controlnet_aux import CannyDetector
import cv2
import numpy as np

# Загрузить ControlNet
controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11p_sd15_canny",
    torch_dtype=torch.float16
)

# Загрузить pipeline
pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=torch.float16
)
pipe.to("cuda")
pipe.enable_model_cpu_offload()

# Подготовить управляющее изображение
image = load_image("input.jpg")
canny = CannyDetector()
control_image = canny(image)

# Генерация
output = pipe(
    prompt="красивая женщина в саду, высокое качество",
    negative_prompt="уродливый, размытый",
    image=control_image,
    num_inference_steps=30,
    controlnet_conditioning_scale=1.0
).images[0]

output.save("canny_output.png")
```

### Контроль глубины

```python
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
from controlnet_aux import MidasDetector
import torch

controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11f1p_sd15_depth",
    torch_dtype=torch.float16
)

pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=torch.float16
).to("cuda")

# Получить карту глубины
depth_estimator = MidasDetector.from_pretrained("lllyasviel/Annotators")
depth_image = depth_estimator(image)

# Генерация с учетом глубины
output = pipe(
    prompt="футуристический город, научная фантастика, детализированно",
    image=depth_image,
    num_inference_steps=30
).images[0]
```

### OpenPose (позы человека)

```python
from controlnet_aux import OpenposeDetector

# Получить позу
pose_detector = OpenposeDetector.from_pretrained("lllyasviel/Annotators")
pose_image = pose_detector(image)

controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11p_sd15_openpose",
    torch_dtype=torch.float16
)

pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=torch.float16
).to("cuda")

output = pipe(
    prompt="балерина танцует, элегантно, студийное освещение",
    image=pose_image,
    num_inference_steps=30
).images[0]
```

### Scribble/Эскиз

```python
from controlnet_aux import HEDdetector

# Обнаружить края как набросок
hed = HEDdetector.from_pretrained("lllyasviel/Annotators")
scribble_image = hed(image, scribble=True)

controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11p_sd15_scribble",
    torch_dtype=torch.float16
)

pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=torch.float16
).to("cuda")

output = pipe(
    prompt="детализированная картина пейзажа",
    image=scribble_image,
    num_inference_steps=30
).images[0]
```

## Много- ControlNet

Комбинировать несколько контролей:

```python
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import torch

# Загрузить несколько ControlNet
controlnet_canny = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11p_sd15_canny",
    torch_dtype=torch.float16
)

controlnet_depth = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11f1p_sd15_depth",
    torch_dtype=torch.float16
)

# Создать конвейер с несколькими ControlNet
pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=[controlnet_canny, controlnet_depth],
    torch_dtype=torch.float16
).to("cuda")

# Генерация с несколькими контролями
output = pipe(
    prompt="красивый портрет",
    image=[canny_image, depth_image],
    controlnet_conditioning_scale=[1.0, 0.8],  # Настроить веса
    num_inference_steps=30
).images[0]
```

## SDXL ControlNet

```python
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel
from controlnet_aux import CannyDetector
import torch

# Загрузить SDXL ControlNet
controlnet = ControlNetModel.from_pretrained(
    "diffusers/controlnet-canny-sdxl-1.0",
    torch_dtype=torch.float16
)

pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    controlnet=controlnet,
    torch_dtype=torch.float16
).to("cuda")

# Подготовить изображение canny
canny = CannyDetector()
control_image = canny(image, low_threshold=100, high_threshold=200)

output = pipe(
    prompt="профессиональная фотография, детализированно, 8k",
    image=control_image,
    controlnet_conditioning_scale=0.5,
    num_inference_steps=30
).images[0]
```

## IP-Adapter (перенос стиля)

```python
from diffusers import StableDiffusionPipeline
from transformers import CLIPVisionModelWithProjection
import torch

# Загрузить IP-Adapter
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16
).to("cuda")

pipe.load_ip_adapter(
    "h94/IP-Adapter",
    subfolder="models",
    weight_name="ip-adapter_sd15.bin"
)

pipe.set_ip_adapter_scale(0.6)

# Изображение-референс стиля
style_image = load_image("style_reference.jpg")

output = pipe(
    prompt="кот сидит на стуле",
    ip_adapter_image=style_image,
    num_inference_steps=30
).images[0]
```

## Препроцессоры

Все доступные препроцессоры:

```python
from controlnet_aux import (
    CannyDetector,           # Обнаружение краев
    HEDdetector,             # Мягкие края/набросок
    MidasDetector,           # Оценка глубины
    OpenposeDetector,        # Поза человека
    MLSDdetector,            # Обнаружение линий
    LineartDetector,         # Линейная графика
    LineartAnimeDetector,    # Аниме-линарт
    NormalBaeDetector,       # Карты нормалей
    ContentShuffleDetector,  # Перемешивание содержимого
    ZoeDetector,             # Улучшенная глубина
    MediapipeFaceDetector,   # Сетка лица
)

# Пример использования
canny = CannyDetector()
canny_image = canny(image, low_threshold=100, high_threshold=200)

depth = MidasDetector.from_pretrained("lllyasviel/Annotators")
depth_image = depth(image)

pose = OpenposeDetector.from_pretrained("lllyasviel/Annotators")
pose_image = pose(image, hand_and_face=True)
```

## Веса контроля

Отрегулируйте влияние для каждого ControlNet:

```python

# Полный контроль
output = pipe(..., controlnet_conditioning_scale=1.0)

# Частичный контроль (больше творческой свободы)
output = pipe(..., controlnet_conditioning_scale=0.5)

# Очень слабое руководство
output = pipe(..., controlnet_conditioning_scale=0.3)
```

### Контроль по шагам

```python

# Контролировать только в определенные шаги
output = pipe(
    prompt="...",
    image=control_image,
    controlnet_conditioning_scale=1.0,
    control_guidance_start=0.0,  # Начать с начала
    control_guidance_end=0.5,    # Остановиться на 50% шагов
    num_inference_steps=30
).images[0]
```

## Инпейнтинг с ControlNet

```python
from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel
import torch

controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11p_sd15_canny",
    torch_dtype=torch.float16
)

pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=torch.float16
).to("cuda")

output = pipe(
    prompt="красный спортивный автомобиль",
    image=init_image,
    mask_image=mask,
    control_image=canny_image,
    num_inference_steps=30
).images[0]
```

## Пакетная обработка

```python
import os
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
from controlnet_aux import CannyDetector
from PIL import Image
import torch

controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11p_sd15_canny",
    torch_dtype=torch.float16
)

pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=torch.float16
).to("cuda")

canny = CannyDetector()

input_dir = "./inputs"
output_dir = "./outputs"
os.makedirs(output_dir, exist_ok=True)

prompt = "красивая пейзажная картина, детализированная, художественная"

for filename in os.listdir(input_dir):
    if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
        image = Image.open(os.path.join(input_dir, filename))
        control_image = canny(image)

        output = pipe(
            prompt=prompt,
            image=control_image,
            num_inference_steps=30
        ).images[0]

        output.save(os.path.join(output_dir, f"cn_{filename}"))
```

## Руководство по типам контроля

| Контроль | Лучше всего для       | Сильная сторона |
| -------- | --------------------- | --------------- |
| Canny    | Архитектура, объекты  | 0.8-1.0         |
| Depth    | 3D-сцены, перспектива | 0.6-0.8         |
| Pose     | Люди, персонажи       | 0.8-1.0         |
| Scribble | Эскизы, концепты      | 0.6-0.8         |
| Line Art | Иллюстрации           | 0.7-0.9         |
| Softedge | Общее руководство     | 0.5-0.7         |
| Seg      | Композиция сцены      | 0.6-0.8         |

## Производительность

| Настройка          | GPU      | Разрешение | Время |
| ------------------ | -------- | ---------- | ----- |
| Один CN SD1.5      | RTX 3090 | 512x512    | \~3s  |
| Несколько CN SD1.5 | RTX 3090 | 512x512    | \~5 с |
| Один CN SDXL       | RTX 4090 | 1024x1024  | \~8s  |

## Оптимизация памяти

```python

# Включить память-эффективное внимание
pipe.enable_xformers_memory_efficient_attention()

# Выгрузка на CPU
pipe.enable_model_cpu_offload()

# Разбиение внимания
pipe.enable_attention_slicing()
```

## Устранение неполадок

### Слабый эффект контроля

* Увеличьте `controlnet_conditioning_scale`
* Проверьте качество вывода препроцессора
* Используйте управляющее изображение более высокого разрешения

### Артефакты

* Уменьшите масштаб контроля
* Используйте более мягкий препроцессор (softedge вместо canny)
* Добавьте негативный prompt для артефактов

### Проблемы с VRAM

* Используйте выгрузку на CPU
* Уменьшить разрешение
* Используйте по одному ControlNet за раз

## Оценка стоимости

Типичные ставки на маркетплейсе CLORE.AI (по состоянию на 2024):

| GPU       | Почасовая ставка | Дневная ставка | Сессия 4 часа |
| --------- | ---------------- | -------------- | ------------- |
| RTX 3060  | \~$0.03          | \~$0.70        | \~$0.12       |
| RTX 3090  | \~$0.06          | \~$1.50        | \~$0.25       |
| RTX 4090  | \~$0.10          | \~$2.30        | \~$0.40       |
| A100 40GB | \~$0.17          | \~$4.00        | \~$0.70       |
| A100 80GB | \~$0.25          | \~$6.00        | \~$1.00       |

*Цены варьируются в зависимости от провайдера и спроса. Проверьте* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *для текущих тарифов.*

**Экономьте деньги:**

* Используйте **Spot** рынок для гибких рабочих нагрузок (часто на 30–50% дешевле)
* Платите с помощью **CLORE** токенов
* Сравнивайте цены у разных провайдеров

## Дальнейшие шаги

* Stable Diffusion WebUI
* Рабочие процессы ComfyUI
* [Обучение Kohya](https://docs.clore.ai/guides/guides_v2-ru/obuchenie/kohya-training)
