Xenova's picture
Xenova HF Staff
sync 2e7068faf55e
87e48ce verified
Raw
History Blame
11.3 kB
{
"domain": "com.microsoft",
"name": "BiasSoftmax",
"sinceVersion": 1,
"description": "Computes `softmax(data + bias)` over the flattened suffix beginning at `axis`. The required `is_inner_broadcast` attribute selects how bias rows are reused: consecutive groups for inner broadcast or cyclic groups for outer broadcast. This specializes the `softmax(scores + additive_mask)` pattern used by transformer attention. Float16 and float32 are supported; the schema's double type is not.",
"inputs": [
{ "role": "data", "dtype": "T", "description": "The input data tensor." },
{
"role": "bias",
"dtype": "T",
"description": "The bias (or additive mask) tensor. Its element count must be an integral number of flattened softmax rows and that row count must divide the data row count."
}
],
"outputs": [
{
"role": "output",
"dtype": "T",
"rank": "ranks.data",
"shape": "shapes.data",
"description": "The output tensor; same shape as data."
}
],
"attributes": { "axis": 1 },
"attributeConstraints": { "is_inner_broadcast": { "required": true } },
"attributeDescriptions": {
"axis": "The axis from which softmax is applied; dimensions from `axis` onward are included in the softmax reduction.",
"is_inner_broadcast": "When 1, bias is broadcast across dimensions from `broadcast_axis` to `axis-1`; when 0, bias is broadcast across dimensions 0 to `broadcast_axis-1`."
},
"typeConstraints": { "T": ["float32", "float16"] },
"args": {
"data": { "kind": "tensor", "semantic": "data", "role": "input" },
"bias": { "kind": "tensor", "semantic": "bias", "role": "input" },
"output": { "kind": "tensor", "semantic": "output", "role": "output" }
},
"derive": {
"axisNorm": "attrs.axis if attrs.axis >= 0 else attrs.axis + ranks.data",
"batchCount": "outer(shapes.data, axisNorm)",
"blockSize": "dim(shapes.data, axisNorm) * inner(shapes.data, axisNorm)",
"biasBlockCount": "numel(shapes.bias) / max(1, blockSize)",
"biasContract": "(numel(shapes.data) == 0 and numel(shapes.bias) == 0) or (blockSize > 0 and biasBlockCount > 0 and numel(shapes.bias) % blockSize == 0 and biasBlockCount <= batchCount and batchCount % biasBlockCount == 0)"
},
"tunables": { "WORKGROUP_SIZE": 256, "BLOCK_COLS": 2048 },
"bindingSets": {
"biasSoftmax": [
{
"name": "data",
"arg": "data",
"semantic": "data",
"buffer": { "type": "read-only-storage" },
"elementType": "$scalar"
},
{
"name": "bias",
"arg": "bias",
"semantic": "bias",
"buffer": { "type": "read-only-storage" },
"elementType": "$scalar"
},
{
"name": "output",
"arg": "output",
"semantic": "output",
"buffer": { "type": "storage" },
"elementType": "$scalar"
},
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": {
"name": "Params",
"fields": [
{ "name": "blockSize", "type": "u32", "value": "blockSize" },
{ "name": "batchCount", "type": "u32", "value": "batchCount" }
]
}
}
]
},
"variants": [
{
"id": "longrow_split",
"priority": 40,
"when": ["numel(shapes.data) == numel(shapes.output)", "ranks.data >= 1", "attrs.axis + ranks.data >= 0", "attrs.axis < ranks.data", "biasContract", "blockSize >= 65536", "batchCount > 0", "batchCount <= device.limits.maxComputeWorkgroupsPerDimension", "ceilDiv(blockSize, tunables.BLOCK_COLS) <= device.limits.maxComputeWorkgroupsPerDimension", "f16Ok(dtypes.T)"],
"constants": { "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"", "combineSubgroups": false },
"intermediates": [
{
"id": "blockMax",
"dtype": "float32",
"shape": "[outer(shapes.data, axisNorm) * ceilDiv(dim(shapes.data, axisNorm) * inner(shapes.data, axisNorm), tunables.BLOCK_COLS)]"
},
{
"id": "blockSum",
"dtype": "float32",
"shape": "[outer(shapes.data, axisNorm) * ceilDiv(dim(shapes.data, axisNorm) * inner(shapes.data, axisNorm), tunables.BLOCK_COLS)]"
},
{ "id": "rowMax", "dtype": "float32", "shape": "[outer(shapes.data, axisNorm)]" },
{ "id": "rowSum", "dtype": "float32", "shape": "[outer(shapes.data, axisNorm)]" }
],
"passes": [
{
"id": "block_stats",
"name": "BiasSoftmax.LongRowBlockStats",
"source": {
"shader": "bias-softmax-longrow-stats.wgsl.jinja",
"inputs": {
"stage": "\"block\"",
"isInnerBroadcast": "attrs.is_inner_broadcast != 0",
"biasBlockCount": "max(1, biasBlockCount)",
"innerRepeat": "max(1, batchCount / max(1, biasBlockCount))"
}
},
"bindings": [
{
"name": "data",
"arg": "data",
"semantic": "data",
"buffer": { "type": "read-only-storage" },
"elementType": "$scalar"
},
{
"name": "bias",
"arg": "bias",
"semantic": "bias",
"buffer": { "type": "read-only-storage" },
"elementType": "$scalar"
},
{ "name": "blockMax", "semantic": "blockMax", "buffer": { "type": "storage" }, "elementType": "f32" },
{ "name": "blockSum", "semantic": "blockSum", "buffer": { "type": "storage" }, "elementType": "f32" },
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": {
"name": "Params",
"fields": [
{ "name": "blockSize", "type": "u32", "value": "blockSize" },
{ "name": "blocks", "type": "u32", "value": "ceilDiv(blockSize, tunables.BLOCK_COLS)" }
]
}
}
],
"dispatch": { "x": "ceilDiv(blockSize, tunables.BLOCK_COLS)", "y": "batchCount" }
},
{
"id": "row_stats",
"name": "BiasSoftmax.LongRowStats",
"source": { "shader": "bias-softmax-longrow-stats.wgsl.jinja", "inputs": { "stage": "\"row\"" } },
"bindings": [
{
"name": "blockMax",
"semantic": "blockMax",
"buffer": { "type": "read-only-storage" },
"elementType": "f32"
},
{
"name": "blockSum",
"semantic": "blockSum",
"buffer": { "type": "read-only-storage" },
"elementType": "f32"
},
{ "name": "rowMax", "semantic": "rowMax", "buffer": { "type": "storage" }, "elementType": "f32" },
{ "name": "rowSum", "semantic": "rowSum", "buffer": { "type": "storage" }, "elementType": "f32" },
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": {
"name": "Params",
"fields": [{ "name": "blocks", "type": "u32", "value": "ceilDiv(blockSize, tunables.BLOCK_COLS)" }]
}
}
],
"dispatch": { "x": "batchCount" }
},
{
"id": "normalize",
"name": "BiasSoftmax.LongRowNormalize",
"source": {
"shader": "bias-softmax-longrow-normalize.wgsl.jinja",
"inputs": {
"isInnerBroadcast": "attrs.is_inner_broadcast != 0",
"biasBlockCount": "max(1, biasBlockCount)",
"innerRepeat": "max(1, batchCount / max(1, biasBlockCount))"
}
},
"bindings": [
{
"name": "data",
"arg": "data",
"semantic": "data",
"buffer": { "type": "read-only-storage" },
"elementType": "$scalar"
},
{
"name": "bias",
"arg": "bias",
"semantic": "bias",
"buffer": { "type": "read-only-storage" },
"elementType": "$scalar"
},
{ "name": "rowMax", "semantic": "rowMax", "buffer": { "type": "read-only-storage" }, "elementType": "f32" },
{ "name": "rowSum", "semantic": "rowSum", "buffer": { "type": "read-only-storage" }, "elementType": "f32" },
{
"name": "output",
"arg": "output",
"semantic": "output",
"buffer": { "type": "storage" },
"elementType": "$scalar"
},
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": { "name": "Params", "fields": [{ "name": "blockSize", "type": "u32", "value": "blockSize" }] }
}
],
"dispatch": { "x": "ceilDiv(blockSize, tunables.BLOCK_COLS)", "y": "batchCount" }
}
]
},
{
"id": "packed_rows",
"priority": 30,
"when": ["numel(shapes.data) == numel(shapes.output)", "ranks.data >= 1", "attrs.axis + ranks.data >= 0", "attrs.axis < ranks.data", "biasContract", "blockSize > 0", "blockSize <= 8", "batchCount >= 64", "f16Ok(dtypes.T)"],
"constants": {
"scalar": "dtypes.T",
"usesF16": "dtypes.T == \"f16\"",
"combineSubgroups": false,
"packedRows": true
},
"passes": [
{
"id": "main",
"name": "BiasSoftmax.PackedRows",
"source": {
"shader": "bias-softmax.wgsl.jinja",
"inputs": {
"blockSize": "blockSize",
"isInnerBroadcast": "attrs.is_inner_broadcast != 0",
"biasBlockCount": "max(1, biasBlockCount)",
"innerRepeat": "max(1, batchCount / max(1, biasBlockCount))"
}
},
"bindings": "biasSoftmax",
"dispatch": { "gridStride": "batchCount", "workgroupSize": "tunables.WORKGROUP_SIZE" }
}
]
},
{
"id": "adaptive_row",
"priority": 10,
"when": ["numel(shapes.data) == numel(shapes.output)", "ranks.data >= 1", "attrs.axis + ranks.data >= 0", "attrs.axis < ranks.data", "biasContract", "numel(shapes.data) >= 0", "f16Ok(dtypes.T)"],
"constants": {
"packedRows": false,
"scalar": "dtypes.T",
"usesF16": "dtypes.T == \"f16\"",
"combineSubgroups": "device.features.has(\"subgroups\")"
},
"passes": [
{
"id": "main",
"name": "BiasSoftmax.AdaptiveRow",
"source": {
"shader": "bias-softmax.wgsl.jinja",
"inputs": {
"blockSize": "blockSize",
"isInnerBroadcast": "attrs.is_inner_broadcast != 0",
"biasBlockCount": "max(1, biasBlockCount)",
"innerRepeat": "max(1, batchCount / max(1, biasBlockCount))"
}
},
"bindings": "biasSoftmax",
"dispatch": { "workgroups": "batchCount" }
}
]
}
]
}