SGLang MMMU 基准评测指南:从 VLM 服务部署到结果解析与性能剖析
【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang
MMMU(Massive Multi-discipline Multimodal Understanding and Reasoning)是评测视觉语言模型(VLM)跨学科多模态理解与推理能力的权威基准,涵盖艺术、商业、科学、医学、人文社科与工程技术六大领域共 30 个学科。本文以 SGLang 仓库中的 benchmark/mmmu/README.md 为骨架,完整讲解如何基于 SGLang 服务框架托管 VLM 并在 MMMU validation 集上执行评测,同时结合仓库内 bench_sglang.py、eval_utils.py 等源码,深入解析评测流程、答案提取正则、LoRA 适配器、采样参数注入以及性能剖析等实战细节。读完本文,你将掌握一套可复现、可扩展、可深挖底层原理的 MMMU 评测方案。
一、评测脚本总览
benchmark/mmmu/目录下的文件构成了完整的评测工具链:
| 文件 | 作用 |
|---|---|
| bench_sglang.py | 通过 OpenAI 兼容 API 对 SGLang 托管的 VLM 发起评测请求 |
| bench_hf.py | 基于 Hugging Face Transformers 直接离线评测同一数据集 |
| data_utils.py | 数据集加载、学科分类映射、prompt 构建与结果保存 |
| eval_utils.py | 评测参数定义、答案解析(选择题/开放题)与准确率统计 |
| prompt_format.yaml | MMMU 的默认 prompt 模板配置(任务指令、题型格式、温度) |
其中data_utils.py定义了完整的学科体系:CAT_SHORT2LONG将 30 个学科缩写(如acc、cs、math)映射为全名,DOMAIN_CAT2SUB_CAT又将 30 个学科归并到 Art and Design、Business、Science、Health and Medicine、Humanities and Social Science、Tech and Engineering 六个领域。最终输出会按学科与领域分别统计准确率,形成类似官方报告的分层结果。
二、用 SGLang 托管 VLM:快速起步
2.1 启动推理服务
首先启动一个 SGLang VLM 服务端。以 Qwen2-VL-7B-Instruct 为例:
python -m sglang.launch_server --model-path Qwen/Qwen2-VL-7B-Instruct --port 30000这里--model-path既可以是 Hugging Face 仓库 ID,也可以是本地权重目录;--port指定 OpenAI 兼容 API 的监听端口,bench_sglang.py会默认向http://127.0.0.1:{port}/v1发起chat.completions请求。
2.2 降低显存占用
MMMU 评测会逐张加载测试图片,输入长度较大,官方 README 明确建议追加--mem-fraction-static参数来控制静态显存占比:
python -m sglang.launch_server --model-path Qwen/Qwen2-VL-7B-Instruct --port 30000 --mem-fraction-static 0.6该参数限制了 KV cache 等静态内存池可使用的显存比例,值越小越保守,适合与多模态模型或显存吃紧的场景配合使用,能有效避免服务启动阶段 OOM。bench_sglang.py会从数据集逐题并行准备图片并保存到~/.cache/mmmu/images/,图片解码也会占用显存,因此显存余量不足时务必调低该值。
2.3 启动评测
服务就绪后,在仓库根目录执行:
python benchmark/mmmu/bench_sglang.py --port 30000 --concurrency 16--concurrency控制并发发送的 OpenAI 请求数。源码中通过asyncio.Semaphore(args.concurrency)限制同时 in-flight 的请求量,并发数越高吞吐越大,但需要服务端有足够max-running-requests与显存支撑。--model参数(默认"default")用于指定 API 请求体中的model字段,多模型部署在同一服务时可用它区分。
2.4 评测输出与结果文件
运行结束后脚本会打印Benchmark time,并写出两个 JSON 文件(默认写在当前工作目录):
./answer_sglang.json:逐题记录pred_ans(解析后的预测答案)、original_response(模型原始回复)、ground_truth(标准答案)与question_type;./val_sglang.json:按 30 个学科、6 大领域及 Overall 汇总的准确率与样本数。
这两个路径分别由脚本内的args.output_path = "./answer_sglang.json"与eval_result(..., eval_output_path="./val_sglang.json")决定,也可通过--result-filename覆盖。
三、关键评测参数详解
除--port、--concurrency外,bench_sglang.py通过 eval_utils.py 中的EvalArgs暴露了一批高价值参数。下表汇总了默认值、含义与源码出处:
| 参数 | 默认值 | 说明 |
|---|---|---|
--seed | 1 | 随机种子,用于可复现的数据处理与随机兜底选答案 |
--split | validation | 数据集划分,官方评测通常用 validation |
--dataset-path | MMMU/MMMU | Hugging Face 数据集路径,可替换为本地镜像 |
--prompt-format-file | prompt_format.yaml | 自定义 prompt 模板 YAML 路径 |
--result-filename | ./val_sglang.json | 评测结果输出路径 |
--image-pixels-limit | -1 | 超过该像素数(宽×高)的图片直接跳过,-1 表示不限制 |
--max-new-tokens | None | 每个样本的最大生成长度,经max_completion_tokens传入请求体 |
--temperature | None | 采样温度,仅在显式指定时覆盖默认值(YAML 中默认为 0) |
--response-answer-regex | (?s)(.*) | 从原始回复中提取答案的正则,捕获组即答案 |
--lora-path | None | 评测时使用的 LoRA 适配器名称,随每个请求以lora_path字段发送 |
--reasoning-effort | None | 推理模型(如 GLM-4.5V)的推理强度,取值none/high |
--extra-request-body | None | 以 JSON 字符串形式向每个请求体追加任意生成参数 |
--profile | False | 是否开启服务端 profile(需配合start_profile/stop_profile接口) |
--profile-number | 5 | profile 模式下只评测前 N 个样本 |
3.1 采样参数合并逻辑
get_sampling_params()展示了参数合并的优先级:先解析--extra-request-body中的 JSON 作为基底,再叠加--max-new-tokens(映射为max_completion_tokens)与--temperature。也就是说,--extra-request-body提供的是"额外生成参数"的通用注入通道,适合一次性传多个参数:
python3 bench_sglang.py --extra-request-body '{"max_new_tokens": 128, "temperature": 0.01}'3.2 自定义答案提取正则
MMMU 许多题目要求模型输出形如Answer: A的结论。--response-answer-regex允许你用正则从模型原始输出中截取最终答案片段,捕获组group(1)会被strip()后送入解析器。官方示例针对 GLM-4.1V 的 box 格式:
python3 -m sglang.launch_server --model-path zai-org/GLM-4.1V-9B-Thinking --reasoning-parser glm45 python3 bench_sglang.py --response-answer-regex "<\|begin_of_box\|>(.*)<\|end_of_box\|>" --concurrency 64注意:--response-answer-regex只决定"提取哪一段作为模型答案",后续选择题解析(parse_multi_choice_response)仍会从该片段中进一步寻找A/B/C/D字母。
四、LoRA 适配器评测
当需要验证 LoRA 微调后的视觉模型效果时,分两步走。
第一步:服务端加载 LoRA。使用--lora-paths以名称=路径的键值对形式注册适配器(多个适配器用逗号分隔),同时按需追加--disable-radix-cache避免前缀缓存干扰:
# Launch server with LoRA enabled python -m sglang.launch_server --model-path microsoft/Phi-4-multimodal-instruct --port 30000 --trust-remote-code --disable-radix-cache --lora-paths vision=<LoRA path>第二步:评测时指定适配器。--lora-path vision传入的是注册名而非磁盘路径:
# Apply LoRA adapter during inferencing python -m benchmark/mmmu/bench_sglang.py --concurrency 8 --lora-path vision从源码看,process_sample()会把{"lora_path": lora_path}放入extra_body,随每个 OpenAI 请求发送,从而实现"同一服务、动态切换适配器"的批量评测。
五、评测流程的源码级拆解
5.1 样本准备阶段
prepare_samples()的工作分四步:加载prompt_format.yaml并展开列表项 → 用ThreadPoolExecutor并行从MMMU/MMMU加载 30 个学科子集并concatenate_datasets合并 → 并行处理每个样本(process_single_sample抽取题目/选项/答案/图片,construct_prompt按题型套用模板)→ 按final_input_prompt排序保证顺序稳定。
construct_prompt()展示了两种题型模板的实际拼装:
- 选择题使用
multi_choice_example_format,将选项格式化为(A) ...、(B) ...并在末尾追加指令Answer with the option's letter from the given choices directly.; - 开放题使用
short_ans_example_format,指令为Answer the question using a single word or phrase.。
这些模板定义在 prompt_format.yaml 中,task_instructions默认为空字符串,temperature默认为 0。
5.2 请求构造与并发控制
process_sample()将 prompt 按<和>拆成 prefix 与 suffix,图片则按 MIME 类型转成data:image/png;base64,...内联到image_url,最终拼成 OpenAI 多模态消息格式:
messages: [ {role: "user", content: [ {type: "text", text: prefix}, {type: "image_url", image_url: {url: image_url}}, {type: "text", text: suffix}, ]} ]并发大于 1 时,脚本用asyncio.Semaphore包裹每个样本的请求任务并通过asyncio.as_completed驱动;并发等于 1 时则退化为顺序执行,保证请求顺序与样本顺序一致——这正是 profile 场景下官方推荐--concurrency 1的原因(见下文 profiling 一节)。
5.3 答案解析与打分
process_result()按题型分流:选择题调用parse_multi_choice_response(),开放题则直接以原始回复作为pred_ans(真正的开放题归一化发生在最终打分阶段)。
选择题解析器parse_multi_choice_response()的判定优先级从源码可以清晰看出:
- 优先匹配显式结论模式(
_EXPLICIT_ANSWER_PATTERNS):如answer: X、Final answer: X、独立成行的(X)、LaTeX 的\boxed{X}、the answer is X,取所有匹配中位置最靠后的一个; - 依次在回复中寻找
(A)/(B)括号形式、A空格形式; - 长度超过 5 个词时尝试匹配选项内容文本;
- 全部失败则随机选一个字母兜底。
最终打分eval_result()会按 30 个学科分别调用evaluate(),再用calculate_ins_level_acc()按样本数加权汇总出六个领域的 Overall 与全局 Overall 准确率,结果通过pprint打印并写入val_sglang.json。
六、用 Hugging Face 基线对比
为了与 HF Transformers 参考实现做公平对比(例如验证 SGLang 服务化推理与原生 PyTorch 的精度一致性),仓库提供了离线评测脚本:
python benchmark/mmmu/bench_hf.py --model-path Qwen/Qwen2-VL-7B-Instructbench_hf.py的关键行为:
- 优先尝试
AutoModelForImageTextToText加载;失败则回退到AutoModel.from_pretrained,其中 InternVL 系列走sglang.srt.multimodal.internvl_utils.image_to_pixel_values做 448×448 分块与缩略图预处理; - 支持
--limit N只评测前 N 个样本,便于快速冒烟验证; - 使用
GenerationConfig(max_new_tokens=..., do_sample=False)贪心解码,温度固定为 0; - 结果输出为
{model_path}_answer_hf.json与{model_path}_val_hf.json,格式与 SGLang 版本一致,可直接对比。
需要说明的是:HF 脚本与 SGLang 脚本共用同一套EvalArgs与样本准备逻辑,因此两者的差异仅来自推理后端本身,对比结果具有较强说服力。
七、MMMU 评测下的性能剖析(Profiling)
当需要定位 SGLang 服务在 MMMU 负载下的性能瓶颈(如多模态编码器耗时、prefill 阶段 kernel 开销)时,可以使用--profile模式:
python3 bench_sglang.py --profile --profile-number 5 --concurrency 1官方 README 明确建议:若开启 profile 选项,请遵循 docs/docs/developer_guide/benchmark_and_profiling.mdx 中的标准剖析说明,并推荐使用--concurrency 1以保证一致性,让剖析与调试更简单。
其原理在源码中清晰可见:--profile开启后,脚本会先调用服务端的/start_profile接口启动 SGLang 内置剖析器,随后只评测前--profile-number(默认 5)个样本,最后调用/stop_profile结束采样。剖析期间使用串行模式(--concurrency 1)可以避免并发请求互相抢占 GPU 导致的时间线互相污染,从而得到干净、可归因的 kernel 耗时数据。剖析产出的 trace 可配合 PyTorch Profiler、Nsight Systems 等工具进一步分析,详见仓库中的官方 profiling 文档。
八、完整实战流程总结
一个端到端的 MMMU 评测流程可以归纳为四步:
- 准备数据:脚本会自动从 Hugging Face 加载
MMMU/MMMU的 validation 划分,并把处理后的图片缓存到~/.cache/mmmu/images/(首次运行需要下载,耗时较长;可通过--dataset-path指向已镜像的数据集加速); - 启动服务:
python -m sglang.launch_server --model-path <VLM> --port 30000,显存紧张时追加--mem-fraction-static 0.6,需要 LoRA 时追加--lora-paths <name>=<path>; - 执行评测:
python benchmark/mmmu/bench_sglang.py --port 30000 --concurrency <N>,按需叠加--response-answer-regex、--extra-request-body、--lora-path等参数; - 阅读结果:查看控制台打印的分层准确率,以及
./answer_sglang.json(逐题明细)与./val_sglang.json(汇总统计)两个文件;需要对照基线时运行bench_hf.py生成 HF 版结果。
如果还需要复现官方论文式的严谨结论,建议固定--seed保证数据顺序与随机兜底行为可复现,并保持 SGLang 服务端与评测脚本版本一致后再横向对比不同模型的 MMMU 分数。
【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考