浏览器 AI:WebGPU 内核与基准测试
Hugging Face 的 2.57 倍 WebGPU 提速附带着 176 项落败
Hugging Face 发布了 207 个采用 Apache-2.0 许可的 WebGPU 内核、一个可通过 JavaScript 运行它们的加载器,以及一款浏览器基准测试工具。其对比 ONNX Runtime Web 的主打 2.57 倍提速,是在 1,756 个测试用例中保留 809 个后得出,并记录了 176 项落败。

Hugging Face 在其 Hub 上新建的 webgpu-kernels 组织下发布了 207 个 WebGPU 内核,外加一个名为 @huggingface/kernels 的 JavaScript 加载器,用于下载这些内核并在浏览器中运行。第三部分 Fleet 则在访客自己拥有的任意 GPU 上对这些内核做基准测试。
这次发布附带了一个数字:在 Apple M4 上对比 ONNX Runtime Web 的 WebGPU 后端,几何平均提速 2.57 倍,中位数为 1.90 倍。两个数字都是真实的。但它们适用的范围都比听起来要窄。
2.57 倍实际测的是什么
此次正面对比在 Apple M4 GPU 上进行,对手是 ONNX Runtime Web 1.30.0-dev.20260826-b1f76d586a。Hugging Face 从覆盖全部 207 个算子的 1,756 个测试用例出发,保留了两种实现输出一致且计时可靠的 809 个用例。其余 947 个用例并未计入该数字。
计时仅覆盖 GPU 计算本身。加载内核、创建会话、上传输入、编译着色器以及回读输出在双方都被排除在外。Hugging Face 提醒说,极短的负载难以测量,且小规模用例可能因 GPU 缓存而获益,因此这些数字更适合当作一种对比,而非对某个具体应用的承诺。单一设备、单一浏览器也不足以描述 WebGPU,这一保留意见由该公司自己提出。
一个 10,000 倍的 Einsum 和一个 301 倍的 CumSum
有两个条目远在总体之外。规模为 4096 的双线性 Einsum 耗时 0.136 毫秒,而 ORT WebGPU 为 1,396 毫秒,差距超过 10,000 倍。对 [256, 4096] 输入做按行 CumSum 耗时 0.016 毫秒,而对手为 4.784 毫秒,相差 301 倍。Hugging Face 称这两者都属异常,并将其归因于通用实现落入了慢路径。
普通算子的表现则要平淡得多:
| 算子 | 用例数 | HF 内核 | ORT WebGPU | 提速 |
|---|---|---|---|---|
| Add | 5 | 0.064 毫秒 | 0.227 毫秒 | 3.52 倍 |
| MatMul | 29 | 0.115 毫秒 | 0.131 毫秒 | 1.14 倍 |
| Softmax | 12 | 0.114 毫秒 | 0.240 毫秒 | 2.11 倍 |
| LayerNormalization | 6 | 0.061 毫秒 | 0.135 毫秒 | 2.22 倍 |
MatMul 提升 1.14 倍。Add 以 3.52 倍胜出,尽管相加几个浮点数并不是推理耗时所在。发布内容并未按算子类别拆分这 629 项胜出,因此这套内核在哪些负载上提速最多,公开数据并未给出答案。
那 176 项落败
Hugging Face 自己的统计是 629 胜、176 负、4 平。落败并不是发布帖必须列出的一栏,发布内容也没有对此作出解释。它确实指出,最佳实现会随输入形状、设备、浏览器和可用的 WebGPU 特性而变化, , 正是这类可变性造就了如此规模的落败栏。按算子细分的落败数据没有公开,因此这些落败是集中在少数几个内核,还是分散在全集中,尚不得而知。
内核被打包成契约,而非着色器
每个内核都有自己的代码库和模型卡,记录语义、输入、输出、属性、支持的数据类型和源文件。模型卡背后有五种产物类型:manifest.json,作为算子契约的事实来源;metadata.json,用于标识符、摘要和来源信息;test.json,用于正确性用例;bench.json,用于基准测试和调优用例;以及 *.wgsl.jinja 文件,存放按请求和设备专门化的参数化 WGSL。
契约版本控制与 ONNX 自身的版本控制保持分离。传给 getKernel 的 version 不是 opset,不是算子的 since_version,也不是模型修订版,这使应用可以依赖稳定的 JavaScript 接口,而底层的着色器实现可以变动。Add 内核提供四个变体,分别用于形状相同、向量化广播、标量处理和一般广播,因为广播加法需要不同的索引方式。
import { getKernel } from "@huggingface/kernels";
const add = await getKernel("webgpu-kernels/ai.onnx.Add", { version: 1 });
const { c } = await add({
a: { data: new Float32Array([1, 2, 3, 4, 5, 6]), shape: [2, 3] },
b: { data: new Float32Array([10, 20, 30]), shape: [3] },
});加载器从 manifest 推导输出形状并分配结果,因此对于那些内核真正能带来收益的重负载算子,调用方式保持不变。Hugging Face 表示正在与 ONNX Runtime 团队合作,将这些改进上游到 ONNX Runtime Web。如果这成为现实,这些提速将不再是采用 Hugging Face 加载器的理由,而会成为 ORT Web 用户默认获得的能力。
Fleet、用户同意,以及与模型之间的距离
Fleet 在浏览器中运行正确性和性能检查,并报告本机的结果。贡献是选择加入的:在获得同意后,每次运行都会添加 Hugging Face 所称的私有证据,用于发现特定设备上的故障、比较变体,并改进针对传统测试实验室无法覆盖的硬件的选择规则。WebGPU 本身的支持情况因浏览器、操作系统、GPU 和驱动程序而异,可通过 "gpu" in navigator 检测。
这一切都不是模型基准测试。测量是按算子进行的,而在浏览器中运行的模型是一系列 GPU 操作,其运行时间只能与它所调度的操作一样高效。抬高了 Add、Softmax 和 LayerNormalization 的下限,并不能保证上层报告出同样的倍数。
决定这一切是否有意义的部分其实很枯燥:ONNX Runtime 的上游工作能否落地、Fleet 收集的证据能否快到足以修复它所发现的问题,以及落败那一栏能否缩小。Hugging Face 把它印在了胜出旁边,这可不是内核发布通常的写法。
- 来源 : Hugging Face's 2.57x WebGPU speedup comes with 176 losses attached — 2026-09-01
每天早晨用 3 分钟掌握科技要闻
每个工作日一封邮件,只讲真正重要的 AI 与科技动态。