跳到主要内容Qwen3-VL 基于 Llama-Factory QLoRA 微调及 Ollama/LMDeploy 部署流程 | 极客日志PythonAI算法
Qwen3-VL 基于 Llama-Factory QLoRA 微调及 Ollama/LMDeploy 部署流程
综述由AI生成使用 Llama-Factory 对 Qwen3-VL-2B-Instruct 模型进行 QLoRA 微调的全流程,基于 Open-EQA 具身智能数据集。内容包括环境配置、训练参数设置、评估指标分析、模型融合导出以及通过 Ollama 和 LMDeploy 进行推理部署。实验在 NVIDIA Tesla T4 显卡上完成,验证了 QLoRA 方案在低显存环境下的有效性,并提供了具体的命令行操作和 API 调用示例。
极客工坊30 浏览 多模态模型 Qwen3-VL 在 Llama-Factory 嵌套量化 QLoRA 训练 + 测试 + 导出 + 部署全流程
数据来源 Open-EQA 多模态具身智能数据集,经过处理每个样本八张图片,划分为训练 - 验证集和测试集。
1. 微调训练
有 cuda 显卡可以执行 pip install unsloth 安装 Unsloth 加快训练和推理。
执行 pip install tensorboard 安装保存完整训练过程的数据,避免中断只能部分曲线。
创建 saves/Qwen3-VL-2B-Instruct/qlora/train_openeqa,并创建文件 training_args.yaml,内容参考,路径根据自己的情况改:
model_name_or_path: model/Qwen3-VL-2B-Instruct
trust_remote_code: true
stage: sft
do_train: true
finetuning_type: lora
lora_target: all
lora_rank: 8
lora_alpha: 16
lora_dropout: 0.1
use_unsloth: false
flash_attn: auto
quantization_bit: 4
quantization_method: bitsandbytes
double_quantization: true
dataset: open_eqa_train_val
template:
qwen3_vl_nothink
cutoff_len:
2048
max_samples:
100000
overwrite_cache:
true
preprocessing_num_workers:
8
output_dir:
saves/Qwen3-VL-2B-Instruct/qlora/train_openeqa
logging_steps:
10
save_steps:
25
resume_from_checkpoint:
false
overwrite_output_dir:
true
per_device_train_batch_size:
2
gradient_accumulation_steps:
4
learning_rate:
5.0e-5
num_train_epochs:
3.0
lr_scheduler_type:
cosine
warmup_ratio:
0.05
fp16:
true
ddp_timeout:
180000000
optim:
adamw_torch
report_to:
tensorboard
plot_loss:
true
video_max_pixels:
65536
video_min_pixels:
256
freeze_multi_modal_projector:
true
freeze_vision_tower:
true
image_max_pixels:
589824
image_min_pixels:
1024
do_eval:
true
per_device_eval_batch_size:
2
val_size:
0.125
eval_strategy:
steps
eval_steps:
25
eval_delay:
0
prediction_loss_only:
true
load_best_model_at_end:
true
这次训练设备配置是显存 16GB 的 NVIDIA Tesla T4,执行 llamafactory-cli train saves/Qwen3-VL-2B-Instruct/qlora/train_openeqa/training_args.yaml 开始训练。
若出现中断,将 resume_from_checkpoint 设置为 true 恢复中断训练继续训练。
llamafactory-cli train saves/Qwen3-VL-2B-Instruct/qlora/train_openeqa/training_args.yaml
从训练和验证的损失曲线与指标来看,Qwen3-VL-2B-Instruct 在 Open-EQA 多模态小样本训练 - 验证集上的表现可以这样总结:
- 损失变化:训练损失初始值很高(约 5.5),在训练初期(前 100 步)快速下降,之后下降速度放缓,在 200 步后稳定在 1.0~1.5 区间。
- 最终指标:最终训练损失为 1.3233,说明模型在训练集上的拟合效果良好,且后期波动很小,收敛稳定。
- 效率:训练总耗时约 2 小时 27 分钟,共完成 453 步,计算量达 48049026 GFLOPs,显示出多模态训练的计算成本较高。
- 损失变化:验证损失初始值约 1.8,同样在初期快速下降,100 步后趋于平缓,后期稳定在 1.25~1.3 区间。
- 最终指标:最终验证损失为 1.2683,略低于训练损失,这表明模型在未见过的验证数据上泛化能力较好,没有出现明显的过拟合。
- 效率:验证集共 173 个样本,耗时约 2 分钟 10 秒,批大小为 2,验证阶段的样本处理速度比训练阶段更快。
训练和验证的损失曲线趋势高度一致,且验证损失略低于训练损失,说明模型在训练过程中不仅对训练数据拟合充分,还具备良好的泛化能力,在 Open-EQA 多模态小样本任务上表现稳定。
如果曲线不完整,可以把云服务器的 runs 目录中 tensorboard 日志文件下载到本地电脑。
在自己电脑的 python 环境执行 uv pip install tensorboard -i http://mirrors.aliyun.com/pypi/simple 安装 tensorboard,对于纯 python 或 conda 可以直接执行 pip install tensorboard -i http://mirrors.aliyun.com/pypi/simple 安装 tensorboard。
执行 tensorboard --logdir=/Users/Zhuanz/Downloads --port 6006 查看,--logdir 是你的 tensorboard 日志文件文件的所在目录(不是文件),port 是端口号可自己设置。
2. 测试评估
创建 saves/Qwen3-VL-2B-Instruct/qlora/eval_openeqa 目录,并建立 eval_args.yaml,内容如下,其中 do_predict 设置为 true 代表评估测试,注意要改适配器路径 adapter_name_or_path、基座模型路径 model_name_or_path 和是融合模型路径 output_dir。
adapter_name_or_path: saves/Qwen3-VL-2B-Instruct/qlora/train_openeqa/
cutoff_len: 2048
dataset_dir: data
ddp_timeout: 180000000
do_predict: true
eval_dataset: open_eqa_test
finetuning_type: lora
flash_attn: auto
max_new_tokens: 128
max_samples: 99999
model_name_or_path: model/Qwen3-VL-2B-Instruct
output_dir: saves/Qwen3-VL-2B-Instruct/qlora/eval_openeqa
per_device_eval_batch_size: 2
predict_with_generate: true
preprocessing_num_workers: 4
report_to: none
stage: sft
temperature: 0.2
template: qwen3_vl_nothink
top_p: 1.0
trust_remote_code: true
执行 llamafactory-cli train saves/Qwen3-VL-2B-Instruct/qlora/eval_openeqa/eval_args.yaml。
结论:Qwen3-VL-2B-Instruct 模型经 QLoRA 轻量化微调 Open-EQA 多模态具身智能数据集后,在 NVIDIA Tesla T4(16GB 显存)硬件环境下完成了全量测试集的推理评估,本次评估共涉及 258 个测试样本,且每个样本包含 8 张关联图片的多模态输入。评估过程中模型采用批大小 2 的推理配置,全程无显存溢出等异常问题,稳定完成所有样本的预测推理,验证了 QLoRA 微调方案对 16GB 显存低算力显卡的良好适配性。从生成指标来看,模型预测 BLEU-4 值达 29.4966,ROUGE 系列指标中 ROUGE-1、ROUGE-2、ROUGE-L 分别为 36.2965、7.9106、35.7659,整体指标表现表明模型经微调后具备了一定的多图关联理解能力和与任务匹配的文本生成能力,其中 ROUGE-1 和 ROUGE-L 的较好表现体现模型能有效捕捉具身智能任务中的核心信息,ROUGE-2 偏低则反映模型在短句语义衔接的细粒度生成上仍有提升空间。从推理效率来看,本次预测全程耗时约 2 小时 55 分钟,样本处理速度为 0.025 个 / 秒、步数处理速度为 0.012 个 / 秒,推理速度整体偏低,核心受单样本 8 张图片的多模态特征提取带来的高计算量影响。整体而言,模型在 16GB 显存的 Tesla T4 显卡上成功实现了 Open-EQA 具身智能多图任务的稳定推理,并取得了具备参考性的生成效果,充分验证了本次 QLoRA 微调的实际有效性,同时也为后续通过优化图片处理策略、调整推理配置来提升模型推理速度,以及针对性优化训练策略改善细粒度生成能力提供了实际参考依据。
3. 融合模型导出
创建 saves/Qwen3-VL-2B-Instruct/qlora/merge 目录,并建立 merge_openeqa.yaml,路径同样需要修改,内容如下:
model_name_or_path: model/Qwen3-VL-2B-Instruct
adapter_name_or_path: saves/Qwen3-VL-2B-Instruct/qlora/train_openeqa/
template: qwen3_vl_nothink
finetuning_type: lora
trust_remote_code: true
export_dir: saves/Qwen3-VL-2B-Instruct/qlora/merge
export_size: 2
export_device: auto
export_legacy_format: false
执行 llamafactory-cli export saves/Qwen3-VL-2B-Instruct/qlora/merge/merge_openeqa.yaml。
4. 推理部署 API 服务
(1) Ollama
将融合模型下载到本地目录,比如 /saves/Qwen3-VL-2B-Instruct/qlora/merge,并进入目录,打开 Modelfile 文件,可以根据需要修改。
# ollama modelfile auto-generated by llamafactory
FROM .
TEMPLATE """{{ if .System }}<|im_start|>system {{ .System }}<|im_end|> {{ end }}{{ range .Messages }}{{ if eq .Role "user" }}<|im_start|>user {{ .Content }}<|im_end|> <|im_start|>assistant {{ else if eq .Role "assistant" }}{{ .Content }}<|im_end|> {{ end }}{{ end }}"""
# PARAMETER temperature 0.7 #可设置温度
PARAMETER stop "<|im_end|>"
PARAMETER num_ctx 4096
到终端执行创建模型的命令,模型将被转换格式并放入 ollama 的模型空间中,这里是这个 qwen3-vl-2b 是在 ollama 模型空间的模型名称,可以修改。
ollama create qwen3-vl-2b -f Modelfile
执行 ollama list 查看 ollama 的模型列表。
执行 ollama run qwen3-vl-2b "问题" 图片路径,比如
ollama run qwen3-vl-2b "墙上有什么东西" ./data/open_eqa_frames/0a0c0f2b9ba65d1b/000.jpg
先执行 ollama run qwen3-vl-2b 加载模型,进入交互模式,然后输入问题及图片路径,比如带有斑纹的椅子上有几个枕头 ./data/open_eqa_frames/0a0c0f2b9ba65d1b/000.jpg。
执行 IMG=$(base64 -i data/open_eqa_frames/0a0c0f2b9ba65d1b/000.jpg | tr -d '\n') 转图片为 base64 格式。
curl http://localhost:11434/api/generate -d '{
"model": "模型名称",
"system": "系统提示词",
"prompt": "用户提示词",
"images": ["$图片 base64 变量"],
"format": "格式",
"stream": "是否流式输出",
"options": {参数设置}
}'
curl http://localhost:11434/api/generate -d '{ "model": "qwen3-vl-2b", "system": "你是机器人控制 AI。你必须输出可执行的动作序列。scene_analysis 必须包含:目标相对于当前视角的方位(左/右/前)和距离(米)。plan 中的 params 必须使用英文键名(target/type/distance/degrees)。严禁使用中文键名。", "prompt": "观察图片,为指令\"怎么关闭台灯\"输出 JSON:\n{\n \"scene_analysis\": \"目标在 [方位],距离 [X] 米\",\n \"plan\": [\n {\"action\": \"rotate\", \"params\": {\"degrees\": 角度,\"direction\": \"left|right\"}},\n {\"action\": \"navigate\", \"params\": {\"distance\": 米数}},\n {\"action\": \"interact\", \"params\": {\"type\": \"press\", \"target\": \"台灯开关\"}}\n ]\n}", "images": ["'$IMG'"], "format": "json", "stream": false, "options": {"temperature": 0.01, "num_predict": 300} }'
回答得不错,基本符合格式,实际使用最好使用解析器处理格式。
(2) LMDeploy
切换激活环境,执行 pip install --no-cache-dir lmdeploy 安装 LMDeploy 库。

