在 Hugging Face 的 WebAI 团队,我们最大的目标之一就是让浏览器端推理尽可能快速且用户友好。要实现这一目标,需要多层努力:模型需要适合浏览器的表示形式,运行时需要构建高效的执行计划,而技术栈底层的各个 GPU 操作则需要充分利用各种不同的设备和浏览器实现。今天,我们发布了这一努力的第一层成果:@huggingface/kernels,这是一个用于从 Hugging Face Hub 加载和运行优化 WebGPU 内核的精简库,同时还在 huggingface.co/webgpu-kernels 发布了首批 207 个内核。
该集合涵盖了各种机器学习架构和工作负载中广泛使用的操作。更重要的是,每个内核都以完整、带版本号的软件包形式发布:其接口、着色器模板、正确性测试用例、基准测试用例和使用说明都一起存放在 Hub 上。
我们还推出了 Fleet,这是一套浏览器内的 GPU 基准测试和测试套件,可在你的硬件上运行内核并为其评分。除了你本机的测试结果外,Fleet 还为社区提供了一种方式,可以从我们传统测试实验室无法覆盖的设备上贡献性能和正确性证据。在你同意的情况下,每次运行都会添加私有证据,这可以帮助我们发现故障(错误结果、病态慢速案例等)、改进内核变体,并在真实硬件上做出更好的优化决策。
摘要
- 207 个 WebGPU 内核,以独立仓库的形式发布在 webgpu-kernels 组织中。采用 Apache-2.0 许可证。
- 一个 JavaScript 加载器 @huggingface/kernels,可直接从 Hub 下载、准备并运行内核。
- 每个内核都有明确的契约和可复现的证据,包括清单、正确性测试、基准测试用例和 WGSL 着色器模板。
- Fleet,一个基于浏览器的基准测试工具,通过众包方式收集真实 GPU 上的正确性和性能证据,帮助我们改进内核及其变体。
为什么从内核开始?
在浏览器中运行的模型最终会变成一系列 GPU 操作:矩阵乘法、归一化、卷积、注意力原语、量化操作、数据布局变换等等。WebGPU 通过可移植的 API 让这些操作在现代浏览器中得以使用,而 WGSL 则为执行这些操作的着色器提供了一种通用语言。
然而,可移植性并不自动意味着性能。两个着色器可以实现相同的操作并产生相同的输出,但在不同加速器上的表现却可能截然不同。工作组大小、内存访问模式、向量化、数据类型和融合策略都会影响性能。最佳选择也会随输入形状、设备、浏览器和可用的 WebGPU 功能而变化。
这就是为什么内核构成了快速浏览器推理的基础层。更高级别的运行时,其效率只能取决于它们所调度的操作。通过让这些操作可以被单独发现、测试、基准测试和版本管理,我们可以在保持上层稳定契约的同时,独立地改进这一基础。
一个内核仓库,而不仅仅是着色器
该集合中的每个内核都有自己的仓库和内核卡片。卡片记录了操作的语义、输入、输出、属性、支持的数据类型、源文件,以及一个可直接运行的 @huggingface/kernels 示例。
例如,ai.onnx.Add 实现了带有多向广播的逐元素加法。它是神经网络中最简单的操作之一,从残差连接到添加偏置,无处不在。它的卡片记录了两个输入、广播后的输出形状、支持的数据类型,以及针对不同形状和设备可用的变体。

