> 技术文档 > 【手把手从零实现】Qwen2.5-VL:环境配置/功能实验(图片识别理解、目标检测、文字OCR、文档解析、视频理解)/模型微调(MS-Swift 和 LLaMA-Factory)

【手把手从零实现】Qwen2.5-VL:环境配置/功能实验(图片识别理解、目标检测、文字OCR、文档解析、视频理解)/模型微调(MS-Swift 和 LLaMA-Factory)


目录

1 先看结论

2 环境准备与安装

        2.1 基础环境与依赖

        2.2 Transformers 开发版安装

        2.3 模型权重下载(HF / ModelScope)

3 快速推理上手

        3.1 显存占用测试

        3.2 单图问答 Demo

4 功能实验全记录

        4.1 多图联合理解

        4.2 输出目标检测框(bbox)

        4.3 OCR(含繁体/手写/票据)

        4.4 文档结构化解析(HTML / Markdown)

        4.5 视频理解(关键帧/字幕/动作概括)

5 批量推理脚本与常见报错定位

6 训练与微调实践

        6.1 选择 MS-Swift 还是 LLaMA-Factory?

        6.2 数据格式准备(图文对话、多模态指令)

        6.3 MS-Swift 微调流程示例

        6.4 LLaMA-Factory 微调流程示例

        6.5 低成本方案:QLoRA / Freeze-Vision-Encoder

        6.6 评测与导出部署

7 资源整理 & 参考命令速查

8 常见问题 FAQ


1. 先看结论

  • Qwen2.5-VL(阿里通义千问最新视觉语言家族)在 图像理解、检测框、OCR、表格解析、视频理解 等方面给出“开箱即用”的接口,3B 模型就很能打

  • 实测显存需求见下表。

模型 FP16 纯推理显存(之前) INT8 权重量化后 备注 Qwen2.5‑VL‑3B ~8 GB ≈4–5 GB 再低可用 4-bit 约 2.5–3 GB Qwen2.5‑VL‑7B ~20 GB ≈10–12 GB KV Cache 仍是 FP16/FP32,序列越长越涨 Qwen2.5‑VL‑72B ~150 GB ≈75–90 GB(多卡/CPU Offload) 实操基本要分布式 + offload
  • HuggingFace transformers 正式版暂时跟不上最新接口,需要从源码装 4.49.0.dev0 左右的开发版

  • MS-Swift(ModelScope 原生工具链)与 LLaMA-Factory(社区爆款微调框架)均已支持多模态微调,可选自己熟悉的生态;本篇给出两套命令行 & 配置模板。

  • 训练数据核心是 图像/视频路径 + Prompt/Answer 的多模态对话格式,注意对齐字段、max_pixels、抽帧策略等。

  • 推理环节推荐自己包一层脚本,解决路径、批处理、可视化等重复工作。

  • 建议:英文 prompt + 中文输出要求,往往效果更稳定。


2. 环境准备与安装

2.1 基础环境与依赖

建议环境(亲测稳定):

  • OS:Ubuntu 20.04/22.04(Win 也能跑,但 CUDA/路径权限坑多)

  • Python:3.10(官方示例多数基于 3.10)

  • CUDA:12.4(本人使用的此版本,也可以使用11.8之类的)

  • PyTorch:2.6.0(和 CUDA 对应,好装好用)

# 1) 新建虚拟环境conda create -n qwen25-vl python=3.10 -yconda activate qwen25-vl# 2) 安装 PyTorch(任选一个 CUDA 版本)# or CUDA 12.4pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 \\ --index-url https://download.pytorch.org/whl/cu124# 3) 其他常用依赖pip install numpy==1.26.4 accelerate qwen-vl-utils==0.0.10 pillow

坑点提示numpy>=2.0 会让部分包崩溃(尤其老代码),这里锁定到 1.26.x。

2.2 Transformers 开发版安装

官方新接口(Qwen2_5_VLForConditionalGeneration)目前只在 dev 版:

git clone https://github.com/huggingface/transformers.gitcd transformers# 建议固定在一个已知可用的 commit(例如 2025-02 月初的)pip install -e .

验证是否成功:

from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor

若无红色波浪警告 / ImportError,即 OK。

2.3 模型权重下载

两种主流路径:

  1. ModelScope CLI(国内快)

  2. HuggingFace Hub(海外多)

