【Diffusers库】第五篇 加载pipeline、model、schedulers

写在前面的话

  这是我们研发的用于 消费决策的AI助理 ,我们会持续优化,欢迎体验与反馈。微信扫描二维码,添加即可。
  官方链接:https://ailab.smzdm.com/

************************************************************** 分割线 ****************************************************************

  官网的这一章节,我觉得有点繁琐,部分内容在前面的博客中有提到,所以这篇梳理总结一下,省些时间。

从不同的位置加载模型

from diffusers import DiffusionPipeline, StableDiffusionPipeline,StableDiffusionImg2ImgPipeline

repo_id = "runwayml/stable-diffusion-v1-5"

# 方法一, 第一次加载会自动下载,随后再次加载会从缓存中加载
pipe = DiffusionPipeline.from_pretrained(repo_id)

# 方法二, 第一次加载会自动下载,随后再次加载会从缓存中加载
pipe = StableDiffusionPipeline.from_pretrained(repo_id)

# 方法三, 第一次加载会自动下载,随后再次加载会从缓存中加载,用于图生图
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(repo_id)

# 方法四, 从指定路径加载
repo_id = "./stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id)

加载模型的不同部分

调度器

查看可用调度器

  在进行图像生成的时候,pipeline有好几个部分,不同的部分产生的作用不一样,因而我们可以替换一下不同的组件,来提升图像生成的质量和效率。

  • 改变调度器,并且权衡图像生成时的速度和质量非常重要。
  • 模型的不同组件通常是独立训练的,您可以将组件换成性能更好的组件。
  • 在微调过程中,通常只训练一些组件,如UNet或文本编码器。

  为了检查调度器与加载模型的兼容性,可以使用compatibles函数:

from diffusers import DiffusionPipeline

repo_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id)
stable_diffusion.scheduler.compatibles

返回

[<class 'diffusers.schedulers.scheduling_lms_discrete.LMSDiscreteScheduler'>,
 <class 'diffusers.schedulers.scheduling_unipc_multistep.UniPCMultistepScheduler'>, 
 <class 'diffusers.utils.dummy_torch_and_torchsde_objects.DPMSolverSDEScheduler'>, 
 <class 'diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler'>, 
 <class 'diffusers.schedulers.scheduling_ddim.DDIMScheduler'>, 
 <class 'diffusers.schedulers.scheduling_dpmsolver_singlestep.DPMSolverSinglestepScheduler'>, 
 <class 'diffusers.schedulers.scheduling_deis_multistep.DEISMultistepScheduler'>, 
 <class 'diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler'>, 
 <class 'diffusers.schedulers.scheduling_pndm.PNDMScheduler'>, 
 <class 'diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler'>, 
 <class 'diffusers.schedulers.scheduling_k_dpm_2_discrete.KDPM2DiscreteScheduler'>, 
 <class 'diffusers.schedulers.scheduling_ddpm.DDPMScheduler'>, 
 <class 'diffusers.schedulers.scheduling_k_dpm_2_ancestral_discrete.KDPM2AncestralDiscreteScheduler'>, 
 <class 'diffusers.schedulers.scheduling_euler_ancestral_discrete.EulerAncestralDiscreteScheduler'>]

这里可以看到这个pipeline可以使用的调度器

更换可用调度器

from diffusers import DiffusionPipeline, EulerDiscreteScheduler, DPMSolverMultistepScheduler
repo_id = "runwayml/stable-diffusion-v1-5"

# 使用EulerDiscreteScheduler中的调度器,替换默认的调度器,但是需要指定文件夹
scheduler = EulerDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, scheduler=scheduler)

安全模型

主要通过from_pretrained方法中的safety_checker参数来设定的。这个主要是 防止色情和暴力之类的。

from diffusers import DiffusionPipeline

repo_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, safety_checker=None)

重复使用组件

还可以在多个pipeline中,使用相同的组件,以避免重复加载:

from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipeline

model_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion_txt2img = StableDiffusionPipeline.from_pretrained(model_id)
components = stable_diffusion_txt2img.components

for i in components:
     print(i)

输出了这个pipeline里的不同的组件,这些组件中记录了模型参数、网络结构等等:

