输出目录在哪?Qwen2.5-7B微调产物定位与调用技巧
1. 为什么你总在找“output”文件夹?
刚跑完Qwen2.5-7B的LoRA微调,终端最后一行显示Saving checkpoint to output/v2-20250412-1632/checkpoint-500,你立刻cd /root,输入ls -l——结果发现:没有output文件夹?或者有,但里面空空如也?又或者一堆带时间戳的子目录,根本分不清哪个才是你刚训练好的权重?
这不是你的错。ms-swift框架默认的输出路径、实际保存逻辑、以及不同调用方式对路径的依赖,存在三重“隐形约定”。本文不讲原理,只说你在终端里敲什么命令、看什么日志、进哪个目录、复制哪段路径,就能100%准确定位并成功调用你的微调成果。
我们全程基于镜像《单卡十分钟完成 Qwen2.5-7B 首次微调》实操,所有路径、命令、现象均来自RTX 4090D真实环境验证。
2. 微调产物的真实落点:/root/output 是起点,不是终点
2.1 默认输出根目录:/root/output(必须存在)
执行swift sft命令时,只要指定了--output_dir output(镜像文档中正是如此),框架就会在当前工作目录下创建output文件夹。而镜像默认工作路径是/root,所以所有产物必然始于/root/output。
验证方法:训练开始前,在终端执行
cd /root && ls -ld output如果提示
No such file or directory,说明你还没运行过微调命令;如果返回类似drwxr-xr-x 3 root root 4096 Apr 12 16:32 output,说明根目录已就位。
2.2 真正的权重藏在带时间戳的子目录里
/root/output本身只是一个“容器”,真正的模型权重不会直接放在它下面。ms-swift会按以下规则生成嵌套路径:
/root/output/ └── v2-20250412-1632/ ← 主版本号 + 日期时间(精确到分钟) ├── checkpoint-500/ ← 训练第500步的完整检查点 │ ├── adapter_model.bin ← LoRA权重核心文件(关键!) │ ├── adapter_config.json ← LoRA配置(含rank、alpha等) │ └── ... ├── checkpoint-1000/ └── ...v2-YYYYMMDD-HHMM:这是唯一稳定可识别的主目录名。v2表示ms-swift v2.x系列,后面是训练启动时刻的本地时间(非UTC)。镜像文档示例中的vX-202X...即指此格式。checkpoint-XXX:每次触发--save_steps(默认50)就会生成一个。你不需要全部保留——--save_total_limit 2已自动清理旧的,只留最新的两个。
快速定位最新权重:在
/root/output下执行ls -t /root/output/ | head -n 1输出就是类似
v2-20250412-1632的文件夹名。再进入它:cd /root/output/$(ls -t /root/output/ | head -n 1) ls -t checkpoint-* | head -n 1输出即为最新检查点目录名,如
checkpoint-500。
2.3 关键文件只有两个:adapter_model.bin 和 adapter_config.json
不必翻遍整个检查点目录。对LoRA推理而言,真正需要的只有:
| 文件名 | 作用 | 是否必需 |
|---|---|---|
adapter_model.bin | 包含所有LoRA权重矩阵(A/B矩阵)的二进制文件 | 必需 |
adapter_config.json | 定义LoRA配置(r=8,alpha=32,target_modules=["all-linear"]等) | 必需 |
其他文件(如pytorch_model.bin、tokenizer.model)是原始Qwen2.5-7B-Instruct的副本,微调过程并未修改它们。你调用时只需指向LoRA权重路径,基础模型仍从/root/Qwen2.5-7B-Instruct加载。
常见误区:有人误以为要复制整个
checkpoint-500文件夹到其他位置。其实只需确保该路径存在且可读,swift infer或vLLM会自动读取其中两个关键文件。
3. 三种调用方式,对应三种路径写法
微调产物定位清楚后,下一步是“怎么用”。镜像支持三种主流调用方式,每种对路径的要求截然不同。
3.1 方式一:ms-swift原生推理(最简单,推荐新手)
这是镜像预置的最快验证方式,直接使用swift infer命令,路径写法最直观:
CUDA_VISIBLE_DEVICES=0 \ swift infer \ --adapters /root/output/v2-20250412-1632/checkpoint-500 \ --stream true \ --temperature 0 \ --max_new_tokens 2048- 路径要求:
--adapters参数后直接跟完整的检查点绝对路径(即/root/output/.../checkpoint-XXX)。 - 无需额外操作:框架自动识别该路径下的
adapter_model.bin和adapter_config.json。 - 零配置:不用管基础模型路径,它默认从
/root/Qwen2.5-7B-Instruct加载。
小技巧:把常用路径设为变量,避免重复输入
export LORA_PATH="/root/output/$(ls -t /root/output/ | head -n 1)/$(ls -t /root/output/$(ls -t /root/output/ | head -n 1)/checkpoint-* | head -n 1)" echo "正在加载:$LORA_PATH" swift infer --adapters "$LORA_PATH" --stream true
3.2 方式二:vLLM集成推理(高性能,适合部署)
当需要高吞吐、低延迟服务时,vLLM是更优选择。但它对路径要求更严格:必须指向包含adapter_model.bin的目录,且该目录不能有同名基础模型文件。
正确路径结构(必须手动准备):
# 创建专用LoRA目录(推荐放在/root下,避免权限问题) mkdir -p /root/lora_adapter cp /root/output/v2-20250412-1632/checkpoint-500/adapter_model.bin /root/lora_adapter/ cp /root/output/v2-20250412-1632/checkpoint-500/adapter_config.json /root/lora_adapter/此时,/root/lora_adapter就是vLLM要求的lora_path。
Python调用代码(修正版,适配最新vLLM):
from vllm import LLM, SamplingParams from vllm.lora.request import LoRARequest def generate_with_lora(model_path, lora_path, prompts): sampling_params = SamplingParams(temperature=0.45, top_p=0.9, max_tokens=2048) # 注意:enable_lora=True 且 dtype 必须与微调一致(bfloat16) llm = LLM( model=model_path, dtype="bfloat16", # 与微调时 --torch_dtype bfloat16 严格对应 enable_lora=True, max_model_len=2048 ) # 关键:LoRARequest 的 lora_path 必须是上一步创建的专用目录 outputs = llm.generate( prompts, sampling_params, lora_request=LoRARequest( lora_name="qwen25-lora", # 自定义名称,无实际影响 lora_int_id=1, # ID必须为整数,1即可 lora_path=lora_path # ← 这里填 /root/lora_adapter ) ) return outputs if __name__ == "__main__": model_path = "/root/Qwen2.5-7B-Instruct" # 基础模型路径 lora_path = "/root/lora_adapter" # LoRA权重专用目录 prompts = ["你是谁?"] outputs = generate_with_lora(model_path, lora_path, prompts) for output in outputs: print(f"生成文本:{output.outputs[0].text.strip()}")- 路径要求:
lora_path必须是一个只含LoRA文件的干净目录(无pytorch_model.bin等)。 - ❌ 错误示范:直接把
/root/output/v2-.../checkpoint-500传给vLLM——它会尝试加载里面的pytorch_model.bin,导致冲突。
3.3 方式三:HuggingFace Transformers原生加载(最大兼容性)
如果你要用transformers库做二次开发(如WebUI、自定义pipeline),需手动加载LoRA权重:
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig from peft import PeftModel # 1. 加载基础模型(量化可选) model = AutoModelForCausalLM.from_pretrained( "/root/Qwen2.5-7B-Instruct", torch_dtype="auto", device_map="auto" ) # 2. 加载LoRA适配器(路径指向 checkpoint-XXX 目录) model = PeftModel.from_pretrained( model, "/root/output/v2-20250412-1632/checkpoint-500", # ← 同swift infer,直接用检查点路径 device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained("/root/Qwen2.5-7B-Instruct")- 路径要求:
PeftModel.from_pretrained()接受检查点绝对路径,与swift infer完全一致。 - 优势:无需额外复制文件,直接复用训练产出。
4. 调用失败的三大高频原因与现场诊断法
即使路径写对了,仍可能报错。以下是RTX 4090D环境下最常遇到的三个问题,附带终端级诊断命令:
4.1 问题:FileNotFoundError: [Errno 2] No such file or directory: 'adapter_model.bin'
现象:swift infer报错,或vLLM启动时报lora_path not found。
根因:你指定的路径下确实没有adapter_model.bin。
现场诊断:
# 替换为你写的路径 ls -l /root/output/v2-20250412-1632/checkpoint-500/adapter_model.bin # 如果报错,说明文件不存在 → 检查训练是否成功完成 # 查看训练日志末尾 tail -n 20 /root/output/v2-20250412-1632/trainer_log.txt | grep "Saving checkpoint"解决方案:训练中途被中断(如Ctrl+C、显存溢出)会导致检查点不完整。重新运行微调命令,并确保看到Saving checkpoint to ...成功日志。
4.2 问题:ValueError: Expected model name or path, but got None
现象:vLLM报错,或transformers加载时提示模型路径为空。
根因:model_path参数为空或路径错误,与LoRA路径无关。
现场诊断:
ls -d /root/Qwen2.5-7B-Instruct # 必须返回该路径 ls -l /root/Qwen2.5-7B-Instruct/config.json # 确认config存在解决方案:镜像中基础模型路径固定为/root/Qwen2.5-7B-Instruct,请勿修改。若误删,请重启容器恢复。
4.3 问题:RuntimeError: Expected all tensors to be on the same device
现象:transformers+peft加载后,model.generate()报设备错误。
根因:基础模型和LoRA权重加载到了不同GPU。
现场诊断:
nvidia-smi --query-gpu=index,name,memory.used --format=csv # 确认只有一张卡(RTX 4090D)且内存被占用解决方案:强制指定device_map="cuda:0":
model = AutoModelForCausalLM.from_pretrained( "/root/Qwen2.5-7B-Instruct", device_map="cuda:0" # 显式指定 ) model = PeftModel.from_pretrained(model, "/root/output/...", device_map="cuda:0")5. 工程化建议:让路径管理不再靠记忆
在真实项目中,手动拼接路径极易出错。以下是经过验证的工程实践:
5.1 创建符号链接,一劳永逸
训练完成后,立即创建指向最新检查点的稳定链接:
# 进入output根目录 cd /root/output # 删除旧链接 rm -f latest # 创建新链接(自动指向最新v2-xxx目录下的最新checkpoint) ln -s "$(ls -t | head -n 1)/$(ls -t "$(ls -t | head -n 1)"/checkpoint-* | head -n 1)" latest此后,所有调用均可使用/root/output/latest,无需关心具体时间戳。
5.2 在训练命令中固化输出路径
修改微调命令,用固定名称替代时间戳:
# 将 --output_dir output 改为 --output_dir output/my_qwen25_lora CUDA_VISIBLE_DEVICES=0 \ swift sft \ --model Qwen2.5-7B-Instruct \ --train_type lora \ --dataset self_cognition.json \ --output_dir output/my_qwen25_lora \ # ← 固定名称 ...则产物路径变为/root/output/my_qwen25_lora/checkpoint-500,语义清晰,便于脚本解析。
5.3 用Python脚本自动提取路径
将路径发现逻辑封装为函数,供所有调用场景复用:
import os import glob def get_latest_lora_path(base_dir="/root/output"): """自动获取最新LoRA检查点的绝对路径""" v_dirs = sorted(glob.glob(os.path.join(base_dir, "v2-*")), reverse=True) if not v_dirs: raise FileNotFoundError("No v2-* directory found in output") latest_v = v_dirs[0] checkpoints = sorted(glob.glob(os.path.join(latest_v, "checkpoint-*")), reverse=True) if not checkpoints: raise FileNotFoundError(f"No checkpoint found in {latest_v}") return checkpoints[0] # 使用示例 lora_path = get_latest_lora_path() print(f"最新LoRA路径:{lora_path}") # 直接用于swift infer或vLLM6. 总结:三句话记住核心路径逻辑
1. 所有产物始于/root/output,这是你第一个要cd进去的地方
2. 真正的权重在/root/output/v2-YYYYMMDD-HHMM/checkpoint-XXX,用ls -t命令两步定位
3. 调用时路径写法取决于工具:swift infer和PeftModel用检查点全路径;vLLM必须用只含LoRA文件的干净目录
微调的价值不在于跑通一次,而在于能快速复现、稳定调用、无缝集成。当你不再为“output在哪”而分心,才能真正聚焦于数据质量、指令设计和效果优化——这才是AI工程化的起点。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。