Diffusers 文档

IP-Adapter

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

IP-Adapter

IP-Adapter 是一个图像 prompt 适配器,可以插入到扩散模型中,以实现图像 prompt,而无需对底层模型进行任何更改。此外,此适配器可以与从同一基础模型微调的其他模型重复使用,并且可以与其他适配器(如 ControlNet)结合使用。IP-Adapter 背后的关键思想是解耦交叉注意力机制,它为图像特征添加了一个单独的交叉注意力层,而不是对文本和图像特征使用相同的交叉注意力层。这使得模型能够学习更多特定于图像的特征。

了解如何在 加载适配器 指南中加载 IP-Adapter,并确保查看 IP-Adapter Plus 部分,该部分需要手动加载图像编码器。

本指南将引导您了解如何使用 IP-Adapter 执行各种任务和用例。

通用任务

让我们来看看如何将 IP-Adapter 的图像 prompt 功能与 StableDiffusionXLPipeline 一起使用,以执行诸如文本到图像、图像到图像和图像修复之类的任务。我们还鼓励您尝试其他 pipelines,例如 Stable Diffusion、LCM-LoRA、ControlNet、T2I-Adapter 或 AnimateDiff!

在以下所有示例中,您都会看到 set_ip_adapter_scale() 方法。此方法控制应用于模型的文本或图像条件的数量。值 1.0 表示模型仅以图像 prompt 为条件。降低此值会鼓励模型生成更多样化的图像,但它们可能与图像 prompt 的对齐程度不高。通常,值 0.5 在两种 prompt 类型之间实现了良好的平衡,并产生了良好的结果。

在下面的示例中,尝试将 low_cpu_mem_usage=True 添加到 load_ip_adapter() 方法以加快加载时间。

文本到图像
图像到图像
图像修复
视频

制作精确的文本 prompt 以生成您想要的图像可能很困难,因为它可能并不总是捕捉到您想要表达的内容。在文本 prompt 旁边添加图像有助于模型更好地理解它应该生成什么,并可以产生更准确的结果。

加载 Stable Diffusion XL (SDXL) 模型,并使用 load_ip_adapter() 方法将 IP-Adapter 插入到模型中。使用 subfolder 参数加载 SDXL 模型权重。

from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image
import torch

pipeline = AutoPipelineForText2Image.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16).to("cuda")
pipeline.load_ip_adapter("h94/IP-Adapter", subfolder="sdxl_models", weight_name="ip-adapter_sdxl.bin")
pipeline.set_ip_adapter_scale(0.6)

创建一个文本 prompt 并加载一个图像 prompt,然后再将它们传递给 pipeline 以生成图像。

image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_diner.png")
generator = torch.Generator(device="cpu").manual_seed(0)
images = 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",
    num_inference_steps=100,
    generator=generator,
).images
images[0]
IP-Adapter 图像
生成的图像

配置参数

有一些 IP-Adapter 参数非常有用,可以帮助您完成图像生成任务。这些参数可以使您的工作流程更高效,或者让您更好地控制图像生成。

图像嵌入

启用 IP-Adapter 的 pipelines 提供了 ip_adapter_image_embeds 参数来接受预计算的图像嵌入。这在您需要多次运行 IP-Adapter pipeline 的情况下特别有用,因为您有多个图像。例如,多 IP-Adapter 是一个特定的用例,您可以在其中提供多个样式图像以生成特定样式的特定图像。每次使用 pipeline 时都加载和编码多个图像效率低下。相反,您可以预先计算并将图像嵌入保存到磁盘(如果您使用的是高质量图像,这可以节省大量空间),并在需要时加载它们。

此参数还使您可以灵活地从其他来源加载嵌入。例如,用于 IP-Adapter 的 ComfyUI 图像嵌入与 Diffusers 兼容,并且应该可以开箱即用!

调用 prepare_ip_adapter_image_embeds() 方法来编码和生成图像嵌入。然后,您可以使用 torch.save 将它们保存到磁盘。

如果您将 IP-Adapter 与 ip_adapter_image_embedding 而不是 ip_adapter_image 一起使用,则可以设置 load_ip_adapter(image_encoder_folder=None,...),因为您不需要加载编码器来生成图像嵌入。

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")

现在,通过将图像嵌入传递给 ip_adapter_image_embeds 参数来加载它们。

image_embeds = torch.load("image_embeds.ipadpt")
images = 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,
    generator=generator,
).images

IP-Adapter 掩码

二元掩码指定输出图像的哪个部分应分配给 IP-Adapter。这对于组合多个 IP-Adapter 图像很有用。对于每个输入 IP-Adapter 图像,您必须提供一个二元掩码。

首先,使用 ~image_processor.IPAdapterMaskProcessor.preprocess() 预处理输入 IP-Adapter 图像以生成其掩码。为了获得最佳结果,请将输出高度和宽度提供给 ~image_processor.IPAdapterMaskProcessor.preprocess()。这确保了不同宽高比的掩码被适当地拉伸。如果输入掩码已经与生成图像的宽高比匹配,则无需设置 heightwidth

