sync c928d21e6cc1
Browse files- build/webgpu/conv-1x1-gemm-tiled-reg.wgsl.jinja +4 -1
- build/webgpu/conv-1x1-gemm-tiled.wgsl.jinja +4 -1
- build/webgpu/conv-1x1-subgroup-matrix.wgsl.jinja +34 -31
- build/webgpu/conv-direct-nd.wgsl.jinja +4 -1
- build/webgpu/conv-direct-unrolled.wgsl.jinja +4 -1
- build/webgpu/conv1d-tiled-reg.wgsl.jinja +4 -1
- build/webgpu/conv2d-grouped-large-w4.wgsl.jinja +4 -1
- build/webgpu/metadata.json +9 -9
build/webgpu/conv-1x1-gemm-tiled-reg.wgsl.jinja
CHANGED
|
@@ -32,7 +32,10 @@ fn fused_act(v: f32) -> f32 {
|
|
| 32 |
{% elif activation == "Sigmoid" %}
|
| 33 |
return 1.0 / (1.0 + exp(-v));
|
| 34 |
{% elif activation == "Tanh" %}
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
| 36 |
{% elif activation == "HardSigmoid" %}
|
| 37 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 38 |
{% else %}
|
|
|
|
| 32 |
{% elif activation == "Sigmoid" %}
|
| 33 |
return 1.0 / (1.0 + exp(-v));
|
| 34 |
{% elif activation == "Tanh" %}
|
| 35 |
+
// Clamped for the reason given in the GEMM activation: an unbounded accumulator
|
| 36 |
+
// overflows the hardware tanh's internal e^2v to Inf/Inf = NaN, and tanh is
|
| 37 |
+
// already +/-1 to full f32 precision by |v| ~ 9.
|
| 38 |
+
return tanh(clamp(v, -10.0, 10.0));
|
| 39 |
{% elif activation == "HardSigmoid" %}
|
| 40 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 41 |
{% else %}
|
build/webgpu/conv-1x1-gemm-tiled.wgsl.jinja
CHANGED
|
@@ -32,7 +32,10 @@ fn fused_act(v: f32) -> f32 {
|
|
| 32 |
{% elif activation == "Sigmoid" %}
|
| 33 |
return 1.0 / (1.0 + exp(-v));
|
| 34 |
{% elif activation == "Tanh" %}
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
| 36 |
{% elif activation == "HardSigmoid" %}
|
| 37 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 38 |
{% else %}
|
|
|
|
| 32 |
{% elif activation == "Sigmoid" %}
|
| 33 |
return 1.0 / (1.0 + exp(-v));
|
| 34 |
{% elif activation == "Tanh" %}
|
| 35 |
+
// Clamped for the reason given in the GEMM activation: an unbounded accumulator
|
| 36 |
+
// overflows the hardware tanh's internal e^2v to Inf/Inf = NaN, and tanh is
|
| 37 |
+
// already +/-1 to full f32 precision by |v| ~ 9.
|
| 38 |
+
return tanh(clamp(v, -10.0, 10.0));
|
| 39 |
{% elif activation == "HardSigmoid" %}
|
| 40 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 41 |
{% else %}
|
build/webgpu/conv-1x1-subgroup-matrix.wgsl.jinja
CHANGED
|
@@ -115,7 +115,10 @@ fn fused_act(v: f32) -> f32 {
|
|
| 115 |
{% elif activation == "Sigmoid" %}
|
| 116 |
return 1.0 / (1.0 + exp(-v));
|
| 117 |
{% elif activation == "Tanh" %}
|
| 118 |
-
|
|
|
|
|
|
|
|
|
|
| 119 |
{% elif activation == "HardSigmoid" %}
|
| 120 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 121 |
{% else %}
|
|
@@ -217,14 +220,14 @@ fn main(
|
|
| 217 |
|
| 218 |
for (var step = 0u; step < TILE_K; step = step + 8u) {
|
| 219 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + step;
|
| 220 |
-
var matA0: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>>(&tile_A, matrix_a_offset,
|
| 221 |
-
var matA1: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>>(&tile_A, matrix_a_offset + 8u * TILE_K,
|
| 222 |
|
| 223 |
let matrix_b_offset = subtile_idx * SUB_COLS * TILE_K + step;
|
| 224 |
-
var matB0: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset,
|
| 225 |
-
var matB1: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + 8u * TILE_K,
|
| 226 |
-
var matB2: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + 16u * TILE_K,
|
| 227 |
-
var matB3: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + 24u * TILE_K,
|
| 228 |
|
| 229 |
matC00 = subgroupMatrixMultiplyAccumulate(matA0, matB0, matC00);
|
| 230 |
matC01 = subgroupMatrixMultiplyAccumulate(matA0, matB1, matC01);
|
|
@@ -244,14 +247,14 @@ fn main(
|
|
| 244 |
// cross-subgroup handoff into the narrow projection. All collective stores
|
| 245 |
// remain subgroup-uniform, and every fragment has a disjoint destination.
|
| 246 |
let fused_tile_offset = base_A * TILE_COLS + base_B;
|
| 247 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 0u, matC00,
|
| 248 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 8u, matC01,
|
| 249 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 16u, matC02,
|
| 250 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 24u, matC03,
|
| 251 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 0u, matC10,
|
| 252 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 8u, matC11,
|
| 253 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 16u, matC12,
|
| 254 |
-
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 24u, matC13,
|
| 255 |
workgroupBarrier();
|
| 256 |
|
| 257 |
// One invocation owns one spatial column and walks the producer channels in
|
|
@@ -290,14 +293,14 @@ fn main(
|
|
| 290 |
// When an epilogue is present, publish the raw accumulators first, then apply
|
| 291 |
// bias, residual Z, and activation cooperatively after one storage barrier.
|
| 292 |
let matrix_c_offset = c_base + (a_global_base + base_A) * N + b_global_base + base_B;
|
| 293 |
-
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 0u, matC00,
|
| 294 |
-
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 8u, matC01,
|
| 295 |
-
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 16u, matC02,
|
| 296 |
-
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 24u, matC03,
|
| 297 |
-
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 0u, matC10,
|
| 298 |
-
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 8u, matC11,
|
| 299 |
-
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 16u, matC12,
|
| 300 |
-
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 24u, matC13,
|
| 301 |
{% if hasBias or hasActivation or hasZ %}
|
| 302 |
storageBarrier();
|
| 303 |
for (var tile_idx = local_idx; tile_idx < TILE_ROWS * TILE_COLS; tile_idx += {{ workgroupThreadsValue }}u) {
|
|
@@ -328,10 +331,10 @@ fn main(
|
|
| 328 |
// give the reads visibility of the store AND stop the second row-group's store from
|
| 329 |
// clobbering the first's still-in-flight readback when a partial final M-tile
|
| 330 |
// diverges storeOutput's guard. Without both barriers the last valid row can be corrupted.
|
| 331 |
-
subgroupMatrixStore(&scratch[subtile_id][0], 0u, matC00,
|
| 332 |
-
subgroupMatrixStore(&scratch[subtile_id][1], 0u, matC01,
|
| 333 |
-
subgroupMatrixStore(&scratch[subtile_id][2], 0u, matC02,
|
| 334 |
-
subgroupMatrixStore(&scratch[subtile_id][3], 0u, matC03,
|
| 335 |
workgroupBarrier();
|
| 336 |
let row = sg_id / 4u;
|
| 337 |
let col = (sg_id % 4u) * 2u;
|
|
@@ -341,10 +344,10 @@ fn main(
|
|
| 341 |
storeOutput(matrix_c_offset, {% if hasBias or polyphase %}row_base, {% endif %}row, col, subtile_id, row_limit{% if padded %}, b_global_base + base_B{% endif %});
|
| 342 |
workgroupBarrier();
|
| 343 |
|
| 344 |
-
subgroupMatrixStore(&scratch[subtile_id][0], 0u, matC10,
|
| 345 |
-
subgroupMatrixStore(&scratch[subtile_id][1], 0u, matC11,
|
| 346 |
-
subgroupMatrixStore(&scratch[subtile_id][2], 0u, matC12,
|
| 347 |
-
subgroupMatrixStore(&scratch[subtile_id][3], 0u, matC13,
|
| 348 |
workgroupBarrier();
|
| 349 |
matrix_c_offset = matrix_c_offset + 8u * N;
|
| 350 |
row_limit = i32(M) - i32(row_base + 8u);
|
|
|
|
| 115 |
{% elif activation == "Sigmoid" %}
|
| 116 |
return 1.0 / (1.0 + exp(-v));
|
| 117 |
{% elif activation == "Tanh" %}
|
| 118 |
+
// Clamped for the reason given in the GEMM activation: an unbounded accumulator
|
| 119 |
+
// overflows the hardware tanh's internal e^2v to Inf/Inf = NaN, and tanh is
|
| 120 |
+
// already +/-1 to full f32 precision by |v| ~ 9.
|
| 121 |
+
return tanh(clamp(v, -10.0, 10.0));
|
| 122 |
{% elif activation == "HardSigmoid" %}
|
| 123 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 124 |
{% else %}
|
|
|
|
| 220 |
|
| 221 |
for (var step = 0u; step < TILE_K; step = step + 8u) {
|
| 222 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + step;
|
| 223 |
+
var matA0: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset, TILE_K);
|
| 224 |
+
var matA1: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset + 8u * TILE_K, TILE_K);
|
| 225 |
|
| 226 |
let matrix_b_offset = subtile_idx * SUB_COLS * TILE_K + step;
|
| 227 |
+
var matB0: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, col_major>(&tile_B, matrix_b_offset, TILE_K);
|
| 228 |
+
var matB1: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, col_major>(&tile_B, matrix_b_offset + 8u * TILE_K, TILE_K);
|
| 229 |
+
var matB2: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, col_major>(&tile_B, matrix_b_offset + 16u * TILE_K, TILE_K);
|
| 230 |
+
var matB3: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, col_major>(&tile_B, matrix_b_offset + 24u * TILE_K, TILE_K);
|
| 231 |
|
| 232 |
matC00 = subgroupMatrixMultiplyAccumulate(matA0, matB0, matC00);
|
| 233 |
matC01 = subgroupMatrixMultiplyAccumulate(matA0, matB1, matC01);
|
|
|
|
| 247 |
// cross-subgroup handoff into the narrow projection. All collective stores
|
| 248 |
// remain subgroup-uniform, and every fragment has a disjoint destination.
|
| 249 |
let fused_tile_offset = base_A * TILE_COLS + base_B;
|
| 250 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 0u * TILE_COLS + 0u, matC00, TILE_COLS);
|
| 251 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 0u * TILE_COLS + 8u, matC01, TILE_COLS);
|
| 252 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 0u * TILE_COLS + 16u, matC02, TILE_COLS);
|
| 253 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 0u * TILE_COLS + 24u, matC03, TILE_COLS);
|
| 254 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 8u * TILE_COLS + 0u, matC10, TILE_COLS);
|
| 255 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 8u * TILE_COLS + 8u, matC11, TILE_COLS);
|
| 256 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 8u * TILE_COLS + 16u, matC12, TILE_COLS);
|
| 257 |
+
subgroupMatrixStore<row_major>(&tile_B, fused_tile_offset + 8u * TILE_COLS + 24u, matC13, TILE_COLS);
|
| 258 |
workgroupBarrier();
|
| 259 |
|
| 260 |
// One invocation owns one spatial column and walks the producer channels in
|
|
|
|
| 293 |
// When an epilogue is present, publish the raw accumulators first, then apply
|
| 294 |
// bias, residual Z, and activation cooperatively after one storage barrier.
|
| 295 |
let matrix_c_offset = c_base + (a_global_base + base_A) * N + b_global_base + base_B;
|
| 296 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 0u * N + 0u, matC00, N);
|
| 297 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 0u * N + 8u, matC01, N);
|
| 298 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 0u * N + 16u, matC02, N);
|
| 299 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 0u * N + 24u, matC03, N);
|
| 300 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 8u * N + 0u, matC10, N);
|
| 301 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 8u * N + 8u, matC11, N);
|
| 302 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 8u * N + 16u, matC12, N);
|
| 303 |
+
subgroupMatrixStore<row_major>(&y, matrix_c_offset + 8u * N + 24u, matC13, N);
|
| 304 |
{% if hasBias or hasActivation or hasZ %}
|
| 305 |
storageBarrier();
|
| 306 |
for (var tile_idx = local_idx; tile_idx < TILE_ROWS * TILE_COLS; tile_idx += {{ workgroupThreadsValue }}u) {
|
|
|
|
| 331 |
// give the reads visibility of the store AND stop the second row-group's store from
|
| 332 |
// clobbering the first's still-in-flight readback when a partial final M-tile
|
| 333 |
// diverges storeOutput's guard. Without both barriers the last valid row can be corrupted.
|
| 334 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][0], 0u, matC00, 8u);
|
| 335 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][1], 0u, matC01, 8u);
|
| 336 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][2], 0u, matC02, 8u);
|
| 337 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][3], 0u, matC03, 8u);
|
| 338 |
workgroupBarrier();
|
| 339 |
let row = sg_id / 4u;
|
| 340 |
let col = (sg_id % 4u) * 2u;
|
|
|
|
| 344 |
storeOutput(matrix_c_offset, {% if hasBias or polyphase %}row_base, {% endif %}row, col, subtile_id, row_limit{% if padded %}, b_global_base + base_B{% endif %});
|
| 345 |
workgroupBarrier();
|
| 346 |
|
| 347 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][0], 0u, matC10, 8u);
|
| 348 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][1], 0u, matC11, 8u);
|
| 349 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][2], 0u, matC12, 8u);
|
| 350 |
+
subgroupMatrixStore<row_major>(&scratch[subtile_id][3], 0u, matC13, 8u);
|
| 351 |
workgroupBarrier();
|
| 352 |
matrix_c_offset = matrix_c_offset + 8u * N;
|
| 353 |
row_limit = i32(M) - i32(row_base + 8u);
|
build/webgpu/conv-direct-nd.wgsl.jinja
CHANGED
|
@@ -19,7 +19,10 @@ fn fused_act(v: f32) -> f32 {
|
|
| 19 |
{% elif activation == "Sigmoid" %}
|
| 20 |
return 1.0 / (1.0 + exp(-v));
|
| 21 |
{% elif activation == "Tanh" %}
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
| 23 |
{% elif activation == "HardSigmoid" %}
|
| 24 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 25 |
{% else %}
|
|
|
|
| 19 |
{% elif activation == "Sigmoid" %}
|
| 20 |
return 1.0 / (1.0 + exp(-v));
|
| 21 |
{% elif activation == "Tanh" %}
|
| 22 |
+
// Clamped for the reason given in the GEMM activation: an unbounded accumulator
|
| 23 |
+
// overflows the hardware tanh's internal e^2v to Inf/Inf = NaN, and tanh is
|
| 24 |
+
// already +/-1 to full f32 precision by |v| ~ 9.
|
| 25 |
+
return tanh(clamp(v, -10.0, 10.0));
|
| 26 |
{% elif activation == "HardSigmoid" %}
|
| 27 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 28 |
{% else %}
|
build/webgpu/conv-direct-unrolled.wgsl.jinja
CHANGED
|
@@ -25,7 +25,10 @@ fn fused_act(v: f32) -> f32 {
|
|
| 25 |
{% elif activation == "Sigmoid" %}
|
| 26 |
return 1.0 / (1.0 + exp(-v));
|
| 27 |
{% elif activation == "Tanh" %}
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
| 29 |
{% elif activation == "HardSigmoid" %}
|
| 30 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 31 |
{% else %}
|
|
|
|
| 25 |
{% elif activation == "Sigmoid" %}
|
| 26 |
return 1.0 / (1.0 + exp(-v));
|
| 27 |
{% elif activation == "Tanh" %}
|
| 28 |
+
// Clamped for the reason given in the GEMM activation: an unbounded accumulator
|
| 29 |
+
// overflows the hardware tanh's internal e^2v to Inf/Inf = NaN, and tanh is
|
| 30 |
+
// already +/-1 to full f32 precision by |v| ~ 9.
|
| 31 |
+
return tanh(clamp(v, -10.0, 10.0));
|
| 32 |
{% elif activation == "HardSigmoid" %}
|
| 33 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 34 |
{% else %}
|
build/webgpu/conv1d-tiled-reg.wgsl.jinja
CHANGED
|
@@ -34,7 +34,10 @@ fn fused_act(v: f32) -> f32 {
|
|
| 34 |
{% elif activation == "Sigmoid" %}
|
| 35 |
return 1.0 / (1.0 + exp(-v));
|
| 36 |
{% elif activation == "Tanh" %}
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
| 38 |
{% elif activation == "HardSigmoid" %}
|
| 39 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 40 |
{% else %}
|
|
|
|
| 34 |
{% elif activation == "Sigmoid" %}
|
| 35 |
return 1.0 / (1.0 + exp(-v));
|
| 36 |
{% elif activation == "Tanh" %}
|
| 37 |
+
// Clamped for the reason given in the GEMM activation: an unbounded accumulator
|
| 38 |
+
// overflows the hardware tanh's internal e^2v to Inf/Inf = NaN, and tanh is
|
| 39 |
+
// already +/-1 to full f32 precision by |v| ~ 9.
|
| 40 |
+
return tanh(clamp(v, -10.0, 10.0));
|
| 41 |
{% elif activation == "HardSigmoid" %}
|
| 42 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 43 |
{% else %}
|
build/webgpu/conv2d-grouped-large-w4.wgsl.jinja
CHANGED
|
@@ -16,7 +16,10 @@ fn fused_act(v: f32) -> f32 {
|
|
| 16 |
{% elif activation == "Sigmoid" %}
|
| 17 |
return 1.0 / (1.0 + exp(-v));
|
| 18 |
{% elif activation == "Tanh" %}
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
| 20 |
{% elif activation == "HardSigmoid" %}
|
| 21 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 22 |
{% else %}
|
|
|
|
| 16 |
{% elif activation == "Sigmoid" %}
|
| 17 |
return 1.0 / (1.0 + exp(-v));
|
| 18 |
{% elif activation == "Tanh" %}
|
| 19 |
+
// Clamped for the reason given in the GEMM activation: an unbounded accumulator
|
| 20 |
+
// overflows the hardware tanh's internal e^2v to Inf/Inf = NaN, and tanh is
|
| 21 |
+
// already +/-1 to full f32 precision by |v| ~ 9.
|
| 22 |
+
return tanh(clamp(v, -10.0, 10.0));
|
| 23 |
{% elif activation == "HardSigmoid" %}
|
| 24 |
return clamp(f32({{ actAlpha }}) * v + f32({{ actBeta }}), 0.0, 1.0);
|
| 25 |
{% else %}
|
build/webgpu/metadata.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "com.microsoft.FusedConv",
|
| 3 |
-
"id": "
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
|
@@ -8,18 +8,18 @@
|
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
"bench.json": "0T4EaJworpji9PrXCF3znUUqiMBBbSgShzzAaM/dOWY=",
|
| 11 |
-
"conv-1x1-gemm-tiled-reg.wgsl.jinja": "
|
| 12 |
-
"conv-1x1-gemm-tiled.wgsl.jinja": "
|
| 13 |
-
"conv-1x1-subgroup-matrix.wgsl.jinja": "
|
| 14 |
-
"conv-direct-nd.wgsl.jinja": "
|
| 15 |
-
"conv-direct-unrolled.wgsl.jinja": "
|
| 16 |
"conv-im2col-nchw.wgsl.jinja": "7IUuXo33elZx0pnR9M2vUXzXDjFuw2bJODkZViV/WQg=",
|
| 17 |
-
"conv1d-tiled-reg.wgsl.jinja": "
|
| 18 |
-
"conv2d-grouped-large-w4.wgsl.jinja": "
|
| 19 |
"manifest.json": "jMjmEiSVgMOjNheSacCaHlppVU7uWplUp2lv3fvGH1A=",
|
| 20 |
"test.json": "/KodhC9ZJ6IxO1wokLmeGH0zsOfDpds9+mjZLZRnPXw="
|
| 21 |
}
|
| 22 |
},
|
| 23 |
-
"provenance": { "kernel": { "sha": "
|
| 24 |
"webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.FusedConv" }
|
| 25 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "com.microsoft.FusedConv",
|
| 3 |
+
"id": "_com_microsoft_fusedconv_webgpu_e37405a",
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
|
|
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
"bench.json": "0T4EaJworpji9PrXCF3znUUqiMBBbSgShzzAaM/dOWY=",
|
| 11 |
+
"conv-1x1-gemm-tiled-reg.wgsl.jinja": "n0CRMXMLwCsmBCTq9ruaSshgRFN+QcWfYHmLLT/nYDg=",
|
| 12 |
+
"conv-1x1-gemm-tiled.wgsl.jinja": "tAifcSzQFhljZg7xs7W7xJ1t92ZjRlCCfET/7sxsrzI=",
|
| 13 |
+
"conv-1x1-subgroup-matrix.wgsl.jinja": "4M+d7l/v8cK31b+6c2QaD20PSrT3EcpMNT5LV14H+wg=",
|
| 14 |
+
"conv-direct-nd.wgsl.jinja": "+rZdtrCmC5XWDKzniyQgM8ZuEPelUn15Wy8XASMqRoI=",
|
| 15 |
+
"conv-direct-unrolled.wgsl.jinja": "Z8nzgvMffIyDdiORizHznKPUpi70ZcWPZvmwhnuE+PQ=",
|
| 16 |
"conv-im2col-nchw.wgsl.jinja": "7IUuXo33elZx0pnR9M2vUXzXDjFuw2bJODkZViV/WQg=",
|
| 17 |
+
"conv1d-tiled-reg.wgsl.jinja": "f6XtRoLCTQvmBsoTWjymS9jK1ewlj9R2t+DWBa7vv/0=",
|
| 18 |
+
"conv2d-grouped-large-w4.wgsl.jinja": "HMab+h8mlTI14B1EdMAkYmwFRFkRipfdT2ZOx36X2dY=",
|
| 19 |
"manifest.json": "jMjmEiSVgMOjNheSacCaHlppVU7uWplUp2lv3fvGH1A=",
|
| 20 |
"test.json": "/KodhC9ZJ6IxO1wokLmeGH0zsOfDpds9+mjZLZRnPXw="
|
| 21 |
}
|
| 22 |
},
|
| 23 |
+
"provenance": { "kernel": { "sha": "c928d21e6cc1310861cba3bafb75f5f679ecf5f3", "dirty": false } },
|
| 24 |
"webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.FusedConv" }
|
| 25 |
}
|