Diffusers LoRA 权重融合后怎么恢复基础模型
来源:17golang原创
时间:2026-10-05 06:50:22 291浏览 收藏
在 Diffusers 里调用 fuse_lora() 之后,LoRA 增量已经写进底层模型权重。此时只调用 disable_lora() 或 unload_lora_weights(),并不等于把融合增量从基础权重里减掉。恢复方法取决于三个事实:融合的是一个还是多个 LoRA、当前进程是否还保留融合上下文、融合后的管线是否已经保存并重新加载。
官方文档:https://huggingface.co/docs/diffusers/main/en/using-diffusers/merge_loras
- 仅加载、没有融合:停用或卸载 LoRA 即可。
- 当前管线只融合了一个 LoRA:先
unfuse_lora(),再unload_lora_weights()。 - 融合了多个 LoRA:官方文档要求重新加载基础模型。
- 融合结果已保存并重新加载:把它视为新的完整检查点,想回到基础模型就从原始模型 ID 重新加载。
先看清:融合改变的是基础权重
load_lora_weights() 把 LoRA 作为独立适配器加载到管线中;基础权重仍然存在,适配器也可以单独切换。fuse_lora() 则把 LoRA 的增量直接融合到 UNet、Transformer 或文本编码器的原始权重中,以减少推理时的适配器开销。两种状态看起来都能生成 LoRA 风格图像,但恢复方式完全不同。

我处理这类问题时,会先问一句:现在的 LoRA 还是“挂载层”,还是已经“写入基础权重”?如果只是挂载层,停用或卸载就够了;如果已经写入,必须反融合,或者重建一条干净管线。
最小配方:单个 LoRA 融合后原地恢复
当当前管线只把一个 LoRA 融合进原始模型,而且还没有把融合结果保存后重新加载时,官方提供的恢复方法是 unfuse_lora()。恢复基础权重后,再卸载 LoRA 适配器,可让管线回到不携带该适配器的状态。
from diffusers import DiffusionPipeline
import torch
base_model_id = "stabilityai/stable-diffusion-xl-base-1.0"
lora_repo_id = "your-org/your-sdxl-lora"
# 创建原始基础模型管线
pipe = DiffusionPipeline.from_pretrained(
base_model_id,
torch_dtype=torch.float16,
).to("cuda")
# 加载一个 LoRA,并给它明确名称
pipe.load_lora_weights(lora_repo_id, adapter_name="style")
# 把这个 LoRA 融合进当前模型权重
pipe.fuse_lora(adapter_names=["style"], lora_scale=1.0)
# 撤销单个 LoRA 对基础权重的融合
pipe.unfuse_lora()
# 移除不再需要的 LoRA 层和配置
pipe.unload_lora_weights()
这里的顺序很重要:unfuse_lora() 处理“权重已经相加”的问题,unload_lora_weights() 处理“适配器模块仍然挂在模型上”的问题。只卸载适配器而不反融合,已写入基础权重的效果可能仍然保留。
关键 API 各自负责什么
| API | 作用 | 能否恢复已融合权重 |
|---|---|---|
disable_lora() | 临时停用已加载的 LoRA 层,便于在同一管线中比较 | 不能替代反融合 |
unload_lora_weights() | 移除 LoRA 层和相关配置 | 单独调用不能保证撤销已融合增量 |
unfuse_lora() | 从当前模型权重中撤销融合 | 可以,但官方限定为只融合一个 LoRA 的情况 |
from_pretrained() | 从原始基础模型重新构建干净管线 | 可以,也是多融合和状态不明时的稳妥方案 |
另一个容易混淆的点是 set_adapters()。它负责选择和缩放已加载的适配器,而 fuse_lora() 才会把选中的增量写入底层权重。调整适配器权重和恢复基础权重不是同一个动作。
三种状态对应三种恢复策略