ai.onnx.Add 仓库将其清单、正确性和基准测试用例,以及 WGSL 着色器模板打包在一起。
在卡片背后,仓库包含了理解和评估实现所需的工件:
- manifest.json 是操作契约的权威来源。它定义了输入、输出、属性、类型约束和形状推导规则。
- metadata.json 记录了内核标识符、摘要和来源信息。
- test.json 包含正确性测试用例,因此可以根据预期行为来检查实现。
- bench.json 包含基准测试和调优用例,这些用例代表了用于评估内核的工作负载。
- *.wgsl.jinja 文件包含参数化的 WGSL 实现,用于为特定请求和设备生成着色器。
这种结构将着色器转变为可复用的软件工件。无需阅读 WGSL 即可检查其接口,正确性和性能测试用例随实现一同分发,并且已发布的版本可以被显式加载,而不是依赖于无版本的 URL。我们的内核还可以作为参考实现,供开发人员构建自定义 WebGPU 内核或将这些操作集成到他们自己的运行时中。
从 Hub 加载内核
从 npm 安装该包:
npm install @huggingface/kernels@preview
运行这些内核需要支持 WebGPU 的浏览器。WebGPU 的可用性取决于浏览器、操作系统、GPU 和驱动程序。你可以通过 JavaScript 中的 `"gpu" in navigator` 来检查。
@huggingface/kernels 提供了内核仓库与你的应用程序之间的桥梁。使用 Hub 仓库 ID 和契约版本调用 getKernel,然后使用类型化的输入数据和张量形状调用返回的函数。以下是一个简单的偏置相加示例:
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],
},
});
第二个输入在第一维上进行广播,产生形状为 [2, 3] 的输出。加载器根据清单契约和输入推导出该输出形状和逻辑数据类型,然后自动分配 c。
对六个浮点数进行加法是刻意设计的最小演示。在这种规模下,GPU 往返的开销远大于计算本身。关键在于调用模式:对于优化内核真正发挥作用的重量级操作(如矩阵乘法(ai.onnx.MatMul)),调用模式完全相同。只有仓库 ID 和输入发生变化。
即便是这种基础运算,也能说明内核为何需要变体。形状相同的加法可以使用直接的向量化路径,而广播输入则需要不同的索引逻辑。已发布的 Add 内核包含针对等形状、向量化广播、标量处理和通用广播的变体。运行时可以在不改变面向应用的 API 的情况下,选择适合当前调用和设备的实现。
version: 1 选项选择已发布内核契约的第 1 版。它与 ONNX opset、算子的 since_version 或模型修订版本是相互独立的。将这些概念分开,可以让应用依赖稳定的 JavaScript 面向契约,而内核实现可以在其后不断演进。
这些内核有多快?
那么,优化后的内核究竟能带来多大的差异?我们将自己的内核集合与 ORT WebGPU 在 Apple M4 GPU 上进行了对比测试,使用的是 ONNX Runtime Web 1.30.0-dev.20260826-b1f76d586a。我们从全部 207 个运算的 1,756 个测试用例开始,保留了双方输出匹配且计时可靠的 809 个用例。
在这些对比中,我们的内核按几何平均值计算快 2.57 倍,按中位数计算快 1.90 倍,其中 629 次胜出,176 次落后,4 次持平。以下是四个常见运算的详细对比:
| 运算 | 对比用例数 | 我们的 WebGPU 内核 | 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 倍 |
一些个别的胜出案例差距要大得多。一个特别困难的双线性 Einsum 用例(i,ij,j,大小为 4096)在我们的内核上运行耗时 0.136 毫秒,而 ORT WebGPU 则需要 1,396 毫秒:快了超过 10,000 倍。对 [256, 4096] 进行逐行 CumSum 运算快了 301 倍,耗时 0.016 毫秒对比 4.784 毫秒。这些是特殊情况,而非你在各处都应期待的加速幅度,但它们展示了当通用实现陷入慢速路径时,专用内核能带来多大的帮助。
我们对 GPU 本身执行的工作进行了计时,排除了加载内核、创建会话、上传输入、编译着色器以及读回输出等准备工作。非常短的工作负载自然更难测量,而且小规模用例可能受益于 GPU 缓存,因此这些数字最好被理解为一种有用的对比参考,而非对每个应用的性能承诺。
这些也是单个运算的结果,而非完整模型的结果。具体性能会因 GPU 和浏览器而异,这正是 Fleet 对于构建更全面图景如此重要的原因。
我们还在与 ONNX Runtime 团队合作,将这些改进上游化,以便让更广泛的 ONNX Runtime Web 生态系统受益。
从单台设备到设备集群
WebGPU 性能因 GPU、浏览器和驱动程序而异,因此单台机器的结果只能说明部分情况。Fleet 让任何人都能在浏览器中运行正确性和性能检查,并查看内核在其硬件上的表现。
在获得同意后,每次运行都会私下贡献证据,帮助我们识别特定设备的故障、比较不同变体并改进选择规则。目标很简单:利用广泛而真实的覆盖范围,让内核为所有人变得更快、更可靠。
为 WebAI 构建共享基础
最初的 207 个内核是一个起点,而非最终状态。在 Hub 上独立发布内核,为我们提供了一个共同的地方来检查契约、比较实现、复现正确性检查并改进性能,而无需将每个着色器直接嵌入到每个运行时中。
该集合也是 Hub 更广泛内核生态系统的一部分:在内核页面上,WebGPU 内核与 CUDA、ROCm、Metal 及其他平台的内核并列展示,并且可以像 Hub 上的任何其他工件一样进行筛选、排序和探索。

