
最近做多模态模型效果评估时我遇到一个很别扭的场景某个图像描述模型在一个公开测试集上拿到了不错的 CIDEr 分数但把生成结果放大看会发现它大量输出 “a photo of a person standing on the street” 这类安全、通顺、永远不出错的套话。它没有描述人物动作、没有指出关键物体、没有提到场景中的视觉焦点。问题在哪里不是模型不会说英语而是它压根没有认真“看”这张图。这就是当前图像描述image captioning评估的尴尬我们用一个总分去衡量模型但这个总分同时混进了两种完全不同的能力——模型是否真的理解图像内容以及模型是否能把理解到的内容组织成高质量的自然语言。前者是眼睛的问题后者是嘴巴的问题。把它们混在一起打分等于把“没看懂但特别会说”和“看懂了但表达不清”这两种完全相反的失败模式折叠成了同一个数字。分数一旦失去诊断能力评测对迭代的指导价值就大打折扣。CAPEval 这个工作强调的关键词是 Decoupled也就是解耦。它把 caption 评估拆成两条独立的线一条评估 Understanding理解一条评估 Generation生成。这篇博客我会从评估痛点讲起拆解 CAPEval 为什么选择解耦并给出一个可运行的参考实现帮助你理解两个维度分别怎么算、怎么解读、怎么接入自己的测评 pipeline。读完你会收获的不是又一个“更聪明的总分”而是一套能帮你定位模型短板的评估思路。1. 为什么 caption 评估需要“解耦”先看一个真实开发场景。你在负责一个电商平台的商品图文生成功能模型根据商品图片生成描述文案。你希望模型既准确识别商品种类、颜色、材质、品牌标识又能写出读起来自然、有吸引力的营销文案。这两个目标本质上分属两个能力域。第一个能力是视觉理解。模型必须从像素层面认出“这是一双红色运动鞋”“鞋面是网面材质”“鞋底有品牌 logo”。如果这个环节出错后面的文案再漂亮也是错的甚至会产生幻觉比如把黑色鞋说成白色鞋。第二个能力是语言生成。模型即使准确理解了图片仍然可能写出重复啰嗦、语法混乱、句式单一的句子或者虽然句子完整但风格不符合电商文案的要求。传统评估指标并不会帮你区分这两种失败。比如 BLEU、ROUGE、CIDEr 这类基于参考句 n-gram 重叠的指标核心逻辑是“生成句子和人工参考句长得像不像”。问题是“像不像”同时受语义准确和语言风格影响。一个模型只要擅长生成常见句式即使漏掉图片中的关键实体也可能因为和参考句共享了大量高频词而拿到不错分数。这就是所谓“安全描述”问题。模型发现“a photo of”“there is a”“a man is” 这类开头在参考句中出现频率极高于是生成时不断复用这些安全句式。CIDEr 的 TF-IDF 加权虽然能降低常用词的权重但无法从根本上解决“句子通顺但内容空泛”的问题。再往后看CLIPScore 这类指标在视觉语义一致性上做了明显改进。它用一个预训练的图文匹配模型直接计算生成 caption 和图像在语义空间的相似度。它的进步在于不再依赖参考句但输出仍然是一个综合分。如果一张图同时有“狗”“公园”“飞盘”三个关键元素CLIPScore 只能告诉你这张图的 caption 和图像整体像不像不能告诉你模型到底漏掉了哪个元素。当评估结果只有一个总分时算法工程师很难决定下一步优化方向。到底是加强视觉编码器还是改进语言解码器是扩充训练数据里的实体覆盖还是调 prompt 让生成更稳定没有维度层面的信号就只能靠猜。CAPEval 的“解耦”正是冲着这个痛点来的先把评估目标拆成理解和生成两个子问题再分别用合适的工具去测最后输出两个可解释的分数。2. CAPEval 的核心原理理解与生成分开测CAPEval 这个名字可以拆成 CAP Eval核心动作是 Caption Evaluation。从标题里 Decoupled across Understanding and Generation 这个表述来看它的核心主张是评估一个 caption 时至少要从两个正交的维度去打分。先定义清楚两个维度。Understanding 维度考察的是“模型是否看清了图像”。这里的“看清”不只包括物体存在性还包括属性、数量、空间关系、动作甚至事件。比如一张图里有一只黑猫在白色沙发上那么“黑猫”“白沙发”“猫在沙发上”这三个信息点都是理解层面应该覆盖的内容。如果 caption 写的是“一只猫坐在家具上”虽然不能说完全错误但它漏掉了颜色和具体家具类型理解精度明显不足生成质量再流畅也不能掩盖这个缺陷。Generation 维度考察的是“模型是否把信息表达好了”。这里的“表达好”包括语法正确性、是否自然连贯、是否符合任务要求的语言风格、是否有不必要的重复。一个 caption 即使理解了图像里的全部关键信息如果写成 “cat black is sitting sofa on white the”那也是不可接受的生成结果。反过来一个句子非常优美但关键对象全说错的 caption更是生成能力无法弥补的。下面这个表格可以帮助快速对比两个维度的差异评估维度核心问题典型失败案例典型优化方向Understanding模型是否准确描述了图像中的关键实体、属性、关系、事件漏掉主体把“红车”说成“蓝车”“狗在追球”说成“狗和球在一起”加强视觉编码器扩充细粒度训练数据增加检测/定位监督Generation模型是否用通顺、自然、符合要求的语言表达了内容语法错误句式重复过度使用套话风格不符合任务要求改进解码策略指令微调引入风格约束使用更高质量的语言训练数据为什么说这两个维度要分开评估而不是合并成一个加权分原因在于它们对应不同的模型组件和不同的错误来源。视觉理解层面的错误大概率来自视觉编码器、跨模态对齐模块或者训练数据中的视觉覆盖不足语言生成层面的错误则更可能来自语言解码器、解码超参数或者指令遵循能力。工业界的模型迭代通常是按模块进行的你不知道错在哪一层就无法决定是重新训练视觉部分还是调整生成策略。还有一个容易被忽略的点理解能力和生成能力并不一定是正相关的。多模态大模型领域中经常能看到两种“偏科”模型。一种是视觉能力很强但生成时词汇贫乏、句式僵硬另一种是语言模型能力很强视觉编码器相对较弱于是非常擅长“脑补”生成出来的句子读起来滴水不漏但内容跟图像只有弱相关。如果你只用一个总分评测这两种模型的得分可能差不多但它们的迭代路径完全不同。CAPEval 这种解耦设计本质上提供的是两份独立的能力体检报告。理解维度内部还可以继续拆。比如判断一个 caption 是否覆盖了图像的关键视觉元素可以进一步区分实体层面的召回属性层面的召回关系层面的召回。这种拆分对一个成熟的评测体系来说很有价值因为它能回答更细的问题模型是不是只认识常见物体遇到颜色和材质就忽略模型是不是看不出空间关系从工程角度看维度拆得越细定位问题越准。CAPEval 至少先把理解和生成这两大维度拆开已经是很大的进步。3. 从 n-gram 到 CLIPScoreCAPEval 解决了什么为了说明 CAPEval 在技术演进中的位置有必要回顾一下 caption 评估指标的发展脉络。这不是为了怀旧而是因为很多对 CAPEval 的误解来自对既有指标能力边界的模糊认知。第一代指标是 n-gram 重叠类指标代表是 BLEU、ROUGE 和 CIDEr。BLEU 最早用于机器翻译通过统计候选句子和参考句子的 n-gram 精确匹配来计算分数ROUGE 更多强调召回早期用于自动摘要CIDEr 在图像描述评测中非常流行它用 TF-IDF 对 n-gram 加权降低常见词的重要性。这类指标的优点是计算快、无需额外模型缺点是过度依赖参考句的词汇形式语义泛化能力弱。两个句子意思完全一致只是换了一批同义词重叠率就会明显下降而一个包含严重语义错误但词汇相近的句子反而可能拿高分。第二代指标引入了场景图匹配代表是 SPICE。SPICE 把 caption 和参考句分别解析成场景图场景图里包含物体、属性和关系三类信息然后计算两个场景图的 F 分数。这个思路本质上已经触及“理解”维度因为它比较的是结构化语义而不是字面词汇。但 SPICE 的瓶颈在于依赖现成的场景图解析器解析错误会直接传导到最终分数而且它仍然需要参考句。第三代指标以 CLIPScore 为代表它直接计算 caption 和图像在联合语义空间中的相似度。因为不再需要参考句它天然适合开放域评估对“图像中有什么”的一致性判断明显更强。但 CLIPScore 的问题前面提过它是一个整体相似度分数无法提供细粒度的诊断信号。你只能知道“不太像”却不知道是漏掉了对象还是错误理解了关系还是只是表述不够清晰。有了这个脉络CAPEval 的定位就很清楚了。它不是一个单纯用来替代 CLIPScore 的新相似度函数而是一个评估框架。框架的意思是它会把旧的、新的指标放到合适的位置上理解维度可以使用场景图匹配、目标检测召回、VQA 问答正确率等措施生成维度可以使用语言流畅度模型、BERTScore、perplexity 等措施。最后分别汇总而不是强行揉成一个值。指标/方法是否需要参考句评估重点主要局限BLEU / ROUGE / CIDEr是生成句与参考句的词面重叠度语义泛化弱容易被安全套话刷分SPICE是场景图级别的语义匹配依赖解析器质量错误会传导CLIPScore否caption 与图像的全局语义相似度无法区分理解错误与生成错误CAPEval 思路按子任务决定理解与生成两个独立维度需要分别设计子评估器成本更高从这个演进可以看到评估维度从“词面”走向“语义”从“全局相似”走向“结构化诊断”。CAPEval 的 decoupled 设计正是顺应这个趋势把两个被长期混在一起的因素彻底分开。这也是为什么我说理解 CAPEval 的关键不是记住某个公式而是理解它改变了“评估对象”的粒度。4. 环境准备与演示项目结构这一节开始进入实操部分。我这里给出的参考实现目的是把 CAPEval 的解耦思路用代码展示出来方便你理解两个维度的计算逻辑。它不是 CAPEval 的官方 SDK。如果论文公开了官方实现请以官方代码为准本文代码的价值在于思路演示你可以在此基础上替换成更合适的评估模型。先看环境准备。一个基础版本至少需要 Python 3.8 及以上版本依赖包括 PyTorch、Transformers、Pillow 等。如果你想使用 BERTScore 做生成维度的语义相似度计算还需要安装 bert-score 库。以下是一个参考 requirements.txttorch2.0.0 transformers4.30.0 pillow10.0.0 bert-score0.3.13 sentence-transformers2.2.0安装方式就是常规的 pip 安装pip install -r requirements.txt如果你的机器有 NVIDIA GPU建议安装对应版本的 CUDA 版 PyTorch如果只有 CPU也可以运行演示代码只是速度会慢一些。项目结构可以参考下面这样保持简单清晰capeval_demo/ ├── capeval_demo.py ├── requirements.txt └── images/ └── sample.jpg这篇文章的示例不会依赖 images 目录因为核心代码只需要 caption 字符串和关键元素列表就能跑通。如果你想在线测试图片输入可以提前准备一张示例图片并在代码中填写本地路径。在实际工程中环境准备通常还要考虑一个问题评估用的模型大小。如果只是快速验证思路完全可以使用轻量模型比如用规则匹配代替检测模型用预训练语言模型的 perplexity 代替大模型打分。如果要做严谨的评测实验再接入大模型或专门的视觉语言模型。CAPEval 的价值在于评估框架而不是绑定某一个具体模型所以你的环境选择非常灵活。5. 参考实现Understanding 与 Generation 评估器现在来看核心实现。我先给出一段完整可运行的 Python 脚本它包含两个独立评估器一个用于理解维度一个用于生成维度。# 文件路径capeval_demo/capeval_demo.py CAPEval 参考实现演示用 功能将图像描述评估拆分成 Understanding 分数和 Generation 分数。 注意这是为展示解耦思路而写的简化实现不是官方 SDK。 import argparse from typing import List, Optional def evaluate_understanding(key_elements: List[str], caption: str) - dict: 理解评估判断 caption 是否覆盖了图像的关键视觉要素。 简化实现用字符串包含关系判断关键元素是否出现。 实际项目可以替换为 1. 目标检测模型输出的关键物体 2. VQA 模型对“图中是否有 X”的回答 3. 多模态大模型给出的视觉证据判断。 caption_lower caption.lower() hit_elements [elem for elem in key_elements if elem.lower() in caption_lower] recall len(hit_elements) / len(key_elements) if key_elements else 0.0 # 这里精确率用一个直观口径命中元素数量 / caption 分词数量 # 实际项目中更推荐用“预测的关键元素中正确比例”来计算 token_count len(caption.split()) precision len(hit_elements) / token_count if token_count 0 else 0.0 f1 2 * precision * recall / (precision recall) if (precision recall) 0 else 0.0 return { key_elements: key_elements, hit_elements: hit_elements, recall: round(recall, 4), precision: round(precision, 4), f1: round(f1, 4), } def evaluate_generation(caption: str, reference_caption: Optional[str] None) - dict: 生成评估评估生成句子的流畅度与基础语言质量。 简化实现用句子长度和参考句词重叠模拟语言质量。 实际项目可以替换为 1. 语言模型 perplexity 2. BERTScore 与参考句的语义相似度 3. GPT/多模态大模型的多维打分。 word_count len(caption.split()) # 用长度映射一个基础流畅分过短或过长都会扣分 length_score min(1.0, word_count / 20.0) if reference_caption: ref_words set(reference_caption.lower().split()) cap_words set(caption.lower().split()) overlap len(ref_words cap_words) / len(ref_words) if ref_words else 0.0 fluency_score 0.7 * length_score 0.3 * overlap else: fluency_score length_score return { word_count: word_count, length_score: round(length_score, 4), fluency_score: round(fluency_score, 4), } def main(): parser argparse.ArgumentParser(descriptionCAPEval reference demo) parser.add_argument(--caption, typestr, defaultA red bus is running on a snowy street.) parser.add_argument(--reference, typestr, default) parser.add_argument( --key-elements, nargs*, default[red bus, snow, street], help图像关键视觉元素例如red bus snow street, ) args parser.parse_args() understanding evaluate_understanding(args.key_elements, args.caption) generation evaluate_generation(args.caption, args.reference or None) print(Understanding:, understanding) print(Generation:, generation) if __name__ __main__: main()这段脚本虽然简单但已经把 CAPEval 的框架感表达出来了。两个评估函数彼此独立输入和输出完全解耦。你可以在不修改另一个函数的情况下升级任意一个维度的评估器。比如把 evaluate_understanding 里的字符串匹配替换成多模态大模型判断或者把 evaluate_generation 里的规则打分替换成 BERTScore都不会影响整体结构。如果你想在理解维度引入更强的视觉信号可以考虑使用 Transformers 的 VQA pipeline。下面是一段可以用在理解评估中的参考代码# 可选的视觉问答评估代码理解维度增强版 # 使用 Hugging Face Transformers 加载 VQA 模型 from transformers import pipeline vqa_pipeline pipeline( visual-question-answering, modeldandelin/ViLT-B32-finetuned-VQA ) def ask_visual_question(image_path: str, question: str) - str: result vqa_pipeline(image_path, question, top_k1) return result[0][answer] if result else 使用这个函数时你可以针对每个关键元素构造一个问题比如“Does the image contain a red bus?”。如果模型回答 yes就认为该关键元素被理解如果回答 no就认为漏掉或识别错误。这种方式的优点是每个元素都有独立的判定依据比字符串匹配可靠得多。生成维度如果要做得更严谨可以使用 BERTScore 来评估生成句和参考句之间的语义相似度# 可选的生成质量评估代码生成维度增强版 from bert_score import BERTScorer scorer BERTScorer(langen, rescale_with_baselineTrue) def compute_bert_score(caption: str, reference: str) - dict: P, R, F1 scorer.score([caption], [reference]) return { bert_precision: P.item(), bert_recall: R.item(), bert_f1: F1.item(), }这里需要说明BERTScore 本质上衡量的是生成句和参考句的语义相似度它更偏向“生成”维度因为它不直接检查图像内容。如果你没有参考句可以用一个语言模型计算 perplexityperplexity 越低通常意味着句子越自然。但要注意perplexity 低不代表内容正确一个训练集里常见的套话也可能有很低的 perplexity。这正是 CAPEval 主张把维度分开的另一个原因每个维度都有自己的强项和盲区分开评估才能看清楚。6. 运行结果与效果验证先运行最小示例cd capeval_demo python capeval_demo.py \ --caption A red bus is running on a snowy street. \ --key-elements red bus snow street预期输出如下Understanding: {key_elements: [red bus, snow, street], hit_elements: [red bus, snow, street], recall: 1.0, precision: 0.2727, f1: 0.4286} Generation: {word_count: 8, length_score: 0.4, fluency_score: 0.4}这个输出结果非常有信息量。理解维度的 recall 是 1.0说明三个关键视觉元素全部出现但 precision 偏低因为 caption 里还有其他词被简化公式视为“预测噪声”。在实际应用中precision 的定义需要根据你的评估目标重新设计。如果目标是“尽可能完整描述图片”recall 优先级更高如果目标是“不要描述图片里不存在的东西”precision 优先级更高。CAPEval 不替你定义业务目标但它把选择权还给了你。然后看 generation 分数。fluency_score 为 0.4主要是因为演示代码里用长度映射流畅度这句话 8 个词按规则只得了 0.4 分。真实场景中请替换成更合理的语言模型评估器这里的分数数值本身没有绝对意义核心价值是呈现两个独立维度的输出格式。当你在一个测试集上批量跑完所有样本后可以把 Understanding 分数和 Generation 分数画成散点图。你会看到四种典型的模型行为分布第一类是高理解、高生成。这是理想情况模型既看懂了图像又能写出自然句子。第二类是高理解、低生成。说明视觉编码器没问题问题出在语言生成模块可以优先优化解码策略或做指令微调。第三类是低理解、高生成。这是最容易被传统指标误导的情况模型很会说但没看懂图需要优先加强视觉理解能力。第四类是低理解、低生成双短板需要从数据集、预训练任务和模型结构整体排查。如果你发现大量样本集中在第三类那么传统 n-gram 指标很可能给出了虚高的分数。这个场景最能体现 CAPEval 解耦评估的价值高生成分数掩盖了低理解水平你的模型可能正在用流利的废话欺骗评测系统。现在两个分数分开这种偏科模型立刻暴露。7. 常见问题与排查思路在实际使用 CAPEval 思路搭建评估体系时会遇到不少工程问题。我整理了几个最容易踩坑的点。问题现象可能原因排查方式解决方案理解分数普遍偏低关键元素列表太长或颗粒度太细抽样查看未命中元素是否真的是图像核心内容合理控制关键元素数量聚焦图像显著内容生成分数虚高使用了套话友好的语言模型或规则人工抽检高分样本看是否有内容空洞问题换用更严格的语言模型评估器或增加多维打分VQA 模型加载失败网络问题或模型仓库名称不对查看 Transformers 报错信息确认模型是否存在更换可用模型或使用本地权重显存不足评估模型过大、批量评估批次太大查看 GPU 显存占用降低 batch size使用半精度或改用 CPU没有参考 caption任务本身是开放域生成评估生成维度时跳过参考句指标使用无参考指标如 perplexity、LLM 打分图片数据涉及隐私评估数据集包含敏感人脸、医疗或业务数据检查数据合规边界在授权范围内使用脱敏后评估避免上传到外部模型第一类问题在实际操作中非常常见。关键元素列表从哪里来可以来自人工标注可以来自目标检测模型也可以来自多模态大模型的自动抽取。如果列表太长模型几乎不可能全部覆盖recall 会普遍偏低这个分数就失去区分度。更稳妥的做法是先对图像做显著物体筛选每张图只保留 3 到 7 个对语义最关键的元素而不是把所有检测框都塞进评估流程。第二类问题值得多说两句。生成维度如果只是测句子通顺度很多“流利废话”会拿到高分。比如 “A person is looking at something in the image” 这句话语法完全正确但作为图像描述信息量极低。如果单独看 generation 维度它可能是合格的问题在于 understanding 维度没能识别出这是低信息量描述。所以建议在生成维度引入“信息量”或“与图像相关性”的约束而不是只看流利度。还有一个常见误解很多人以为 CAPEval 一定要用大模型做 judge。其实不一定。如果评估数据规模很大跑大模型成本很高你可以先用轻量模型做粗筛再用大模型对边界样本做精评。这种两阶段评估思路在工程上更可行。8. 最佳实践与工程建议把 CAPEval 的思路落到实际项目我建议遵循下面几个原则。第一个原则是分开报告不要急着合并。即使业务方只想要一个分你在内部也应该至少保留 Understanding 和 Generation 两个分数的存档。合并动作可以发生但一定要发生在下一次迭代开始之前而不是评估结束之后。两个分数分开记录长期积累下来的数据会非常有价值。第二个原则是理解维度的关键元素抽取要稳定。如果下周评估时换了另一套关键元素抽取模型分数波动可能不是因为模型变好或变差而是因为评估口径变了。建议固定一套关键元素抽取方案或者在同一版本内完成对比实验。同时每次评估记录关键元素抽取器的版本方便回溯。第三个原则是生成维度要避免“单指标崇拜”。一个流畅度指标不足以评估生成质量建议组合使用多个指标比如流利度、相关度、风格一致性、信息量。使用 LLM 打分时提示词里要求模型给出判断依据并引用对应视觉证据能明显减少无依据的主观打分。第四个原则是评估集要有针对性。如果你关注的是细粒度视觉理解评测集里应该包含大量颜色、材质、数量、空间关系等案例如果你关注的是生成多样性评测集里应该设计同图多次生成的任务。CAPEval 的解耦框架不会自动帮你提升模型但它能帮你找到模型在哪类样本上偏科。第五个原则是注意数据安全和合规边界。评估时如果用到外部大模型 API要确保图像数据没有隐私风险。涉及人脸、车牌、医疗影像等敏感信息时建议使用本地模型或在授权环境下运行。安全边界不是评估框架本身的问题但评估体系建设时必须一起考虑。第六个原则是引入本体约束。这是与最近热门的 oagOntology-Augmented Generation方向很自然的结合点。理解评估如果只依赖自由文本抽取关键元素很难保证覆盖所有重要语义关系。引入一个领域本体把关键实体、属性、关系组织成结构化规范理解评估的粒度就会更清晰。例如在一个体育场景评估集中本体可以明确定义“运动员”“球”“裁判”是实体“在……旁边”“正在追赶”是关系。模型生成的 caption 是否覆盖这些结构化元素可以直接映射到评估分数上。这会让 CAPEval 在垂直领域的落地更可控也更接近工业级评测的需求。9. 总结与后续学习方向CAPEval 值得关注的地方不在于它又提出了一个更复杂的分数而在于它用一个简单有力的动作改变了评测视角把“图像理解”和“文本生成”从总分里拆开。这种解耦让评测结果重新具备诊断能力。模型分数高你能知道它到底强在哪里模型分数低你能知道它该优化哪里。如果你准备在自己的项目里尝试我建议先不要追求完整复现论文里的所有细节而是先复现本文第三节的演示代码把 Understanding 和 Generation 两个分数的输出格式跑通。然后逐步替换其中的简化逻辑理解维度换成 VQA 或目标检测模型生成维度换成 BERTScore 或语言模型评分。跑通之后再在评测集上做统计分析和人工抽检。接下来值得深入的方向包括关键视觉元素的结构化抽取、领域本体的构建和使用、LLM 作为评估器时的偏置控制、以及多语言图像描述评估。尤其是 oag 方向它与 CAPEval 的结合点非常自然用本体规范理解评估的结构用 CAPEval 的解耦框架约束评估的维度。这可能是下一步图像描述评估落地到垂直行业时会频繁遇到的组合。最后提醒一句任何自动评估指标都不能完全替代人工判断。CAPEval 的价值是帮你高效圈定可疑样本、快速定位模型短板但在发布模型或做重要决策之前抽检人工评估这一关不应该省掉。把 CAPEval 当作评估体系中的诊断工具比把它当作一个最终的真理分数更有意义。