from lmdeploy import pipeline, TurbomindEngineConfig, PytorchEngineConfig, GenerationConfig
from lmdeploy.vl import load_image
import time
MODEL_PATH = "/workspace/LlamaFactory/saves/Qwen3-VL-2B-Instruct/qlora/merge"
IMAGE_PATH = "/workspace/LlamaFactory/data/open_eqa_frames/0a0c0f2b9ba65d1b/000.jpg"
print("🚀 使用 LMDeploy PyTorch 后端加载 Qwen3-VL...")
engine_config = PytorchEngineConfig(
tp=1,
session_len=4096,
max_batch_size=4,
cache_max_entry_count=0.6,
eager_mode=True,
)
if __name__ == '__main__':
pipe = pipeline(MODEL_PATH, backend_config=engine_config)
print("✅ 模型加载成功!")
image = load_image(IMAGE_PATH)
print("\n🎯 单图推理测试...")
prompts = [
("描述这张图片", image),
]
start = time.time()
response = pipe(prompts, gen_config=GenerationConfig(max_new_tokens=256, temperature=0.7))
latency = time.time() - start
print(f"⏱️ 延迟:{latency:.2f} s")
print(f"📝 输出:{response[0].text}")
print("\n🎯 Batch 推理测试(4 张相同图片,体现 continuous batching)...")
prompts_batch = [
("描述这张图片", image),
("图中有几个人?", image),
("这是什么场景?", image),
("图片主色调是什么?", image),
]
start = time.time()
responses = pipe(prompts_batch, gen_config=GenerationConfig(max_new_tokens=128))
batch_latency = time.time() - start
print(f"⏱️ Batch 总延迟:{batch_latency:.2f} s")
print(f"⚡ 平均每个请求:{batch_latency/4:.2f} s")
print("📊 throughput 提升:{:.1f}x".format(4 / (batch_latency / latency)))

