From 5d65b586461b68c4516f5b4ba27f2889ea3488c7 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 18 Feb 2025 14:14:07 -0800 Subject: [PATCH 1/2] Add missing validation steps for several ops A follow-on to #706 and the [audit](https://docs.google.com/spreadsheets/d/1S5-bMWN1hDrkPGiHFCyX-OjcbEBj1a-aWNdtTQ2dcGg) by @huningxin that adds validation steps to several ops identified for edge cases in the Chromium prototype implementation. This touches the following ops: - convTranspose2d - outputSizes items must be valid dimensions - lstm - steps must be greater than 0 - pool2d - windowDimensions must be greater than 0 - pool2d - outputSizes items must be valid dimensions - pool2d - specified output sizes must be floor() or ceil() of calculated output sizes - split - splits (if a number) must be greater than 0 Fixes #818 as well. --- index.bs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/index.bs b/index.bs index cd2aedf2..da075447 100644 --- a/index.bs +++ b/index.bs @@ -2658,15 +2658,19 @@ partial dictionary MLOpSupportLimits { 1. If |options|.{{MLConv2dOptions/bias}} [=map/exists=]: 1. If its [=MLOperand/shape=] is not [=list/equal=] to « |outputChannels| », then [=exception/throw=] a {{TypeError}}. 1. If its [=MLOperand/dataType=] is not one of its [=/allowed data types=] (according to [this table](#constraints-conv2d)), then [=exception/throw=] a {{TypeError}}. - 1. Let |outputSizes| be the result of [=MLGraphBuilder/calculating conv2d output sizes=] given |inputHeight|, |inputWidth|, |filterHeight|, |filterWidth|, |options|.{{MLConv2dOptions/padding}}, |options|.{{MLConv2dOptions/strides}}, and |options|.{{MLConv2dOptions/dilations}}. + 1. Let « |outputHeight|, |outputWidth| » be the result of [=MLGraphBuilder/calculating conv2d output sizes=] given |inputHeight|, |inputWidth|, |filterHeight|, |filterWidth|, |options|.{{MLConv2dOptions/padding}}, |options|.{{MLConv2dOptions/strides}}, and |options|.{{MLConv2dOptions/dilations}}. + 1. If either |outputHeight| or |outputWidth| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. 1. Switch on |options|.{{MLConv2dOptions/inputLayout}}:
: {{MLInputOperandLayout/"nchw"}} - :: Let |outputShape| be « |batches|, |outputChannels|, floor( |outputSizes|[0] ), floor( |outputSizes|[1] ) ». + :: Let |outputShape| be « |batches|, |outputChannels|, floor( |outputHeight| ), floor( |outputWidth| ) ». : {{MLInputOperandLayout/"nhwc"}} - :: Let |outputShape| be « |batches|, floor( |outputSizes|[0] ), floor( |outputSizes|[1] ), |outputChannels| ». + :: Let |outputShape| be « |batches|, floor( |outputHeight| ), floor( |outputWidth| ), |outputChannels| ».
1. If any [=list/item=] in |outputShape| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. + + Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| above. Remove it? + 1. Let |desc| be the result of [=creating an MLOperandDescriptor=] given |input|'s [=MLOperand/dataType=] and |outputShape|. 1. *Make graph connections:* 1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |desc|. @@ -2852,6 +2856,10 @@ partial dictionary MLOpSupportLimits { 1. Otherwise, if |options|.{{MLConvTranspose2dOptions/outputPadding}}'s [=list/size=] is not 2, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLConvTranspose2dOptions/outputSizes}} [=map/exists=]: 1. If its [=list/size=] is not 2, then [=exception/throw=] a {{TypeError}}. + 1. If any of its [=list/items=] is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. + + Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| below. Remove it? + 1. Otherwise: 1. If |options|.{{MLConvTranspose2dOptions/outputPadding}}[0] is greater than or equal to |options|.{{MLConvTranspose2dOptions/strides}}[0], or |options|.{{MLConvTranspose2dOptions/outputPadding}}[1] is greater than or equal to |options|.{{MLConvTranspose2dOptions/strides}}[1], then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLConvTranspose2dOptions/groups}} is 0, then [=exception/throw=] a {{TypeError}}. @@ -2884,6 +2892,7 @@ partial dictionary MLOpSupportLimits { 1. Otherwise: 1. Let |outputHeight| be the result of [=MLGraphBuilder/calculating convtranspose output size=] given |inputHeight|, |filterHeight|, |padding|[0], |padding|[1], |strides|[0], |dilations|[0], and |outputPadding|[0]. 1. Let |outputWidth| be the result of [=MLGraphBuilder/calculating convtranspose output size=] given |inputWidth|, |filterWidth|, |padding|[2], |padding|[3], |strides|[1], |dilations|[1] and |outputPadding|[1]. + 1. If either |outputHeight| or |outputWidth| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. 1. Switch on |options|.{{MLConvTranspose2dOptions/inputLayout}}:
: {{MLInputOperandLayout/"nchw"}} @@ -2892,6 +2901,9 @@ partial dictionary MLOpSupportLimits { :: Let |outputShape| be « |batches|, floor( |outputHeight| ), floor( |outputWidth| ), |outputChannels| ».
1. If any [=list/item=] in |outputShape| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. + + Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| above. Remove it? + 1. Let |desc| be the result of [=creating an MLOperandDescriptor=] given |input|'s [=MLOperand/dataType=] and |outputShape|. 1. *Make graph connections:* 1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |desc|. @@ -5602,6 +5614,7 @@ partial dictionary MLOpSupportLimits { 1. Let |numDirections| be 2 if |options|.{{MLLstmOptions/direction}} is {{MLRecurrentNetworkDirection/"both"}}, or 1 otherwise. 1. If the [=MLOperand/dataType=] of any of |input|, |weight| or |recurrentWeight| is not one of its [=/allowed data types=] (according to [this table](#constraints-lstm)), then [=exception/throw=] a {{TypeError}}. 1. If the [=MLOperand/rank=] of any of |input|, |weight| or |recurrentWeight| is not its [=/allowed rank=], then [=exception/throw=] a {{TypeError}}. + 1. If |steps| is 0, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/shape=][0] is not equal to |steps|, then [=exception/throw=] a {{TypeError}}. 1. Let |batchSize| be |input|'s [=MLOperand/shape=][1]. 1. Let |inputSize| be |input|'s [=MLOperand/shape=][2]. @@ -6547,6 +6560,7 @@ partial dictionary MLOpSupportLimits { 1. If |options|.{{MLPool2dOptions/windowDimensions}} does not [=map/exist=], set |options|.{{MLPool2dOptions/windowDimensions}} to « |inputHeight|, |inputWidth| ». 1. If |options|.{{MLPool2dOptions/windowDimensions}}'s [=list/size=] is not 2, then [=exception/throw=] a {{TypeError}}. + 1. If any [=list/item=] in |options|.{{MLPool2dOptions/windowDimensions}} is equal to 0, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLPool2dOptions/outputSizes}} [=map/exists=], or if |options|.{{MLPool2dOptions/padding}} does not [=map/exist=], set |options|.{{MLPool2dOptions/padding}} to the [=/list=] « 0, 0, 0, 0 ». 1. If |options|.{{MLPool2dOptions/padding}}'s [=list/size=] is not 4, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLPool2dOptions/strides}} does not [=map/exist=], set |options|.{{MLPool2dOptions/strides}} to the [=/list=] « 1, 1 ». @@ -6560,11 +6574,13 @@ partial dictionary MLOpSupportLimits { 1. If any value in |options|.{{MLPool2dOptions/dilations}} is not greater than 0, then [=exception/throw=] a {{TypeError}}. 1. Let |desc| be a copy of |input|.{{MLOperand/[[descriptor]]}}. 1. *Calculate the output shape:* - 1. If |options|.{{MLPool2dOptions/outputSizes}} [=map/exists=], then let « |outputHeight|, |outputWidth| » be |options|.{{MLPool2dOptions/outputSizes}}. + 1. Let « |windowHeight|, |windowWidth| » be |options|.{{MLPool2dOptions/windowDimensions}}. + 1. Let « |calculatedOutputHeight|, |calculatedOutputWidth| » be the result of [=MLGraphBuilder/calculating conv2d output sizes=] given |inputHeight|, |inputWidth|, |windowHeight|, |windowWidth|, |options|.{{MLPool2dOptions/padding}}, |options|.{{MLPool2dOptions/strides}}, and |options|.{{MLPool2dOptions/dilations}}. + 1. If |options|.{{MLPool2dOptions/outputSizes}} [=map/exists=], then: + 1. Let « |outputHeight|, |outputWidth| » be |options|.{{MLPool2dOptions/outputSizes}}. + 1. If neither |outputHeight| equals floor( |calculatedOutputHeight| ) and |outputWidth| equals floor( |calculatedOutputWidth| ), nor |outputHeight| equals ceil( |calculatedOutputHeight| ) and |outputWidth| equals ceil( |calculatedOutputWidth| ), then [=exception/throw=] a {{TypeError}}. 1. Otherwise: - 1. Let « |windowHeight|, |windowWidth| » be |options|.{{MLPool2dOptions/windowDimensions}}. - 1. Let |outputSizes| be the result of [=MLGraphBuilder/calculating conv2d output sizes=] given |inputHeight|, |inputWidth|, |windowHeight|, |windowWidth|, |options|.{{MLPool2dOptions/padding}}, |options|.{{MLPool2dOptions/strides}}, and |options|.{{MLPool2dOptions/dilations}}. - 1. Let « |outputHeight|, |outputWidth| » be |outputSizes|. + 1. Let « |outputHeight|, |outputWidth| » be « |calculatedOutputHeight|, |calculatedOutputWidth| ». 1. Switch on |options|.{{MLPool2dOptions/roundingType}}:
: {{MLRoundingType/"floor"}} @@ -6576,6 +6592,7 @@ partial dictionary MLOpSupportLimits { 1. Set |outputWidth| to ceiling(|outputWidth|). 1. Set |outputHeight| to ceiling(|outputHeight|).
+ 1. If either |outputHeight| or |outputWidth| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. 1. Switch on |options|.{{MLPool2dOptions/layout}}:
: {{MLInputOperandLayout/"nchw"}} @@ -6584,6 +6601,9 @@ partial dictionary MLOpSupportLimits { :: Let |outputShape| be « |batches|, |outputHeight|, |outputWidth|, |channels| ».
1. If any [=list/item=] in |outputShape| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. + + Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| above. Remove it? + 1. Set |desc|.{{MLOperandDescriptor/shape}} to |outputShape|. 1. *Make graph connections:* 1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |desc|. @@ -7816,6 +7836,7 @@ partial dictionary MLOpSupportLimits { 1. Let |axis| be |options|.{{MLSplitOptions/axis}}. 1. If |axis| is greater than or equal to |input|'s [=MLOperand/rank=], then [=exception/throw=] a {{TypeError}}. 1. If |splits| is an {{unsigned long}}: + 1. If |splits| is 0, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/shape=][|axis|] % |splits| is not 0, then [=exception/throw=] a {{TypeError}}. 1. Otherwise, let |splitCount| be |splits|. 1. If |splits| is a [=sequence=]<{{unsigned long}}>: From a0ab8c7623e170d255753d40660d585176706d19 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 21 Feb 2025 13:04:10 -0800 Subject: [PATCH 2/2] Review feedback --- index.bs | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/index.bs b/index.bs index da075447..bb5a076c 100644 --- a/index.bs +++ b/index.bs @@ -2659,18 +2659,16 @@ partial dictionary MLOpSupportLimits { 1. If its [=MLOperand/shape=] is not [=list/equal=] to « |outputChannels| », then [=exception/throw=] a {{TypeError}}. 1. If its [=MLOperand/dataType=] is not one of its [=/allowed data types=] (according to [this table](#constraints-conv2d)), then [=exception/throw=] a {{TypeError}}. 1. Let « |outputHeight|, |outputWidth| » be the result of [=MLGraphBuilder/calculating conv2d output sizes=] given |inputHeight|, |inputWidth|, |filterHeight|, |filterWidth|, |options|.{{MLConv2dOptions/padding}}, |options|.{{MLConv2dOptions/strides}}, and |options|.{{MLConv2dOptions/dilations}}. + 1. Set |outputHeight| to floor( |outputHeight| ). + 1. Set |outputWidth| to floor( |outputWidth| ). 1. If either |outputHeight| or |outputWidth| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. 1. Switch on |options|.{{MLConv2dOptions/inputLayout}}:
: {{MLInputOperandLayout/"nchw"}} - :: Let |outputShape| be « |batches|, |outputChannels|, floor( |outputHeight| ), floor( |outputWidth| ) ». + :: Let |outputShape| be « |batches|, |outputChannels|, |outputHeight|, |outputWidth| ». : {{MLInputOperandLayout/"nhwc"}} - :: Let |outputShape| be « |batches|, floor( |outputHeight| ), floor( |outputWidth| ), |outputChannels| ». + :: Let |outputShape| be « |batches|, |outputHeight|, |outputWidth|, |outputChannels| ».
- 1. If any [=list/item=] in |outputShape| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. - - Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| above. Remove it? - 1. Let |desc| be the result of [=creating an MLOperandDescriptor=] given |input|'s [=MLOperand/dataType=] and |outputShape|. 1. *Make graph connections:* 1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |desc|. @@ -2827,10 +2825,10 @@ partial dictionary MLOpSupportLimits {
- To calculate convtranspose output size given unsigned integers |inputSize|, |filterSize|, |beginningPadding|, |endingPadding|, |stride|, |dilation|, and |outputPadding|, perform these steps. They return a number. + To calculate convtranspose output size given unsigned integers |inputSize|, |filterSize|, |beginningPadding|, |endingPadding|, |stride|, and |dilation|, perform these steps. They return a number. 1. Let |effectiveFilterSize| be ( |filterSize| - 1 ) * |dilation| + 1. - 1. Let |outputSize| be ( |inputSize| - 1 ) * |stride| + |effectiveFilterSize| - |beginningPadding| - |endingPadding| + |outputPadding|. + 1. Let |outputSize| be ( |inputSize| - 1 ) * |stride| + |effectiveFilterSize| - |beginningPadding| - |endingPadding|. 1. Return |outputSize|.
@@ -2856,10 +2854,6 @@ partial dictionary MLOpSupportLimits { 1. Otherwise, if |options|.{{MLConvTranspose2dOptions/outputPadding}}'s [=list/size=] is not 2, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLConvTranspose2dOptions/outputSizes}} [=map/exists=]: 1. If its [=list/size=] is not 2, then [=exception/throw=] a {{TypeError}}. - 1. If any of its [=list/items=] is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. - - Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| below. Remove it? - 1. Otherwise: 1. If |options|.{{MLConvTranspose2dOptions/outputPadding}}[0] is greater than or equal to |options|.{{MLConvTranspose2dOptions/strides}}[0], or |options|.{{MLConvTranspose2dOptions/outputPadding}}[1] is greater than or equal to |options|.{{MLConvTranspose2dOptions/strides}}[1], then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLConvTranspose2dOptions/groups}} is 0, then [=exception/throw=] a {{TypeError}}. @@ -2884,14 +2878,19 @@ partial dictionary MLOpSupportLimits { 1. If |inputChannels| is not equal to |filterInputChannels|, then [=exception/throw=] a {{TypeError}}. 1. Let |outputChannels| be |filterOutputChannels| * |options|.{{MLConvTranspose2dOptions/groups}}. + 1. If |outputChannels| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLConvTranspose2dOptions/bias}} [=map/exists=]: 1. If its [=MLOperand/shape=] is not [=list/equal=] to « |outputChannels| », then [=exception/throw=] a {{TypeError}}. 1. If its [=MLOperand/dataType=] is not one of its [=/allowed data types=] (according to [this table](#constraints-convTranspose2d)), then [=exception/throw=] a {{TypeError}}. + 1. Let |calculatedOutputHeight| be the result of [=MLGraphBuilder/calculating convtranspose output size=] given |inputHeight|, |filterHeight|, |padding|[0], |padding|[1], |strides|[0] and |dilations|[0]. + 1. Let |calculatedOutputWidth| be the result of [=MLGraphBuilder/calculating convtranspose output size=] given |inputWidth|, |filterWidth|, |padding|[2], |padding|[3], |strides|[1] and |dilations|[1]. 1. If |options|.{{MLConvTranspose2dOptions/outputSizes}} [=map/exists=], then: 1. Let « |outputHeight|, |outputWidth| » be |options|.{{MLConvTranspose2dOptions/outputSizes}}. + 1. If |outputHeight| is less than |calculatedOutputHeight|, or |outputHeight| is greater than or equal to |calculatedOutputHeight| + |strides|[0], then [=exception/throw=] a {{TypeError}}. + 1. If |outputWidth| is less than |calculatedOutputWidth|, or |outputWidth| is greater than or equal to |calculatedOutputWidth| + |strides|[1], then [=exception/throw=] a {{TypeError}}. 1. Otherwise: - 1. Let |outputHeight| be the result of [=MLGraphBuilder/calculating convtranspose output size=] given |inputHeight|, |filterHeight|, |padding|[0], |padding|[1], |strides|[0], |dilations|[0], and |outputPadding|[0]. - 1. Let |outputWidth| be the result of [=MLGraphBuilder/calculating convtranspose output size=] given |inputWidth|, |filterWidth|, |padding|[2], |padding|[3], |strides|[1], |dilations|[1] and |outputPadding|[1]. + 1. Let |outputHeight| be |calculatedOutputHeight| + |options|.{{MLConvTranspose2dOptions/outputPadding}}[0]. + 1. Let |outputWidth| be |calculatedOutputWidth| + |options|.{{MLConvTranspose2dOptions/outputPadding}}[1]. 1. If either |outputHeight| or |outputWidth| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. 1. Switch on |options|.{{MLConvTranspose2dOptions/inputLayout}}:
@@ -2900,10 +2899,6 @@ partial dictionary MLOpSupportLimits { : {{MLInputOperandLayout/"nhwc"}} :: Let |outputShape| be « |batches|, floor( |outputHeight| ), floor( |outputWidth| ), |outputChannels| ».
- 1. If any [=list/item=] in |outputShape| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. - - Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| above. Remove it? - 1. Let |desc| be the result of [=creating an MLOperandDescriptor=] given |input|'s [=MLOperand/dataType=] and |outputShape|. 1. *Make graph connections:* 1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |desc|. @@ -6600,10 +6595,6 @@ partial dictionary MLOpSupportLimits { : {{MLInputOperandLayout/"nhwc"}} :: Let |outputShape| be « |batches|, |outputHeight|, |outputWidth|, |channels| ». - 1. If any [=list/item=] in |outputShape| is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. - - Issue: The preceding step appears redundant with the validation of |outputHeight| and |outputWidth| above. Remove it? - 1. Set |desc|.{{MLOperandDescriptor/shape}} to |outputShape|. 1. *Make graph connections:* 1. Let |output| be the result of [=creating an MLOperand=] given [=this=] and |desc|.