当前位置:   article > 正文

探索稳定扩散技术中的LoRA权重激活:从模型微调到动漫风格图像生成的全过程_dynamic lora weights

dynamic lora weights

低秩适应(LoRA)技术是一种创新的方法,用于解决微调扩散器和大型语言模型(LLMs)的问题。在稳定扩散微调中,LoRA可应用于图像表示的交叉注意层,其中包含描述的潜在信息。为了理解模型微调的基本概念和方法,您可以参考Hugging Face扩散器的文档https://huggingface.co/docs/diffusers/training/lora

在这篇博客中,我们旨在介绍如何使用OpenVINO™优化构建Stable Diffusion + ControlNet管道,并启用LoRA权重,以便通过Stable Diffusion的Unet模型生成具有不同风格的图像。演示源代码基于https://github.com/FionaZZ92/OpenVINO_sample/tree/master/SD_controlnet

稳定扩散控制网络流水线

步骤1:环境准备

首先,按照以下步骤准备开发环境。您可以选择从Hugging Face下载模型以获得更好的运行时体验。在本例中,我们选择了ControlNet用于canny图像任务。

# 安装所需的依赖和下载模型
$ mkdir ControlNet && cd ControlNet
$ wget https://huggingface.co/lllyasviel/ControlNet/resolve/main/annotator/ckpts/body_pose_model.pth
$ conda create -n SD python==3.10
$ conda activate SD
$ pip install opencv-contrib-python
$ pip install -q "diffusers>=0.14.0" "git+https://github.com/huggingface/accelerate.git" controlnet-aux gradio
$ pip install openvino openvino-dev onnx
$ pip install torch==1.13.1 # 重要:确保使用torch==1.13.1
$ git lfs install
$ git clone https://huggingface.co/lllyasviel/sd-controlnet-canny 
$ git clone https://huggingface.co/runwayml/stable-diffusion-v1-5
$ git clone https://huggingface.co/openai/clip-vit-large-patch14 
$ wget https://huggingface.co/takuma104/controlnet_dev/blob/main/gen_compare/control_images/vermeer_512x512.png 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

请注意,如果您的torch版本大于等于2.0,则扩散器将开始使用torch.nn.functional.scaled_dot_product_attention。由于ONNX不支持“Aten::scaled_dot_product_attention”的op转换,为了避免在模型转换时出现错误,请确保您使用的是torch==1.13.1。

步骤2:模型转换

使用提供的两个程序之一,将模型转换为OpenVINO™ IR。使用get_model.py脚本,通过以下方式检查脚本的选项:

$ python get_model.py -h
  • 1

在这个例子中,我们选择多个批次大小以生成多个图像。视觉生成的常见应用有两个批次的概念:

  1. batch_size:指定输入提示或负提示的长度,用于生成N图像。
  2. num_images_per_prompt:指定每个提示生成的图像数量,用于生成M图像。

因此,对于常见的用户应用,可以在扩散器中使用这两个属性通过N提示生成 N ∗ M N*M NM图像。例如,基本种子是42,要生成 N ( 2 ) ∗ M ( 2 ) N(2)*M(2) N(2)M(2)图像,实际生成如下:

  • N=1,M=1:prompt_list[0],seed=42
  • N=1,M=2:prompt_list[0],seed=43
  • N=2,M=1:prompt_list[1],seed=42
  • N=2,M=2:prompt_list[1],seed=43

在这种情况下,以N=2,M=1作为快速演示的示例,因此使用–batch 2。此脚本将默认生成一个静态形状模型。如果您使用不同的N和M值,请指定–dynamic。

$ python get_model.py -b 2 -sd stable-diffusion-v1-5/
  • 1

请检查您当前的路径,并确保您已经生成了以下模型。其他ONNX文件可以删除以节省空间。

  • controlnet-canny.<xml|bin>
  • text_encoder.<xml|bin>
  • unet_controlnet.<xml|bin>
  • vae_decoder.<xml|bin>

如果您的本地路径已经存在ONNX或IR模型,脚本将生成ONNX/IR。如果您更新了pytorch模型或想生成具有不同形状的模型,请记得删除现有的ONNX和IR模型。

步骤3:运行时流水线测试

提供的run_pipe.py程序是手动构建的用于StableDiffusionControlNet的流水线,参考了diffusers.StableDiffusionControlNetPipeline的源代码。您可以在GitHub查看源代码。

不同之处在于,通过OpenVINO™运行时API简化了流水线,通过该API可以确保在Intel® CPU和GPU平台上加速模型推断。

