Diffusers documentation

Инпейнтинг

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.42.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Инпейнтинг

Inpainting заменяет или редактирует определённые области изображения. Это делает его полезным инструментом для восстановления изображений, например, для удаления дефектов и артефактов, или даже для замены области изображения чем-то совершенно новым. Inpainting опирается на маску, чтобы определить, какие области изображения необходимо заполнить; область для inpainting представлена белыми пикселями, а область, которую нужно сохранить, — чёрными пикселями. Белые пиксели заполняются на основе промпта.

С помощью 🤗 Diffusers выполнить inpainting можно так:

  1. Загрузите контрольную точку для инпейнтинга с помощью класса AutoPipelineForInpainting. Он автоматически определит подходящий класс пайплайна для загрузки на основе контрольной точки:
import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "kandinsky-community/kandinsky-2-2-decoder-inpaint", dtype=torch.float16
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

В ходе выполнения руководства вы заметите, что мы используем enable_model_cpu_offload() и enable_xformers_memory_efficient_attention(), чтобы экономить память и увеличивать скорость инференса. Если вы используете PyTorch 2.0, нет необходимости вызывать enable_xformers_memory_efficient_attention() для вашего пайплайна, так как он уже использует нативный scaled-dot product attention из PyTorch 2.0.

  1. Загрузите базовое и маскирующее изображения:
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")
  1. Создайте промпт для инпейнтинга изображения и передайте его в пайплайн вместе с базовым изображением и маской:
prompt = "a black cat with glowing eyes, cute, adorable, disney, pixar, highly detailed, 8k"
negative_prompt = "bad anatomy, deformed, ugly, disfigured"
image = pipeline(prompt=prompt, negative_prompt=negative_prompt, image=init_image, mask_image=mask_image).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)
базовый образ
маска изображения
сгенерированное изображение

Создание изображения маски

Весь текст этого руководства содержит примеры кода, в которых для удобства используется изображение маски. Вы можете выполнять инпейнтинг на собственных изображениях, но для этого потребуется создать изображение маски. Используйте Space ниже, чтобы легко создать изображение маски.

Загрузите базовое изображение для инпейнтинга и используйте инструмент «Скетч», чтобы нарисовать маску. Когда закончите, нажмите Run, чтобы сгенерировать и скачать изображение маски.

Размытие маски

Метод blur() предоставляет возможность настроить способ слияния исходного изображения и области инпейнта. Степень размытия определяется параметром blur_factor. Увеличение значения blur_factor усиливает размытие по краям маски, смягчая переход между исходным изображением и областью инпейнта. Низкое или нулевое значение blur_factor сохраняет более чёткие края маски.

Для этого создайте размытую маску с помощью процессора изображений.

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image
from PIL import Image

pipeline = AutoPipelineForInpainting.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16).to('cuda')  # or "mps", "xpu", "cpu"

mask = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/seashore_mask.png")
blurred_mask = pipeline.mask_processor.blur(mask, blur_factor=33)
blurred_mask
маска без размытия
маска с применённым размытием

Популярные модели

Stable Diffusion Inpainting, Stable Diffusion XL (SDXL) Inpainting и Kandinsky 2.2 Inpainting — одни из самых популярных моделей для inpainting. SDXL, как правило, генерирует изображения с более высоким разрешением, чем Stable Diffusion v1.5, а Kandinsky 2.2 также способен создавать изображения высокого качества.

Stable Diffusion Inpainting

Stable Diffusion Inpainting — это латентная диффузионная модель, дообученная на изображениях 512x512 для задачи inpainting. Это хорошая отправная точка, поскольку модель работает относительно быстро и генерирует изображения высокого качества. Чтобы использовать эту модель для inpainting, необходимо передать в пайплайн промпт, базовое изображение и маску:

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

generator = torch.Generator("cuda").manual_seed(92)
prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, generator=generator).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)

Inpainting в Stable Diffusion XL (SDXL)