vae
text_encoder
tokenizer
unet
scheduler
safety_checker
feature_extractor

然后,可以将组件传递到另一个pipeline,无需将模型重新加载到内存中:

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

模型变种

这个概念可能比较陌生,我的理解就是在预训练模型的基础上,训练出来的模型,叫做模型变体(Checkpoint variants)

  • 模型中的参数的数据类型在进行存储的时候是有选择的,比如:torch.float16,可以获得较低的精度和较低的存储空间。但是,如果使用的是CPU,则不能使用此变体。
  • Non-exponential mean averaged (EMA) weights 不能进行图例,只能进行微调模型。

加载

另外,还有2个重要的参数,在加载模型的时候要使用,
一个是指定torch_dtype(数据格式),就是上文中提到的torch.float16,
一个是指定variant(模型变种),我感觉,这个参数会明确加载模型时的目的,是用于推理 or 训练。

from diffusers import DiffusionPipeline

# load fp16 variant
stable_diffusion = DiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5", variant="fp16", torch_dtype=torch.float16
)
# load non_ema variant
stable_diffusion = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", variant="non_ema")

保存

保存的时候,使用 DiffusionPipeline.save_pretrained() 函数,并且要指明 variant 参数是:fp16 or non_ema,应该将模型保存到与原始检查点相同的文件夹中,这样您就可以从同一文件夹加载这两个模型了:

from diffusers import DiffusionPipeline

# save as fp16 variant
stable_diffusion.save_pretrained("runwayml/stable-diffusion-v1-5", variant="fp16")
# save as non-ema variant
stable_diffusion.save_pretrained("runwayml/stable-diffusion-v1-5", variant="non_ema")

如果不将模型保存到现有文件夹中,则必须指定模型参数,否则它将引发异常,找不到模型:

# 👎 this won't work
stable_diffusion = DiffusionPipeline.from_pretrained("./stable-diffusion-v1-5", torch_dtype=torch.float16)
# 👍 this works
stable_diffusion = DiffusionPipeline.from_pretrained(
    "./stable-diffusion-v1-5", variant="fp16", torch_dtype=torch.float16
)

模型和调度器

模型

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

或者 直接从工程目录下面加载

from diffusers import UNet2DModel

repo_id = "google/ddpm-cifar10-32"
model = UNet2DModel.from_pretrained(repo_id)

也可以通过ModelMixin来加载和保存模型变量: ModelMixin.from_pretrained() 和 ModelMixin.save_pretrained():

from diffusers import UNet2DConditionModel

model = UNet2DConditionModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="unet", variant="non-ema")
model.save_pretrained("./local-unet", variant="non-ema")

调度器

调度器的加载可以使用 SchedulerMixin.from_pretrained() ,调度器不会被训练。调度器不会消耗大量的内存。下面的代码可以尝试加载不同的调度器。

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

# replace `dpm` with any of `ddpm`, `ddim`, `pndm`, `lms`, `euler_anc`, `euler`
pipeline = StableDiffusionPipeline.from_pretrained(repo_id, scheduler=dpm)

关于model_index.json

一般情况下,在hugging-face下的模型工程,都会存在一个model_index.json,用来说明该模型下的工程文件配置。比如:runwayml/stable-diffusion-v1-5。尤其在实例化之后,pipeline中的各个组件的默认使用情况,就和model_index.json中记载的一样。如下文件就是runwayml/stable-diffusion-v1-5的默认指定组件。

{
  "_class_name": "StableDiffusionPipeline",
  "_diffusers_version": "0.6.0",
  "feature_extractor": [
    "transformers",
    "CLIPImageProcessor"
  ],
  "safety_checker": [
    "stable_diffusion",
    "StableDiffusionSafetyChecker"
  ],
  "scheduler": [
    "diffusers",
    "PNDMScheduler"
  ],
  "text_encoder": [
    "transformers",
    "CLIPTextModel"
  ],
  "tokenizer": [
    "transformers",
    "CLIPTokenizer"
  ],
  "unet": [
    "diffusers",
    "UNet2DConditionModel"
  ],
  "vae": [
    "diffusers",
    "AutoencoderKL"
  ]
}

  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值