diff --git a/index.bs b/index.bs index 4100a344..75beb72f 100644 --- a/index.bs +++ b/index.bs @@ -869,6 +869,8 @@ interface MLContext { undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs); Promise createTensor(MLTensorDescriptor descriptor); + Promise createConstantTensor( + MLOperandDescriptor descriptor, AllowSharedBufferSource inputData); Promise readTensor(MLTensor tensor); Promise readTensor(MLTensor tensor, AllowSharedBufferSource outputData); @@ -939,6 +941,7 @@ The context type is the type of the execution context that manages th 1. If |namedTensors|'s [=map/size=] is not equal to |namedDescriptors|'s [=map/size=], then return false. 1. [=map/For each=] |name| → |tensor| of |namedTensors|: + 1. If |tensor|.{{MLTensor/[[isConstant]]}} is true, then return false. 1. If |namedDescriptors|[|name|] does not [=map/exist=], then return false. 1. If |tensor|.{{MLTensor/[[descriptor]]}} is not [=MLOperandDescriptor/equal=] to |namedDescriptors|[|name|], then return false. 1. Return true. @@ -981,6 +984,11 @@ Note: `dispatch()` itself provides no signal that graph execution has completed. 1. Return {{undefined}}. +

+ When a constant operand is created using a tensor, it is legal for that tensor to be destroyed after build completes. + Implementations are expected to ensure that the compiled graph remains valid and unaffected by such destruction. +

