ControlNet en 馃Ж Difusores

'ControlNet en 馃Ж Difusores' can be condensed to 'ControlNet en Difusores'

Desde que Stable Diffusion caus贸 sensaci贸n en el mundo, las personas han estado buscando formas de tener m谩s control sobre los resultados del proceso de generaci贸n. ControlNet proporciona una interfaz m铆nima que permite a los usuarios personalizar en gran medida el proceso de generaci贸n. 隆Con ControlNet, los usuarios pueden condicionar f谩cilmente la generaci贸n con diferentes contextos espaciales como un mapa de profundidad, un mapa de segmentaci贸n, un garabato, puntos clave, 隆y mucho m谩s!

Podemos convertir un dibujo animado en una foto realista con una incre铆ble coherencia.

Realistic Lofi Girl

O incluso usarlo como tu dise帽ador de interiores.

Antes Despu茅s

Puedes convertir tu garabato en un dibujo art铆stico.

Antes Despu茅s

Tambi茅n puedes dar vida a algunos de los famosos logotipos.

Antes Despu茅s

Con ControlNet, el cielo es el l铆mite 馃尃

En esta publicaci贸n de blog, primero presentamos el StableDiffusionControlNetPipeline y luego mostramos c贸mo se puede aplicar para varias condiciones de control. 隆Empecemos a controlar!

ControlNet: TL;DR

ControlNet fue introducido en Adding Conditional Control to Text-to-Image Diffusion Models por Lvmin Zhang y Maneesh Agrawala. Introduce un marco que permite admitir varios contextos espaciales que pueden servir como condicionantes adicionales para modelos de difusi贸n como Stable Diffusion. La implementaci贸n de los difusores se adapta del c贸digo fuente original .

El entrenamiento de ControlNet consta de los siguientes pasos:

  1. Clonar los par谩metros preentrenados de un modelo de difusi贸n, como el UNet latente de Stable Diffusion, (denominado “copia entrenable”) mientras se mantienen los par谩metros preentrenados por separado (“copia bloqueada”). Se hace para que la copia bloqueada de los par谩metros pueda preservar el vasto conocimiento aprendido de un gran conjunto de datos, mientras que la copia entrenable se utiliza para aprender los aspectos espec铆ficos de la tarea.
  2. Las copias entrenable y bloqueada de los par谩metros se conectan mediante capas de “convoluci贸n cero” (consulte aqu铆 para obtener m谩s informaci贸n), que se optimizan como parte del marco de ControlNet. Este es un truco de entrenamiento para preservar la sem谩ntica ya aprendida por el modelo congelado a medida que se entrenan las nuevas condiciones.

De manera pict贸rica, el entrenamiento de un ControlNet se ve as铆:

El diagrama se toma de aqu铆 .

Una muestra del conjunto de entrenamiento para un entrenamiento similar a ControlNet se ve as铆 (la condici贸n adicional es a trav茅s de mapas de bordes):

Indicaci贸n Imagen Original Condicionamiento
“p谩jaro”

De manera similar, si condicion谩ramos ControlNet con mapas de segmentaci贸n sem谩ntica, una muestra de entrenamiento se ver铆a as铆:

Indicaci贸n Imagen Original Condicionamiento
“casa grande”

Cada nuevo tipo de condicionamiento requiere entrenar una copia nueva de los pesos de ControlNet. 隆El art铆culo propuso 8 modelos de condicionamiento diferentes que son compatibles en Diffusers!

Para la inferencia, se necesitan tanto los pesos de los modelos de difusi贸n pre-entrenados como los pesos entrenados de ControlNet. Por ejemplo, usar Stable Diffusion v1-5 con un punto de control de ControlNet requiere aproximadamente 700 millones de par谩metros m谩s en comparaci贸n con solo usar el modelo original de Stable Diffusion, lo que hace que ControlNet sea un poco m谩s costoso en memoria para la inferencia.

Debido a que los modelos de difusi贸n pre-entrenados est谩n bloqueados durante el entrenamiento, solo es necesario cambiar los par谩metros de ControlNet al utilizar un condicionamiento diferente. Esto hace que sea bastante simple implementar m煤ltiples pesos de ControlNet en una aplicaci贸n, como veremos a continuaci贸n.

El StableDiffusionControlNetPipeline

