sync 2e7068faf55e
Browse files- README.md +79 -0
- build/webgpu/bench.json +69 -0
- build/webgpu/fused-gemm.wgsl.jinja +186 -0
- build/webgpu/gemm-subgroup-matrix.wgsl.jinja +269 -0
- build/webgpu/manifest.json +594 -0
- build/webgpu/metadata.json +19 -0
- build/webgpu/test.json +662 -0
README.md
CHANGED
|
@@ -1,3 +1,82 @@
|
|
| 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.FusedGemm
|
| 10 |
+
|
| 11 |
+
`com.microsoft` · ONNX Runtime contrib operator · contrib since_version 1
|
| 12 |
+
|
| 13 |
+
## Description
|
| 14 |
+
|
| 15 |
+
Gemm with a fused activation: `Y = act(alpha * A' * B' + beta * C)`, where `A'` and `B'` are optionally transposed and `C` is broadcastable to `(M, N)`. The activation runs in the f32 accumulator before the single output narrowing. This package supports `Relu`, `LeakyRelu`, `Sigmoid`, `Tanh` and `HardSigmoid`; the other activation strings and numeric types admitted by the open schema are not implemented. Omitting `activation` gives plain Gemm.
|
| 16 |
+
|
| 17 |
+
See the [ONNX Runtime `FusedGemm` contrib-operator spec](https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.FusedGemm) for the reference semantics.
|
| 18 |
+
|
| 19 |
+
## Inputs
|
| 20 |
+
|
| 21 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 22 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
+
| `A` | `A` | `T` | `2` | — | Left operand, `(M, K)` when `transA` is 0 and `(K, M)` otherwise. | required |
|
| 24 |
+
| `B` | `B` | `T` | `2` | — | Right operand, `(K, N)` when `transB` is 0 and `(N, K)` otherwise. | required |
|
| 25 |
+
| `C` | `C` | `T` | — | — | Optional additive term, unidirectionally broadcastable to `(M, N)`: a scalar, a row `(N)`, a column `(M, 1)`, or the full matrix. | optional |
|
| 26 |
+
|
| 27 |
+
## Outputs
|
| 28 |
+
|
| 29 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 30 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 31 |
+
| `Y` | `Y` | `T` | `2` | derived; see description | `act(alpha * A' * B' + beta * C)` with shape `(M, N)`. | required |
|
| 32 |
+
|
| 33 |
+
## Attributes
|
| 34 |
+
|
| 35 |
+
Attributes and default values (overridable per request):
|
| 36 |
+
|
| 37 |
+
| Attribute | Default | Description |
|
| 38 |
+
| --- | --- | --- |
|
| 39 |
+
| `alpha` | `1` | Scalar multiplier for the product `A' * B'`; the standard default is 1. |
|
| 40 |
+
| `beta` | `1` | Scalar multiplier for `C`; the standard default is 1. |
|
| 41 |
+
| `transA` | `0` | Whether `A` is stored transposed. The standard default is 0. |
|
| 42 |
+
| `transB` | `0` | Whether `B` is stored transposed. The standard default is 0. |
|
| 43 |
+
| `activation` | — | Optional fused activation name. Supported modes are `Relu`, `LeakyRelu`, `Sigmoid`, `Tanh` and `HardSigmoid`; omission applies none. |
|
| 44 |
+
| `activation_alpha` | — | First activation parameter: the slope for `LeakyRelu` or `alpha` for `HardSigmoid`. |
|
| 45 |
+
| `activation_beta` | — | Second activation parameter: `beta` for `HardSigmoid`. |
|
| 46 |
+
|
| 47 |
+
## Type constraints
|
| 48 |
+
|
| 49 |
+
| Variable | Allowed dtypes |
|
| 50 |
+
| --- | --- |
|
| 51 |
+
| `T` | `float32`, `float16` |
|
| 52 |
+
|
| 53 |
+
## Device requirements
|
| 54 |
+
|
| 55 |
+
Some implementation variants require `subgroup-matrix` and `subgroups`. These are route-specific capabilities, not package-wide requirements; availability also depends on the request shape and dtype.
|
| 56 |
+
|
| 57 |
+
## Files
|
| 58 |
+
|
| 59 |
+
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
|
| 60 |
+
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 61 |
+
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 62 |
+
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
| 63 |
+
- [`fused-gemm.wgsl.jinja`](build/webgpu/fused-gemm.wgsl.jinja)
|
| 64 |
+
- [`gemm-subgroup-matrix.wgsl.jinja`](build/webgpu/gemm-subgroup-matrix.wgsl.jinja)
|
| 65 |
+
|
| 66 |
+
## Use with `@huggingface/kernels`
|
| 67 |
+
|
| 68 |
+
The loader derives every required output's shape and logical dtype from the manifest contract and this call.
|
| 69 |
+
It then allocates the result tensors automatically.
|
| 70 |
+
|
| 71 |
+
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
| 72 |
+
|
| 73 |
+
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 74 |
+
|
| 75 |
+
```js
|
| 76 |
+
import { getKernel } from "@huggingface/kernels";
|
| 77 |
+
|
| 78 |
+
const kernel = await getKernel("webgpu-kernels/com.microsoft.FusedGemm", { version: 1 });
|
| 79 |
+
const { Y } = await kernel({ A: { data: AData, shape: [7, 13] }, B: { data: BData, shape: [13, 11] } }, {
|
| 80 |
+
attrs: { activation: "Relu" },
|
| 81 |
+
});
|
| 82 |
+
```
|
build/webgpu/bench.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "com.microsoft.FusedGemm",
|
| 3 |
+
"cases": [
|
| 4 |
+
{
|
| 5 |
+
"name": "fusedgemm-relu-m3072-k768-n3072",
|
| 6 |
+
"preset": "smoke",
|
| 7 |
+
"vars": { "dtype": "float32" },
|
| 8 |
+
"attrs": { "activation": "Relu" },
|
| 9 |
+
"inputs": {
|
| 10 |
+
"A": { "shape": [3072, 768], "dtype": "float32", "dist": "normal", "seed": 5300, "scale": 1 },
|
| 11 |
+
"B": { "shape": [768, 3072], "dtype": "float32", "dist": "normal", "seed": 5301, "scale": 1 },
|
| 12 |
+
"C": { "shape": [3072], "dtype": "float32", "dist": "normal", "seed": 5302, "scale": 1 }
|
| 13 |
+
},
|
| 14 |
+
"outputs": { "Y": { "shape": [3072, 3072], "dtype": "float32" } },
|
| 15 |
+
"bench": { "metrics": [{ "type": "gflops", "value": "2 * 3072 * 768 * 3072" }] }
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"name": "fusedgemm-transb-relu-m3072-k768-n3072",
|
| 19 |
+
"preset": "smoke",
|
| 20 |
+
"vars": { "dtype": "float32" },
|
| 21 |
+
"attrs": { "transB": 1, "activation": "Relu" },
|
| 22 |
+
"inputs": {
|
| 23 |
+
"A": { "shape": [3072, 768], "dtype": "float32", "dist": "normal", "seed": 5310, "scale": 1 },
|
| 24 |
+
"B": { "shape": [3072, 768], "dtype": "float32", "dist": "normal", "seed": 5311, "scale": 1 },
|
| 25 |
+
"C": { "shape": [3072], "dtype": "float32", "dist": "normal", "seed": 5312, "scale": 1 }
|
| 26 |
+
},
|
| 27 |
+
"outputs": { "Y": { "shape": [3072, 3072], "dtype": "float32" } },
|
| 28 |
+
"bench": { "metrics": [{ "type": "gflops", "value": "2 * 3072 * 768 * 3072" }] }
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"name": "fusedgemm-f16-relu-m3072-k768-n3072",
|
| 32 |
+
"preset": "model",
|
| 33 |
+
"vars": { "dtype": "float16" },
|
| 34 |
+
"attrs": { "activation": "Relu" },
|
| 35 |
+
"inputs": {
|
| 36 |
+
"A": { "shape": [3072, 768], "dtype": "float16", "dist": "normal", "seed": 5320, "scale": 1 },
|
| 37 |
+
"B": { "shape": [768, 3072], "dtype": "float16", "dist": "normal", "seed": 5321, "scale": 1 },
|
| 38 |
+
"C": { "shape": [3072], "dtype": "float16", "dist": "normal", "seed": 5322, "scale": 1 }
|
| 39 |
+
},
|
| 40 |
+
"outputs": { "Y": { "shape": [3072, 3072], "dtype": "float16" } },
|
| 41 |
+
"bench": { "metrics": [{ "type": "gflops", "value": "2 * 3072 * 768 * 3072" }] }
|
| 42 |
+
},
|
| 43 |
+
{
|
| 44 |
+
"name": "fusedgemm-nobias-tanh-m2048-k1024-n2048",
|
| 45 |
+
"preset": "model",
|
| 46 |
+
"vars": { "dtype": "float32" },
|
| 47 |
+
"attrs": { "activation": "Tanh" },
|
| 48 |
+
"inputs": {
|
| 49 |
+
"A": { "shape": [2048, 1024], "dtype": "float32", "dist": "normal", "seed": 5330, "scale": 1 },
|
| 50 |
+
"B": { "shape": [1024, 2048], "dtype": "float32", "dist": "normal", "seed": 5331, "scale": 1 }
|
| 51 |
+
},
|
| 52 |
+
"outputs": { "Y": { "shape": [2048, 2048], "dtype": "float32" } },
|
| 53 |
+
"bench": { "metrics": [{ "type": "gflops", "value": "2 * 2048 * 1024 * 2048" }] }
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"name": "fusedgemm-noactivation-m2048-k1024-n2048",
|
| 57 |
+
"preset": "model",
|
| 58 |
+
"vars": { "dtype": "float32" },
|
| 59 |
+
"attrs": {},
|
| 60 |
+
"inputs": {
|
| 61 |
+
"A": { "shape": [2048, 1024], "dtype": "float32", "dist": "normal", "seed": 5340, "scale": 1 },
|
| 62 |
+
"B": { "shape": [1024, 2048], "dtype": "float32", "dist": "normal", "seed": 5341, "scale": 1 },
|
| 63 |
+
"C": { "shape": [2048], "dtype": "float32", "dist": "normal", "seed": 5342, "scale": 1 }
|
| 64 |
+
},
|
| 65 |
+
"outputs": { "Y": { "shape": [2048, 2048], "dtype": "float32" } },
|
| 66 |
+
"bench": { "metrics": [{ "type": "gflops", "value": "2 * 2048 * 1024 * 2048" }] }
|
| 67 |
+
}
|
| 68 |
+
]
|
| 69 |
+
}
|
build/webgpu/fused-gemm.wgsl.jinja
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 is defined and usesF16 %}enable f16;
|
| 2 |
+
{% endif %}{% set OUT = "f16" if (usesF16 is defined and usesF16) else "f32" %}
|
| 3 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 4 |
+
|
| 5 |
+
// Shape-driven, register-blocked f32 GEMM for all four transpose combinations.
|
| 6 |
+
// Runtime M/N/K share one compiled pipeline. A 4x4 thread micro-tile forms a
|
| 7 |
+
// 64x64 output tile with BK=16; transpose modes change only load strides and
|
| 8 |
+
// keep the stored-contiguous axis coalesced. M/N/K tails are bounds-checked.
|
| 9 |
+
// Both tiles are indexed by their own output axis and group four K values per
|
| 10 |
+
// vector word, so the micro-tile accumulates through dot() and one step reads
|
| 11 |
+
// TM + TN words instead of 4 * (TM + TN) scalars.
|
| 12 |
+
{% set gemmEpi = gemmEpilogue if gemmEpilogue is defined else "none" %}
|
| 13 |
+
{% if gemmEpi == "fastgelu" %}
|
| 14 |
+
fn tanh_safe(x: f32) -> f32 {
|
| 15 |
+
if (x > 10.0) { return 1.0; }
|
| 16 |
+
if (x < -10.0) { return -1.0; }
|
| 17 |
+
return tanh(x);
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
fn gelu_tanh(v: f32) -> f32 {
|
| 21 |
+
return 0.5 * v * (1.0 + tanh_safe(0.7978845608028654 * (v + 0.044715 * v * v * v)));
|
| 22 |
+
}
|
| 23 |
+
{% elif gemmEpi == "activation" %}
|
| 24 |
+
{% set actMode = gemmActivation | default("") %}
|
| 25 |
+
{% set actA = gemmActAlpha | default(0.0) %}
|
| 26 |
+
{% set actB = gemmActBeta | default(0.0) %}
|
| 27 |
+
fn fused_act(v: f32) -> f32 {
|
| 28 |
+
{% if actMode == "Relu" %}
|
| 29 |
+
return max(v, 0.0);
|
| 30 |
+
{% endif %}
|
| 31 |
+
{% if actMode == "LeakyRelu" %}
|
| 32 |
+
return select(v * f32({{ actA }}), v, v >= 0.0);
|
| 33 |
+
{% endif %}
|
| 34 |
+
{% if actMode == "Sigmoid" %}
|
| 35 |
+
return 1.0 / (1.0 + exp(-v));
|
| 36 |
+
{% endif %}
|
| 37 |
+
{% if actMode == "Tanh" %}
|
| 38 |
+
return tanh(v);
|
| 39 |
+
{% endif %}
|
| 40 |
+
{% if actMode == "HardSigmoid" %}
|
| 41 |
+
return clamp(f32({{ actA }}) * v + f32({{ actB }}), 0.0, 1.0);
|
| 42 |
+
{% endif %}
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
{% endif %}
|
| 46 |
+
{% set epiOpen = "gelu_tanh(" if gemmEpi == "fastgelu" else ("fused_act(" if gemmEpi == "activation" else "") %}
|
| 47 |
+
{% set epiClose = ")" if gemmEpi != "none" else "" %}
|
| 48 |
+
const BK: u32 = 16u;
|
| 49 |
+
const BM: u32 = 64u;
|
| 50 |
+
const BN: u32 = 64u;
|
| 51 |
+
const TM: u32 = 4u; // per-thread micro-tile rows
|
| 52 |
+
const TN: u32 = 4u; // per-thread micro-tile cols
|
| 53 |
+
|
| 54 |
+
// Stage tiles at the operands' storage width. For f16 inputs this is
|
| 55 |
+
// bit-identical to widening on shared load, keeps f32 FMA registers, and halves
|
| 56 |
+
// workgroup storage.
|
| 57 |
+
{% set tileT = OUT %}
|
| 58 |
+
const K_VECS: u32 = BK / 4u;
|
| 59 |
+
var<workgroup> tileA: array<array<vec4<{{ tileT }}>, K_VECS>, BM>; // [64][4] logical A'[m][k/4]
|
| 60 |
+
var<workgroup> tileB: array<array<vec4<{{ tileT }}>, K_VECS>, BN>; // [64][4] logical B'[n][k/4]
|
| 61 |
+
|
| 62 |
+
@compute @workgroup_size(16, 16, 1)
|
| 63 |
+
fn main(
|
| 64 |
+
@builtin(workgroup_id) wg: vec3<u32>,
|
| 65 |
+
@builtin(local_invocation_id) lid: vec3<u32>,
|
| 66 |
+
@builtin(num_workgroups) nwg: vec3<u32>
|
| 67 |
+
) {
|
| 68 |
+
let li = lid.y * 16u + lid.x;
|
| 69 |
+
let M = params.M;
|
| 70 |
+
let N = params.N;
|
| 71 |
+
let K = params.K;
|
| 72 |
+
let n_tiles = (N + BN - 1u) / BN;
|
| 73 |
+
let m_tiles = (M + BM - 1u) / BM;
|
| 74 |
+
for (var nt: u32 = wg.x; nt < n_tiles; nt = nt + nwg.x) {
|
| 75 |
+
let nBase = nt * BN;
|
| 76 |
+
for (var mt: u32 = wg.y; mt < m_tiles; mt = mt + nwg.y) {
|
| 77 |
+
let mBase = mt * BM;
|
| 78 |
+
|
| 79 |
+
var acc: array<f32, TM * TN>;
|
| 80 |
+
for (var i: u32 = 0u; i < TM * TN; i = i + 1u) { acc[i] = 0.0; }
|
| 81 |
+
|
| 82 |
+
let numTiles = (K + BK - 1u) / BK;
|
| 83 |
+
for (var kt: u32 = 0u; kt < numTiles; kt = kt + 1u) {
|
| 84 |
+
let kBase = kt * BK;
|
| 85 |
+
// Cooperative load: one vector word per lane per pass. The lane grid is
|
| 86 |
+
// laid out so the axis the operand stores contiguously stays coalesced.
|
| 87 |
+
for (var idx: u32 = li; idx < BM * K_VECS; idx = idx + 256u) {
|
| 88 |
+
{% if transA %}
|
| 89 |
+
// A stored [K, M]: logical A'[m,k] = a[k*M + m]. Coalesce on m (contiguous).
|
| 90 |
+
let ar = idx % BM;
|
| 91 |
+
let ac4 = idx / BM;
|
| 92 |
+
{% else %}
|
| 93 |
+
// A stored [M, K]: logical A[m,k] = a[m*K + k]. Coalesce on k (contiguous).
|
| 94 |
+
let ar = idx / K_VECS;
|
| 95 |
+
let ac4 = idx % K_VECS;
|
| 96 |
+
{% endif %}
|
| 97 |
+
let am = mBase + ar;
|
| 98 |
+
let ak = kBase + ac4 * 4u;
|
| 99 |
+
var aWord = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 100 |
+
if (am < M) {
|
| 101 |
+
{% for component in range(4) %}
|
| 102 |
+
if (ak + {{ component }}u < K) {
|
| 103 |
+
{% if transA %}
|
| 104 |
+
aWord[{{ component }}u] = {{ tileT }}(a[(ak + {{ component }}u) * M + am]);
|
| 105 |
+
{% else %}
|
| 106 |
+
aWord[{{ component }}u] = {{ tileT }}(a[am * K + ak + {{ component }}u]);
|
| 107 |
+
{% endif %}
|
| 108 |
+
}
|
| 109 |
+
{% endfor %}
|
| 110 |
+
}
|
| 111 |
+
tileA[ar][ac4] = aWord;
|
| 112 |
+
}
|
| 113 |
+
for (var idx: u32 = li; idx < BN * K_VECS; idx = idx + 256u) {
|
| 114 |
+
{% if transB is defined and transB %}
|
| 115 |
+
// B stored [N, K]: logical B[k,n] = b[n*K + k]. Coalesce on k (contiguous).
|
| 116 |
+
let bc = idx / K_VECS;
|
| 117 |
+
let br4 = idx % K_VECS;
|
| 118 |
+
{% else %}
|
| 119 |
+
// B stored [K, N]: logical B[k,n] = b[k*N + n]. Coalesce on n (contiguous).
|
| 120 |
+
let bc = idx % BN;
|
| 121 |
+
let br4 = idx / BN;
|
| 122 |
+
{% endif %}
|
| 123 |
+
let bn = nBase + bc;
|
| 124 |
+
let bk = kBase + br4 * 4u;
|
| 125 |
+
var bWord = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 126 |
+
if (bn < N) {
|
| 127 |
+
{% for component in range(4) %}
|
| 128 |
+
if (bk + {{ component }}u < K) {
|
| 129 |
+
{% if transB is defined and transB %}
|
| 130 |
+
bWord[{{ component }}u] = {{ tileT }}(b[bn * K + bk + {{ component }}u]);
|
| 131 |
+
{% else %}
|
| 132 |
+
bWord[{{ component }}u] = {{ tileT }}(b[(bk + {{ component }}u) * N + bn]);
|
| 133 |
+
{% endif %}
|
| 134 |
+
}
|
| 135 |
+
{% endfor %}
|
| 136 |
+
}
|
| 137 |
+
tileB[bc][br4] = bWord;
|
| 138 |
+
}
|
| 139 |
+
workgroupBarrier();
|
| 140 |
+
{% set regIndent = " " %}{% set regT = "f32" %}{% set regCast = 1 if tileT != "f32" else 0 %}{{ regIndent }}let aRow = lid.y * TM;
|
| 141 |
+
{{ regIndent }}let bCol = lid.x * TN;
|
| 142 |
+
{{ regIndent }}for (var kv: u32 = 0u; kv < BK / 4u; kv = kv + 1u) {
|
| 143 |
+
{{ regIndent }} var av: array<vec4<{{ regT }}>, TM>;
|
| 144 |
+
{{ regIndent }} var bv: array<vec4<{{ regT }}>, TN>;
|
| 145 |
+
{{ regIndent }} for (var i: u32 = 0u; i < TM; i = i + 1u) { av[i] = {% if regCast %}vec4<{{ regT }}>(tileA[aRow + i][kv]){% else %}tileA[aRow + i][kv]{% endif %}; }
|
| 146 |
+
{{ regIndent }} for (var j: u32 = 0u; j < TN; j = j + 1u) { bv[j] = {% if regCast %}vec4<{{ regT }}>(tileB[bCol + j][kv]){% else %}tileB[bCol + j][kv]{% endif %}; }
|
| 147 |
+
{{ regIndent }} for (var i: u32 = 0u; i < TM; i = i + 1u) {
|
| 148 |
+
{{ regIndent }} for (var j: u32 = 0u; j < TN; j = j + 1u) {
|
| 149 |
+
{{ regIndent }} acc[i * TN + j] = acc[i * TN + j] + dot(av[i], bv[j]);
|
| 150 |
+
{{ regIndent }} }
|
| 151 |
+
{{ regIndent }} }
|
| 152 |
+
{{ regIndent }}}
|
| 153 |
+
workgroupBarrier();
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
let m0 = mBase + lid.y * TM;
|
| 157 |
+
let n0 = nBase + lid.x * TN;
|
| 158 |
+
for (var ti: u32 = 0u; ti < TM; ti = ti + 1u) {
|
| 159 |
+
let m = m0 + ti;
|
| 160 |
+
if (m >= M) { continue; }
|
| 161 |
+
for (var tj: u32 = 0u; tj < TN; tj = tj + 1u) {
|
| 162 |
+
let n = n0 + tj;
|
| 163 |
+
if (n < N) {
|
| 164 |
+
// alpha == 0 nulls A*B exactly and avoids Inf*0 becoming NaN.
|
| 165 |
+
let product = select(acc[ti * TN + tj] * params.alpha, 0.0, params.alpha == 0.0);
|
| 166 |
+
{% if hasBias is defined and hasBias %}
|
| 167 |
+
{% if rowBias is defined and rowBias %}
|
| 168 |
+
let biasValue = f32(bias[n]);
|
| 169 |
+
{% elif scalarBias is defined and scalarBias %}
|
| 170 |
+
let biasValue = f32(bias[0u]);
|
| 171 |
+
{% elif columnBias is defined and columnBias %}
|
| 172 |
+
let biasValue = f32(bias[m]);
|
| 173 |
+
{% else %}
|
| 174 |
+
let biasValue = f32(bias[m * N + n]);
|
| 175 |
+
{% endif %}
|
| 176 |
+
let biasTerm = select(biasValue * params.beta, 0.0, params.beta == 0.0);
|
| 177 |
+
y[m * N + n] = {{ OUT }}({{ epiOpen }}product + biasTerm{{ epiClose }});
|
| 178 |
+
{% else %}
|
| 179 |
+
y[m * N + n] = {{ OUT }}({{ epiOpen }}product{{ epiClose }});
|
| 180 |
+
{% endif %}
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
}
|
build/webgpu/gemm-subgroup-matrix.wgsl.jinja
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
enable subgroups;
|
| 5 |
+
{% if pinSubgroupSize32 %}
|
| 6 |
+
enable subgroup_size_control;
|
| 7 |
+
{% endif %}
|
| 8 |
+
enable chromium_experimental_subgroup_matrix;
|
| 9 |
+
diagnostic(off, chromium.subgroup_matrix_uniformity);
|
| 10 |
+
|
| 11 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 12 |
+
|
| 13 |
+
{% set operandScalar = mmaScalar %}
|
| 14 |
+
{% set accScalar = "f32" %}
|
| 15 |
+
{% set tileMValue = tileM if tileM is defined else 32 %}
|
| 16 |
+
{% set tileNValue = tileN if tileN is defined else 64 %}
|
| 17 |
+
{% set tileKValue = tileK if tileK is defined else 32 %}
|
| 18 |
+
{% set gemmEpi = gemmEpilogue if gemmEpilogue is defined else "none" %}
|
| 19 |
+
{% set epiOpen = "gelu_tanh(" if gemmEpi == "fastgelu" else ("fused_act(" if gemmEpi == "activation" else "") %}
|
| 20 |
+
{% set epiClose = ")" if gemmEpi != "none" else "" %}
|
| 21 |
+
{% set useDoubleBufferedB = doubleBufferedB is defined and doubleBufferedB %}
|
| 22 |
+
{% set aTransposed = aTransposedStorage if aTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 23 |
+
{% set bTransposed = bTransposedStorage if bTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 24 |
+
{% set columnTileBaseValue = columnTileBase if columnTileBase is defined else 0 %}
|
| 25 |
+
{% set rowTileBaseValue = rowTileBase if rowTileBase is defined else 0 %}
|
| 26 |
+
// Four subgroups cover 32xN as a 2x2 grid, or taller tiles as four row bands.
|
| 27 |
+
{% set subtileCols = (tileNValue / 2)|int %}
|
| 28 |
+
{% set subtileRows = 16 %}
|
| 29 |
+
{% set aTilesPerSubgroup = (subtileRows / 8)|int %}
|
| 30 |
+
{% set bTilesPerSubgroup = (subtileCols / 8)|int %}
|
| 31 |
+
{% set subgroupCount = 4 %}
|
| 32 |
+
{% set scratchBanks = subgroupCount * aTilesPerSubgroup * bTilesPerSubgroup %}
|
| 33 |
+
|
| 34 |
+
{% if gemmEpi == "fastgelu" %}
|
| 35 |
+
fn tanh_safe(x: f32) -> f32 {
|
| 36 |
+
if (x > 10.0) { return 1.0; }
|
| 37 |
+
if (x < -10.0) { return -1.0; }
|
| 38 |
+
return tanh(x);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
fn gelu_tanh(v: f32) -> f32 {
|
| 42 |
+
return 0.5 * v * (1.0 + tanh_safe(0.7978845608028654 * (v + 0.044715 * v * v * v)));
|
| 43 |
+
}
|
| 44 |
+
{% elif gemmEpi == "activation" %}
|
| 45 |
+
{% set actMode = gemmActivation | default("") %}
|
| 46 |
+
{% set actA = gemmActAlpha | default(0.0) %}
|
| 47 |
+
{% set actB = gemmActBeta | default(0.0) %}
|
| 48 |
+
fn fused_act(v: f32) -> f32 {
|
| 49 |
+
{% if actMode == "Relu" %}
|
| 50 |
+
return max(v, 0.0);
|
| 51 |
+
{% endif %}
|
| 52 |
+
{% if actMode == "LeakyRelu" %}
|
| 53 |
+
return select(v * f32({{ actA }}), v, v >= 0.0);
|
| 54 |
+
{% endif %}
|
| 55 |
+
{% if actMode == "Sigmoid" %}
|
| 56 |
+
return 1.0 / (1.0 + exp(-v));
|
| 57 |
+
{% endif %}
|
| 58 |
+
{% if actMode == "Tanh" %}
|
| 59 |
+
return tanh(v);
|
| 60 |
+
{% endif %}
|
| 61 |
+
{% if actMode == "HardSigmoid" %}
|
| 62 |
+
return clamp(f32({{ actA }}) * v + f32({{ actB }}), 0.0, 1.0);
|
| 63 |
+
{% endif %}
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
{% endif %}
|
| 67 |
+
const IN_F: u32 = {{ inFeatures }}u;
|
| 68 |
+
const OUT_F: u32 = {{ outFeatures }}u;
|
| 69 |
+
{% set kLoopEndValue = kLoopEnd if kLoopEnd is defined else ("K_LOOP" if tailSafe is defined and tailSafe else "IN_F") %}
|
| 70 |
+
const TILE_COLS: u32 = {{ tileNValue }}u;
|
| 71 |
+
const TILE_ROWS: u32 = {{ tileMValue }}u;
|
| 72 |
+
const TILE_K: u32 = {{ tileKValue }}u;
|
| 73 |
+
const SUB_COLS: u32 = {{ subtileCols }}u;
|
| 74 |
+
const SUB_ROWS: u32 = {{ subtileRows }}u;
|
| 75 |
+
const COLUMN_TILE_BASE: u32 = {{ columnTileBaseValue }}u;
|
| 76 |
+
const ROW_TILE_BASE: u32 = {{ rowTileBaseValue }}u;
|
| 77 |
+
|
| 78 |
+
var<workgroup> tile_A: array<{{ operandScalar }}, {{ tileMValue }} * {{ tileKValue }}>;
|
| 79 |
+
var<workgroup> tile_B: array<{{ operandScalar }}, {{ (2 if useDoubleBufferedB else 1) * tileNValue }} * {{ tileKValue }}>;
|
| 80 |
+
// Distinct readback banks for every result matrix, so one barrier can publish
|
| 81 |
+
// the full subtile without write-after-read reuse.
|
| 82 |
+
var<workgroup> scratch: array<array<{{ accScalar }}, 64>, {{ scratchBanks }}>;
|
| 83 |
+
|
| 84 |
+
fn loadSHMA(tile_base: u32, k_idx: u32, row: u32, c_idx: u32) {
|
| 85 |
+
{% if aTransposed %}
|
| 86 |
+
// Generic transA stores A as [K,M]. Keep both the global and workgroup writes
|
| 87 |
+
// contiguous as [K,tileM], then transpose in subgroupMatrixLoad.
|
| 88 |
+
let local_idx = row * {{ (tileKValue / 8)|int }}u + c_idx;
|
| 89 |
+
let vectors_per_k = TILE_ROWS / 4u;
|
| 90 |
+
let total_vectors = TILE_K * vectors_per_k;
|
| 91 |
+
for (var vector_idx = local_idx; vector_idx < total_vectors; vector_idx += 128u) {
|
| 92 |
+
let k_local = vector_idx / vectors_per_k;
|
| 93 |
+
let m4 = (vector_idx - k_local * vectors_per_k) * 4u;
|
| 94 |
+
for (var component = 0u; component < 4u; component++) {
|
| 95 |
+
let m_local = m4 + component;
|
| 96 |
+
let global_m = tile_base + m_local;
|
| 97 |
+
let global_k = k_idx + k_local;
|
| 98 |
+
tile_A[k_local * TILE_ROWS + m_local] = x[global_k * params.M + global_m];
|
| 99 |
+
}
|
| 100 |
+
}
|
| 101 |
+
{% else %}
|
| 102 |
+
// Clamp the partial-M tail to the last valid row (M-1) instead of zero-filling
|
| 103 |
+
// it. Some subgroup-matrix implementations let a zero-padded left tile corrupt
|
| 104 |
+
// the adjacent valid row. Replicating row M-1 avoids that boundary; the
|
| 105 |
+
// replicated rows are discarded by storeOutput's row_limit guard, so every valid
|
| 106 |
+
// output row stays bit-identical. M >= 1 is guaranteed by the when-clause args.M > 0.
|
| 107 |
+
let col: u32 = c_idx * 8u;
|
| 108 |
+
for (var row_offset: u32 = 0u; row_offset < TILE_ROWS; row_offset += {{ (1024 / tileKValue)|int }}u) {
|
| 109 |
+
let r: u32 = row + row_offset;
|
| 110 |
+
let a_global: u32 = min(tile_base + r, params.M - 1u);
|
| 111 |
+
for (var col_offset: u32 = 0u; col_offset < 8u; col_offset++) {
|
| 112 |
+
let k: u32 = k_idx + col + col_offset;
|
| 113 |
+
tile_A[r * TILE_K + col + col_offset] =
|
| 114 |
+
x[a_global * IN_F + k];
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
{% endif %}
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
fn loadSHMB(tile_base: u32, k_idx: u32, row: u32, c_idx: u32, bank_offset: u32) {
|
| 121 |
+
{% if bTransposed %}
|
| 122 |
+
// Generic transB=0 stores B as [K,N]. Stage that native orientation and load
|
| 123 |
+
// the subgroup right operand without a transpose.
|
| 124 |
+
let local_idx = row * {{ (tileKValue / 16)|int }}u + c_idx;
|
| 125 |
+
let vectors_per_k = TILE_COLS / 4u;
|
| 126 |
+
let total_vectors = TILE_K * vectors_per_k;
|
| 127 |
+
for (var vector_idx = local_idx; vector_idx < total_vectors; vector_idx += 128u) {
|
| 128 |
+
let k_local = vector_idx / vectors_per_k;
|
| 129 |
+
let n4 = (vector_idx - k_local * vectors_per_k) * 4u;
|
| 130 |
+
for (var component = 0u; component < 4u; component++) {
|
| 131 |
+
let n_local = n4 + component;
|
| 132 |
+
let global_n = tile_base + n_local;
|
| 133 |
+
let global_k = k_idx + k_local;
|
| 134 |
+
tile_B[bank_offset + k_local * TILE_COLS + n_local] = w[global_k * OUT_F + global_n];
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
{% else %}
|
| 138 |
+
let col: u32 = c_idx * 16u;
|
| 139 |
+
for (var row_offset: u32 = 0u; row_offset < TILE_COLS; row_offset += {{ (2048 / tileKValue)|int }}u) {
|
| 140 |
+
let b_row: u32 = row + row_offset;
|
| 141 |
+
// Non-power-of-two tuning widths (48/96) use only a prefix of lanes on the
|
| 142 |
+
// final row band. Keep those inactive lanes out of tile_B and global memory.
|
| 143 |
+
if (b_row < TILE_COLS) {
|
| 144 |
+
let w_global: u32 = tile_base + b_row;
|
| 145 |
+
for (var i: u32 = 0u; i < 16u; i++) {
|
| 146 |
+
let k: u32 = k_idx + col + i;
|
| 147 |
+
tile_B[bank_offset + b_row * TILE_K + col + i] =
|
| 148 |
+
w[w_global * IN_F + k];
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
{% endif %}
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
{% set needsColBase = hasBias or (tailSafe is defined and tailSafe) %}
|
| 156 |
+
{% set BIAS_1 = (" + " ~ accScalar ~ "(bias[col_base + col])") if hasBias else "" %}
|
| 157 |
+
{% set BIAS_2 = (" + " ~ accScalar ~ "(bias[col_base + col2])") if hasBias else "" %}
|
| 158 |
+
fn storeOutput(offset: u32{% if needsColBase %}, col_base: u32{% endif %}, row: u32, col: u32, src_slot: u32, row_limit: i32) {
|
| 159 |
+
if (row_limit > 0 && row < u32(row_limit)) {
|
| 160 |
+
let col2: u32 = col + 1u;
|
| 161 |
+
y[offset + row * OUT_F + col] = {{ yScalar }}({{ epiOpen }}scratch[src_slot][row * 8u + col]{{ BIAS_1 }}{{ epiClose }});
|
| 162 |
+
y[offset + row * OUT_F + col2] = {{ yScalar }}({{ epiOpen }}scratch[src_slot][row * 8u + col2]{{ BIAS_2 }}{{ epiClose }});
|
| 163 |
+
}
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
@compute @workgroup_size(128, 1, 1){{ " @subgroup_size(32)" if pinSubgroupSize32 else "" }}
|
| 167 |
+
fn main(
|
| 168 |
+
@builtin(workgroup_id) workgroup_id: vec3<u32>,
|
| 169 |
+
@builtin(num_workgroups) nwg: vec3<u32>,
|
| 170 |
+
@builtin(local_invocation_index) local_idx: u32,
|
| 171 |
+
@builtin(subgroup_invocation_id) sg_id: u32,
|
| 172 |
+
@builtin(subgroup_size) sg_size: u32
|
| 173 |
+
) {
|
| 174 |
+
// 2D-folded M-tile (row) base: workgroup_id.z carries the high bits when the
|
| 175 |
+
// row tile exceeds the per-dimension dispatch limit.
|
| 176 |
+
// Reduces to workgroup_id.y when nwg.z == 1; the row_limit guard in storeOutput
|
| 177 |
+
// (i32(M) - i32(a_global_base + ...)) drops the over-dispatched tail.
|
| 178 |
+
let a_global_base: u32 = (ROW_TILE_BASE + workgroup_id.y + workgroup_id.z * nwg.y) * TILE_ROWS;
|
| 179 |
+
let w_global_base: u32 = (COLUMN_TILE_BASE + workgroup_id.x) * TILE_COLS;
|
| 180 |
+
|
| 181 |
+
let subtile_id: u32 = local_idx / sg_size;
|
| 182 |
+
let subtile_idx: u32 = subtile_id / 2u;
|
| 183 |
+
let subtile_idy: u32 = subtile_id % 2u;
|
| 184 |
+
let base_A: u32 = subtile_idy * SUB_ROWS;
|
| 185 |
+
let base_B: u32 = subtile_idx * SUB_COLS;
|
| 186 |
+
|
| 187 |
+
{% for m in range(aTilesPerSubgroup) %}
|
| 188 |
+
{% for n in range(bTilesPerSubgroup) %}
|
| 189 |
+
var matC{{ m }}{{ n }}: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 190 |
+
{% endfor %}
|
| 191 |
+
{% endfor %}
|
| 192 |
+
|
| 193 |
+
for (var kidx: u32 = 0u; kidx < {{ kLoopEndValue }}; kidx += TILE_K) {
|
| 194 |
+
loadSHMA(a_global_base, kidx, local_idx / {{ (tileKValue / 8)|int }}u, local_idx % {{ (tileKValue / 8)|int }}u);
|
| 195 |
+
loadSHMB(w_global_base, kidx, local_idx / {{ (tileKValue / 16)|int }}u, local_idx % {{ (tileKValue / 16)|int }}u, 0u);
|
| 196 |
+
workgroupBarrier();
|
| 197 |
+
|
| 198 |
+
for (var step: u32 = 0u; step < TILE_K; step += 8u) {
|
| 199 |
+
{% set dynamicATiles = aTilesPerSubgroup if aTilesPerSubgroup is defined else 2 %}
|
| 200 |
+
{% set aTransposed = aTransposedStorage if aTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 201 |
+
{% set bTransposed = bTransposedStorage if bTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 202 |
+
{% set B_BANK = "b_bank_offset + " if doubleBufferedB is defined and doubleBufferedB else "" %}
|
| 203 |
+
{% if aTransposed %}
|
| 204 |
+
let matrix_a_offset = step * TILE_ROWS + subtile_idy * SUB_ROWS;
|
| 205 |
+
{% else %}
|
| 206 |
+
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + step;
|
| 207 |
+
{% endif %}
|
| 208 |
+
{% for m in range(dynamicATiles) %}
|
| 209 |
+
{% if aTransposed %}
|
| 210 |
+
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>>(&tile_A, matrix_a_offset + {{ m * 8 }}u, true, TILE_ROWS);
|
| 211 |
+
{% else %}
|
| 212 |
+
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>>(&tile_A, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * TILE_K{% endif %}, false, TILE_K);
|
| 213 |
+
{% endif %}
|
| 214 |
+
{% endfor %}
|
| 215 |
+
|
| 216 |
+
{% if bTransposed %}
|
| 217 |
+
let matrix_b_offset = {{ B_BANK }}step * TILE_COLS + subtile_idx * SUB_COLS;
|
| 218 |
+
{% else %}
|
| 219 |
+
let matrix_b_offset = {{ B_BANK }}subtile_idx * SUB_COLS * TILE_K + step;
|
| 220 |
+
{% endif %}
|
| 221 |
+
{% for n in range(bTilesPerSubgroup) %}
|
| 222 |
+
{% if bTransposed %}
|
| 223 |
+
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + {{ n * 8 }}u, false, TILE_COLS);
|
| 224 |
+
{% else %}
|
| 225 |
+
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + {{ n * 8 }}u * TILE_K, true, TILE_K);
|
| 226 |
+
{% endif %}
|
| 227 |
+
{% endfor %}
|
| 228 |
+
|
| 229 |
+
{% for m in range(dynamicATiles) %}
|
| 230 |
+
{% for n in range(bTilesPerSubgroup) %}
|
| 231 |
+
matC{{ m }}{{ n }} = subgroupMatrixMultiplyAccumulate(matA{{ m }}, matB{{ n }}, matC{{ m }}{{ n }});
|
| 232 |
+
{% endfor %}
|
| 233 |
+
{% endfor %}
|
| 234 |
+
|
| 235 |
+
}
|
| 236 |
+
workgroupBarrier();
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
let matrix_c_offset: u32 = (a_global_base + base_A) * OUT_F + w_global_base + base_B;
|
| 240 |
+
let row: u32 = sg_id / 4u;
|
| 241 |
+
let col: u32 = (sg_id % 4u) * 2u;
|
| 242 |
+
// Stage every result into a distinct bank before one barrier. Tail/bias paths
|
| 243 |
+
// retain this guarded scalar epilogue: subgroupMatrixStore scatters values
|
| 244 |
+
// across lanes, so its cross-lane readback must be published before partial-M
|
| 245 |
+
// guards diverge. The epilogue also handles output conversion and bias.
|
| 246 |
+
let bank: u32 = subtile_id * {{ aTilesPerSubgroup * bTilesPerSubgroup }}u;
|
| 247 |
+
{% for m in range(aTilesPerSubgroup) %}
|
| 248 |
+
{% for n in range(bTilesPerSubgroup) %}
|
| 249 |
+
subgroupMatrixStore(&scratch[bank + {{ m * bTilesPerSubgroup + n }}u], 0u, matC{{ m }}{{ n }}, false, 8u);
|
| 250 |
+
{% endfor %}
|
| 251 |
+
{% endfor %}
|
| 252 |
+
workgroupBarrier();
|
| 253 |
+
|
| 254 |
+
{% for m in range(aTilesPerSubgroup) %}
|
| 255 |
+
let row_limit_{{ m }}: i32 = i32(params.M) - i32(a_global_base + base_A + {{ m * 8 }}u);
|
| 256 |
+
{% for n in range(bTilesPerSubgroup) %}
|
| 257 |
+
storeOutput(
|
| 258 |
+
matrix_c_offset + {{ m * 8 }}u * OUT_F + {{ n * 8 }}u{% if needsColBase %},
|
| 259 |
+
w_global_base + base_B + {{ n * 8 }}u,
|
| 260 |
+
{% else %},
|
| 261 |
+
{% endif %}
|
| 262 |
+
row,
|
| 263 |
+
col,
|
| 264 |
+
bank + {{ m * bTilesPerSubgroup + n }}u,
|
| 265 |
+
row_limit_{{ m }}
|
| 266 |
+
);
|
| 267 |
+
{% endfor %}
|
| 268 |
+
{% endfor %}
|
| 269 |
+
}
|
build/webgpu/manifest.json
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"domain": "com.microsoft",
|
| 3 |
+
"name": "FusedGemm",
|
| 4 |
+
"sinceVersion": 1,
|
| 5 |
+
"description": "Gemm with a fused activation: `Y = act(alpha * A' * B' + beta * C)`, where `A'` and `B'` are optionally transposed and `C` is broadcastable to `(M, N)`. The activation runs in the f32 accumulator before the single output narrowing. This package supports `Relu`, `LeakyRelu`, `Sigmoid`, `Tanh` and `HardSigmoid`; the other activation strings and numeric types admitted by the open schema are not implemented. Omitting `activation` gives plain Gemm.",
|
| 6 |
+
"inputs": [
|
| 7 |
+
{
|
| 8 |
+
"role": "A",
|
| 9 |
+
"dtype": "T",
|
| 10 |
+
"rank": 2,
|
| 11 |
+
"description": "Left operand, `(M, K)` when `transA` is 0 and `(K, M)` otherwise."
|
| 12 |
+
},
|
| 13 |
+
{
|
| 14 |
+
"role": "B",
|
| 15 |
+
"dtype": "T",
|
| 16 |
+
"rank": 2,
|
| 17 |
+
"description": "Right operand, `(K, N)` when `transB` is 0 and `(N, K)` otherwise."
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"role": "C",
|
| 21 |
+
"dtype": "T",
|
| 22 |
+
"optional": true,
|
| 23 |
+
"description": "Optional additive term, unidirectionally broadcastable to `(M, N)`: a scalar, a row `(N)`, a column `(M, 1)`, or the full matrix."
|
| 24 |
+
}
|
| 25 |
+
],
|
| 26 |
+
"outputs": [
|
| 27 |
+
{
|
| 28 |
+
"role": "Y",
|
| 29 |
+
"dtype": "T",
|
| 30 |
+
"rank": 2,
|
| 31 |
+
"shape": "[gemmM, gemmN]",
|
| 32 |
+
"description": "`act(alpha * A' * B' + beta * C)` with shape `(M, N)`."
|
| 33 |
+
}
|
| 34 |
+
],
|
| 35 |
+
"attributes": { "alpha": 1, "beta": 1, "transA": 0, "transB": 0 },
|
| 36 |
+
"attributeDescriptions": {
|
| 37 |
+
"alpha": "Scalar multiplier for the product `A' * B'`; the standard default is 1.",
|
| 38 |
+
"beta": "Scalar multiplier for `C`; the standard default is 1.",
|
| 39 |
+
"transA": "Whether `A` is stored transposed. The standard default is 0.",
|
| 40 |
+
"transB": "Whether `B` is stored transposed. The standard default is 0.",
|
| 41 |
+
"activation": "Optional fused activation name. Supported modes are `Relu`, `LeakyRelu`, `Sigmoid`, `Tanh` and `HardSigmoid`; omission applies none.",
|
| 42 |
+
"activation_alpha": "First activation parameter: the slope for `LeakyRelu` or `alpha` for `HardSigmoid`.",
|
| 43 |
+
"activation_beta": "Second activation parameter: `beta` for `HardSigmoid`."
|
| 44 |
+
},
|
| 45 |
+
"attributeConstraints": { "activation": { "values": ["Relu", "LeakyRelu", "Sigmoid", "Tanh", "HardSigmoid"] } },
|
| 46 |
+
"typeConstraints": { "T": ["float32", "float16"] },
|
| 47 |
+
"args": {
|
| 48 |
+
"A": { "kind": "tensor", "semantic": "A", "role": "input" },
|
| 49 |
+
"B": { "kind": "tensor", "semantic": "B", "role": "weights" },
|
| 50 |
+
"C": { "kind": "tensor", "semantic": "C", "role": "weights", "required": false },
|
| 51 |
+
"Y": { "kind": "tensor", "semantic": "Y", "role": "output" }
|
| 52 |
+
},
|
| 53 |
+
"derive": {
|
| 54 |
+
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
| 55 |
+
"wave32Adapter": "has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize == 32 and device.adapterInfo.subgroupMaxSize == 32",
|
| 56 |
+
"canPinSubgroupSize32": "device.features.has(\"subgroups\") and device.features.has(\"subgroup-size-control\") and has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize <= 32 and device.adapterInfo.subgroupMaxSize >= 32",
|
| 57 |
+
"pinSubgroupSize32": "canPinSubgroupSize32 and not wave32Adapter",
|
| 58 |
+
"wave32Effective": "wave32Adapter or pinSubgroupSize32",
|
| 59 |
+
"transAFlag": "has(attrs, \"transA\") and attrs.transA != 0",
|
| 60 |
+
"transBFlag": "has(attrs, \"transB\") and attrs.transB != 0",
|
| 61 |
+
"gemmM": "dim(shapes.A, 1) if transAFlag else dim(shapes.A, 0)",
|
| 62 |
+
"gemmK": "dim(shapes.A, 0) if transAFlag else dim(shapes.A, 1)",
|
| 63 |
+
"gemmN": "dim(shapes.B, 0) if transBFlag else dim(shapes.B, 1)",
|
| 64 |
+
"gemmKB": "dim(shapes.B, 1) if transBFlag else dim(shapes.B, 0)",
|
| 65 |
+
"shapeOk": "ranks.A == 2 and ranks.B == 2 and ranks.Y == 2 and gemmK == gemmKB and dim(shapes.Y, 0) == gemmM and dim(shapes.Y, 1) == gemmN",
|
| 66 |
+
"dtypeOk": "(tensorDtypes.A == \"float32\" or tensorDtypes.A == \"float16\") and tensorDtypes.B == tensorDtypes.A and tensorDtypes.Y == tensorDtypes.A and f16Ok(dtypes.T)",
|
| 67 |
+
"rowBiasOk": "present.C and ((ranks.C == 1 and dim(shapes.C, 0) == gemmN) or (ranks.C == 2 and dim(shapes.C, 0) == 1 and dim(shapes.C, 1) == gemmN))",
|
| 68 |
+
"scalarBiasOk": "present.C and (ranks.C == 0 or (ranks.C == 1 and dim(shapes.C, 0) == 1) or (ranks.C == 2 and dim(shapes.C, 0) == 1 and dim(shapes.C, 1) == 1))",
|
| 69 |
+
"columnBiasOk": "present.C and ranks.C == 2 and dim(shapes.C, 0) == gemmM and dim(shapes.C, 1) == 1",
|
| 70 |
+
"matrixBiasOk": "present.C and ranks.C == 2 and dim(shapes.C, 0) == gemmM and dim(shapes.C, 1) == gemmN",
|
| 71 |
+
"cOk": "tensorDtypes.C == tensorDtypes.A and (rowBiasOk or scalarBiasOk or columnBiasOk or matrixBiasOk)",
|
| 72 |
+
"hasActivation": "has(attrs, \"activation\")",
|
| 73 |
+
"activationName": "attrs.activation if hasActivation else \"\"",
|
| 74 |
+
"activationOk": "not hasActivation or activationName == \"Relu\" or activationName == \"LeakyRelu\" or activationName == \"Sigmoid\" or activationName == \"Tanh\" or activationName == \"HardSigmoid\"",
|
| 75 |
+
"activationAlpha": "attrs.activation_alpha if has(attrs, \"activation_alpha\") else (0.2 if activationName == \"HardSigmoid\" else (0.01 if activationName == \"LeakyRelu\" else 0.0))",
|
| 76 |
+
"activationBeta": "attrs.activation_beta if has(attrs, \"activation_beta\") else (0.5 if activationName == \"HardSigmoid\" else 0.0)",
|
| 77 |
+
"baseContract": "shapeOk and dtypeOk and activationOk",
|
| 78 |
+
"noBiasContract": "baseContract and not present.C",
|
| 79 |
+
"biasContract": "baseContract and present.C and cOk",
|
| 80 |
+
"sgmatOperandBytes": "2 if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else 4",
|
| 81 |
+
"sgmatStorageBytes": "(32 * 32 + 64 * 32) * sgmatOperandBytes + 32 * 64 * 4",
|
| 82 |
+
"sgmatResourcesFit": "128 <= deviceWorkgroupCap and sgmatStorageBytes <= device.limits.maxComputeWorkgroupStorageSize",
|
| 83 |
+
"sgmatScalingOk": "(attrs.alpha if has(attrs, \"alpha\") else 1) == 1 and (attrs.beta if has(attrs, \"beta\") else 1) == 1",
|
| 84 |
+
"sgmatLayoutOk": "gemmM > 0 and gemmK % 32 == 0 and gemmN % 64 == 0 and ((tensorDtypes.A == \"float16\" and device.features.has(\"shader-f16\") and gemmM >= 2) or (tensorDtypes.A == \"float32\" and gemmM >= 32)) and ceilDiv(gemmM, 32) <= device.limits.maxComputeWorkgroupsPerDimension and ceilDiv(gemmN, 64) <= device.limits.maxComputeWorkgroupsPerDimension",
|
| 85 |
+
"sgmatContract": "wave32Effective and sgmatLayoutOk and sgmatScalingOk and sgmatResourcesFit",
|
| 86 |
+
"sgmatRowBiasContract": "sgmatContract and rowBiasOk and ranks.C == 1"
|
| 87 |
+
},
|
| 88 |
+
"constants": {
|
| 89 |
+
"usesF16": "tensorDtypes.A == \"float16\"",
|
| 90 |
+
"gemmActivation": "activationName",
|
| 91 |
+
"gemmActAlpha": "activationAlpha",
|
| 92 |
+
"gemmActBeta": "activationBeta",
|
| 93 |
+
"gemmEpilogue": "\"activation\" if hasActivation else \"none\""
|
| 94 |
+
},
|
| 95 |
+
"bindingSets": {
|
| 96 |
+
"noBias": [
|
| 97 |
+
{ "name": "a", "arg": "A", "semantic": "A", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 98 |
+
{ "name": "b", "arg": "B", "semantic": "B", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 99 |
+
{ "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$T" },
|
| 100 |
+
{
|
| 101 |
+
"name": "params",
|
| 102 |
+
"semantic": "kernel.params",
|
| 103 |
+
"buffer": { "type": "uniform" },
|
| 104 |
+
"struct": {
|
| 105 |
+
"name": "Params",
|
| 106 |
+
"fields": [
|
| 107 |
+
{ "name": "M", "type": "u32", "value": "gemmM" },
|
| 108 |
+
{ "name": "N", "type": "u32", "value": "gemmN" },
|
| 109 |
+
{ "name": "K", "type": "u32", "value": "gemmK" },
|
| 110 |
+
{ "name": "alpha", "type": "f32", "value": "attrs.alpha if has(attrs, \"alpha\") else 1" }
|
| 111 |
+
]
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
],
|
| 115 |
+
"withBias": [
|
| 116 |
+
{ "name": "a", "arg": "A", "semantic": "A", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 117 |
+
{ "name": "b", "arg": "B", "semantic": "B", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 118 |
+
{ "name": "bias", "arg": "C", "semantic": "C", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 119 |
+
{ "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$T" },
|
| 120 |
+
{
|
| 121 |
+
"name": "params",
|
| 122 |
+
"semantic": "kernel.params",
|
| 123 |
+
"buffer": { "type": "uniform" },
|
| 124 |
+
"struct": {
|
| 125 |
+
"name": "Params",
|
| 126 |
+
"fields": [
|
| 127 |
+
{ "name": "M", "type": "u32", "value": "gemmM" },
|
| 128 |
+
{ "name": "N", "type": "u32", "value": "gemmN" },
|
| 129 |
+
{ "name": "K", "type": "u32", "value": "gemmK" },
|
| 130 |
+
{ "name": "alpha", "type": "f32", "value": "attrs.alpha if has(attrs, \"alpha\") else 1" },
|
| 131 |
+
{ "name": "beta", "type": "f32", "value": "attrs.beta if has(attrs, \"beta\") else 1" }
|
| 132 |
+
]
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
],
|
| 136 |
+
"sgmatNoBias": [
|
| 137 |
+
{ "name": "x", "arg": "A", "semantic": "A", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 138 |
+
{ "name": "w", "arg": "B", "semantic": "B", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 139 |
+
{ "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$T" },
|
| 140 |
+
{
|
| 141 |
+
"name": "params",
|
| 142 |
+
"semantic": "kernel.params",
|
| 143 |
+
"buffer": { "type": "uniform" },
|
| 144 |
+
"struct": { "name": "Params", "fields": [{ "name": "M", "type": "u32", "value": "gemmM" }] }
|
| 145 |
+
}
|
| 146 |
+
],
|
| 147 |
+
"sgmatBias": [
|
| 148 |
+
{ "name": "x", "arg": "A", "semantic": "A", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 149 |
+
{ "name": "w", "arg": "B", "semantic": "B", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 150 |
+
{ "name": "bias", "arg": "C", "semantic": "C", "buffer": { "type": "read-only-storage" }, "elementType": "$T" },
|
| 151 |
+
{ "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$T" },
|
| 152 |
+
{
|
| 153 |
+
"name": "params",
|
| 154 |
+
"semantic": "kernel.params",
|
| 155 |
+
"buffer": { "type": "uniform" },
|
| 156 |
+
"struct": { "name": "Params", "fields": [{ "name": "M", "type": "u32", "value": "gemmM" }] }
|
| 157 |
+
}
|
| 158 |
+
]
|
| 159 |
+
},
|
| 160 |
+
"variants": [
|
| 161 |
+
{
|
| 162 |
+
"id": "notrans_sgmat_bias",
|
| 163 |
+
"priority": 100,
|
| 164 |
+
"requires": {
|
| 165 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 166 |
+
"subgroupMatrixConfigs": [
|
| 167 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 168 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 169 |
+
]
|
| 170 |
+
},
|
| 171 |
+
"when": ["sgmatRowBiasContract", "transAFlag == false", "transBFlag == false"],
|
| 172 |
+
"constants": {
|
| 173 |
+
"hasBias": true,
|
| 174 |
+
"aTransposedStorage": false,
|
| 175 |
+
"bTransposedStorage": "not false",
|
| 176 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 177 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 178 |
+
"bScalar": "\"f16\" if tensorDtypes.C == \"float16\" else \"f32\"",
|
| 179 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 180 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 181 |
+
"inFeatures": "gemmK",
|
| 182 |
+
"outFeatures": "gemmN"
|
| 183 |
+
},
|
| 184 |
+
"passes": [
|
| 185 |
+
{
|
| 186 |
+
"id": "main",
|
| 187 |
+
"name": "FusedGemm.SubgroupMatrixBias",
|
| 188 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 189 |
+
"bindings": "sgmatBias",
|
| 190 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 191 |
+
}
|
| 192 |
+
]
|
| 193 |
+
},
|
| 194 |
+
{
|
| 195 |
+
"id": "notrans_sgmat",
|
| 196 |
+
"priority": 100,
|
| 197 |
+
"requires": {
|
| 198 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 199 |
+
"subgroupMatrixConfigs": [
|
| 200 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 201 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 202 |
+
]
|
| 203 |
+
},
|
| 204 |
+
"when": ["noBiasContract and sgmatContract", "transAFlag == false", "transBFlag == false"],
|
| 205 |
+
"constants": {
|
| 206 |
+
"hasBias": false,
|
| 207 |
+
"aTransposedStorage": false,
|
| 208 |
+
"bTransposedStorage": "not false",
|
| 209 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 210 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 211 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 212 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 213 |
+
"inFeatures": "gemmK",
|
| 214 |
+
"outFeatures": "gemmN"
|
| 215 |
+
},
|
| 216 |
+
"passes": [
|
| 217 |
+
{
|
| 218 |
+
"id": "main",
|
| 219 |
+
"name": "FusedGemm.SubgroupMatrix",
|
| 220 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 221 |
+
"bindings": "sgmatNoBias",
|
| 222 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 223 |
+
}
|
| 224 |
+
]
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"id": "transA_sgmat_bias",
|
| 228 |
+
"priority": 100,
|
| 229 |
+
"requires": {
|
| 230 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 231 |
+
"subgroupMatrixConfigs": [
|
| 232 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 233 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 234 |
+
]
|
| 235 |
+
},
|
| 236 |
+
"when": ["sgmatRowBiasContract", "transAFlag == true", "transBFlag == false"],
|
| 237 |
+
"constants": {
|
| 238 |
+
"hasBias": true,
|
| 239 |
+
"aTransposedStorage": true,
|
| 240 |
+
"bTransposedStorage": "not false",
|
| 241 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 242 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 243 |
+
"bScalar": "\"f16\" if tensorDtypes.C == \"float16\" else \"f32\"",
|
| 244 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 245 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 246 |
+
"inFeatures": "gemmK",
|
| 247 |
+
"outFeatures": "gemmN"
|
| 248 |
+
},
|
| 249 |
+
"passes": [
|
| 250 |
+
{
|
| 251 |
+
"id": "main",
|
| 252 |
+
"name": "FusedGemm.SubgroupMatrixBias",
|
| 253 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 254 |
+
"bindings": "sgmatBias",
|
| 255 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 256 |
+
}
|
| 257 |
+
]
|
| 258 |
+
},
|
| 259 |
+
{
|
| 260 |
+
"id": "transA_sgmat",
|
| 261 |
+
"priority": 100,
|
| 262 |
+
"requires": {
|
| 263 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 264 |
+
"subgroupMatrixConfigs": [
|
| 265 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 266 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 267 |
+
]
|
| 268 |
+
},
|
| 269 |
+
"when": ["noBiasContract and sgmatContract", "transAFlag == true", "transBFlag == false"],
|
| 270 |
+
"constants": {
|
| 271 |
+
"hasBias": false,
|
| 272 |
+
"aTransposedStorage": true,
|
| 273 |
+
"bTransposedStorage": "not false",
|
| 274 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 275 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 276 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 277 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 278 |
+
"inFeatures": "gemmK",
|
| 279 |
+
"outFeatures": "gemmN"
|
| 280 |
+
},
|
| 281 |
+
"passes": [
|
| 282 |
+
{
|
| 283 |
+
"id": "main",
|
| 284 |
+
"name": "FusedGemm.SubgroupMatrix",
|
| 285 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 286 |
+
"bindings": "sgmatNoBias",
|
| 287 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 288 |
+
}
|
| 289 |
+
]
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
"id": "transB_sgmat_bias",
|
| 293 |
+
"priority": 100,
|
| 294 |
+
"requires": {
|
| 295 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 296 |
+
"subgroupMatrixConfigs": [
|
| 297 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 298 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 299 |
+
]
|
| 300 |
+
},
|
| 301 |
+
"when": ["sgmatRowBiasContract", "transAFlag == false", "transBFlag == true"],
|
| 302 |
+
"constants": {
|
| 303 |
+
"hasBias": true,
|
| 304 |
+
"aTransposedStorage": false,
|
| 305 |
+
"bTransposedStorage": "not true",
|
| 306 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 307 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 308 |
+
"bScalar": "\"f16\" if tensorDtypes.C == \"float16\" else \"f32\"",
|
| 309 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 310 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 311 |
+
"inFeatures": "gemmK",
|
| 312 |
+
"outFeatures": "gemmN"
|
| 313 |
+
},
|
| 314 |
+
"passes": [
|
| 315 |
+
{
|
| 316 |
+
"id": "main",
|
| 317 |
+
"name": "FusedGemm.SubgroupMatrixBias",
|
| 318 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 319 |
+
"bindings": "sgmatBias",
|
| 320 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 321 |
+
}
|
| 322 |
+
]
|
| 323 |
+
},
|
| 324 |
+
{
|
| 325 |
+
"id": "transB_sgmat",
|
| 326 |
+
"priority": 100,
|
| 327 |
+
"requires": {
|
| 328 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 329 |
+
"subgroupMatrixConfigs": [
|
| 330 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 331 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 332 |
+
]
|
| 333 |
+
},
|
| 334 |
+
"when": ["noBiasContract and sgmatContract", "transAFlag == false", "transBFlag == true"],
|
| 335 |
+
"constants": {
|
| 336 |
+
"hasBias": false,
|
| 337 |
+
"aTransposedStorage": false,
|
| 338 |
+
"bTransposedStorage": "not true",
|
| 339 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 340 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 341 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 342 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 343 |
+
"inFeatures": "gemmK",
|
| 344 |
+
"outFeatures": "gemmN"
|
| 345 |
+
},
|
| 346 |
+
"passes": [
|
| 347 |
+
{
|
| 348 |
+
"id": "main",
|
| 349 |
+
"name": "FusedGemm.SubgroupMatrix",
|
| 350 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 351 |
+
"bindings": "sgmatNoBias",
|
| 352 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 353 |
+
}
|
| 354 |
+
]
|
| 355 |
+
},
|
| 356 |
+
{
|
| 357 |
+
"id": "transAB_sgmat_bias",
|
| 358 |
+
"priority": 100,
|
| 359 |
+
"requires": {
|
| 360 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 361 |
+
"subgroupMatrixConfigs": [
|
| 362 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 363 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 364 |
+
]
|
| 365 |
+
},
|
| 366 |
+
"when": ["sgmatRowBiasContract", "transAFlag == true", "transBFlag == true"],
|
| 367 |
+
"constants": {
|
| 368 |
+
"hasBias": true,
|
| 369 |
+
"aTransposedStorage": true,
|
| 370 |
+
"bTransposedStorage": "not true",
|
| 371 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 372 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 373 |
+
"bScalar": "\"f16\" if tensorDtypes.C == \"float16\" else \"f32\"",
|
| 374 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 375 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 376 |
+
"inFeatures": "gemmK",
|
| 377 |
+
"outFeatures": "gemmN"
|
| 378 |
+
},
|
| 379 |
+
"passes": [
|
| 380 |
+
{
|
| 381 |
+
"id": "main",
|
| 382 |
+
"name": "FusedGemm.SubgroupMatrixBias",
|
| 383 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 384 |
+
"bindings": "sgmatBias",
|
| 385 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 386 |
+
}
|
| 387 |
+
]
|
| 388 |
+
},
|
| 389 |
+
{
|
| 390 |
+
"id": "transAB_sgmat",
|
| 391 |
+
"priority": 100,
|
| 392 |
+
"requires": {
|
| 393 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 394 |
+
"subgroupMatrixConfigs": [
|
| 395 |
+
{ "componentType": "f16", "M": 8, "N": 8, "K": 8 },
|
| 396 |
+
{ "componentType": "f32", "resultComponentType": "f32", "M": 8, "N": 8, "K": 8 }
|
| 397 |
+
]
|
| 398 |
+
},
|
| 399 |
+
"when": ["noBiasContract and sgmatContract", "transAFlag == true", "transBFlag == true"],
|
| 400 |
+
"constants": {
|
| 401 |
+
"hasBias": false,
|
| 402 |
+
"aTransposedStorage": true,
|
| 403 |
+
"bTransposedStorage": "not true",
|
| 404 |
+
"xScalar": "\"f16\" if tensorDtypes.A == \"float16\" else \"f32\"",
|
| 405 |
+
"wScalar": "\"f16\" if tensorDtypes.B == \"float16\" else \"f32\"",
|
| 406 |
+
"yScalar": "\"f16\" if tensorDtypes.Y == \"float16\" else \"f32\"",
|
| 407 |
+
"mmaScalar": "\"f16\" if tensorDtypes.A == \"float16\" and tensorDtypes.B == \"float16\" else \"f32\"",
|
| 408 |
+
"inFeatures": "gemmK",
|
| 409 |
+
"outFeatures": "gemmN"
|
| 410 |
+
},
|
| 411 |
+
"passes": [
|
| 412 |
+
{
|
| 413 |
+
"id": "main",
|
| 414 |
+
"name": "FusedGemm.SubgroupMatrix",
|
| 415 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 416 |
+
"bindings": "sgmatNoBias",
|
| 417 |
+
"dispatch": { "workgroups": "ceilDiv(gemmM, 32)", "x": "ceilDiv(gemmN, 64)" }
|
| 418 |
+
}
|
| 419 |
+
]
|
| 420 |
+
},
|
| 421 |
+
{
|
| 422 |
+
"id": "notrans_bias",
|
| 423 |
+
"priority": 0,
|
| 424 |
+
"when": ["biasContract", "transAFlag == false", "transBFlag == false"],
|
| 425 |
+
"constants": {
|
| 426 |
+
"transA": false,
|
| 427 |
+
"transB": false,
|
| 428 |
+
"hasBias": true,
|
| 429 |
+
"rowBias": "rowBiasOk",
|
| 430 |
+
"scalarBias": "scalarBiasOk",
|
| 431 |
+
"columnBias": "columnBiasOk"
|
| 432 |
+
},
|
| 433 |
+
"passes": [
|
| 434 |
+
{
|
| 435 |
+
"id": "main",
|
| 436 |
+
"name": "FusedGemm.Bias",
|
| 437 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 438 |
+
"bindings": "withBias",
|
| 439 |
+
"dispatch": {
|
| 440 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 441 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 442 |
+
}
|
| 443 |
+
}
|
| 444 |
+
]
|
| 445 |
+
},
|
| 446 |
+
{
|
| 447 |
+
"id": "notrans",
|
| 448 |
+
"priority": 0,
|
| 449 |
+
"when": ["noBiasContract", "transAFlag == false", "transBFlag == false"],
|
| 450 |
+
"constants": { "transA": false, "transB": false, "hasBias": false },
|
| 451 |
+
"passes": [
|
| 452 |
+
{
|
| 453 |
+
"id": "main",
|
| 454 |
+
"name": "FusedGemm",
|
| 455 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 456 |
+
"bindings": "noBias",
|
| 457 |
+
"dispatch": {
|
| 458 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 459 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 460 |
+
}
|
| 461 |
+
}
|
| 462 |
+
]
|
| 463 |
+
},
|
| 464 |
+
{
|
| 465 |
+
"id": "transA_bias",
|
| 466 |
+
"priority": 0,
|
| 467 |
+
"when": ["biasContract", "transAFlag == true", "transBFlag == false"],
|
| 468 |
+
"constants": {
|
| 469 |
+
"transA": true,
|
| 470 |
+
"transB": false,
|
| 471 |
+
"hasBias": true,
|
| 472 |
+
"rowBias": "rowBiasOk",
|
| 473 |
+
"scalarBias": "scalarBiasOk",
|
| 474 |
+
"columnBias": "columnBiasOk"
|
| 475 |
+
},
|
| 476 |
+
"passes": [
|
| 477 |
+
{
|
| 478 |
+
"id": "main",
|
| 479 |
+
"name": "FusedGemm.Bias",
|
| 480 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 481 |
+
"bindings": "withBias",
|
| 482 |
+
"dispatch": {
|
| 483 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 484 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 485 |
+
}
|
| 486 |
+
}
|
| 487 |
+
]
|
| 488 |
+
},
|
| 489 |
+
{
|
| 490 |
+
"id": "transA",
|
| 491 |
+
"priority": 0,
|
| 492 |
+
"when": ["noBiasContract", "transAFlag == true", "transBFlag == false"],
|
| 493 |
+
"constants": { "transA": true, "transB": false, "hasBias": false },
|
| 494 |
+
"passes": [
|
| 495 |
+
{
|
| 496 |
+
"id": "main",
|
| 497 |
+
"name": "FusedGemm",
|
| 498 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 499 |
+
"bindings": "noBias",
|
| 500 |
+
"dispatch": {
|
| 501 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 502 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 503 |
+
}
|
| 504 |
+
}
|
| 505 |
+
]
|
| 506 |
+
},
|
| 507 |
+
{
|
| 508 |
+
"id": "transB_bias",
|
| 509 |
+
"priority": 0,
|
| 510 |
+
"when": ["biasContract", "transAFlag == false", "transBFlag == true"],
|
| 511 |
+
"constants": {
|
| 512 |
+
"transA": false,
|
| 513 |
+
"transB": true,
|
| 514 |
+
"hasBias": true,
|
| 515 |
+
"rowBias": "rowBiasOk",
|
| 516 |
+
"scalarBias": "scalarBiasOk",
|
| 517 |
+
"columnBias": "columnBiasOk"
|
| 518 |
+
},
|
| 519 |
+
"passes": [
|
| 520 |
+
{
|
| 521 |
+
"id": "main",
|
| 522 |
+
"name": "FusedGemm.Bias",
|
| 523 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 524 |
+
"bindings": "withBias",
|
| 525 |
+
"dispatch": {
|
| 526 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 527 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 528 |
+
}
|
| 529 |
+
}
|
| 530 |
+
]
|
| 531 |
+
},
|
| 532 |
+
{
|
| 533 |
+
"id": "transB",
|
| 534 |
+
"priority": 0,
|
| 535 |
+
"when": ["noBiasContract", "transAFlag == false", "transBFlag == true"],
|
| 536 |
+
"constants": { "transA": false, "transB": true, "hasBias": false },
|
| 537 |
+
"passes": [
|
| 538 |
+
{
|
| 539 |
+
"id": "main",
|
| 540 |
+
"name": "FusedGemm",
|
| 541 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 542 |
+
"bindings": "noBias",
|
| 543 |
+
"dispatch": {
|
| 544 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 545 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 546 |
+
}
|
| 547 |
+
}
|
| 548 |
+
]
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"id": "transAB_bias",
|
| 552 |
+
"priority": 0,
|
| 553 |
+
"when": ["biasContract", "transAFlag == true", "transBFlag == true"],
|
| 554 |
+
"constants": {
|
| 555 |
+
"transA": true,
|
| 556 |
+
"transB": true,
|
| 557 |
+
"hasBias": true,
|
| 558 |
+
"rowBias": "rowBiasOk",
|
| 559 |
+
"scalarBias": "scalarBiasOk",
|
| 560 |
+
"columnBias": "columnBiasOk"
|
| 561 |
+
},
|
| 562 |
+
"passes": [
|
| 563 |
+
{
|
| 564 |
+
"id": "main",
|
| 565 |
+
"name": "FusedGemm.Bias",
|
| 566 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 567 |
+
"bindings": "withBias",
|
| 568 |
+
"dispatch": {
|
| 569 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 570 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 571 |
+
}
|
| 572 |
+
}
|
| 573 |
+
]
|
| 574 |
+
},
|
| 575 |
+
{
|
| 576 |
+
"id": "transAB",
|
| 577 |
+
"priority": 0,
|
| 578 |
+
"when": ["noBiasContract", "transAFlag == true", "transBFlag == true"],
|
| 579 |
+
"constants": { "transA": true, "transB": true, "hasBias": false },
|
| 580 |
+
"passes": [
|
| 581 |
+
{
|
| 582 |
+
"id": "main",
|
| 583 |
+
"name": "FusedGemm",
|
| 584 |
+
"shader": "fused-gemm.wgsl.jinja",
|
| 585 |
+
"bindings": "noBias",
|
| 586 |
+
"dispatch": {
|
| 587 |
+
"x": "min(ceilDiv(gemmN, 64), device.limits.maxComputeWorkgroupsPerDimension)",
|
| 588 |
+
"y": "min(ceilDiv(gemmM, 64), device.limits.maxComputeWorkgroupsPerDimension)"
|
| 589 |
+
}
|
| 590 |
+
}
|
| 591 |
+
]
|
| 592 |
+
}
|
| 593 |
+
]
|
| 594 |
+
}
|
build/webgpu/metadata.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "com.microsoft.FusedGemm",
|
| 3 |
+
"id": "_com_microsoft_fusedgemm_webgpu_afa4467",
|
| 4 |
+
"version": 1,
|
| 5 |
+
"license": "Apache-2.0",
|
| 6 |
+
"backend": { "type": "webgpu" },
|
| 7 |
+
"digest": {
|
| 8 |
+
"algorithm": "sha256",
|
| 9 |
+
"files": {
|
| 10 |
+
"bench.json": "5+Pgon1ED+99xPL6smxxz2G47C5gDnfB0kJ+Zj2wZLc=",
|
| 11 |
+
"fused-gemm.wgsl.jinja": "IkB53JqVNn9Xezw0YcKYDvm9IwDvoZNnSeA/UY4Eci4=",
|
| 12 |
+
"gemm-subgroup-matrix.wgsl.jinja": "gk0C1ZhDuTerG8rDtHYjQp74zieMlGP6QeFm0XqRZSw=",
|
| 13 |
+
"manifest.json": "s7cSq5so+VQS0XTbiHalmSHGnQQA2ylTu524o3V815U=",
|
| 14 |
+
"test.json": "xyQ7rg3TZtQ7zZA5W25GP1jcfMvCLIWiBlk6ASHNmi0="
|
| 15 |
+
}
|
| 16 |
+
},
|
| 17 |
+
"provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
|
| 18 |
+
"webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.FusedGemm" }
|
| 19 |
+
}
|
build/webgpu/test.json
ADDED
|
@@ -0,0 +1,662 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "com.microsoft.FusedGemm",
|
| 3 |
+
"cases": [
|
| 4 |
+
{
|
| 5 |
+
"name": "notrans_rowbias_relu",
|
| 6 |
+
"provenance": { "notes": "No transpose, a row bias, and Relu." },
|
| 7 |
+
"attrs": { "activation": "Relu" },
|
| 8 |
+
"inputs": {
|
| 9 |
+
"A": {
|
| 10 |
+
"dtype": "float32",
|
| 11 |
+
"shape": [96, 80],
|
| 12 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.18000000000000002, "cosStep": 0.32 }
|
| 13 |
+
},
|
| 14 |
+
"B": {
|
| 15 |
+
"dtype": "float32",
|
| 16 |
+
"shape": [80, 72],
|
| 17 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.12, "cosStep": 0.24000000000000002 }
|
| 18 |
+
},
|
| 19 |
+
"C": {
|
| 20 |
+
"dtype": "float32",
|
| 21 |
+
"shape": [72],
|
| 22 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.3, "cosStep": 0.14 }
|
| 23 |
+
}
|
| 24 |
+
},
|
| 25 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [96, 72], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"name": "transa_rowbias_relu",
|
| 29 |
+
"provenance": { "notes": "transA: A stored (K, M), which changes only the load index." },
|
| 30 |
+
"attrs": { "transA": 1, "activation": "Relu" },
|
| 31 |
+
"inputs": {
|
| 32 |
+
"A": {
|
| 33 |
+
"dtype": "float32",
|
| 34 |
+
"shape": [80, 96],
|
| 35 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.19, "cosStep": 0.33 }
|
| 36 |
+
},
|
| 37 |
+
"B": {
|
| 38 |
+
"dtype": "float32",
|
| 39 |
+
"shape": [80, 72],
|
| 40 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.13, "cosStep": 0.25 }
|
| 41 |
+
},
|
| 42 |
+
"C": {
|
| 43 |
+
"dtype": "float32",
|
| 44 |
+
"shape": [72],
|
| 45 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.31, "cosStep": 0.15 }
|
| 46 |
+
}
|
| 47 |
+
},
|
| 48 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [96, 72], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"name": "transb_rowbias_leaky",
|
| 52 |
+
"provenance": { "notes": "transB with LeakyRelu at its default slope of 0.01." },
|
| 53 |
+
"attrs": { "transB": 1, "activation": "LeakyRelu" },
|
| 54 |
+
"inputs": {
|
| 55 |
+
"A": {
|
| 56 |
+
"dtype": "float32",
|
| 57 |
+
"shape": [96, 80],
|
| 58 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.2, "cosStep": 0.33999999999999997 }
|
| 59 |
+
},
|
| 60 |
+
"B": {
|
| 61 |
+
"dtype": "float32",
|
| 62 |
+
"shape": [72, 80],
|
| 63 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.14, "cosStep": 0.26 }
|
| 64 |
+
},
|
| 65 |
+
"C": {
|
| 66 |
+
"dtype": "float32",
|
| 67 |
+
"shape": [72],
|
| 68 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.31999999999999995, "cosStep": 0.16 }
|
| 69 |
+
}
|
| 70 |
+
},
|
| 71 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [96, 72], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"name": "transab_rowbias_tanh",
|
| 75 |
+
"provenance": { "notes": "Both operands transposed, with Tanh." },
|
| 76 |
+
"attrs": { "transA": 1, "transB": 1, "activation": "Tanh" },
|
| 77 |
+
"inputs": {
|
| 78 |
+
"A": {
|
| 79 |
+
"dtype": "float32",
|
| 80 |
+
"shape": [80, 96],
|
| 81 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.21000000000000002, "cosStep": 0.35 }
|
| 82 |
+
},
|
| 83 |
+
"B": {
|
| 84 |
+
"dtype": "float32",
|
| 85 |
+
"shape": [72, 80],
|
| 86 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.15, "cosStep": 0.27 }
|
| 87 |
+
},
|
| 88 |
+
"C": {
|
| 89 |
+
"dtype": "float32",
|
| 90 |
+
"shape": [72],
|
| 91 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.32999999999999996, "cosStep": 0.17 }
|
| 92 |
+
}
|
| 93 |
+
},
|
| 94 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [96, 72], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"name": "notrans_nobias_sigmoid",
|
| 98 |
+
"provenance": { "notes": "No bias at all -- the other binding set -- with Sigmoid." },
|
| 99 |
+
"attrs": { "activation": "Sigmoid" },
|
| 100 |
+
"inputs": {
|
| 101 |
+
"A": {
|
| 102 |
+
"dtype": "float32",
|
| 103 |
+
"shape": [96, 80],
|
| 104 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.22000000000000003, "cosStep": 0.36 }
|
| 105 |
+
},
|
| 106 |
+
"B": {
|
| 107 |
+
"dtype": "float32",
|
| 108 |
+
"shape": [80, 72],
|
| 109 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.16, "cosStep": 0.28 }
|
| 110 |
+
}
|
| 111 |
+
},
|
| 112 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [96, 72], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"name": "transa_nobias_none",
|
| 116 |
+
"provenance": { "notes": "transA with no bias and no activation, which is plain Gemm." },
|
| 117 |
+
"attrs": { "transA": 1 },
|
| 118 |
+
"inputs": {
|
| 119 |
+
"A": {
|
| 120 |
+
"dtype": "float32",
|
| 121 |
+
"shape": [48, 64],
|
| 122 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.23, "cosStep": 0.37 }
|
| 123 |
+
},
|
| 124 |
+
"B": {
|
| 125 |
+
"dtype": "float32",
|
| 126 |
+
"shape": [48, 40],
|
| 127 |
+
"data": {
|
| 128 |
+
"kind": "fillFloat32",
|
| 129 |
+
"scale": 0.6,
|
| 130 |
+
"sinStep": 0.16999999999999998,
|
| 131 |
+
"cosStep": 0.29000000000000004
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
},
|
| 135 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 40], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"name": "transab_nobias_hardsigmoid",
|
| 139 |
+
"provenance": { "notes": "Both transposed, HardSigmoid at its 0.2/0.5 defaults." },
|
| 140 |
+
"attrs": { "transA": 1, "transB": 1, "activation": "HardSigmoid" },
|
| 141 |
+
"inputs": {
|
| 142 |
+
"A": {
|
| 143 |
+
"dtype": "float32",
|
| 144 |
+
"shape": [48, 64],
|
| 145 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.25, "cosStep": 0.39 }
|
| 146 |
+
},
|
| 147 |
+
"B": {
|
| 148 |
+
"dtype": "float32",
|
| 149 |
+
"shape": [40, 48],
|
| 150 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.19, "cosStep": 0.31 }
|
| 151 |
+
}
|
| 152 |
+
},
|
| 153 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 40], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"name": "scalar_bias_relu",
|
| 157 |
+
"provenance": { "notes": "A scalar C, broadcast to every element." },
|
| 158 |
+
"attrs": { "activation": "Relu" },
|
| 159 |
+
"inputs": {
|
| 160 |
+
"A": {
|
| 161 |
+
"dtype": "float32",
|
| 162 |
+
"shape": [48, 32],
|
| 163 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.26, "cosStep": 0.4 }
|
| 164 |
+
},
|
| 165 |
+
"B": {
|
| 166 |
+
"dtype": "float32",
|
| 167 |
+
"shape": [32, 24],
|
| 168 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.2, "cosStep": 0.32 }
|
| 169 |
+
},
|
| 170 |
+
"C": {
|
| 171 |
+
"dtype": "float32",
|
| 172 |
+
"shape": [1],
|
| 173 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.38, "cosStep": 0.22 }
|
| 174 |
+
}
|
| 175 |
+
},
|
| 176 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [48, 24], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"name": "column_bias_relu",
|
| 180 |
+
"provenance": { "notes": "A column C of shape (M, 1)." },
|
| 181 |
+
"attrs": { "activation": "Relu" },
|
| 182 |
+
"inputs": {
|
| 183 |
+
"A": {
|
| 184 |
+
"dtype": "float32",
|
| 185 |
+
"shape": [48, 32],
|
| 186 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.27, "cosStep": 0.41000000000000003 }
|
| 187 |
+
},
|
| 188 |
+
"B": {
|
| 189 |
+
"dtype": "float32",
|
| 190 |
+
"shape": [32, 24],
|
| 191 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.21000000000000002, "cosStep": 0.33 }
|
| 192 |
+
},
|
| 193 |
+
"C": {
|
| 194 |
+
"dtype": "float32",
|
| 195 |
+
"shape": [48, 1],
|
| 196 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.39, "cosStep": 0.23 }
|
| 197 |
+
}
|
| 198 |
+
},
|
| 199 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [48, 24], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 200 |
+
},
|
| 201 |
+
{
|
| 202 |
+
"name": "matrix_bias_relu",
|
| 203 |
+
"provenance": { "notes": "A full (M, N) C." },
|
| 204 |
+
"attrs": { "activation": "Relu" },
|
| 205 |
+
"inputs": {
|
| 206 |
+
"A": {
|
| 207 |
+
"dtype": "float32",
|
| 208 |
+
"shape": [48, 32],
|
| 209 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.28, "cosStep": 0.42 }
|
| 210 |
+
},
|
| 211 |
+
"B": {
|
| 212 |
+
"dtype": "float32",
|
| 213 |
+
"shape": [32, 24],
|
| 214 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.22, "cosStep": 0.34 }
|
| 215 |
+
},
|
| 216 |
+
"C": {
|
| 217 |
+
"dtype": "float32",
|
| 218 |
+
"shape": [48, 24],
|
| 219 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.39999999999999997, "cosStep": 0.24 }
|
| 220 |
+
}
|
| 221 |
+
},
|
| 222 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [48, 24], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 223 |
+
},
|
| 224 |
+
{
|
| 225 |
+
"name": "row2d_bias_tanh",
|
| 226 |
+
"provenance": { "notes": "A (1, N) C, the rank-2 spelling of a row bias." },
|
| 227 |
+
"attrs": { "activation": "Tanh" },
|
| 228 |
+
"inputs": {
|
| 229 |
+
"A": {
|
| 230 |
+
"dtype": "float32",
|
| 231 |
+
"shape": [48, 32],
|
| 232 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.29000000000000004, "cosStep": 0.43 }
|
| 233 |
+
},
|
| 234 |
+
"B": {
|
| 235 |
+
"dtype": "float32",
|
| 236 |
+
"shape": [32, 24],
|
| 237 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.22999999999999998, "cosStep": 0.35 }
|
| 238 |
+
},
|
| 239 |
+
"C": {
|
| 240 |
+
"dtype": "float32",
|
| 241 |
+
"shape": [1, 24],
|
| 242 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.41, "cosStep": 0.25 }
|
| 243 |
+
}
|
| 244 |
+
},
|
| 245 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [48, 24], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 246 |
+
},
|
| 247 |
+
{
|
| 248 |
+
"name": "alpha_beta_leaky_explicit",
|
| 249 |
+
"provenance": { "notes": "Explicit alpha, beta and LeakyRelu slope, none of them defaults." },
|
| 250 |
+
"attrs": { "alpha": 0.5, "beta": 2, "activation": "LeakyRelu", "activation_alpha": 0.25 },
|
| 251 |
+
"inputs": {
|
| 252 |
+
"A": {
|
| 253 |
+
"dtype": "float32",
|
| 254 |
+
"shape": [48, 32],
|
| 255 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.30000000000000004, "cosStep": 0.44 }
|
| 256 |
+
},
|
| 257 |
+
"B": {
|
| 258 |
+
"dtype": "float32",
|
| 259 |
+
"shape": [32, 24],
|
| 260 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.24, "cosStep": 0.36 }
|
| 261 |
+
},
|
| 262 |
+
"C": {
|
| 263 |
+
"dtype": "float32",
|
| 264 |
+
"shape": [24],
|
| 265 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.42, "cosStep": 0.26 }
|
| 266 |
+
}
|
| 267 |
+
},
|
| 268 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [48, 24], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"name": "alpha_zero_relu",
|
| 272 |
+
"provenance": {
|
| 273 |
+
"notes": "alpha = 0 nulls the product exactly rather than multiplying it, so an infinite accumulator cannot become NaN."
|
| 274 |
+
},
|
| 275 |
+
"attrs": { "alpha": 0, "activation": "Relu" },
|
| 276 |
+
"inputs": {
|
| 277 |
+
"A": {
|
| 278 |
+
"dtype": "float32",
|
| 279 |
+
"shape": [32, 24],
|
| 280 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.32, "cosStep": 0.45999999999999996 }
|
| 281 |
+
},
|
| 282 |
+
"B": {
|
| 283 |
+
"dtype": "float32",
|
| 284 |
+
"shape": [24, 16],
|
| 285 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.26, "cosStep": 0.38 }
|
| 286 |
+
},
|
| 287 |
+
"C": {
|
| 288 |
+
"dtype": "float32",
|
| 289 |
+
"shape": [16],
|
| 290 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.43999999999999995, "cosStep": 0.28 }
|
| 291 |
+
}
|
| 292 |
+
},
|
| 293 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [32, 16], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 294 |
+
},
|
| 295 |
+
{
|
| 296 |
+
"name": "beta_zero_relu",
|
| 297 |
+
"provenance": { "notes": "beta = 0 nulls the C term the same way." },
|
| 298 |
+
"attrs": { "beta": 0, "activation": "Relu" },
|
| 299 |
+
"inputs": {
|
| 300 |
+
"A": {
|
| 301 |
+
"dtype": "float32",
|
| 302 |
+
"shape": [32, 24],
|
| 303 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.33, "cosStep": 0.47 }
|
| 304 |
+
},
|
| 305 |
+
"B": {
|
| 306 |
+
"dtype": "float32",
|
| 307 |
+
"shape": [24, 16],
|
| 308 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.27, "cosStep": 0.39 }
|
| 309 |
+
},
|
| 310 |
+
"C": {
|
| 311 |
+
"dtype": "float32",
|
| 312 |
+
"shape": [16],
|
| 313 |
+
"data": {
|
| 314 |
+
"kind": "fillFloat32",
|
| 315 |
+
"scale": 0.4,
|
| 316 |
+
"sinStep": 0.44999999999999996,
|
| 317 |
+
"cosStep": 0.29000000000000004
|
| 318 |
+
}
|
| 319 |
+
}
|
| 320 |
+
},
|
| 321 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [32, 16], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 322 |
+
},
|
| 323 |
+
{
|
| 324 |
+
"name": "small_unaligned_relu",
|
| 325 |
+
"provenance": { "notes": "M, K and N all below one tile and none a multiple of the micro-tile." },
|
| 326 |
+
"attrs": { "activation": "Relu" },
|
| 327 |
+
"inputs": {
|
| 328 |
+
"A": {
|
| 329 |
+
"dtype": "float32",
|
| 330 |
+
"shape": [7, 13],
|
| 331 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.34, "cosStep": 0.48 }
|
| 332 |
+
},
|
| 333 |
+
"B": {
|
| 334 |
+
"dtype": "float32",
|
| 335 |
+
"shape": [13, 11],
|
| 336 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.28, "cosStep": 0.4 }
|
| 337 |
+
},
|
| 338 |
+
"C": {
|
| 339 |
+
"dtype": "float32",
|
| 340 |
+
"shape": [11],
|
| 341 |
+
"data": {
|
| 342 |
+
"kind": "fillFloat32",
|
| 343 |
+
"scale": 0.4,
|
| 344 |
+
"sinStep": 0.45999999999999996,
|
| 345 |
+
"cosStep": 0.30000000000000004
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
},
|
| 349 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [7, 11], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"name": "f16_notrans_bias_relu",
|
| 353 |
+
"provenance": { "notes": "float16 operands, accumulating in f32." },
|
| 354 |
+
"attrs": { "activation": "Relu" },
|
| 355 |
+
"inputs": {
|
| 356 |
+
"A": {
|
| 357 |
+
"dtype": "float16",
|
| 358 |
+
"shape": [64, 48],
|
| 359 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.35, "cosStep": 0.49 }
|
| 360 |
+
},
|
| 361 |
+
"B": {
|
| 362 |
+
"dtype": "float16",
|
| 363 |
+
"shape": [48, 32],
|
| 364 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.29, "cosStep": 0.41000000000000003 }
|
| 365 |
+
},
|
| 366 |
+
"C": {
|
| 367 |
+
"dtype": "float16",
|
| 368 |
+
"shape": [32],
|
| 369 |
+
"data": { "kind": "fillFloat32", "scale": 0.4, "sinStep": 0.47, "cosStep": 0.31 }
|
| 370 |
+
}
|
| 371 |
+
},
|
| 372 |
+
"outputs": { "Y": { "dtype": "float16", "shape": [64, 32], "tolerance": 0.006, "relTolerance": 0.006 } }
|
| 373 |
+
},
|
| 374 |
+
{
|
| 375 |
+
"name": "f16_transb_nobias_tanh",
|
| 376 |
+
"provenance": { "notes": "float16 with transB and no bias." },
|
| 377 |
+
"attrs": { "transB": 1, "activation": "Tanh" },
|
| 378 |
+
"inputs": {
|
| 379 |
+
"A": {
|
| 380 |
+
"dtype": "float16",
|
| 381 |
+
"shape": [64, 48],
|
| 382 |
+
"data": { "kind": "fillFloat32", "scale": 0.9, "sinStep": 0.36, "cosStep": 0.5 }
|
| 383 |
+
},
|
| 384 |
+
"B": {
|
| 385 |
+
"dtype": "float16",
|
| 386 |
+
"shape": [32, 48],
|
| 387 |
+
"data": { "kind": "fillFloat32", "scale": 0.6, "sinStep": 0.3, "cosStep": 0.42000000000000004 }
|
| 388 |
+
}
|
| 389 |
+
},
|
| 390 |
+
"outputs": { "Y": { "dtype": "float16", "shape": [64, 32], "tolerance": 0.006, "relTolerance": 0.006 } }
|
| 391 |
+
},
|
| 392 |
+
{
|
| 393 |
+
"name": "pinned_transab_leaky_alpha_beta",
|
| 394 |
+
"provenance": {
|
| 395 |
+
"notes": "Hand-computed at float64 from the schema's own definition -- alpha * A' * B' + beta * C, then LeakyRelu -- with both operands transposed and every scalar explicit, so nothing in the pin comes from a default."
|
| 396 |
+
},
|
| 397 |
+
"attrs": {
|
| 398 |
+
"transA": 1,
|
| 399 |
+
"transB": 1,
|
| 400 |
+
"alpha": 0.75,
|
| 401 |
+
"beta": 1.5,
|
| 402 |
+
"activation": "LeakyRelu",
|
| 403 |
+
"activation_alpha": 0.125
|
| 404 |
+
},
|
| 405 |
+
"inputs": {
|
| 406 |
+
"A": {
|
| 407 |
+
"dtype": "float32",
|
| 408 |
+
"shape": [10, 12],
|
| 409 |
+
"data": {
|
| 410 |
+
"kind": "values",
|
| 411 |
+
"values": [0.482, 0.233, -0.17, 1.167, -0.64, 1.418, 0.317, -0.314, 0.628, 0.761, 0.092, -1.224, 1.017, 0.692, -0.239, -1.141, 0.507, 1.027, 0.417, 1.008, -1.377, -1.169, 0.818, 0.125, -0.798, 0.491, -0.397, -0.028, 1.262, 0.159, -1.326, 0.973, -0.57, 0.244, 1.381, -0.037, -1.135, -0.158, -0.767, 0.452, 1.127, -0.526, 1.431, -0.255, -0.505, 0.154, -0.336, 0.414, -0.21, 1.258, -0.143, -0.146, -1.313, 0.676, -0.406, 1.497, -1.321, 1.005, 0.274, -1.266, -1.498, -0.927, 0.328, 0.949, -0.043, 1.29, -0.088, -0.031, 0.975, 0.247, 0.213, -0.993, 0.848, 0.355, 0.745, -0.006, 0.934, -0.819, 0.242, 1.171, -0.907, -1.153, 0.361, -0.612, -0.006, -1.408, 0.302, -0.531, 1.072, 0.002, 1.211, -0.427, 0.901, -0.552, -1.033, 0.857, -1.401, -0.719, -1.259, 0.575, -1.481, 0.209, 0.107, 0.975, 0.802, 1.009, 0.77, 1.493, 1.138, -1.32, 1.026, -0.854, -0.22, 1.076, -1.45, -0.272, 0.24, 1.368, -1.149, 0.598]
|
| 412 |
+
}
|
| 413 |
+
},
|
| 414 |
+
"B": {
|
| 415 |
+
"dtype": "float32",
|
| 416 |
+
"shape": [8, 10],
|
| 417 |
+
"data": {
|
| 418 |
+
"kind": "values",
|
| 419 |
+
"values": [-0.756, 1.16, -0.81, -1.402, -0.32, -0.036, 0.068, -1.181, -1.451, -1.096, -1.089, -0.777, 1.363, 0.017, -1.26, 1.485, 0.309, 1.036, -0.894, 1.06, 0.977, -1.123, -1.369, -1.108, 0.193, 0.923, -0.324, 0.673, 1.35, -1.017, 1.247, -0.487, 0.898, 0.209, 0.78, -1.249, 1.274, -0.422, -1.282, 0.118, 0.51, 0.864, -0.868, 1.06, -1.42, -1.341, -0.608, 0.888, 1.183, 0.199, 1.423, 0.737, -0.285, 0.903, 0.487, -0.826, 0.934, -1.365, -1.034, -1.222, 1.233, -0.428, -0.705, 1.431, -1.459, 0.817, -1.361, 1.45, 0.173, -1.252, -1.415, 1.357, -0.751, 0.894, -0.602, 0.879, 1.197, 0.168, -0.407, 0.107]
|
| 420 |
+
}
|
| 421 |
+
},
|
| 422 |
+
"C": {
|
| 423 |
+
"dtype": "float32",
|
| 424 |
+
"shape": [8],
|
| 425 |
+
"data": { "kind": "values", "values": [0.235, -0.223, 0.474, -0.529, 0.922, 0.252, -0.834, 0.806] }
|
| 426 |
+
}
|
| 427 |
+
},
|
| 428 |
+
"outputs": {
|
| 429 |
+
"Y": {
|
| 430 |
+
"dtype": "float32",
|
| 431 |
+
"shape": [12, 8],
|
| 432 |
+
"data": {
|
| 433 |
+
"kind": "values",
|
| 434 |
+
"values": [3.370844, -0.198133, -0.199107, 2.110806, 2.109943, 2.351428, -0.592314, 1.807759, 3.546125, -0.528558, -0.131459, 2.441212, -0.108338, 5.288458, -0.547352, 0.359243, 1.611335, 2.095594, -0.005854, 0.27388, -0.058539, -0.047104, -0.393263, 2.309827, -0.150555, -0.116139, 3.783087, -0.084227, 0.70041, 1.53985, 1.740793, -0.062086, 0.411694, 4.257617, -0.456835, 0.679208, 1.923927, 0.92273, 0.173925, 4.421494, -0.056756, -0.076294, 1.740675, -0.189957, 0.772669, -0.025928, -0.126539, 0.139902, -0.006079, -0.264435, 2.411458, -0.232052, 4.870933, 2.281323, 3.98095, 3.349453, 0.326566, -0.256703, -0.033174, 0.35729, -0.059635, 1.535964, -0.698491, 1.830789, -0.243493, 1.843096, 5.123723, -0.469259, 2.88782, -0.427406, 3.358449, -0.070443, -0.430807, -0.122892, 2.170899, -0.110731, 0.818956, -0.183576, -0.207642, -0.302042, 1.494748, -0.206163, 0.184732, -0.042274, -0.008104, 2.140054, -0.375211, 0.824137, -0.229193, 0.648641, 0.168956, -0.499118, 5.959787, -0.428765, 0.006611, 2.00139]
|
| 435 |
+
},
|
| 436 |
+
"tolerance": 0.00002,
|
| 437 |
+
"relTolerance": 0.0002
|
| 438 |
+
}
|
| 439 |
+
}
|
| 440 |
+
},
|
| 441 |
+
{
|
| 442 |
+
"name": "pinned_column_bias_hardsigmoid",
|
| 443 |
+
"provenance": { "notes": "Independently pinned column-bias broadcast with HardSigmoid at explicit parameters." },
|
| 444 |
+
"attrs": { "activation": "HardSigmoid", "activation_alpha": 0.3, "activation_beta": 0.4 },
|
| 445 |
+
"inputs": {
|
| 446 |
+
"A": {
|
| 447 |
+
"dtype": "float32",
|
| 448 |
+
"shape": [9, 7],
|
| 449 |
+
"data": {
|
| 450 |
+
"kind": "values",
|
| 451 |
+
"values": [-1.053, 0.354, -0.86, -0.3, 0.047, -0.117, -0.287, -0.319, -1.275, -0.229, 1.483, 0.499, 0.027, -0.762, -0.484, 1.402, -0.067, -1.282, 1.004, -0.316, 0.827, -0.547, 1.007, 0.853, 1.198, 0.01, -0.728, -0.59, 0.576, -0.694, 0.916, -1.297, -1.274, -0.773, -0.042, -0.708, -0.676, -0.463, -0.763, -0.803, 0.241, -0.813, 1.473, 0.728, 0.481, 0.679, -0.263, 0.948, 0.487, -0.141, 0.651, -1.067, 0.751, 1.368, 0.358, 0.552, 0.481, -1.401, 1.166, -0.338, -0.392, 0.853, 1.361]
|
| 452 |
+
}
|
| 453 |
+
},
|
| 454 |
+
"B": {
|
| 455 |
+
"dtype": "float32",
|
| 456 |
+
"shape": [7, 6],
|
| 457 |
+
"data": {
|
| 458 |
+
"kind": "values",
|
| 459 |
+
"values": [-0.006, -1.252, 0.157, -1.417, -1.042, 1.004, -0.995, 0.459, -1.464, 0.63, -0.926, -1.197, -0.321, -0.703, 0.213, 1.042, -0.752, -1.147, -0.595, -0.542, 1.233, 0.919, -1.13, 0.523, -1.206, -1.173, -0.179, 0.925, 0.323, -1.273, 0.567, 0.742, 0.435, 0.361, -1.469, -1.195, -1.211, -0.674, 0.828, 0.501, 0.515, -0.094]
|
| 460 |
+
}
|
| 461 |
+
},
|
| 462 |
+
"C": {
|
| 463 |
+
"dtype": "float32",
|
| 464 |
+
"shape": [9, 1],
|
| 465 |
+
"data": { "kind": "values", "values": [-0.957, 0.099, -0.259, -0.825, -0.224, -0.876, 0.837, -0.309, -0.723] }
|
| 466 |
+
}
|
| 467 |
+
},
|
| 468 |
+
"outputs": {
|
| 469 |
+
"Y": {
|
| 470 |
+
"dtype": "float32",
|
| 471 |
+
"shape": [9, 6],
|
| 472 |
+
"data": {
|
| 473 |
+
"kind": "values",
|
| 474 |
+
"values": [0.212855, 0.802754, 0.0, 0.233126, 0.651217, 0.0, 0.669088, 0.165598, 1.0, 0.688478, 0.351265, 0.924192, 0.0, 0.328861, 0.0, 0.78732, 0.898156, 0.0, 0.0, 0.075651, 0.0, 1.0, 0.0, 0.0, 1.0, 0.323342, 0.200611, 0.0, 0.78929, 1.0, 1.0, 1.0, 0.0, 0.0, 0.599796, 0.449499, 0.3431, 0.191342, 0.941447, 0.602963, 0.0, 0.521214, 0.0, 0.039497, 0.334728, 0.865142, 0.216728, 0.0, 0.340949, 0.0, 1.0, 0.173301, 0.069842, 0.182348]
|
| 475 |
+
},
|
| 476 |
+
"tolerance": 0.00002,
|
| 477 |
+
"relTolerance": 0.0002
|
| 478 |
+
}
|
| 479 |
+
}
|
| 480 |
+
},
|
| 481 |
+
{
|
| 482 |
+
"name": "sgmat_notrans_rowbias_relu",
|
| 483 |
+
"provenance": {
|
| 484 |
+
"notes": "Aligned for the subgroup-matrix gate (M >= 32, K % 32 == 0, N % 64 == 0), so this selects notrans_sgmat_bias where the unaligned fixtures above stay on the tiled kernel. Stages A as [M,K] and B as [K,N], which is the operand orientation this transpose pair asks the matrix kernel for, and fuses Relu in the accumulator domain over a rank-1 row bias."
|
| 485 |
+
},
|
| 486 |
+
"attrs": { "activation": "Relu" },
|
| 487 |
+
"inputs": {
|
| 488 |
+
"A": {
|
| 489 |
+
"dtype": "float32",
|
| 490 |
+
"shape": [64, 64],
|
| 491 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.11, "cosStep": 0.27 }
|
| 492 |
+
},
|
| 493 |
+
"B": {
|
| 494 |
+
"dtype": "float32",
|
| 495 |
+
"shape": [64, 128],
|
| 496 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.13 }
|
| 497 |
+
},
|
| 498 |
+
"C": {
|
| 499 |
+
"dtype": "float32",
|
| 500 |
+
"shape": [128],
|
| 501 |
+
"data": { "kind": "fillFloat32", "scale": 0.35, "sinStep": 0.23, "cosStep": 0.41 }
|
| 502 |
+
}
|
| 503 |
+
},
|
| 504 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 505 |
+
},
|
| 506 |
+
{
|
| 507 |
+
"name": "sgmat_notrans_nobias_tanh",
|
| 508 |
+
"provenance": {
|
| 509 |
+
"notes": "The no-bias arm of the same gate and layout: the matrix kernel renders a separate set of store sites without the bias term."
|
| 510 |
+
},
|
| 511 |
+
"attrs": { "activation": "Tanh" },
|
| 512 |
+
"inputs": {
|
| 513 |
+
"A": {
|
| 514 |
+
"dtype": "float32",
|
| 515 |
+
"shape": [64, 64],
|
| 516 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.15, "cosStep": 0.27 }
|
| 517 |
+
},
|
| 518 |
+
"B": {
|
| 519 |
+
"dtype": "float32",
|
| 520 |
+
"shape": [64, 128],
|
| 521 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.17 }
|
| 522 |
+
}
|
| 523 |
+
},
|
| 524 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"name": "sgmat_transa_rowbias_tanh",
|
| 528 |
+
"provenance": {
|
| 529 |
+
"notes": "Aligned for the subgroup-matrix gate (M >= 32, K % 32 == 0, N % 64 == 0), so this selects transa_sgmat_bias where the unaligned fixtures above stay on the tiled kernel. Stages A as [K,M] and B as [K,N], which is the operand orientation this transpose pair asks the matrix kernel for, and fuses Tanh in the accumulator domain over a rank-1 row bias."
|
| 530 |
+
},
|
| 531 |
+
"attrs": { "transA": 1, "activation": "Tanh" },
|
| 532 |
+
"inputs": {
|
| 533 |
+
"A": {
|
| 534 |
+
"dtype": "float32",
|
| 535 |
+
"shape": [64, 64],
|
| 536 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.12, "cosStep": 0.27 }
|
| 537 |
+
},
|
| 538 |
+
"B": {
|
| 539 |
+
"dtype": "float32",
|
| 540 |
+
"shape": [64, 128],
|
| 541 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.14 }
|
| 542 |
+
},
|
| 543 |
+
"C": {
|
| 544 |
+
"dtype": "float32",
|
| 545 |
+
"shape": [128],
|
| 546 |
+
"data": { "kind": "fillFloat32", "scale": 0.35, "sinStep": 0.23, "cosStep": 0.41 }
|
| 547 |
+
}
|
| 548 |
+
},
|
| 549 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 550 |
+
},
|
| 551 |
+
{
|
| 552 |
+
"name": "sgmat_transa_nobias_sigmoid",
|
| 553 |
+
"provenance": {
|
| 554 |
+
"notes": "The no-bias arm of the same gate and layout: the matrix kernel renders a separate set of store sites without the bias term."
|
| 555 |
+
},
|
| 556 |
+
"attrs": { "transA": 1, "activation": "Sigmoid" },
|
| 557 |
+
"inputs": {
|
| 558 |
+
"A": {
|
| 559 |
+
"dtype": "float32",
|
| 560 |
+
"shape": [64, 64],
|
| 561 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.16, "cosStep": 0.27 }
|
| 562 |
+
},
|
| 563 |
+
"B": {
|
| 564 |
+
"dtype": "float32",
|
| 565 |
+
"shape": [64, 128],
|
| 566 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.18 }
|
| 567 |
+
}
|
| 568 |
+
},
|
| 569 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 570 |
+
},
|
| 571 |
+
{
|
| 572 |
+
"name": "sgmat_transb_rowbias_sigmoid",
|
| 573 |
+
"provenance": {
|
| 574 |
+
"notes": "Aligned for the subgroup-matrix gate (M >= 32, K % 32 == 0, N % 64 == 0), so this selects transb_sgmat_bias where the unaligned fixtures above stay on the tiled kernel. Stages A as [M,K] and B as [N,K], which is the operand orientation this transpose pair asks the matrix kernel for, and fuses Sigmoid in the accumulator domain over a rank-1 row bias."
|
| 575 |
+
},
|
| 576 |
+
"attrs": { "transB": 1, "activation": "Sigmoid" },
|
| 577 |
+
"inputs": {
|
| 578 |
+
"A": {
|
| 579 |
+
"dtype": "float32",
|
| 580 |
+
"shape": [64, 64],
|
| 581 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.13, "cosStep": 0.27 }
|
| 582 |
+
},
|
| 583 |
+
"B": {
|
| 584 |
+
"dtype": "float32",
|
| 585 |
+
"shape": [128, 64],
|
| 586 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.15 }
|
| 587 |
+
},
|
| 588 |
+
"C": {
|
| 589 |
+
"dtype": "float32",
|
| 590 |
+
"shape": [128],
|
| 591 |
+
"data": { "kind": "fillFloat32", "scale": 0.35, "sinStep": 0.23, "cosStep": 0.41 }
|
| 592 |
+
}
|
| 593 |
+
},
|
| 594 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 595 |
+
},
|
| 596 |
+
{
|
| 597 |
+
"name": "sgmat_transb_nobias_leakyrelu",
|
| 598 |
+
"provenance": {
|
| 599 |
+
"notes": "The no-bias arm of the same gate and layout: the matrix kernel renders a separate set of store sites without the bias term."
|
| 600 |
+
},
|
| 601 |
+
"attrs": { "transB": 1, "activation": "LeakyRelu" },
|
| 602 |
+
"inputs": {
|
| 603 |
+
"A": {
|
| 604 |
+
"dtype": "float32",
|
| 605 |
+
"shape": [64, 64],
|
| 606 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.16999999999999998, "cosStep": 0.27 }
|
| 607 |
+
},
|
| 608 |
+
"B": {
|
| 609 |
+
"dtype": "float32",
|
| 610 |
+
"shape": [128, 64],
|
| 611 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.19 }
|
| 612 |
+
}
|
| 613 |
+
},
|
| 614 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 615 |
+
},
|
| 616 |
+
{
|
| 617 |
+
"name": "sgmat_transab_rowbias_leakyrelu",
|
| 618 |
+
"provenance": {
|
| 619 |
+
"notes": "Aligned for the subgroup-matrix gate (M >= 32, K % 32 == 0, N % 64 == 0), so this selects transab_sgmat_bias where the unaligned fixtures above stay on the tiled kernel. Stages A as [K,M] and B as [N,K], which is the operand orientation this transpose pair asks the matrix kernel for, and fuses LeakyRelu in the accumulator domain over a rank-1 row bias."
|
| 620 |
+
},
|
| 621 |
+
"attrs": { "transA": 1, "transB": 1, "activation": "LeakyRelu" },
|
| 622 |
+
"inputs": {
|
| 623 |
+
"A": {
|
| 624 |
+
"dtype": "float32",
|
| 625 |
+
"shape": [64, 64],
|
| 626 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.14, "cosStep": 0.27 }
|
| 627 |
+
},
|
| 628 |
+
"B": {
|
| 629 |
+
"dtype": "float32",
|
| 630 |
+
"shape": [128, 64],
|
| 631 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.16 }
|
| 632 |
+
},
|
| 633 |
+
"C": {
|
| 634 |
+
"dtype": "float32",
|
| 635 |
+
"shape": [128],
|
| 636 |
+
"data": { "kind": "fillFloat32", "scale": 0.35, "sinStep": 0.23, "cosStep": 0.41 }
|
| 637 |
+
}
|
| 638 |
+
},
|
| 639 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 640 |
+
},
|
| 641 |
+
{
|
| 642 |
+
"name": "sgmat_transab_nobias_relu",
|
| 643 |
+
"provenance": {
|
| 644 |
+
"notes": "The no-bias arm of the same gate and layout: the matrix kernel renders a separate set of store sites without the bias term."
|
| 645 |
+
},
|
| 646 |
+
"attrs": { "transA": 1, "transB": 1, "activation": "Relu" },
|
| 647 |
+
"inputs": {
|
| 648 |
+
"A": {
|
| 649 |
+
"dtype": "float32",
|
| 650 |
+
"shape": [64, 64],
|
| 651 |
+
"data": { "kind": "fillFloat32", "scale": 0.8, "sinStep": 0.18, "cosStep": 0.27 }
|
| 652 |
+
},
|
| 653 |
+
"B": {
|
| 654 |
+
"dtype": "float32",
|
| 655 |
+
"shape": [128, 64],
|
| 656 |
+
"data": { "kind": "fillFloat32", "scale": 0.5, "sinStep": 0.19, "cosStep": 0.2 }
|
| 657 |
+
}
|
| 658 |
+
},
|
| 659 |
+
"outputs": { "Y": { "dtype": "float32", "shape": [64, 128], "tolerance": 0.00002, "relTolerance": 0.0002 } }
|
| 660 |
+
}
|
| 661 |
+
]
|
| 662 |
+
}
|