SDXL — это более крупная и мощная версия Stable Diffusion v1.5. Эта модель может следовать двухэтапному процессу (хотя каждую модель можно использовать и по отдельности): базовая модель генерирует изображение, а модель-рефинер принимает это изображение и дополнительно улучшает его детали и качество. Ознакомьтесь с руководством по SDXL, чтобы получить более подробную информацию о том, как использовать SDXL и настроить его параметры.

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "diffusers/stable-diffusion-xl-1.0-inpainting-0.1", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

generator = torch.Generator("cuda").manual_seed(92)
prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, generator=generator).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)

Kandinsky 2.2 Inpainting

Семейство моделей Kandinsky похоже на SDXL, поскольку также использует две модели: модель image prior создаёт эмбеддинги изображений, а диффузионная модель генерирует изображения на их основе. Вы можете загрузить модель image prior и диффузионную модель отдельно, но самый простой способ использовать Kandinsky 2.2 — загрузить его в класс AutoPipelineForInpainting, который под капотом использует KandinskyV22InpaintCombinedPipeline.

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "kandinsky-community/kandinsky-2-2-decoder-inpaint", dtype=torch.float16
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

generator = torch.Generator("cuda").manual_seed(92)
prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, generator=generator).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)
базовый образ
Stable Diffusion Inpainting
Stable Diffusion XL Inpainting
Kandinsky 2.2 Inpainting

Чекпоинты, не предназначенные для инпейнта

До сих пор в этом руководстве использовались контрольные точки, специфичные для inpaint, такие как stable-diffusion-v1-5/stable-diffusion-inpainting. Однако можно также использовать обычные контрольные точки, например stable-diffusion-v1-5/stable-diffusion-v1-5. Сравним результаты двух контрольных точек.

Изображение слева сгенерировано из обычного контрольного пункта, а изображение справа — из контрольного пункта для inpaint. Вы сразу заметите, что изображение слева менее чистое, и на нём всё ещё виден контур области, которую модель должна заполнить. Изображение справа значительно чище, а заполненная область выглядит более естественно.

stable-diffusion-v1-5/stable-diffusion-v1-5
stable-diffusion-v1-5/stable-diffusion-inpainting
import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

generator = torch.Generator("cuda").manual_seed(92)
prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, generator=generator).images[0]
make_image_grid([init_image, image], rows=1, cols=2)
stable-diffusion-v1-5/stable-diffusion-v1-5
stable-diffusion-v1-5/stable-diffusion-inpainting

Однако для более простых задач, таких как удаление объекта с изображения (например, камней на дороге), обычный чекпоинт даёт довольно хорошие результаты. Разница между обычным чекпоинтом и чекпоинтом для инпейнта менее заметна.

stable-diffusion-v1-5/stable-diffusion-v1-5
stable-diffusion-v1-5/stable-diffusion-inpaint
import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/road-mask.png")

image = pipeline(prompt="road", image=init_image, mask_image=mask_image).images[0]
make_image_grid([init_image, image], rows=1, cols=2)
stable-diffusion-v1-5/stable-diffusion-v1-5
stable-diffusion-v1-5/stable-diffusion-inpainting

Компромисс при использовании чекпоинта, не предназначенного специально для инпейнта, заключается в том, что общее качество изображения может быть ниже, однако, как правило, область маски сохраняется (именно поэтому виден её контур). Чекпоинты, специально обученные для инпейнта, намеренно обучаются для генерации изображений с более высоким качеством, что включает создание более естественного перехода между замаскированной и незамаскированной областями. В результате эти чекпоинты с большей вероятностью изменят вашу незамаскированную область.

Если для вашей задачи важно сохранить немаскированную область изображения, вы можете использовать метод VaeImageProcessor.apply_overlay(), чтобы принудительно оставить её неизменной, что приведёт к несколько менее естественным переходам между маскированной и немаскированной областями.

import PIL
import numpy as np
import torch

from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

device = "cuda"  # or "mps", "xpu", "cpu"
pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting",
    dtype=torch.float16,
    variant="fp16"
)
pipeline = pipeline.to(device)

img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png"
mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png"

init_image = load_image(img_url).resize((512, 512))
mask_image = load_image(mask_url).resize((512, 512))

prompt = "Face of a yellow cat, high resolution, sitting on a park bench"
repainted_image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image).images[0]
repainted_image.save("repainted_image.png")