Antes de comenzar, queremos agradecer enormemente al colaborador de la comunidad Takuma Mori por liderar la integraci贸n de ControlNet en Diffusers 鉂わ笍.

Para experimentar con ControlNet, Diffusers expone el StableDiffusionControlNetPipeline similar a los otros pipelines de Diffusers. Central en el StableDiffusionControlNetPipeline est谩 el argumento controlnet, que nos permite proporcionar una instancia espec铆fica de ControlNetModel entrenado manteniendo los pesos pre-entrenados del modelo de difusi贸n iguales.

Exploraremos diferentes casos de uso con el StableDiffusionControlNetPipeline en esta publicaci贸n de blog. El primer modelo de ControlNet que vamos a analizar es el modelo Canny, que es uno de los modelos m谩s populares que gener贸 algunas de las im谩genes asombrosas que seguramente est谩s viendo en internet.

Te invitamos a ejecutar los fragmentos de c贸digo que se muestran en las secciones a continuaci贸n con este Cuaderno de Colab.

Antes de comenzar, asegur茅monos de tener todas las bibliotecas necesarias instaladas:

pip install diffusers==0.14.0 transformers xformers git+https://github.com/huggingface/accelerate.git

Para procesar diferentes condicionamientos dependiendo del ControlNet elegido, tambi茅n necesitamos instalar algunas dependencias adicionales:

  • OpenCV
  • controlnet-aux: una colecci贸n simple de modelos de preprocesamiento para ControlNet
pip install opencv-contrib-python
pip install controlnet_aux

Utilizaremos la famosa pintura “Girl With A Pearl” para este ejemplo. Entonces, descarguemos la imagen y echemos un vistazo:

from diffusers.utils import load_image

image = load_image(
    "https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/input_image_vermeer.png"
)
image

A continuaci贸n, pasaremos la imagen por el preprocesador de Canny:

import cv2
from PIL import Image
import numpy as np

image = np.array(image)

low_threshold = 100
high_threshold = 200

image = cv2.Canny(image, low_threshold, high_threshold)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
canny_image = Image.fromarray(image)
canny_image

Como podemos ver, es b谩sicamente detecci贸n de bordes:

Ahora, cargamos el modelo runwaylml/stable-diffusion-v1-5 y el modelo ControlNet para bordes canny. Los modelos se cargan en media precisi贸n (torch.dtype) para permitir una inferencia r谩pida y eficiente en memoria.

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import torch

controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16)
pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16
)

En lugar de utilizar el programador PNDMScheduler predeterminado de Stable Diffusion, utilizamos uno de los programadores de modelos de difusi贸n m谩s r谩pidos actualmente, llamado UniPCMultistepScheduler. Elegir un programador mejorado puede reducir dr谩sticamente el tiempo de inferencia; en nuestro caso, podemos reducir el n煤mero de pasos de inferencia de 50 a 20, manteniendo m谩s o menos la misma calidad de generaci贸n de im谩genes. Se puede encontrar m谩s informaci贸n sobre los programadores aqu铆.

from diffusers import UniPCMultistepScheduler

pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)

En lugar de cargar directamente nuestra canalizaci贸n en la GPU, habilitamos la descarga inteligente de la CPU, que se puede lograr con la funci贸n enable_model_cpu_offload.

Recuerde que durante la inferencia de modelos de difusi贸n, como Stable Diffusion, no solo se requiere un componente del modelo, sino m煤ltiples componentes del modelo que se ejecutan secuencialmente. En el caso de Stable Diffusion con ControlNet, primero utilizamos el codificador de texto CLIP, luego el modelo de difusi贸n unet y el control net, luego el decodificador VAE y finalmente ejecutamos un verificador de seguridad. La mayor铆a de los componentes solo se ejecutan una vez durante el proceso de difusi贸n y, por lo tanto, no es necesario que ocupen memoria de la GPU todo el tiempo. Al habilitar la descarga inteligente del modelo, nos aseguramos de que cada componente se cargue en la GPU solo cuando sea necesario, lo que nos permite ahorrar significativamente el consumo de memoria sin ralentizar significativamente la inferencia.

Nota: Al ejecutar enable_model_cpu_offload, no mueva manualmente la canalizaci贸n a la GPU con .to("cuda"): una vez que se habilita la descarga de la CPU, la canalizaci贸n se encarga autom谩ticamente de la administraci贸n de la memoria de la GPU.

