已关闭
[Bug]: LoRA 微调 adapter-only 存盘仍写入全量 DCP,每次保存无谓复制冻结基模型(~36G) #577
iceflysnow创建于 8月7日关闭于 6 天前
8月7日 添加了label:bug
8月7日 关联了pull request:fix(train): skip full-model DCP write on LoRA adapter-only export
LKONE
7 天前 评论:
7 天前 评论:
您好,该问题当前已有其他改进方案,新增 lora_save_only 参数控制是否仅保存 lora adapter权重,具体使用方式和场景如下:
- lora_save_only 开启时,仅保存 lora adapter 权重,包括 lora 权重文件和 adapter.json 配置文件,可用于权重融合和加载 lora 权重训练;
- lora_save_only 关闭且 save_format 为 dcp 时,保存全量权重信息(包括基础权重和 lora 权重),并可以结合 no_save_optim: false 和no_save_rng: false 参数保存优化器/随机数状态以进行断点续训;
- lora_save_only 关闭且 save_format 为 hf 时(且当前模型支持 hf 权重直接导出),将 lora 权重与基础权重进行融合后导出,可直接用于后续的推理/评测任务。
若有其他改进意见,欢迎继续提出,感谢您的支持!


7 天前 关联了pull request:feat: support configurable LoRA weight saving
6 天前 添加了label:resolved
6 天前 issue状态由 TODO 改变为 DONE
6 天前 关闭了 issue
环境信息
问题描述
在 LoRA 微调 + 仅导出 adapter(
no_save_optim: true且no_save_rng: true)的配置下,每次 checkpoint 保存虽然正确写出了 adapter 的.safetensors,但控制流未在此处返回,继续落入下方的「全量模型 DCP 写入」分支,导致每个 iter 的 save 都把冻结的基模型整份再写一遍(Qwen3.5-9B 约 36G/次)。既无训练态可续(optim/rng 都不存),全量 DCP 写只服务于 resumption,此刻纯属浪费:磁盘与 IO 被吞掉,但训练本身不崩,是静默 bug。
根因
mindspeed_mm/fsdp/train/train_engine.pysave()方法,LoRA 分支在save_lora_only(...)之后没有return,直接落到# Default save behavior (full model)的全量 DCP 写入:https://gitcode.com/Ascend/MindSpeed-MM/blob/master/mindspeed_mm/fsdp/train/train_engine.py#L390-L404
def save(self, iteration, consumed_train_samples): """Save checkpoint with model, optimizer, and training state.""" args = self.args # Handle LoRA save modes if args.training.lora.enable: # Save only LoRA adapter weights if self.lora_weight_manager is not None: self.lora_weight_manager.save_lora_only( # ← 只存 adapter save_path=args.training.save, iteration=iteration, ) # ← 此处缺少 return # Default save behavior (full model) ← 落入全量 DCP 写 state = { "model": self.model, "extra_state": { ... }, }复现步骤
qwen3_5插件 +qwen3_vl_nothink模板的 Qwen3.5-9B LoRA 配置,关键字段:training: lora: enable: true r: 8 save: /path/to/save no_save_optim: true # adapter-only 意图 no_save_rng: true save_interval: 2 train_iters: 3预期行为
no_save_optim + no_save_rng时只写 adapter(~56M/次),save 目录总计应在百 MB 量级,不出现iter_*目录、不出现*.distcp分片。实际行为
save 目录总计 71G,含
iter_0000002/+iter_0000003/两个全量 DCP 目录(各约 36G,含__*_0.distcp分片),另有两个 adapterlora_adapter_iteration_*.safetensors。rc=0,无报错——静默浪费。建议修复
在 LoRA 分支
save_lora_only(...)之后,当既不存 optim 也不存 rng(即无训练态可续)时早退return,跳过只服务于 resumption 的全量 DCP 写入:if args.training.lora.enable: # Save only LoRA adapter weights if self.lora_weight_manager is not None: self.lora_weight_manager.save_lora_only( save_path=args.training.save, iteration=iteration, ) + # Adapter-only export: when neither optimizer nor RNG state is being + # saved there is no training state to resume from, so the full-model + # DCP write (which only exists to support resumption) would duplicate + # the frozen base model on every save with no benefit. Skip it. + if args.training.no_save_optim and args.training.no_save_rng: + torch.distributed.barrier() + return # Default save behavior (full model, for resumption) state = {