from diffusers.image_processor import IPAdapterMaskProcessor

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")

output_height = 1024
output_width = 1024

processor = IPAdapterMaskProcessor()
masks = processor.preprocess([mask1, mask2], height=output_height, width=output_width)
掩码一
掩码二

当有多个输入 IP-Adapter 图像时,将它们作为列表加载并提供 IP-Adapter 缩放列表。此处的每个输入 IP-Adapter 图像都对应于上面生成的掩码之一。

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]])  # one scale for each image-mask pair

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")

ip_images = [[face_image1, face_image2]]

masks = [masks.reshape(1, masks.shape[0], masks.shape[2], masks.shape[3])]
IP-Adapter 图像一
IP-Adapter 图像二

现在,将预处理的掩码传递给 pipeline 调用中的 cross_attention_kwargs

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

image = pipeline(
    prompt="2 girls",
    ip_adapter_image=ip_images,
    negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
    num_inference_steps=20,
    num_images_per_prompt=num_images,
    generator=generator,
    cross_attention_kwargs={"ip_adapter_masks": masks}
).images[0]
image
已应用 IP-Adapter 掩码
未应用 IP-Adapter 掩码

特定用例

IP-Adapter 的图像 prompt 功能以及与其他适配器和模型的兼容性使其成为各种用例的多功能工具。本节介绍 IP-Adapter 的一些更流行的应用,我们迫不及待想看看您会想到什么!

面部模型

生成准确的面部是很具有挑战性的,因为它们复杂且细致入微。Diffusers 支持两个 IP-Adapter 检查点,专门用于从 h94/IP-Adapter 仓库生成面部

此外,Diffusers 支持所有使用 insightface 面部模型提取的面部嵌入训练的 IP-Adapter 检查点。支持的模型来自 h94/IP-Adapter-FaceID 仓库。

对于面部模型,请使用 h94/IP-Adapter 检查点。还建议将 DDIMSchedulerEulerDiscreteScheduler 用于面部模型。

import torch
from diffusers import StableDiffusionPipeline, DDIMScheduler
from diffusers.utils import load_image

pipeline = StableDiffusionPipeline.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5",
    torch_dtype=torch.float16,
).to("cuda")
pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config)
pipeline.load_ip_adapter("h94/IP-Adapter", subfolder="models", weight_name="ip-adapter-full-face_sd15.bin")

pipeline.set_ip_adapter_scale(0.5)

image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_einstein_base.png")
generator = torch.Generator(device="cpu").manual_seed(26)

image = pipeline(
    prompt="A photo of Einstein as a chef, wearing an apron, cooking in a French restaurant",
    ip_adapter_image=image,
    negative_prompt="lowres, bad anatomy, worst quality, low quality",
    num_inference_steps=100,
    generator=generator,
).images[0]
image
IP-Adapter 图像
生成的图像

要使用 IP-Adapter FaceID 模型,首先使用 insightface 提取面部嵌入。然后将 tensors 列表作为 ip_adapter_image_embeds 传递给 pipeline。

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",
    torch_dtype=torch.float16,
).to("cuda")
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_BGR2RGB)
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")

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

images = pipeline(
    prompt="A photo of a girl",
    ip_adapter_image_embeds=[id_embeds],
    negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
    num_inference_steps=20, num_images_per_prompt=1,
    generator=generator
).images

IP-Adapter FaceID Plus 和 Plus v2 模型都需要 CLIP 图像嵌入。您可以按照之前所示准备面部嵌入,然后您可以提取 CLIP 嵌入并将其传递给隐藏图像投影层。

from insightface.utils import face_align

ref_images_embeds = []
ip_adapter_images = []
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_BGR2RGB)
faces = app.get(image)
ip_adapter_images.append(face_align.norm_crop(image, landmark=faces[0].kps, image_size=224))
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")

clip_embeds = pipeline.prepare_ip_adapter_image_embeds(
  [ip_adapter_images], None, torch.device("cuda"), num_images, True)[0]

pipeline.unet.encoder_hid_proj.image_projection_layers[0].clip_embeds = clip_embeds.to(dtype=torch.float16)
pipeline.unet.encoder_hid_proj.image_projection_layers[0].shortcut = False # True if Plus v2

多 IP-Adapter

可以同时使用多个 IP-Adapter 以生成具有更多样化风格的特定图像。例如,您可以使用 IP-Adapter-Face 生成一致的面部和角色,并使用 IP-Adapter Plus 以特定风格生成这些面部。

阅读 IP-Adapter Plus 部分,了解为什么需要手动加载图像编码器。

使用 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",
    torch_dtype=torch.float16,
)

接下来,您将加载基础模型、scheduler 和 IP-Adapters。要使用的 IP-Adapters 作为列表传递给 weight_name 参数

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    torch_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])
pipeline.enable_model_cpu_offload()

加载图像提示和一个包含您想要使用的特定风格图像的文件夹。

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)]
IP-Adapter 面部图像
IP-Adapter 风格图像

