如何用 benchmark_llm 对 tinygrad LLM 做离线 prefill 与 decode 吞吐基准测试
【免费下载链接】tinygradYou like pytorch? You like micrograd? You love tinygrad! ❤️项目地址: https://gitcode.com/GitHub_Trending/tiny/tinygrad
仓库里自带了一个现成的基准脚本 extra/benchmark_llm.py,它从本地路径加载一个 GGUF 模型,先用一段合成 token 序列做分块 prefill,再逐 token decode 固定数量,最后分别打印两个阶段的 tok/s。整个过程不访问网络、不需要真实文本 prompt,适合在改动编译选项或切换后端之后,快速对比同一模型在 prefill 和 decode 两条路径上的吞吐变化。本文围绕这个脚本给出从环境准备到读数的完整流程。
准备环境:安装 tinygrad 并确认设备
README.md 推荐的安装方式是从源码安装:
git clone https://github.com/tinygrad/tinygrad.git cd tinygrad python3 -m pip install -e .如果只是想 clone 后直接运行脚本而暂时不安装,docs/tinygpu.md 中提到可以用PYTHONPATH=.代替安装步骤,例如PYTHONPATH=. python3 extra/benchmark_llm.py ...。
安装完成后,用下面这条命令确认 tinygrad 实际选择的默认设备:
python3 -c "from tinygrad import Device; print(Device.DEFAULT)"打印出设备名(如CPU、CL、CUDA等)即说明环境可用。之后运行基准时实际跑在哪个后端,就以此输出和DEV变量(见后文)为准。
运行脚本本身没有额外依赖安装步骤,但需要准备一个本地 GGUF 模型文件:--model是必填参数,extra/benchmark_llm.py 要求传入 "path to gguf model",即模型文件的本地路径。项目文档没有给出固定的模型下载地址,模型文件由读者自行准备,下文命令中的<your-model.gguf>均指你自己模型文件的路径,首次出现时说明,后文不再重复。
运行基准测试
最短主路径,全部使用脚本默认参数:
python3 extra/benchmark_llm.py --model <your-model.gguf>脚本的完整参数(来自 extra/benchmark_llm.py 的 argparse 定义):
| 参数 | 默认值 | 用途 |
|---|---|---|
--model | 必填 | GGUF 模型文件路径 |
--max-context | 8192 | max context length |
--prompt-tokens | 1024 | number of prompt tokens |
--decode-tokens | 16 | number of tokens to decode |
--chunk-size | 32 | chunk size for prefill |
两个由模型加载逻辑决定的边界条件,改参数前需要知道(来自 tinygrad/llm/model.py 中Transformer.from_gguf与Transformer.generate):
--max-context会在加载时与 GGUF 元数据中的context_length取较小值,传得比模型本身支持更长也不会生效。generate的循环条件是 token 总数达到max_context即停止,因此--prompt-tokens加--decode-tokens的总量不要超过--max-context,否则请求的 decode 数量跑不满。默认的 1024 + 16 远小于 8192,不受影响。
一次典型的参数化运行示例(把 prefill 长度和 chunk 一起放大,验证分块 prefill 的影响):
python3 extra/benchmark_llm.py --model <your-model.gguf> --prompt-tokens 4096 --chunk-size 128输出结果怎么看
脚本按顺序打印四行,每一行对应一个阶段,这也是判断一次运行是否完整跑通的标准:
load <秒数>s warm <秒数>s prefill <tok/s> decode <tok/s> output <生成的 token 列表>各行的含义(对照 extra/benchmark_llm.py 源码):
load:Transformer.from_gguf(args.model, args.max_context)加载模型耗时。warm:model.warmup()耗时。warmup的实现是跑两次generate([0])(见 tinygrad/llm/model.py),用于在正式计时前完成 JIT 编译等一次性开销,所以load/warm两行与后面的吞吐数字相互独立。prefill:prompt_tokens除以从model.generate启动到拿到第一个 token 的耗时。源码注释明确写了 "first token is time-to-first-token; counted as part of prefill",即首 token 延迟计入 prefill 统计。prefill 阶段按--chunk-size分块消费 prompt,--chunk-size改的就是这里。decode:decode_tokens除以第一个 token 之后剩余--decode-tokens个 token 的生成耗时,行尾output是本次实际生成出的 token 序列。
需要强调离线性质的一点:prompt 不是真实文本,而是合成序列[257] + [1000+i%1000 for i in range(prompt_tokens-1)],即首 token 为 257,其后在 1000–1999 区间内循环取模。模型文件也从本地路径读取,因此脚本运行期间不需要网络,测得的是吞吐本身,与生成质量无关。对比不同配置时,只比较同一模型、同一参数下prefill与decode两个 tok/s 数值即可。
可选分支:切换后端与打开 DEBUG 观察
docs/env_vars.md 说明了DEV与DEBUG两个环境变量,都可以直接加在基准命令前:
指定后端:
DEV用于选择设备、renderer 与架构,文档给出的解释示例包括AMD(use the AMD device)、CPU:LLVM(use the CPU device with the LLVM renderer)。例如在 CPU 上跑同一基准作为对照组:DEV=CPU:LLVM python3 extra/benchmark_llm.py --model <your-model.gguf>打开调试输出:
DEBUG=2起提供每个 kernel 的计时、内存与带宽指标;DEBUG=4起额外打印生成的 kernel 代码。例如:DEBUG=2 python3 extra/benchmark_llm.py --model <your-model.gguf>当两次基准吞吐差异明显时,用
DEBUG=2找出耗时集中在哪些 kernel,比只看总 tok/s 更容易定位改动的影响。
需要注意的限制
- 权重默认按 float16 加载:
from_gguf中当环境变量HALF非 0(默认 1)时,会把 state dict cast 成 float16。对比不同后端时这一点天然一致;如需保留原始 dtype,按源码可用HALF=0运行。 from_gguf的第三个参数realize默认取环境变量REALIZE(默认 0),决定是否在加载后立即 realize 全部参数(见 tinygrad/llm/model.py)。- 模型带循环状态块(SSM/hybrid 结构)且当前设备不支持对应的自定义 kernel 时,
generate会把chunk_size强制降为 1,分块 prefill 退化为逐 token,此时--chunk-size不再生效(tinygrad/llm/model.py)。 - 合成 prompt 决定了这套数字不能直接当作真实对话场景的首 token 延迟或解码速度,它只是同一口径下的相对吞吐基准。
【免费下载链接】tinygradYou like pytorch? You like micrograd? You love tinygrad! ❤️项目地址: https://gitcode.com/GitHub_Trending/tiny/tinygrad
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考