Hub 内核页面上全部 207 个 WebGPU 内核,已按平台筛选。
这些组成部分相互强化:
- 内核仓库定义了透明、带版本管理的运算契约。
- @huggingface/kernels 让这些运算能够从 JavaScript 中轻松加载和运行。
- Fleet 通过众包方式,在远比传统基准测试实验室所能覆盖的更广泛设备范围内收集真实世界的证据。
- 每一次贡献的运行结果都能揭示失败案例、指导调优、改进变体选择,并帮助验证未来的内核版本。
这是我们浏览器推理栈后续步骤的低层基础。我们很高兴能将这些内核连接到更高级别的模型工具,继续扩大算子覆盖范围,并让 WebAI 生态系统中更易用上快速的本地推理。
探索 WebGPU 内核集合,试用 @huggingface/kernels,并加入 Fleet,从你的设备贡献数据,帮助我们让这些内核惠及所有人。
One of our biggest goals on the WebAI team at Hugging Face is to make browser inference as fast and as user-friendly as possible. Getting there is a multi-layer effort: models need browser-friendly representations, runtimes need to build efficient execution plans, and the individual GPU operations at the bottom of the stack need to make the most of many different devices and browser implementations. Today, we are releasing the first layer of that effort: @huggingface/kernels, a minimal library for loading and running optimized WebGPU kernels from the Hugging Face Hub, together with an initial collection of 207 kernels at huggingface.co/webgpu-kernels.
The collection covers operations used across a wide variety of machine learning architectures and workloads. More importantly, each kernel is published as a complete, versioned package: its interface, shader templates, correctness cases, benchmark cases, and usage instructions all live together on the Hub.
We are also launching Fleet, an in-browser GPU benchmarking and testing suite that runs and scores the kernels on your hardware. Beyond the results for your own machine, Fleet gives the community a way to contribute performance and correctness evidence from devices we could never cover in a conventional test lab. With your consent, every run adds private evidence that can help us find failures (incorrect results, pathologically slow cases, etc.), improve kernel variants, and make better optimization decisions across real-world hardware.
TL;DR
- 207 WebGPU kernels, published as individual repositories in the
webgpu-kernelsorganization. Apache-2.0 licensed. - A JavaScript loader,
@huggingface/kernels, which downloads, prepares, and runs kernels directly from the Hub. - Explicit contracts and reproducible evidence for every kernel, including manifests, correctness tests, benchmark cases, and WGSL shader templates.
- Fleet, a browser-based benchmarking tool that crowdsources correctness and performance evidence across real-world GPUs to help us improve kernels and their variants.
Why start with kernels?
A model running in the browser eventually becomes a sequence of GPU operations: matrix multiplications, normalizations, convolutions, attention primitives, quantization operations, data-layout transformations, and many more. WebGPU makes these operations available across modern browsers through a portable API, while WGSL provides a common language for the shaders that execute them.
Portability, however, does not automatically mean performance. Two shaders can implement the same operation and produce the same output while behaving completely differently across different accelerators. Workgroup sizes, memory access patterns, vectorization, data types, and fusion strategies can all affect performance. The best choice can also change with the input shape, device, browser, and available WebGPU features.
This is why kernels form a foundational layer of fast browser inference. Higher-level runtimes can only be as efficient as the operations they dispatch. By making those operations individually discoverable, testable, benchmarkable, and versioned, we can improve the foundation independently while keeping a stable contract for the layers above it.
A kernel repository, not just a shader
Each kernel in the collection has its own repository and kernel card. The card documents the operation's semantics, inputs, outputs, attributes, supported data types, source files, and a ready-to-run @huggingface/kernels example.
For example, ai.onnx.Add implements elementwise addition with multidirectional broadcasting. It is one of the simplest operations in a neural network, used everywhere from residual connections to adding a bias. Its card documents the two inputs, the broadcasted output shape, supported data types, and the variants available for different shapes and devices.

