ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Diagram-MMU完整解读:科学图解多模态评测基准与实战

2026/8/31 1:31:37 拓冰建站 浏览量
Diagram-MMU完整解读:科学图解多模态评测基准与实战 第一篇博文想聊聊最近关注度很高的 Diagram-MMU 这个科学图解多模态评测基准。前阵子在给团队选型视觉语言模型VLM时我们最大的困扰不是模型效果不够好而是“好”这个结论到底怎么量化。常规 benchmark 刷分和真实业务里的科学图解理解场景差距很大直到 Diagram-MMU 出现才感觉有了一个更对口的测试集。接下来我会把它的设计思路、评测原理以及如何在自己的环境里跑通完整评测流程做一个完整的拆解。1. Diagram-MMU 是什么一个专注科学图解的视觉问答基准1.1 为什么需要一个新的多模态评测基准过去两年多模态大模型VLM的发展速度非常快从早期的图像描述、OCR 识别到现在的复杂图表推理、跨学科知识问答模型的视觉理解能力一直在升级。但评测体系却长期存在两个问题。第一个问题是“测不准”。很多公开榜单上的任务和真实科研、教育场景脱节。比如模型能识别一张自然照片里的猫能念出身份证上的文字但当你给它一张电子电路图问它“这个反馈网络属于什么类型”时它往往答非所问。自然图像理解和科学图解理解是两种完全不同的能力后者需要同时具备视觉结构解析、学科知识调用和逻辑推理能力。第二个问题是“测不全”。传统的 VQA视觉问答数据集大多是单学科、单题型涉及科学图解的部分也比较零散缺少一个覆盖多学科、多难度、多图解类型的系统性评测集。这导致开发者在模型选型时很难回答一个基本问题“这个模型在科学图表理解上到底处于什么水平”Diagram-MMU 正是为了解决这个问题而提出的。它是一个面向科学图解的多模态评测基准核心目标是考察视觉语言模型“理解和推理科学图解”的能力。1.2 Diagram-MMU 的核心设计思路从公开资料来看Diagram-MMU 在设计上有几个很鲜明的特点。第一个特点是题目来源真实。测试题不是人工凭空编造的而是来源于教科书、讲义、学术论文中的真实科学图解。这样做的好处是题目本身具备严谨性模型没法靠“背诵题库”来刷分。第二个特点是分学科、分难度。题目覆盖了物理、化学、数学、生物、计算机科学等多个学科难度上划分了高中、大学、研究生博士等不同等级。这种分层设计非常实用高中题目考的是基础图解阅读能力大学题目考的是专业知识调用博士题目则侧重前沿论文图表的理解。第三个特点是图解类型多样。科学图解不只是“图表”两个字能概括的它包含流程图、结构示意图、架构图、映射关系图、统计图等。不同类型的图解对模型的挑战并不一样。流程图考察的是时序逻辑理解架构图考察的是层次关系提取统计图考察的是数值与趋势判断。这三个特点合在一起让 Diagram-MMU 成为一个既考察“看没看清”又考察“懂没懂”的评测基准。1.3 与 MMMU、ScienceQA 等基准的定位差异很多读者之前接触过 MMMUMassive Multi-discipline Multimodal Understanding和 ScienceQA这里有必要做个区分。MMMU 是一个覆盖面很广的多模态学科理解基准包含了艺术、商科、科学等多个领域题目以大学级别为主。它的优势是“广”但科学图解只是其中一部分并不会针对图解类型做专门细化。ScienceQA 则是一个科学问答数据集题目以自然科学为主包含图文混合的问答形式。它更偏向知识问答图解本身的结构和推理深度相对有限。Diagram-MMU 的定位介于两者之间但它更聚焦“图解理解”这个能力维度。如果说 MMMU 是“百科知识考试”ScienceQA 是“科学课随堂测验”那么 Diagram-MMU 更像是一场“看图解题的专项能力测试”。维度Diagram-MMUMMMUScienceQA核心考察点科学图解理解与推理多学科综合理解科学知识问答学科覆盖物理、化学、数学、生物、计算机等艺术、商科、科学等 30 个学科自然科学为主难度分层高中 / 大学 / 研究生大学级别为主K-12 科学课程图解类型流程图、架构图、示意图等自然图像、图表混用图文混排为主适用场景科研教育类 VLM 选型评测通用 VLM 能力对比基础教育科学模型评测了解这层差异后你在做技术选型时就能更有针对性如果你的业务场景是教育题库、科研论文分析、工程图纸理解那么 Diagram-MMU 的参考价值会比通用 benchmark 更高。2. 评测原理与指标拆解2.1 任务定义多选形式的视觉问答Diagram-MMU 的任务形式是多项选择视觉问答。给定一张科学图解和一个问题模型需要从若干个候选项中选择正确答案。这种任务形式有几个好处。第一客观性更强。比起开放性问答多选题的评分标准非常明确答案非对即错减少了人工评分的主观偏差。第二可比性更强。不同模型在同一组题目上的准确率可以直接对比便于排行榜排序。第三更容易定位错误类型。通过统计模型在不同学科、不同难度、不同图解类型上的准确率可以反推模型的能力短板。从任务定义可以看出Diagram-MMU 本质上是一个多选题形式的视觉问答评测模型需要先理解图像内容再调用学科知识完成推理。2.2 常用评估指标准确率与部分正确率Diagram-MMU 使用的指标主要是 Accuracy准确率和 PPRPartial Point Rate部分正确率不过具体以官方最新说明为准。准确率的计算很简单就是模型预测正确的题数占总题数的比例。所有题目等权计算公式如下accuracy correct_count / total_countPPR 则是针对部分题目设计的细粒度评估。有些题目存在多个子问或者答案分多个要点如果模型只答对了一部分可以按比例给分。这类指标在多选题、复合题型中很有价值能反映模型“部分掌握”的情况。从工程角度看评测脚本里最重要的是把“模型输出”和“标准答案”做规范化对齐。很多模型会输出多余的解释文字直接进行字符串比较会浪费大量正确结果所以通常需要先抽取答案选项字母再做比对。2.3 按学科、难度、图解类型拆分评估单一总分只是一个粗略的参考真正有价值的是细粒度拆分。我建议在自己的评测脚本里把结果按照三个维度切分。按学科拆分可以知道模型在物理电路图、化学分子结构、生物流程图上的表现差异。按难度拆分可以观察模型是从高中阶段就开始掉点还是到了研究生级别才出现明显下滑。按图解类型拆分则能看出模型是流程图理解差还是架构图理解差。这三种拆分组合起来可以形成一张“模型能力热力图”对后续优化方向的指导意义远大于一个孤零零的总分。3. 环境准备与数据准备3.1 运行环境建议本节进入实操环节。先说明一点Diagram-MMU 的官方发布信息和训练/评测代码会持续更新以下示例以常见的多模态评测流程为基础重点演示评测思路实际运行时请以官方仓库为准。推荐环境如下操作系统LinuxUbuntu 20.04 及以上或 macOSPython 版本3.10 及以上主要依赖transformers、torch、openai、Pillow、pandas、openpyxl推理框架可以使用 Hugging Face Transformers也可以通过 OpenAI 兼容 API 调用远端模型建议先创建独立的虚拟环境避免依赖冲突conda create -n diagram_mmu python3.10 -y conda activate diagram_mmu pip install transformers torch openai pillow pandas openpyxl3.2 数据集获取与目录结构以官方发布为准通常数据集会包含图片文件和标注文件。标注文件常见为 JSON 或 JSONL 格式每条记录包含题目 ID、学科、难度、图解类型、问题文本、选项列表、标准答案和对应图片路径。建议把数据整理成如下目录结构diagram_mmu_eval/ ├── data/ │ ├── images/ │ │ ├── 00001.png │ │ ├── 00002.png │ │ └── ... │ └── annotations/ │ ├── dev.jsonl │ ├── test.jsonl │ └── ... ├── scripts/ │ ├── run_eval.py │ ├── score.py │ └── analysis.py └── results/ └── ...下面是一个典型的 JSONL 标注示例字段名为示例实际以官方格式为准{ id: diagram_mmu_00001, subject: physics, difficulty: undergraduate, diagram_type: circuit_diagram, question: 该电路中的反馈类型是什么, options: [A. 电压串联负反馈, B. 电压并联负反馈, C. 电流串联负反馈, D. 电流并联负反馈], answer: A, image: images/00001.png }拿到数据后先做一步数据完整性检查确认图片文件都能正常打开再进入评测流程。4. 动手实战跑通一次 Diagram-MMU 评测4.1 加载评测数据先把 JSONL 文件加载成 Python 对象列表。这里需要注意编码问题和缺失字段容错。# 文件路径scripts/load_data.py import json def load_jsonl(file_path): data [] with open(file_path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue try: record json.loads(line) data.append(record) except json.JSONDecodeError as e: print(f解析失败: {line}错误: {e}) return data if __name__ __main__: records load_jsonl(data/annotations/test.jsonl) print(f共加载 {len(records)} 条评测样本) print(records[0][question])这段代码做了基础容错解析失败的行会打印出来但不会中断整个流程。实际评测时我建议先单独跑通这条脚本确认数据没有问题再继续后续步骤。4.2 编写模型推理脚本模型推理是整个评测流程的核心。这里给出两种调用方式一种是调用 OpenAI 兼容接口适合远端模型另一种是基于 Hugging Face Transformers适合本地模型。方式一OpenAI 兼容 API假设后端模型支持gpt-4o或qwen-vl这类多模态接口图片通常以 base64 编码后随请求发送。# 文件路径scripts/vlm_api_infer.py import base64 import os from openai import OpenAI client OpenAI( base_urlos.getenv(VLM_BASE_URL, http://localhost:8000/v1), api_keyos.getenv(VLM_API_KEY, EMPTY), ) def image_to_base64(image_path: str) - str: with open(image_path, rb) as f: return base64.b64encode(f.read()).decode(utf-8) def run_vlm(question, options, image_path, modelgpt-4o): prompt ( 请根据图片内容回答下面的科学图解选择题。\n f问题{question}\n f选项{ .join(options)}\n 请直接输出一个选项字母如 A、B、C、D不要输出额外解释。 ) img_b64 image_to_base64(image_path) response client.chat.completions.create( modelmodel, messages[ { role: user, content: [ {type: text, text: prompt}, { type: image_url, image_url: { url: fdata:image/png;base64,{img_b64} }, }, ], } ], temperature0, ) return response.choices[0].message.content.strip()这里使用temperature0是为了最大程度保证输出的确定性减少随机性对评测结果的影响。如果你使用本地 vLLM 服务也可以通过 OpenAI 兼容协议直接对接。方式二Hugging Face Transformers 本地推理本地模型的调用方式略有差异不同模型的对话模板和图像处理方法不同。下面是一个最小示例思路# 文件路径scripts/vlm_hf_infer.py from transformers import AutoProcessor, AutoModelForCausalLM from PIL import Image model_id your-vlm-model-id processor AutoProcessor.from_pretrained(model_id) model AutoModelForCausalLM.from_pretrained( model_id, device_mapauto, torch_dtypeauto, ) def run_vlm_hf(question, options, image_path): image Image.open(image_path).convert(RGB) prompt ( 请根据图片内容回答下面的科学图解选择题。\n f问题{question}\n f选项{ .join(options)}\n 请直接输出一个选项字母如 A、B、C、D。 ) inputs processor( textprompt, imagesimage, return_tensorspt, ).to(model.device) output model.generate( **inputs, max_new_tokens32, do_sampleFalse, ) generated processor.decode(output[0], skip_special_tokensTrue) return generated[len(prompt):].strip()不同的模型处理器在参数细节上可能有差异需要按实际模型调整。这里演示的是通用流程。4.3 批量评测与结果缓存评测数据集通常有上千条样本为了防止中途断网或进程异常导致前功尽弃强烈建议引入结果缓存机制。每推理完一条就立即写入结果文件。# 文件路径scripts/run_eval.py import json import os from load_data import load_jsonl from vlm_api_infer import run_vlm def load_done_ids(result_path): done_ids set() if os.path.exists(result_path): with open(result_path, r, encodingutf-8) as f: for line in f: record json.loads(line) done_ids.add(record[id]) return done_ids def main(): data_path data/annotations/test.jsonl result_path results/predictions.jsonl model_name gpt-4o records load_jsonl(data_path) done_ids load_done_ids(result_path) os.makedirs(results, exist_okTrue) with open(result_path, a, encodingutf-8) as out_f: for idx, record in enumerate(records): if record[id] in done_ids: continue image_path os.path.join(data, record[image]) prediction run_vlm( record[question], record[options], image_path, modelmodel_name, ) out_f.write(json.dumps({ id: record[id], subject: record[subject], difficulty: record[difficulty], diagram_type: record[diagram_type], ground_truth: record[answer], prediction: prediction, }, ensure_asciiFalse) \n) out_f.flush() if (idx 1) % 50 0: print(f已完成 {idx 1} / {len(records)} 条) if __name__ __main__: main()这种“边推理边写文件”的方式可以在进程中断后从断点继续跑不需要重新推理已完成的部分。4.4 结果评分与规范化匹配模型输出可能包含各种格式比如“答案是 A”“我认为是 B”“选 C”等。因此评分前必须做输出规范化。# 文件路径scripts/score.py import re import json def normalize_answer(text): 从模型输出中抽取选项字母。 if not text: return text text.strip() # 直接命中的情况输出为 A、A.、A) 等 m re.match(r^[A-D], text, flagsre.IGNORECASE) if m: return m.group(0).upper() # 从“答案是 A”这类句子中抽取 m re.search(r答案(?:是|为)?[:]?\s*[(]?([A-D])[)]?, text) if m: return m.group(1).upper() # 从“选 C”这类句子中抽取 m re.search(r选\s*([A-D]), text) if m: return m.group(1).upper() return def calc_accuracy(results): correct 0 total len(results) for item in results: pred normalize_answer(item[prediction]) gt item[ground_truth].strip().upper() if pred gt: correct 1 return correct / total if total else 0 if __name__ __main__: results [] with open(results/predictions.jsonl, r, encodingutf-8) as f: for line in f: if line.strip(): results.append(json.loads(line)) acc calc_accuracy(results) print(f样本总数: {len(results)}) print(f整体准确率: {acc:.4f})normalize_answer函数里做了三层匹配先处理最简单的情况再处理中英文混合句子最后兜底提取“选 X”的表达。这种做法可以显著减少因输出格式导致的误判。4.5 细粒度分析按学科和难度拆分整体准确率只是第一步下面给出按学科和难度拆分的分析脚本。# 文件路径scripts/analysis.py import json from collections import defaultdict from score import calc_accuracy, normalize_answer def analyze(results): metrics defaultdict(lambda: {correct: 0, total: 0}) for item in results: pred normalize_answer(item[prediction]) gt item[ground_truth].strip().upper() key item[subject] metrics[key][total] 1 if pred gt: metrics[key][correct] 1 for key, value in metrics.items(): acc value[correct] / value[total] if value[total] else 0 print(f{key}: {value[correct]}/{value[total]} {acc:.4f}) if __name__ __main__: results [] with open(results/predictions.jsonl, r, encodingutf-8) as f: for line in f: if line.strip(): results.append(json.loads(line)) print( 分学科准确率 ) analyze(results)类似的逻辑可以扩展到难度、图解类型维度。把这些维度组合起来就能找出模型具体的薄弱环节。5. 常见问题与排查思路在跑 Diagram-MMU 评测时我踩过一些坑这里整理成排查清单供大家参考。问题现象常见原因解决思路图片加载失败图片路径拼错或文件损坏在推理前用PIL统一验证图片是否可打开模型输出为空远端服务超时或本地显存不足调大超时时间、降低并发、检查显存占用准确率异常低输出规范化不完整模型回答被误判检查normalize_answer是否能覆盖常见输出格式部分学科样本为 0数据集字段名与脚本不匹配先打印一条样本核对字段映射同一模型多次评测结果不一致temperature未设为 0 或后端有随机采样统一设置采样参数关闭随机性评测中断后重复推理没有结果缓存或断点续跑逻辑采用逐条写入 JSONL 的缓存机制内存占用过高批量加载过多图片改为单条流式处理不要一次性把所有图片读入内存这里特别强调图片加载问题。前期我遇到过图片路径包含相对路径前缀的情况直接用os.path.join(data, record[image])处理时假如record[image]本身已经含有images/前缀就会重复拼接。建议先打印一条完整路径确认再大规模运行。另外一个容易忽视的问题是大规模评测的成本。如果调用远端 API上千张图片的推理费用和对端并发限制都需提前评估。建议先随机抽 100 条做小规模验证确认整体流程没问题后再跑全量数据。6. 提升模型在 Diagram-MMU 上表现的最佳实践6.1 数据层面构建高质量微调集如果目标是提升自己模型在 Diagram-MMU 上的表现首要手段是构建高质量的科学图解指令微调集。建议从教科书、公开课程、论文配图中收集图文问答对覆盖不同类型的图解并注意与评测集隔离避免数据泄露。在扩充数据时可以采用“题目改写”策略保留原图对问题做同义改写或者对选项顺序做扰动。这样可以增加数据多样性降低模型对固定选项顺序的依赖。同时要保证答案的准确性任何标注错误都会直接污染模型能力。6.2 模型层面选择合适的底座与输入分辨率多模态模型的图像编码器分辨率直接影响科学图解的识别效果。很多模型默认会把图片缩放到固定尺寸而科学图解中常常有细小的文字、符号和图例缩放后信息丢失严重。训练或推理时如果模型支持高分辨率输入建议优先开启。从模型选型角度看科学图解理解强的模型通常具备两个特征一是视觉编码器参数量大、分辨率高二是语言模型部分有较强的逻辑推理能力。实际选型时可以先用 Diagram-MMU 的上百条子集快速筛选再做全量评测。6.3 提示词层面让模型先看结构再作答推理时的提示词设计对结果有明显影响。对于科学图解类题目可以引导模型分步骤思考先描述图中的关键结构和元素再结合问题做推理最后给出答案。请按以下步骤回答科学图解选择题 1. 简要描述图片中的核心结构或流程。 2. 找出与问题直接相关的关键信息。 3. 结合学科知识分析每个选项。 4. 最后单独一行输出你的答案字母。需要提醒的是这种“思维链”式提示会增加输出长度和推理耗时。如果评测目的是对比模型能力建议对不同模型使用统一提示词保证公平性如果目的是挖掘模型极限性能则可以为每个模型单独优化提示词。6.4 评测工程化建立可复现的评测流水线评测工作不只是跑一条脚本建议搭建可复现的评测流水线。具体包括固定模型版本和推理参数记录环境依赖清单。使用结果缓存和断点续跑机制支持大规模评测。每次评测后生成细粒度分析报告沉淀到版本管理中。对模型输出做抽样人工复核防止自动化评分掩盖语义问题。这样做的好处是当模型版本更新时可以快速重跑同一套评测观察能力变化。7. 写在最后的几点实践建议评测多模态模型的科学图解能力不能只盯着一张“排行榜单”看。通过 Diagram-MMU 这类细粒度 benchmark可以透视模型在不同学科、不同难度、不同图解类型上的真实表现这才是评测的核心价值。如果接下来你想上手实践我建议顺序是先下载一个开源 VLM 跑通推理脚本再用 100 条样本验证评分逻辑最后再全量评测。这套流程跑通之后你会发现后续换模型、调参数都变得非常顺畅。如果你在跑评测时遇到其他奇怪的问题也欢迎在评论区交流我们一起把这份评测经验补完整。