简介:面向深度学习与图像识别方向的毕业设计、课程设计或期末大作业需求,这份资料围绕Qwen2-VL模型的图像识别微调任务,提供了一个轻量级的完整实战参考。压缩包内共23个文件,包含4个Python脚本,分别负责数据预处理与格式转换、训练、预测推理等关键环节;另有测试样例图片、训练结果图表以及README说明文档,可直观对照代码运行效果。资源整体仅1.16MB,目录结构简洁,方便下载后快速定位所需模块。从数据集的准备与增强、微调策略与超参数设置,到模型训练、性能监控与结果评估,内容覆盖了视觉语言模型微调的主要流程,能够帮助学习者理解迁移学习在图像识别中的具体应用,并支持直接运行或二次改造。已有56人学习下载,适合正在准备课程设计、毕业设计,或希望快速上手Qwen2-VL微调的学生与开发者,也可作为项目报告或答辩展示中的辅助资料。
1. 图像识别课设与毕设的选型困境:Qwen2-VL 微调为什么值得做
课程设计、毕业设计做图像识别,最常见的路子是拿 ResNet、VGG 在公开数据集上训练分类器。方案本身没错,但答辩时竞争力越来越弱——模型现成、脚本照抄,老师问一句“你怎么证明网络学到的特征是有效的”,基本卡住。反过来,直接上手大模型又有门槛:没有 GPU 环境、不知道从哪下手、微调完不知道对不对。Qwen2-VL 恰好卡在中间:视觉编码器加大语言模型,微调后既能输出结构化结果,也能生成自然语言解释,项目能讲的东西一下子多出好几层。这份资源覆盖环境配置、模型微调、模型部署到效果展示的完整链路,适合做课设、毕设,也适合想上手多模态微调的人。拆完这套流程我的感受是:真正耗时间的不在训练,在数据格式和版本匹配。
2. Qwen2-VL 微调原理:架构差异、LoRA 选型与数据格式
2.1 视觉编码器 + 大语言模型:Qwen2-VL 的结构要点
Qwen2-VL 是典型的多模态架构:前面是一个 ViT 视觉编码器,负责把图片切成 patch 并映射成视觉 token;中间有一个 MLP 投影层,把视觉特征对齐到文本 embedding 空间;后面是 Qwen2 的大语言模型基座,负责综合视觉和文本信息生成回复。相比第一代 Qwen-VL,Qwen2-VL 把视觉编码器支持的最大 token 数从 64 个提升到了 256 个,同时改进了窗口注意力(window attention),能够处理更长分辨率甚至视频输入。后续发布的 Qwen2.5-VL 和 Qwen3-VL 在此基础上一路升级:动态分辨率处理更精细,视觉 token 压缩策略更激进,最大输入分辨率也提升到了百万像素级别。对这些架构演进有个印象就够用了,因为微调流程完全同构——只要 Qwen2-VL 跑通,2.5 和 3 只是换一个模型名的问题。
需要特别注意的是:图像在模型内部是以视觉 token 形式参与计算的,不是“一张图对应一个分类标签”的传统逻辑。这意味着如果我们要做图像识别,最自然的做法是构造类似 human 发图加提问、assistant 回答类别与依据这样的对话数据,而不是像传统训练那样只给图像路径加标签。很多第一次上手的人在这里就理解反了,后面训练完推理时会出现“模型不理会图像、直接答非所问”的怪现象。
这里还要说清一个选型误区:如果只是做单标签分类,CLIP 微调确实是更轻的选择。CLIP 把图像和文本做对比学习,分类头简单、训练快,课设完全够用。但它的局限也很明显——输出不够结构化,解释能力弱,老师问“为什么把这张图判为这一类”时答不上来。Qwen2-VL 走生成式路线,回答里可以带类别、带置信度、带一句话说明,项目展示时信息密度完全不一样。做课设的差异化竞争,这一点很关键。
2.2 为什么选 LoRA 而不是全参微调
全参微调 Qwen2-VL-7B 对显存的需求是灾难级别的。推理时 7B 模型用 BF16 精度大约需要 16GB 显存,训练时还要额外存放优化器状态、梯度,动辄 40GB 以上,普通学生机根本扛不住。LoRA(Low-Rank Adaptation)的思路是冻结全部原始权重,只在 attention 层的 Q、K、V、O 投影上插入低秩分解矩阵,训练时只更新这部分参数。LoRA 参数总量通常只有原始模型的 0.5%~2%,显存占用能降到 12GB~16GB,消费级显卡就能跑。
我一般把 LoRA 关键参数控制在这样一组范围:rank(即 r)取 8 或 16,alpha(即 lora_alpha)取 16 或 32,dropout 取 0.05。rank 决定低秩矩阵的容量,图像识别这类中等复杂度任务取 8 就够,取太高反而容易过拟合;alpha 控制缩放比例,一般保持 alpha 是 rank 的两倍。微调完成后,LoRA 权重先保存为 adapter,再通过脚本合并回原始模型,合并后的模型是完整的、可以独立部署的 Qwen2-VL 变体,不再依赖适配器框架。
说个 LoRA 的隐藏优势:一个基础模型可以挂多套 LoRA adapter。比如课程设计做三个不同场景的图像识别,只需要在同一个 Qwen2-VL 上微调三份 LoRA,推理时按需切换对应 adapter 就行,不用保留三个完整模型。这在大模型微调实战里是省显存、省磁盘的常规玩法。反过来,如果数据量特别小、且任务高度依赖记忆细节(比如记住某几张特定图的内容),LoRA 这种低秩表达会产生信息瓶颈,这时才需要考虑全参微调或更大 rank。
2.3 训练数据长什么样:对话模板与图像占位符
Qwen2-VL 的微调数据本质上是多轮对话,每条样本由 messages 数组构成,图像通过占位符 嵌入对话中。这里有一个非常关键的差异:Qwen2-VL 与 Qwen2.5-VL、Qwen3-VL 的对话模板不完全一致,训练时如果用了错误的模板,模型会输出非常奇怪的格式,甚至出现 <|im_start|> 这类 token 裸露在回答里的情况。后面第五章排查时会专门展开。
一条标准的训练样本长这样:system 提示词里写“你是一个图像识别助手,根据用户提供的图像和问题,输出类别名称,并给出简要依据”;messages 里是一条 user 消息,内容是“ \n请判断这张图片属于以下哪个类别:猫、狗、鸟。”,然后是 assistant 回答“这是一张猫的图片。依据:图片中有明显的三角形耳朵和细长尾巴,整体毛色为橘色,符合猫的典型特征。”注意 必须独立占一行,后面加换行再写问题文本,否则视觉 token 的定位会出问题,这是 Qwen 系模型的硬性要求。
数据量方面,图像识别微调和文本微调不同,它不需要海量文本语料。每个类别准备 50~100 张有代表性的图,总共几百到一千条对话样本,训练 3 个 epoch,基本能出一个像样的效果。这里我踩过的坑是类别极度不平衡——比如猫 500 张、鸟只有 30 张,训练完模型会对鸟产生严重的漏判。解决方法是先按类别统计数量,对样本少的类别做增采样,或者对样本多的类别做随机下采样,尽量让各类别数量在同一个量级。
3. 环境配置与数据集构建:版本匹配、划分策略与 JSON 格式
3.1 环境安装与版本匹配
GPU 微调大模型的第一步,先把环境锁死在一个能跑通的组合里。建议使用 Python 3.10、CUDA 11.8 或 12.1、PyTorch 2.1 以上,transformers 版本不低于 4.45。Qwen2-VL 的视觉部分依赖 qwen-vl-utils 库做图像预处理,这个包早期版本和 transformers 的接口有兼容性问题,装的时候尽量选最新版本。
安装命令一般是这样:
conda create -n qwenvl python=3.10 -y conda activate qwenvl pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install transformers accelerate peft deepspeed qwen-vl-utils第一条命令创建独立环境,避免和系统 Python 包产生冲突,这个习惯无论做课设还是自己玩都值得保持。第三条把 torch 指定到 CUDA 12.1 的源,这里的版本号要根据本机 NVIDIA 驱动支持的 CUDA 版本调整,判断方法很简单:终端执行 nvidia-smi,右上角显示的 CUDA Version 就是驱动支持的上限,低于 12.1 就要换成对应的 cu118 源。最后一条把训练相关库一起装上,deepspeed 在小显存环境下可以先不装,用到时再补。
环境装完先做一个可用性验证:加载 Qwen2-VL-7B-Instruct,对一张本地图片调用一次推理。这一步能跑通,后面训练才有意义。验证脚本的核心代码大概是这样:
from transformers import AutoProcessor, Qwen2VLForConditionalGeneration from qwen_vl_utils import process_vision_info model = Qwen2VLForConditionalGeneration.from_pretrained( "Qwen/Qwen2-VL-7B-Instruct", torch_dtype="auto", device_map="auto" ) processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-7B-Instruct") messages = [ {"role": "user", "content": [ {"type": "image", "image": "test.jpg"}, {"type": "text", "text": "这张图片里是什么?"} ]} ] text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) image_inputs, video_inputs = process_vision_info(messages) inputs = processor(text=[text], images=image_inputs, videos=video_inputs, return_tensors="pt") output = model.generate(**inputs, max_new_tokens=128) print(processor.batch_decode(output, skip_special_tokens=True)[0])这段脚本有三个值得解释的地方。第一,process_vision_info 负责把 messages 里的 image 路径读取并预处理成模型需要的视觉输入,这是 qwen-vl-utils 的核心作用;第二,apply_chat_template 会把 messages 渲染成带系统提示词的完整 prompt,这一步如果跳过,模型生成格式会乱;第三,输出解码时要加 skip_special_tokens=True,否则结果里混入一堆特殊 token。第一次加载模型需要下载约 16GB 权重,如果你在 8GB 显存的卡上跑,可以把 torch_dtype 换成 8bit 加载,这样即使推理能过,后面训练前也好心里有数。
3.2 图像数据集的组织方式与划分
数据准备是微调里最花时间、也最影响结果的一步。图像识别微调的数据集组织,建议按类别分文件夹存放,而不是全部丢在一个目录里。这样有两个好处:方便做训练集和验证集的自动划分,也方便后期做错误分析时按类别回溯。常见目录结构是:
data/ images/ cat/ # 每一类放一个文件夹 dog/ bird/ train.json val.json划分比例我一般按 8:2 切分,但划分时要按文件夹层级做,不能简单随机打乱所有文件,否则模型可能过拟合到具体某一张图上。这里有个容易被忽略的点:验证集不能用训练时见过的图像,哪怕同一张图的翻转、裁剪版本也不行,否则验证准确率会虚高,答辩时一旦被质疑,解释起来非常被动。
数据进入训练之前还要过一次清洗。模糊的、遮挡过度的、标签明显错误的图,直接删掉或修正。图像尺寸方面,Qwen2-VL 支持动态分辨率,不用自己 resize 到固定尺寸,但原图太大的话预处理耗时和显存都会上去,我一般会把长边控制在 1024 像素以内。类别数量差距过大的,先做增采样或者换数据增强策略,别指望模型自己“理解”少数类有多重要,它只会学到你给它的数据分布。
3.3 一份可用的 JSON 训练集怎么写
训练集 JSON 的格式直接决定后续能否被 LLaMA-Factory 或原生训练脚本正确读取,每条样本包含 system、user、assistant 三个环节。下面是符合 Qwen2-VL 要求的训练数据片段:
[ { "messages": [ { "role": "system", "content": "你是一个图像识别助手。请根据用户提供的图像,输出正确的类别名称,并给出判断依据。" }, { "role": "user", "content": "<image>\n请判断这张图片属于以下哪个类别:猫、狗、鸟。" }, { "role": "assistant", "content": "猫。判断依据:图片中的动物有直立三角形耳朵、细长尾巴,毛发为橘色并带有条纹,这些特征与猫一致。" } ], "images": ["data/images/cat/cat01.jpg"] } ]人工手写几百条这种 JSON 不现实,我一般用脚本批量生成。把图像路径和标注放在一个 CSV 或字典里,循环拼装成上述结构,最后整体 dump 成 JSON 文件。这里要提醒三个细节:第一,"images" 字段用相对路径,训练脚本的工作目录必须和这个路径对上,否则加载时 FileNotFoundError;第二,问题里把候选类别列出来,能显著约束模型的输出范围,比开放式问“这是什么”更容易收敛;第三,assistant 回答的结构要统一,上面用的是“类别。判断依据:……”的格式,如果有的回答写了依据、有的没写,模型学到的输出风格就会不稳定,后期评估准确率时也很容易被干扰。
到这里,环境、数据都准备完毕,可以进入训练环节。而且有一点我特别想强调:数据格式是否规范,比模型参数调得好不好重要一个数量级。官方 demo 能跑通,不代表你自己造的数据能跑通,第一次做先拿 10 条样本把整个链路跑一遍,再上全量数据,这样排查问题时定位会快很多。
4. 微调实操:LLaMA-Factory 训练、模型合并与部署
4.1 用 LLaMA-Factory 跑 LoRA 训练
训练部分我直接用 LLaMA-Factory 完成,它封装了数据加载、模板渲染、LoRA 注入和训练循环,不需要自己手搓 Trainer,同时对 Qwen2-VL 的支持已经比较成熟。如果你想更深入控制训练过程,也可以用 transformers 的 Trainer 手写训练脚本,但课设和毕设场景下,把精力花在数据质量和结果分析上,比花在训练循环调试上更有价值。
LLaMA-Factory 的安装很简单,源码方式拉下来后安装依赖即可:
git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory pip install -e .装完之后最重要的动作是注册数据集。编辑 LLaMA-Factory 里的 data/dataset_info.json,追加一条自定义数据集记录:
{ "my_vl_dataset": { "file_name": "data/train.json", "formatting": "sharegpt", "columns": { "messages": "messages", "images": "images" }, "tags": { "role_tag": "role", "content_tag": "content", "user_tag": "user", "assistant_tag": "assistant" } } }这个配置里有两处容易翻车。第一,"formatting" 必须设为 "sharegpt",因为我们造的是 messages 数组格式,和 LLaMA-Factory 的 alpaca 格式不兼容;第二,验证集可以单独再注册一个条目,也可以在训练参数里通过 val_dataset 指定。如果想让模型训练过程中跑验证,就在注册完训练集后,用同样方式注册 val.json 并配上 val_dataset 参数。
训练命令我常用下面这一条:
llamafactory-cli train \ --model_name_or_path Qwen/Qwen2-VL-7B-Instruct \ --template qwen_vl \ --stage sft \ --finetuning_type lora \ --dataset my_vl_dataset \ --val_size 0.1 \ --cutoff_len 1024 \ --learning_rate 1e-4 \ --num_train_epochs 3 \ --per_device_train_batch_size 2 \ --gradient_accumulation_steps 4 \ --lora_rank 8 \ --lora_alpha 16 \ --output_dir output/qwen2vl_lora \ --logging_steps 10 \ --save_steps 200 \ --bf16 true按重要性排一个参数说明。--template qwen_vl 必须显式指定,用错模板,训练出来的模型输出格式会直接崩掉;--lora_rank 8 和 --lora_alpha 16 是前面说的低秩参数组合;--cutoff_len 1024 表示只截取前 1024 个 token 参与训练,图像识别任务里一个样本的文本部分通常不超过几百 token,设 1024 足够,又不浪费显存;--per_device_train_batch_size 2 搭配 --gradient_accumulation_steps 4,等效 batch size 为 8。如果你的显卡只有 8GB 显存,把 batch size 降到 1,先跑通流程,质量后面再说。
训练过程中日志信息很多,重点看 loss 和 eval_loss。图像识别这类 SFT 任务,loss 在第 1 个 epoch 内降到 1.0 以下属于正常,如果 500 步还在 2.0 以上徘徊,大概率是数据格式或模板出了问题,不要盲目加大训练轮数,先停排查。训练完成的标准是 eval_loss 不再明显下降,继续多跑几轮只会让训练集 loss 继续降、验证集 loss 反而回升,那就是过拟合信号。
4.2 模型合并与导出
训练结束后,output 目录里保存的是一堆 LoRA adapter 权重,不是完整模型。要让它能独立加载运行、能在答辩演示时脱离 LLaMA-Factory 环境,必须把 LoRA 权重合并回基础模型。
合并操作在 LLaMA-Factory 里是一条命令:
llamafactory-cli export \ --model_name_or_path Qwen/Qwen2-VL-7B-Instruct \ --adapter_name_or_path output/qwen2vl_lora \ --template qwen_vl \ --finetuning_type lora \ --export_dir output/qwen2vl_merged \ --export_size 4--export_dir 是合并后模型的输出目录,合并后的模型结构完整,用 transformers 的 from_pretrained 直接加载即可,不再需要 LoRA 相关代码;--export_size 4 表示按约 4GB 分片保存,便于复制和移动。这一步容易忽略的是,合并时基础模型路径必须和训练时一致,如果训练用的是本地副本,合并时也要用同一个本地路径,模型版本不一致会直接报 shape mismatch。合并完成后,输出目录里应该有 model-00001-of-0000X.safetensors、config.json、tokenizer 等文件,这样一个完整的推理模型骨架就齐了。
4.3 部署与推理验证:效果展示脚本
合并完成后,写一个独立的推理脚本验证效果,这也是答辩效果展示环节的核心代码。我习惯把下面这段保存为 inference.py:
from transformers import AutoProcessor, Qwen2VLForConditionalGeneration from qwen_vl_utils import process_vision_info model_dir = "output/qwen2vl_merged" model = Qwen2VLForConditionalGeneration.from_pretrained( model_dir, torch_dtype="auto", device_map="auto" ) processor = AutoProcessor.from_pretrained(model_dir, trust_remote_code=True) image_path = "data/images/cat/cat01.jpg" messages = [ {"role": "user", "content": [ {"type": "image", "image": image_path}, {"type": "text", "text": "请判断这张图片属于以下哪个类别:猫、狗、鸟。"} ]} ] text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) image_inputs, video_inputs = process_vision_info(messages) inputs = processor(text=[text], images=image_inputs, videos=video_inputs, return_tensors="pt").to(model.device) output = model.generate(**inputs, max_new_tokens=128, do_sample=False) print(processor.batch_decode(output, skip_special_tokens=True)[0])推理时我关闭了采样(do_sample=False),因为图像识别任务希望输出稳定,同样一张图每次应该得到同样的答案,而不是像对话那样带随机性。如果想让展示更有“智能感”,可以把 do_sample 改为 True 并设 temperature,但用于评估时一定要保持 False。到这一步,从训练到合并到推理的完整链路已经闭环,你手里是一个真正做过微调的图像识别模型,而不是单纯加载预训练权重。
下面单独讲这条链路里最容易翻车的几个地方,这些坑我几乎全踩过,拿出来给各位当个参考。
5. 常见问题排查:微调翻车的五个高频故障
微调过程中遇到问题不可怕,可怕的是不知道问题出在哪个环节。根据我拆过和帮别人调过的项目,绝大多数故障都集中在数据格式、模板匹配和显存估算这三类问题上。下面五条按现象、原因、解决的顺序写,可以直接对照排查。
| 现象 | 主要原因 | 解决方向 |
|---|---|---|
| 显存溢出,进程被杀 | batch size / cutoff_len 过大 | 降 batch 到 1,cutoff 降到 512 |
| 推理时完全不看图像 | 占位符格式错误 | 修正占位符,独立占一行 |
| 验证集准确率虚高 | 划分时有信息泄漏 | 按目录分层划分,删减增强副本 |
| 输出带 <|im_start|> token | template 选错 | 训练和推理统一用 qwen_vl 模板 |
| 合并模型报 shape mismatch | 基础模型来源不一致 | 统一模型路径,避免二次下载 |
5.1 训练时显存溢出,进程直接被 kill
现象:训练刚开始或者跑到第一个 epoch 时报 CUDA Out Of Memory,更极端的情况下连报错都没有,进程直接消失,终端里只剩 "Killed"。原因:per_device_train_batch_size 太大,或者 cutoff_len 太长,再加上模型的视觉编码器和语言模型同时占显存,整卡根本装不下。解决:先把 batch size 降到 1,再把 cutoff_len 降到 512,同时用 gradient_accumulation_steps 补偿等效 batch size。如果显存还是不够,就用 8bit 量化加载基础模型,LLaMA-Factory 里对应参数是 --quantization_bit 8。我的血泪经验是:先跑通再优化,宁可在小参数下完成一次完整训练,也不要反复试大参数把时间都耗在 OOM 上。
5.2 模型训练时损失正常,但推理时完全不看图像
现象:训练曲线正常下降,但推理时问“这张图是什么”,模型给出的回答和图像内容完全无关,甚至直接说“我无法查看图片”。原因:训练数据里的 占位符和问题文本放在同一行,或者占位符写成了 、[image] 等其他形式,模型根本没把图像 token 和文本 token 正确拼接,整条训练样本退化成纯文本微调。解决:回到数据文件,确认 user 内容严格写成 " \n请判断……" 的格式,占位符必须是大写 image 且带尖括号,换行符不能省略。这类问题最坑的地方在于训练时完全无感知,loss 照常下降,只能靠推理结果反推,所以第一次跑全量数据之前,务必先用一条样本做端到端验证。
5.3 验证集准确率虚高,答辩被问倒
现象:训练过程里验证准确率冲到 98%,但换一张没见过的测试图,效果一塌糊涂。原因:验证集里混入了训练集图像的增强版本,或者划分数据时没有按目录分层,同一张图出现在两边。解决:重新按类别目录做分层划分,保证同一张图只出现在训练集或验证集之一;更严格一点,把同一来源、相似角度的图像也放到同一侧,避免信息泄漏。验证集的意义在于给答辩数据提供可信度,如果数据划分站不住脚,整个项目会被一票否决,这个问题比显存溢出严重得多。我自己现在每次划分完都会写一个小脚本,扫描两个集合里的文件名做交集比对,确认没有重叠才继续。
5.4 模型输出格式混乱,特殊 token 裸露
现象:推理结果里出现 <|im_start|>、<|im_end|> 一类 token,或者回答前面多出来一长段 system 提示词。原因:训练时 template 设置错误,比如 LLaMA-Factory 的 template 选成了 qwen 而不是 qwen_vl;或者推理脚本里没调用 apply_chat_template,直接拼接了原始文本。解决:训练和推理两侧的模板必须统一。训练命令里 --template qwen_vl,推理脚本里用 processor.apply_chat_template,并且两处的 tokenizer 必须来自同一个模型路径。输出解码时保留 skip_special_tokens=True,能在最外层兜底。这种问题在校验数据时很难发现,因为训练集里的 assistant 回答是人工写的、格式规整,模型只是在生成时暴露了模板学习不充分。
5.5 合并后的模型加载报 shape mismatch
现象:模型合并的 export 命令报 shape mismatch,或者加载后在推理时 tensor 大小对不上。原因:合并时基础模型路径和训练时用的不是同一来源,比如训练时用官方下载的 Qwen/Qwen2-VL-7B-Instruct,合并时换成了本地某个旧版本目录。解决:统一模型来源。合并时把 --model_name_or_path 写成训练时完全一致的路径。如果训练时用的是 LLaMA-Factory 自动下载的缓存路径,训练完成后先记录实际使用的模型目录,合并时直接复制这个路径。我的习惯是训练前就把模型固定到本地目录,整个过程不做第二次下载,避免版本漂移。还有一个容易忽略的关联问题:如果训练时开了 8bit 量化,但合并时没有加相同的量化参数,也会出现权重维度对不上的情况,合并配置要和训练配置保持一致。
6. 进阶:把微调模型接进自己的图像识别流程
6.1 与目标检测、分类等任务的协同使用
微调后的 Qwen2-VL 可以当作一个视觉理解引擎嵌入到更大的流程里,而不只是单张图分类的工具。常见组合:先用目标检测模型定位图像中的目标区域,裁剪出目标后再交给微调后的 Qwen2-VL 做属性识别或细粒度分类,输出结果以 JSON 形式传给后续逻辑。这样分工的好处是检测和识别各司其职,排查问题时容易定位到底哪个环节出错。热词里提到的驾驶员要素提取这类视觉层微调任务,本质也在这里——把通用 VLM 通过微调约束到特定细分领域,思路和图像识别完全一致,区别只在于数据内容和输出格式。如果你后续要把这套方法迁移到其他场景,只需要改数据集的标注内容,再跑一遍同样的流程,工程上基本是平移的。
6.2 效果验证:自建测试集与指标设计
微调完成后,不要只看训练集 loss,更不要只看几条样例的输出效果就下结论。我会从原数据集中按类别抽出 20% 作为测试集,逐条调用推理脚本,再用脚本统计准确率。关键是模型回答里经常带有多余字符,比如“猫。判断依据:……”,所以需要先做字符串抽取或正则匹配,提取出首段的类别名,再和真实标签比对,不能直接比较整句字符串。我第一次评估时拿整句回答去比,准确率虚低到离谱,一度以为模型完全没学到东西,后面加了正则抽取才发现真实准确率在 90% 以上。从那以后,我每次微调任务都会强制走一遍完整流程:固定环境版本、校验数据格式、小参数跑通、标准模板推理、独立测试集评估,然后再进入正式训练。这套习惯也推荐给每一个准备做多模态微调课设或毕设的人。Qwen2-VL 的微调思路,迁移到 Qwen2.5-VL 和 Qwen3-VL 时同样适用,因为它们的数据格式和模板机制一脉相承。希望帮到你,动手跑一遍比看十篇文章有用得多。
本文还有配套的精品资源,点击获取