pipe.enable_model_cpu_offload()

Finalmente, queremos aprovechar al m谩ximo la incre铆ble aceleraci贸n de la capa de atenci贸n FlashAttention/xformers, 隆as铆 que vamos a habilitar esto! Si este comando no funciona para usted, es posible que no tenga xformers instalado correctamente. En este caso, simplemente puede omitir la siguiente l铆nea de c贸digo.

pipe.enable_xformers_memory_efficient_attention()

Ahora estamos listos para ejecutar la canalizaci贸n ControlNet.

Todav铆a proporcionamos una frase para guiar el proceso de generaci贸n de im谩genes, como lo har铆amos normalmente con una canalizaci贸n de imagen a imagen de Stable Diffusion. Sin embargo, ControlNet permitir谩 mucho m谩s control sobre la imagen generada porque podremos controlar la composici贸n exacta en la imagen generada con la imagen de bordes canny que acabamos de crear.

Ser谩 divertido ver algunas im谩genes en las que las celebridades contempor谩neas posan para esta misma pintura del siglo XVII. Y es realmente f谩cil hacerlo con ControlNet, 隆todo lo que tenemos que hacer es incluir los nombres de estas celebridades en la frase!

Primero, creemos una funci贸n auxiliar simple para mostrar im谩genes como una cuadr铆cula.

