嗨,大家好!你是否曾想象过,如何能够轻松地使用扩散系统进行推理,而不必深入研究其复杂的组成部分?Diffusers库为你提供了解决方案。扩散系统通常包括多个组件,如参数化模型、分词器和调度器,它们以复杂的方式相互作用。因此,我们设计了DiffusionPipeline,将整个扩散系统的复杂性封装成易于使用的API,同时仍然具有足够的灵活性,可以用作构建自己的扩散系统的构建块。
你可以使用from_pretrained()
方法轻松加载所有需要进行推理或训练的内容。
加载Pipeline
DiffusionPipeline类是从Hub中加载任何扩散模型的最简单和最通用的方法。DiffusionPipeline.from_pretrained()
方法会自动检测正确的管道类别,从检查点下载和缓存所有所需的配置和权重文件,并返回一个准备好进行推理的管道实例。
from diffusers import DiffusionPipeline
repo_id = "runwayml/stable-diffusion-v1-5"
pipe = DiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)
你也可以加载具有特定管道类别的检查点。上面的示例加载了一个Stable Diffusion模型;要获得相同的结果,使用StableDiffusionPipeline类:
from diffusers import StableDiffusionPipeline
repo_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)
一个检查点(例如CompVis/stable-diffusion-v1-4或runwayml/stable-diffusion-v1-5)也可以用于多个任务,比如文本到图像或图像到图像。为了区分要使用检查点进行的任务,你必须直接使用相应的任务特定管道类别加载它:
from diffusers import StableDiffusionImg2ImgPipeline
repo_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(repo_id)
本地Pipeline
要在本地加载扩散管道,使用git-lfs手动下载检查点(在本例中是runwayml/stable-diffusion-v1-5)到本地磁盘。这将在你的磁盘上创建一个本地文件夹,即./stable-diffusion-v1-5:
git-lfs install
git clone https://huggingface.co/runwayml/stable-diffusion-v1-5
然后将本地路径传递给from_pretrained()
:
from diffusers import DiffusionPipeline
repo_id = "./stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)
当检测到本地路径时,from_pretrained()
方法不会从Hub下载任何文件,但这也意味着它不会下载和缓存检查点的最新更改。
替换管道中的组件
你可以使用另一个兼容的组件自定义任何管道的默认组件。自定义是重要的,因为:
- 更改调度器对于探索生成速度和质量之间的权衡是重要的。
- 模型的不同组件通常是独立训练的,你可以用更性能更好的组件替换一个组件。
- 在微调过程中,通常只有一些组件,如UNet或文本编码器,是经过训练的。
要了解哪些调度器可以进行自定义,你可以使用compatibles
方法:
from diffusers import DiffusionPipeline
repo_id = "runwayml/stable-d
iffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)
stable_diffusion.scheduler.compatibles
让我们使用SchedulerMixin.from_pretrained()
方法将默认的PNDMScheduler替换为性能更好的调度器EulerDiscreteScheduler。subfolder="scheduler"
参数是从管道仓库的正确子文件夹加载调度器配置所必需的。
然后,你可以将新的EulerDiscreteScheduler实例传递给DiffusionPipeline中的scheduler参数:
from diffusers import DiffusionPipeline, EulerDiscreteScheduler, DPMSolverMultistepScheduler
repo_id = "runwayml/stable-diffusion-v1-5"
scheduler = EulerDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, scheduler=scheduler, use_safetensors=True)
安全检查器
稳定扩散等扩散模型可能生成有害内容,因此Diffusers库具有安全检查器,用于检查生成的输出是否包含已知的硬编码NSFW内容。如果出于任何原因要禁用安全检查器,请将None
传递给safety_checker
参数:
from diffusers import DiffusionPipeline
repo_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, safety_checker=None, use_safetensors=True)
在多个管道之间重用组件
你还可以在多个管道中重用相同的组件,以避免将权重加载到RAM两次。使用components
方法保存组件:
from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipeline
model_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion_txt2img = StableDiffusionPipeline.from_pretrained(model_id, use_safetensors=True)
components = stable_diffusion_txt2img.components
然后,你可以将组件传递给另一个管道,而不必重新加载权重到RAM:
stable_diffusion_img2img = StableDiffusionImg2ImgPipeline(**components)
如果你想更灵活地选择要重用或禁用的组件,还可以逐个传递组件给管道。例如,在图像到图像管道中重用相同的组件,除了安全检查器和特征提取器:
from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipeline
model_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion_txt2img = StableDiffusionPipeline.from_pretrained(model_id, use_safetensors=True)
stable_diffusion_img2img = StableDiffusionImg2ImgPipeline(
vae=stable_diffusion_txt2img.vae,
text_encoder=stable_diffusion_txt2img.text_encoder,
tokenizer=stable_diffusion_txt2img.tokenizer,
unet=stable_diffusion_txt2img.unet,
scheduler=stable_diffusion_txt2img.scheduler,
safety_checker=None,
feature_extractor=None,
requires_safety_checker=False,
)
检查点变体
检查点变体通常是具有以下特点的检查点:
- 以不同的浮点类型存储,以实现较低的精度和存储(例如torch.float16),因为它只需要半带宽和存储来下载。如果要继续训练或使用CPU,你不能使用此变体。
- 非指数均值平均(EMA)权重,不应用于推理。你应该使用这些权重来继续微调模型。
当检查点具有相同的模型结构但是在不同的数据集和不同的训练设置下训练时,它们应该存储在不同的存储库中,而不是在变体中(例如stable-diffusion-v1-4和stable-diffusion-v1-5)。
否则,变体与原始检查点完全相同。它们具有完全相同的序列化格式(如Safetensors)、模型结构和权重具有相同的张量形状。
有两个重要的参数用于加载变体:
-
torch_dtype 定义加载检查点的浮点精度。例如,如果你想通过加载fp16变体来节省带宽,应该指定torch_dtype=torch.float16以将权重转换为fp16。否则,fp16权重将在加载后转换为默认的fp32精度。你还可以加载原始检查点,而不定义variant参数,并在加载后将其转换为fp16,方法是torch_dtype=torch.float16。在这种情况下,首先下载默认的fp32权重,然后在加载后将其转换为fp16。
-
variant 定义应从存储库中加载哪些文件。例如,如果要从diffusers/stable-diffusion-variants存储库中加载non_ema变体,你应该指定variant="non_ema"以下载non_ema文件。
from diffusers import DiffusionPipeline
import torch
# 加载fp16变体
stable_diffusion = DiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5", variant="fp16", torch_dtype=torch.float16, use_safetensors=True
)
# 加载non_ema变体
stable_diffusion = DiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5", variant="non_ema", use_safetensors=True
)
要将存储在不同浮点类型中的检查点或非EMA变体保存到检查点中,请使用DiffusionPipeline.save_pretrained()方法,并指定variant参数。你应该尝试将变体保存到与原始检查点相同的文件夹中,以便可以从同一文件夹中加载两者:
from diffusers import DiffusionPipeline
# 保存为fp16变体
stable_diffusion.save_pretrained("runwayml/stable-diffusion-v1-5", variant="fp16")
# 保存为non_ema变体
stable_diffusion.save_pretrained("runwayml/stable
-diffusion-v1-5", variant="non_ema")
如果你不将变体保存到现有文件夹中,则必须指定variant参数,否则它会抛出异常,因为找不到原始检查点:
# 这样不行
stable_diffusion = DiffusionPipeline.from_pretrained(
"./stable-diffusion-v1-5", torch_dtype=torch.float16, use_safetensors=True
)
# 这样可以
stable_diffusion = DiffusionPipeline.from_pretrained(
"./stable-diffusion-v1-5", variant="fp16", torch_dtype=torch.float16, use_safetensors=True
)
模型
模型是使用ModelMixin.from_pretrained()方法加载的,该方法下载并缓存模型权重和配置的最新版本。如果本地缓存中可用最新文件,则from_pretrained()将重用缓存中的文件,而不会重新下载它们。
可以使用subfolder
参数从子文件夹加载模型。例如,runwayml/stable-diffusion-v1-5的模型权重存储在unet子文件夹中:
from diffusers import UNet2DConditionModel
repo_id = "runwayml/stable-diffusion-v1-5"
model = UNet2DConditionModel.from_pretrained(repo_id, subfolder="unet", use_safetensors=True)
或直接从存储库的目录中加载:
from diffusers import UNet2DModel
repo_id = "google/ddpm-cifar10-32"
model = UNet2DModel.from_pretrained(repo_id, use_safetensors=True)
你还可以通过在ModelMixin.from_pretrained()和ModelMixin.save_pretrained()中指定variant参数来加载和保存模型变体:
from diffusers import UNet2DConditionModel
model = UNet2DConditionModel.from_pretrained(
"runwayml/stable-diffusion-v1-5", subfolder="unet", variant="non-ema", use_safetensors=True
)
model.save_pretrained("./local-unet", variant="non-ema")
调度器
调度器是从SchedulerMixin.from_pretrained()方法加载的,与模型不同,调度器不是参数化或训练的,而是由配置文件定义的。
加载调度器不会消耗大量内存,相同的配置文件可以用于各种不同的调度器。例如,以下调度器与StableDiffusionPipeline兼容,这意味着你可以在这些类中的任何一个中加载相同的调度器配置文件:
from diffusers import StableDiffusionPipeline
from diffusers import (
DDPMScheduler,
DDIMScheduler,
PNDMScheduler,
LMSDiscreteScheduler,
EulerDiscreteScheduler,
EulerAncestralDiscreteScheduler,
DPMSolverMultistepScheduler,
)
repo_id = "runwayml/stable-diffusion-v1-5"
ddpm = DDPMScheduler.from_pretrained(repo_id, subfolder="scheduler")
ddim = DDIMScheduler.from_pretrained(repo_id, subfolder="scheduler")
pndm = PNDMScheduler.from_pretrained(repo_id, subfolder="scheduler")
lms = LMSDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
euler_anc = EulerAncestralDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
euler = EulerDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
dpm = DPMSolverMultistepScheduler.from_pretrained(repo_id, subfolder="scheduler")
# 用任何一个替换`dpm`,如`ddpm`、`ddim`、`pndm`、`lms`、`euler_anc`、`euler`
pipeline = StableDiffusionPipeline.from_pretrained(repo_id, scheduler=dpm, use_safetensors=True)
DiffusionPipeline解释
作为一个类方法,DiffusionPipeline.from_pretrained()负责两件事:
- 下载所需的用于推理的文件夹结构的最新版本并将其缓存。如果本地缓存中有最新的文件夹结构,则DiffusionPipeline.from_pretrained()将重用缓存并不会重新下载文件。
- 加载缓存的权重到正确的管道类中 - 从model_index.json文件中检索 - 并返回一个已准备好进行推理的实例。
管道的底层文件夹结构与它们的类实例直接对应。例如,StableDiffusionPipeline对应于runwayml/stable-diffusion-v1-5的文件夹结构。在这个结构中,各个组件都是独立的,允许你自由地替换或升级它们,同时确保其他组件保持不变。
结论
Diffusers库为AI艺术的未来提供了强大的工具,使你能够轻松地加载、自定义和重用扩散系统的组件。这些功能使你能够更灵活地使用扩散系统,以满足你的创作和研究需求。无论是加载模型、替换调度器还是定制组件,Diffusers库都为你提供了便捷的方法,助力你在AI艺术领域取得更多创新成果。
本文介绍了Diffusers库的主要功能和使用方法,希望对你有所帮助。如果你有任何问题或需要进一步的帮助,请随时提出。愿你在AI艺术的创作旅程中取得巨大成功!