ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

用 SGLang benchmark/uno 复现 UNO 全量数学评测:run_math_eval 实战与源码解析

用 SGLang benchmark/uno 复现 UNO 全量数学评测:run_math_eval 实战与源码解析 用 SGLang benchmark/uno 复现 UNO 全量数学评测run_math_eval 实战与源码解析【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang本篇指南以 benchmark/uno/README.md 为核心完整讲解 SGLang 仓库中全量数学评测工具run_math_eval.py的用法与实现它如何在同一套数据集、提示词、采样参数与评分规则下公平对比自回归AR解码与 UNO、DFLASH、EAGLE、EAGLE3 等投机解码算法的数学准确率与吞吐指标TPF、tok/s。读完本文你将能够在自己的 H200 单卡环境上逐行复现 PR 中的评测表理解 UNO 线性/树两种模式的参数映射、TPF 统计口径以及 SGLang 侧 UNO 实现的约束边界。工具定位统一的投机解码数学评测框架benchmark/uno/run_math_eval.py的核心设计目标是在完全一致的条件下横向比较不同解码算法。根据 README 与 run_math_eval.py 的实现该评测框架具备以下特征统一评测口径AR、UNO、DFLASH、EAGLE、EAGLE3 使用相同的数据集、提示词、采样参数和评分器只通过--speculative-algorithm切换解码路径。进程内引擎创建进程内的sgl.Engine不启动独立 server 进程。从源码可见评测脚本在 _generate 中直接调用engine.generate(input_ids..., sampling_params..., rid...)结束后在finally中调用engine.shutdown()。计时边界明确引擎启动耗时不计入计时区间perf_counter()在sgl.Engine构造之后才启动并且不做任何额外的请求预热warmup。数据集固定版本下载固定 revisioncommit hash的 GSM8K、MATH-500、AIME 2024、AIME 2025、AIME 2026保证跨机器、跨时间可复现。统一提示与模板对所有引擎施加相同的\boxed{}作答指令与 Qwen reasoning 聊天模板。统一评分基于math_verify的 parse/verify 进行数学答案比对。环境准备与安装README 要求以可编辑模式安装带评测依赖的 SGLangpip install -e python[test][test]可选依赖中包含了评测运行所需的math_verify等库。math_grader.py 在导入math_verify失败时会优雅降级parse None、verify None以保证--help仍可用但真正执行评分时会抛出RuntimeError(math scoring requires the math_verify package)提示必须安装该包。数据集、提示词与模板math_data.py 深度解读数据集准备逻辑集中在 math_data.py。它定义了五个基准及其固定的 revision基准名数据集与 split固定 revision期望行数提示词构造gsm8kopenai/gsm8kmain, test740312add88f781978c0658806c59bc2815b98661319Q: {question}\nA: Lets think step by step.math500HuggingFaceH4/MATH-500test6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be500直接使用problem字段aime24hypaai/Hypa_AIME2024english11ab79f0eed5f4fdf3d469b466663ab86bbd77c830Question: {problem}\nAnswer:aime25math-ai/aime25test563bb8404243c5f09de6ec262f2db674fe5bce9b30Question: {problem}\nAnswer:aime26math-ai/aime26test79037aebdb6580008fb960d17cb21fd3099083e330Question: {problem}\nAnswer:所有基准共享同一条作答指令math_data.pyPlease reason step by step and put your final answer in \boxed{}.同时所有基准都使用chat_template_kwargs{reasoning_effort: high}调用 Qwen reasoning 聊天模板Qwen3 系列的 reasoning 模式。这条指令会以 system 消息形式注入若消息中已存在 system 消息则拼接到其前部见 _format_prompt。prepare_benchmark_data的缓存与校验机制值得一提数据以{benchmark}.jsonl落在--data-root下若文件已存在且行数与期望一致则直接复用否则重建行数不符会抛ValueError写入采用临时文件 replace的原子方式避免半成品污染缓存。复现 H200 评测表完整命令逐行解读README 的核心是可复现脚本。首先设置环境变量与公共参数均从仓库根目录执行export MODEL_PATHQwen/Qwen3-8B export TOKENIZER_PATHQwen/Qwen3-8B export UNO_LORA_PATHs-sahoo/uno-qwen3-8B export DATA_ROOT/path/to/math-eval-data export RESULT_ROOT/path/to/math-eval-results COMMON_ARGS( --model-path $MODEL_PATH --tokenizer-path $TOKENIZER_PATH --data-root $DATA_ROOT --context-length 40960 --max-tokens 32768 --temperature 1 --top-k 50 --top-p 0.95 --random-seed 42 )COMMON_ARGS中的数值正是 run_math_eval.py 的默认值CONTEXT_LENGTH 40960、MAX_TOKENS 2**15 32768以及采样默认值temperature1.0、top-k50、top-p0.95、random-seed42。PYTHONPATHpython前缀保证从仓库根目录能导入benchmark.uno包。定义三个启动函数AR 基线、UNO 线性模式、UNO 树模式。run_ar() { local benchmark$1 samples$2 requests$3 output_name$4 PYTHONPATHpython python -m benchmark.uno.run_math_eval \ ${COMMON_ARGS[]} \ --benchmark $benchmark \ --num-samples $samples \ --max-running-requests $requests \ --output-dir $RESULT_ROOT/$output_name } run_linear_uno() { local benchmark$1 samples$2 requests$3 output_name$4 PYTHONPATHpython python -m benchmark.uno.run_math_eval \ ${COMMON_ARGS[]} \ --benchmark $benchmark \ --num-samples $samples \ --max-running-requests $requests \ --output-dir $RESULT_ROOT/$output_name \ --speculative-algorithm UNO \ --uno-lora-path $UNO_LORA_PATH \ --speculative-num-steps 1 \ --speculative-eagle-topk 1 \ --speculative-num-draft-tokens 8 } run_tree_uno() { local benchmark$1 samples$2 requests$3 output_name$4 PYTHONPATHpython python -m benchmark.uno.run_math_eval \ ${COMMON_ARGS[]} \ --benchmark $benchmark \ --num-samples $samples \ --max-running-requests $requests \ --output-dir $RESULT_ROOT/$output_name \ --speculative-algorithm UNO \ --uno-lora-path $UNO_LORA_PATH \ --speculative-num-steps 15 \ --speculative-eagle-topk 32 \ --speculative-num-draft-tokens 32 }批次 64 的 AR 与 UNO 线性B/K/V 8/1/8六行GSM8K、MATH-500 每题 1 个样本AIME 2025 每题 10 个样本共 300 条 completionrun_ar gsm8k 1 64 ar-gsm8k-c64 run_linear_uno gsm8k 1 64 uno-linear-b8-k1-v8-gsm8k-c64 run_ar math500 1 64 ar-math500-c64 run_linear_uno math500 1 64 uno-linear-b8-k1-v8-math500-c64 run_ar aime25 10 64 ar-aime25-c64 run_linear_uno aime25 10 64 uno-linear-b8-k1-v8-aime25-c64批次 1 的 AR 与 UNO 树B/K/V 16/32/32六行run_ar gsm8k 1 1 ar-gsm8k-c1 run_tree_uno gsm8k 1 1 uno-tree-b16-k32-v32-gsm8k-c1 run_ar math500 1 1 ar-math500-c1 run_tree_uno math500 1 1 uno-tree-b16-k32-v32-math500-c1 run_ar aime25 10 1 ar-aime25-c1 run_tree_uno aime25 10 1 uno-tree-b16-k32-v32-aime25-c1注意 UNO 树模式的参数映射--speculative-num-steps 15意味着草稿前向宽度B 15 1 16--speculative-eagle-topk 32即树宽K 32--speculative-num-draft-tokens 32即验证宽度V 32详见下文B/K/V 参数映射。run_math_eval 全参数详解完整的命令行参数定义见 parse_args参数默认值说明--model-pathQwen/Qwen3-8B目标模型路径或 HF repo id--tokenizer-path缺省取--model-pathtokenizer 路径支持独立指定--revision无目标模型权重 revision--dtypebfloat16模型精度--attention-backendfa3注意力后端UNO 强制要求 fa3--data-root必填数据集缓存/下载目录--output-dir必填结果输出目录--benchmark全部五个可重复指定如--benchmark gsm8k --benchmark math500缺省跑全部--limit无每个基准最多执行的题目数--num-samples1每题采样次数AIME 表复现用 10--max-running-requests4引擎并发上限表复现用 64 或 1--context-length40960上下文长度--max-tokens32768每题最大生成 token 数--temperature1.0采样温度--top-k50top-k 采样--top-p0.95nucleus 采样--random-seed42随机种子--speculative-algorithm无EAGLE/EAGLE3/DFLASH/UNO自动转大写--speculative-draft-model-path无草稿模型路径UNO 禁止使用--speculative-draft-model-revision无草稿模型 revision--speculative-num-steps无草稿步数--speculative-eagle-topk无EAGLE 系候选数--speculative-num-draft-tokens无草稿/验证 token 数--speculative-dflash-block-size无DFLASH 专用验证窗口长度--speculative-draft-attention-backend无草稿注意力后端--uno-lora-path无UNO 专用草稿 LoRA 检查点路径参数校验_validate_argsnum_samples、max_running_requests、context_length、max_tokens、top_k必须为正数top_p必须落在(0, 1]temperature必须非负limit若指定必须为正。上下文预留context reserve_context_reserve是一个容易踩坑的细节投机解码的草稿/验证会额外占用上下文位置脚本会按算法预留DFLASH 预留2 * block_sizeUNO 树模式topk 1预留max(draft_tokens, steps1) 1其余按draft_tokens预留。随后逐条检查context_length - prompt_len - reserve max_tokens不满足即报错并提示increase--context-length。这解释了为什么表复现必须把 context length 开到 40960、max-tokens 开到 32768——既要容纳超长 reasoning 输出又要给投机窗口留出余量。运行流程与结果产物main 的执行管线为解析参数并校验加载 tokenizer使用transformers.AutoTokenizeruse_fastTrue、trust_remote_codeTrue准备提示词对每个基准下载/复用数据 → 逐行套用统一指令与 Qwen reasoning 模板渲染_format_prompt返回 token ids 与文本→ 按--num-samples复制出{source}:sample{i}的 prompt id构造引擎并生成_engine_options中设置了skip_tokenizer_initTruetokenizer 已由脚本预加载、log_levelinfo、max_running_requests并将所有投机相关选项原样透传给引擎run_math_eval.py_generate在引擎构造完成后才开始计时统计 TPF见下节写结果按基准分目录输出。每个基准的--output-dir/benchmark/下会生成四类文件文件内容generations.jsonl原始生成结果含output_ids、解码文本、token 数、num_forwards、tokens_per_forward、sglang_meta_infogrades.jsonl逐条评分后的结果含parsed_generations、correct、accuracyscores.json评分汇总num_rows、num_problems、accuracy、单样本的avg_at_1/pass_at_1多样本的pass_at_Nsummary.json/summary.md跨基准汇总summary.md的表格格式固定为run_math_eval.py| Dataset | Accuracy | TPF | tok/s | tok/s/request |末行Average的 Accuracy 与 TPF 是各数据集的无加权平均tok/s 是总输出 token 数除以计时生成秒数tok/s/request 再除以max_running_requests。summary.json则记录了完整元数据enginesglang-offline、mode、模型路径、投机参数、采样参数、generation_seconds、num_tokens、num_forwards、tokens_per_forward、unweighted_mean_tokens_per_forward、by_benchmark等并在进程结束前打印到 stdout。TPF 统计口径三种算法的差异TPFtokens per forward每次前向生成的 token 数是衡量投机解码效率的关键指标脚本在 _build_rows 中按算法区别统计AR 基线num_forwards len(token_ids)即每生成一个 token 记一次前向TPF 恒为 1UNOnum_forwards 2 * spec_verify_ct。因为 UNO 每个投机周期的两次前向都是完整的目标模型前向——扩散路径diffusion-pathway的草稿前向 AR 路径AR-pathway的验证前向两者各算一次EAGLE / EAGLE3 / DFLASHnum_forwards spec_verify_ct遵循 SGLang 的 acceptance-length 约定只统计目标模型验证前向草稿模型的前向不计入。spec_verify_ct来自引擎输出的meta_infoOpenAI 协议中对应的字段定义见 protocol.py。需要特别留意由于口径不同UNO 的 TPF 与 EAGLE/DFLASH 的 TPF不可直接数值对比只能在同一算法内部比较配置优劣。评分器实现math_grader.py评分模块 math_grader.py 自称Minimal math scorer adapted from Nano-vLLM-UNOs Eval360 grader。其核心处理链路答案抽取extract_last_boxed_content用正则 花括号配对深度扫描提取最后一个\boxed{...}/\fbox{...}的内容文本规范化normalize_answer_text做大量 LaTeX 清洗——提取 GSM8K 的####后答案、\dfrac/\tfrac归一为\frac、去除\left/\right、\mathbf、\text/\mathrm包装、\frac{a}{b}转a/b、去掉空白与千分位逗号等候选解析_parse_boxed_content优先交给math_verify.parse带$包裹尝试纯变量答案保留文本数字答案提取前导数字无 boxed 时走_parse_unboxed_answer的十余种自然语言模式The answer is ...、Final answer: ...、Therefore, the answer is ... 等最后兜底取最后一个句子的最后一个数字比对_compare_answers优先math_verify.verify(answer, gold)失败则再解析 gold 反向 verify文本型答案走_text_answers_match含浮点相等、(A)括号选项、向量分量比对。score_math同时输出多套口径avg_at_1/pass_at_1首样本以及多样本时的avg_at_N/pass_at_N任一采样正确即算通过。AIME 2025 的 10 采样配置正是通过num_samples10触发了后一套统计。评测其他投机解码器DFLASH 与 EAGLE/EAGLE3README 强调The runner uses the same public option names assglang serve即评测脚本与在线服务共享同一套投机参数命名结论可直接迁移到线上部署。DFLASH 示例草稿模型 block size 草稿注意力后端PYTHONPATHpython python -m benchmark.uno.run_math_eval \ ${COMMON_ARGS[]} \ --benchmark math500 \ --num-samples 1 \ --output-dir $RESULT_ROOT/dflash-b8-math500-c64 \ --max-running-requests 64 \ --speculative-algorithm DFLASH \ --speculative-draft-model-path z-lab/Qwen3-8B-DFlash-b16 \ --speculative-dflash-block-size 8 \ --speculative-draft-attention-backend fa3EAGLE / EAGLE3 示例export EAGLE_DRAFT_MODEL/path/to/compatible-eagle-draft-model PYTHONPATHpython python -m benchmark.uno.run_math_eval \ ${COMMON_ARGS[]} \ --benchmark math500 \ --num-samples 1 \ --output-dir $RESULT_ROOT/eagle3-b8-math500-c64 \ --max-running-requests 64 \ --speculative-algorithm EAGLE3 \ --speculative-draft-model-path $EAGLE_DRAFT_MODEL \ --speculative-num-steps 7 \ --speculative-eagle-topk 1 \ --speculative-num-draft-tokens 8EAGLE 与 DFLASH 的 TPF 遵循上文所述的 acceptance-length 约定。UNO 原理与源码印证单模型双前向架构SGLang 中的 UNO 实现是 UnoWorkerV2Single-model UNO worker with linear and native-EAGLE tree decode。与 EAGLE/DFLASH 需要加载独立草稿模型不同UNO复用目标 transformer 完成每个投机周期的两次前向草稿前向每个请求的第一行使用基础权重其余B - 1行使用训练好的 UNO LoRAdiffusion-pathway draft验证前向完全使用基础权重AR-pathway verification。因此 spec.py 中 UNO 的启动参数是--speculative-algorithm UNO--uno-lora-path如s-sahoo/uno-qwen3-8B而--speculative-draft-model-path会被显式拒绝。这也解释了为什么 UNO 的每次周期成本是两次完整目标模型前向——评测脚本中2 * spec_verify_ct的 TPF 口径正是对该架构的忠实刻画。B/K/V 参数映射UNO 的三种形态参数B/K/V含义为草稿前向宽度 / 每层扩展保留的候选数 / 验证宽度。命令行映射由 uno_worker_v2.py 与 speculative_hook.py 共同决定模式判定BKV线性Linear--speculative-eagle-topk ≤ 1--speculative-num-draft-tokens如 81steps/topk 被强制为 1--speculative-num-draft-tokens8树Tree--speculative-eagle-topk 1--speculative-num-steps 1如 15116--speculative-eagle-topk32--speculative-num-draft-tokens32线性模式构建并验证单条草稿链类似 DFLASH 的 proposal 布局树模式在每层草稿深度扩展多个候选并复用 SGLang 的 EAGLE 树验证路径native-EAGLE tree verification。注意 UNO 的K控制的是提议树宽度与请求采样参数top_k无关。启动期硬性约束_handle_uno 是 UNO 配置的守门员任何违规配置都会在启动期直接抛ValueError而不是拖到解码时才崩溃仅支持 CUDA且要求 prefill 与 decode 注意力后端均为FA3必须提供--uno-lora-path禁止--speculative-draft-model-path要求TPPP1不支持 DP attention 与上下文并行CP不支持确定性推理--enable-deterministic-inference、strict thinking依赖 grammar decoding、公共 Multi-LoRA 服务--uno-lora-path加载的是固定内部 adapter不使用--speculative-use-rejection-samplingUNO 自管随机验证树模式额外校验V ≥ B、V ≤ 128、V × K ≤ 2048、提议树容量与 EAGLE parent-list ABI 可表示性、两个接受阈值必须为 1.0、暂不支持 PDMux 与 two-batch overlap混合分块 prefillmixed chunked prefill会被自动禁用给出 warning 而非报错。以上约束在 speculative_decoding.mdx 的 Key requirements and limitations 一节亦有完整列举可作为部署前核对清单。测试验证仓库内的测试进一步印证了实现细节test_uno.py 是端到端 CUDA-graph 测试在Qwen/Qwen3-8Bs-sahoo/uno-qwen3-8B上同时覆盖线性与树两种模式用 32 token 的贪心前缀校验与 AR 解码的输出一致性PARITY_TOKENS 32并显式定义FORWARDS_PER_UNO_CYCLE 2——与 TPF 双前向口径完全对应test_uno_tree_config.py 验证了启动期校验确定性推理、strict thinking、非法树形配置均被拒绝另有 test_uno_request_validation.py、test_uno_lora_targets.py 覆盖请求级校验与 UNO LoRA 目标层校验不支持的 LoRA 目标层会在启动期被拒绝。常见问题与注意事项从仓库根目录运行命令均以PYTHONPATHpython python -m benchmark.uno.run_math_eval形式执行不要在benchmark/uno/目录内直接python run_math_eval.py。--data-root与--output-dir必须显式指定且应使用不同目录避免数据缓存与结果互相覆盖。上下文余量不足若某题的可用生成空间小于--max-tokens脚本会报错并提示增大--context-length投机解码会额外占用上下文见_context_reserve。TPF 跨算法不可直接比较UNO 计两次完整前向EAGLE/DFLASH 只计验证前向AR 恒为 1比较时应关注同一算法内的相对提升或同时参考 tok/s 与准确率。UNO 适配器必须与目标模型检查点精确匹配README 与官方文档均强调使用为特定 checkpoint 训练的 adapter当前已验证Qwen/Qwen3-8BLoRA 目标层不匹配会在启动期报错。评分依赖math_verify未安装时 CLI 帮助可用但评分会报错请使用pip install -e python[test]安装完整评测依赖。【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进