默认迭代次数为20,图像形状为 512 ∗ 512 512*512 512512,种子为42,输入图像和提示为“戴珍珠耳环的女孩”。您可以调整或自定义您的流水线属性以进行测试。

$ python run_pipe.py
  • 1

在 batch_size=2 的情况下,生成的图像如下:

在这里插入图片描述

启用稳定扩散的LoRA权重

正常的LoRA权重有两种类型,一种是 pytorch_lora_weights.bin,另一种是使用safetensors。在这种情况下,我们为这两种LoRA权重介绍两种方法。

启用LoRA权重的主要思想是将权重附加到稳定扩散的原始Unet模型上,然后导出保留LoRA权重的Unet的IR模型。

在https://civitai.com/tag/lora上有各种LoRA模型,我们选择了HuggingFace上的一些公共模型作为示例,您可以考虑用自己的模型替换它们。

步骤4-1:通过pytorch_lora_weights.bin启用LoRA

此步骤介绍了通过 pipe.unet.load_attn_procs(…) 函数将LoRA权重添加到稳定扩散的Unet模型的方法。通过使用这种方式,LoRA权重将被加载到稳定扩散的Unet模型的注意力层中。

$ git clone https://huggingface.co/TheUpperCaseGuy/finetune-lora-stable-diffusion
$ rm unet_controlnet.* unet_controlnet/unet_controlnet.onnx
$ python get_model.py -b 2 -sd stable-diffusion-v1-5/ -lt bin -lw finetune-lora-stable-diffusion/
  • 1
  • 2
  • 3

切记删除现有的 Unet 模型,以生成带有 LoRA 权重的新 IR

然后,运行管道推理程序检查结果。

$ python run_pipe.py
  • 1

LoRA 权重加上稳定扩散模型和 controlNet 管道,可以生成如下图像:
在这里插入图片描述

步骤4-2:通过safetensors类型的权重启用LoRA

此步骤介绍了通过 'diffusers/scripts/convert_lora_safetensor_to_diffusers.py’将LoRA权重添加到稳定扩散的Unet模型的方法。Diffusers提供了使用safetensors类型的LoRA模型启用新的稳定扩散模型的脚本。通过此方法,您将需要将加权路径替换为具有LoRA的新生成的StableDiffusion模型。您可以调整 alpha 选项的值以更改注意力层中 W = W 0 + a l p h a ∗ d e l t a W W = W_0 + alpha * deltaW W=W0+alphadeltaW 的合并比率。

$ git clone https://huggingface.co/ntc-ai/fluffy-stable-diffusion-1.5-lora-trained-without-data
$ git clone https://github.com/huggingface/diffusers.git && cd diffusers
$ python scripts/convert_lora_safetensor_to_diffusers.py --base_model_path ../stable-diffusion-v1-5/ --checkpoint_path ../fluffy-stable-diffusion-1.5-lora-trained-without-data/fluffySingleWordConcept_v10.safetensors --dump_path ../stable-diffusion-v1-5-fluffy-lora --alpha=1.5
$ cd .. && rm unet_controlnet.* unet_controlnet/unet_controlnet.onnx
$ python get_model.py -b 2 -sd stable-diffusion-v1-5-fluffy-lora/ -lt safetensors
  • 1
  • 2
  • 3
  • 4
  • 5

然后,运行管道推理程序检查结果。

$ python run_pipe.py
  • 1

使用控制网管道的 LoRA 权重附加 SD 模型可以生成如下图像:在这里插入图片描述

步骤4-3:通过MatcherPass在运行时启用LoRA合并

此步骤介绍了在Unet或text_encoder模型编译之前在运行时添加LoRA权重的方法。对于具有多个不同LoRA权重的客户端应用,通过重用相同的Unet/text_encoder结构,可以更改图像样式,这将非常有帮助。

此方法是在safetensors文件中提取LoRA权重,找到Unet模型中的相应权重,并插入LoRA权重偏差。添加LoRA权重的通用方法如下:

W = W 0 + W b i a s ( a l p h a ∗ t o r c h . m m ( l o r a u p , l o r a d o w n ) ) W = W_0 + W_{bias}(alpha * torch.mm(lora_{up}, lora_{down})) W=W0+Wbias(alphatorch.mm(loraup,loradown))

