ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Qwen2-VL-2B+LoRA:图像描述微调实战与显存优化指南

Qwen2-VL-2B+LoRA:图像描述微调实战与显存优化指南 简介图像描述Image Captioning是连接计算机视觉与自然语言处理的核心任务旨在让模型自动生成对图片内容的自然语言描述。多模态大模型的兴起使得这一任务从传统的CNNRNN架构演进为视觉-语言统一建模显著提升了跨模态理解与生成能力。然而在实际落地中大模型的高推理成本与显存占用常成为瓶颈。LoRA低秩适配微调技术通过冻结基础模型、仅训练少量适配参数大幅降低了模型微调的算力与显存需求使得2B级多模态模型在消费级显卡上进行高精度领域适配成为可能。基于Qwen2-VL-2B与LoRA的实践路线覆盖了从COCO2014数据清洗、视觉token处理、QLoRA量化配置到推理优化与部署成本控制的完整流程。该方法在图像描述生成中兼顾了效果与资源消耗为设备端智能应用提供了高效落地方案。 今年年初我给一个小型设备做图像描述Image Captioning功能。设备侧推理资源比较紧张云端 API 的成本在长期运行后又扛不住我最终把方案落在了阿里通义实验室的 Qwen2-VL-2B-Instruct 上并用 LoRA 在 COCO2014 图像描述数据集上做了专项微调。整个过程走下来最大的体会是多模态大模型微调的门槛不在“训练”本身而在数据整理、视觉 token 处理和显存控制这些容易被忽略的细节上。这篇文章把我的完整项目从模型选型、数据处理、LoRA 参数配置、踩坑记录到评测部署全部写出来给同样想用 2B 级多模态模型落地图像识别与描述任务的朋友一个可直接参考的实操路径。1. 为什么是 Qwen2-VL-2B图像描述场景下的模型选型分析1.1 图像描述任务需要什么样的多模态模型图像识别与描述任务说白了就是输入一张图片输出一句能准确概括图中主要信息的自然语言。它比纯分类任务复杂得多模型不仅要“认出”图里有猫、有沙发、有人在喝水还要把这些元素组织成一句符合语法的描述甚至要能区分“一个穿红色外套的男孩在滑板上”和“一个男孩在红毯上滑行”这种细粒度差异。COCO2014 数据集的标注风格天然就带有这种多样化描述的特点每张图有 5 个不同的人类标注同一张图会被描述成不同侧重点的句子。一个能做好这个任务的模型必须同时具备视觉理解能力和语言生成能力这正是 Qwen2-VL 这类多模态大模型擅长的事情。传统做法是训练一个 CNN 编码器加 LSTM/Transformer 解码器比如经典的 NIC、Oscar、VinVL 这类模型。这套路线在 COCO 指标上确实达到了不错的水准但有个非常现实的问题它们的视觉编码器大多是固定的或者只做了浅层的跨模态交互遇到未见过的物体组合、场景和语言表达泛化能力很有限。而 Qwen2-VL 这种统一架构的多模态大模型把视觉编码器、视觉-语言投影层和 LLM 主干放在同一个训练框架里微调时可以让视觉和语言侧同时适应目标任务天然比“冻结视觉编码器只调解码器”的方案更有上限。1.2 2B 参数量的现实考量这里必须坦白一句在 COCO2014 上做图像描述真要刷榜选 Qwen2-VL-7B 甚至 72B 肯定效果更好。但我的落地场景对单卡显存和推理时延有硬约束最终锁定 Qwen2-VL-2B-Instruct理由很直接。首先是显存。2B 模型的 bf16 全量权重大约 4.8GB用 QLoRA 4bit 量化后基础模型权重只需要 1.5GB 左右。配合 LoRA 的低秩适配器和合理的 batch size单张 10GB 显存的显卡就能跑训练如果使用更激进的梯度累积和更小的 max_pixels8GB 甚至 6GB 显存也有机会。相比之下7B 模型光 4bit 量化后就要 4GB 权重加上激活和优化器状态低端卡基本没戏。其次是推理成本。设备端跑 caption 任务往往有实时响应需求2B 模型在消费级 GPU 上生成一句描述通常在一秒以内在 Apple Silicon 或者带 NPU 的嵌入式设备上也有工程可行性。7B 模型就算量化了延迟也是 2B 的 2~3 倍对于小批量部署来说差距非常直观。1.3 微调目标不是“教会看懂图”而是“教会说 COCO 的话”很多人对图像描述微调有个误解觉得微调是为了让模型“认识更多东西”。其实 Qwen2-VL-2B 基座模型本身已经见过海量图文数据图片识别能力并不差。它原生的问题是你直接问它“请描述这张图片”它倾向于输出一段很泛、很 Safe 的宽泛描述比如“图片中有一个人和一条狗”而不是 COCO 标注风格里那种“一个男人蹲在路边手里拿着一个喷漆罐喷漆罐上写着 STOP”的精确定格式描述。LoRA 微调的核心目标是让模型在保持原有世界知识的同时学会输出更贴近 COCO 标注风格、句式更完整、信息密度更高的描述。这也是我最终决定在 COCO2014 上做微调而不是直接使用零样本能力的原因基座模型能理解图像但它的输出分布和下游任务的期望分布不一致需要用少量高质量标注把它们拉齐。2. COCO2014 图像描述数据的清洗与样本构建2.1 数据集下载与目录组织COCO2014 的 caption 数据由 images 和 annotations 两部分组成。图片分为 train2014 和 val2014 两个目录标注文件有captions_train2014.json、captions_val2014.json。我在项目里只用了 val2014 中带标注的子集来充当训练集的一部分不标准做法是 train2014 用来训练val2014 用来验证。不过 COCO 官方真正用于离线评测的 “test” 标注是不公开的所以很多开源工作会从 val2014 中切一小部分做验证。我的目录结构如下data/ ├── images/ │ ├── train2014/ │ └── val2014/ └── annotations/ ├── captions_train2014.json └── captions_val2014.json需要提醒的是COCO 图片的压缩包解压之后有 13GB 左右trainval下载时建议用官方给出的 HTTP 链接不要用第三方网盘避免文件缺失或校验不一致。解压完之后先用一段脚本检查一下每张图是否可正常打开不要假装它们都是好的。2.2 从 captions json 到对话式训练样本captions_train2014.json的结构是三个字段info、images、annotations。images数组里有每个图片文件的 id、文件名、宽高等信息annotations数组里每一条记录包含image_id、id和caption。同一张图对应 5 条 caption。Qwen2-VL 微调用的数据格式是对话式的训练脚本会让模型以多轮对话的方式输出 caption。我构建的格式如下{ id: COCO_train2014_000000000001, image: data/images/train2014/COCO_train2014_000000000001.jpg, conversations: [ { from: human, value: image\n请描述这张图片的内容。 }, { from: gpt, value: A man with a red helmet on a small moped on a dirt road. } ] }这里有一个容易踩的坑image占位符必须放在 human 的 value 里而且前面不要乱加空格。Qwen2-VL 的 processor 会把它替换成动态计算的视觉 token。训练时如果占位符缺失或者位置不对模型可能会学到一个“看不见图”的幻觉训练 loss 看起来正常但推理时完全不对。我也没有一股脑把 5 条 caption 都喂进去。实践下来每张图随机取 1~2 条作为训练标签就够了。一方面控制数据量另一方面也避免模型对同一张图产生“标准答案困惑”——5 条标注风格差异不小全部作为监督信号会让模型输出变得平庸。随机取 1 条反而能让模型学会更多样的描述方式。2.3 样本清洗与验证集划分COCO caption 虽然人工标注质量不错但依然存在少量脏数据。比如有些 caption 出现多余的 HTML 转义字符像amp;被写成了训练前最好统一做 HTML unescape 并去掉不可见字符。还有些 caption 纯粹是“A picture of a something”这种套话如果是为目标场景微调可以一并过滤掉但如果你要做的是 COCO 标准评测保留会更接近官方分布。我是按标准评测来做的所以保留了全部样本只做了字符层清洗。清洗完以后从captions_train2014.json里抽 30 张图作为最小实验集先跑通整个管线再上全量。全量训练集我构建了约 12 万条人机对话样本验证集是从captions_val2014.json里随机抽取 3000 张图构成的每张图保留 5 条官方的参考描述专门用于计算 BLEU 和 CIDEr。注意验证集的构造不能和训练集有交叉COCO train2014 和 val2014 的图片 id 是隔离的不存在泄漏问题。2.4 数据加载器实现细节Qwen2-VL 加载图片时不会把原图直接塞给模型而是会先做动态分辨率缩放把图片等比缩放到不超过max_pixels的范围内再切成若干 patch 作为视觉 token。这个行为意味着数据加载时要拿到真实的图片字节流而不是只传一个文件路径字符串。import json from PIL import Image from datasets import load_dataset, Dataset def build_dataset(ann_path, image_root, sample_limitNone): with open(ann_path, r, encodingutf-8) as f: anns json.load(f) samples [] for ann in anns[annotations]: image_id ann[image_id] file_name fCOCO_train2014_{image_id:012d}.jpg img_path f{image_root}/{file_name} samples.append({ id: fCOCO_train2014_{image_id:012d}, image: img_path, caption: ann[caption].strip(), image_id: image_id, }) return Dataset.from_list(samples)加载之后打开图片要统一转成 RGB去掉 EXIF 里可能存在的旋转信息干扰。否则某些手机拍摄的历史图片在描述时会出现“上下颠倒”“左右镜像”的错乱虽然 COCO 里大多是网络图片但保不齐有少量带特殊 EXIF 的样本。用Image.open(...).convert(RGB)一步处理即可。3. LoRA 微调实战配置、参数与训练全流程3.1 环境准备与依赖版本这个项目的依赖不算复杂但版本必须卡死。我最初在 transformes 4.44 上跑直接报 Qwen2VL 模型类不存在的错误。Qwen2-VL 的原生支持是在 transformers 4.45 之后才稳定的建议直接上 4.46 以上版本。我的核心环境如下Python 3.10 torch 2.3.1 transformers 4.46.2 accelerate 0.33.0 peft 0.13.0 bitsandbytes 0.43.3 qwen-vl-utils 0.0.8 datasets 2.21.0 deepspeed 0.14.4可选单卡不需要需要注意qwen-vl-utils 是用来处理图像到messages格式的关键依赖它会做图像尺寸的有效性校验别漏装。训练脚本如果自己写强烈建议用transformers.Trainerpeft不要手撸训练循环否则你会花很多时间去对齐视觉 token 的 attention mask 和 label。3.2 加载基座模型与处理器加载方式有两条路。一条是从 Hugging Face 直接加载Qwen/Qwen2-VL-2B-Instruct另一条是从本地 zip 解压后的路径加载。我项目里用的是本地路径方式因为内网环境比较常见。关键加载参数如下from transformers import Qwen2VLForConditionalGeneration, AutoProcessor from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training import torch model Qwen2VLForConditionalGeneration.from_pretrained( Qwen/Qwen2-VL-2B-Instruct, torch_dtypetorch.bfloat16, device_mapauto, quantization_configBitsAndBytesConfig( load_in_4bitTrue, bnb_4bit_compute_dtypetorch.bfloat16, bnb_4bit_use_double_quantTrue, bnb_4bit_quant_typenf4, ), attn_implementationsdpa, ) model prepare_model_for_kbit_training(model) processor AutoProcessor.from_pretrained(Qwen/Qwen2-VL-2B-Instruct, trust_remote_codeTrue) processor.tokenizer.padding_side right这里我用了 QLoRA 的 4bit NF4 量化加上 double quant。这样加载后的基础模型权重放在显存里的占用只有大约 1.5GB给后续 LoRA 参数和激活值留下了充足空间。attn_implementationsdpa用 PyTorch 的 scaled dot product attention比默认的 eager attention 省显存且更快。3.3 LoRA target_modules 的选择逻辑LoRA 微调需要决定往哪些线性层注入低秩矩阵。Qwen2-VL-2B 的 Transformer 结构里有多组线性层注意力层的q_proj、k_proj、v_proj、o_proj以及 FFN 层的gate_proj、up_proj、down_proj。我的经验是对图像描述这类生成任务同时微调注意力层和 FFN 层效果更好。只调注意力层模型学得慢只调 FFN 层模型对描述句式的拟合很容易过拟合到“续写”而忽略图像内容。最终我选择了全部 7 个模块lora_config LoraConfig( r16, lora_alpha32, target_modules[ q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj ], lora_dropout0.05, biasnone, task_typeCAUSAL_LM, )有人会问为什么不把视觉编码器里的投影层也加进去我试过把merger层的线性层也加入 target训练 loss 下降更快但评测指标CIDEr没有显著提升反而多了不少可训练参数。推测是视觉编码器在预训练时已经学到了比较通用的视觉特征COCO 图像分布不算特殊没必要做太深层的视觉适配。所以最终保留了纯 LLM 侧的 LoRA。3.4 训练超参数设定与梯度累积我的训练配置如下参数取值说明per_device_train_batch_size2每卡 2 个样本图片分辨率高时很容易 OOMgradient_accumulation_steps8等效 batch size 16num_train_epochs312 万样本3 轮足够learning_rate2e-4LoRA 常用学习率区间lr_scheduler_typecosine配合 warmup 比较稳定warmup_ratio0.03冷启动平滑optimpaged_adamw_8bit8bit 优化器省显存weight_decay0.05正则化max_seq_length1024图文序列总长度max_pixels512400图片缩放后的最大像素数关键点在于max_pixels。Qwen2-VL 会把图片按面积缩放到max_pixels内。我在项目里把它设为 512400大约是 828x618 的像素规模这样单张图最多生成约 600~800 个视觉 token加上文本序列总长控制在 1024 以内。如果你不设这个参数原始 1024x1024 图片可能产生 2000 视觉 tokenbatch size 稍微一大就直接 OOM。训练时用Trainer封装配合DataCollatorForSeq2Seq。Qwen2-VL 的 labels 处理比纯文本模型要更小心图片占位符的 token 位置在标签里要填-100否则模型会在预测图片 token 的位置计算 loss导致训练 loss 虚高且误导模型。用官方 Trainer 时processor会自动处理好这个问题但如果你自己写 collator一定要检查labels里所有 image token 对应的位置是不是被 mask 掉了。3.5 训练过程中的显存观测单卡 24GB 显存的环境下我的实际显存占用峰值约 11GB其中有约 4GB 来自反向传播的激活值。如果把max_pixels降到 307200峰值可以压到 8GB 左右但描述精度会略有下降因为小图丢细节。训练速度方面单张 A100 40GB 上约 1.5 小时/epoch如果是 4090 24GB约 2.2 小时/epoch。如果只有 8GB 显存建议把max_pixels降到 307200per_device_train_batch_size设为 1gradient_accumulation_steps提高到 16。梯度累积不会增加显存只是会拉长训练时间但至少能让训练跑起来。这应该是 2B 模型 QLoRA 微调和消费级显卡之间最舒服的平衡点了。4. 训练过程中的 Loss 曲线、显存表现与踩坑修复4.1 loss 曲线长什么样第一轮刚开始时训练 loss 在 1.8 左右这个数字看起来很高但注意 Qwen2-VL 的 tokenizer 词表较大且 caption 句子的平均长度在 10~20 个单词每一个 token 的预测难度都不低。到第一个 epoch 结束时loss 降到 1.1 附近。等第三个 epoch 完成训练 loss 稳定在 0.85~0.9验证集的 loss我每 1000 步抽 200 条算一次保持在 1.0~1.05没有明显的过拟合迹象。如果验证集 loss 在某个点开始反弹优先检查是不是训练数据重复曝光太多次。COCO 每张图只有 5 条标注模型在第 2 个 epoch 就会把常见句式的组合背得比较熟。我的处理方式是只训练 3 个 epoch并且把验证集 loss 的上升作为早停信号。4.2 常见踩坑一图片分辨率引发的 OOM这个坑我翻车了好几次值得单独拿出来说。Qwen2-VL 内部的视觉编码器会把图片切成 16x16 像素的 patch然后把这些 patch 映射成视觉 token 送入 LLM。如果图片是 1024x1024 的方形图视觉 patch 数量大约是(1024/16)^2 4096个 token。再算上每个 patch 还有 4 个子位置实际更夸张。这会一下子把输入序列长度撑到 5000就算 batch size 为 1显存也会瞬间爆炸。我的排查过程是先用torch.cuda.max_memory_allocated()打印峰值显存发现训练 loss 还没算就 OOM。检查每张图片的尺寸分布发现部分图片是长条型等比缩放后像素数虽然不高但 patch 数量因为长边限制反而非常多。最终把所有图片统一经过processor.image_processor处理并显式设置max_pixels同时过滤掉长宽比超过 3:1 的极端图片问题解决。from qwen_vl_utils import process_vision_info # 或直接设置 max_pixels IMAGE_1 {image: image_path, max_pixels: 512400}4.3 常见踩坑二对话模板与 image_token 处理不一致Qwen2-VL 对图片占位符的要求非常严格。Transformers 的processor.apply_chat_template在内部把image替换成真正的视觉 token如果你的数据里 human 的 value 不是用image开头而是用了文本提示“请看图片”再放占位符训练时也可能成功但推理时会发现模型把 prompt 里的几个词当成图片内容来“描述”输出乱七八糟。另一个更隐蔽的问题是我最初把padding_side设置成了left这在纯文本模型里没问题但在多模态模型里会导致视觉 token 和文本 token 在 padding 后错位。Qwen2-VL 的官方 processor 在训练阶段要求padding_sideright也就是右侧 padding否则 attention mask 的位置会乱。这里建议直接用官方数据 collator 的默认行为不要自己造轮子。4.4 常见踩坑三数据集里有损坏图片COCO 图片质量总体稳定但我不止一次遇到过某张 JPEG 文件在Image.open()时能打开训练到中途解码却报OSError: broken data stream。原因大多是图片文件本来就有截断或者 cmyk 色彩空间异常。我的方案是在 build dataset 时做一次预检把所有图片统一转成 RGB 再存成新的文件夹同时用try-except跳过坏文件并记录坏图 id。from PIL import Image import os def verify_and_convert(img_path, out_root): try: with Image.open(img_path) as im: im im.convert(RGB) out_path os.path.join(out_root, os.path.basename(img_path)) im.save(out_path, JPEG, quality95) return out_path except Exception: return None预处理过程中发现大约 0.03% 的图存在问题比例不高但如果不处理训练到一半挂掉是最折磨人的。4.5 另一条经验LoRA rank 不需要大前几次实验我把r设成了 32lora_alpha设为 64理论上可训练参数翻倍但最终 CIDEr 只比r16高了 0.3而训练时间增加了约 40%。对于 COCO 这种标注风格相对机械、样本量又大的任务r16已经足够。把省下来的显存拿去提高max_pixels或 batch size收益更明显。5. 微调后模型的推理评测5.1 单张图片推理脚本训练收敛之后我用下面这段脚本加载 LoRA 权重做单张图片推理import torch from transformers import Qwen2VLForConditionalGeneration, AutoProcessor base_model_path Qwen/Qwen2-VL-2B-Instruct lora_path ./output/coco_caption_lora/ model Qwen2VLForConditionalGeneration.from_pretrained( base_model_path, torch_dtypetorch.bfloat16, device_mapauto, attn_implementationsdpa, ) model.load_adapter(lora_path) processor AutoProcessor.from_pretrained(base_model_path, trust_remote_codeTrue) image_path test_images/COCO_val2014_000000000042.jpg messages [ { role: user, content: [ {type: image, image: image_path}, {type: text, text: 请描述这张图片的内容。}, ], } ] text processor.apply_chat_template(messages, tokenizeFalse, add_generation_promptTrue) inputs processor(text[text], images[image_path], return_tensorspt) inputs inputs.to(model.device) generated_ids model.generate( **inputs, do_sampleFalse, num_beams3, max_new_tokens128, ) generated_ids_trimmed [ out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids) ] output_text processor.batch_decode( generated_ids_trimmed, skip_special_tokensTrue, clean_up_tokenization_spacesFalse ) print(output_text[0])这里用的推理参数是num_beams3和do_sampleFalse。我对比过 greedy、beam3、beam5 以及 temperature0.8 的采样beam3 在质量和速度之间最平衡beam5 的 CIDEr 只提升 0.5 左右但时间几乎翻倍。如果想要多样化的描述结果可以把do_sampleTrue并调高温度比如temperature0.9但首句质量会略不稳定。5.2 基座模型与微调模型的定性对比从 val2014 随机抽了 20 张图做人工对比差异非常明显。原图是一张厨房场景背景有烤箱、橱柜、一个站立的人。基座模型输出The kitchen features wooden cabinets and a stove.微调模型输出A person standing in a kitchen with wooden cabinets, a stove, and a window.基座模型输出的句子更通用微调模型学会了 COCO 风格的“主体 环境 动作倾向”句式且信息密度更高。另一张图是有多辆公交车停靠在路边。基座模型说A street with buses parked on the side.微调模型说Several buses are parked along the side of a road near a building.更自然也更贴近 COCO 参考标注的句式。5.3 定量评估BLEU-4 与 CIDEr评估方式我从 val2014 里随机抽取了 1000 张带有 5 条参考描述的图片用上述推理脚本批量生成描述然后用 pycocoevalcap 计算 BLEU-4、ROUGE-L 和 CIDEr-D。结果如下模型BLEU-4ROUGE-LCIDEr-D基座 Qwen2-VL-2B-Instruct零样本12.631.764.8LoRA 微调后r16, 3 epochs17.436.287.3经典指标参考Oscar 等偏老模型18.937.492.1BLEU-4 从 12.6 提升到 17.4CIDEr 从 64.8 提升到 87.3这个幅度在图像描述任务里算非常显著了。虽然还没到老牌专用模型的巅峰值但 Qwen2-VL 基座的语义理解能力明显更强遇到复杂场景时生成结果的鲁棒性要优于 Oscar 那类老模型。5.4 评估结果背后的讨论需要泼一盆冷水的是COCO 的 caption 评测指标和真实产品体验并不完全划等号。BLEU 和 CIDEr 对“措辞匹配”很敏感同样的意思换了表达方式指标就会下降。微调模型能大幅涨分一部分原因是它的输出句式确实和 COCO 参考标注更像了。如果你要拿这套模型去做真实产品的图像描述不要只盯着评测指标还是要做一轮人评重点观察语义正确性和信息完整性。从我的测试看微调后的模型在以下场景有明显短板图片里有大量密集小物体比如一群鸟、一堆人描述数量容易不准确图片里存在抽象概念比如讽刺、幽默、时间感模型基本无能为力中文场景如果直接用 COCO 英文标注微调输出会仍然偏英文需要额外准备中文 caption 数据。6. 模型合并、部署成本与后续扩展方向6.1 LoRA 权重合并与导出训练完的 LoRA 适配器可以单独保存推理时用load_adapter临时加载。但生产环境最好把 LoRA 权重合并进主干模型省去加载时多做一步 Lora 融合的麻烦。from peft import PeftModel base_model Qwen2VLForConditionalGeneration.from_pretrained(..., torch_dtypetorch.bfloat16) model PeftModel.from_pretrained(base_model, ./output/coco_caption_lora/) merged_model model.merge_and_unload() merged_model.save_pretrained(./merged_model/) processor.save_pretrained(./merged_model/)合并后的模型可以直接替换原来的模型路径推理性能和基座模型完全一致不会因为多一层 LoRA 分支而变慢。我建议所有上线流程都走这一步既方便部署也不容易出现环境差异。6.2 部署成本估算合并后的 bf16 模型大小约 4.8GB。如果部署在 GPU 上2B 模型的显存占用大约 5GB加上推理时的 KV cache7GB 左右就够。使用 vLLM 或 SGLang 这类推理框架在 A10 或 4090 上单卡数实例吞吐可以达到 50~100 tokens/s生成一句 20 词左右的描述只需要 0.5~1 秒。如果目标是纯 CPU 或边缘设备可以把模型进一步做 4bit 量化AWQ 或 GPTQ量化后权重降到 1.5GB 左右。CPU 上生成一句描述大约需要 3~10 秒取决于所用硬件的内存带宽。带 NPU 的移动平台有机会把延迟压到 1 秒以内但需要针对性的算子适配工程量较大。6.3 后续可以这样扩展这个项目的底座是英文 COCO 描述但实际落地时我很快遇到了中文描述需求。后续可以考虑的做法是在现有 LoRA 权重基础上用一份中文图像描述数据集比如 COCO-CN 或自建数据继续做增量 LoRA 微调学习率降到 1e-4epoch 降到 1~2这样可以让模型保留英文 COCO 风格的句式能力同时迁移到中文输出。另外如果对描述结果有更多定制需求可以在 prompt 里加控制指令比如“用不超过 15 个词描述图片”“请着重描述人物的动作”。Qwen2-VL 对指令理解能力不错LoRA 微调后也不会丢失这个能力。最后想说的是COCO 数据集虽然经典但在特定垂直域内直接套用会有些水土不服。如果是安防、医疗、工业质检等场景建议在 COCO 微调得到的权重基础上再收集 500~1000 条领域内标注做第二轮微调。从我的经验看这种两段式微调在小样本场景下效果比直接一步到位好很多因为 COCO 微调已经帮模型建立了一个“如何输出高质量描述”的先验。整个项目踩过不少坑但最值得记住的一点是2B 级别的多模态模型配合 LoRA在图像描述任务上完全能达到接近专用模型的精度而训练和部署成本都低一个量级。希望在评论区看到你们在类似场景下的实验结果尤其是用不同数据集微调后的评测对比细节。本文还有配套的精品资源点击获取
返回列表