+ #### Examples #### {#api-mlcontext-dispatch-examples}
@@ -1065,6 +1073,42 @@ Creates an {{MLTensor}} associated with this {{MLContext}}. 1. Return |promise|.
+### {{MLContext/createConstantTensor()}} ### {#api-mlcontext-createconstanttensor} + +Creates a constant {{MLTensor}} associated with this {{MLContext}}. + +
+ **Arguments:** + - descriptor: an {{MLOperandDescriptor}}. + - inputData: an {{AllowSharedBufferSource}}. The buffer whose bytes will be written into the tensor. + + **Returns:** {{Promise}}<{{MLTensor}}>. +
+ +
+ + The createConstantTensor(|descriptor|, |inputData|) method steps are: + + 1. Let |global| be [=this=]'s [=relevant global object=]. + 1. Let |realm| be [=this=]'s [=relevant realm=]. + 1. If [=this=] [=MLContext/is lost=], then return [=a new promise=] in |realm| [=rejected=] with an "{{InvalidStateError}}" {{DOMException}}. + 1. If [=MLOperandDescriptor/checking dimensions=] given |descriptor| returns false, then return [=a new promise=] in |realm| [=rejected=] with a {{TypeError}}. + 1. If [=validating buffer with descriptor=] given |inputData| and |descriptor| returns false, then return [=a new promise=] in |realm| [=rejected=] with a {{TypeError}}. + 1. Let |bytes| be the result of [=getting a copy of the bytes held by the buffer source=] given |inputData|. + 1. [=Assert=]: |bytes|'s [=byte sequence/length=] is equal to |descriptor|'s [=MLOperandDescriptor/byte length=]. + 1. Let |tensor| be the result of [=creating a constant MLTensor=] given [=this=], and |descriptor|. + 1. Let |promise| be [=a new promise=] in |realm|. + 1. Enqueue the following steps to [=this=].{{MLContext/[[timeline]]}}: + 1. Run these steps, but [=/abort when=] [=this=] [=MLContext/is lost=]: + 1. Create |tensor|.{{MLTensor/[[data]]}} given |descriptor|. + 1. If that fails, then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{UnknownError}}" {{DOMException}}, and abort these steps. + 1. Copy |bytes| to |tensor|.{{MLTensor/[[data]]}}. + 1. If that fails, then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{UnknownError}}" {{DOMException}}, and abort these steps. + 1. Otherwise, [=queue an ML task=] with |global| to [=resolve=] |promise| with |tensor|. + 1. [=/If aborted=], then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{InvalidStateError}}" {{DOMException}}. + 1. Return |promise|. +
+ ### {{MLContext/readTensor(tensor)}} ### {#api-mlcontext-readtensor} Reads back the {{MLTensor/[[data]]}} of an {{MLTensor}} from the {{MLContext}}.{{MLContext/[[timeline]]}} to script. @@ -1454,6 +1498,10 @@ typedef (bigint or unrestricted double) MLNumber; : \[[operator]] of type [=operator=] :: Reference to {{MLOperand}}'s corresponding [=operator=]. + + : \[[constantTensor]] of type {{MLTensor}} + :: + The {{MLOperand}}'s tensor (only for constant operands).
@@ -1553,6 +1601,7 @@ interface MLTensor { readonly attribute FrozenArray shape; readonly attribute boolean readable; readonly attribute boolean writable; + readonly attribute boolean constant; undefined destroy(); }; @@ -1576,6 +1625,10 @@ interface MLTensor { : \[[data]] of an [=implementation-defined=] type :: The bytes backing the {{MLTensor}}. This data may only be accessed or modified from the {{MLTensor/[[context]]}}.{{MLContext/[[timeline]]}}. + + : \[[isConstant]] of type {{boolean}} + :: + Whether the {{MLTensor}} was created by [=create a constant MLTensor=]. @@ -1591,6 +1644,8 @@ The readable [=getter steps=] are to return [= The writable [=getter steps=] are to return [=this=].{{MLTensor/[[descriptor]]}}.{{MLTensorDescriptor/writable}}. +The constant [=getter steps=] are to return [=this=]'s {{MLTensor/[[isConstant]]}}. + ### Creating an {{MLTensor}} ### {#api-mltensor-create} An {{MLTensor}} is created by its associated {{MLContext}}. @@ -1604,6 +1659,7 @@ An {{MLTensor}} is created by its associated {{MLContext}}. 1. Set |tensor|.{{MLTensor/[[context]]}} to |context|. 1. Set |tensor|.{{MLTensor/[[descriptor]]}} to |descriptor|. 1. Set |tensor|.{{MLTensor/[[isDestroyed]]}} to false. + 1. Set |tensor|.{{MLTensor/[[isConstant]]}} to false. 1. Return |tensor|. @@ -1627,6 +1683,28 @@ Releases the resources associated with the {{MLTensor}}. This method is idempote Note: Since no further operations can be enqueued using this tensor, implementations can free any additional resource allocations associated with this tensor once all previously submitted operations using it are complete. +### Creating a constant {{MLTensor}} ### {#api-mlconstant-tensor-create} + +A constant {{MLTensor}} is created by its associated {{MLContext}}. + +
+ + To create a constant MLTensor given {{MLContext}} |context|, {{MLOperandDescriptor}} |inputDescriptor|, run the following steps: + + 1. Let |realm| be |context|'s [=relevant realm=]. + 1. Let |tensor| be a new {{MLTensor}} in |realm|. + 1. Set |tensor|.{{MLTensor/[[context]]}} to |context|. + 1. Let |tensorDescriptor| be a new {{MLTensorDescriptor}}. + 1. Set |tensorDescriptor|.{{MLTensorDescriptor/readable}} to false. + 1. Set |tensorDescriptor|.{{MLTensorDescriptor/writable}} to false. + 1. Set |tensorDescriptor|.{{MLOperandDescriptor/dataType}} to |inputDescriptor|.{{MLOperandDescriptor/dataType}}. + 1. Set |tensorDescriptor|.{{MLOperandDescriptor/shape}} to |inputDescriptor|.{{MLOperandDescriptor/shape}}. + 1. Set |tensor|.{{MLTensor/[[descriptor]]}} to |tensorDescriptor|. + 1. Set |tensor|.{{MLTensor/[[isDestroyed]]}} to false. + 1. Set |tensor|.{{MLTensor/[[isConstant]]}} to true. + 1. Return |tensor|. +
+ ## {{MLGraphBuilder}} interface ## {#api-mlgraphbuilder} The {{MLGraphBuilder}} interface defines a set of operations as identified by the [[#usecases]] that can be composed into a computational graph. It also represents the intermediate state of a graph building session. @@ -1649,6 +1727,9 @@ interface MLGraphBuilder { // Create a scalar operand from the specified number of the specified type. MLOperand constant(MLOperandDataType type, MLNumber value); + // Create an operand from a specified constant tensor. + MLOperand constant(MLTensor tensor); + // Compile the graph up to the specified output operands asynchronously. Promise build(MLNamedOperands outputs); }; @@ -1749,6 +1830,30 @@ Create a constant {{MLOperand}} of the specified data type and shape that contai 1. Return |operand|. +#### {{MLGraphBuilder/constant(tensor)}} #### {#api-mlgraphbuilder-constant-tensor} +Create a constant {{MLOperand}} of the specified data type and shape that contains the initialized data. + +
+ **Arguments:** + - tensor: an {{MLTensor}}. The constant tensor containing the initialized data. + **Returns:** an {{MLOperand}}. The constant output tensor. +
+ +
+ + The constant(|tensor|) method steps are: + + 1. If |tensor|.{{MLTensor/[[context]]}} is not [=this=].{{MLGraphBuilder/[[context]]}}, then [=exception/throw=] a {{TypeError}}. + 1. If |tensor|.{{MLTensor/[[isDestroyed]]}} is true, then [=exception/throw=] a {{TypeError}}. + 1. If |tensor|.{{MLTensor/[[isConstant]]}} is false, then [=exception/throw=] a {{TypeError}}. + 1. If [=this=] [=MLGraphBuilder/can not build=], then [=exception/throw=] an "{{InvalidStateError}}" {{DOMException}}. + 1. *Make graph connections:* + 1. Let |operand| be the result of [=creating an MLOperand=] given [=this=] and |tensor|.{{MLTensor/[[descriptor]]}}. + 1. Set |operand|.{{MLOperand/[[constantTensor]]}} to |tensor|. + 1. Add |operand| to [=this=]'s [=MLGraphBuilder/graph=]'s [=computational graph/constants=] with |tensor| as value. + 1. Return |operand|. +
+ #### {{MLGraphBuilder/constant(type, value)}} #### {#api-mlgraphbuilder-constant-type-value} Create a scalar constant {{MLOperand}} of the specified value and data type. @@ -1796,6 +1901,7 @@ Build a composed graph up to a given output operand into a computational graph a 1. If |name| is empty, then return [=a new promise=] in |realm| [=rejected=] with a {{TypeError}}. 1. If [=MLGraphBuilder/validating operand=] given [=this=] and |operand| returns false, then return [=a new promise=] in |realm| [=rejected=] with a {{TypeError}}. 1. If |operand| is in [=this=]'s [=MLGraphBuilder/graph=]'s [=computational graph/inputs=] or [=computational graph/constants=], then return [=a new promise=] in |realm| [=rejected=] with a {{TypeError}}. + 1. If |operand|.{{MLOperand/[[constantTensor]]}} exists and |operand|.{{MLOperand/[[constantTensor]]}}.{{MLTensor/[[isDestroyed]]}} is true, then return [=a new promise=] in |realm| [=rejected=] with a {{TypeError}}. 1. Let |operands| be a new empty [=/set=]. 1. Let |operators| be a new empty [=/set=]. 1. Let |inputs| be a new empty [=/set=]. @@ -1817,7 +1923,7 @@ Build a composed graph up to a given output operand into a computational graph a 1. Set |graph|.{{MLGraph/[[outputDescriptors]]}}[|name|] to |operand|.{{MLOperand/[[descriptor]]}}. 1. Set [=this=].{{MLGraphBuilder/[[hasBuilt]]}} to true. 1. Let |promise| be [=a new promise=] in |realm|. - 1. Run the following steps [=in parallel=]: + 1. Enqueue the following steps to |graph|.{{MLGraph/[[context]]}}.{{MLContext/[[timeline]]}}: 1. Run these steps, but [=/abort when=] |graph|.{{MLGraph/[[context]]}} [=MLContext/is lost=]: 1. Let |graphImpl| be the result of converting [=this=]'s [=MLGraphBuilder/graph=] with |operands|, |operators|, |inputs|, and |outputs|'s [=map/values=] into an [=implementation-defined=] format which can be interpreted by the underlying platform. 1. If the previous step failed, then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{OperationError}}" {{DOMException}}, and abort these steps.