将图像提示和风格图像作为列表传递给 ip_adapter_image 参数,并运行 pipeline!

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

image = pipeline(
    prompt="wonderwoman",
    ip_adapter_image=[style_images, face_image],
    negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
    num_inference_steps=50, num_images_per_prompt=1,
    generator=generator,
).images[0]
image
   

即时生成

潜在一致性模型 (LCM) 是扩散模型,与其他扩散模型(如 SDXL,通常需要更多步骤)相比,它可以在短短 4 步内生成图像。 这就是为什么使用 LCM 生成图像感觉“即时”的原因。 IP-Adapter 可以插入到 LCM-LoRA 模型中,以使用图像提示即时生成图像。

需要先加载 IP-Adapter 权重,然后您可以使用 load_lora_weights() 加载您想要应用于图像的 LoRA 风格和权重。

from diffusers import DiffusionPipeline, LCMScheduler
import torch
from diffusers.utils import load_image

model_id = "sd-dreambooth-library/herge-style"
lcm_lora_id = "latent-consistency/lcm-lora-sdv1-5"

pipeline = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)

pipeline.load_ip_adapter("h94/IP-Adapter", subfolder="models", weight_name="ip-adapter_sd15.bin")
pipeline.load_lora_weights(lcm_lora_id)
pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
pipeline.enable_model_cpu_offload()

尝试使用较低的 IP-Adapter 缩放比例,以便更多地根据 herge_style 检查点进行图像生成调节,并记住在您的提示中使用特殊 token herge_style 来触发和应用该风格。

pipeline.set_ip_adapter_scale(0.4)

prompt = "herge_style woman in armor, best quality, high quality"
generator = torch.Generator(device="cpu").manual_seed(0)

ip_adapter_image = load_image("https://user-images.githubusercontent.com/24734142/266492875-2d50d223-8475-44f0-a7c6-08b51cb53572.png")
image = pipeline(
    prompt=prompt,
    ip_adapter_image=ip_adapter_image,
    num_inference_steps=4,
    guidance_scale=1,
).images[0]
image
   

结构控制

为了更大程度地控制图像生成,您可以将 IP-Adapter 与 ControlNet 等模型结合使用。 ControlNet 也是一种适配器,可以插入到扩散模型中,以允许根据额外的控制图像进行调节。 控制图像可以是深度图、边缘图、姿势估计等等。

加载一个以深度图为条件的 ControlNetModel 检查点,将其插入到扩散模型中,并加载 IP-Adapter。

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import torch
from diffusers.utils import load_image

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

pipeline = StableDiffusionControlNetPipeline.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16)
pipeline.to("cuda")
pipeline.load_ip_adapter("h94/IP-Adapter", subfolder="models", weight_name="ip-adapter_sd15.bin")

现在加载 IP-Adapter 图像和深度图。

ip_adapter_image = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/statue.png")
depth_map = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/depth.png")
IP-Adapter 图像
深度图

将深度图和 IP-Adapter 图像传递给 pipeline 以生成图像。

generator = torch.Generator(device="cpu").manual_seed(33)
image = 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",
    num_inference_steps=50,
    generator=generator,
).images[0]
image
   

风格和布局控制

InstantStyle 是 IP-Adapter 之上的即插即用方法,它从图像提示中解耦风格和布局以控制图像生成。 这样,您可以仅根据图像提示的风格或布局生成图像,并显着提高多样性。 这是通过仅激活模型特定部分的 IP-Adapter 来实现的。

默认情况下,IP-Adapter 插入到模型的所有层。 使用带有字典的 set_ip_adapter_scale() 方法为不同层的 IP-Adapter 分配缩放比例。

from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image
import torch

pipeline = AutoPipelineForText2Image.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16).to("cuda")
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)

这将在模型的 down-part block 2 和 up-part block 0 的第二层激活 IP-Adapter。前者是 IP-Adapter 注入布局信息的层,后者注入风格。 将 IP-Adapter 插入到这两层,您可以生成既遵循图像提示的风格和布局,又具有更符合文本提示的内容的图像。

style_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/0052a70beed5bf71b92610a43a52df6d286cd5f3/diffusers/rabbit.jpg")

generator = torch.Generator(device="cpu").manual_seed(26)
image = 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,
    num_inference_steps=30,
    generator=generator,
).images[0]
image
IP-Adapter 图像
生成的图像

相反,将 IP-Adapter 插入到所有层通常会生成过度关注图像提示并降低多样性的图像。

仅在风格层激活 IP-Adapter,然后再次调用 pipeline。

scale = {
    "up": {"block_0": [0.0, 1.0, 0.0]},
}
pipeline.set_ip_adapter_scale(scale)

generator = torch.Generator(device="cpu").manual_seed(26)
image = 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,
    num_inference_steps=30,
    generator=generator,
).images[0]
image
仅在风格层中的 IP-Adapter
所有层中的 IP-Adapter

请注意,您不必在字典中指定所有层。 未包含在字典中的层将设置为比例 0,这意味着默认情况下禁用 IP-Adapter。

< > 在 GitHub 上更新