- 单图推理能精准描述图片细节(深蓝色沙发、条纹扶手椅、装饰画文字
Live, Travel, Explore、绿植 / 百叶窗等),无遗漏关键视觉信息;
- Batch4 个不同问题的推理均能正确响应,模型对视觉问答的语义理解符合预期,多模态能力完全正常发挥;
- 全程无报错、无 OOM(显存溢出),说明 LMDeploy 对 Qwen3-VL 的 PyTorch 后端适配完善,图片加载 / 提示构造 / 推理流程全链路通畅。
b. 单图推理性能:符合 T4+PyTorch 后端的预期
单图延迟 9.63s,这个数值在当前约束下是合理且可接受的:多模态推理的耗时主要来自视觉特征提取(Qwen3-VL 的视觉分支需要处理图片张量)+ 文本生成,而 T4 算力有限、PyTorch 后端无 TurboMind 的极致优化,2B 模型的这个延迟是中端硬件的正常表现。
- 总延迟:31.42s → 平均单请求延迟 7.86s(比单图的 9.63s 降低 18.4%);
- 吞吐量提升:1.2x,验证了 LMDeploy
continuous batching 的价值。
nohup lmdeploy serve api_server /workspace/LlamaFactory/saves/Qwen3-VL-2B-Instruct/qlora/merge --model-name qwen3-vl --backend pytorch --tp 1 --session-len 4096 --cache-max-entry-count 0.6 --max-batch-size 4 --eager-mode --server-port 23333 > api_server.log 2>&1 &
| 参数 | 作用 | T4 约束 |
|---|
--backend pytorch | 使用 PyTorch 后端推理 | 必须:TurboMind(C++) 不支持 Qwen3-VL 架构,且 T4 是 SM75 架构 |
--tp 1 | 张量并行数 | T4 只有 1 张卡,设为 1(多卡可加速但 T4 不支持 NVLink 高效通信) |
--session-len 4096 | 最大序列长度 | 受限于 16GB 显存,4096 是安全值(过长会 OOM) |
--cache-max-entry-count 0.6 | KV Cache 显存占比 | 核心优化:0.6×16GB=9.6GB 给 KV Cache,剩余给模型权重 (4-5GB) 和激活值 |
--max-batch-size 4 | 最大 batch size | Continuous Batching 并发上限,T4 建议 4-8,过高会延迟增加 |
--eager-mode | 禁用 CUDA Graph 编译 | 必须:T4 架构较旧,CUDA Graph 可能导致非法指令或内存错误 |
--server-port 23333 | API 端口 | 默认与 OpenAI API(8080) 区分避免冲突 |
| 符号 | 含义 |
|---|
nohup | No Hang Up,用户退出 SSH 后进程继续运行 |
> api_server.log | 标准输出 (STDOUT) 重定向到日志文件 |
2>&1 | 标准错误 (STDERR) 重定向到 STDOUT(即也进日志) |
& | 后台运行(立即返回命令行,不阻塞) |
BASE64_IMG=$(base64 -w 0 /workspace/LlamaFactory/data/open_eqa_frames/0a0c0f2b9ba65d1b/000.jpg)
curl -X POST http://localhost:23333/v1/chat/completions \
-H "Content-Type: application/json" \
-d "{ \"model\": \"qwen3-vl\", \"messages\": [{ \"role\": \"user\", \"content\": [ {\"type\": \"image_url\", \"image_url\": {\"url\": \"data:image/jpeg;base64,${BASE64_IMG}\"}}, {\"type\": \"text\", \"text\": \"描述这张图片\"} ] }], \"max_tokens\": 256, \"temperature\": 0.7 }"
执行 tail -f api_server.log 查看日志。
执行 ps aux | grep "lmdeploy serve api_server" 查看后台进程 pid。
| PID | 进程 | 说明 |
|---|
| 12684 | /root/miniforge3/bin/lmdeploy serve api_server ... | 真正的 LMDeploy 服务(占 1.9GB 内存) |
| 13135 | grep --color=auto lmdeploy serve api_server | 刚执行的 grep 命令本身(临时进程,已结束) |
执行 kill 12684 杀死服务,注意 pid 以实际为准。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online