- 大模型
- 推理模型
- 微调
- 模型推理服务
【免费下载链接】s1
s1: Simple test-time scaling
导读
本文面向需要在 s1 测试时缩放(test-time scaling)项目环境中复现 GSM8K 数学推理性能对比的开发者。文章以 eval/rebase/sglang/benchmark/gsm8k/README.md 为主线,完整继承其数据下载与 SGLang、vLLM、LightLLM、Guidance、LMQL 五种后端的基准测试操作步骤,并结合同目录下的 bench_sglang.py 与 bench_other.py 源码,深入讲解 few-shot 提示构造、答案数值抽取、准确率计算与结果落盘机制。读完本文,你将能够独立搭建并运行一套可复现的 GSM8K 多后端推理基准,并理解每条命令背后的实现原理。
基准测试目录结构
该基准位于仓库的 sglang 分支目录下:
eval/rebase/sglang/benchmark/gsm8k/ ├── README.md # 操作指南(本文主体) ├── bench_sglang.py # SGLang 专用客户端(使用 SGL 结构化生成语言) └── bench_other.py # 多后端通用客户端(vllm / lightllm / guidance / lmql / srt-raw)两个客户端脚本与 README 同目录存放,其中bench_sglang.py面向 SGLang 运行时(SRT),bench_other.py面向其余四种外部后端,二者共享同一套 few-shot 构造与答案抽取逻辑,保证各后端在完全相同的输入与评分标准下进行对比。仓库中benchmark/目录下还有 mmlu、hellaswag、multi_chain_reasoning 等同类基准(benchmark 目录),GSM8K 是其中面向数学应用题评测的代表用例。
第一步:下载 GSM8K 测试数据
README 提供了直接获取 OpenAI GSM8K 官方测试集的命令:
wget https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl下载得到的test.jsonl为 JSONL(每行一个 JSON 对象)格式,每一行至少包含两个字段:
question:小学应用题题干(自然语言描述 + 数学问题);answer:包含完整推导与最终数值的参考答案,格式形如"#### 25"。
该文件路径随后被两个客户端脚本通过--data-path参数引用(默认值即test.jsonl,见 bench_sglang.py 与 bench_other.py)。数据读取由read_jsonl完成,该工具位于 python/sglang/utils.py,逐行解析 JSON 并跳过以#开头的注释行。
第二步:构建 few-shot 提示与答案标签
在启动任何后端之前,两个脚本都会做两件事:构造 few-shot 示例和提取标准答案数值。
few-shot 提示构造
bench_sglang.py 中的构造逻辑如下:
def get_one_example(lines, i, include_answer): ret = "Question: " + lines[i]["question"] + "\nAnswer:" if include_answer: ret += " " + lines[i]["answer"] return ret def get_few_shot_examples(lines, k): ret = "" for i in range(k): ret += get_one_example(lines, i, True) + "\n\n" return ret默认取前 5 条(--num-shot 5)带答案的样本拼接为演示(demonstration),随后为每条测试问题生成"Question: ...\nAnswer:"形式的待补全输入,期望模型续写出Answer:之后的求解过程与最终数值。这一设计使所有后端共享完全一致的上下文格式,消除提示工程差异对对比结果的影响。
标准答案数值抽取
参考答案字符串包含完整推导,评分前需先抽取最终数值。bench_sglang.py 中get_answer_value的实现为:
INVALID = -9999999 def get_answer_value(answer_str): answer_str = answer_str.replace(",", "") # 去掉千分位逗号 numbers = re.findall(r'\d+', answer_str) # 提取所有数字 if len(numbers) < 1: return INVALID try: return ast.literal_eval(numbers[-1]) # 取最后一个数字 except SyntaxError: return INVALID即:去除千分位逗号后取字符串中最后一个整数作为模型预测值,抽不出数字或解析失败时标记为INVALID = -9999999。测试集标签同样经此函数转换,并在进入主流程前通过assert all(l != INVALID for l in labels)确保标签全部有效。
第三步:SGLang 后端基准(SRT)
启动 SGLang 服务端
python -m sglang.launch_server --model-path meta-llama/Llama-2-7b-chat-hf --port 30000该命令以sglang.launch_server模块启动 SGLang Runtime(SRT),加载 Llama-2-7b-chat 模型并监听 30000 端口。README 的 Quick Start 部分(sglang/README.md)给出了相同用法,可额外叠加的常用启动参数包括:
--tp 2:启用 2 卡张量并行;--mem-fraction-static 0.7:显存不足时降低 KV cache 池静态内存占比(默认 0.9);--chat-template llama-2:覆盖模型自带的对话模板。
运行 SGLang 客户端
python3 bench_sglang.py --num-questions 200客户端核心是一段 SGL 结构化生成程序(bench_sglang.py):
import sglang as sgl @sgl.function def few_shot_gsm8k(s, question): s += few_shot_examples + question s += sgl.gen("answer", max_tokens=256, stop="Question")@sgl.function将普通 Python 函数声明为 SGL 程序;sgl.gen("answer", max_tokens=256, stop="Question")声明一次受限生成:最多 256 token,遇到Question即停止,结果存入answer状态变量。
随后通过select_sglang_backend(args)选择后端(默认srt,即连接http://127.0.0.1:30000的 RuntimeEndpoint),并以run_batch批量执行、连续批处理(continuous batching)调度(bench_sglang.py):
backend = select_sglang_backend(args) states = few_shot_gsm8k.run_batch( arguments, temperature=0, backend=backend, num_threads=args.parallel)温度固定为 0,保证贪心解码、结果可复现。--parallel默认 64 表示并发线程数(test_utils.py 中add_common_sglang_args_and_parse定义)。select_sglang_backend还支持srt-no-parallel(关闭并行解码/编码)与gpt-*(走 OpenAI 云端模型)等变体(test_utils.py)。
第四步:vLLM 后端基准
启动 vLLM 服务端
python3 -m vllm.entrypoints.api_server --tokenizer-mode auto --model meta-llama/Llama-2-7b-chat-hf --disable-log-requests --port 21000以 vLLM 的 OpenAI 兼容 API 服务启动同一模型,监听 21000 端口,--disable-log-requests关闭逐请求日志以减少 I/O 开销。
运行 vLLM 客户端
python3 bench_other.py --num-questions 200 --backend vllmbench_other.py通过add_common_other_args_and_parse解析参数,其中--backend为必选项,可选值包括vllm、lightllm、guidance、lmql、srt-raw、llama.cpp(test_utils.py)。未显式传--port时,脚本按后端映射默认端口:vllm=21000、lightllm=22000、lmql=23000、srt-raw=30000。
vLLM 分支将请求封装为call_generate_vllm(test_utils.py):POST 到{host}:{port}/generate,请求体携带prompt、temperature、max_tokens、stop字段,返回文本经pred[0][len(prompt):]截取新增部分作为续写结果。并发由ThreadPoolExecutor(args.parallel)线程池驱动。
第五步:LightLLM 后端基准
启动 LightLLM 服务端
# A10G python -m lightllm.server.api_server --tokenizer_mode auto --model_dir ~/model_weights/llama-2-7b-chat-hf --max_total_token_num 16000 --port 22000LightLLM 使用本地模型权重目录(--model_dir),A10G 环境下将 KV cache token 上限设为 16000;显存更小的 V100 上 README 建议将该值降至 4500(见同目录 mmlu 基准 README.md 的对照配置)。
运行 LightLLM 客户端
python3 bench_other.py --num-questions 200 --backend lightllmLightLLM 分支走call_generate_lightllm(test_utils.py):请求体字段为inputs+parameters(temperature、max_new_tokens、stop_sequences),返回generated_text[0]。注意该分支使用与 vLLM 不同的请求体结构,bench_other.py通过partial预绑定 url 实现差异封装。
第六步:Guidance 后端基准
Guidance 不需要独立的服务端进程,直接在客户端进程内加载 GGUF 量化模型:
python3 bench_other.py --num-questions 200 --backend guidance --parallel 1bench_other.py 中 guidance 分支的实现为:
from guidance import models, gen model = models.LlamaCpp( "/home/ubuntu/model_weights/Llama-2-7b-chat.gguf", n_gpu_layers=-1, n_ctx=4096) def call_generate(prompt, temperature, max_tokens, stop): out = model + prompt + gen(name="answer", max_tokens=max_tokens, temperature=temperature, stop=stop) return out["answer"]- 需预先准备 Llama-2-7b-chat 的 GGUF 权重文件(README 中示例路径为
/home/ubuntu/model_weights/Llama-2-7b-chat.gguf); n_gpu_layers=-1表示全部层加载到 GPU,n_ctx=4096设置上下文窗口;- 用
gen(name="answer", ...)声明受限生成节点,通过返回对象的out["answer"]取出结果。
由于是进程内推理、单模型实例,README 明确要求--parallel 1,避免多线程并发访问同一 LlamaCpp 实例造成冲突。
第七步:LMQL 后端基准
启动 LMQL 服务端
CUDA_VISIBLE_DEVICES=0,1 lmql serve-model meta-llama/Llama-2-7b-chat-hf --cuda --port 23000lmql serve-model启动 LMQL 模型服务,--cuda启用 GPU,占用 0、1 两块 GPU,监听 23000 端口。
运行 LMQL 客户端
python3 bench_other.py --num-questions 100 --backend lmql --parallel 2LMQL 分支(bench_other.py)使用@lmql.query声明约束生成程序:
import lmql model = lmql.model(args.model_path, endpoint=f"{args.host}:{args.port}") @lmql.query(model=model) async def program(question): '''lmql """{question}[ANSWER]""" where len(TOKENS(ANSWER)) < 257 and STOPS_AT(ANSWER, "Question") return ANSWER '''LMQL 约束语言以声明式 where 子句限定生成长度(len(TOKENS(ANSWER)) < 257,与 max_tokens=256 对齐)与停止条件(STOPS_AT(ANSWER, "Question"))。该分支不使用线程池,而是通过asyncio.gather按args.parallel的批大小并发调度(bench_other.py),README 给出的示例批大小为 2。因服务端负载与并发模型不同,示例请求数也相应减为 100。
评分逻辑与结果输出
统一评分流程
无论哪个后端,bench_sglang.py 与 bench_other.py 都执行相同的四步评分:
- 对每条模型输出调用
get_answer_value抽取最后一个整数作为预测值; acc = np.mean(np.array(preds) == np.array(labels))计算预测与标签完全相等的比例,即准确率;invalid = np.mean(np.array(preds) == INVALID)统计无法抽取出数字的输出占比;- 打印
Latency(整批请求的端到端耗时,单位秒)、Invalid、Accuracy三项指标。
其中accuracy基于严格的数值相等判断,只要模型答案的最终数字与参考答案最后一个数字一致即判对,这一粗粒度匹配规则与 GSM8K 评测惯例一致,但无法区分推导过程正确与否。
结果落盘
评测结果以追加写方式(open(args.result_file, "a"))写入 JSONL,默认文件名为result.jsonl,每条记录包含:
{ "task": "gsm8k", "backend": "sglang", "num_gpus": 1, "latency": 12.345, "accuracy": 0.35, "num_requests": 200, "other": {"num_questions": 200, "parallel": 64} }同时,dump_state_text(f"tmp_output_{args.backend}.txt", states)会把全部生成状态(含原始输出文本)落盘为tmp_output_<backend>.txt,便于事后排查失败样本与复算指标。
常见问题与调参建议
显存不足(OOM)
- SGLang 服务端可调低
--mem-fraction-static(默认 0.9); - LightLLM 降低
--max_total_token_num(A10G 用 16000,V100 用 4500); - Guidance 减小
n_ctx或减少 GPU 层数。
端口冲突
各后端默认端口约定为:SGLang=30000、vLLM=21000、LightLLM=22000、LMQL=23000(test_utils.py 中default_port映射)。修改服务端端口时,客户端需用--port显式对齐。
结果波动
所有后端在temperature=0下运行以保证可复现;如需观察不同并发对吞吐的影响,可调节--parallel(默认 64)与--num-questions(默认 200)。
扩展阅读
- 客户端公共参数与后端请求封装:python/sglang/test/test_utils.py
- SGLang 前端语言与运行时整体介绍:eval/rebase/sglang/README.md
- 同类基准的目录组织(含 mmlu、hellaswag、multi_chain_reasoning 等):eval/rebase/sglang/benchmark
- 仓库内 s1 项目推理相关工具:data/utils/inference_utils.py、data/bulk_inference.py
在 s1 测试时缩放工作流中,本文的 GSM8K 基准可用于快速验证不同推理引擎对数学应用题生成与评分的端到端表现,为缩放策略的消融对比提供稳定、可复现的测量基线。
- 大模型
- 推理模型
- 微调
- 模型推理服务
【免费下载链接】s1
s1: Simple test-time scaling
相关推荐
SGLang GSM8K 基准测试实战:从服务启动到 few-shot 数学推理评测
SGLang GSM8K 基准测试实战:从服务启动到 few shot 数学推理评测 GSM8K(Grade School Math 8K)是评测大语言模型小学
模型推理服务推理引擎人工智能大模型本地部署多模态SGLang MMLU 基准测试指南:数据准备、服务部署与 few-shot 精度评测
SGLang MMLU 基准测试指南:数据准备、服务部署与 few shot 精度评测 本文基于 SGLang 仓库中 benchmark/mmlu https
模型推理服务推理引擎人工智能大模型本地部署多模态cann/asc-devkit FMA空间接口
GetFmaMaxMinTmpSize<a name="ZH CN_TOPIC_0000002349009538" </a 功能说明<a name="secti
人工智能深度学习算子库CANNAscend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考