本文打算通过OpenVINO™ opset10.add(W0, W_bias) 为Unet的注意力权重插入Add操作。Unet模型中的原始注意力权重是通过Const操作加载的,通常的处理路径是 Const->Convert->Matmul->…,如果我们添加LoRA权重,我们应该插入计算得到的LoRA权重偏差,如 Const->Convert->Add->Matmul->…。在这个函数中,我们采用openvino.runtime.passes.MatcherPass 以迭代方式插入 opset10.add(),并使用 call_back() 函数。
在这里插入图片描述

其中转换操作将首先插入 opset.Add(),然后在使用设备进行模型编译期间。图将执行常量折叠,以将Add操作与接下来的MatMul操作合并,以优化模型的运行时推断。因此,这是将LoRA权重合并到原始模型的有效方法。

您可以查看实现源代码,并找到称为 InsertLoRA(MatcherPass) 的MatcherPass函数的定义。

class InsertLoRA(MatcherPass):
    def __init__(self,lora_dict_list):
        MatcherPass.__init__(self)
        self.model_changed = False

        param = WrapType("opset10.Convert")

        def callback(matcher: Matcher) -> bool:
            root = matcher.get_match_root()
            root_output = matcher.get_match_value()
            for y in lora_dict_list:
                if root.get_friendly_name().replace('.','_').replace('_weight','') == y["name"]:
                    consumers = root_output.get_target_inputs()
                    lora_weights = ops.constant(y["value"],Type.f32,name=y["name"])
                    add_lora = ops.add(root,lora_weights,auto_broadcast='numpy')
                    for consumer in consumers:
                        consumer.replace_source_output(add_lora.output(0))

                    # Use new operation for additional matching
                    self.register_new_node(add_lora)
            # Root node wasn't replaced or changed
            return False
        self.register_matcher(Matcher(param,"InsertLoRA"), callback)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

'InsertLoRA(MatcherPass) '函数将通过 'manager.register_pass(InsertLoRA(lora_dict_list))'进行注册,并通过 ‘manager.run_passes(ov_unet)’ 被调用。在此运行时MatcherPass操作之后,使用设备插件编译的图已准备好进行推断。

运行一个流水线推断程序来检查结果。结果与步骤4-2相同。

python run_pipe.py -lp fluffy-stable-diffusion-1.5-lora-trained-without-data/fluffySingleWordConcept_v10.safetensors -a 1.5
  • 1

LoRA 权重加上稳定扩散模型和 controlNet 管道,可以生成如下图像:

在这里插入图片描述

步骤4-4:启用多个LoRA权重

有许多不同的方法可以添加多个LoRA权重。我在这里列出两种方法。假设您有两个LoRA权重,LoRA A和LoRA B。您可以简单地按照步骤4-3的方法循环使用MatcherPass函数,将其插入到原始Unet Convert层和LoRA A的添加层之间。这很容易实现。但是,这样的性能不够好。
在这里插入图片描述
请考虑MatcherPass函数的逻辑。此函数需要过滤出所有具有Convert类型的层,然后通过条件判断确定每个由权重Constant连接的Convert层是否已在LoRA权重文件中进行了微调和更新。LoRA启用的主要成本由InsertLoRA()函数耗费,因此主要思想是只调用InsertLoRA()函数一次,但附加多个LoRA文件的权重。
在这里插入图片描述
通过上述方法添加多个LoRA,附加2个或更多LoRA权重的成本几乎与添加1个LoRA权重相同。

现在,让我们将稳定扩散与dreamlike-anime-1.0一起更改,以生成具有动画风格的图像。我从 https://civitai.com/tag/lora 中挑选了两个SD 1.5的LoRA权重。

您可能需要进行提示工程工作以生成如下有用的提示:

  • prompt: “1girl, cute, beautiful face, portrait, cloudy mountain, outdoors, trees, rock, river, (soul card:1.2), highly intricate details, realistic light, trending on cgsociety, neon details, ultra-realistic details, global illumination, shadows, octane render, 8k, ultra sharp”
  • Negativate prompt: “3D, cartoon, low-res, bad anatomy, bad hands, text, error”
  • Seed: 0
  • num_steps: 30
  • canny low_threshold: 100
$ python run_pipe.py -lp soulcard.safetensors -a 0.7 -lp2 epi_noiseoffset2.safetensors -a2 0.7

  • 1
  • 2

您可以获得一个美妙的图像,生成一个带有灵魂卡典型边框的动画女孩,如下图所示:

在这里插入图片描述
这样,您已经学到了如何在Stable Diffusion和ControlNet管道中使用LoRA权重,并且可以生成具有不同风格的图像。希望这能满足您的需求!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/422655
推荐阅读
相关标签
  

闽ICP备14008679号