From 7fe0e79c072a643ad0bd6aa19ada986e60f765e8 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Wed, 17 Apr 2024 14:48:08 -0700 Subject: [PATCH 1/2] Validate the maximum hidden size of GRU and LSTM operators For gru()/gruCell() and lstm()/lstmCell(), a hiddenSize parameter is passed, a multiple of which defines a dimension of the output. - This is sometimes implicitly validated by the presence of an option with the same dimension - but not always. - Some underlying platforms operate on a single bias tensor, rather than the two bias/recurrentBias options present in the WebNN API. So the combined size needs to also be a valid dimension. Introduce validation for all cases, validate the combined size, and add an explanation inline since this is subtle. Fixes #625 --- index.bs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/index.bs b/index.bs index ff58ae67..f0856818 100644 --- a/index.bs +++ b/index.bs @@ -3073,6 +3073,11 @@ partial interface MLGraphBuilder { 1. If [=MLGraphBuilder/validating operand=] with [=this=] and any of |input|, |weight|, |recurrentWeight|, |options|.{{MLGruOptions/bias}} (if it [=map/exists=]), |options|.{{MLGruOptions/recurrentBias}} (if it [=map/exists=]), and |options|.{{MLGruOptions/initialHiddenState}} (if it [=map/exists=]) returns false, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLGruOptions/activations}} [=map/exists=], and [=MLGraphBuilder/validating activation=] with [=this=] and any [=list/item=] in it returns false, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/rank=] or |weight| or |recurrentWeight| is not 3, then [=exception/throw=] a {{TypeError}}. + 1. If |hiddenSize| * 6 is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. +
+ Why |hiddenSize| * 6 ? + Some underlying platforms operate on a single bias tensor which is a concatenation of {{MLGruOptions/bias}} and {{MLGruOptions/recurrentBias}}. Therefore, 3 * |hiddenSize| + 3 * |hiddenSize| must also be a [=valid dimension=]. +
1. If |options|.{{MLGruOptions/bias}} [=map/exists=]. 1. If |options|.{{MLGruOptions/bias}}'s [=MLOperand/shape=][1] is not equal to 3 * |hiddenSize|, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLGruOptions/recurrentBias}} [=map/exists=]. @@ -3241,6 +3246,11 @@ partial interface MLGraphBuilder { 1. If [=MLGraphBuilder/validating operand=] with [=this=] and any of |input|, |weight|, |recurrentWeight|, |hiddenState|, |options|.{{MLGruCellOptions/bias}} (if it [=map/exists=]), and |options|.{{MLGruCellOptions/recurrentBias}} (if it [=map/exists=]) returns false, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLGruCellOptions/activations}} [=map/exists=], and [=MLGraphBuilder/validating activation=] with [=this=] and any [=list/item=] in it returns false, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/rank=] or |weight| or |recurrentWeight| or |hiddenState| is not 2, then [=exception/throw=] a {{TypeError}}. + 1. If |hiddenSize| * 6 is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. +
+ Why |hiddenSize| * 6 ? + Some underlying platforms operate on a single bias tensor which is a concatenation of {{MLGruCellOptions/bias}} and {{MLGruCellOptions/recurrentBias}}. Therefore, 3 * |hiddenSize| + 3 * |hiddenSize| must also be a [=valid dimension=]. +
1. If |weight|'s [=MLOperand/shape=][0] is not equal to 3 * |hiddenSize|, then [=exception/throw=] a {{TypeError}}. 1. If |recurrentWeight|'s [=MLOperand/shape=][0] is not equal to 3 * |hiddenSize|, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLGruOptions/bias}} [=map/exists=]: @@ -3958,6 +3968,11 @@ partial interface MLGraphBuilder { 1. Let |numDirections| be 1 if |options|.{{MLLstmOptions/direction}} is {{MLRecurrentNetworkDirection/"forward"}}, or otherwise let it be 2. 1. If |input|'s [=MLOperand/rank=] or |weight| or |recurrentWeight| is not 3, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/shape=][0] is not equal to |steps|, then [=exception/throw=] a {{TypeError}}. + 1. If |hiddenSize| * 8 is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. +
+ Why |hiddenSize| * 8 ? + Some underlying platforms operate on a single bias tensor which is a concatenation of {{MLLstmOptions/bias}} and {{MLLstmOptions/recurrentBias}}. Therefore, 4 * |hiddenSize| + 4 * |hiddenSize| must also be a [=valid dimension=]. +
1. Let |batchSize| be |input|'s [=MLOperand/shape=][1]. 1. If |options|.{{MLLstmOptions/bias}} [=map/exists=]: 1. If its [=MLOperand/rank=] is not 2, then [=exception/throw=] a {{TypeError}}. @@ -4163,6 +4178,11 @@ partial interface MLGraphBuilder { 1. If [=MLGraphBuilder/validating operand=] with [=this=] and any of |input|, |weight|, |recurrentWeight|, |hiddenState|, |cellState|, |options|.{{MLLstmCellOptions/bias}} (if it [=map/exists=]), |options|.{{MLLstmCellOptions/recurrentBias}} (if it [=map/exists=]), and |options|.{{MLLstmCellOptions/peepholeWeight}} (if it [=map/exists=]) returns false, then [=exception/throw=] a {{TypeError}}. 1. If |options|.{{MLLstmCellOptions/activations}} [=map/exists=], and [=MLGraphBuilder/validating activation=] with [=this=] and any [=list/item=] in it returns false, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/rank=], |weight|, |recurrentWeight|, |hiddenState| or |cellState| is not 2, then [=exception/throw=] a {{TypeError}}. + 1. If |hiddenSize| * 8 is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}. +
+ Why |hiddenSize| * 8 ? + Some underlying platforms operate on a single bias tensor which is a concatenation of {{MLLstmCellOptions/bias}} and {{MLLstmCellOptions/recurrentBias}}. Therefore, 4 * |hiddenSize| + 4 * |hiddenSize| must also be a [=valid dimension=]. +
1. Let |batchSize| be |input|'s [=MLOperand/shape=][0]. 1. If |options|.{{MLLstmCellOptions/bias}} [=map/exists=]: 1. If its [=MLOperand/rank=] is not 1, then [=exception/throw=] a {{TypeError}}. From 98e3892872e85cfec401624bb9ca1d178b3561f0 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 27 Apr 2024 21:56:54 -0700 Subject: [PATCH 2/2] fix merge residue --- index.bs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/index.bs b/index.bs index 5ddf4e8d..be6f7031 100644 --- a/index.bs +++ b/index.bs @@ -3985,15 +3985,12 @@ partial interface MLGraphBuilder { 1. If |input|'s [=MLOperand/dataType=] is not {{MLOperandDataType/"float32"}} or {{MLOperandDataType/"float16"}}, then [=exception/throw=] a {{TypeError}}. 1. If the [=MLOperand/rank=] of any of |input|, |weight| or |recurrentWeight| is not 3, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/shape=][0] is not equal to |steps|, then [=exception/throw=] a {{TypeError}}. -<<<<<<< HEAD + 1. If the [=MLOperand/dataType=] of either |weight| or |recurrentWeight| is not equal to |input|'s [=MLOperand/dataType=], then [=exception/throw=] a {{TypeError}}. 1. If |hiddenSize| * 8 is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}.
Why |hiddenSize| * 8 ? Some underlying platforms operate on a single bias tensor which is a concatenation of {{MLLstmOptions/bias}} and {{MLLstmOptions/recurrentBias}}. Therefore, 4 * |hiddenSize| + 4 * |hiddenSize| must also be a [=valid dimension=].
-======= - 1. If the [=MLOperand/dataType=] of either |weight| or |recurrentWeight| is not equal to |input|'s [=MLOperand/dataType=], then [=exception/throw=] a {{TypeError}}. ->>>>>>> refs/heads/review 1. Let |batchSize| be |input|'s [=MLOperand/shape=][1]. 1. If |options|.{{MLLstmOptions/bias}} [=map/exists=]: 1. If its [=MLOperand/dataType=] is not equal to |input|'s [=MLOperand/dataType=], then [=exception/throw=] a {{TypeError}}. @@ -4210,15 +4207,12 @@ partial interface MLGraphBuilder { 1. If |options|.{{MLLstmCellOptions/activations}} [=map/exists=], and [=MLGraphBuilder/validating activation=] with [=this=] and any [=list/item=] in it returns false, then [=exception/throw=] a {{TypeError}}. 1. If |input|'s [=MLOperand/dataType=] is not {{MLOperandDataType/"float32"}} or {{MLOperandDataType/"float16"}}, then [=exception/throw=] a {{TypeError}}. 1. If the [=MLOperand/rank=] of any of |input|, |weight|, |recurrentWeight|, |hiddenState| or |cellState| is not 2, then [=exception/throw=] a {{TypeError}}. -<<<<<<< HEAD + 1. If the [=MLOperand/dataType=] of any of |weight|, |recurrentWeight|, |hiddenState| or |cellState| is not equal to |input|'s [=MLOperand/dataType=], then [=exception/throw=] a {{TypeError}}. 1. If |hiddenSize| * 8 is not a [=valid dimension=], then [=exception/throw=] a {{TypeError}}.
Why |hiddenSize| * 8 ? Some underlying platforms operate on a single bias tensor which is a concatenation of {{MLLstmCellOptions/bias}} and {{MLLstmCellOptions/recurrentBias}}. Therefore, 4 * |hiddenSize| + 4 * |hiddenSize| must also be a [=valid dimension=].
-======= - 1. If the [=MLOperand/dataType=] of any of |weight|, |recurrentWeight|, |hiddenState| or |cellState| is not equal to |input|'s [=MLOperand/dataType=], then [=exception/throw=] a {{TypeError}}. ->>>>>>> refs/heads/review 1. Let |batchSize| be |input|'s [=MLOperand/shape=][0]. 1. If |options|.{{MLLstmCellOptions/bias}} [=map/exists=]: 1. If its [=MLOperand/dataType=] is not equal to |input|'s [=MLOperand/dataType=], then [=exception/throw=] a {{TypeError}}.