前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用Diffusers调用civitai中的checkpoint及LoRA(二)

使用Diffusers调用civitai中的checkpoint及LoRA(二)

原创
作者头像
buzzfrog
发布2023-09-06 22:02:22
发布2023-09-06 22:02:22
6.1K120
代码可运行
举报
文章被收录于专栏:云上修行云上修行
运行总次数:0
代码可运行

背景

上一篇《使用Diffusers调用civitai中的checkpoint及LoRA》使用了Diffusers的脚本将C站(civitai)的checkpoint及LoRA转化成Diffusers可以识别的格式,然后供Diffusers使用。

lora方面,上篇的方法有这样几个问题:

  1. 必须将LoRA下载下来,基于checkpoint和LoRA文件离线转化为几个GB的新的模型供Diffusers使用,不能在线运行过程中调整LoRA的权重,没有sd-webui方便;
  2. 生成图片的效果和sd-webui不太一样。 在Diffusers v0.20.0之后,有了新的解法。这里分享给大家,亲测有效。

原理

本文提供的解决方案运行良好且快速, 虽然它需要对 LoRA alpha 权重进行额外管理, 我们需要创建一个变量来记住当前的 LoRA 权重α。因为加载 LoRA 代码只是添加将 LoRA 中的 A 和 B 矩阵放在一起。

来自 LoRA 的权重
来自 LoRA 的权重

然后与主检查点模型权重 W 合并。

将 LoRA 权重与检查点权重合并
将 LoRA 权重与检查点权重合并

要删除 LoRA 权重, 我们需要负 -α 来删除 LoRA 权重, 或重新创建pipeline。

使用 LoRA 的另一种方法是修改执行模块转发过程的代码, 并在计算文本嵌入和注意力分数期间引入 LoRA 权重。

Monkey补丁模型与LoRA
Monkey补丁模型与LoRA

这就是Diffusers在v0.20.0之前的LoraLoaderMixin的LoRA加载方法。这种方法的好处是没有更新模型权重, 我们可以轻松重置 LoRA 并提供一个新的α来定义 LoRA 权重。但这种方式由于和越南大佬做的sd-webui的方式不同,导致使用Diffusers的很多困扰。

在Diffusers v0.20.0之后,这些问题部分性的解决了。就是说,我们可以使用Diffusers将checkpoint模型与LoRA一起加载,并获得使用sd-webui生成完全相同的结果.

代码实操及效果

先来看看diffusers docs中推荐的方式。https://huggingface.co/docs/diffusers/v0.20.0/en/training/lora

代码语言:python
代码运行次数:0
运行
复制
import torch
from diffusers import StableDiffusionPipeline

pipe = StableDiffusionPipeline.from_pretrained(
    "emilianJR/chilloutmix_NiPrunedFp32Fix",
    torch_dtype = torch.float16,
    safety_checker = None
)
pipe = pipe.to("cuda")
lora_path = "<path/to/lora.safetensors>"
pipe.load_lora_weights(lora_path)

seed = int.from_bytes(os.urandom(2), "big")
generator = torch.Generator("cuda").manual_seed(seed)
image = pipe(
    prompt="(masterpiece),(best quality),(ultra-detailed),1boy, full body, chibi, yellow, outdoors, beret", 
    negative_prompt="(low quality:1.3), (worst quality:1.3)",
    width=512,
    height=768,
    guidance_scale=9,
    num_inference_steps=30,
    generator=generator
).images[0]
output_path = f"/tmp/out-{seed}.png"
image.save(output_path)

只需一行代码: pipe.load_lora_weights(lora_path) ,就可以完成lora模型的加载。如果需要加载多个lora,多次调用pipe.load_lora_weights(lora_path) 即可。

备注:

<path/to/lora.safetensors>是将C站的LoRA下载下来的*.safetensors放在本地硬盘的具体路径和文件名;

emilianJR/chilloutmix_NiPrunedFp32Fix来自图片中红色方框中的内容,无需手动下载。

emilianJR/chilloutmix_NiPrunedFp32Fix来自图片中红色方框中的内容
emilianJR/chilloutmix_NiPrunedFp32Fix来自图片中红色方框中的内容

如果希望下载一次后使用本地缓存,则可以加入cache_dir参数。如下示例:

代码语言:python
代码运行次数:0
运行
复制
import torch
from diffusers import StableDiffusionPipeline

pipe = StableDiffusionPipeline.from_pretrained(
    "emilianJR/chilloutmix_NiPrunedFp32Fix"
    , torch_dtype = torch.float16
    , safety_checker = None
    , cache_dir="diffusers-cache"
).to("cuda")

lora_path = "<path/to/lora.safetensors>"
pipe.load_lora_weights(lora_path)

要重置 LoRA, 只需调用函数 unload_lora_weights 即可:

代码语言:python
代码运行次数:0
运行
复制
pipe.unload_lora_weights()

这里我们可以发现一个问题,就是我们在sd-webui中,可以设置lora的权重,比如我们在prompt中加入:<lora:myLora:0.5>。但这里是不支持的。怎么办呢?Andrew Zhu提供了一段代码来解决这个问题:

代码语言:python
代码运行次数:0
运行
复制
pipe.unload_lora_weights()
lora_path = "<path/to/lora.safetensors>"

lora_w = 0.5
pipe._lora_scale = lora_w

state_dict, network_alphas = pipe.lora_state_dict(
    lora_path
)

for key in network_alphas:
    network_alphas[key] = network_alphas[key] * lora_w

#network_alpha = network_alpha * lora_w
pipe.load_lora_into_unet(
    state_dict = state_dict
    , network_alphas = network_alphas
    , unet = pipe.unet
)

pipe.load_lora_into_text_encoder(
    state_dict = state_dict
    , network_alphas = network_alphas
    , text_encoder = pipe.text_encoder
)

我们看看这个提示词在两边的效果对比:

代码语言:txt
复制
(masterpiece),(best quality),(ultra-detailed),1boy, full body, chibi, yellow, outdoors, beret<lora:blindbox_v1_mix:0.5>
Negative prompt: (low quality:1.3), (worst quality:1.3)
Steps: 30, Sampler: Euler, CFG scale: 9, Seed: 1875473241, Size: 512x768, Model hash: fc2511737a, Model: chilloutmix_NiPrunedFp32Fix, Lora hashes: "blindbox_v1_mix: ee3fbe5a8576", Version: v1.3.2
sd-webui中
sd-webui中
Diffusers中
Diffusers中

能看出有区别吗?

总结

本文介绍了Diffusers对Lora支持的最新进展。通过Diffusers v0.20.0的更新,我们可以通过Diffusers获得与sd-webui相同的效果,便于不同框架之间的效果对比。当然,目前依然有若干问题需要解决:

  1. 如果要在线方式支持LoRA权重,就只能使用Andrew Zhu或类似的Hacker方式,Diffusers目前还不支持。
  2. 不支持同时加载多个权重不同的LoRA。 期待后续有其他新的解决方案。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 原理
  • 代码实操及效果
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档