def image_grid(imgs, rows, cols):
    assert len(imgs) == rows * cols

    w, h = imgs[0].size
    grid = Image.new("RGB", size=(cols * w, rows * h))
    grid_w, grid_h = grid.size

    for i, img in enumerate(imgs):
        grid.paste(img, box=(i % cols * w, i // cols * h))
    return grid

A continuaci贸n, definimos las indicaciones de entrada y establecemos una semilla para la reproducibilidad.

prompt = ", mejor calidad, extremadamente detallado"
prompt = [t + prompt for t in ["Sandra Oh", "Kim Kardashian", "rihanna", "taylor swift"]]
generator = [torch.Generator(device="cpu").manual_seed(2) for i in range(len(prompt))]

Finalmente, 隆podemos ejecutar el pipeline y mostrar la imagen!

output = pipe(
    prompt,
    canny_image,
    negative_prompt=["monocromo, baja resoluci贸n, mala anatom铆a, peor calidad, baja calidad"] * 4,
    num_inference_steps=20,
    generator=generator,
)

image_grid(output.images, 2, 2)

隆Podemos combinar sin esfuerzo ControlNet con el ajuste fino tambi茅n! Por ejemplo, podemos ajustar finamente un modelo con DreamBooth y usarlo para representarnos en diferentes escenas.

En esta publicaci贸n, vamos a utilizar a nuestro querido Mr Potato Head como ejemplo para mostrar c贸mo utilizar ControlNet con DreamBooth.

Podemos utilizar el mismo ControlNet. Sin embargo, en lugar de utilizar el Stable Diffusion 1.5, vamos a cargar el modelo de Mr Potato Head en nuestro pipeline: Mr Potato Head es un modelo de Stable Diffusion ajustado finamente con el concepto de Mr Potato Head utilizando Dreambooth 馃

隆Vamos a ejecutar los comandos anteriores de nuevo, manteniendo el mismo controlnet!

model_id = "sd-dreambooth-library/mr-potato-head"
pipe = StableDiffusionControlNetPipeline.from_pretrained(
    model_id,
    controlnet=controlnet,
    torch_dtype=torch.float16,
)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()
pipe.enable_xformers_memory_efficient_attention()

隆Ahora hagamos que Mr Potato se ponga en posici贸n para Johannes Vermeer!

generator = torch.manual_seed(2)
prompt = "una foto de Mr Potato Head de sks, mejor calidad, extremadamente detallado"
output = pipe(
    prompt,
    canny_image,
    negative_prompt="monocromo, baja resoluci贸n, mala anatom铆a, peor calidad, baja calidad",
    num_inference_steps=20,
    generator=generator,
)
output.images[0]

Es notable que Mr Potato Head no es el mejor candidato, pero hizo todo lo posible y hizo un buen trabajo capturando parte de la esencia 馃崯

Otra aplicaci贸n exclusiva de ControlNet es que podemos tomar una pose de una imagen y reutilizarla para generar una imagen diferente con la misma pose exacta. As铆 que en este pr贸ximo ejemplo, 隆vamos a ense帽ar a los superh茅roes a hacer yoga usando Open Pose ControlNet!

Primero, necesitaremos obtener algunas im谩genes de personas haciendo yoga:

urls = "yoga1.jpeg", "yoga2.jpeg", "yoga3.jpeg", "yoga4.jpeg"
imgs = [
    load_image("https://huggingface.co/datasets/YiYiXu/controlnet-testing/resolve/main/" + url) 
    for url in urls
]

image_grid(imgs, 2, 2)

Ahora extrayamos las poses de yoga utilizando los preprocesadores de OpenPose que est谩n disponibles de manera pr谩ctica a trav茅s de controlnet_aux.

from controlnet_aux import OpenposeDetector

model = OpenposeDetector.from_pretrained("lllyasviel/ControlNet")

poses = [model(img) for img in imgs]
image_grid(poses, 2, 2)

Para utilizar estas poses de yoga para generar nuevas im谩genes, creemos un Open Pose ControlNet. Generaremos algunas im谩genes de superh茅roes, pero en las poses de yoga mostradas anteriormente. 隆Vamos all谩! 馃殌

controlnet = ControlNetModel.from_pretrained(
    "fusing/stable-diffusion-v1-5-controlnet-openpose", torch_dtype=torch.float16
)

model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionControlNetPipeline.from_pretrained(
    model_id,
    controlnet=controlnet,
    torch_dtype=torch.float16,
)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()

隆Ahora es hora de hacer yoga!

generator = [torch.Generator(device="cpu").manual_seed(2) for i in range(4)]
prompt = "personaje de superh茅roe, mejor calidad, extremadamente detallado"
output = pipe(
    [prompt] * 4,
    poses,
    negative_prompt=["monocromo, baja resoluci贸n, mala anatom铆a, peor calidad, baja calidad"] * 4,
    generator=generator,
    num_inference_steps=20,
)
image_grid(output.images, 2, 2)

Combinando m煤ltiples acondicionamientos

Se pueden combinar m煤ltiples acondicionamientos de ControlNet para generar una sola imagen. Pase una lista de ControlNets al constructor del pipeline y una lista correspondiente de acondicionamientos a __call__.

Cuando se combinan acondicionamientos, es 煤til enmascarar los acondicionamientos para que no se superpongan. En el ejemplo, enmascaramos el centro del mapa de Canny donde se encuentra el acondicionamiento de la pose.

Tambi茅n puede ser 煤til variar las escalas de controlnet_conditioning_scale para enfatizar un acondicionamiento sobre el otro.

Acondicionamiento de Canny

La imagen original

Preparando el acondicionamiento

from diffusers.utils import load_image
from PIL import Image
import cv2
import numpy as np
from diffusers.utils import load_image

canny_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/landscape.png"
)
canny_image = np.array(canny_image)

low_threshold = 100
high_threshold = 200

canny_image = cv2.Canny(canny_image, low_threshold, high_threshold)

# anulamos las columnas centrales de la imagen donde se superpondr谩 la pose
zero_start = canny_image.shape[1] // 4
zero_end = zero_start + canny_image.shape[1] // 2
canny_image[:, zero_start:zero_end] = 0

canny_image = canny_image[:, :, None]
canny_image = np.concatenate([canny_image, canny_image, canny_image], axis=2)
canny_image = Image.fromarray(canny_image)

Acondicionamiento de Openpose

La imagen original

Preparando el acondicionamiento

from controlnet_aux import OpenposeDetector
from diffusers.utils import load_image

openpose = OpenposeDetector.from_pretrained("lllyasviel/ControlNet")

openpose_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/person.png"
)
openpose_image = openpose(openpose_image)

Ejecuci贸n de ControlNet con m煤ltiples acondicionamientos

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, UniPCMultistepScheduler
import torch

controlnet = [
    ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-openpose", torch_dtype=torch.float16),
    ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16),
]

pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16
)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)

pipe.enable_xformers_memory_efficient_attention()
pipe.enable_model_cpu_offload()

prompt = "un gigante parado en un paisaje de fantas铆a, mejor calidad"
negative_prompt = "monocromo, baja resoluci贸n, mala anatom铆a, peor calidad, baja calidad"