状态一:LoRA 只是加载,还没有融合
如果代码只执行了 load_lora_weights(),没有执行 fuse_lora(),可以临时停用,也可以直接卸载。临时停用适合做同种子对照;确定不再使用时再卸载释放结构。
# 临时停用已加载的 LoRA,基础权重本身没有被修改
pipe.disable_lora()
# 需要时重新启用,避免重复加载权重
pipe.enable_lora()
# 确定不再使用时,移除 LoRA 层和配置
pipe.unload_lora_weights()
状态二:当前管线只融合了一个 LoRA
用 unfuse_lora() 撤销融合,再卸载适配器。这是成本最低的原地恢复方式。若恢复后还想用不同的 lora_scale 重新融合,应重新加载或重新启用所需适配器,再按新的比例调用 fuse_lora()。
状态三:融合了多个 LoRA,或融合历史不明确
Diffusers 官方合并 LoRA 文档明确说明:unfuse_lora() 只适用于原始模型仅融合一个 LoRA 的情况;融合多个 LoRA 时需要重新加载模型。不要试图连续调用多次 unfuse_lora() 猜测恢复顺序,因为不同适配器的权重和缩放可能已经共同写入底层参数。
from diffusers import DiffusionPipeline
import torch
# 从原始基础模型 ID 重新构建干净管线
clean_pipe = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
).to("cuda")
已保存融合模型时为什么必须重新加载基础模型
常见部署做法是先融合 LoRA,调用 unload_lora_weights(),再用 save_pretrained() 保存完整管线。这样得到的目录已经包含融合后的模型权重,后续从这个目录加载时,不需要再单独加载 LoRA。代价是这个检查点本身不再等同于原始基础模型。
# 保存的是融合后的完整管线,而不是原始基础模型
pipe.fuse_lora(adapter_names=["style"])
pipe.unload_lora_weights()
pipe.save_pretrained("./fused-pipeline")
# 重新加载融合目录后,如需基础模型,应改用原始模型 ID
base_pipe = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
).to("cuda")
换句话说,unfuse_lora() 是当前运行实例中的撤销动作,不是对任意融合检查点的通用“还原按钮”。如果基础模型来自本地目录,就重新加载融合前保留的那份目录;如果来自 Hub,就保留原始模型 ID、revision 和 variant,避免恢复时误用另一个版本。
完整片段:恢复后做同参数对照
恢复是否成功,最实用的检查方式是使用相同提示词、随机种子、步数、尺寸和调度器,对比恢复后的管线与一条全新基础管线。浮点精度、硬件和注意力实现可能让像素不完全一致,因此重点检查 LoRA 特征是否消失,以及配置和模型来源是否一致。
from diffusers import DiffusionPipeline
import torch
base_model_id = "stabilityai/stable-diffusion-xl-base-1.0"
prompt = "a quiet library interior, soft daylight"
# 当前管线只融合过一个 LoRA,可先原地反融合并卸载
pipe.unfuse_lora()
pipe.unload_lora_weights()
# 用同一基础模型再创建一条对照管线
reference_pipe = DiffusionPipeline.from_pretrained(
base_model_id,
torch_dtype=torch.float16,
).to("cuda")
# 为两条管线分别创建相同种子的生成器
generator_a = torch.Generator(device="cuda").manual_seed(2026)
generator_b = torch.Generator(device="cuda").manual_seed(2026)
# 使用相同参数生成恢复结果与基础模型对照结果
restored_image = pipe(
prompt,
generator=generator_a,
num_inference_steps=30,
).images[0]
reference_image = reference_pipe(
prompt,
generator=generator_b,
num_inference_steps=30,
).images[0]
兼容坑与排查要点
- 多适配器不能原地保证还原:只要调用过一次多 LoRA 融合,就优先重新加载基础模型。
- 保存顺序会改变产物含义:融合、卸载再保存,得到的是融合检查点;它适合部署,不适合作为可随时还原的基础模型备份。
- 文本编码器也可能被融合:LoRA 不一定只作用于 UNet,恢复时不要只替换某一个组件就认为全部干净。
- 编译模型先处理权重状态:若使用
torch.compile,通常应先融合并卸载再编译;需要恢复时,重建管线往往比在编译图上反复切换更清晰。 - 保留可追溯信息:记录基础模型 ID、revision、variant、LoRA 名称、缩放值和融合顺序,恢复与复现实验都会更可靠。
总结:Diffusers LoRA 融合后的恢复不是单纯“关掉适配器”。单个 LoRA 在当前管线中融合时,使用 unfuse_lora() 撤销权重变化,再用 unload_lora_weights() 清理适配器;多个 LoRA、已保存重载的融合检查点或状态不明时,直接从原始基础模型重新创建管线。把“适配器状态”和“基础权重状态”分开判断,就不会在恢复时误用 API。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
372 收藏
-
314 收藏
-
293 收藏
-
247 收藏
-
194 收藏
-
268 收藏
-
316 收藏
-
150 收藏
-
148 收藏
-
251 收藏
-
333 收藏
-
145 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习