sync 2e7068faf55e
Browse files- README.md +99 -0
- build/webgpu/bench.json +293 -0
- build/webgpu/manifest.json +535 -0
- build/webgpu/matmul-nbits-fused-rms-norm.wgsl.jinja +117 -0
- build/webgpu/metadata.json +19 -0
- build/webgpu/qkv-projection.wgsl.jinja +221 -0
- build/webgpu/test.json +663 -0
README.md
CHANGED
|
@@ -1,3 +1,102 @@
|
|
| 1 |
---
|
|
|
|
| 2 |
license: apache-2.0
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
library_name: kernels
|
| 3 |
license: apache-2.0
|
| 4 |
+
tags:
|
| 5 |
+
- kernel
|
| 6 |
+
- webgpu
|
| 7 |
+
- wgsl
|
| 8 |
---
|
| 9 |
+
# com.microsoft.MatMulNBitsQkv
|
| 10 |
+
|
| 11 |
+
`com.microsoft` · ONNX Runtime contrib operator · contrib since_version 1
|
| 12 |
+
|
| 13 |
+
## Description
|
| 14 |
+
|
| 15 |
+
Fuses RMS normalization with three block-quantized attention projections: `A_norm = RMSNorm(A + skip, norm_scale)` (or without `skip`), followed by Q, K, and V projections. The optional fourth output returns `A + skip`. Only 4-bit weights with `block_size = 32` are supported; projection biases, bfloat16, and non-default `accuracy_level` values are not implemented.
|
| 16 |
+
|
| 17 |
+
See the [ONNX Runtime `MatMulNBitsQkv` contrib-operator spec](https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.MatMulNBitsQkv) for the reference semantics.
|
| 18 |
+
|
| 19 |
+
## Inputs
|
| 20 |
+
|
| 21 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 22 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
+
| `A` | `aT` | `T1` | — | — | Shared activation of rank 2 `(M, K)` or rank 3 `(batch, sequence, K)`; only the last axis is the reduction axis. | required |
|
| 24 |
+
| `skip` | `skipT` | `T1` | — | — | Residual added to A before the normalization, with A's shape. | optional |
|
| 25 |
+
| `norm_scale` | `normScaleT` | `T1` | `1` | — | Simplified-layer-normalization (RMS) gain of shape `[K]`. | required |
|
| 26 |
+
| `q_B` | `qBT` | `T2` | `3` | — | Bit-packed uint8 Q weights of shape `(Nq, k_blocks, blob_size)`. | required |
|
| 27 |
+
| `q_scales` | `qScalesT` | `T1` | `2` | — | Per-block Q scales of shape `(Nq, k_blocks)`. Quantization is symmetric: there is no zero-point input, so codes are offset by the midpoint `2^(bits - 1)`. | required |
|
| 28 |
+
| `k_B` | `kBT` | `T2` | `3` | — | Bit-packed K weights of shape `(Nkv, k_blocks, blob_size)`. | required |
|
| 29 |
+
| `k_scales` | `kScalesT` | `T1` | `2` | — | Per-block K scales of shape `(Nkv, k_blocks)`. | required |
|
| 30 |
+
| `v_B` | `vBT` | `T2` | `3` | — | Bit-packed V weights of shape `(Nkv, k_blocks, blob_size)`. | required |
|
| 31 |
+
| `v_scales` | `vScalesT` | `T1` | `2` | — | Per-block V scales of shape `(Nkv, k_blocks)`. | required |
|
| 32 |
+
|
| 33 |
+
## Outputs
|
| 34 |
+
|
| 35 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 36 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 37 |
+
| `Q` | `qT` | `T1` | same as `A` | derived; see description | Query projection: A's leading axes with a trailing Nq. | required |
|
| 38 |
+
| `K` | `kT` | `T1` | same as `A` | derived; see description | Key projection: A's leading axes with a trailing Nkv. | required |
|
| 39 |
+
| `V` | `vT` | `T1` | same as `A` | derived; see description | Value projection: A's leading axes with a trailing Nkv. | required |
|
| 40 |
+
| `input_skip_bias_sum` | `residualT` | `T1` | same as `A` | same as `A` | The residual sum A + skip, with A's shape. Requires the skip input. | optional |
|
| 41 |
+
|
| 42 |
+
## Attributes
|
| 43 |
+
|
| 44 |
+
Attributes and default values (overridable per request):
|
| 45 |
+
|
| 46 |
+
| Attribute | Default | Description |
|
| 47 |
+
| --- | --- | --- |
|
| 48 |
+
| `accuracy_level` | `0` | Minimum internal accuracy level, following MatMulNBits semantics; this implementation supports the standard default 0. |
|
| 49 |
+
| `bits` | `4` | Bit width used to quantize all three weight matrices; only 4 is supported. |
|
| 50 |
+
| `epsilon` | `9.999999974752427e-7` | Epsilon used by the simplified layer-normalization reduction. |
|
| 51 |
+
| `K` | — | Input feature dimension shared by the normalized input and all projection weights. |
|
| 52 |
+
| `Nq` | — | Output feature dimension of the Q projection. |
|
| 53 |
+
| `Nkv` | — | Output feature dimension shared by the K and V projections. |
|
| 54 |
+
| `block_size` | — | Size of each quantization block along K; only 32 is supported. |
|
| 55 |
+
|
| 56 |
+
## Type constraints
|
| 57 |
+
|
| 58 |
+
| Variable | Allowed dtypes |
|
| 59 |
+
| --- | --- |
|
| 60 |
+
| `T1` | `float32`, `float16` |
|
| 61 |
+
| `T2` | `uint8` |
|
| 62 |
+
|
| 63 |
+
## Files
|
| 64 |
+
|
| 65 |
+
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
|
| 66 |
+
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 67 |
+
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 68 |
+
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
| 69 |
+
- [`matmul-nbits-fused-rms-norm.wgsl.jinja`](build/webgpu/matmul-nbits-fused-rms-norm.wgsl.jinja)
|
| 70 |
+
- [`qkv-projection.wgsl.jinja`](build/webgpu/qkv-projection.wgsl.jinja)
|
| 71 |
+
|
| 72 |
+
## Use with `@huggingface/kernels`
|
| 73 |
+
|
| 74 |
+
The loader derives every required output's shape and logical dtype from the manifest contract and this call.
|
| 75 |
+
It then allocates the result tensors automatically.
|
| 76 |
+
|
| 77 |
+
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
| 78 |
+
|
| 79 |
+
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 80 |
+
|
| 81 |
+
```js
|
| 82 |
+
import { getKernel } from "@huggingface/kernels";
|
| 83 |
+
|
| 84 |
+
const kernel = await getKernel("webgpu-kernels/com.microsoft.MatMulNBitsQkv", { version: 1 });
|
| 85 |
+
const { qT, kT, vT } = await kernel({
|
| 86 |
+
aT: { data: aTData, shape: [2, 32] },
|
| 87 |
+
normScaleT: { data: normScaleTData, shape: [32] },
|
| 88 |
+
qBT: { data: qBTData, shape: [5, 1, 16] },
|
| 89 |
+
qScalesT: { data: qScalesTData, shape: [5, 1] },
|
| 90 |
+
kBT: { data: kBTData, shape: [3, 1, 16] },
|
| 91 |
+
kScalesT: { data: kScalesTData, shape: [3, 1] },
|
| 92 |
+
vBT: { data: vBTData, shape: [3, 1, 16] },
|
| 93 |
+
vScalesT: { data: vScalesTData, shape: [3, 1] },
|
| 94 |
+
}, {
|
| 95 |
+
attrs: {
|
| 96 |
+
K: 32,
|
| 97 |
+
Nq: 5,
|
| 98 |
+
Nkv: 3,
|
| 99 |
+
block_size: 32,
|
| 100 |
+
},
|
| 101 |
+
});
|
| 102 |
+
```
|
build/webgpu/bench.json
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "com.microsoft.MatMulNBitsQkv",
|
| 3 |
+
"tunableSpace": { "TILE_N": [4, 8, 16], "LANES": [4, 8, 16] },
|
| 4 |
+
"cases": [
|
| 5 |
+
{
|
| 6 |
+
"name": "qkv-q4-decode-k2048-nq2048-nkv512",
|
| 7 |
+
"preset": "smoke",
|
| 8 |
+
"vars": { "dtype": "float32" },
|
| 9 |
+
"attrs": { "K": 2048, "Nq": 2048, "Nkv": 512, "block_size": 32 },
|
| 10 |
+
"inputs": {
|
| 11 |
+
"aT": { "shape": [1, 2048], "dtype": "float32", "dist": "normal", "seed": 9101, "scale": 1 },
|
| 12 |
+
"normScaleT": { "shape": [2048], "dtype": "float32", "dist": "normal", "seed": 9102, "scale": 1 },
|
| 13 |
+
"qBT": { "shape": [2048, 64, 16], "dtype": "uint8", "dist": "uniform", "seed": 9103, "scale": 255 },
|
| 14 |
+
"qScalesT": { "shape": [2048, 64], "dtype": "float32", "dist": "normal", "seed": 9104, "scale": 0.05 },
|
| 15 |
+
"kBT": { "shape": [512, 64, 16], "dtype": "uint8", "dist": "uniform", "seed": 9105, "scale": 255 },
|
| 16 |
+
"kScalesT": { "shape": [512, 64], "dtype": "float32", "dist": "normal", "seed": 9106, "scale": 0.05 },
|
| 17 |
+
"vBT": { "shape": [512, 64, 16], "dtype": "uint8", "dist": "uniform", "seed": 9107, "scale": 255 },
|
| 18 |
+
"vScalesT": { "shape": [512, 64], "dtype": "float32", "dist": "normal", "seed": 9108, "scale": 0.05 }
|
| 19 |
+
},
|
| 20 |
+
"outputs": {
|
| 21 |
+
"qT": { "shape": [1, 2048], "dtype": "float32" },
|
| 22 |
+
"kT": { "shape": [1, 512], "dtype": "float32" },
|
| 23 |
+
"vT": { "shape": [1, 512], "dtype": "float32" }
|
| 24 |
+
},
|
| 25 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(2048 + 512 + 512) * 64 * 16 * 4" }] }
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"name": "qkv-q4-llama-decode-k4096-nq4096-nkv4096",
|
| 29 |
+
"preset": "model",
|
| 30 |
+
"provenance": {
|
| 31 |
+
"notes": "Llama class defaults (hidden_size 4096, num_attention_heads 32, no GQA so num_key_value_heads matches) at a decode step. Bytes are GPU storage, not the packed blob: this backend gives a uint8 tensor one byte per u32 element, so a 4-bit code costs 2 bytes of traffic and the projection moves four times its on-disk size. Counting the blob understated the traffic 4x and reported this kernel at a tenth of the bandwidth rail when it runs at about half."
|
| 32 |
+
},
|
| 33 |
+
"vars": { "dtype": "float32", "tokens": 1, "K": 4096, "Nq": 4096, "Nkv": 4096 },
|
| 34 |
+
"attrs": { "K": 4096, "Nq": 4096, "Nkv": 4096, "block_size": 32 },
|
| 35 |
+
"inputs": {
|
| 36 |
+
"aT": { "shape": [1, 4096], "dtype": "float32", "dist": "normal", "seed": 7100, "scale": 0.5 },
|
| 37 |
+
"normScaleT": {
|
| 38 |
+
"shape": [4096],
|
| 39 |
+
"dtype": "float32",
|
| 40 |
+
"dist": "uniform",
|
| 41 |
+
"seed": 7101,
|
| 42 |
+
"scale": 0.1,
|
| 43 |
+
"offset": 1
|
| 44 |
+
},
|
| 45 |
+
"qBT": { "shape": [4096, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7102, "min": 0, "max": 255 },
|
| 46 |
+
"qScalesT": {
|
| 47 |
+
"shape": [4096, 128],
|
| 48 |
+
"dtype": "float32",
|
| 49 |
+
"dist": "uniform",
|
| 50 |
+
"seed": 7103,
|
| 51 |
+
"min": 0.005,
|
| 52 |
+
"max": 0.05
|
| 53 |
+
},
|
| 54 |
+
"kBT": { "shape": [4096, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7104, "min": 0, "max": 255 },
|
| 55 |
+
"kScalesT": {
|
| 56 |
+
"shape": [4096, 128],
|
| 57 |
+
"dtype": "float32",
|
| 58 |
+
"dist": "uniform",
|
| 59 |
+
"seed": 7105,
|
| 60 |
+
"min": 0.005,
|
| 61 |
+
"max": 0.05
|
| 62 |
+
},
|
| 63 |
+
"vBT": { "shape": [4096, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7106, "min": 0, "max": 255 },
|
| 64 |
+
"vScalesT": {
|
| 65 |
+
"shape": [4096, 128],
|
| 66 |
+
"dtype": "float32",
|
| 67 |
+
"dist": "uniform",
|
| 68 |
+
"seed": 7107,
|
| 69 |
+
"min": 0.005,
|
| 70 |
+
"max": 0.05
|
| 71 |
+
}
|
| 72 |
+
},
|
| 73 |
+
"outputs": {
|
| 74 |
+
"qT": { "shape": [1, 4096], "dtype": "float32" },
|
| 75 |
+
"kT": { "shape": [1, 4096], "dtype": "float32" },
|
| 76 |
+
"vT": { "shape": [1, 4096], "dtype": "float32" }
|
| 77 |
+
},
|
| 78 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(args.Nq + 2 * args.Nkv) * args.K * 2" }] }
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"name": "qkv-q4-mistral-decode-k4096-nq4096-nkv1024",
|
| 82 |
+
"preset": "model",
|
| 83 |
+
"provenance": {
|
| 84 |
+
"notes": "Mistral class defaults (hidden_size 4096, 32 query heads, 8 key/value heads, head_dim 128) -- the GQA case, where K and V projections are a quarter of Q. Bytes are GPU storage, not the packed blob: this backend gives a uint8 tensor one byte per u32 element, so a 4-bit code costs 2 bytes of traffic and the projection moves four times its on-disk size. Counting the blob understated the traffic 4x and reported this kernel at a tenth of the bandwidth rail when it runs at about half."
|
| 85 |
+
},
|
| 86 |
+
"vars": { "dtype": "float32", "tokens": 1, "K": 4096, "Nq": 4096, "Nkv": 1024 },
|
| 87 |
+
"attrs": { "K": 4096, "Nq": 4096, "Nkv": 1024, "block_size": 32 },
|
| 88 |
+
"inputs": {
|
| 89 |
+
"aT": { "shape": [1, 4096], "dtype": "float32", "dist": "normal", "seed": 7200, "scale": 0.5 },
|
| 90 |
+
"normScaleT": {
|
| 91 |
+
"shape": [4096],
|
| 92 |
+
"dtype": "float32",
|
| 93 |
+
"dist": "uniform",
|
| 94 |
+
"seed": 7201,
|
| 95 |
+
"scale": 0.1,
|
| 96 |
+
"offset": 1
|
| 97 |
+
},
|
| 98 |
+
"qBT": { "shape": [4096, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7202, "min": 0, "max": 255 },
|
| 99 |
+
"qScalesT": {
|
| 100 |
+
"shape": [4096, 128],
|
| 101 |
+
"dtype": "float32",
|
| 102 |
+
"dist": "uniform",
|
| 103 |
+
"seed": 7203,
|
| 104 |
+
"min": 0.005,
|
| 105 |
+
"max": 0.05
|
| 106 |
+
},
|
| 107 |
+
"kBT": { "shape": [1024, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7204, "min": 0, "max": 255 },
|
| 108 |
+
"kScalesT": {
|
| 109 |
+
"shape": [1024, 128],
|
| 110 |
+
"dtype": "float32",
|
| 111 |
+
"dist": "uniform",
|
| 112 |
+
"seed": 7205,
|
| 113 |
+
"min": 0.005,
|
| 114 |
+
"max": 0.05
|
| 115 |
+
},
|
| 116 |
+
"vBT": { "shape": [1024, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7206, "min": 0, "max": 255 },
|
| 117 |
+
"vScalesT": {
|
| 118 |
+
"shape": [1024, 128],
|
| 119 |
+
"dtype": "float32",
|
| 120 |
+
"dist": "uniform",
|
| 121 |
+
"seed": 7207,
|
| 122 |
+
"min": 0.005,
|
| 123 |
+
"max": 0.05
|
| 124 |
+
}
|
| 125 |
+
},
|
| 126 |
+
"outputs": {
|
| 127 |
+
"qT": { "shape": [1, 4096], "dtype": "float32" },
|
| 128 |
+
"kT": { "shape": [1, 1024], "dtype": "float32" },
|
| 129 |
+
"vT": { "shape": [1, 1024], "dtype": "float32" }
|
| 130 |
+
},
|
| 131 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(args.Nq + 2 * args.Nkv) * args.K * 2" }] }
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"name": "qkv-q4-gemma3-decode-k2304-nq2048-nkv1024",
|
| 135 |
+
"preset": "model",
|
| 136 |
+
"provenance": {
|
| 137 |
+
"notes": "Gemma3 class defaults (hidden_size 2304, 8 query heads, 4 key/value heads, head_dim 256); the projection is wider than hidden, so K does not equal Nq. Bytes are GPU storage, not the packed blob: this backend gives a uint8 tensor one byte per u32 element, so a 4-bit code costs 2 bytes of traffic and the projection moves four times its on-disk size. Counting the blob understated the traffic 4x and reported this kernel at a tenth of the bandwidth rail when it runs at about half."
|
| 138 |
+
},
|
| 139 |
+
"vars": { "dtype": "float32", "tokens": 1, "K": 2304, "Nq": 2048, "Nkv": 1024 },
|
| 140 |
+
"attrs": { "K": 2304, "Nq": 2048, "Nkv": 1024, "block_size": 32 },
|
| 141 |
+
"inputs": {
|
| 142 |
+
"aT": { "shape": [1, 2304], "dtype": "float32", "dist": "normal", "seed": 7300, "scale": 0.5 },
|
| 143 |
+
"normScaleT": {
|
| 144 |
+
"shape": [2304],
|
| 145 |
+
"dtype": "float32",
|
| 146 |
+
"dist": "uniform",
|
| 147 |
+
"seed": 7301,
|
| 148 |
+
"scale": 0.1,
|
| 149 |
+
"offset": 1
|
| 150 |
+
},
|
| 151 |
+
"qBT": { "shape": [2048, 72, 16], "dtype": "uint8", "dist": "uniform", "seed": 7302, "min": 0, "max": 255 },
|
| 152 |
+
"qScalesT": {
|
| 153 |
+
"shape": [2048, 72],
|
| 154 |
+
"dtype": "float32",
|
| 155 |
+
"dist": "uniform",
|
| 156 |
+
"seed": 7303,
|
| 157 |
+
"min": 0.005,
|
| 158 |
+
"max": 0.05
|
| 159 |
+
},
|
| 160 |
+
"kBT": { "shape": [1024, 72, 16], "dtype": "uint8", "dist": "uniform", "seed": 7304, "min": 0, "max": 255 },
|
| 161 |
+
"kScalesT": {
|
| 162 |
+
"shape": [1024, 72],
|
| 163 |
+
"dtype": "float32",
|
| 164 |
+
"dist": "uniform",
|
| 165 |
+
"seed": 7305,
|
| 166 |
+
"min": 0.005,
|
| 167 |
+
"max": 0.05
|
| 168 |
+
},
|
| 169 |
+
"vBT": { "shape": [1024, 72, 16], "dtype": "uint8", "dist": "uniform", "seed": 7306, "min": 0, "max": 255 },
|
| 170 |
+
"vScalesT": {
|
| 171 |
+
"shape": [1024, 72],
|
| 172 |
+
"dtype": "float32",
|
| 173 |
+
"dist": "uniform",
|
| 174 |
+
"seed": 7307,
|
| 175 |
+
"min": 0.005,
|
| 176 |
+
"max": 0.05
|
| 177 |
+
}
|
| 178 |
+
},
|
| 179 |
+
"outputs": {
|
| 180 |
+
"qT": { "shape": [1, 2048], "dtype": "float32" },
|
| 181 |
+
"kT": { "shape": [1, 1024], "dtype": "float32" },
|
| 182 |
+
"vT": { "shape": [1, 1024], "dtype": "float32" }
|
| 183 |
+
},
|
| 184 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(args.Nq + 2 * args.Nkv) * args.K * 2" }] }
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"name": "qkv-q4-phi3-decode-k3072-nq3072-nkv3072",
|
| 188 |
+
"preset": "model",
|
| 189 |
+
"provenance": {
|
| 190 |
+
"notes": "Phi-3 class defaults (hidden_size 3072, num_attention_heads 32, no GQA). Bytes are GPU storage, not the packed blob: this backend gives a uint8 tensor one byte per u32 element, so a 4-bit code costs 2 bytes of traffic and the projection moves four times its on-disk size. Counting the blob understated the traffic 4x and reported this kernel at a tenth of the bandwidth rail when it runs at about half."
|
| 191 |
+
},
|
| 192 |
+
"vars": { "dtype": "float32", "tokens": 1, "K": 3072, "Nq": 3072, "Nkv": 3072 },
|
| 193 |
+
"attrs": { "K": 3072, "Nq": 3072, "Nkv": 3072, "block_size": 32 },
|
| 194 |
+
"inputs": {
|
| 195 |
+
"aT": { "shape": [1, 3072], "dtype": "float32", "dist": "normal", "seed": 7400, "scale": 0.5 },
|
| 196 |
+
"normScaleT": {
|
| 197 |
+
"shape": [3072],
|
| 198 |
+
"dtype": "float32",
|
| 199 |
+
"dist": "uniform",
|
| 200 |
+
"seed": 7401,
|
| 201 |
+
"scale": 0.1,
|
| 202 |
+
"offset": 1
|
| 203 |
+
},
|
| 204 |
+
"qBT": { "shape": [3072, 96, 16], "dtype": "uint8", "dist": "uniform", "seed": 7402, "min": 0, "max": 255 },
|
| 205 |
+
"qScalesT": {
|
| 206 |
+
"shape": [3072, 96],
|
| 207 |
+
"dtype": "float32",
|
| 208 |
+
"dist": "uniform",
|
| 209 |
+
"seed": 7403,
|
| 210 |
+
"min": 0.005,
|
| 211 |
+
"max": 0.05
|
| 212 |
+
},
|
| 213 |
+
"kBT": { "shape": [3072, 96, 16], "dtype": "uint8", "dist": "uniform", "seed": 7404, "min": 0, "max": 255 },
|
| 214 |
+
"kScalesT": {
|
| 215 |
+
"shape": [3072, 96],
|
| 216 |
+
"dtype": "float32",
|
| 217 |
+
"dist": "uniform",
|
| 218 |
+
"seed": 7405,
|
| 219 |
+
"min": 0.005,
|
| 220 |
+
"max": 0.05
|
| 221 |
+
},
|
| 222 |
+
"vBT": { "shape": [3072, 96, 16], "dtype": "uint8", "dist": "uniform", "seed": 7406, "min": 0, "max": 255 },
|
| 223 |
+
"vScalesT": {
|
| 224 |
+
"shape": [3072, 96],
|
| 225 |
+
"dtype": "float32",
|
| 226 |
+
"dist": "uniform",
|
| 227 |
+
"seed": 7407,
|
| 228 |
+
"min": 0.005,
|
| 229 |
+
"max": 0.05
|
| 230 |
+
}
|
| 231 |
+
},
|
| 232 |
+
"outputs": {
|
| 233 |
+
"qT": { "shape": [1, 3072], "dtype": "float32" },
|
| 234 |
+
"kT": { "shape": [1, 3072], "dtype": "float32" },
|
| 235 |
+
"vT": { "shape": [1, 3072], "dtype": "float32" }
|
| 236 |
+
},
|
| 237 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(args.Nq + 2 * args.Nkv) * args.K * 2" }] }
|
| 238 |
+
},
|
| 239 |
+
{
|
| 240 |
+
"name": "qkv-q4-llama-spec8-k4096-nq4096-nkv4096",
|
| 241 |
+
"preset": "model",
|
| 242 |
+
"provenance": {
|
| 243 |
+
"notes": "Llama class defaults with 8 rows, the shape speculative decoding verifies in one pass. Bytes are GPU storage, not the packed blob: this backend gives a uint8 tensor one byte per u32 element, so a 4-bit code costs 2 bytes of traffic and the projection moves four times its on-disk size. Counting the blob understated the traffic 4x and reported this kernel at a tenth of the bandwidth rail when it runs at about half."
|
| 244 |
+
},
|
| 245 |
+
"vars": { "dtype": "float32", "tokens": 8, "K": 4096, "Nq": 4096, "Nkv": 4096 },
|
| 246 |
+
"attrs": { "K": 4096, "Nq": 4096, "Nkv": 4096, "block_size": 32 },
|
| 247 |
+
"inputs": {
|
| 248 |
+
"aT": { "shape": [8, 4096], "dtype": "float32", "dist": "normal", "seed": 7500, "scale": 0.5 },
|
| 249 |
+
"normScaleT": {
|
| 250 |
+
"shape": [4096],
|
| 251 |
+
"dtype": "float32",
|
| 252 |
+
"dist": "uniform",
|
| 253 |
+
"seed": 7501,
|
| 254 |
+
"scale": 0.1,
|
| 255 |
+
"offset": 1
|
| 256 |
+
},
|
| 257 |
+
"qBT": { "shape": [4096, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7502, "min": 0, "max": 255 },
|
| 258 |
+
"qScalesT": {
|
| 259 |
+
"shape": [4096, 128],
|
| 260 |
+
"dtype": "float32",
|
| 261 |
+
"dist": "uniform",
|
| 262 |
+
"seed": 7503,
|
| 263 |
+
"min": 0.005,
|
| 264 |
+
"max": 0.05
|
| 265 |
+
},
|
| 266 |
+
"kBT": { "shape": [4096, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7504, "min": 0, "max": 255 },
|
| 267 |
+
"kScalesT": {
|
| 268 |
+
"shape": [4096, 128],
|
| 269 |
+
"dtype": "float32",
|
| 270 |
+
"dist": "uniform",
|
| 271 |
+
"seed": 7505,
|
| 272 |
+
"min": 0.005,
|
| 273 |
+
"max": 0.05
|
| 274 |
+
},
|
| 275 |
+
"vBT": { "shape": [4096, 128, 16], "dtype": "uint8", "dist": "uniform", "seed": 7506, "min": 0, "max": 255 },
|
| 276 |
+
"vScalesT": {
|
| 277 |
+
"shape": [4096, 128],
|
| 278 |
+
"dtype": "float32",
|
| 279 |
+
"dist": "uniform",
|
| 280 |
+
"seed": 7507,
|
| 281 |
+
"min": 0.005,
|
| 282 |
+
"max": 0.05
|
| 283 |
+
}
|
| 284 |
+
},
|
| 285 |
+
"outputs": {
|
| 286 |
+
"qT": { "shape": [8, 4096], "dtype": "float32" },
|
| 287 |
+
"kT": { "shape": [8, 4096], "dtype": "float32" },
|
| 288 |
+
"vT": { "shape": [8, 4096], "dtype": "float32" }
|
| 289 |
+
},
|
| 290 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(args.Nq + 2 * args.Nkv) * args.K * 2" }] }
|
| 291 |
+
}
|
| 292 |
+
]
|
| 293 |
+
}
|
build/webgpu/manifest.json
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"domain": "com.microsoft",
|
| 3 |
+
"name": "MatMulNBitsQkv",
|
| 4 |
+
"sinceVersion": 1,
|
| 5 |
+
"description": "Fuses RMS normalization with three block-quantized attention projections: `A_norm = RMSNorm(A + skip, norm_scale)` (or without `skip`), followed by Q, K, and V projections. The optional fourth output returns `A + skip`. Only 4-bit weights with `block_size = 32` are supported; projection biases, bfloat16, and non-default `accuracy_level` values are not implemented.",
|
| 6 |
+
"inputs": [
|
| 7 |
+
{
|
| 8 |
+
"role": "A",
|
| 9 |
+
"dtype": "T1",
|
| 10 |
+
"description": "Shared activation of rank 2 `(M, K)` or rank 3 `(batch, sequence, K)`; only the last axis is the reduction axis."
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"role": "skip",
|
| 14 |
+
"dtype": "T1",
|
| 15 |
+
"optional": true,
|
| 16 |
+
"description": "Residual added to A before the normalization, with A's shape."
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"role": "norm_scale",
|
| 20 |
+
"dtype": "T1",
|
| 21 |
+
"rank": 1,
|
| 22 |
+
"description": "Simplified-layer-normalization (RMS) gain of shape `[K]`."
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"role": "q_B",
|
| 26 |
+
"dtype": "T2",
|
| 27 |
+
"rank": 3,
|
| 28 |
+
"description": "Bit-packed uint8 Q weights of shape `(Nq, k_blocks, blob_size)`."
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"role": "q_scales",
|
| 32 |
+
"dtype": "T1",
|
| 33 |
+
"rank": 2,
|
| 34 |
+
"description": "Per-block Q scales of shape `(Nq, k_blocks)`. Quantization is symmetric: there is no zero-point input, so codes are offset by the midpoint `2^(bits - 1)`."
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"role": "k_B",
|
| 38 |
+
"dtype": "T2",
|
| 39 |
+
"rank": 3,
|
| 40 |
+
"description": "Bit-packed K weights of shape `(Nkv, k_blocks, blob_size)`."
|
| 41 |
+
},
|
| 42 |
+
{ "role": "k_scales", "dtype": "T1", "rank": 2, "description": "Per-block K scales of shape `(Nkv, k_blocks)`." },
|
| 43 |
+
{
|
| 44 |
+
"role": "v_B",
|
| 45 |
+
"dtype": "T2",
|
| 46 |
+
"rank": 3,
|
| 47 |
+
"description": "Bit-packed V weights of shape `(Nkv, k_blocks, blob_size)`."
|
| 48 |
+
},
|
| 49 |
+
{ "role": "v_scales", "dtype": "T1", "rank": 2, "description": "Per-block V scales of shape `(Nkv, k_blocks)`." }
|
| 50 |
+
],
|
| 51 |
+
"outputs": [
|
| 52 |
+
{
|
| 53 |
+
"role": "Q",
|
| 54 |
+
"dtype": "T1",
|
| 55 |
+
"rank": "ranks.aT",
|
| 56 |
+
"shape": "shapes.aT[:-1] + [attrs.Nq]",
|
| 57 |
+
"description": "Query projection: A's leading axes with a trailing Nq."
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"role": "K",
|
| 61 |
+
"dtype": "T1",
|
| 62 |
+
"rank": "ranks.aT",
|
| 63 |
+
"shape": "shapes.aT[:-1] + [attrs.Nkv]",
|
| 64 |
+
"description": "Key projection: A's leading axes with a trailing Nkv."
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"role": "V",
|
| 68 |
+
"dtype": "T1",
|
| 69 |
+
"rank": "ranks.aT",
|
| 70 |
+
"shape": "shapes.aT[:-1] + [attrs.Nkv]",
|
| 71 |
+
"description": "Value projection: A's leading axes with a trailing Nkv."
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"role": "input_skip_bias_sum",
|
| 75 |
+
"dtype": "T1",
|
| 76 |
+
"rank": "ranks.aT",
|
| 77 |
+
"optional": true,
|
| 78 |
+
"shape": "shapes.aT",
|
| 79 |
+
"description": "The residual sum A + skip, with A's shape. Requires the skip input."
|
| 80 |
+
}
|
| 81 |
+
],
|
| 82 |
+
"attributes": { "accuracy_level": 0, "bits": 4, "epsilon": 9.999999974752427e-7 },
|
| 83 |
+
"attributeDescriptions": {
|
| 84 |
+
"K": "Input feature dimension shared by the normalized input and all projection weights.",
|
| 85 |
+
"Nq": "Output feature dimension of the Q projection.",
|
| 86 |
+
"Nkv": "Output feature dimension shared by the K and V projections.",
|
| 87 |
+
"accuracy_level": "Minimum internal accuracy level, following MatMulNBits semantics; this implementation supports the standard default 0.",
|
| 88 |
+
"bits": "Bit width used to quantize all three weight matrices; only 4 is supported.",
|
| 89 |
+
"block_size": "Size of each quantization block along K; only 32 is supported.",
|
| 90 |
+
"epsilon": "Epsilon used by the simplified layer-normalization reduction."
|
| 91 |
+
},
|
| 92 |
+
"attributeConstraints": {
|
| 93 |
+
"K": { "required": true },
|
| 94 |
+
"Nq": { "required": true },
|
| 95 |
+
"Nkv": { "required": true },
|
| 96 |
+
"accuracy_level": { "values": [0] },
|
| 97 |
+
"bits": { "values": [4] },
|
| 98 |
+
"block_size": { "required": true, "values": [32] }
|
| 99 |
+
},
|
| 100 |
+
"typeConstraints": { "T1": ["float32", "float16"], "T2": ["uint8"] },
|
| 101 |
+
"args": {
|
| 102 |
+
"aT": { "kind": "tensor", "semantic": "A", "role": "input" },
|
| 103 |
+
"skipT": { "kind": "tensor", "semantic": "skip", "role": "input", "required": false },
|
| 104 |
+
"normScaleT": { "kind": "tensor", "semantic": "norm_scale", "role": "weights" },
|
| 105 |
+
"qBT": { "kind": "tensor", "semantic": "q_B", "role": "weights" },
|
| 106 |
+
"qScalesT": { "kind": "tensor", "semantic": "q_scales", "role": "weights" },
|
| 107 |
+
"kBT": { "kind": "tensor", "semantic": "k_B", "role": "weights" },
|
| 108 |
+
"kScalesT": { "kind": "tensor", "semantic": "k_scales", "role": "weights" },
|
| 109 |
+
"vBT": { "kind": "tensor", "semantic": "v_B", "role": "weights" },
|
| 110 |
+
"vScalesT": { "kind": "tensor", "semantic": "v_scales", "role": "weights" },
|
| 111 |
+
"qT": { "kind": "tensor", "semantic": "Q", "role": "output" },
|
| 112 |
+
"kT": { "kind": "tensor", "semantic": "K", "role": "output" },
|
| 113 |
+
"vT": { "kind": "tensor", "semantic": "V", "role": "output" },
|
| 114 |
+
"residualT": { "kind": "tensor", "semantic": "input_skip_bias_sum", "role": "output", "required": false }
|
| 115 |
+
},
|
| 116 |
+
"tunables": { "TILE_N": 8, "LANES": 8, "NORM_WORKGROUP_SIZE": 128, "ROW_TILE": 8 },
|
| 117 |
+
"derive": {
|
| 118 |
+
"aRows": "numel(shapes.aT) / max(1, attrs.K)",
|
| 119 |
+
"rowTile": "1 if aRows <= 1 else min(aRows, tunables.ROW_TILE)",
|
| 120 |
+
"rowGroups": "ceilDiv(aRows, rowTile)",
|
| 121 |
+
"kBlocks": "dim(shapes.qBT, 1)",
|
| 122 |
+
"blobSize": "dim(shapes.qBT, 2)",
|
| 123 |
+
"codesPerByte": "8 / attrs.bits",
|
| 124 |
+
"codeMask": "3 if attrs.bits == 2 else (15 if attrs.bits == 4 else 255)",
|
| 125 |
+
"pairSharesWord": "codesPerByte >= 2",
|
| 126 |
+
"epsilonValue": "attrs.epsilon",
|
| 127 |
+
"weightShapeOk": "ranks.qBT == 3 and ranks.kBT == 3 and ranks.vBT == 3 and dim(shapes.qBT, 0) == attrs.Nq and dim(shapes.kBT, 0) == attrs.Nkv and dim(shapes.vBT, 0) == attrs.Nkv and dim(shapes.kBT, 1) == kBlocks and dim(shapes.vBT, 1) == kBlocks and dim(shapes.kBT, 2) == blobSize and dim(shapes.vBT, 2) == blobSize and kBlocks == ceilDiv(attrs.K, attrs.block_size) and blobSize * 8 == attrs.block_size * attrs.bits",
|
| 128 |
+
"scaleShapeOk": "ranks.qScalesT == 2 and ranks.kScalesT == 2 and ranks.vScalesT == 2 and dim(shapes.qScalesT, 0) == attrs.Nq and dim(shapes.qScalesT, 1) == kBlocks and dim(shapes.kScalesT, 0) == attrs.Nkv and dim(shapes.kScalesT, 1) == kBlocks and dim(shapes.vScalesT, 0) == attrs.Nkv and dim(shapes.vScalesT, 1) == kBlocks",
|
| 129 |
+
"ioShapeOk": "(ranks.aT == 2 or ranks.aT == 3) and dim(shapes.aT, ranks.aT - 1) == attrs.K and ranks.qT == ranks.aT and ranks.kT == ranks.aT and ranks.vT == ranks.aT and dim(shapes.qT, ranks.qT - 1) == attrs.Nq and dim(shapes.kT, ranks.kT - 1) == attrs.Nkv and dim(shapes.vT, ranks.vT - 1) == attrs.Nkv and sameShape(prefix(shapes.qT, ranks.qT - 1), prefix(shapes.aT, ranks.aT - 1)) and sameShape(prefix(shapes.kT, ranks.kT - 1), prefix(shapes.aT, ranks.aT - 1)) and sameShape(prefix(shapes.vT, ranks.vT - 1), prefix(shapes.aT, ranks.aT - 1))",
|
| 130 |
+
"dtypeOk": "tensorDtypes.qBT == \"uint8\" and tensorDtypes.kBT == \"uint8\" and tensorDtypes.vBT == \"uint8\" and tensorDtypes.qScalesT == tensorDtypes.aT and tensorDtypes.kScalesT == tensorDtypes.aT and tensorDtypes.vScalesT == tensorDtypes.aT and tensorDtypes.qT == tensorDtypes.aT and tensorDtypes.kT == tensorDtypes.aT and tensorDtypes.vT == tensorDtypes.aT and tensorDtypes.normScaleT == tensorDtypes.aT and f16Ok(tensorDtypes.aT)",
|
| 131 |
+
"lanesPow2": "tunables.LANES == pow2ceil(tunables.LANES)",
|
| 132 |
+
"normContractOk": "ranks.normScaleT == 1 and dim(shapes.normScaleT, 0) == attrs.K and (sameShape(shapes.skipT, shapes.aT) and tensorDtypes.skipT == tensorDtypes.aT if present.skipT else true) and (sameShape(shapes.residualT, shapes.aT) and tensorDtypes.residualT == tensorDtypes.aT and present.skipT if present.residualT else true)",
|
| 133 |
+
"qkvShapeOk": "weightShapeOk and scaleShapeOk and ioShapeOk and dtypeOk and lanesPow2 and normContractOk and pairSharesWord and attrs.K > 0 and attrs.Nq > 0 and attrs.Nkv > 0",
|
| 134 |
+
"projectionTiles": "ceilDiv(attrs.Nq, tunables.TILE_N) + 2 * ceilDiv(attrs.Nkv, tunables.TILE_N)",
|
| 135 |
+
"dispatchFits": "projectionTiles <= device.limits.maxComputeWorkgroupsPerDimension and aRows <= device.limits.maxComputeWorkgroupsPerDimension and tunables.TILE_N * tunables.LANES <= device.limits.maxComputeInvocationsPerWorkgroup and tunables.TILE_N * tunables.LANES <= device.limits.maxComputeWorkgroupSizeX and tunables.NORM_WORKGROUP_SIZE <= device.limits.maxComputeInvocationsPerWorkgroup and tunables.NORM_WORKGROUP_SIZE <= device.limits.maxComputeWorkgroupSizeX"
|
| 136 |
+
},
|
| 137 |
+
"constants": {
|
| 138 |
+
"aScalar": "\"f16\" if tensorDtypes.aT == \"float16\" else \"f32\"",
|
| 139 |
+
"scalar": "\"f16\" if tensorDtypes.aT == \"float16\" else \"f32\"",
|
| 140 |
+
"usesF16": "tensorDtypes.aT == \"float16\"",
|
| 141 |
+
"K": "attrs.K",
|
| 142 |
+
"nq": "attrs.Nq",
|
| 143 |
+
"nkv": "attrs.Nkv",
|
| 144 |
+
"blockSize": "attrs.block_size",
|
| 145 |
+
"kBlocks": "kBlocks",
|
| 146 |
+
"blobSize": "blobSize",
|
| 147 |
+
"bits": "attrs.bits",
|
| 148 |
+
"codesPerByte": "codesPerByte",
|
| 149 |
+
"codeMask": "codeMask",
|
| 150 |
+
"defaultZero": "\"8.0\"",
|
| 151 |
+
"tileN": "tunables.TILE_N",
|
| 152 |
+
"lanes": "tunables.LANES",
|
| 153 |
+
"hidden": "attrs.K",
|
| 154 |
+
"workgroupSize": "tunables.NORM_WORKGROUP_SIZE",
|
| 155 |
+
"epsilon": "epsilonValue",
|
| 156 |
+
"hasSkip": "present.skipT",
|
| 157 |
+
"writeResidual": "present.residualT",
|
| 158 |
+
"K_LEN": "attrs.K",
|
| 159 |
+
"rowTile": "rowTile",
|
| 160 |
+
"rows": "aRows"
|
| 161 |
+
},
|
| 162 |
+
"bindingSets": {
|
| 163 |
+
"normFull": [
|
| 164 |
+
{
|
| 165 |
+
"name": "a",
|
| 166 |
+
"arg": "aT",
|
| 167 |
+
"semantic": "A",
|
| 168 |
+
"buffer": { "type": "read-only-storage" },
|
| 169 |
+
"elementType": "$aScalar"
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"name": "skip",
|
| 173 |
+
"arg": "skipT",
|
| 174 |
+
"semantic": "skip",
|
| 175 |
+
"buffer": { "type": "read-only-storage" },
|
| 176 |
+
"elementType": "$aScalar"
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"name": "norm_scale",
|
| 180 |
+
"arg": "normScaleT",
|
| 181 |
+
"semantic": "norm_scale",
|
| 182 |
+
"buffer": { "type": "read-only-storage" },
|
| 183 |
+
"elementType": "$aScalar",
|
| 184 |
+
"length": "$K_LEN"
|
| 185 |
+
},
|
| 186 |
+
{ "name": "normed", "semantic": "normedA", "buffer": { "type": "storage" }, "elementType": "f32" },
|
| 187 |
+
{
|
| 188 |
+
"name": "residual",
|
| 189 |
+
"arg": "residualT",
|
| 190 |
+
"semantic": "input_skip_bias_sum",
|
| 191 |
+
"buffer": { "type": "storage" },
|
| 192 |
+
"elementType": "$aScalar"
|
| 193 |
+
},
|
| 194 |
+
{
|
| 195 |
+
"name": "params",
|
| 196 |
+
"semantic": "kernel.params",
|
| 197 |
+
"buffer": { "type": "uniform" },
|
| 198 |
+
"struct": { "name": "Params", "fields": [{ "name": "rows", "type": "u32", "value": "aRows" }] }
|
| 199 |
+
}
|
| 200 |
+
],
|
| 201 |
+
"normSkip": [
|
| 202 |
+
{
|
| 203 |
+
"name": "a",
|
| 204 |
+
"arg": "aT",
|
| 205 |
+
"semantic": "A",
|
| 206 |
+
"buffer": { "type": "read-only-storage" },
|
| 207 |
+
"elementType": "$aScalar"
|
| 208 |
+
},
|
| 209 |
+
{
|
| 210 |
+
"name": "skip",
|
| 211 |
+
"arg": "skipT",
|
| 212 |
+
"semantic": "skip",
|
| 213 |
+
"buffer": { "type": "read-only-storage" },
|
| 214 |
+
"elementType": "$aScalar"
|
| 215 |
+
},
|
| 216 |
+
{
|
| 217 |
+
"name": "norm_scale",
|
| 218 |
+
"arg": "normScaleT",
|
| 219 |
+
"semantic": "norm_scale",
|
| 220 |
+
"buffer": { "type": "read-only-storage" },
|
| 221 |
+
"elementType": "$aScalar",
|
| 222 |
+
"length": "$K_LEN"
|
| 223 |
+
},
|
| 224 |
+
{ "name": "normed", "semantic": "normedA", "buffer": { "type": "storage" }, "elementType": "f32" },
|
| 225 |
+
{
|
| 226 |
+
"name": "params",
|
| 227 |
+
"semantic": "kernel.params",
|
| 228 |
+
"buffer": { "type": "uniform" },
|
| 229 |
+
"struct": { "name": "Params", "fields": [{ "name": "rows", "type": "u32", "value": "aRows" }] }
|
| 230 |
+
}
|
| 231 |
+
],
|
| 232 |
+
"normOnly": [
|
| 233 |
+
{
|
| 234 |
+
"name": "a",
|
| 235 |
+
"arg": "aT",
|
| 236 |
+
"semantic": "A",
|
| 237 |
+
"buffer": { "type": "read-only-storage" },
|
| 238 |
+
"elementType": "$aScalar"
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"name": "norm_scale",
|
| 242 |
+
"arg": "normScaleT",
|
| 243 |
+
"semantic": "norm_scale",
|
| 244 |
+
"buffer": { "type": "read-only-storage" },
|
| 245 |
+
"elementType": "$aScalar",
|
| 246 |
+
"length": "$K_LEN"
|
| 247 |
+
},
|
| 248 |
+
{ "name": "normed", "semantic": "normedA", "buffer": { "type": "storage" }, "elementType": "f32" },
|
| 249 |
+
{
|
| 250 |
+
"name": "params",
|
| 251 |
+
"semantic": "kernel.params",
|
| 252 |
+
"buffer": { "type": "uniform" },
|
| 253 |
+
"struct": { "name": "Params", "fields": [{ "name": "rows", "type": "u32", "value": "aRows" }] }
|
| 254 |
+
}
|
| 255 |
+
],
|
| 256 |
+
"projection": [
|
| 257 |
+
{ "name": "normed", "semantic": "normedA", "buffer": { "type": "read-only-storage" }, "elementType": "f32" },
|
| 258 |
+
{
|
| 259 |
+
"name": "q_b",
|
| 260 |
+
"arg": "qBT",
|
| 261 |
+
"semantic": "q_B",
|
| 262 |
+
"buffer": { "type": "read-only-storage" },
|
| 263 |
+
"elementType": "u32"
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"name": "q_scales",
|
| 267 |
+
"arg": "qScalesT",
|
| 268 |
+
"semantic": "q_scales",
|
| 269 |
+
"buffer": { "type": "read-only-storage" },
|
| 270 |
+
"elementType": "$aScalar"
|
| 271 |
+
},
|
| 272 |
+
{
|
| 273 |
+
"name": "k_b",
|
| 274 |
+
"arg": "kBT",
|
| 275 |
+
"semantic": "k_B",
|
| 276 |
+
"buffer": { "type": "read-only-storage" },
|
| 277 |
+
"elementType": "u32"
|
| 278 |
+
},
|
| 279 |
+
{
|
| 280 |
+
"name": "k_scales",
|
| 281 |
+
"arg": "kScalesT",
|
| 282 |
+
"semantic": "k_scales",
|
| 283 |
+
"buffer": { "type": "read-only-storage" },
|
| 284 |
+
"elementType": "$aScalar"
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"name": "v_b",
|
| 288 |
+
"arg": "vBT",
|
| 289 |
+
"semantic": "v_B",
|
| 290 |
+
"buffer": { "type": "read-only-storage" },
|
| 291 |
+
"elementType": "u32"
|
| 292 |
+
},
|
| 293 |
+
{
|
| 294 |
+
"name": "v_scales",
|
| 295 |
+
"arg": "vScalesT",
|
| 296 |
+
"semantic": "v_scales",
|
| 297 |
+
"buffer": { "type": "read-only-storage" },
|
| 298 |
+
"elementType": "$aScalar"
|
| 299 |
+
},
|
| 300 |
+
{ "name": "q", "arg": "qT", "semantic": "Q", "buffer": { "type": "storage" }, "elementType": "$aScalar" },
|
| 301 |
+
{ "name": "k", "arg": "kT", "semantic": "K", "buffer": { "type": "storage" }, "elementType": "$aScalar" },
|
| 302 |
+
{ "name": "v", "arg": "vT", "semantic": "V", "buffer": { "type": "storage" }, "elementType": "$aScalar" }
|
| 303 |
+
],
|
| 304 |
+
"projectionQ": [
|
| 305 |
+
{ "name": "normed", "semantic": "normedA", "buffer": { "type": "read-only-storage" }, "elementType": "f32" },
|
| 306 |
+
{
|
| 307 |
+
"name": "q_b",
|
| 308 |
+
"arg": "qBT",
|
| 309 |
+
"semantic": "q_B",
|
| 310 |
+
"buffer": { "type": "read-only-storage" },
|
| 311 |
+
"elementType": "u32"
|
| 312 |
+
},
|
| 313 |
+
{
|
| 314 |
+
"name": "q_scales",
|
| 315 |
+
"arg": "qScalesT",
|
| 316 |
+
"semantic": "q_scales",
|
| 317 |
+
"buffer": { "type": "read-only-storage" },
|
| 318 |
+
"elementType": "$aScalar"
|
| 319 |
+
},
|
| 320 |
+
{ "name": "q", "arg": "qT", "semantic": "Q", "buffer": { "type": "storage" }, "elementType": "$aScalar" }
|
| 321 |
+
],
|
| 322 |
+
"projectionK": [
|
| 323 |
+
{ "name": "normed", "semantic": "normedA", "buffer": { "type": "read-only-storage" }, "elementType": "f32" },
|
| 324 |
+
{
|
| 325 |
+
"name": "k_b",
|
| 326 |
+
"arg": "kBT",
|
| 327 |
+
"semantic": "k_B",
|
| 328 |
+
"buffer": { "type": "read-only-storage" },
|
| 329 |
+
"elementType": "u32"
|
| 330 |
+
},
|
| 331 |
+
{
|
| 332 |
+
"name": "k_scales",
|
| 333 |
+
"arg": "kScalesT",
|
| 334 |
+
"semantic": "k_scales",
|
| 335 |
+
"buffer": { "type": "read-only-storage" },
|
| 336 |
+
"elementType": "$aScalar"
|
| 337 |
+
},
|
| 338 |
+
{ "name": "k", "arg": "kT", "semantic": "K", "buffer": { "type": "storage" }, "elementType": "$aScalar" }
|
| 339 |
+
],
|
| 340 |
+
"projectionV": [
|
| 341 |
+
{ "name": "normed", "semantic": "normedA", "buffer": { "type": "read-only-storage" }, "elementType": "f32" },
|
| 342 |
+
{
|
| 343 |
+
"name": "v_b",
|
| 344 |
+
"arg": "vBT",
|
| 345 |
+
"semantic": "v_B",
|
| 346 |
+
"buffer": { "type": "read-only-storage" },
|
| 347 |
+
"elementType": "u32"
|
| 348 |
+
},
|
| 349 |
+
{
|
| 350 |
+
"name": "v_scales",
|
| 351 |
+
"arg": "vScalesT",
|
| 352 |
+
"semantic": "v_scales",
|
| 353 |
+
"buffer": { "type": "read-only-storage" },
|
| 354 |
+
"elementType": "$aScalar"
|
| 355 |
+
},
|
| 356 |
+
{ "name": "v", "arg": "vT", "semantic": "V", "buffer": { "type": "storage" }, "elementType": "$aScalar" }
|
| 357 |
+
]
|
| 358 |
+
},
|
| 359 |
+
"variants": [
|
| 360 |
+
{
|
| 361 |
+
"id": "norm",
|
| 362 |
+
"priority": 20,
|
| 363 |
+
"when": ["qkvShapeOk", "dispatchFits", "not present.skipT", "not present.residualT"],
|
| 364 |
+
"intermediates": [{ "id": "normedA", "dtype": "float32", "shape": "[numel(shapes.aT)]" }],
|
| 365 |
+
"passes": [
|
| 366 |
+
{
|
| 367 |
+
"id": "norm",
|
| 368 |
+
"name": "MatMulNBitsQkv.RmsNorm",
|
| 369 |
+
"shader": "matmul-nbits-fused-rms-norm.wgsl.jinja",
|
| 370 |
+
"bindings": "normOnly",
|
| 371 |
+
"dispatch": { "workgroups": "aRows" }
|
| 372 |
+
},
|
| 373 |
+
{
|
| 374 |
+
"id": "main",
|
| 375 |
+
"name": "MatMulNBitsQkv.Projection",
|
| 376 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"\"" } },
|
| 377 |
+
"bindings": "projection",
|
| 378 |
+
"dispatch": { "x": "projectionTiles", "y": "rowGroups" }
|
| 379 |
+
}
|
| 380 |
+
]
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"id": "split_norm",
|
| 384 |
+
"priority": 10,
|
| 385 |
+
"when": ["qkvShapeOk", "dispatchFits", "not present.skipT", "not present.residualT"],
|
| 386 |
+
"intermediates": [{ "id": "normedA", "dtype": "float32", "shape": "[numel(shapes.aT)]" }],
|
| 387 |
+
"passes": [
|
| 388 |
+
{
|
| 389 |
+
"id": "norm",
|
| 390 |
+
"name": "MatMulNBitsQkv.RmsNorm",
|
| 391 |
+
"shader": "matmul-nbits-fused-rms-norm.wgsl.jinja",
|
| 392 |
+
"bindings": "normOnly",
|
| 393 |
+
"dispatch": { "workgroups": "aRows" }
|
| 394 |
+
},
|
| 395 |
+
{
|
| 396 |
+
"id": "q",
|
| 397 |
+
"name": "MatMulNBitsQkv.ProjectionQ",
|
| 398 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"q\"" } },
|
| 399 |
+
"bindings": "projectionQ",
|
| 400 |
+
"dispatch": { "x": "ceilDiv(attrs.Nq, tunables.TILE_N)", "y": "rowGroups" }
|
| 401 |
+
},
|
| 402 |
+
{
|
| 403 |
+
"id": "k",
|
| 404 |
+
"name": "MatMulNBitsQkv.ProjectionK",
|
| 405 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"k\"" } },
|
| 406 |
+
"bindings": "projectionK",
|
| 407 |
+
"dispatch": { "x": "ceilDiv(attrs.Nkv, tunables.TILE_N)", "y": "rowGroups" }
|
| 408 |
+
},
|
| 409 |
+
{
|
| 410 |
+
"id": "v",
|
| 411 |
+
"name": "MatMulNBitsQkv.ProjectionV",
|
| 412 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"v\"" } },
|
| 413 |
+
"bindings": "projectionV",
|
| 414 |
+
"dispatch": { "x": "ceilDiv(attrs.Nkv, tunables.TILE_N)", "y": "rowGroups" }
|
| 415 |
+
}
|
| 416 |
+
]
|
| 417 |
+
},
|
| 418 |
+
{
|
| 419 |
+
"id": "skip",
|
| 420 |
+
"priority": 20,
|
| 421 |
+
"when": ["qkvShapeOk", "dispatchFits", "present.skipT", "not present.residualT"],
|
| 422 |
+
"intermediates": [{ "id": "normedA", "dtype": "float32", "shape": "[numel(shapes.aT)]" }],
|
| 423 |
+
"passes": [
|
| 424 |
+
{
|
| 425 |
+
"id": "norm",
|
| 426 |
+
"name": "MatMulNBitsQkv.RmsNorm",
|
| 427 |
+
"shader": "matmul-nbits-fused-rms-norm.wgsl.jinja",
|
| 428 |
+
"bindings": "normSkip",
|
| 429 |
+
"dispatch": { "workgroups": "aRows" }
|
| 430 |
+
},
|
| 431 |
+
{
|
| 432 |
+
"id": "main",
|
| 433 |
+
"name": "MatMulNBitsQkv.Projection",
|
| 434 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"\"" } },
|
| 435 |
+
"bindings": "projection",
|
| 436 |
+
"dispatch": { "x": "projectionTiles", "y": "rowGroups" }
|
| 437 |
+
}
|
| 438 |
+
]
|
| 439 |
+
},
|
| 440 |
+
{
|
| 441 |
+
"id": "split_skip",
|
| 442 |
+
"priority": 10,
|
| 443 |
+
"when": ["qkvShapeOk", "dispatchFits", "present.skipT", "not present.residualT"],
|
| 444 |
+
"intermediates": [{ "id": "normedA", "dtype": "float32", "shape": "[numel(shapes.aT)]" }],
|
| 445 |
+
"passes": [
|
| 446 |
+
{
|
| 447 |
+
"id": "norm",
|
| 448 |
+
"name": "MatMulNBitsQkv.RmsNorm",
|
| 449 |
+
"shader": "matmul-nbits-fused-rms-norm.wgsl.jinja",
|
| 450 |
+
"bindings": "normSkip",
|
| 451 |
+
"dispatch": { "workgroups": "aRows" }
|
| 452 |
+
},
|
| 453 |
+
{
|
| 454 |
+
"id": "q",
|
| 455 |
+
"name": "MatMulNBitsQkv.ProjectionQ",
|
| 456 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"q\"" } },
|
| 457 |
+
"bindings": "projectionQ",
|
| 458 |
+
"dispatch": { "x": "ceilDiv(attrs.Nq, tunables.TILE_N)", "y": "rowGroups" }
|
| 459 |
+
},
|
| 460 |
+
{
|
| 461 |
+
"id": "k",
|
| 462 |
+
"name": "MatMulNBitsQkv.ProjectionK",
|
| 463 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"k\"" } },
|
| 464 |
+
"bindings": "projectionK",
|
| 465 |
+
"dispatch": { "x": "ceilDiv(attrs.Nkv, tunables.TILE_N)", "y": "rowGroups" }
|
| 466 |
+
},
|
| 467 |
+
{
|
| 468 |
+
"id": "v",
|
| 469 |
+
"name": "MatMulNBitsQkv.ProjectionV",
|
| 470 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"v\"" } },
|
| 471 |
+
"bindings": "projectionV",
|
| 472 |
+
"dispatch": { "x": "ceilDiv(attrs.Nkv, tunables.TILE_N)", "y": "rowGroups" }
|
| 473 |
+
}
|
| 474 |
+
]
|
| 475 |
+
},
|
| 476 |
+
{
|
| 477 |
+
"id": "skipsum",
|
| 478 |
+
"priority": 20,
|
| 479 |
+
"when": ["qkvShapeOk", "dispatchFits", "present.skipT", "present.residualT"],
|
| 480 |
+
"intermediates": [{ "id": "normedA", "dtype": "float32", "shape": "[numel(shapes.aT)]" }],
|
| 481 |
+
"passes": [
|
| 482 |
+
{
|
| 483 |
+
"id": "norm",
|
| 484 |
+
"name": "MatMulNBitsQkv.RmsNorm",
|
| 485 |
+
"shader": "matmul-nbits-fused-rms-norm.wgsl.jinja",
|
| 486 |
+
"bindings": "normFull",
|
| 487 |
+
"dispatch": { "workgroups": "aRows" }
|
| 488 |
+
},
|
| 489 |
+
{
|
| 490 |
+
"id": "main",
|
| 491 |
+
"name": "MatMulNBitsQkv.Projection",
|
| 492 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"\"" } },
|
| 493 |
+
"bindings": "projection",
|
| 494 |
+
"dispatch": { "x": "projectionTiles", "y": "rowGroups" }
|
| 495 |
+
}
|
| 496 |
+
]
|
| 497 |
+
},
|
| 498 |
+
{
|
| 499 |
+
"id": "split_skipsum",
|
| 500 |
+
"priority": 10,
|
| 501 |
+
"when": ["qkvShapeOk", "dispatchFits", "present.skipT", "present.residualT"],
|
| 502 |
+
"intermediates": [{ "id": "normedA", "dtype": "float32", "shape": "[numel(shapes.aT)]" }],
|
| 503 |
+
"passes": [
|
| 504 |
+
{
|
| 505 |
+
"id": "norm",
|
| 506 |
+
"name": "MatMulNBitsQkv.RmsNorm",
|
| 507 |
+
"shader": "matmul-nbits-fused-rms-norm.wgsl.jinja",
|
| 508 |
+
"bindings": "normFull",
|
| 509 |
+
"dispatch": { "workgroups": "aRows" }
|
| 510 |
+
},
|
| 511 |
+
{
|
| 512 |
+
"id": "q",
|
| 513 |
+
"name": "MatMulNBitsQkv.ProjectionQ",
|
| 514 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"q\"" } },
|
| 515 |
+
"bindings": "projectionQ",
|
| 516 |
+
"dispatch": { "x": "ceilDiv(attrs.Nq, tunables.TILE_N)", "y": "rowGroups" }
|
| 517 |
+
},
|
| 518 |
+
{
|
| 519 |
+
"id": "k",
|
| 520 |
+
"name": "MatMulNBitsQkv.ProjectionK",
|
| 521 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"k\"" } },
|
| 522 |
+
"bindings": "projectionK",
|
| 523 |
+
"dispatch": { "x": "ceilDiv(attrs.Nkv, tunables.TILE_N)", "y": "rowGroups" }
|
| 524 |
+
},
|
| 525 |
+
{
|
| 526 |
+
"id": "v",
|
| 527 |
+
"name": "MatMulNBitsQkv.ProjectionV",
|
| 528 |
+
"source": { "shader": "qkv-projection.wgsl.jinja", "inputs": { "singleProjection": "\"v\"" } },
|
| 529 |
+
"bindings": "projectionV",
|
| 530 |
+
"dispatch": { "x": "ceilDiv(attrs.Nkv, tunables.TILE_N)", "y": "rowGroups" }
|
| 531 |
+
}
|
| 532 |
+
]
|
| 533 |
+
}
|
| 534 |
+
]
|
| 535 |
+
}
|
build/webgpu/matmul-nbits-fused-rms-norm.wgsl.jinja
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
|
| 6 |
+
// Shared MatMulNBits MLP/QKV normalization pass.
|
| 7 |
+
// normed[row, d] = (A + skip)[row, d] * inverseSqrt(mean_d((A + skip)^2) + eps) * norm_scale[d]
|
| 8 |
+
// One workgroup owns one row. Every intermediate stays in f32 and `normed` is an
|
| 9 |
+
// f32 scratch tensor, so the projection pass reads exactly what the fused
|
| 10 |
+
// single-dispatch kernel keeps in registers -- the two paths agree for float16
|
| 11 |
+
// inputs instead of differing by one narrowing.
|
| 12 |
+
const HIDDEN: u32 = {{ hidden }}u;
|
| 13 |
+
const WG: u32 = {{ workgroupSize }}u;
|
| 14 |
+
const EPSILON: f32 = {{ epsilon }};
|
| 15 |
+
|
| 16 |
+
var<workgroup> partial: array<f32, WG>;
|
| 17 |
+
|
| 18 |
+
{% macro wgsl_tree_fold_stmt(a, op, idx, svar) %}
|
| 19 |
+
{% if op == "max" %}
|
| 20 |
+
{{ a }}[{{ idx }}] = max({{ a }}[{{ idx }}], {{ a }}[{{ idx }} + {{ svar }}]);
|
| 21 |
+
{%- else %}
|
| 22 |
+
{{ a }}[{{ idx }}] = {{ a }}[{{ idx }}] + {{ a }}[{{ idx }} + {{ svar }}];
|
| 23 |
+
{%- endif %}
|
| 24 |
+
{% endmacro %}
|
| 25 |
+
{% macro wgsl_tree_fold(arrays, op="add", idx="lid", wg="WORKGROUP_SIZE", svar="stride", typed=false, form="tail", breakInline=false, bodyInline=false, barrierFirst=false) %}
|
| 26 |
+
var {{ svar }}{{ ": u32 " if typed else " " }}= {{ wg }} / 2u;
|
| 27 |
+
loop {
|
| 28 |
+
{% if form == "head" %}
|
| 29 |
+
{% if breakInline %}
|
| 30 |
+
if ({{ svar }} == 0u) { break; }
|
| 31 |
+
{% else %}
|
| 32 |
+
if ({{ svar }} == 0u) {
|
| 33 |
+
break;
|
| 34 |
+
}
|
| 35 |
+
{% endif %}
|
| 36 |
+
{% endif %}
|
| 37 |
+
{% if bodyInline %}
|
| 38 |
+
if ({{ idx }} < {{ svar }}) { {{ wgsl_tree_fold_stmt(arrays[0], op, idx, svar) }} }
|
| 39 |
+
{% else %}
|
| 40 |
+
if ({{ idx }} < {{ svar }}) {
|
| 41 |
+
{% for a in arrays %}
|
| 42 |
+
{{ wgsl_tree_fold_stmt(a, op, idx, svar) }}
|
| 43 |
+
{% endfor %}
|
| 44 |
+
}
|
| 45 |
+
{% endif %}
|
| 46 |
+
{% if form == "head" %}
|
| 47 |
+
{% if barrierFirst %}
|
| 48 |
+
workgroupBarrier();
|
| 49 |
+
{{ svar }} = {{ svar }} / 2u;
|
| 50 |
+
{% else %}
|
| 51 |
+
{{ svar }} = {{ svar }} / 2u;
|
| 52 |
+
workgroupBarrier();
|
| 53 |
+
{% endif %}
|
| 54 |
+
{% else %}
|
| 55 |
+
workgroupBarrier();
|
| 56 |
+
if ({{ svar }} == 1u) {
|
| 57 |
+
break;
|
| 58 |
+
}
|
| 59 |
+
{{ svar }} = {{ svar }} / 2u;
|
| 60 |
+
{% endif %}
|
| 61 |
+
}
|
| 62 |
+
{%- endmacro %}
|
| 63 |
+
|
| 64 |
+
// Reusing partial after this reduction requires a barrier between the read of
|
| 65 |
+
// partial[0] and the next write, or the next round can race the prior readers.
|
| 66 |
+
{% set trailingBarrier = trailingBarrier is defined and trailingBarrier %}
|
| 67 |
+
fn reduce_sum(value: f32, tid: u32) -> f32 {
|
| 68 |
+
partial[tid] = value;
|
| 69 |
+
workgroupBarrier();
|
| 70 |
+
{{ wgsl_tree_fold(["partial"], idx="tid", wg="WG", form="head") }}
|
| 71 |
+
{% if trailingBarrier %}
|
| 72 |
+
let total = partial[0];
|
| 73 |
+
workgroupBarrier();
|
| 74 |
+
return total;
|
| 75 |
+
{% else %}
|
| 76 |
+
return partial[0];
|
| 77 |
+
{% endif %}
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
fn row_value(index: u32) -> f32 {
|
| 82 |
+
{% if hasSkip %}
|
| 83 |
+
return f32(a[index]) + f32(skip[index]);
|
| 84 |
+
{% else %}
|
| 85 |
+
return f32(a[index]);
|
| 86 |
+
{% endif %}
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
@compute @workgroup_size(WG, 1, 1)
|
| 90 |
+
fn main(@builtin(workgroup_id) wg: vec3<u32>,
|
| 91 |
+
@builtin(num_workgroups) nwg: vec3<u32>,
|
| 92 |
+
@builtin(local_invocation_id) lid: vec3<u32>) {
|
| 93 |
+
// 2D-folded row index: wg.y carries the high bits past the
|
| 94 |
+
// maxComputeWorkgroupsPerDimension dispatch limit. Reduces to wg.x when nwg.y == 1.
|
| 95 |
+
let row = wg.x + wg.y * nwg.x;
|
| 96 |
+
if (row >= params.rows) {
|
| 97 |
+
return;
|
| 98 |
+
}
|
| 99 |
+
let tid = lid.x;
|
| 100 |
+
let base = row * HIDDEN;
|
| 101 |
+
|
| 102 |
+
var local_sq = 0.0;
|
| 103 |
+
for (var d = tid; d < HIDDEN; d = d + WG) {
|
| 104 |
+
let value = row_value(base + d);
|
| 105 |
+
local_sq = local_sq + value * value;
|
| 106 |
+
}
|
| 107 |
+
let inv = inverseSqrt(reduce_sum(local_sq, tid) / f32(HIDDEN) + EPSILON);
|
| 108 |
+
|
| 109 |
+
for (var d = tid; d < HIDDEN; d = d + WG) {
|
| 110 |
+
let index = base + d;
|
| 111 |
+
let value = row_value(index);
|
| 112 |
+
{% if writeResidual %}
|
| 113 |
+
residual[index] = {{ scalar }}(value);
|
| 114 |
+
{% endif %}
|
| 115 |
+
normed[index] = value * inv * f32(norm_scale[d]);
|
| 116 |
+
}
|
| 117 |
+
}
|
build/webgpu/metadata.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "com.microsoft.MatMulNBitsQkv",
|
| 3 |
+
"id": "_com_microsoft_matmulnbitsqkv_webgpu_07222b0",
|
| 4 |
+
"version": 1,
|
| 5 |
+
"license": "Apache-2.0",
|
| 6 |
+
"backend": { "type": "webgpu" },
|
| 7 |
+
"digest": {
|
| 8 |
+
"algorithm": "sha256",
|
| 9 |
+
"files": {
|
| 10 |
+
"bench.json": "TMTSE3iJebIWYjPDDVFyPwWC3YdOekG83a3gOGp3Xao=",
|
| 11 |
+
"manifest.json": "xLf6qGf+IK/6nqf+JAlvzmyVSbm5jUarc5DL/IVW3w0=",
|
| 12 |
+
"matmul-nbits-fused-rms-norm.wgsl.jinja": "4TI9Mc/RZWVgMl6NVG2iwe5OpvqQmswhe6xtGvctNmI=",
|
| 13 |
+
"qkv-projection.wgsl.jinja": "sINPOc7UfVRs5YFgICljS7B6QxhlPuL6IVEEatlIaMY=",
|
| 14 |
+
"test.json": "Ttc9zF84a34u+oxrvXeKL3Wah8leZYmRrkN0Ddw+P0E="
|
| 15 |
+
}
|
| 16 |
+
},
|
| 17 |
+
"provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
|
| 18 |
+
"webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.MatMulNBitsQkv" }
|
| 19 |
+
}
|
build/webgpu/qkv-projection.wgsl.jinja
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro matmul_nbits_packed_code(fn="packed_weight", buffer="b", kBlocks="params.kBlocks", blobSize="params.blobSize", bits=4) %}
|
| 2 |
+
fn {{ fn }}(n: u32, block: u32, offset: u32) -> u32 {
|
| 3 |
+
{% if bits == 2 %}
|
| 4 |
+
let byte_index = offset / 4u;
|
| 5 |
+
let shift = (offset % 4u) * 2u;
|
| 6 |
+
let packed_index = (n * {{ kBlocks }} + block) * {{ blobSize }} + byte_index;
|
| 7 |
+
return ({{ buffer }}[packed_index] >> shift) & 3u;
|
| 8 |
+
{% elif bits == 4 %}
|
| 9 |
+
let byte_index = offset / 2u;
|
| 10 |
+
let shift = (offset % 2u) * 4u;
|
| 11 |
+
let packed_index = (n * {{ kBlocks }} + block) * {{ blobSize }} + byte_index;
|
| 12 |
+
return ({{ buffer }}[packed_index] >> shift) & 15u;
|
| 13 |
+
{% else %}
|
| 14 |
+
let packed_index = (n * {{ kBlocks }} + block) * {{ blobSize }} + offset;
|
| 15 |
+
return {{ buffer }}[packed_index] & 255u;
|
| 16 |
+
{% endif %}
|
| 17 |
+
}
|
| 18 |
+
{%- endmacro %}
|
| 19 |
+
|
| 20 |
+
{% if usesF16 %}
|
| 21 |
+
enable f16;
|
| 22 |
+
{% endif %}
|
| 23 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 24 |
+
|
| 25 |
+
// com.microsoft.MatMulNBitsQkv, projection pass.
|
| 26 |
+
// Q[row, n] = dot(A_norm[row], q_weight[n]), and likewise K and V.
|
| 27 |
+
{% if source.singleProjection %}
|
| 28 |
+
// This specialization binds and computes one projection.
|
| 29 |
+
{% else %}
|
| 30 |
+
// All three projections read the same normalized row, so one dispatch covers
|
| 31 |
+
// them: the column-tile grid is laid out as Q's tiles, then K's, then V's, and
|
| 32 |
+
// a workgroup's tile index alone decides which projection it serves. That keeps
|
| 33 |
+
// the branch workgroup-uniform -- no lane in a workgroup ever takes a different
|
| 34 |
+
// arm -- while still reading each activation row once per tile instead of once
|
| 35 |
+
// per projection.
|
| 36 |
+
{% endif %}
|
| 37 |
+
// Within a tile, LANES threads cooperate on one output column: thread
|
| 38 |
+
// (column, lane) strides the reduction axis by LANES and the partials are
|
| 39 |
+
// folded inside the column's own lane group. Codes dequantize as
|
| 40 |
+
// (code - ZERO) * block_scale with the scale hoisted out of the inner loop;
|
| 41 |
+
// this operator has no zero-point input, so ZERO is the symmetric midpoint.
|
| 42 |
+
// A workgroup also covers ROW_TILE activation rows, reusing each unpacked code
|
| 43 |
+
// across their accumulators.
|
| 44 |
+
const K: u32 = {{ K }}u;
|
| 45 |
+
{% if source.singleProjection == "q" %}
|
| 46 |
+
const N: u32 = {{ nq }}u;
|
| 47 |
+
{% elif source.singleProjection %}
|
| 48 |
+
const N: u32 = {{ nkv }}u;
|
| 49 |
+
{% else %}
|
| 50 |
+
const NQ: u32 = {{ nq }}u;
|
| 51 |
+
const NKV: u32 = {{ nkv }}u;
|
| 52 |
+
{% endif %}
|
| 53 |
+
const BLOCK_SIZE: u32 = {{ blockSize }}u;
|
| 54 |
+
const KBLOCKS: u32 = {{ kBlocks }}u;
|
| 55 |
+
const BLOB_SIZE: u32 = {{ blobSize }}u;
|
| 56 |
+
const TILE_N: u32 = {{ tileN }}u;
|
| 57 |
+
const LANES: u32 = {{ lanes }}u;
|
| 58 |
+
const ROW_TILE: u32 = {{ rowTile }}u;
|
| 59 |
+
const ROWS: u32 = {{ rows }}u;
|
| 60 |
+
const WG: u32 = TILE_N * LANES;
|
| 61 |
+
const ZERO: f32 = {{ defaultZero }};
|
| 62 |
+
{% if not source.singleProjection %}
|
| 63 |
+
const Q_TILES: u32 = (NQ + TILE_N - 1u) / TILE_N;
|
| 64 |
+
const KV_TILES: u32 = (NKV + TILE_N - 1u) / TILE_N;
|
| 65 |
+
{% endif %}
|
| 66 |
+
|
| 67 |
+
const BITS: u32 = {{ bits }}u;
|
| 68 |
+
// Codes per logical byte and the mask for one code. Physical uint8 storage uses
|
| 69 |
+
// a u32 slot, so packing increases the number of codes returned by each load.
|
| 70 |
+
const CODES_PER_BYTE: u32 = {{ codesPerByte }}u;
|
| 71 |
+
const CODE_MASK: u32 = {{ codeMask }}u;
|
| 72 |
+
|
| 73 |
+
{% for stream in (["q", "k", "v"] if not source.singleProjection else [source.singleProjection]) %}
|
| 74 |
+
{{ matmul_nbits_packed_code(fn=stream ~ "_code", buffer=stream ~ "_b", kBlocks="KBLOCKS", blobSize="BLOB_SIZE", bits=bits) }}
|
| 75 |
+
// Decode two consecutive reduction-axis codes from one stored word. An odd
|
| 76 |
+
// offset would straddle words, so callers advance by two from an even start.
|
| 77 |
+
fn {{ stream }}_code_pair(n: u32, block: u32, offset: u32) -> vec2<u32> {
|
| 78 |
+
let word = {{ stream }}_b[(n * KBLOCKS + block) * BLOB_SIZE + offset / CODES_PER_BYTE];
|
| 79 |
+
let shift = (offset % CODES_PER_BYTE) * BITS;
|
| 80 |
+
return vec2<u32>((word >> shift) & CODE_MASK, (word >> (shift + BITS)) & CODE_MASK);
|
| 81 |
+
}
|
| 82 |
+
{% endfor %}
|
| 83 |
+
|
| 84 |
+
var<workgroup> reduction: array<f32, WG * ROW_TILE>;
|
| 85 |
+
|
| 86 |
+
{% macro walk_block(codeFn, guarded) %}
|
| 87 |
+
for (var offset = lane * 2u; offset + 1u < BLOCK_SIZE; offset = offset + LANES * 2u) {
|
| 88 |
+
let k = k_base + offset;
|
| 89 |
+
{% if guarded %}
|
| 90 |
+
if (k + 1u < K) {
|
| 91 |
+
{% endif %}
|
| 92 |
+
let codes = {{ codeFn }}_pair(n, block, offset);
|
| 93 |
+
let code_lo = f32(codes.x) - ZERO;
|
| 94 |
+
let code_hi = f32(codes.y) - ZERO;
|
| 95 |
+
{% for r in range(rowTile) %}
|
| 96 |
+
block_acc_{{ r }} = block_acc_{{ r }} + normed[base_{{ r }} + k] * code_lo
|
| 97 |
+
+ normed[base_{{ r }} + k + 1u] * code_hi;
|
| 98 |
+
{% endfor %}
|
| 99 |
+
{% if guarded %}
|
| 100 |
+
} else if (k < K) {
|
| 101 |
+
let code = f32({{ codeFn }}(n, block, offset)) - ZERO;
|
| 102 |
+
{% for r in range(rowTile) %}
|
| 103 |
+
block_acc_{{ r }} = block_acc_{{ r }} + normed[base_{{ r }} + k] * code;
|
| 104 |
+
{% endfor %}
|
| 105 |
+
}
|
| 106 |
+
{% endif %}
|
| 107 |
+
}
|
| 108 |
+
{%- endmacro %}
|
| 109 |
+
|
| 110 |
+
{% macro project(codeFn, scalesBuffer) %}
|
| 111 |
+
for (var block = 0u; block < KBLOCKS; block = block + 1u) {
|
| 112 |
+
let scale = f32({{ scalesBuffer }}[n * KBLOCKS + block]);
|
| 113 |
+
let k_base = block * BLOCK_SIZE;
|
| 114 |
+
{% for r in range(rowTile) %}
|
| 115 |
+
var block_acc_{{ r }} = 0.0;
|
| 116 |
+
{% endfor %}
|
| 117 |
+
// Each trip handles two codes. BLOCK_SIZE is even for every admitted
|
| 118 |
+
// packing, so paired trips cover a full block. Only a final partial block
|
| 119 |
+
// needs bounds checks; the branch is workgroup-uniform.
|
| 120 |
+
if (k_base + BLOCK_SIZE <= K) {
|
| 121 |
+
{{ walk_block(codeFn, false) }}
|
| 122 |
+
} else {
|
| 123 |
+
{{ walk_block(codeFn, true) }}
|
| 124 |
+
}
|
| 125 |
+
{% for r in range(rowTile) %}
|
| 126 |
+
acc_{{ r }} = acc_{{ r }} + block_acc_{{ r }} * scale;
|
| 127 |
+
{% endfor %}
|
| 128 |
+
}
|
| 129 |
+
{%- endmacro %}
|
| 130 |
+
|
| 131 |
+
@compute @workgroup_size(WG, 1, 1)
|
| 132 |
+
fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 133 |
+
let row0 = wg.y * ROW_TILE;
|
| 134 |
+
let tid = lid.x;
|
| 135 |
+
let column = tid / LANES;
|
| 136 |
+
let lane = tid % LANES;
|
| 137 |
+
{% for r in range(rowTile) %}
|
| 138 |
+
// Rows past the end of the batch clamp onto the last real row; their
|
| 139 |
+
// accumulators are finite and the store guard drops them.
|
| 140 |
+
let base_{{ r }} = min(row0 + {{ r }}u, ROWS - 1u) * K;
|
| 141 |
+
{% endfor %}
|
| 142 |
+
|
| 143 |
+
{% if source.singleProjection %}
|
| 144 |
+
let n = wg.x * TILE_N + column;
|
| 145 |
+
|
| 146 |
+
{% for r in range(rowTile) %}
|
| 147 |
+
var acc_{{ r }} = 0.0;
|
| 148 |
+
{% endfor %}
|
| 149 |
+
if (n < N) {
|
| 150 |
+
{{ project(source.singleProjection ~ "_code", source.singleProjection ~ "_scales") }}
|
| 151 |
+
}
|
| 152 |
+
{% else %}
|
| 153 |
+
// Tile index selects the projection, so every thread in this workgroup takes
|
| 154 |
+
// the same arm and the reduction below stays uniform.
|
| 155 |
+
let tile = wg.x;
|
| 156 |
+
var projection = 2u;
|
| 157 |
+
var local_tile = tile - Q_TILES - KV_TILES;
|
| 158 |
+
if (tile < Q_TILES) {
|
| 159 |
+
projection = 0u;
|
| 160 |
+
local_tile = tile;
|
| 161 |
+
} else if (tile < Q_TILES + KV_TILES) {
|
| 162 |
+
projection = 1u;
|
| 163 |
+
local_tile = tile - Q_TILES;
|
| 164 |
+
}
|
| 165 |
+
let n = local_tile * TILE_N + column;
|
| 166 |
+
let limit = select(NKV, NQ, projection == 0u);
|
| 167 |
+
|
| 168 |
+
{% for r in range(rowTile) %}
|
| 169 |
+
var acc_{{ r }} = 0.0;
|
| 170 |
+
{% endfor %}
|
| 171 |
+
if (n < limit) {
|
| 172 |
+
if (projection == 0u) {
|
| 173 |
+
{{ project("q_code", "q_scales") }}
|
| 174 |
+
} else if (projection == 1u) {
|
| 175 |
+
{{ project("k_code", "k_scales") }}
|
| 176 |
+
} else {
|
| 177 |
+
{{ project("v_code", "v_scales") }}
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
+
{% endif %}
|
| 181 |
+
|
| 182 |
+
{% for r in range(rowTile) %}
|
| 183 |
+
reduction[{{ r }}u * WG + tid] = acc_{{ r }};
|
| 184 |
+
{% endfor %}
|
| 185 |
+
workgroupBarrier();
|
| 186 |
+
// Fold within each column's own LANES-wide group, one group per staged row.
|
| 187 |
+
// LANES is a power of two, so lane + stride never leaves the group.
|
| 188 |
+
for (var stride = LANES / 2u; stride > 0u; stride = stride / 2u) {
|
| 189 |
+
if (lane < stride) {
|
| 190 |
+
{% for r in range(rowTile) %}
|
| 191 |
+
reduction[{{ r }}u * WG + tid] = reduction[{{ r }}u * WG + tid] + reduction[{{ r }}u * WG + tid + stride];
|
| 192 |
+
{% endfor %}
|
| 193 |
+
}
|
| 194 |
+
workgroupBarrier();
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
{% if source.singleProjection %}
|
| 198 |
+
if (lane == 0u && n < N) {
|
| 199 |
+
{% for r in range(rowTile) %}
|
| 200 |
+
if (row0 + {{ r }}u < ROWS) {
|
| 201 |
+
{{ source.singleProjection }}[(row0 + {{ r }}u) * N + n] = {{ scalar }}(reduction[{{ r }}u * WG + tid]);
|
| 202 |
+
}
|
| 203 |
+
{% endfor %}
|
| 204 |
+
}
|
| 205 |
+
{% else %}
|
| 206 |
+
if (lane == 0u && n < limit) {
|
| 207 |
+
{% for r in range(rowTile) %}
|
| 208 |
+
if (row0 + {{ r }}u < ROWS) {
|
| 209 |
+
let value_{{ r }} = {{ scalar }}(reduction[{{ r }}u * WG + tid]);
|
| 210 |
+
if (projection == 0u) {
|
| 211 |
+
q[(row0 + {{ r }}u) * NQ + n] = value_{{ r }};
|
| 212 |
+
} else if (projection == 1u) {
|
| 213 |
+
k[(row0 + {{ r }}u) * NKV + n] = value_{{ r }};
|
| 214 |
+
} else {
|
| 215 |
+
v[(row0 + {{ r }}u) * NKV + n] = value_{{ r }};
|
| 216 |
+
}
|
| 217 |
+
}
|
| 218 |
+
{% endfor %}
|
| 219 |
+
}
|
| 220 |
+
{% endif %}
|
| 221 |
+
}
|
build/webgpu/test.json
ADDED
|
@@ -0,0 +1,663 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "com.microsoft.MatMulNBitsQkv",
|
| 3 |
+
"fixtureArrays": {
|
| 4 |
+
"norm_gqa_input_vBT": [90, 17, 203, 156, 64, 241, 112, 38, 175, 229, 83, 11, 198, 147, 52, 220, 105]
|
| 5 |
+
},
|
| 6 |
+
"cases": [
|
| 7 |
+
{
|
| 8 |
+
"name": "norm_gqa",
|
| 9 |
+
"provenance": {
|
| 10 |
+
"notes": "Grouped-query shape: Nq is twice Nkv, so the three projections have two different column counts."
|
| 11 |
+
},
|
| 12 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 13 |
+
"inputs": {
|
| 14 |
+
"aT": {
|
| 15 |
+
"dtype": "float32",
|
| 16 |
+
"shape": [3, 32],
|
| 17 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 18 |
+
},
|
| 19 |
+
"normScaleT": {
|
| 20 |
+
"dtype": "float32",
|
| 21 |
+
"shape": [32],
|
| 22 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 23 |
+
},
|
| 24 |
+
"qBT": {
|
| 25 |
+
"dtype": "uint8",
|
| 26 |
+
"shape": [8, 1, 16],
|
| 27 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 28 |
+
},
|
| 29 |
+
"qScalesT": {
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"shape": [8, 1],
|
| 32 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 33 |
+
},
|
| 34 |
+
"kBT": {
|
| 35 |
+
"dtype": "uint8",
|
| 36 |
+
"shape": [4, 1, 16],
|
| 37 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 38 |
+
},
|
| 39 |
+
"kScalesT": {
|
| 40 |
+
"dtype": "float32",
|
| 41 |
+
"shape": [4, 1],
|
| 42 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 43 |
+
},
|
| 44 |
+
"vBT": {
|
| 45 |
+
"dtype": "uint8",
|
| 46 |
+
"shape": [4, 1, 16],
|
| 47 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 48 |
+
},
|
| 49 |
+
"vScalesT": {
|
| 50 |
+
"dtype": "float32",
|
| 51 |
+
"shape": [4, 1],
|
| 52 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 53 |
+
}
|
| 54 |
+
},
|
| 55 |
+
"outputs": {
|
| 56 |
+
"qT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 57 |
+
"kT": { "dtype": "float32", "shape": [3, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 58 |
+
"vT": { "dtype": "float32", "shape": [3, 4], "tolerance": 0.0001, "relTolerance": 0.0001 }
|
| 59 |
+
}
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"name": "norm_rows_past_one_tile",
|
| 63 |
+
"provenance": {
|
| 64 |
+
"notes": "Ten activation rows against an eight-row projection tile: two row groups where the second carries only two real rows, so the store guard has to drop the six that clamped onto the last row."
|
| 65 |
+
},
|
| 66 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 67 |
+
"inputs": {
|
| 68 |
+
"aT": {
|
| 69 |
+
"dtype": "float32",
|
| 70 |
+
"shape": [10, 32],
|
| 71 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.31, "scale": 0.8 }
|
| 72 |
+
},
|
| 73 |
+
"normScaleT": {
|
| 74 |
+
"dtype": "float32",
|
| 75 |
+
"shape": [32],
|
| 76 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 77 |
+
},
|
| 78 |
+
"qBT": {
|
| 79 |
+
"dtype": "uint8",
|
| 80 |
+
"shape": [8, 1, 16],
|
| 81 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 82 |
+
},
|
| 83 |
+
"qScalesT": {
|
| 84 |
+
"dtype": "float32",
|
| 85 |
+
"shape": [8, 1],
|
| 86 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 87 |
+
},
|
| 88 |
+
"kBT": {
|
| 89 |
+
"dtype": "uint8",
|
| 90 |
+
"shape": [4, 1, 16],
|
| 91 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 92 |
+
},
|
| 93 |
+
"kScalesT": {
|
| 94 |
+
"dtype": "float32",
|
| 95 |
+
"shape": [4, 1],
|
| 96 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 97 |
+
},
|
| 98 |
+
"vBT": {
|
| 99 |
+
"dtype": "uint8",
|
| 100 |
+
"shape": [4, 1, 16],
|
| 101 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 102 |
+
},
|
| 103 |
+
"vScalesT": {
|
| 104 |
+
"dtype": "float32",
|
| 105 |
+
"shape": [4, 1],
|
| 106 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 107 |
+
}
|
| 108 |
+
},
|
| 109 |
+
"outputs": {
|
| 110 |
+
"qT": { "dtype": "float32", "shape": [10, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 111 |
+
"kT": { "dtype": "float32", "shape": [10, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 112 |
+
"vT": { "dtype": "float32", "shape": [10, 4], "tolerance": 0.0001, "relTolerance": 0.0001 }
|
| 113 |
+
}
|
| 114 |
+
},
|
| 115 |
+
{
|
| 116 |
+
"name": "skip_gqa",
|
| 117 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32, "epsilon": 0.00001 },
|
| 118 |
+
"inputs": {
|
| 119 |
+
"aT": {
|
| 120 |
+
"dtype": "float32",
|
| 121 |
+
"shape": [3, 32],
|
| 122 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 123 |
+
},
|
| 124 |
+
"skipT": {
|
| 125 |
+
"dtype": "float32",
|
| 126 |
+
"shape": [3, 32],
|
| 127 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.11, "scale": 0.5 }
|
| 128 |
+
},
|
| 129 |
+
"normScaleT": {
|
| 130 |
+
"dtype": "float32",
|
| 131 |
+
"shape": [32],
|
| 132 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 133 |
+
},
|
| 134 |
+
"qBT": {
|
| 135 |
+
"dtype": "uint8",
|
| 136 |
+
"shape": [8, 1, 16],
|
| 137 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 138 |
+
},
|
| 139 |
+
"qScalesT": {
|
| 140 |
+
"dtype": "float32",
|
| 141 |
+
"shape": [8, 1],
|
| 142 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 143 |
+
},
|
| 144 |
+
"kBT": {
|
| 145 |
+
"dtype": "uint8",
|
| 146 |
+
"shape": [4, 1, 16],
|
| 147 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 148 |
+
},
|
| 149 |
+
"kScalesT": {
|
| 150 |
+
"dtype": "float32",
|
| 151 |
+
"shape": [4, 1],
|
| 152 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 153 |
+
},
|
| 154 |
+
"vBT": {
|
| 155 |
+
"dtype": "uint8",
|
| 156 |
+
"shape": [4, 1, 16],
|
| 157 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 158 |
+
},
|
| 159 |
+
"vScalesT": {
|
| 160 |
+
"dtype": "float32",
|
| 161 |
+
"shape": [4, 1],
|
| 162 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 163 |
+
}
|
| 164 |
+
},
|
| 165 |
+
"outputs": {
|
| 166 |
+
"qT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 167 |
+
"kT": { "dtype": "float32", "shape": [3, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 168 |
+
"vT": { "dtype": "float32", "shape": [3, 4], "tolerance": 0.0001, "relTolerance": 0.0001 }
|
| 169 |
+
}
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"name": "skipsum_gqa",
|
| 173 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 174 |
+
"inputs": {
|
| 175 |
+
"aT": {
|
| 176 |
+
"dtype": "float32",
|
| 177 |
+
"shape": [3, 32],
|
| 178 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 179 |
+
},
|
| 180 |
+
"skipT": {
|
| 181 |
+
"dtype": "float32",
|
| 182 |
+
"shape": [3, 32],
|
| 183 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.11, "scale": 0.5 }
|
| 184 |
+
},
|
| 185 |
+
"normScaleT": {
|
| 186 |
+
"dtype": "float32",
|
| 187 |
+
"shape": [32],
|
| 188 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 189 |
+
},
|
| 190 |
+
"qBT": {
|
| 191 |
+
"dtype": "uint8",
|
| 192 |
+
"shape": [8, 1, 16],
|
| 193 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 194 |
+
},
|
| 195 |
+
"qScalesT": {
|
| 196 |
+
"dtype": "float32",
|
| 197 |
+
"shape": [8, 1],
|
| 198 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 199 |
+
},
|
| 200 |
+
"kBT": {
|
| 201 |
+
"dtype": "uint8",
|
| 202 |
+
"shape": [4, 1, 16],
|
| 203 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 204 |
+
},
|
| 205 |
+
"kScalesT": {
|
| 206 |
+
"dtype": "float32",
|
| 207 |
+
"shape": [4, 1],
|
| 208 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 209 |
+
},
|
| 210 |
+
"vBT": {
|
| 211 |
+
"dtype": "uint8",
|
| 212 |
+
"shape": [4, 1, 16],
|
| 213 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 214 |
+
},
|
| 215 |
+
"vScalesT": {
|
| 216 |
+
"dtype": "float32",
|
| 217 |
+
"shape": [4, 1],
|
| 218 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 219 |
+
}
|
| 220 |
+
},
|
| 221 |
+
"outputs": {
|
| 222 |
+
"qT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 223 |
+
"kT": { "dtype": "float32", "shape": [3, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 224 |
+
"vT": { "dtype": "float32", "shape": [3, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 225 |
+
"residualT": { "dtype": "float32", "shape": [3, 32], "tolerance": 0.000001, "relTolerance": 0.000001 }
|
| 226 |
+
}
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
"name": "decode_single_row",
|
| 230 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 231 |
+
"inputs": {
|
| 232 |
+
"aT": {
|
| 233 |
+
"dtype": "float32",
|
| 234 |
+
"shape": [1, 32],
|
| 235 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 236 |
+
},
|
| 237 |
+
"skipT": {
|
| 238 |
+
"dtype": "float32",
|
| 239 |
+
"shape": [1, 32],
|
| 240 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.11, "scale": 0.5 }
|
| 241 |
+
},
|
| 242 |
+
"normScaleT": {
|
| 243 |
+
"dtype": "float32",
|
| 244 |
+
"shape": [32],
|
| 245 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 246 |
+
},
|
| 247 |
+
"qBT": {
|
| 248 |
+
"dtype": "uint8",
|
| 249 |
+
"shape": [8, 1, 16],
|
| 250 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 251 |
+
},
|
| 252 |
+
"qScalesT": {
|
| 253 |
+
"dtype": "float32",
|
| 254 |
+
"shape": [8, 1],
|
| 255 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 256 |
+
},
|
| 257 |
+
"kBT": {
|
| 258 |
+
"dtype": "uint8",
|
| 259 |
+
"shape": [4, 1, 16],
|
| 260 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 261 |
+
},
|
| 262 |
+
"kScalesT": {
|
| 263 |
+
"dtype": "float32",
|
| 264 |
+
"shape": [4, 1],
|
| 265 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 266 |
+
},
|
| 267 |
+
"vBT": {
|
| 268 |
+
"dtype": "uint8",
|
| 269 |
+
"shape": [4, 1, 16],
|
| 270 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 271 |
+
},
|
| 272 |
+
"vScalesT": {
|
| 273 |
+
"dtype": "float32",
|
| 274 |
+
"shape": [4, 1],
|
| 275 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 276 |
+
}
|
| 277 |
+
},
|
| 278 |
+
"outputs": {
|
| 279 |
+
"qT": { "dtype": "float32", "shape": [1, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 280 |
+
"kT": { "dtype": "float32", "shape": [1, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 281 |
+
"vT": { "dtype": "float32", "shape": [1, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 282 |
+
"residualT": { "dtype": "float32", "shape": [1, 32], "tolerance": 0.000001, "relTolerance": 0.000001 }
|
| 283 |
+
}
|
| 284 |
+
},
|
| 285 |
+
{
|
| 286 |
+
"name": "equal_nq_nkv",
|
| 287 |
+
"provenance": {
|
| 288 |
+
"notes": "Multi-head shape where Nq equals Nkv; the tile grid still lays Q, K and V out in sequence."
|
| 289 |
+
},
|
| 290 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 8, "block_size": 32 },
|
| 291 |
+
"inputs": {
|
| 292 |
+
"aT": {
|
| 293 |
+
"dtype": "float32",
|
| 294 |
+
"shape": [2, 32],
|
| 295 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 296 |
+
},
|
| 297 |
+
"normScaleT": {
|
| 298 |
+
"dtype": "float32",
|
| 299 |
+
"shape": [32],
|
| 300 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 301 |
+
},
|
| 302 |
+
"qBT": {
|
| 303 |
+
"dtype": "uint8",
|
| 304 |
+
"shape": [8, 1, 16],
|
| 305 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 306 |
+
},
|
| 307 |
+
"qScalesT": {
|
| 308 |
+
"dtype": "float32",
|
| 309 |
+
"shape": [8, 1],
|
| 310 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 311 |
+
},
|
| 312 |
+
"kBT": {
|
| 313 |
+
"dtype": "uint8",
|
| 314 |
+
"shape": [8, 1, 16],
|
| 315 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 316 |
+
},
|
| 317 |
+
"kScalesT": {
|
| 318 |
+
"dtype": "float32",
|
| 319 |
+
"shape": [8, 1],
|
| 320 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 321 |
+
},
|
| 322 |
+
"vBT": {
|
| 323 |
+
"dtype": "uint8",
|
| 324 |
+
"shape": [8, 1, 16],
|
| 325 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 326 |
+
},
|
| 327 |
+
"vScalesT": {
|
| 328 |
+
"dtype": "float32",
|
| 329 |
+
"shape": [8, 1],
|
| 330 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 331 |
+
}
|
| 332 |
+
},
|
| 333 |
+
"outputs": {
|
| 334 |
+
"qT": { "dtype": "float32", "shape": [2, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 335 |
+
"kT": { "dtype": "float32", "shape": [2, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 336 |
+
"vT": { "dtype": "float32", "shape": [2, 8], "tolerance": 0.0001, "relTolerance": 0.0001 }
|
| 337 |
+
}
|
| 338 |
+
},
|
| 339 |
+
{
|
| 340 |
+
"name": "tiles_not_aligned",
|
| 341 |
+
"provenance": {
|
| 342 |
+
"notes": "Neither column count is a multiple of the column tile, so both projections have a partial last tile."
|
| 343 |
+
},
|
| 344 |
+
"attrs": { "K": 32, "Nq": 5, "Nkv": 3, "block_size": 32 },
|
| 345 |
+
"inputs": {
|
| 346 |
+
"aT": {
|
| 347 |
+
"dtype": "float32",
|
| 348 |
+
"shape": [2, 32],
|
| 349 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 350 |
+
},
|
| 351 |
+
"normScaleT": {
|
| 352 |
+
"dtype": "float32",
|
| 353 |
+
"shape": [32],
|
| 354 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 355 |
+
},
|
| 356 |
+
"qBT": {
|
| 357 |
+
"dtype": "uint8",
|
| 358 |
+
"shape": [5, 1, 16],
|
| 359 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 360 |
+
},
|
| 361 |
+
"qScalesT": {
|
| 362 |
+
"dtype": "float32",
|
| 363 |
+
"shape": [5, 1],
|
| 364 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 365 |
+
},
|
| 366 |
+
"kBT": {
|
| 367 |
+
"dtype": "uint8",
|
| 368 |
+
"shape": [3, 1, 16],
|
| 369 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 370 |
+
},
|
| 371 |
+
"kScalesT": {
|
| 372 |
+
"dtype": "float32",
|
| 373 |
+
"shape": [3, 1],
|
| 374 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 375 |
+
},
|
| 376 |
+
"vBT": {
|
| 377 |
+
"dtype": "uint8",
|
| 378 |
+
"shape": [3, 1, 16],
|
| 379 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 380 |
+
},
|
| 381 |
+
"vScalesT": {
|
| 382 |
+
"dtype": "float32",
|
| 383 |
+
"shape": [3, 1],
|
| 384 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 385 |
+
}
|
| 386 |
+
},
|
| 387 |
+
"outputs": {
|
| 388 |
+
"qT": { "dtype": "float32", "shape": [2, 5], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 389 |
+
"kT": { "dtype": "float32", "shape": [2, 3], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 390 |
+
"vT": { "dtype": "float32", "shape": [2, 3], "tolerance": 0.0001, "relTolerance": 0.0001 }
|
| 391 |
+
}
|
| 392 |
+
},
|
| 393 |
+
{
|
| 394 |
+
"name": "tail_block_partial_k",
|
| 395 |
+
"provenance": { "notes": "K is not a multiple of block_size, so the final block is partly out of range." },
|
| 396 |
+
"attrs": { "K": 20, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 397 |
+
"inputs": {
|
| 398 |
+
"aT": {
|
| 399 |
+
"dtype": "float32",
|
| 400 |
+
"shape": [2, 20],
|
| 401 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 402 |
+
},
|
| 403 |
+
"normScaleT": {
|
| 404 |
+
"dtype": "float32",
|
| 405 |
+
"shape": [20],
|
| 406 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 407 |
+
},
|
| 408 |
+
"qBT": {
|
| 409 |
+
"dtype": "uint8",
|
| 410 |
+
"shape": [8, 1, 16],
|
| 411 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 412 |
+
},
|
| 413 |
+
"qScalesT": {
|
| 414 |
+
"dtype": "float32",
|
| 415 |
+
"shape": [8, 1],
|
| 416 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 417 |
+
},
|
| 418 |
+
"kBT": {
|
| 419 |
+
"dtype": "uint8",
|
| 420 |
+
"shape": [4, 1, 16],
|
| 421 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 422 |
+
},
|
| 423 |
+
"kScalesT": {
|
| 424 |
+
"dtype": "float32",
|
| 425 |
+
"shape": [4, 1],
|
| 426 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 427 |
+
},
|
| 428 |
+
"vBT": {
|
| 429 |
+
"dtype": "uint8",
|
| 430 |
+
"shape": [4, 1, 16],
|
| 431 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 432 |
+
},
|
| 433 |
+
"vScalesT": {
|
| 434 |
+
"dtype": "float32",
|
| 435 |
+
"shape": [4, 1],
|
| 436 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 437 |
+
}
|
| 438 |
+
},
|
| 439 |
+
"outputs": {
|
| 440 |
+
"qT": { "dtype": "float32", "shape": [2, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 441 |
+
"kT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 442 |
+
"vT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.0001, "relTolerance": 0.0001 }
|
| 443 |
+
}
|
| 444 |
+
},
|
| 445 |
+
{
|
| 446 |
+
"name": "rank3_activation",
|
| 447 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 448 |
+
"inputs": {
|
| 449 |
+
"aT": {
|
| 450 |
+
"dtype": "float32",
|
| 451 |
+
"shape": [1, 4, 32],
|
| 452 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 453 |
+
},
|
| 454 |
+
"normScaleT": {
|
| 455 |
+
"dtype": "float32",
|
| 456 |
+
"shape": [32],
|
| 457 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 458 |
+
},
|
| 459 |
+
"qBT": {
|
| 460 |
+
"dtype": "uint8",
|
| 461 |
+
"shape": [8, 1, 16],
|
| 462 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 463 |
+
},
|
| 464 |
+
"qScalesT": {
|
| 465 |
+
"dtype": "float32",
|
| 466 |
+
"shape": [8, 1],
|
| 467 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 468 |
+
},
|
| 469 |
+
"kBT": {
|
| 470 |
+
"dtype": "uint8",
|
| 471 |
+
"shape": [4, 1, 16],
|
| 472 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 473 |
+
},
|
| 474 |
+
"kScalesT": {
|
| 475 |
+
"dtype": "float32",
|
| 476 |
+
"shape": [4, 1],
|
| 477 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 478 |
+
},
|
| 479 |
+
"vBT": {
|
| 480 |
+
"dtype": "uint8",
|
| 481 |
+
"shape": [4, 1, 16],
|
| 482 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 483 |
+
},
|
| 484 |
+
"vScalesT": {
|
| 485 |
+
"dtype": "float32",
|
| 486 |
+
"shape": [4, 1],
|
| 487 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 488 |
+
}
|
| 489 |
+
},
|
| 490 |
+
"outputs": {
|
| 491 |
+
"qT": { "dtype": "float32", "shape": [1, 4, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 492 |
+
"kT": { "dtype": "float32", "shape": [1, 4, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 493 |
+
"vT": { "dtype": "float32", "shape": [1, 4, 4], "tolerance": 0.0001, "relTolerance": 0.0001 }
|
| 494 |
+
}
|
| 495 |
+
},
|
| 496 |
+
{
|
| 497 |
+
"name": "two_quant_blocks",
|
| 498 |
+
"provenance": { "notes": "K=64 covers two of the provider's supported 32-element quantization blocks." },
|
| 499 |
+
"attrs": { "K": 64, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 500 |
+
"inputs": {
|
| 501 |
+
"aT": {
|
| 502 |
+
"dtype": "float32",
|
| 503 |
+
"shape": [2, 64],
|
| 504 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 505 |
+
},
|
| 506 |
+
"skipT": {
|
| 507 |
+
"dtype": "float32",
|
| 508 |
+
"shape": [2, 64],
|
| 509 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.11, "scale": 0.5 }
|
| 510 |
+
},
|
| 511 |
+
"normScaleT": {
|
| 512 |
+
"dtype": "float32",
|
| 513 |
+
"shape": [64],
|
| 514 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 515 |
+
},
|
| 516 |
+
"qBT": {
|
| 517 |
+
"dtype": "uint8",
|
| 518 |
+
"shape": [8, 2, 16],
|
| 519 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 520 |
+
},
|
| 521 |
+
"qScalesT": {
|
| 522 |
+
"dtype": "float32",
|
| 523 |
+
"shape": [8, 2],
|
| 524 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 525 |
+
},
|
| 526 |
+
"kBT": {
|
| 527 |
+
"dtype": "uint8",
|
| 528 |
+
"shape": [4, 2, 16],
|
| 529 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 530 |
+
},
|
| 531 |
+
"kScalesT": {
|
| 532 |
+
"dtype": "float32",
|
| 533 |
+
"shape": [4, 2],
|
| 534 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 535 |
+
},
|
| 536 |
+
"vBT": {
|
| 537 |
+
"dtype": "uint8",
|
| 538 |
+
"shape": [4, 2, 16],
|
| 539 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 540 |
+
},
|
| 541 |
+
"vScalesT": {
|
| 542 |
+
"dtype": "float32",
|
| 543 |
+
"shape": [4, 2],
|
| 544 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 545 |
+
}
|
| 546 |
+
},
|
| 547 |
+
"outputs": {
|
| 548 |
+
"qT": { "dtype": "float32", "shape": [2, 8], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 549 |
+
"kT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 550 |
+
"vT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.0001, "relTolerance": 0.0001 },
|
| 551 |
+
"residualT": { "dtype": "float32", "shape": [2, 64], "tolerance": 0.000001, "relTolerance": 0.000001 }
|
| 552 |
+
}
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
"name": "f16_skipsum",
|
| 556 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 557 |
+
"inputs": {
|
| 558 |
+
"aT": {
|
| 559 |
+
"dtype": "float16",
|
| 560 |
+
"shape": [2, 32],
|
| 561 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 562 |
+
},
|
| 563 |
+
"skipT": {
|
| 564 |
+
"dtype": "float16",
|
| 565 |
+
"shape": [2, 32],
|
| 566 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.11, "scale": 0.5 }
|
| 567 |
+
},
|
| 568 |
+
"normScaleT": {
|
| 569 |
+
"dtype": "float16",
|
| 570 |
+
"shape": [32],
|
| 571 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 572 |
+
},
|
| 573 |
+
"qBT": {
|
| 574 |
+
"dtype": "uint8",
|
| 575 |
+
"shape": [8, 1, 16],
|
| 576 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 577 |
+
},
|
| 578 |
+
"qScalesT": {
|
| 579 |
+
"dtype": "float16",
|
| 580 |
+
"shape": [8, 1],
|
| 581 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 582 |
+
},
|
| 583 |
+
"kBT": {
|
| 584 |
+
"dtype": "uint8",
|
| 585 |
+
"shape": [4, 1, 16],
|
| 586 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 587 |
+
},
|
| 588 |
+
"kScalesT": {
|
| 589 |
+
"dtype": "float16",
|
| 590 |
+
"shape": [4, 1],
|
| 591 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 592 |
+
},
|
| 593 |
+
"vBT": {
|
| 594 |
+
"dtype": "uint8",
|
| 595 |
+
"shape": [4, 1, 16],
|
| 596 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 597 |
+
},
|
| 598 |
+
"vScalesT": {
|
| 599 |
+
"dtype": "float16",
|
| 600 |
+
"shape": [4, 1],
|
| 601 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 602 |
+
}
|
| 603 |
+
},
|
| 604 |
+
"outputs": {
|
| 605 |
+
"qT": { "dtype": "float16", "shape": [2, 8], "tolerance": 0.002, "relTolerance": 0.01 },
|
| 606 |
+
"kT": { "dtype": "float16", "shape": [2, 4], "tolerance": 0.002, "relTolerance": 0.01 },
|
| 607 |
+
"vT": { "dtype": "float16", "shape": [2, 4], "tolerance": 0.002, "relTolerance": 0.01 },
|
| 608 |
+
"residualT": { "dtype": "float16", "shape": [2, 32], "tolerance": 0.002, "relTolerance": 0.002 }
|
| 609 |
+
}
|
| 610 |
+
},
|
| 611 |
+
{
|
| 612 |
+
"name": "f16_norm",
|
| 613 |
+
"attrs": { "K": 32, "Nq": 8, "Nkv": 4, "block_size": 32 },
|
| 614 |
+
"inputs": {
|
| 615 |
+
"aT": {
|
| 616 |
+
"dtype": "float16",
|
| 617 |
+
"shape": [3, 32],
|
| 618 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.8 }
|
| 619 |
+
},
|
| 620 |
+
"normScaleT": {
|
| 621 |
+
"dtype": "float16",
|
| 622 |
+
"shape": [32],
|
| 623 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41, "scale": 0.4, "offset": 1.0 }
|
| 624 |
+
},
|
| 625 |
+
"qBT": {
|
| 626 |
+
"dtype": "uint8",
|
| 627 |
+
"shape": [8, 1, 16],
|
| 628 |
+
"data": { "kind": "cycle", "values": [27, 180, 75, 226, 33, 150, 201, 108, 57, 246, 129, 66, 195] }
|
| 629 |
+
},
|
| 630 |
+
"qScalesT": {
|
| 631 |
+
"dtype": "float16",
|
| 632 |
+
"shape": [8, 1],
|
| 633 |
+
"data": { "kind": "cycle", "values": [0.04, 0.055, 0.05, 0.065, 0.06, 0.075, 0.07] }
|
| 634 |
+
},
|
| 635 |
+
"kBT": {
|
| 636 |
+
"dtype": "uint8",
|
| 637 |
+
"shape": [4, 1, 16],
|
| 638 |
+
"data": { "kind": "cycle", "values": [211, 44, 137, 98, 165, 20, 233, 121, 78, 190, 15, 252, 87, 143, 61] }
|
| 639 |
+
},
|
| 640 |
+
"kScalesT": {
|
| 641 |
+
"dtype": "float16",
|
| 642 |
+
"shape": [4, 1],
|
| 643 |
+
"data": { "kind": "cycle", "values": [0.045, 0.03, 0.07, 0.05, 0.08, 0.035] }
|
| 644 |
+
},
|
| 645 |
+
"vBT": {
|
| 646 |
+
"dtype": "uint8",
|
| 647 |
+
"shape": [4, 1, 16],
|
| 648 |
+
"data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/norm_gqa_input_vBT" } }
|
| 649 |
+
},
|
| 650 |
+
"vScalesT": {
|
| 651 |
+
"dtype": "float16",
|
| 652 |
+
"shape": [4, 1],
|
| 653 |
+
"data": { "kind": "cycle", "values": [0.052, 0.038, 0.061, 0.029, 0.073] }
|
| 654 |
+
}
|
| 655 |
+
},
|
| 656 |
+
"outputs": {
|
| 657 |
+
"qT": { "dtype": "float16", "shape": [3, 8], "tolerance": 0.002, "relTolerance": 0.01 },
|
| 658 |
+
"kT": { "dtype": "float16", "shape": [3, 4], "tolerance": 0.002, "relTolerance": 0.01 },
|
| 659 |
+
"vT": { "dtype": "float16", "shape": [3, 4], "tolerance": 0.002, "relTolerance": 0.01 }
|
| 660 |
+
}
|
| 661 |
+
}
|
| 662 |
+
]
|
| 663 |
+
}
|