unmasked_unchanged_image = pipeline.image_processor.apply_overlay(mask_image, init_image, repainted_image)
unmasked_unchanged_image.save("force_unmasked_unchanged.png")
make_image_grid([init_image, mask_image, repainted_image, unmasked_unchanged_image], rows=2, cols=2)

Настройка параметров конвейера

Изображательные характеристики — такие как качество и «креативность» — зависят от параметров конвейера. Понимание того, что делают эти параметры, важно для получения желаемого результата. Рассмотрим наиболее важные параметры и посмотрим, как их изменение влияет на вывод.

Сила

strength — это показатель того, сколько шума добавляется к базовому изображению, что влияет на степень сходства результата с исходным изображением.

  • 📈 высокое значение strength означает, что к изображению добавляется больше шума, а процесс денойзинга занимает больше времени, но вы получите изображения более высокого качества, которые будут сильнее отличаться от исходного изображения
  • 📉 низкое значение strength означает, что к изображению добавляется меньше шума, а процесс денойзинга проходит быстрее, однако качество изображения может быть ниже, а сгенерированное изображение будет больше походить на исходное
import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, strength=0.6).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)
strength = 0.6
strength = 0.8
strength = 1.0

Масштаб направляющего сигнала

guidance_scale влияет на степень соответствия текстового промпта и сгенерированного изображения.

  • 📈 высокое значение guidance_scale означает, что промпт и сгенерированное изображение тесно согласованы, поэтому результат представляет собой более строгую интерпретацию промпта
  • 📉 низкое значение guidance_scale означает, что промпт и сгенерированное изображение связаны менее строго, поэтому результат может сильнее отличаться от промпта

Вы можете использовать strength и guidance_scale вместе для более точного контроля над выразительностью модели. Например, сочетание высоких значений strength и guidance_scale предоставляет модели максимальную творческую свободу.

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, guidance_scale=2.5).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)
guidance_scale = 2.5
guidance_scale = 7.5
guidance_scale = 12.5

Негативный промпт

Отрицательный промпт выполняет роль, противоположную обычному промпту: он направляет модель так, чтобы она не генерировала определённые элементы на изображении. Это полезно для быстрого повышения качества изображения и предотвращения генерации нежелательных объектов.

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
negative_prompt = "bad architecture, unstable, poor details, blurry"
image = pipeline(prompt=prompt, negative_prompt=negative_prompt, image=init_image, mask_image=mask_image).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)
negative_prompt = "bad architecture, unstable, poor details, blurry"

Обрезка маски отступов

Один из способов повысить качество изображения при inpainting — использовать параметр padding_mask_crop. При включении этого параметра область маски обрезается с заданным пользователем отступом, а та же область вырезается и из исходного изображения. И изображение, и маска масштабируются до более высокого разрешения для inpainting, а затем накладываются на исходное изображение. Это простой и быстрый способ улучшить качество изображения без использования отдельного конвейера, такого как StableDiffusionUpscalePipeline.

Добавьте параметр padding_mask_crop в вызов конвейера и установите для него нужное значение отступов.

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image
from PIL import Image

generator = torch.Generator(device='cuda').manual_seed(0)  # or "mps", "xpu", "cpu"
pipeline = AutoPipelineForInpainting.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16).to('cuda')

base = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/seashore.png")
mask = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/seashore_mask.png")

image = pipeline("boat", image=base, mask_image=mask, strength=0.75, generator=generator, padding_mask_crop=32).images[0]
image
изображение для inpaint по умолчанию
восстановление изображения с включённым padding_mask_crop

Цепочки пайплайнов для инпейнтинга

AutoPipelineForInpainting можно объединять с другими пайплайнами 🤗 Diffusers для редактирования их результатов. Это часто полезно для повышения качества вывода из других диффузионных пайплайнов, а при использовании нескольких пайплайнов их объединение позволяет экономить память, сохраняя результаты в латентном пространстве и повторно используя одни и те же компоненты пайплайна.

Текст в изображение в инпейнт

Chaining a text-to-image and inpainting pipeline allows you to inpaint the generated image, and you don’t have to provide a base image to begin with. This makes it convenient to edit your favorite text-to-image outputs without having to generate an entirely new image.