The ai.onnx.Add repository packages its manifest, correctness and benchmark cases, and WGSL shader templates together.
Behind the card, the repository contains the artifacts needed to understand and evaluate the implementation:
manifest.jsonis the source of truth for the operation contract. It defines inputs, outputs, attributes, type constraints, and shape derivation rules.metadata.jsonrecords the kernel identifier, digests, and provenance.test.jsoncontains correctness cases, so an implementation can be checked against expected behavior.bench.jsoncontains benchmark and tuning cases that represent the workloads used to evaluate the kernel.*.wgsl.jinjafiles contain the parameterized WGSL implementations used to produce shaders for a particular request and device.
This structure turns a shader into a reusable software artifact. The interface is inspectable without reading WGSL, correctness and performance cases travel with the implementation, and published versions can be loaded explicitly rather than depending on an unversioned file URL. Our kernels can also serve as reference implementations for developers building custom WebGPU kernels or integrating these operations into their own runtimes.
Loading a kernel from the Hub
Install the package from npm:
npm install @huggingface/kernels@preview
Running these kernels requires a browser with WebGPU support. WebGPU availability depends on the browser, operating system, GPU, and driver. You can check for it in JavaScript with
"gpu" in navigator.
@huggingface/kernels provides the bridge between a kernel repository and your application. Call getKernel with a Hub repository ID and a contract version, then invoke the returned function with typed input data and tensor shapes. Here is a small bias-add example:
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],
},
});
The second input is broadcast across the first dimension, producing an output with shape [2, 3]. The loader derives that output shape and logical data type from the manifest contract and the inputs, then allocates c automatically.
Addition on six floats is deliberately the smallest possible demo. At this size, the GPU round trip costs far more than the math. The point is the call pattern: it stays exactly the same for the heavyweight operations where optimized kernels actually pay off, such as matrix multiplication (ai.onnx.MatMul). Only the repository ID and the inputs change.
Even this elementary operation illustrates why kernels need variants. Equal-shape addition can use a direct vectorized path, while broadcasted inputs need different indexing logic. The published Add kernel includes variants for equal shapes, vectorized broadcasting, scalar processing, and general broadcasting. The runtime can select an implementation that fits the current call and device without changing the application-facing API.
The version: 1 option selects version 1 of the published kernel contract. It is separate from an ONNX opset, an operator's since_version, or a model revision. Keeping those concepts separate lets applications depend on a stable JavaScript-facing contract while kernel implementations evolve behind it.
How fast are the kernels?
So, how much of a difference do optimized kernels actually make? We put our collection head-to-head with ORT WebGPU on an Apple M4 GPU, using ONNX Runtime Web 1.30.0-dev.20260826-b1f76d586a. We started with 1,756 test cases across all 207 operations and kept the 809 cases where both sides produced matching outputs and reliable timings.
Across those comparisons, our kernels were 2.57x faster by geometric mean and 1.90x faster at the median, with 629 wins, 176 losses, and 4 ties. Here is a closer look at four familiar operations:
| Operation | Compared cases | Our WebGPU Kernel | ORT WebGPU | Speedup |
|---|---|---|---|---|
| Add | 5 | 0.064 ms | 0.227 ms | 3.52x |
| MatMul | 29 | 0.115 ms | 0.131 ms | 1.14x |
| Softmax | 12 | 0.114 ms | 0.240 ms | 2.11x |
| LayerNormalization | 6 | 0.061 ms | 0.135 ms | 2.22x |
Some individual wins were much bigger. A particularly difficult bilinear Einsum case (i,ij,j with size 4096) ran in 0.136 ms with our kernel versus 1,396 ms with ORT WebGPU: more than 10,000x faster. A row-wise CumSum over [256, 4096] was 301x faster, at 0.016 ms versus 4.784 ms. These are unusual cases rather than the speedups you should expect everywhere, but they show how much a specialized kernel can help when a general implementation hits a slow path.
We timed the work done on the GPU itself, leaving out setup such as loading kernels, creating sessions, uploading inputs, compiling shaders, and reading outputs back. Very short workloads are naturally harder to measure, and small cases can benefit from the GPU cache, so these numbers are best read as a useful comparison rather than a promise for every application.
They are also results for individual operations, not complete models. Exact performance will change across GPUs and browsers, which is why Fleet is so important for building a broader picture.
We are also working with the ONNX Runtime team to upstream these improvements so they can benefit the broader ONNX Runtime Web ecosystem.
From one device to a fleet
WebGPU performance varies across GPUs, browsers, and drivers, so results from one machine only tell part of the story. Fleet lets anyone run correctness and performance checks in the browser and see how the kernels behave on their hardware.
With consent, each run privately contributes evidence that helps us spot device-specific failures, compare variants, and improve selection rules. The goal is simple: use broad, real-world coverage to make the kernels faster and more reliable for everyone.
Building a shared foundation for WebAI
The initial 207 kernels are a starting point, not the end state. Publishing kernels independently on the Hub gives us a common place to inspect contracts, compare implementations, reproduce correctness checks, and improve performance without embedding every shader directly into every runtime.
The collection is also part of the Hub's broader kernel ecosystem: on the Kernels page, the WebGPU kernels sit alongside kernels for CUDA, ROCm, Metal, and other platforms, and can be filtered, sorted, and explored like any other artifact on the Hub.

All 207 WebGPU kernels on the Hub's Kernels page, filtered by platform.
The pieces reinforce one another:
- Kernel repositories define transparent, versioned operation contracts.
@huggingface/kernelsmakes those operations straightforward to load and run from JavaScript.- Fleet crowdsources real-world evidence across a much broader range of devices than a conventional benchmark lab can cover.
- Every contributed run can reveal failures, guide tuning, improve variant selection, and help validate future kernel versions.
This is the low-level foundation for the next steps in our browser inference stack. We are excited to connect these kernels to higher-level model tooling, continue expanding operation coverage, and make fast local inference easier to use across the WebAI ecosystem.
Explore the WebGPU kernel collection, try @huggingface/kernels, and join the Fleet to contribute evidence from your device and help us make the kernels better for everyone.