示例(ModelScope):

# 3Bmodelscope download --model Qwen/Qwen2.5-VL-3B-Instruct --local_dir ./qwen25-vl-3b# 7Bmodelscope download --model Qwen/Qwen2.5-VL-7B-Instruct --local_dir ./qwen25-vl-7b# 72Bmodelscope download --model Qwen/Qwen2.5-VL-72B-Instruct --local_dir ./qwen25-vl-72b

建议:提前准备 ~/.cache/modelscope 的磁盘空间(几十 GB 起)。


3. 快速推理上手

3.1 显存占用测试

import os, torchfrom transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessoros.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\"model_path = \"./qwen25-vl-3b\"model = Qwen2_5_VLForConditionalGeneration.from_pretrained( model_path, torch_dtype=\"auto\", device_map=\"auto\")processor = AutoProcessor.from_pretrained(model_path)print(\"Loaded!\")

记录不同模型的首次加载显存占用(实际略有浮动):

模型 显存需求(大约) 3B 8 GB+ 7B 20 GB+ 72B 150 GB+(建议多卡或 CPU Offload)

3.2 单图问答 Demo

from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessorfrom qwen_vl_utils import process_vision_infofrom PIL import Imageimport torchmodel_path = \"./qwen25-vl-3b\"img_path = \"./demo/giraffe.jpg\"question = \"请用中文描述一下这张图片的内容,并给出主要物体。\"model = Qwen2_5_VLForConditionalGeneration.from_pretrained( model_path, torch_dtype=\"auto\", device_map=\"auto\")processor = AutoProcessor.from_pretrained(model_path)image = Image.open(img_path)messages = [{ \"role\": \"user\", \"content\": [ {\"type\": \"image\", \"image\": image}, {\"type\": \"text\", \"text\": question}, ],}]prompt = processor.apply_chat_template(messages, add_generation_prompt=True)image_inputs, video_inputs = process_vision_info(messages)inputs = processor( text=[prompt], images=image_inputs, videos=video_inputs, padding=True, return_tensors=\"pt\").to(\"cuda\")with torch.inference_mode(): out = model.generate(**inputs, max_new_tokens=128)ans = processor.batch_decode(out[:, inputs.input_ids.shape[-1]:], skip_special_tokens=True)[0]print(ans)

4. 功能实验全记录

下面所有示例我都用 3B 模型 跑过;更大模型同理(更强但更贵)。

4.1 多图联合理解

场景:一次性输入一组图片,让模型找共性、排序、或者逐张命名。
提示词技巧:英文主述,最后加上 “Answer in Chinese” 更稳。

import osfrom transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessorfrom qwen_vl_utils import process_vision_infomodel_path = \"./qwen25-vl-3b\"img_dir = \"./demo/multi_images\"question = ( \"Describe the key entities in each image respectively. \" \"List them in order. Please output the entity names in Chinese.\")model = Qwen2_5_VLForConditionalGeneration.from_pretrained(model_path, torch_dtype=\"auto\", device_map=\"auto\")processor = AutoProcessor.from_pretrained(model_path)content = []for fn in sorted(os.listdir(img_dir)): if fn.lower().endswith((\".jpg\", \".jpeg\", \".png\")): content.append({\"type\": \"image\", \"image\": os.path.join(img_dir, fn)})content.append({\"type\": \"text\", \"text\": question})messages = [{\"role\": \"user\", \"content\": content}]prompt = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)img_inputs, vid_inputs = process_vision_info(messages)inputs = processor( text=[prompt], images=img_inputs, videos=vid_inputs, padding=True, return_tensors=\"pt\").to(\"cuda\")out = model.generate(**inputs, max_new_tokens=256)ans = processor.batch_decode(out[:, inputs.input_ids.shape[-1]:], skip_special_tokens=True)[0]print(ans)

【示意图位置:展示多张图片+模型输出的清单样式】

4.2 输出目标检测框(bbox)

只需在提示词里要求“返回坐标”,并明确格式。例如:

question = ( \"Detect all objects in the image. \" \"Return a JSON list with items like {\\\"bbox_2d\\\": [x1,y1,x2,y2], \\\"label\\\": \\\"中文类别\\\"}.\")

解析可视化示例(Pillow):

from PIL import Image, ImageDraw, ImageFontimport jsondef draw_bboxes(img_path, json_str, font_path=\"C:/Windows/Fonts/SimHei.ttf\"): img = Image.open(img_path).convert(\"RGB\") data = json.loads(json_str) draw = ImageDraw.Draw(img) font = ImageFont.truetype(font_path, 24) for item in data: x1,y1,x2,y2 = item[\"bbox_2d\"] cls = item[\"label\"] draw.rectangle([x1,y1,x2,y2], outline=\"red\", width=3) draw.text((x1, y1-24), cls, fill=\"yellow\", font=font) return img# 用 ans 中的 json 段落调用

【示意图位置:原图 + 画框后的结果对比】

4.3 OCR

提示词可用:

  • “Read all texts line by line.”

  • “请逐行输出图中出现的所有文字,不要遗漏。”

建议:默认 OCR 结果是纯文本;若想要位置、字体大小等信息,目前需要再追问或切换专门 OCR 模型。

【示意图位置:古籍/票据/手写体样例 + 输出文本】

4.4 文档结构化解析(HTML / Markdown)

让模型输出 HTML 表格非常实用,尤其是财报、表格截图。

提示词示例:

\"Convert the information in this image into a valid HTML table. Keep all numbers as they are.\"

实测模型喜欢加 ```html 代码块,可用正则截取内部再另存为 .html

【示意图位置:表格截图 + 浏览器渲染后的 HTML 表格对比图】

4.5 视频理解

官方接口需要把视频路径放进 messages,并设置 max_pixelsfps(抽帧率)。核心示例:

messages = [{ \"role\": \"user\", \"content\": [ {\"type\": \"video\", \"video\": \"./demo/video.mp4\", \"max_pixels\": 360*420, \"fps\": 1.0}, {\"type\": \"text\", \"text\": \"Describe this video in Chinese.\"}, ]}]

处理方式:

text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)img_inputs, vid_inputs, vid_kwargs = process_vision_info(messages, return_video_kwargs=True)inputs = processor( text=[text], images=img_inputs, videos=vid_inputs, fps=vid_kwargs.get(\"fps\"), padding=True, return_tensors=\"pt\", **vid_kwargs).to(\"cuda\")

注意fps 需传入 processor;处理视频比图片更吃内存,做好分辨率/帧率权衡。

【示意图位置:视频关键帧拼图 + 输出摘要】


5. 批量推理脚本与常见报错定位

  • 批处理脚本建议

    • 使用 argparse 解析输入目录 / 输出目录 / 模型路径 / prompt。

    • 将所有推理结果(文本/JSON/HTML)统一保存为 xx.jsonl 或者分多种文件夹。

    • 可加上 tqdm 做进度条,防止不知道进度卡哪了。

  • 常见报错

    1. CUDA out of memory:减小 max_pixelsfp16、关掉 cache、多卡分配;

    2. ValueError: image tensor sizes must be ...:多图/视频时,processor 输入不一致导致,确保调用 process_vision_info

    3. transformers 版本不对:确认是 dev 版并且 pip list | grep transformers 正确;

    4. Windows pillow font 路径问题:改用默认字体或者指定 ttf 路径。


6. 训练与微调实践

6.1 选择 MS-Swift 还是 LLaMA-Factory?

方案 优点 缺点 适合人群 MS-Swift ModelScope 原生支持、官方教程多、多模态处理封装较好 文档大多中文但示例偏官方;生态小一点 已经在用 ModelScope 的团队 LLaMA-Factory 社区火爆、文档齐全、支持大量模型/LoRA/QLoRA 多模态刚加入不久,版本差异需注意 习惯 HF 生态、追求灵活性的开发者

结论:你用哪个熟就用哪个,两者都能跑起来。下面分别给出示例。

6.2 数据格式准备

通用思路:一条样本 = (多模态输入, 文本输出)

  • 图像:本地路径 / base64 皆可,但在训练时通常给路径让 dataloader 去读。

  • 文本:Prompt、Answer 多轮对话(role=user/assistant)。

  • 视频:建议提前抽帧,或者在 dataloader 中设定抽帧策略(统一帧数 / 间隔抽帧)。

  • Qwen 官方推荐的 messages 结构(和推理一致),训练时直接走 chat_template 会更省事。

示例 JSON(单条)

{ \"id\": \"sample_0001\", \"messages\": [ { \"role\": \"user\", \"content\": [ {\"type\": \"image\", \"image\": \"/path/to/img_001.jpg\"}, {\"type\": \"text\", \"text\": \"图中有哪些动物?请用中文回答。\"} ] }, { \"role\": \"assistant\", \"content\": [ {\"type\": \"text\", \"text\": \"有两只长颈鹿和一只斑马。\"} ] } ]}

6.3 用 MS-Swift 微调

安装

pip install ms-swift# 或者git clone https://github.com/modelscope/ms-swift.gitcd ms-swift && pip install -e .

命令行 SFT 示例(LoRA)

swift sft \\ --model Qwen/Qwen2.5-VL-3B-Instruct \\ --dataset /path/to/your_multimodal.jsonl \\ --output_dir ./outputs/qwen25vl_lora \\ --vision_tower auto \\ --max_pixels 518400 \\ --lora_rank 64 \\ --per_device_train_batch_size 1 \\ --gradient_accumulation_steps 16 \\ --fp16 \\ --num_train_epochs 3 \\ --learning_rate 1e-4 \\ --save_steps 500 \\ --logging_steps 20

要点

  • --vision_tower auto 会自动识别视觉编码器。

  • --max_pixels 控制单图分辨率上限,别设太大容易炸显存。

  • LoRA Rank 一般 32/64 起步,结合资源调整。

  • 数据集可用 JSONL,一行一个样本。

6.4 用 LLaMA-Factory 微调

安装

git clone https://github.com/hiyouga/LLaMA-Factory.gitcd LLaMA-Factorypip install -e .

配置文件示例(qwen25vl_sft.yaml

model_name_or_path: ./qwen25-vl-3bstage: sftdo_train: truedataset: /data/mm_instructions.jsonltemplate: qwen2.5_vlvision_tower: automax_pixels: 518400lora_target: q_proj,v_proj # 具体看模型结构lora_rank: 64per_device_train_batch_size: 1gradient_accumulation_steps: 16learning_rate: 1e-4num_train_epochs: 3fp16: trueoutput_dir: outputs/qwen25vl_lorasave_steps: 500logging_steps: 20

命令行启动

python src/train.py --config qwen25vl_sft.yaml

若报 vision 相关错误,确保 template 里定义了 image/video 字段处理流程。
最新的 LLaMA-Factory 分支里一般已经内置对 QwenVL 的 support,可参考其 docs/recipes。

6.5 低成本方案

  • QLoRA: 4-bit 权重量化,显存能再省一半左右。

  • 冻结视觉编码器和语言头:只微调跨模态层(通常还是要放开一点点语言头),损失一点效果但速度快、省显存。

  • 分布式/Deepspeed ZeRO:大模型、72B 场景必须上。

6.6 评测与导出部署

  • 微调后权重合并:swift export 或 LLaMA-Factory 的 merge_lora.py

  • gguf / turbomind 等格式部署(视情况选择)。

  • 定制评测集(多模态指令、OCR 表格准确率、bbox mAP)来客观比较。


7. 资源整理 & 参考命令速查

  • 官方仓库:Qwen2.5-VL GitHub / Blog / ModelScope 集合

  • 多模态工具qwen-vl-utilsqwen_agent

  • 训练框架:MS-Swift、LLaMA-Factory、xtuner

  • 冷门但好用的小工具

    • 图像批缩放:img2dataset / mmcv

    • 视频抽帧:ffmpeg -i in.mp4 -vf fps=1 out_%04d.jpg


8. 常见问题 FAQ

Q1:Windows 下 CUDA 驱动经常报错怎么办?
A:优先用 WSL2 或直接 Linux;Win 下注意显卡驱动版本和 PyTorch 匹配。

Q2:为什么建议使用英文?
A:训练数据分布所致。建议主逻辑用英文,最后补一句 “请用中文回答”。

Q3:HTML 表格输出总少几列 / 数字错位?
A:提示词里强调“保留所有列”“不要合并单元格”;必要时二次解析文本再纠错。

Q4:72B 一定要单机 8 卡吗?
A:不一定,cpu_offload + 4bit + device_map=\"auto\" 能勉强跑,但速度慢。

Q5:微调后效果不稳?
A:检查数据质量(是否多轮对齐)、超参(lr 太高/epoch 太多),以及视觉编码器是否被破坏。