Начните с пайплайна text-to-image, чтобы создать замок:

import torch
from diffusers import AutoPipelineForText2Image, AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16, variant="fp16", use_safetensors=True
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

text2image = pipeline("concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k").images[0]

Загрузите изображение маски вывода, полученного выше:

mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_text-chain-mask.png")

А теперь заполним замаскированную область изображением водопада:

pipeline = AutoPipelineForInpainting.from_pretrained(
    "kandinsky-community/kandinsky-2-2-decoder-inpaint", dtype=torch.float16
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

prompt = "digital painting of a fantasy waterfall, cloudy"
image = pipeline(prompt=prompt, image=text2image, mask_image=mask_image).images[0]
make_image_grid([text2image, mask_image, image], rows=1, cols=3)
text-to-image
inpaint

Inpaint-to-image-to-image

Вы также можете подключить конвейер inpainting перед другим конвейером, например image-to-image или апскейлером, чтобы улучшить качество.

Начните с инпейнтинга изображения:

import torch
from diffusers import AutoPipelineForInpainting, AutoPipelineForImage2Image
from diffusers.utils import load_image, make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image_inpainting = pipeline(prompt=prompt, image=init_image, mask_image=mask_image).images[0]

# resize image to 1024x1024 for SDXL
image_inpainting = image_inpainting.resize((1024, 1024))

Теперь передадим изображение в другой пайплайн инпейнтинга с использованием модели-рефинера SDXL, чтобы улучшить детали и качество изображения:

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stabilityai/stable-diffusion-xl-refiner-1.0", dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

image = pipeline(prompt=prompt, image=image_inpainting, mask_image=mask_image, output_type="latent").images[0]

Важно указать output_type="latent" в конвейере, чтобы все выходные данные оставались в латентном пространстве и избежать ненужного шага декодирования-кодирования. Это работает только в том случае, если связанные конвейеры используют одну и ту же VAE. Например, в разделе Text-to-image-to-inpaint Kandinsky 2.2 использует класс VAE, отличный от того, что применяется в модели Stable Diffusion, поэтому это не сработает. Но если вы используете Stable Diffusion v1.5 для обоих конвейеров, то можете оставить всё в латентном пространстве, поскольку оба используют AutoencoderKL.

Наконец, вы можете передать это изображение в пайплайн image-to-image, чтобы внести последние штрихи. Более эффективно использовать метод from_pipe() для переиспользования существующих компонентов пайплайна и избежать ненужной повторной загрузки всех компонентов пайплайна в память.

pipeline = AutoPipelineForImage2Image.from_pipe(pipeline)
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

image = pipeline(prompt=prompt, image=image).images[0]
make_image_grid([init_image, mask_image, image_inpainting, image], rows=2, cols=2)
изображение по умолчанию
inpaint
image-to-image

Image-to-image and inpainting are actually very similar tasks. Image-to-image generates a new image that resembles the existing provided image. Inpainting does the same thing, but it only transforms the image area defined by the mask and the rest of the image is unchanged. You can think of inpainting as a more precise tool for making specific changes and image-to-image has a broader scope for making more sweeping changes.

Управление генерацией изображений

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

Взвешивание промптов

Взвешивание промпта (prompt weighting) предоставляет количественный способ масштабирования представления концепций в промпте. С его помощью можно увеличивать или уменьшать величину вектора текстового эмбеддинга для каждой концепции в промпте, что впоследствии определяет, насколько сильно каждая концепция будет представлена в генерируемом результате. Библиотека Compel предлагает интуитивно понятный синтаксис для масштабирования весов промпта и генерации эмбеддингов. Узнайте, как создавать эмбеддинги, в руководстве Prompt weighting.

После генерации эмбеддингов передайте их в параметр prompt_embeds (а также negative_prompt_embeds, если вы используете негативный промпт) в AutoPipelineForInpainting. Эмбеддинги заменяют параметр prompt:

import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import make_image_grid

pipeline = AutoPipelineForInpainting.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16,
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

image = pipeline(prompt_embeds=prompt_embeds, # generated from Compel
    negative_prompt_embeds=negative_prompt_embeds, # generated from Compel
    image=init_image,
    mask_image=mask_image
).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)

