多模态视觉语言模型

本文系统讲解多模态视觉语言模型的工程落地,回答 CLIP 与 VLM 怎么分工、视觉 token 怎么压缩、多模态 RAG 怎么搭等实战问题。覆盖视觉编码器与投影层结构、对比学习对齐、指令微调数据构造、视觉问答、多模态检索增强、幻觉成因与缓解、评估基准、以及显存与吞吐估算,并给出 CLIP 检索与显存估算两段可运行代码。

引言

传统视觉模型只能输出预定义类别的标签,而视觉语言模型(Vision-Language Model,VLM)能用自然语言回答问题、描述场景、按指令定位目标。这带来的工程变化是:视觉系统的「输出接口」从固定类别表变成了自由文本,需求变更不再需要重新标注与训练。

但落地 VLM 会遇到三类新问题。第一是成本:一张高分辨率图会被切成上千个视觉 token,显存与延迟远高于纯文本推理。第二是幻觉:模型会自信地描述图中不存在的东西,在医疗、工业等场景是硬伤。第三是评估:自由文本输出没有单一的准确率指标,需要构造任务化基准。

本文聚焦工程落地,讲清 VLM 的结构、训练、检索增强、幻觉治理与成本估算。CLIP 的对比学习原理、ViT 的注意力机制在 视觉 Transformer 与多模态模型 中已有铺垫,本文更侧重把模型变成可用系统。

目录

  1. VLM 的三段式结构与演进
  2. 视觉编码器的选择
  3. 投影层与视觉 token 压缩
  4. 对比学习与图文对齐
  5. 指令微调与数据构造
  6. 代码:CLIP 图文检索
  7. 视觉问答与对话式理解
  8. 多模态 RAG
  9. 幻觉成因与缓解
  10. 评估基准与指标
  11. 部署成本与显存估算
  12. 代码:显存与吞吐估算

1. VLM 的三段式结构与演进

几乎所有 VLM 都是「视觉编码器 + 连接模块 + 语言模型」三段式。演进主线是连接方式与训练策略的变化。

阶段代表连接方式特点
双塔CLIP、ALIGN各自编码后算相似度只做匹配,不能生成
查询压缩BLIP-2、FlamingoQ-Former 或交叉注意力冻结 LLM,只训连接层
投影对齐LLaVA、MiniGPT-4线性或 MLP 投影结构最简,需指令微调
原生多模态GPT-4V、Gemini、Qwen-VL早期融合,统一 token能力强,闭源或大参数

工程含义:查询压缩方案(BLIP-2)视觉 token 少、推理便宜,适合作为「图片描述器」;投影对齐方案(LLaVA)结构简单、易微调,是自研 VLM 的常见起点;原生多模态能力强但可控性差、成本高。

2. 视觉编码器的选择

视觉编码器决定模型「看得清什么」,选型主要看分辨率与训练数据。

  • CLIP ViT-L/14:336 或 448 输入,通用性强,是 LLaVA 系列的默认选择。
  • SigLIP:用 sigmoid 损失替代 softmax,对批次大小不敏感,训练更稳,近两年被大量 VLM 采用。
  • DINOv2:自监督训练,稠密特征质量高,适合需要精细定位的任务。
  • SAM 编码器:分割能力强,适合需要像素级理解的多模态任务。
  • EVA-CLIP:更大规模训练,特征更丰富。

分辨率是最关键的工程参数:224 输入只能看清大物体,OCR 与小目标需要 448 以上,或用「切片 + 拼接」(如 LLaVA-1.6 的 AnyRes)把大图切成若干子图分别编码。

