swift LoRA模型合并完整指南:3步把适配器权重融合为可部署的完整模型
【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600+ LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300+ MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swift
LoRA微调跑完了,checkpoint目录里却只有适配器权重,没法直接拿去部署。这篇教程带你用swift的模型合并功能,3步把LoRA权重融合进基础模型,得到一个标准、独立、可直接上线的完整模型,全程只需一条swift export命令。
核心概念:合并到底在做什么
为什么LoRA权重要先"合并"一次
⚡ LoRA训练时基础模型参数是冻结的,你实际训出来的只是一组低秩增量矩阵(A、B)。这意味着:
- 适配器不能单独工作:它必须挂载在原始基础模型上才能推理;
- 部署时要多带一步加载:每次部署都得"基础模型 + 适配器"成对提供,多一个依赖就多一个出错点;
- 推理时有额外开销:每个目标层都要额外做一次低秩矩阵乘法。
模型合并(Model Merging)就是把这组增量一次性算进基础模型的原始权重里,输出一个"不再需要适配器"的完整模型。
swift合并的内部原理
mermaid
在swift里,整个过程由swift export驱动,核心就三步(源码见 swift/pipelines/export/merge_lora.py):
- 准备模型与模板:
prepare_model_template加载基础模型并套上适配器; - 执行融合:
Swift.merge_and_unload(model)把LoRA增量写入各层权重,然后卸载适配器; - 落盘保存:
save_checkpoint按标准格式保存权重(默认safetensors,默认单分片5GB)。
合并带来的三个直接收益
| 收益 | 说明 |
|---|---|
| 部署简化 | 一个目录就是一个完整模型,vLLM、Ollama、swift infer都能直接加载,无需再传--adapters |
| 推理提速 | 目标层少一次低秩矩阵乘法,逐token生成的延迟会稳定下降 |
| 分发方便 | 单个模型目录即可交付、打包、做版本管理 |
快速上手:一条命令完成合并
环境准备
先装好swift并确认可用:
# 推荐pip安装 pip install 'ms-swift' -U # 或源码安装(需要最新功能时) git clone https://gitcode.com/GitHub_Trending/swift1/swift cd swift pip install -e .# 验证安装 swift --help | head最小可运行命令
假设你已经用swift跑过一次LoRA训练(比如 examples/train/lora_sft.sh 里的写法),得到了output/vx-xxx/checkpoint-xxx目录。合并只需要:
swift export \ --adapters output/vx-xxx/checkpoint-xxx \ --merge_lora true就这么短。✅ 你不需要写--model,因为swift会自动从checkpoint里的args.json读出训练时的基础模型、精度、模板等全部配置。
跑完后,合并结果默认保存在<checkpoint目录>/checkpoint-xxx-merged/。
关键参数速查
参数说明(完整列表见 docs/source/Instruction/Command-line-parameters.md 的"合并参数"一节):
--adapters:必填。LoRA训练输出的checkpoint目录,目录内须有swift训练时自动生成的args.json--merge_lora:设为true才触发合并,支持lora、llamapro、longlora三种tuner--output_dir:可选。不指定时自动在checkpoint旁生成xxx-merged目录--safe_serialization:默认true,保存为safetensors--max_shard_size:默认5GB,控制权重分片大小
深度解析:合并流程与核心数学
完整执行流程
注意最后一步:合并完成后,swift会把args.model指向合并结果、清空adapters,所以量化、导出Ollama、推送这些后续操作天然作用在合并后的模型上,一条命令串起来即可。
核心融合数学
每个被LoRA覆盖的线性层,融合只做一次矩阵加法。用伪代码表示:
# 每个被LoRA覆盖的线性层(源码: Swift.merge_and_unload) delta = lora_B @ lora_A # 低秩增量 delta = delta * scaling # scaling = lora_alpha / lora_rank weight.data += delta融合是纯本地张量运算,不需要GPU加速框架,7B量级的模型通常在几分钟内完成(视磁盘IO而定)。
args.json替你省掉的活
swift export启动时会调用load_args_from_ckpt(见 swift/arguments/base_args/base_args.py):只要你没手动指定,model、model_type、torch_dtype、task_type等训练配置都从checkpoint的args.json中恢复。
这带来一个实用好处:合并命令对多模态模型同样简单——Qwen2.5-VL这类模型处理器的版本、模板配置也一并被还原,不会出现"合并成功但多模态推理跑偏"的问题。
真实场景:4个进阶用法
场景一:合并+量化一步到位
合并后直接AWQ/GPTQ量化,省一次完整模型的读写。⚠️ 量化必须提供校准数据集,否则直接报错:
swift export \ --adapters output/checkpoint-1000 \ --merge_lora true \ --quant_method awq \ --quant_bits 4 \ --dataset 'AI-ModelScope/alpaca-gpt4-data-zh#128' \ --output_dir merged_model-awq支持的量化方法:awq、gptq、bnb、fp8、gptq_v2,量化细节见 docs/source/Instruction/Export-and-push.md。
场景二:合并并推送模型库
合并完直接推送到Model Hub,用于团队共享:
swift export \ --adapters output/checkpoint-1000 \ --merge_lora true \ --push_to_hub true \ --hub_model_id your_name/your-model-merged场景三:合并后导出Ollama格式
本地部署到Ollama,生成所需的Modelfile:
swift export \ --adapters output/checkpoint-1000 \ --merge_lora true \ --to_ollama true场景四:指定分片与输出路径
大模型按5GB分片保存可能产生太多文件,可以调大分片:
swift export \ --adapters output/checkpoint-1000 \ --merge_lora true \ --output_dir merged_model \ --max_shard_size 10GB验证与避坑:确认合并真的成功了
确认合并成功
📌 两层验证,缺一不可:
1. 检查输出目录结构(以Qwen2.5-7B为例):
checkpoint-1000-merged/ ├── config.json ├── generation_config.json ├── model-00001-of-0000X.safetensors ├── model.safetensors.index.json └── tokenizer 相关文件2. 推理对比:合并前(带适配器)与合并后(纯模型)输出应基本一致:
# 合并前 swift infer --model Qwen/Qwen2.5-7B-Instruct \ --adapters output/checkpoint-1000 \ --stream true # 合并后 swift infer --model output/checkpoint-1000-merged \ --stream true高频报错对照表
| 报错/现象 | 原因 | 解决 |
|---|---|---|
AssertionError: args_path: ... | checkpoint目录里没有args.json | checkpoint必须是swift训练产出;手动训练的模型请显式传--model等参数 |
FileExistsError: ... already exists | --output_dir指定的目录已存在 | 换路径,或加--exist_ok true覆盖 |
| 日志提示"already exists, skipping" | 默认的xxx-merged目录已存在,本次跳过了保存 | 加--exist_ok true,或删除旧目录后重跑 |
ValueError: Please input the quant dataset | AWQ/GPTQ量化缺校准集 | 补充--dataset参数 |
警告:--to_mcore/to_hfdoes not support--merge_lora | 两类参数不兼容,merge_lora被自动关闭 | 拆成两步:先合并,再做格式转换 |
| 加载基础模型时OOM | 合并需完整载入一次基座权重 | 加--device_map cpu_offload把权重卸载到CPU,牺牲速度换显存 |
排错三板斧
# 1. 看args.json,确认基础模型和LoRA配置是否为预期 cat output/checkpoint-1000/args.json | head -30 # 2. 看合并日志关键行 # 正常应依次出现: 'Merge LoRA...' -> 'Saving merged weights...' # -> 'Successfully merged LoRA and saved in `...`' # 3. 用swift infer做合并前后输出对比(见上文验证命令)总结
回顾一下这条最短路径:
- 训练:
swift sft --tuner_type lora ...产出带args.json的checkpoint - 合并:
swift export --adapters <ckpt> --merge_lora true,配置自动还原,默认存到xxx-merged - 部署:对合并后的目录直接用
swift infer/swift deploy/vLLM加载,无需再带--adapters
进阶时记住两个组合拳:--merge_lora+--quant_method(合并即量化)和**--merge_lora+--push_to_hub/--to_ollama**(合并即分发)。
源码入口在 swift/pipelines/export/,示例脚本在 examples/export/。如果你正在做LoRA微调,建议现在就跑一遍合并流程,把"训练→合并→部署"的闭环走通。觉得这篇教程有用的话,欢迎点赞收藏,后续更新swift训练推理实践的文章别错过。
【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600+ LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300+ MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swift
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考