Diffusers documentation
IP-Adapter
IP-Adapter
IP-Adapter direciona um modelo de difusão pré-treinado com uma imagem de referência enquanto você mantém um prompt de texto. Ele congela o modelo base e adiciona um pequeno conjunto de camadas de atenção cruzada de imagem, o que o torna prático para corresponder a um sujeito ou estilo de uma foto sem ajuste fino.
text prompt reference image
| |
text encoder image encoder
| |
v v
text cross-attn (frozen) IP-Adapter cross-attn
\ /
\ /
+--------> denoiser <-----------+
(frozen base)Os checkpoints do IP-Adapter são tipicamente de ~100MB, pois armazenam os pesos do adaptador, não um modelo completo. Carregue primeiro um pipeline base e, em seguida, carregue o adaptador com load_ip_adapter().
IP-Adapters estão disponíveis para muitos modelos, como Flux e Stable Diffusion 3, entre outros. Os exemplos neste guia usam Stable Diffusion e Stable Diffusion XL.
Use set_ip_adapter_scale() para controlar a intensidade com que o IP-Adapter direciona a geração. 1.0 aplica o adaptador em sua intensidade máxima; 0.5 geralmente equilibra os prompts de texto e de imagem.
Os exemplos abaixo mostram o IP-Adapter em tarefas comuns.
import torch
from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image
pipeline = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.8)Passe uma imagem para ip_adapter_image junto com um prompt de texto para gerar uma imagem.
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_diner.png")
pipeline(
prompt="a polar bear sitting in a chair drinking a milkshake",
ip_adapter_image=image,
negative_prompt="deformed, ugly, wrong proportion, low res, bad anatomy, worst quality, low quality",
).images[0]
import torch
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image
pipeline = AutoPipelineForImage2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.8)
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_bear_1.png")
ip_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_gummy.png")
pipeline(
prompt="best quality, high quality",
image=image,
ip_adapter_image=ip_image,
strength=0.5,
).images[0]
import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image
pipeline = AutoPipelineForInpainting.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.6)
mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_mask.png")
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_bear_1.png")
ip_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_gummy.png")
pipeline(
prompt="a cute gummy bear waving",
image=image,
mask_image=mask_image,
ip_adapter_image=ip_image,
).images[0]
O método enable_model_cpu_offload() é útil para reduzir o uso de memória e deve ser ativado após o carregamento do IP-Adapter. Caso contrário, o codificador de imagens do IP-Adapter também é transferido para a CPU e retorna um erro.
import torch
from diffusers import AnimateDiffPipeline, DDIMScheduler, MotionAdapter
from diffusers.utils import export_to_gif
from diffusers.utils import load_image
adapter = MotionAdapter.from_pretrained(
"guoyww/animatediff-motion-adapter-v1-5-2",
dtype=torch.float16
)
pipeline = AnimateDiffPipeline.from_pretrained(
"emilianJR/epiCRealism",
motion_adapter=adapter,
dtype=torch.float16
)
scheduler = DDIMScheduler.from_pretrained(
"emilianJR/epiCRealism",
subfolder="scheduler",
clip_sample=False,
timestep_spacing="linspace",
beta_schedule="linear",
steps_offset=1,
)
pipeline.scheduler = scheduler
pipeline.vae.enable_slicing()
pipeline.load_ip_adapter("h94/IP-Adapter", subfolder="models", weight_name="ip-adapter_sd15.bin")
pipeline.enable_model_cpu_offload()
ip_adapter_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_inpaint.png")
pipeline(
prompt="A cute gummy bear waving",
negative_prompt="bad quality, worse quality, low resolution",
ip_adapter_image=ip_adapter_image,
num_frames=16,
guidance_scale=7.5,
num_inference_steps=50,
).frames[0]
Variantes de checkpoint
Carregue o Plus quando os detalhes da imagem de referência forem mais importantes. Carregue o FaceID quando você precisar de embeddings de identidade do InsightFace em vez de embeddings de imagem do CLIP.
import torch
from transformers import CLIPVisionModelWithProjection
from diffusers import AutoPipelineForText2Image
image_encoder = CLIPVisionModelWithProjection.from_pretrained(
"h94/IP-Adapter",
subfolder="models/image_encoder",
dtype=torch.float16
)
pipeline = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
image_encoder=image_encoder,
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name="ip-adapter-plus_sdxl_vit-h.safetensors"
)Os checkpoints do FaceID usam embeddings faciais do InsightFace em vez de embeddings de imagem do CLIP. Use o DDIMScheduler ou o EulerDiscreteScheduler para modelos FaceID. Extraia os embeddings faciais e passe-os como uma lista de tensores para ip_adapter_image_embeds.
# pip install insightface
import cv2
import numpy as np
import torch
from diffusers import StableDiffusionPipeline, DDIMScheduler
from diffusers.utils import load_image
from insightface.app import FaceAnalysis
pipeline = StableDiffusionPipeline.from_pretrained(
"stable-diffusion-v1-5/stable-diffusion-v1-5",
dtype=torch.float16,
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config)
pipeline.load_ip_adapter(
"h94/IP-Adapter-FaceID",
subfolder=None,
weight_name="ip-adapter-faceid_sd15.bin",
image_encoder_folder=None
)
pipeline.set_ip_adapter_scale(0.6)
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl1.png")
ref_images_embeds = []
app = FaceAnalysis(name="buffalo_l", providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))
image = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
faces = app.get(image)
image = torch.from_numpy(faces[0].normed_embedding)
ref_images_embeds.append(image.unsqueeze(0))
ref_images_embeds = torch.stack(ref_images_embeds, dim=0).unsqueeze(0)
neg_ref_images_embeds = torch.zeros_like(ref_images_embeds)
id_embeds = torch.cat([neg_ref_images_embeds, ref_images_embeds]).to(dtype=torch.float16, device="cuda")
pipeline(
prompt="A photo of a girl",
ip_adapter_image_embeds=[id_embeds],
negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
).images[0]Para o FaceID Plus, carregue CLIPVisionModelWithProjection como o codificador de imagem.
import torch
from transformers import CLIPVisionModelWithProjection
from diffusers import AutoPipelineForText2Image
image_encoder = CLIPVisionModelWithProjection.from_pretrained(
"laion/CLIP-ViT-H-14-laion2B-s32B-b79K",
dtype=torch.float16,
)
pipeline = AutoPipelineForText2Image.from_pretrained(
"stable-diffusion-v1-5/stable-diffusion-v1-5",
image_encoder=image_encoder,
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter-FaceID",
subfolder=None,
weight_name="ip-adapter-faceid-plus_sd15.bin"
)FaceID Plus e Plus v2 também precisam de embeddings de imagem CLIP em conjunto com os embeds do InsightFace. Após preparar os embeddings faciais, codifique a imagem de referência e atribua os embeds CLIP à camada de projeção de imagem.
import torch
from diffusers.utils import load_image
ip_adapter_images = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl1.png")
num_images = 1
clip_embeds = pipeline.prepare_ip_adapter_image_embeds(
ip_adapter_image=[ip_adapter_images],
ip_adapter_image_embeds=None,
device=torch.device("cuda"),
num_images_per_prompt=num_images,
do_classifier_free_guidance=True,
)[0]
pipeline.unet.encoder_hid_proj.image_projection_layers[0].clip_embeds = clip_embeds.to(dtype=torch.float16)
# set to True if using IP-Adapter FaceID Plus v2
pipeline.unet.encoder_hid_proj.image_projection_layers[0].shortcut = FalseEmbeddings de imagem
prepare_ip_adapter_image_embeds() codifica as imagens do IP-Adapter em embeddings que você pode salvar e reutilizar. Pré-compute-os uma vez, em vez de carregar e codificar as mesmas imagens a cada execução do pipeline.
import torch
from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image
pipeline = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name="ip-adapter_sdxl.bin"
)
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_bear_1.png")
image_embeds = pipeline.prepare_ip_adapter_image_embeds(
ip_adapter_image=image,
ip_adapter_image_embeds=None,
device="cuda",
num_images_per_prompt=1,
do_classifier_free_guidance=True,
)
torch.save(image_embeds, "image_embeds.ipadpt")Recarregue os embeddings de imagem passando-os para o parâmetro ip_adapter_image_embeds. Defina image_encoder_folder como None, pois você não precisa mais do codificador de imagem para gerar os embeddings de imagem.
Você também pode carregar incorporações de imagem de outras fontes, como o ComfyUI.
pipeline = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
image_encoder_folder=None,
weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.8)
image_embeds = torch.load("image_embeds.ipadpt")
pipeline(
prompt="a polar bear sitting in a chair drinking a milkshake",
ip_adapter_image_embeds=image_embeds,
negative_prompt="deformed, ugly, wrong proportion, low res, bad anatomy, worst quality, low quality",
num_inference_steps=100,
).images[0]Mascaramento
A máscara binária permite atribuir uma imagem do IP-Adapter a uma área específica da imagem de saída, o que a torna útil para compor múltiplas imagens do IP-Adapter. Cada imagem do IP-Adapter requer uma máscara binária.
Carregue o IPAdapterMaskProcessor para pré-processar as máscaras de imagem. Para obter os melhores resultados, forneça a height e a width de saída para garantir que máscaras com diferentes proporções de aspecto sejam dimensionadas adequadamente. Se as máscaras de entrada já corresponderem à proporção de aspecto da imagem gerada, não é necessário definir a height e a width.
import torch
from diffusers import AutoPipelineForText2Image
from diffusers.image_processor import IPAdapterMaskProcessor
from diffusers.utils import load_image
pipeline = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
mask1 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_mask1.png")
mask2 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_mask2.png")
processor = IPAdapterMaskProcessor()
masks = processor.preprocess([mask1, mask2], height=1024, width=1024)
Forneça as imagens do IP-Adapter e suas escalas como uma lista. Passe as máscaras pré-processadas para cross_attention_kwargs no pipeline.
face_image1 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl1.png")
face_image2 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl2.png")
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name=["ip-adapter-plus-face_sdxl_vit-h.safetensors"]
)
pipeline.set_ip_adapter_scale([[0.7, 0.7]])
ip_images = [[face_image1, face_image2]]
masks = [masks.reshape(1, masks.shape[0], masks.shape[2], masks.shape[3])]
pipeline(
prompt="2 girls",
ip_adapter_image=ip_images,
negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
cross_attention_kwargs={"ip_adapter_masks": masks}
).images[0]
Receitas
Combine o IP-Adapter com outros adaptadores ou pipelines, como múltiplos adaptadores, ControlNet, InstantStyle ou LCM de poucas etapas, quando uma única imagem de referência não for suficiente.
Vários IP-Adapters
Combine multiple IP-Adapters to generate images in more diverse styles. For example, you can use IP-Adapter Face to generate consistent faces and characters and IP-Adapter Plus to generate those faces in specific styles. Combine múltiplos IP-Adapters para gerar imagens em estilos mais diversos. Por exemplo, você pode usar o IP-Adapter Face para gerar rostos e personagens consistentes e o IP-Adapter Plus para gerar esses rostos em estilos específicos.
Carregue um codificador de imagem com CLIPVisionModelWithProjection.
import torch
from diffusers import AutoPipelineForText2Image, DDIMScheduler
from transformers import CLIPVisionModelWithProjection
from diffusers.utils import load_image
image_encoder = CLIPVisionModelWithProjection.from_pretrained(
"h94/IP-Adapter",
subfolder="models/image_encoder",
dtype=torch.float16,
)Carregue um modelo base, um agendador e os seguintes IP-Adapters.
- ip-adapter-plus_sdxl_vit-h usa embeddings de patch e um codificador de imagem ViT-H
- ip-adapter-plus-face_sdxl_vit-h usa embeddings de patch e um codificador de imagem ViT-H, mas é condicionado em imagens de rostos recortados
pipeline = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16,
image_encoder=image_encoder,
)
pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config)
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name=["ip-adapter-plus_sdxl_vit-h.safetensors", "ip-adapter-plus-face_sdxl_vit-h.safetensors"]
)
pipeline.set_ip_adapter_scale([0.7, 0.3])
# enable_model_cpu_offload to reduce memory usage
pipeline.enable_model_cpu_offload()Carregue uma imagem e uma pasta contendo imagens de um determinado estilo a ser aplicado.
face_image = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/women_input.png")
style_folder = "https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/style_ziggy"
style_images = [load_image(f"{style_folder}/img{i}.png") for i in range(10)]
Passar as imagens de estilo e rosto como uma lista para ip_adapter_image.
generator = torch.Generator(device="cpu").manual_seed(0)
pipeline(
prompt="wonderwoman",
ip_adapter_image=[style_images, face_image],
negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
).images[0]
Controle estrutural
Para controle estrutural, combine o IP-Adapter com ControlNet condicionado em mapas de profundidade, mapas de bordas, estimativas de pose e muito mais.
O exemplo abaixo carrega um checkpoint de ControlNetModel condicionado em mapas de profundidade e o combina com um IP-Adapter.
import torch
from diffusers.utils import load_image
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
controlnet = ControlNetModel.from_pretrained(
"lllyasviel/control_v11f1p_sd15_depth",
dtype=torch.float16
)
pipeline = StableDiffusionControlNetPipeline.from_pretrained(
"stable-diffusion-v1-5/stable-diffusion-v1-5",
controlnet=controlnet,
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="models",
weight_name="ip-adapter_sd15.bin"
)Passe o mapa de profundidade e a imagem do IP-Adapter para o pipeline.
depth_map = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/depth.png")
ip_adapter_image = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/statue.png")
pipeline(
prompt="best quality, high quality",
image=depth_map,
ip_adapter_image=ip_adapter_image,
negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
).images[0]
Controle de estilo e layout
Para controle de estilo e layout, combine o IP-Adapter com InstantStyle. O InstantStyle separa o estilo (cor, textura, sensação geral) do conteúdo e aplica o estilo apenas nos blocos específicos de estilo, de modo que as áreas de conteúdo permaneçam intactas. Isso proporciona uma consistência de estilo mais forte e um controle de layout mais claro.
Ative o IP-Adapter apenas em camadas selecionadas com set_ip_adapter_scale(). O exemplo abaixo o ativa no bloco block_2 (layout) de descida e no bloco block_0 (estilo) de subida do modelo.
import torch
from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image
pipeline = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="sdxl_models",
weight_name="ip-adapter_sdxl.bin"
)
scale = {
"down": {"block_2": [0.0, 1.0]},
"up": {"block_0": [0.0, 1.0, 0.0]},
}
pipeline.set_ip_adapter_scale(scale)Carregue a imagem de estilo e gere uma imagem.
style_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/0052a70beed5bf71b92610a43a52df6d286cd5f3/diffusers/rabbit.jpg")
pipeline(
prompt="a cat, masterpiece, best quality, high quality",
ip_adapter_image=style_image,
negative_prompt="text, watermark, lowres, low quality, worst quality, deformed, glitch, low contrast, noisy, saturation, blurry",
guidance_scale=5,
).images[0]
As figuras abaixo comparam a ativação apenas de estilo do InstantStyle (até o block_0) com a ativação do IP-Adapter em todas as camadas. A configuração de todas as camadas geralmente segue o prompt de imagem com mais força e pode reduzir a diversidade. Prefira a escala apenas de estilo quando desejar o comportamento de preservação de layout do InstantStyle.
Você não precisa especificar todas as camadas no dicionário
scale. As camadas não incluídas são definidas como 0, o que significa que o IP-Adapter está desativado.
scale = {
"up": {"block_0": [0.0, 1.0, 0.0]},
}
pipeline.set_ip_adapter_scale(scale)
pipeline(
prompt="a cat, masterpiece, best quality, high quality",
ip_adapter_image=style_image,
negative_prompt="text, watermark, lowres, low quality, worst quality, deformed, glitch, low contrast, noisy, saturation, blurry",
guidance_scale=5,
).images[0]
Geração instantânea
Combine o IP-Adapter com um LoRA LCM para geração em poucas etapas.
import torch
from diffusers import DiffusionPipeline, LCMScheduler
from diffusers.utils import load_image
pipeline = DiffusionPipeline.from_pretrained(
"sd-dreambooth-library/herge-style",
dtype=torch.float16
)
pipeline.load_ip_adapter(
"h94/IP-Adapter",
subfolder="models",
weight_name="ip-adapter_sd15.bin"
)
pipeline.load_lora_weights("latent-consistency/lcm-lora-sdv1-5")
pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
pipeline.enable_model_cpu_offload()
pipeline.set_ip_adapter_scale(0.4)
ip_adapter_image = load_image("https://user-images.githubusercontent.com/24734142/266492875-2d50d223-8475-44f0-a7c6-08b51cb53572.png")
pipeline(
prompt="herge_style woman in armor, best quality, high quality",
ip_adapter_image=ip_adapter_image,
num_inference_steps=4,
guidance_scale=1,
).images[0]