ControlNet

Модели ControlNet используются вместе с другими диффузионными моделями, такими как Stable Diffusion, и обеспечивают более гибкий и точный способ управления процессом генерации изображения. ControlNet принимает дополнительный вход в виде условного изображения, которое направляет диффузионную модель сохранять содержащиеся в нём признаки.

Например, давайте зададим условие для изображения с помощью ControlNet, предварительно обученного на изображениях для inpaint:

import torch
import numpy as np
from diffusers import ControlNetModel, StableDiffusionControlNetInpaintPipeline
from diffusers.utils import load_image, make_image_grid

# load ControlNet
controlnet = ControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_inpaint", dtype=torch.float16, variant="fp16")

# pass ControlNet to the pipeline
pipeline = StableDiffusionControlNetInpaintPipeline.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-inpainting", controlnet=controlnet, dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

# load base and mask image
init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png")
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

# prepare control image
def make_inpaint_condition(init_image, mask_image):
    init_image = np.array(init_image.convert("RGB")).astype(np.float32) / 255.0
    mask_image = np.array(mask_image.convert("L")).astype(np.float32) / 255.0

    assert init_image.shape[0:1] == mask_image.shape[0:1], "image and image_mask must have the same image size"
    init_image[mask_image > 0.5] = -1.0  # set as masked pixel
    init_image = np.expand_dims(init_image, 0).transpose(0, 3, 1, 2)
    init_image = torch.from_numpy(init_image)
    return init_image

control_image = make_inpaint_condition(init_image, mask_image)

Теперь сгенерируйте изображение на основе базового изображения, маски и управляющего изображения. Вы заметите, что особенности базового изображения сильно сохраняются в сгенерированном изображении.

prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, control_image=control_image).images[0]
make_image_grid([init_image, mask_image, PIL.Image.fromarray(np.uint8(control_image[0][0])).convert('RGB'), image], rows=2, cols=2)

Вы можете пойти дальше и объединить это с конвейером image-to-image, чтобы применить новый стиль:

from diffusers import AutoPipelineForImage2Image

pipeline = AutoPipelineForImage2Image.from_pretrained(
    "nitrosocke/elden-ring-diffusion", dtype=torch.float16,
)
pipeline.enable_model_cpu_offload()
# remove following line if xFormers is not installed or you have PyTorch 2.0 or higher installed
pipeline.enable_xformers_memory_efficient_attention()

prompt = "elden ring style castle" # include the token "elden ring style" in the prompt
negative_prompt = "bad architecture, deformed, disfigured, poor details"

image_elden_ring = pipeline(prompt, negative_prompt=negative_prompt, image=image).images[0]
make_image_grid([init_image, mask_image, image, image_elden_ring], rows=2, cols=2)
изображение по умолчанию
ControlNet inpaint
image-to-image

Оптимизация

Запуск диффузионных моделей может быть сложным и медленным при ограниченных ресурсах, но с помощью нескольких оптимизационных приёмов это можно исправить. Одна из самых значимых (и простых) оптимизаций — переход на энергоэффективное внимание. Если вы используете PyTorch 2.0, scaled-dot product attention включается автоматически, и ничего дополнительно делать не нужно. Пользователи версий PyTorch, отличных от 2.0, могут установить и использовать реализацию энергоэффективного внимания от xFormers. Оба варианта снижают потребление памяти и ускоряют инференс.

Вы также можете выгрузить модель на CPU, чтобы сэкономить ещё больше памяти:

+ pipeline.enable_xformers_memory_efficient_attention()
+ pipeline.enable_model_cpu_offload()

Чтобы ещё больше ускорить код инференса, используйте torch_compile. Вам следует обернуть torch.compile вокруг наиболее ресурсоёмкого компонента конвейера, которым обычно является UNet:

pipeline.unet = torch.compile(pipeline.unet, mode="reduce-overhead", fullgraph=True)

Подробнее в руководствах Сокращение использования памяти и Ускорение вывода.

Update on GitHub