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
Wording change: Tighten up output shape calculation algorithms (#523)
* Wording change: Tighten up output shape calculation algorithms
For gemm() - make lists that are mutated be explicit clones using
Infra terminology, and simplify the wording reversing the lists.
For matmul() - make lists that are mutated be explicit clones using
Infra terminology, use append/prepend definitions from Infra, convert
a variable change from "let" to "set" and drop use of "array".
For #395
* Rewrite to match Chromium impl
* Update index.bs
Co-authored-by: Dwayne Robinson <[email protected]>
---------
Co-authored-by: Dwayne Robinson <[email protected]>
The <dfn method for=MLGraphBuilder>gemm(|a|, |b|, |options|)</dfn> method steps are:
2893
2893
</summary>
2894
2894
<div class=algorithm-steps>
2895
-
1. Let |shapeA| be |a|'s [=MLOperand/shape=] and |sizeA| be |a|'s [=MLOperand/rank=].
2896
-
1. Let |shapeB| be |b|'s [=MLOperand/shape=] and |sizeB| be |b|'s [=MLOperand/rank=].
2895
+
1. Let |shapeA| be a [=list/clone=] of |a|'s [=MLOperand/shape=].
2896
+
1. Let |sizeA| be the [=list/size=] of |shapeA|.
2897
+
1. Let |shapeB| be a [=list/clone=] of |b|'s [=MLOperand/shape=].
2898
+
1. Let |sizeB| be the [=list/size=] of |shapeB|.
2897
2899
1. If |sizeA| is not 2 or |sizeB| is not 2, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
2898
-
1. If |options|.{{MLGemmOptions/aTranspose}} is true, then let |shapeA| be the reverse array of |shapeA|.
2899
-
1. If |options|.{{MLGemmOptions/bTranspose}} is true, then let |shapeB| be the reverse array of |shapeB|.
2900
+
1. If |options|.{{MLGemmOptions/aTranspose}} is true, then reverse the order of the items in |shapeA|.
2901
+
1. If |options|.{{MLGemmOptions/bTranspose}} is true, then reverse the order of the items in |shapeB|.
2900
2902
1. If |shapeA|[1] is not equal to |shapeB|[0], then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
2901
2903
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}}.
- If both *a* and *b* are 2-dimensional, they are multiplied like conventional
4336
4338
matrices and produce a 2-dimensional tensor as the output.
4337
4339
- If either *a* or *b* is `N`-dimensional where `N > 2`, it is treated as a stack of matrices with dimensions corresponding to the last two indices. The matrix multiplication will be broadcasted accordingly by following the [[!numpy-broadcasting-rule]]. The output is a `N`-dimensional tensor whose rank is the maximum [=rank=] of the input tensors. For each dimension, except the last two, of the output tensor, its size is the maximum size along that dimension of the input tensors.
4338
-
- If *a* is 1-dimensional, it is converted to a 2-dimensional tensor by prepending a 1 to its dimensions.
4339
-
- If *b* is 1-dimensional, it is converted to a 2-dimensional tensor by by appending a 1 to its dimensions.
4340
-
- If both *a* and *b* are 1-dimensional, the operation is a vector dot-product, which produces a scalar output.
4341
4340
</div>
4342
4341
4343
4342
<details open algorithm>
4344
4343
<summary>
4345
4344
To <dfn dfn-for=MLGraphBuilder>calculate matmul output sizes</dfn>, given |a| and |b| run the following steps:
4346
4345
</summary>
4347
4346
<div class=algorithm-steps>
4348
-
1. Let |shapeA| be |a|'s [=MLOperand/shape=] and |sizeA| be |a|'s [=MLOperand/rank=].
4349
-
1. Let |shapeB| be |b|'s [=MLOperand/shape=] and |sizeB| be |b|'s [=MLOperand/rank=].
4350
-
1. If |sizeA| and |sizeB| is 1, return the [=/list=] « 1 ».
4351
-
1. If |sizeA| is 1 and |sizeB| is not, then insert 1 in the front of |shapeA| to become [ 1 | |shapeA| ] and let |sizeA| be 2.
4352
-
1. If |shapeA|[0] is not equal to |shapeB|[|sizeB| - 2], then [=exception/throw=] an "{{OperationError}}" {{DOMException}}.
4353
-
1. If |sizeB| is 1 and |sizeA| is not, then append 1 to |shapeB| to become [ |shapeB| | 1 ] and let |sizeB| be 2.
4354
-
1. If |shapeA|[|sizeA| - 1] is not equal to |shapeB|[0], then [=exception/throw=] an "{{OperationError}}" {{DOMException}}.
4355
-
1. Let |shape| be an array whose size |size| is the maximum of |sizeA| and |sizeB|.
4356
-
1. [=list/For each=] |index| in [=the range=] 0 to |size|, exclusive:
4357
-
1. Set |shape|[|index|] to the maximum of |shapeA|[|index|] and |shapeB|[|index|].
4358
-
1. Return |shape|.
4347
+
1. Let |shapeA| be a [=list/clone=] of |a|'s [=MLOperand/shape=]
4348
+
1. Let |sizeA| be the [=list/size=] of |shapeA|.
4349
+
1. Let |shapeB| be a [=list/clone=] of |b|'s [=MLOperand/shape=]
4350
+
1. Let |sizeB| be the [=list/size=] of |shapeB|.
4351
+
1. If either |sizeA| or |sizeB| is less than 2, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
4352
+
1. Let |colsA| be |shapeA|[|sizeA| - 1].
4353
+
1. Let |rowsA| be |shapeA|[|sizeA| - 2].
4354
+
1. Let |colsB| be |shapeB|[|sizeB| - 1].
4355
+
1. Let |rowsB| be |shapeB|[|sizeB| - 2].
4356
+
1. If |colsA| is not equal to |rowsB|, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
4357
+
1. Let |batchShapeA| be a [=list/clone=] of |shapeA| with the spatial dimensions (last 2 items) [=list/removed=].
4358
+
1. Let |batchShapeB| be a [=list/clone=] of |shapeB| with the spatial dimensions (last 2 items) [=list/removed=].
4359
+
1. Let |outputShape| be the result of [=bidirectionally broadcasting the shapes=] |batchShapeA| and |batchShapeB|. If that returns failure, then [=exception/throw=] a "{{DataError}}" {{DOMException}}.
4360
+
1. [=list/Append=] « |rowsA|, |colsB| » to |outputShape|.
0 commit comments