# 视觉 token 数量随分辨率平方增长,这是显存的主要来源
def vision_tokens(image_size, patch=14, extra=1):
    return (image_size // patch) ** 2 + extra

for size in [224, 336, 448, 672]:
    print(size, "->", vision_tokens(size), "tokens")
# 224 -> 257, 336 -> 577, 448 -> 1025, 672 -> 2305

从上表可见,448 分辨率的一张图就产生 1025 个 token,相当于一篇千字文章。多图或多帧场景要乘以倍数。

3. 投影层与视觉 token 压缩

连接模块把视觉特征映射到语言模型的词嵌入空间,主流做法有三种:

  • 线性投影:一个 Linear 层,最简单,LLaVA 的做法。参数量极小,但需要指令微调来对齐。
  • MLP 投影:两层 MLP,表达能力更强,LLaVA-1.5 起采用。
  • Q-Former / Perceiver Resampler:用一组可学习的查询向量把 N 个视觉 token 压缩成固定的 M 个(如 32 个)。BLIP-2 用 32 个查询 token 压缩整张图,显存与延迟大幅下降。
  • 池化压缩:对视觉 token 做平均池化或注意力池化,简单粗暴但有效。

压缩是降低推理成本最直接的手段。从 576 个视觉 token 压到 64 个,预填充阶段的算力降近一个数量级,代价是细粒度信息(小字、细微纹理)丢失。工程上按任务定:图像描述可激进压缩,OCR 与图表理解必须保留高分辨率。

4. 对比学习与图文对齐

CLIP 用 4 亿图文对训练双塔:图像编码器与文本编码器输出归一化向量,用对称的 InfoNCE 损失让匹配对的余弦相似度高于不匹配对。批次内所有其他样本充当负样本。

工程上的几个关键事实:

  • 温度系数 τ 是可学习参数,控制分布的尖锐程度,影响训练稳定性。
  • 批次越大负样本越多,效果越好,但显存吃紧,因此常用梯度缓存扩大等效批次。
  • 零样本分类的精度对 prompt 措辞敏感,多模板 ensemble 通常提升 1 到 2 个点。
  • 对比学习学到的嵌入空间天然适合检索,这是多模态 RAG 的基础。

对齐质量的直观检验是「文本搜图」:用一句描述检索图库,看 Top-5 是否相关。若检索质量差,说明嵌入空间没对齐好,后续 VLM 的视觉理解也会受限。

5. 指令微调与数据构造

投影对齐后模型还不会「按指令回答」,需要指令微调(Instruction Tuning)。数据构造是关键,分两类:

  • 从标注数据模板化:把检测、分割、VQA 数据集转成对话格式。例如 COCO 的框标注转成「图中左上角的物体是什么」。成本低、可批量生成。
  • 模型生成 + 人工筛选:用强模型(GPT-4V)生成对话数据,人工抽检。质量高但成本高、有蒸馏风险。

训练策略上,常见三阶段:

  1. 冻结视觉编码器与 LLM,只训投影层,让视觉特征先对齐语言空间。
  2. 解冻 LLM(或加 LoRA),用混合指令数据微调。
  3. 任务特化微调,针对目标场景补数据。
# LLaVA 风格的两阶段微调配置示例
stage1 = dict(train_projector=True, train_llm=False, lr=1e-3, epochs=1)
stage2 = dict(train_projector=True, train_llm=True, lr=2e-5, epochs=1)
# 阶段一学习率大、只训投影层;阶段二学习率小、解冻 LLM
for name, cfg in [("align", stage1), ("instruct", stage2)]:
    print(name, cfg)

显存有限时,LLM 部分用 LoRA 或 QLoRA,把可训练参数压到 1% 以内,单卡也能微调 7B 级 VLM。

6. 代码:CLIP 图文检索

下面用 CLIP 建一个图文检索索引,这是多模态 RAG 的第一步。

import numpy as np
import torch
import open_clip
from PIL import Image

model, _, preprocess = open_clip.create_model_and_transforms(
    "ViT-B-32", pretrained="laion2b_s34b_b79k")
model.eval()
tokenizer = open_clip.get_tokenizer("ViT-B-32")

def encode_images(paths):
    with torch.inference_mode():
        batch = torch.stack([preprocess(Image.open(p).convert("RGB")) for p in paths])
        feat = model.encode_image(batch)
    return feat / feat.norm(dim=-1, keepdim=True)

def encode_text(texts):
    with torch.inference_mode():
        feat = model.encode_text(tokenizer(texts))
    return feat / feat.norm(dim=-1, keepdim=True)

gallery = encode_images(["a.jpg", "b.jpg", "c.jpg"])
query = encode_text(["a photo of a red car"])[0]
sims = (gallery @ query).tolist()
print("ranking:", sorted(enumerate(sims), key=lambda x: -x[1]))

检索时务必 L2 归一化,否则内积会被向量模长主导。图库规模上万后改用 FAISS 建索引,思路与 向量数据库选型 中一致。

7. 视觉问答与对话式理解

VQA(Visual Question Answering)是 VLM 最典型的任务:给一张图与一个问题,输出自然语言答案。工程上分两种形态:

  • 单轮问答:一问一答,无状态,易于批处理与缓存。
  • 多轮对话:保留历史,支持「它左边那个呢」这类指代。需要把历史消息与图像 token 一起构造输入。

多轮对话的坑在于图像 token 重复:如果每轮都把图像重新塞进上下文,token 数会随轮次线性增长,成本飙升。优化手段是缓存视觉 token 的 KV,或用「图像引用 + 摘要」替代重复图像。

# 多轮输入构造:图像 token 只放一次,后续轮次引用
def build_messages(question, history, image_token="<image>"):
    msgs = [{"role": "user", "content": f"{image_token}\n这张图里有什么?"}]
    msgs.append({"role": "assistant", "content": "图中是一张街道照片。"})
    for q, a in history:
        msgs += [{"role": "user", "content": q}, {"role": "assistant", "content": a}]
    msgs.append({"role": "user", "content": question})
    return msgs

print(build_messages("那辆车是什么颜色?", []))

结构化输出是另一类需求:不要自然语言,而要 JSON。做法是给 few-shot 示例加约束解码,或用模型的 JSON mode。工业场景几乎总要把输出转成结构化字段再进下游系统。

8. 多模态 RAG

多模态 RAG 把「检索」从纯文本扩展到图像与图文混合,用于「问一个关于图库或文档的问题」。

三种典型架构:

  • 文搜图 + VLM 回答:用 CLIP 检索相关图,再把图送 VLM 回答。适合图片素材库。
  • 图文混合索引:把文档页渲染成图,用 VLM 生成页面摘要,摘要进文本索引,命中后回取原图。适合图文混排的 PDF。
  • 多向量索引:ColPali 类方法把文档页切成 patch,每个 patch 一个向量,检索时对 patch 做后期交互(late interaction)。对复杂版式效果最好,代价是索引体积大。
import numpy as np

def late_interaction_score(query_patches, doc_patches):
    # ColBERT 风格:每个查询 patch 取与文档 patch 的最大相似度后求和
    sim = query_patches @ doc_patches.T          # (Q, D)
    return float(sim.max(axis=1).sum())

q = np.random.rand(32, 128).astype(np.float32)
d = np.random.rand(256, 128).astype(np.float32)
q /= np.linalg.norm(q, axis=1, keepdims=True)
d /= np.linalg.norm(d, axis=1, keepdims=True)
print("score:", round(late_interaction_score(q, d), 3))

多模态 RAG 的评估要分开看检索与生成:检索看 Recall@K,生成看答案准确率与引用正确性。只报生成指标会掩盖检索失败。

9. 幻觉成因与缓解

VLM 幻觉指模型描述图中不存在的内容。成因有三:

  • 语言先验过强:LLM 部分按「常见搭配」生成,如看到餐桌就写「有刀叉」,即使图里没有。
  • 视觉信息不足:低分辨率或 token 压缩过度,模型只能靠猜。
  • 训练数据偏差:指令数据中「是/否」比例失衡,模型倾向肯定回答。

缓解手段:

手段做法效果
提高分辨率用切片编码保留细节显著减少细节幻觉
减少压缩保留更多视觉 token有效但成本上升
约束解码要求引用图中区域提升可核查性
自一致性多次采样取一致答案有效但成本翻倍
外部工具接检测或 OCR 交叉验证工程最可靠
拒答训练数据中加入「图中没有」样本减少盲目肯定

工业场景最实用的组合是「VLM 出结果 + 小模型交叉验证」:让 VLM 描述,再用检测器或 OCR 验证关键事实,不一致就降级到人工。

10. 评估基准与指标

VLM 评估比传统视觉难得多,因为输出是自由文本。

基准任务指标
VQAv2视觉问答答案与人工答案的一致率
TextVQA图中文字问答精确匹配
GQA组合推理准确率
MMBench综合能力选择题准确率
MME感知与认知是/否准确率与得分
POPE幻觉是/否偏差
ChartQA图表理解宽松准确率

工程上更该自建领域基准:从真实业务里抽 200 到 500 个样本,人工标注标准答案,固定下来做回归测试。公开榜单反映的是通用能力,与你的场景相关性有限。

评估的两个陷阱:一是用强模型当裁判(LLM-as-Judge)有位置偏差与冗长偏好,需要随机交换答案顺序;二是样本量太小,几十个样本的准确率差异不显著。

11. 部署成本与显存估算

VLM 推理成本由三部分构成,量级差异很大:

部分显存/算力来源优化手段
视觉编码器图像分辨率与 patch 数降分辨率、切片复用
预填充视觉 token 数的平方token 压缩、KV 缓存复用
解码输出长度 × 参数量量化、投机解码、限制输出

估算显存的经验公式(推理,FP16):

显存 ≈ 参数量(B) × 2GB + KV_cache + 激活峰值
KV_cache ≈ 2 × layers × heads × head_dim × seq_len × batch × 2B

7B 模型 FP16 权重约 14GB,加 KV 与激活通常要 20GB 以上;INT4 量化后权重降到约 4GB,可在单张 24GB 卡上跑。视觉 token 让 seq_len 从几百涨到两三千,KV 缓存与预填充算力同步放大。

延迟上,预填充是算力受限、解码是带宽受限。视觉 token 多会显著拉长预填充,因此「先压缩视觉 token 再推理」往往比换更小的语言模型更有效。更多推理优化手段见 大模型推理优化 与 多模态模型部署 。

12. 代码:显存与吞吐估算

上线前先算一遍,避免买错卡。

def kv_cache_gb(layers=32, heads=32, head_dim=128, seq_len=2048, batch=1, dtype_bytes=2):
    # 2 表示 K 与 V 各一份
    return 2 * layers * heads * head_dim * seq_len * batch * dtype_bytes / 1e9

def weights_gb(params_b, dtype_bytes=2):
    return params_b * 1e9 * dtype_bytes / 1e9

def estimate(params_b=7, vision_tokens=1025, out_tokens=128, batch=1, quant=2):
    w = weights_gb(params_b, quant)
    prefill_kv = kv_cache_gb(seq_len=vision_tokens + 64, batch=batch, dtype_bytes=2)
    decode_kv = kv_cache_gb(seq_len=vision_tokens + out_tokens, batch=batch, dtype_bytes=2)
    total = w + max(prefill_kv, decode_kv) + 2.0     # 2GB 留给激活与框架
    return dict(weights=round(w, 1), kv=round(decode_kv, 2), total=round(total, 1))

print(estimate(7, 1025, 128, 1, quant=2))    # FP16
print(estimate(7, 1025, 128, 1, quant=0.5))  # INT4

按这个公式,7B VLM 在 1025 视觉 token 下 FP16 需要约 17 到 20GB,INT4 约 7 到 9GB。把视觉 token 压到 256 个,KV 部分能省一半以上。

权衡取舍

维度倾向代价
高分辨率与低成本OCR 用高分辨率token 数平方增长
开源与闭源可控与私有化用开源能力上限略低
全量微调与 LoRA显存紧用 LoRA能力上限略低
自然语言与结构化输出下游系统要结构化需约束解码或后处理
端到端 VLM 与级联小模型级联更可控更便宜工程链路更长
激进压缩与保真描述任务可压缩细节任务不能压

几条实用原则:

  • 先算显存与延迟再选模型,不要先选模型再想办法塞进去。
  • 视觉 token 是成本主因,压缩的收益通常大于换小模型。
  • 幻觉在关键场景必须靠外部工具交叉验证,不能只靠 prompt。
  • 自建领域基准比刷公开榜单更有价值,样本 200 条起。

常见坑清单

  • 图像 token 未归一化:CLIP 特征不归一化,相似度排序错乱。
  • 分辨率与 patch 不匹配:patch 14 需要尺寸为 14 的倍数,否则要 padding。
  • 多轮重复塞图:每轮重放图像 token,上下文线性膨胀,成本失控。
  • 忽略预填充瓶颈:只优化解码,视觉 token 导致预填充占了大头。
  • 用公开榜单代替领域评估:通用能力与业务效果相关性弱。
  • LLM 当裁判不换序:位置偏差导致结论不可靠。
  • 过度压缩视觉 token:OCR 与图表任务信息直接丢失。
  • 幻觉不设兜底:关键字段靠 VLM 直接输出,错误直接进业务系统。
  • 微调时冻结全部视觉编码器:领域差异大时视觉特征不匹配,需解冻后几层。
  • 数据构造全用强模型生成:有蒸馏与合规风险,需人工抽检。
  • 忘记输出长度限制:模型生成冗长描述,延迟与成本远超预期。
  • 显存估算漏掉 KV:按权重估卡,上线后并发一开就 OOM。

小结

多模态 VLM 工程的主线是:选视觉编码器(分辨率优先)→ 投影层对齐 → 指令微调 → 视觉 token 压缩控成本 → 检索增强补知识 → 交叉验证治幻觉 → 自建领域基准做回归。记住三个判断点:视觉 token 数是成本主因、幻觉必须靠外部工具兜底、评估要分检索与生成两段。

落地顺序建议先用 CLIP 类模型做检索与零样本分类,验证数据与场景可行性,再引入生成式 VLM 做问答。私有化部署优先选开源 7B 级模型加 LoRA 微调,配合 INT4 量化在单卡上跑通。当业务对结构化输出有硬要求时,把 VLM 定位成「理解器」,下游接规则或小模型做抽取,比让 VLM 直接输出结构化结果更稳。

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「计算机视觉」更多文章

  1. 检测与分割的评估指标
  2. 3D 视觉:点云与深度估计
  3. 视频理解与多目标跟踪