IP-Adapter
IP-Adapter 是一种图像提示适配器,可以插入扩散模型中,以在不改变底层模型的情况下实现图像提示。此外,该适配器可以与从同一基础模型微调的其他模型一起重复使用,并且可以与其他适配器(如 ControlNet)组合使用。 IP-Adapter 背后的关键思想是解耦交叉注意力机制,该机制为图像特征添加了一个单独的交叉注意力层,而不是对文本和图像特征使用相同的交叉注意力层。这使得模型能够学习更多特定于图像的特征。
了解如何在 加载适配器 指南中加载 IP-Adapter,并确保查看 IP-Adapter Plus 部分,该部分需要手动加载图像编码器。
本指南将指导您完成在各种任务和用例中使用 IP-Adapter 的步骤。
常规任务
让我们看看如何使用 IP-Adapter 的图像提示功能,并使用 StableDiffusionXLPipeline 完成文本到图像、图像到图像和修复等任务。我们还鼓励您尝试其他管道,例如 Stable Diffusion、LCM-LoRA、ControlNet、T2I-Adapter 或 AnimateDiff!
在以下所有示例中,您将看到 set_ip_adapter_scale() 方法。此方法控制应用于模型的文本或图像条件的数量。值为 1.0
表示模型仅受图像提示条件约束。降低此值会鼓励模型生成更多样化的图像,但它们可能与图像提示不那么一致。通常,值为 0.5
在两种提示类型之间取得良好的平衡,并产生良好的结果。
在以下示例中,尝试在 load_ip_adapter() 方法中添加 low_cpu_mem_usage=True
以加快加载时间。
创建用于生成所需图像的精确文本提示可能很困难,因为它可能无法始终捕获您想要表达的内容。在文本提示旁边添加图像可以帮助模型更好地理解它应该生成的内容,并可能导致更准确的结果。
加载 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)
创建文本提示并加载图像提示,然后将它们传递给管道以生成图像。
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_image_embeds
参数以接受预先计算的图像嵌入。这在您需要多次运行 IP-Adapter 管道的情况下特别有用,因为您有多个图像。例如,多个 IP-Adapter 是一个特定的用例,您提供多个样式图像以在特定样式中生成特定图像。每次使用管道时加载和编码多个图像效率低下。相反,您可以预先计算并将图像嵌入保存到磁盘(如果您使用的是高质量图像,这可以节省大量空间),并在需要时加载它们。
此参数还让您能够从其他来源加载嵌入。例如,用于 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()
。这可以确保具有不同纵横比的遮罩被适当地拉伸。如果输入遮罩已经匹配生成图像的纵横比,则您不必设置 height
和 width
。
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])]
现在将预处理的遮罩传递给管道调用中的 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 的一些更流行的应用,我们迫不及待地想看看你会想出什么!
人脸模型
生成准确的人脸具有挑战性,因为它们复杂且细微。Diffusers 支持两个专门训练用于从 h94/IP-Adapter 存储库生成人脸的 IP-Adapter 检查点。
- ip-adapter-full-face_sd15.safetensors 经过裁剪人脸图像和去除背景的训练。
- ip-adapter-plus-face_sd15.safetensors 使用补丁嵌入,并经过裁剪人脸图像的训练。
此外,Diffusers 支持所有使用 insightface
人脸模型提取的人脸嵌入训练的 IP-Adapter 检查点。支持的模型来自 h94/IP-Adapter-FaceID 存储库。
对于人脸模型,请使用 h94/IP-Adapter 检查点。建议使用 DDIMScheduler 或 EulerDiscreteScheduler 用于人脸模型。
import torch
from diffusers import StableDiffusionPipeline, DDIMScheduler
from diffusers.utils import load_image
pipeline = StableDiffusionPipeline.from_pretrained(
"runwayml/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 FaceID 模型,首先使用 insightface
提取人脸嵌入。然后将张量列表作为 ip_adapter_image_embeds
传递到管道。
import torch
from diffusers import StableDiffusionPipeline, DDIMScheduler
from diffusers.utils import load_image
from insightface.app import FaceAnalysis
pipeline = StableDiffusionPipeline.from_pretrained(
"runwayml/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,
)
接下来,您将加载基本模型、调度器和 IP-Adapter。要使用的 IP-Adapter 作为列表传递给 weight_name
参数。
- ip-adapter-plus_sdxl_vit-h 使用补丁嵌入和 ViT-H 图像编码器。
- ip-adapter-plus-face_sdxl_vit-h 具有相同的架构,但经过裁剪人脸图像的训练。
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_image
参数,并运行管道!
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 检查点,并记住在您的提示中使用特殊标记 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(
"runwayml/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 图像传递到管道以生成图像。
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)
这将在模型的下部块 2 和上部块 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,然后再次调用管道。
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
请注意,您不必在字典中指定所有层。字典中未包含的那些默认情况下将设置为比例 0,这意味着禁用 IP-Adapter。
< > 更新 在 GitHub 上