You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
New content: Add definition for shape broadcasting
This change introduces a new section for Algorithms, following APIs,
to collect algorithms referenced throughout the specification.
A section for Broadcasting is introduced, which defines broadcasting
shapes and gives an explicit algorithm matching WebNN implementations
of NumPy's General Broadcasting Rules. Definitions for "broadcastable"
and "unidirectionally broadcastable" are introduced. The previous
definition of "broadcast-shapes" is removed in favor of these new
algorithms.
For webmachinelearning#324, webmachinelearning#462, and potentially webmachinelearning#523.
1. If |a|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}} is not equal to |b|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}}, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
2440
2440
1. Let |descriptor| be a new {{MLOperandDescriptor}}.
2441
2441
1. Set |descriptor|.{{MLOperandDescriptor/dataType}} to |a|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}}.
2442
-
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of running the [=MLGraphBuilder/broadcast-shapes=] steps given |a|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |b|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
2443
-
1. If that [=exception/throws=] an error, re-[=exception/throw=]the error.
2442
+
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of [=broadcasting the shapes=] |a|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |b|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
2443
+
1. If that returns failure, then [=exception/throw=]a "{{DataError}}" {{DOMException}}.
2444
2444
1. If any of the following sub-steps fail, [=exception/throw=] an "{{OperationError}}" {{DOMException}}.
2445
2445
1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |descriptor|.
To <dfn for="MLGraphBuilder">broadcast-shapes</dfn> given |shape1| and |shape2|, run the following steps:
2460
-
</summary>
2461
-
<div class=algorithm-steps>
2462
-
1. [=Assert=]: The type of |shape1| and |shape2| is `sequence of unsigned long`.
2463
-
1. Let |output| be the result of invoking the [=implementation-defined=] shape broadcast on |shape1| and |shape2|.
2464
-
1. If that fails, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
2465
-
1. Return |output|.
2466
-
<div class = "note">
2467
-
The most common implementation is that two shapes are compatible, when each of their corresponding dimensions are equal, or one of them is 1. The output shape consists of the maximum of the corresponding dimensions.
2468
-
</div>
2469
-
</div>
2470
-
</details>
2471
-
2472
2457
<details open>
2473
2458
<summary>
2474
2459
The element-wise binary operation algorithms invoke the [=MLGraphBuilder/element-wise-binary-op | create element-wise binary operation=] steps as follows.
@@ -2576,8 +2561,8 @@ Although operations *greaterOrEqual* and *lesserOrEqual* can each be implemented
2576
2561
1. If |a|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}} is not equal to |b|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}}, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
2577
2562
1. Let |descriptor| be a new {{MLOperandDescriptor}}.
2578
2563
1. Set |descriptor|.{{MLOperandDescriptor/dataType}} to {{MLOperandDataType/"uint8"}}.
2579
-
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of running the [=MLGraphBuilder/broadcast-shapes=] steps given |a|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |b|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
2580
-
1. If that [=exception/throws=] an error, re-[=exception/throw=]the error.
2564
+
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of [=broadcasting the shapes=] |a|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |b|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
2565
+
1. If that returns failure, then [=exception/throw=]a "{{DataError}}" {{DOMException}}.
2581
2566
1. If any of the following sub-steps fail, [=exception/throw=] an "{{OperationError}}" {{DOMException}}.
2582
2567
1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |descriptor|.
Calculate the [general matrix multiplication of the Basic Linear Algebra Subprograms](https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms#Level_3). The calculation follows the expression `alpha * A * B + beta * C`, where `A` is a 2-D tensor with shape [M, K] or [K, M], `B` is a 2-D tensor with shape [K, N] or [N, K], and `C` is broadcastable to the shape [M, N]. `A` and `B` may optionally be transposed prior to the calculation.
3054
+
Calculate the [general matrix multiplication of the Basic Linear Algebra Subprograms](https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms#Level_3). The calculation follows the expression `alpha * A * B + beta * C`, where `A` is a 2-D tensor with shape [M, K] or [K, M], `B` is a 2-D tensor with shape [K, N] or [N, K], and `C` is [=broadcastable=] to the shape [M, N]. `A` and `B` may optionally be transposed prior to the calculation.
An {{MLOperand}}. Specifies the third input tensor. It is either a scalar, or of the shape that is unidirectionally broadcastable to the shape [M, N] according to [[!numpy-broadcasting-rule]]. When it is not specified, the computation is done as if *c* is a scalar 0.0.
3074
+
An {{MLOperand}}. Specifies the third input tensor. It is either a scalar, or of the shape that is [=unidirectionally broadcastable=] to the shape [M, N]. When it is not specified, the computation is done as if *c* is a scalar 0.0.
1. If |options|.{{MLGemmOptions/aTranspose}} is true, then let |shapeA| be the reverse array of |shapeA|.
3128
3113
1. If |options|.{{MLGemmOptions/bTranspose}} is true, then let |shapeB| be the reverse array of |shapeB|.
3129
3114
1. If |shapeA|[1] is not equal to |shapeB|[0], then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
3130
-
1. If |options|.{{MLGemmOptions/c}}[=map/exists=] and is not unidirectionally broadcastable to the shape [|shapeA|[0], |shapeB|[1]] according to the [[!numpy-broadcasting-rule]], then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
3115
+
1. If |options|.{{MLGemmOptions/c}}[=map/exists=] and is not [=unidirectionally broadcastable=] to the shape [|shapeA|[0], |shapeB|[1]], then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
3131
3116
<div class="note">
3132
3117
Type compatibility between |a|, |b| and |options|.{{MLGemmOptions/c}} can be also checked.
- *slope*: an {{MLOperand}}. The slope tensor. Its shape is either the same as, or unidirectionally broadcastable to the shape of input tensor *input* according to [[!numpy-broadcasting-rule]].
4959
+
- *slope*: an {{MLOperand}}. The slope tensor. Its shape is either the same as, or [=unidirectionally broadcastable=] to the shape of input tensor *input*.
4975
4960
4976
4961
**Returns:**
4977
4962
- an {{MLOperand}}. The output tensor of the same shape as *input*.
1. [=Assert=]: the type of |input| and |slope| is {{MLOperand}}.
4987
4972
1. Let |descriptor| be a new {{MLOperandDescriptor}}.
4988
4973
1. Set |descriptor|.{{MLOperandDescriptor/dataType}} to |input|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}}.
4989
-
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of running the [=MLGraphBuilder/broadcast-shapes=] steps given |input|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |slope|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
4990
-
1. If that [=exception/throws=] an error, re-[=exception/throw=]the error.
4974
+
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of [=broadcasting the shapes=] |input|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |slope|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
4975
+
1. If that returns failure, then [=exception/throw=]a "{{DataError}}" {{DOMException}}.
4991
4976
1. If any of the following sub-steps fail, [=exception/throw=] an "{{OperationError}}" {{DOMException}}.
4992
4977
1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |descriptor|.
1. If |input|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}} is not equal to |other|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}}, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
6128
6113
1. Let |descriptor| be a new {{MLOperandDescriptor}}.
6129
6114
1. Set |descriptor|.{{MLOperandDescriptor/dataType}} to |input|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dataType}}.
6130
-
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of running the [=MLGraphBuilder/broadcast-shapes=] steps given |input|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |other|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
6131
-
1. If that [=exception/throws=] an error, re-[=exception/throw=]the error.
6132
-
1. If |condition| is not unidirectionally broadcastable to |descriptor|.{{MLOperandDescriptor/dimensions}} according to the [[!numpy-broadcasting-rule]], then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
6115
+
1. Set |descriptor|.{{MLOperandDescriptor/dimensions}} to the result of [=broadcasting the shapes=] |input|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}} and |other|.{{MLOperand/[[descriptor]]}}.{{MLOperandDescriptor/dimensions}}.
6116
+
1. If that returns failure, then [=exception/throw=]a "{{DataError}}" {{DOMException}}.
6117
+
1. If |condition| is not [=unidirectionally broadcastable=] to |descriptor|.{{MLOperandDescriptor/dimensions}}, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
6133
6118
1. If any of the following sub-steps fail, [=exception/throw=] an "{{OperationError}}" {{DOMException}}.
6134
6119
1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |descriptor|.
Broadcasting refers to how operations treat tensors with different shapes, and follow the precedent set by [[!numpy-broadcasting-rule]].
6340
+
6341
+
<div algorithm>
6342
+
To <dfn>broadcast the shapes</dfn> |A| and |B|, perform the following steps. |A| and |B| are [=/lists=] of positive integers, representing the dimensions of tensors, and the steps return a new [=/list=] of positive integers, or failure.
6343
+
6344
+
1. Let |sizeA| be the [=list/size=] of |A|.
6345
+
1. Let |sizeB| be the [=list/size=] of |B|.
6346
+
1. Let |output| be a new [=/list=].
6347
+
1. [=list/For each=] |index| in [=the range=] 0 to |sizeA|, exclusive:
6348
+
1. Let |dimA| be |A|[|sizeA| - |index| - 1] if |index| < |sizeA|, or 1 otherwise.
6349
+
1. Let |dimB| be |B|[|sizeB| - |index| - 1] if |index| < |sizeB|, or 1 otherwise.
6350
+
1. If |dimA| is not equal to |dimB| and |dimA| is not equal to 1, then return failure.
6351
+
1. [=list/Prepend=] |dimA| to |output|.
6352
+
1. Return |output|.
6353
+
6354
+
</div>
6355
+
6356
+
<div algorithm>
6357
+
|A| is <dfn>broadcastable</dfn> to |B| if [=broadcasting the shapes=] |A| and |B| does not result in failure.
6358
+
</div>
6359
+
6360
+
<div algorithm>
6361
+
|A| is <dfn>unidirectionally broadcastable</dfn> to |B| if |A| is [=broadcastable=] to |B|, and |B| is [=broadcastable=] to |A|.
0 commit comments