news 2026/9/10 1:07:22

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 等基准的定位差异

很多读者之前接触过 MMMU(Massive 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(准确率)和 PPR(Partial Point Rate,部分正确率),不过具体以官方最新说明为准。

准确率的计算很简单,就是模型预测正确的题数占总题数的比例。所有题目等权计算,公式如下:

accuracy = correct_count / total_count

PPR 则是针对部分题目设计的细粒度评估。有些题目存在多个子问,或者答案分多个要点,如果模型只答对了一部分,可以按比例给分。这类指标在多选题、复合题型中很有价值,能反映模型“部分掌握”的情况。

从工程角度看,评测脚本里最重要的是把“模型输出”和“标准答案”做规范化对齐。很多模型会输出多余的解释文字,直接进行字符串比较会浪费大量正确结果,所以通常需要先抽取答案选项字母,再做比对。

2.3 按学科、难度、图解类型拆分评估

单一总分只是一个粗略的参考,真正有价值的是细粒度拆分。我建议在自己的评测脚本里,把结果按照三个维度切分。

按学科拆分,可以知道模型在物理电路图、化学分子结构、生物流程图上的表现差异。按难度拆分,可以观察模型是从高中阶段就开始掉点,还是到了研究生级别才出现明显下滑。按图解类型拆分,则能看出模型是流程图理解差,还是架构图理解差。

这三种拆分组合起来,可以形成一张“模型能力热力图”,对后续优化方向的指导意义远大于一个孤零零的总分。

3. 环境准备与数据准备

3.1 运行环境建议

本节进入实操环节。先说明一点:Diagram-MMU 的官方发布信息和训练/评测代码会持续更新,以下示例以常见的多模态评测流程为基础,重点演示评测思路,实际运行时请以官方仓库为准。

推荐环境如下:

  • 操作系统:Linux(Ubuntu 20.04 及以上)或 macOS
  • Python 版本:3.10 及以上
  • 主要依赖:transformerstorchopenaiPillowpandasopenpyxl
  • 推理框架:可以使用 Hugging Face Transformers,也可以通过 OpenAI 兼容 API 调用远端模型

建议先创建独立的虚拟环境,避免依赖冲突:

conda create -n diagram_mmu python=3.10 -y conda activate diagram_mmu pip install transformers torch openai pillow pandas openpyxl

3.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", encoding="utf-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-4oqwen-vl这类多模态接口,图片通常以 base64 编码后随请求发送。

# 文件路径:scripts/vlm_api_infer.py import base64 import os from openai import OpenAI client = OpenAI( base_url=os.getenv("VLM_BASE_URL", "http://localhost:8000/v1"), api_key=os.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, model="gpt-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( model=model, messages=[ { "role": "user", "content": [ {"type": "text", "text": prompt}, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{img_b64}" }, }, ], } ], temperature=0, ) return response.choices[0].message.content.strip()

这里使用temperature=0是为了最大程度保证输出的确定性,减少随机性对评测结果的影响。如果你使用本地 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_map="auto", torch_dtype="auto", ) 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( text=prompt, images=image, return_tensors="pt", ).to(model.device) output = model.generate( **inputs, max_new_tokens=32, do_sample=False, ) generated = processor.decode(output[0], skip_special_tokens=True) 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", encoding="utf-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_ok=True) with open(result_path, "a", encoding="utf-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, model=model_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_ascii=False) + "\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, flags=re.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", encoding="utf-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", encoding="utf-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 条样本验证评分逻辑,最后再全量评测。这套流程跑通之后,你会发现后续换模型、调参数都变得非常顺畅。如果你在跑评测时遇到其他奇怪的问题,也欢迎在评论区交流,我们一起把这份评测经验补完整。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 15:28:59

鸿蒙ArkTS仿小红书类毕业设计:社交笔记+电商商城+Web后台完整项目

毕业设计选题又撞了?如果你今年还在纠结“做一个简单商城”或者“仿一个社区 App”,这个基于鸿蒙系统的小红书类项目,完全可以换一个方向。它不是普通的前端静态页面,而是使用 ArkTS 原生开发的应用端,同时包含社交笔记…

作者头像 李华
网站建设 2026/9/5 11:35:55

兜底代码与固定控制:游戏技能状态机的正确修复姿势

最近组里复盘一个线上战斗问题,有人半开玩笑地抛出一句话:把0.1秒风的兜底代码,改成固定控制1秒不就行了吗?这样所有Bug都看上去解决了,多数玩家不会察觉到的。这句话说完之后会议室安静了几秒。因为大家心里都清楚&am…

作者头像 李华
网站建设 2026/9/5 11:35:50

京东Android笔试复盘:算法、机制与性能优化全攻略

前阵子整理旧硬盘,翻出一份当年京东2019春招Android开发类岗位的笔试记录。说实话,看到文件名的瞬间,很多画面就回来了——那时候我还在为第一份大厂Offer刷题,凌晨两点对着Activity启动模式画思维导图,第二天爬起来继…

作者头像 李华
网站建设 2026/9/5 15:28:31

Cocos Creator 3D微信小游戏跑酷Demo源码全解析

简介:这是一份基于CocosCreator3D v1.0.0开发的微信小游戏完整源码,聚焦3D跑酷闯关玩法,适用于计算机相关专业学生及初级开发者开展实战训练、课程设计或毕业设计。项目已通过真机测试,包含7个可递进挑战的关卡逻辑、角色移动与障…

作者头像 李华
网站建设 2026/9/5 15:26:45

Python零基础入门:先跑通第一个脚本,别让教程吃灰

收藏夹里躺着几百集的Python零基础教程,标题写着全平台最细、一周学完、学不会退出IT界,但你点开视频的次数可能不超过三次。这不是意志力的问题,而是学习路径里的一个关键环节没有打通:你始终没有完成一次“写代码 → 看到报错 →…

作者头像 李华
网站建设 2026/9/5 15:24:10

贝壳找房2023校招算法卷2复盘:KMP、动态规划与业务场景全解析

最近帮朋友复盘贝壳找房2023届校招算法卷2,正好手头还留着当时的笔记和部分题目回忆,整理了一篇完整拆解。这份卷子整体难度在中上水平,既有经典的算法题,也有一些跟业务场景结合得很紧的题目,涵盖的考点比较全&#x…

作者头像 李华