generator = torch.Generator(device="cpu").manual_seed(1)

images = [openpose_image, canny_image]

image = pipe(
    prompt,
    images,
    num_inference_steps=20,
    generator=generator,
    negative_prompt=negative_prompt,
    controlnet_conditioning_scale=[1.0, 0.8],
).images[0]

image.save("./multi_controlnet_output.png")

A lo largo de los ejemplos, exploramos m煤ltiples facetas de StableDiffusionControlNetPipeline para mostrar lo f谩cil e intuitivo que es jugar con ControlNet a trav茅s de los Difusores. Sin embargo, no cubrimos todos los tipos de condicionamientos soportados por ControlNet. Para saber m谩s sobre ellos, te animamos a que consultes las respectivas p谩ginas de documentaci贸n del modelo:

  • lllyasviel/sd-controlnet-depth
  • lllyasviel/sd-controlnet-hed
  • lllyasviel/sd-controlnet-normal
  • lllyasviel/sd-controlnet-scribble
  • lllyasviel/sd-controlnet-seg
  • lllyasviel/sd-controlnet-openpose
  • lllyasviel/sd-controlnet-mlsd
  • lllyasviel/sd-controlnet-canny

Te invitamos a combinar estos diferentes elementos y compartir tus resultados con @diffuserslib . Aseg煤rate de consultar el cuaderno de Colab para probar algunos de los ejemplos anteriores!

Tambi茅n mostramos algunas t茅cnicas para hacer que el proceso de generaci贸n sea m谩s r谩pido y que consuma menos memoria, utilizando un planificador r谩pido, la descarga inteligente del modelo y xformers . Con estas t茅cnicas combinadas, el proceso de generaci贸n tarda solo ~3 segundos en una GPU V100 y consume solo ~4 GB de VRAM para una sola imagen 鈿★笍 En servicios gratuitos como Google Colab, la generaci贸n tarda aproximadamente 5 segundos en la GPU predeterminada (T4), mientras que la implementaci贸n original requiere 17 segundos para crear el mismo resultado! Combinar todas las piezas en la caja de herramientas de diffusers es un verdadero superpoder 馃挭

Conclusi贸n

Hemos estado jugando mucho con StableDiffusionControlNetPipeline , 隆y nuestra experiencia ha sido divertida hasta ahora! Estamos emocionados de ver qu茅 construye la comunidad sobre esta tuber铆a. Si quieres ver otras tuber铆as y t茅cnicas admitidas en Diffusers que permiten una generaci贸n controlada, consulta nuestra documentaci贸n oficial .

Si no puedes esperar para probar ControlNet directamente, 隆tambi茅n te tenemos cubierto! Simplemente haz clic en uno de los siguientes espacios para jugar con ControlNet:

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Adopci贸n empresarial de la IA generativa

Hola, soy Michael y he estado inmerso en la adopci贸n de IA empresarial desde 2018 cuando comenzamos una conferencia s...

Ciencias de la Computaci贸n

La inteligencia artificial se utiliz贸 para crear una nueva canci贸n final de los Beatles, seg煤n Paul McCartney.

El m煤sico dice que utiliz贸 tecnolog铆a para 'extraer' la voz de John Lennon de una vieja demo y completar una canci贸n ...

Inteligencia Artificial

Silicon Volley Los dise帽adores utilizan la IA generativa para obtener un asistente de Chip

Un art铆culo de investigaci贸n publicado hoy describe formas en que la inteligencia artificial generativa puede ayudar ...

Inteligencia Artificial

6 Podcasts de GenAI que deber铆as estar escuchando

Introducci贸n En el paisaje en constante evoluci贸n de la inteligencia artificial, el campo de la IA generativa (GenAI)...

Inteligencia Artificial

Investigadores de Meta IA publican como c贸digo abierto Pearl una biblioteca de agentes de IA de aprendizaje por refuerzo lista para la producci贸n.

Aprendizaje por refuerzo (RL) es un subcampo del aprendizaje autom谩tico en el cual un agente toma acciones adecuadas ...

Inteligencia Artificial

Principales extensiones de Chrome con inteligencia artificial AI

La idea de una m谩quina que escriba por ti ha pasado de ser ciencia ficci贸n a realidad gracias a los avances en la tec...