Diffusers documentation
Inpainting
Inpainting
El inpainting reemplaza o edita áreas específicas de una imagen. Esto lo convierte en una herramienta útil para la restauración de imágenes, como la eliminación de defectos y artefactos, o incluso para reemplazar un área de la imagen con algo completamente nuevo. El inpainting se basa en una máscara para determinar qué regiones de la imagen deben rellenarse; el área a inpaintear se representa con píxeles blancos y el área a conservar se representa con píxeles negros. Los píxeles blancos se rellenan mediante el prompt.
Con 🤗 Diffusers, así es como puedes hacer inpainting:
- Carga un punto de control de inpainting con la clase AutoPipelineForInpainting. Esto detectará automáticamente la clase de pipeline adecuada para cargar en función del punto de control:
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()A lo largo de la guía, notará que usamos enable_model_cpu_offload() y enable_xformers_memory_efficient_attention() para ahorrar memoria y aumentar la velocidad de inferencia. Si está usando PyTorch 2.0, no es necesario llamar a enable_xformers_memory_efficient_attention() en su pipeline, ya que ya estará utilizando la scaled-dot product attention nativa de PyTorch 2.0.
- Cargue las imágenes de base y máscara:
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")- Crea un prompt para rellenar la imagen y pásalo a la pipeline junto con las imágenes base y de máscara:
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)
Crear una imagen de máscara
A lo largo de esta guía, la imagen de máscara se proporciona en todos los ejemplos de código para mayor comodidad. Puedes realizar inpainting en tus propias imágenes, pero necesitarás crear una imagen de máscara para ello. Usa el Space de abajo para crear fácilmente una imagen de máscara.
Sube una imagen base para retocar y usa la herramienta de boceto para dibujar una máscara. Cuando termines, haz clic en Run para generar y descargar la imagen de la máscara.
Desenfoque de máscara
El método blur() ofrece una opción para definir cómo se combinan la imagen original y el área de inpainting. La cantidad de desenfoque se determina mediante el parámetro blur_factor. Aumentar el blur_factor incrementa el desenfoque aplicado a los bordes de la máscara, suavizando la transición entre la imagen original y el área de inpainting. Un blur_factor bajo o cero preserva los bordes más definidos de la máscara.
Para usar esto, cree una máscara difuminada con el procesador de imágenes.
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
Modelos populares
Stable Diffusion Inpainting, Stable Diffusion XL (SDXL) Inpainting y Kandinsky 2.2 Inpainting son algunos de los modelos más populares para inpainting. SDXL suele generar imágenes de mayor resolución que Stable Diffusion v1.5, y Kandinsky 2.2 también es capaz de generar imágenes de alta calidad.
Stable Diffusion Inpainting
Stable Diffusion Inpainting es un modelo de difusión latente afinado en imágenes de 512x512 para inpainting. Es un buen punto de partida porque es relativamente rápido y genera imágenes de buena calidad. Para usar este modelo para inpainting, debes pasar un prompt, una imagen base y una imagen de máscara a la pipeline:
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 de Stable Diffusion XL (SDXL)
SDXL es una versión más grande y potente de Stable Diffusion v1.5. Este modelo puede seguir un proceso de dos etapas (aunque cada modelo también puede usarse de forma independiente); el modelo base genera una imagen y un modelo de refinamiento toma esa imagen para mejorar aún más sus detalles y calidad. Consulta la guía de SDXL para obtener una guía más completa sobre cómo usar SDXL y configurar sus parámetros.
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
La familia de modelos Kandinsky es similar a SDXL porque también utiliza dos modelos; el modelo de prior de imagen crea embeddings de imagen y el modelo de difusión genera imágenes a partir de ellos. Puedes cargar el modelo de prior de imagen y el modelo de difusión por separado, pero la forma más sencilla de usar Kandinsky 2.2 es cargarlo en la clase AutoPipelineForInpainting, que utiliza KandinskyV22InpaintCombinedPipeline internamente.
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)
Puntos de control específicos no de relleno
Hasta ahora, esta guía ha utilizado puntos de control específicos para inpaint, como stable-diffusion-v1-5/stable-diffusion-inpainting. Pero también puedes usar puntos de control regulares, como stable-diffusion-v1-5/stable-diffusion-v1-5. Comparemos los resultados de los dos puntos de control.
La imagen de la izquierda se genera desde un checkpoint regular, y la imagen de la derecha es de un checkpoint de inpaint. Notarás de inmediato que la imagen de la izquierda no es tan limpia y aún se puede ver el contorno del área que el modelo debe inpaint. La imagen de la derecha es mucho más limpia y el área inpaintada parece más natural.
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)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, image], rows=1, cols=2)
Sin embargo, para tareas más básicas, como borrar un objeto de una imagen (por ejemplo, las rocas en el camino), un checkpoint regular produce resultados bastante buenos. No hay una diferencia tan notable entre el checkpoint regular y el checkpoint de 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)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/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)
La desventaja de usar un checkpoint no específico para inpainting es que la calidad general de la imagen puede ser inferior, pero generalmente tiende a preservar el área de la máscara (por eso se puede ver el contorno de la máscara). Los checkpoints específicos para inpainting se entrenan intencionalmente para generar imágenes inpaintadas de mayor calidad, y eso incluye crear una transición más natural entre las áreas enmascaradas y no enmascaradas. Como resultado, es más probable que estos checkpoints modifiquen su área no enmascarada.
Si preservar el área sin máscara es importante para su tarea, puede usar el método VaeImageProcessor.apply_overlay() para forzar que el área sin máscara de una imagen permanezca igual, a costa de transiciones algo menos naturales entre las áreas con y sin máscara.
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)Configurar los parámetros de la canalización
Las características de la imagen, como la calidad y la “creatividad”, dependen de los parámetros de la pipeline. Conocer qué hacen estos parámetros es importante para obtener los resultados que se desean. Veamos los parámetros más importantes y cómo afecta su modificación a la salida.
Fuerza
strength es una medida de la cantidad de ruido que se añade a la imagen base, lo que influye en qué tan similar es la imagen de salida a la imagen base.
- 📈 un valor de
strengthalto significa que se añade más ruido a la imagen y el proceso de desruidoado tarda más, pero obtendrás imágenes de mayor calidad que difieren más de la imagen base - 📉 un valor de
strengthbajo significa que se añade menos ruido a la imagen y el proceso de desruido es más rápido, pero la calidad de la imagen puede no ser tan buena y la imagen generada se parecerá más a la imagen base
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)
Escala de guía
guidance_scale afecta el grado de alineación entre el texto del prompt y la imagen generada.
- 📈 un valor alto de
guidance_scalesignifica que el prompt y la imagen generada están estrechamente alineados, por lo que la salida es una interpretación más estricta del prompt - 📉 un valor bajo de
guidance_scalesignifica que el prompt y la imagen generada están alineados de forma más laxa, por lo que la salida puede ser más variada respecto al prompt
Puedes usar strength y guidance_scale juntos para tener más control sobre lo expresivo que es el modelo. Por ejemplo, una combinación de valores altos de strength y guidance_scale otorga al modelo la mayor libertad creativa.
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)
Prompt negativo
Un prompt negativo asume el papel opuesto al de un prompt; guía al modelo para que no genere ciertos elementos en una imagen. Esto es útil para mejorar rápidamente la calidad de la imagen y evitar que el modelo genere cosas que no deseas.
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)
Recorte de la máscara de relleno
Un método para mejorar la calidad de la imagen en el inpainting es utilizar el parámetro padding_mask_crop. Cuando está habilitado, esta opción recorta el área enmascarada con un relleno especificado por el usuario y también recorta la misma área de la imagen original. Tanto la imagen como la máscara se escalan a una resolución más alta para el inpainting y luego se superponen sobre la imagen original. Esta es una forma rápida y sencilla de mejorar la calidad de la imagen sin utilizar una pipeline separada como StableDiffusionUpscalePipeline.
Agrega el parámetro padding_mask_crop a la llamada de la pipeline y establécelo en el valor de relleno deseado.
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
Pipelines de inpainting encadenados
AutoPipelineForInpainting se puede encadenar con otras pipelines de 🤗 Diffusers para editar sus salidas. Esto suele ser útil para mejorar la calidad de la salida de otras pipelines de difusión, y si se utilizan varias pipelines, puede ser más eficiente en memoria encadenarlas para mantener las salidas en el espacio latente y reutilizar los mismos componentes de la pipeline.
Texto a imagen a inpainting
Encadenar un pipeline de texto a imagen y un pipeline de inpainting permite realizar inpainting en la imagen generada, sin necesidad de proporcionar una imagen base desde el principio. Esto facilita editar tus salidas favoritas de texto a imagen sin tener que generar una imagen completamente nueva.
Comience con el pipeline de texto a imagen para crear un castillo:
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]Cargue la imagen de la máscara de la salida anterior:
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_text-chain-mask.png")Y ahora rellenemos el área enmascarada con una cascada:
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)
Inpaint-to-image-to-image
También puede encadenar un pipeline de inpainting antes de otro pipeline, como image-to-image o un upscaler, para mejorar la calidad.
Comience aplicando inpainting a una imagen:
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))Ahora pasemos la imagen a otro pipeline de inpainting con el modelo refiner de SDXL para mejorar los detalles y la calidad de la imagen:
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]Es importante especificar
output_type="latent"en el pipeline para mantener todas las salidas en el espacio latente y evitar un paso innecesario de decodificación y codificación. Esto solo funciona si los pipelines encadenados utilizan el mismo VAE. Por ejemplo, en la sección Text-to-image-to-inpaint, Kandinsky 2.2 utiliza una clase de VAE diferente a la del modelo Stable Diffusion, por lo que no funcionará. Pero si usas Stable Diffusion v1.5 para ambos pipelines, puedes mantener todo en el espacio latente porque ambos utilizan AutoencoderKL.
Por último, puedes pasar esta imagen a un pipeline de imagen a imagen para darle los últimos retoques. Es más eficiente usar el método from_pipe() para reutilizar los componentes existentes del pipeline y evitar cargar innecesariamente todos los componentes del pipeline en memoria de nuevo.
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)
La generación de imagen a imagen y el inpainting son, en realidad, tareas muy similares. La generación de imagen a imagen crea una nueva imagen que se asemeja a la imagen existente proporcionada. El inpainting hace lo mismo, pero solo transforma el área de la imagen definida por la máscara y el resto de la imagen permanece sin cambios. Puedes pensar en el inpainting como una herramienta más precisa para realizar cambios específicos, mientras que la generación de imagen a imagen tiene un alcance más amplio para realizar cambios más generales.
Controlar la generación de imágenes
Lograr que una imagen se vea exactamente como se desea es un desafío porque el proceso de desruido es aleatorio. Si bien es posible controlar ciertos aspectos de la generación configurando parámetros como negative_prompt, existen métodos mejores y más eficientes para controlar la generación de imágenes.
Pesos de los prompts
El ponderado de prompts ofrece una forma cuantificable de escalar la representación de los conceptos en un prompt. Puede utilizarlo para aumentar o disminuir la magnitud del vector de embedding de texto para cada concepto en el prompt, lo que determina en consecuencia cuánto de cada concepto se genera. La biblioteca Compel ofrece una sintaxis intuitiva para escalar los pesos del prompt y generar los embeddings. Aprenda a crear los embeddings en la guía de Ponderado de prompts.
Una vez que hayas generado los embeddings, pásalos al parámetro prompt_embeds (y negative_prompt_embeds si estás usando un prompt negativo) en AutoPipelineForInpainting. Los embeddings reemplazan al parámetro 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
Los modelos ControlNet se utilizan junto con otros modelos de difusión como Stable Diffusion, y ofrecen una forma aún más flexible y precisa de controlar cómo se genera una imagen. Un ControlNet acepta una imagen de condicionamiento adicional como entrada que guía al modelo de difusión para que preserve las características presentes en ella.
Por ejemplo, condicional una imagen con un ControlNet preentrenado en imágenes de 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)Ahora genera una imagen a partir de las imágenes base, de máscara y de control. Notarás que las características de la imagen base se conservan fuertemente en la imagen generada.
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)Puede llevar esto un paso más allá y encadenarlo con un pipeline de imagen a imagen para aplicar un nuevo estilo:
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)
Optimizar
Ejecutar modelos de difusión puede ser difícil y lento si tienes recursos limitados, pero no tiene por qué ser así con algunos trucos de optimización. Una de las optimizaciones más grandes (y fáciles) que puedes activar es cambiar a una atención eficiente en memoria. Si usas PyTorch 2.0, scaled-dot product attention se habilita automáticamente y no necesitas hacer nada más. Para usuarios de versiones de PyTorch anteriores a 2.0, puedes instalar y usar la implementación de atención eficiente en memoria de xFormers. Ambas opciones reducen el uso de memoria y aceleran la inferencia.
También puede descargar el modelo a la CPU para ahorrar aún más memoria:
+ pipeline.enable_xformers_memory_efficient_attention()
+ pipeline.enable_model_cpu_offload()Para acelerar aún más tu código de inferencia, usa torch_compile. Deberás envolver torch.compile alrededor del componente más intensivo de la tubería, que normalmente es el UNet:
pipeline.unet = torch.compile(pipeline.unet, mode="reduce-overhead", fullgraph=True)Obtén más información en las guías Reduce memory usage y Accelerate inference.
Update on GitHub