Skip to content

Commit 5c83cc9

Browse files
committed
Allow tensors for graph constants.
As noted in the issue, sharing weights between graphs is a effective way to enable reuse of device buffers, allowing web developers to manage weight data in graphs similarly to other input or output buffers. Resolves #760
1 parent 69bb88d commit 5c83cc9

File tree

1 file changed

+96
-1
lines changed

1 file changed

+96
-1
lines changed

index.bs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,7 @@ interface MLContext {
869869
undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs);
870870

871871
Promise<MLTensor> createTensor(MLTensorDescriptor descriptor);
872+
Promise<MLConstantTensor> createConstantTensor(MLOperandDescriptor descriptor, AllowSharedBufferSource inputData);
872873

873874
Promise<ArrayBuffer> readTensor(MLTensor tensor);
874875
Promise<undefined> readTensor(MLTensor tensor, AllowSharedBufferSource outputData);
@@ -939,6 +940,7 @@ The <dfn>context type</dfn> is the type of the execution context that manages th
939940
</summary>
940941
1. If |namedTensors|'s [=map/size=] is not equal to |namedDescriptors|'s [=map/size=], then return false.
941942
1. [=map/For each=] |name| → |tensor| of |namedTensors|:
943+
1. If |tensor| is a {{MLConstantTensor}} then return false.
942944
1. If |namedDescriptors|[|name|] does not [=map/exist=], then return false.
943945
1. If |tensor|.{{MLTensor/[[descriptor]]}} is not [=MLOperandDescriptor/equal=] to |namedDescriptors|[|name|], then return false.
944946
1. Return true.
@@ -1058,7 +1060,42 @@ Creates an {{MLTensor}} associated with this {{MLContext}}.
10581060
1. Let |promise| be [=a new promise=] in |realm|.
10591061
1. Enqueue the following steps to [=this=].{{MLContext/[[timeline]]}}:
10601062
1. Run these steps, but [=/abort when=] [=this=] [=MLContext/is lost=]:
1061-
1. Create |tensor|.{{MLTensor/[[data]]}} given |descriptor| and initialize all bytes to zeros.
1063+
1. Create |tensor|.{{MLTensor/[[data]]}} given |descriptor|.
1064+
1. If that fails, then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{UnknownError}}" {{DOMException}}, and abort these steps.
1065+
1. Otherwise, [=queue an ML task=] with |global| to [=resolve=] |promise| with |tensor|.
1066+
1. [=/If aborted=], then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{InvalidStateError}}" {{DOMException}}.
1067+
1. Return |promise|.
1068+
</details>
1069+
1070+
### {{MLContext/createConstantTensor()}} ### {#api-mlcontext-createconstanttensor}
1071+
1072+
Creates an {{MLConstantTensor}} associated with this {{MLContext}}.
1073+
1074+
<div dfn-for="MLContext/createConstantTensor(descriptor, inputData)" dfn-type=argument>
1075+
**Arguments:**
1076+
- <dfn>descriptor</dfn>: an {{MLOperandDescriptor}}.
1077+
- <dfn>inputData</dfn>: an {{AllowSharedBufferSource}}. The buffer whose bytes will be written into the tensor.
1078+
1079+
**Returns:** {{Promise}}<{{MLConstantTensor}}>.
1080+
</div>
1081+
1082+
<details open algorithm>
1083+
<summary>
1084+
The <dfn method for=MLContext>createConstantTensor(|descriptor|, |inputData|)</dfn> method steps are:
1085+
</summary>
1086+
1. Let |global| be [=this=]'s [=relevant global object=].
1087+
1. Let |realm| be [=this=]'s [=relevant realm=].
1088+
1. If [=this=] [=MLContext/is lost=], then return [=a new promise=] in |realm| [=rejected=] with an "{{InvalidStateError}}" {{DOMException}}.
1089+
1. If [=MLOperandDescriptor/checking dimensions=] given |descriptor| returns false, then [=exception/throw=] a {{TypeError}}.
1090+
1. If [=validating buffer with descriptor=] given |inputData| and |descriptor| returns false, then return [=a new promise=] in |realm| [=rejected=] with a {{TypeError}}.
1091+
1. Let |bytes| be the result of [=getting a copy of the bytes held by the buffer source=] given |inputData|.
1092+
1. [=Assert=]: |bytes|'s [=byte sequence/length=] is equal to |descriptor|'s [=MLOperandDescriptor/byte length=].
1093+
1. Let |tensor| be the result of [=creating an MLConstantTensor=] given [=this=], and |descriptor|.
1094+
1. Let |promise| be [=a new promise=] in |realm|.
1095+
1. Enqueue the following steps to [=this=].{{MLContext/[[timeline]]}}:
1096+
1. Run these steps, but [=/abort when=] [=this=] [=MLContext/is lost=]:
1097+
1. Create |tensor|.{{MLTensor/[[data]]}} given |descriptor|.
1098+
1. Copy |bytes| to |tensor|.{{MLTensor/[[data]]}}.
10621099
1. If that fails, then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{UnknownError}}" {{DOMException}}, and abort these steps.
10631100
1. Otherwise, [=queue an ML task=] with |global| to [=resolve=] |promise| with |tensor|.
10641101
1. [=/If aborted=], then [=queue an ML task=] with |global| to [=reject=] |promise| with an "{{InvalidStateError}}" {{DOMException}}.
@@ -1627,6 +1664,39 @@ Releases the resources associated with the {{MLTensor}}. This method is idempote
16271664

16281665
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.
16291666

1667+
## {{MLConstantTensor}} interface ## {#api-mlconstanttensor}
1668+
1669+
The {{MLConstantTensor}} interface represents a tensor which may be used as a constant to an {{MLGraph}}. The memory backing an {{MLConstantTensor}} should be allocated in an [=implementation-defined=] fashion according to the requirements of the {{MLContext}} and the {{MLOperandDescriptor}} used to create it. Operations involving the {{MLTensor/[[data]]}} of an {{MLConstantTensor}} occur on the {{MLContext/[[timeline]]}} of its associated {{MLContext}}.
1670+
1671+
The [=implementation-defined=] requirements of how an {{MLConstantTensor}} is allocated may include constraints such as that the memory is allocated with a particular byte alignment or in a particular memory pool.
1672+
1673+
<script type=idl>
1674+
[SecureContext, Exposed=(Window, Worker)]
1675+
interface MLConstantTensor : MLTensor {
1676+
};
1677+
</script>
1678+
1679+
### Creating an {{MLConstantTensor}} ### {#api-mlconstanttensor-create}
1680+
1681+
An {{MLConstantTensor}} is created by its associated {{MLContext}}.
1682+
1683+
<details open algorithm>
1684+
<summary>
1685+
To <dfn>create an MLConstantTensor</dfn> given {{MLContext}} |context|, {{MLOperandDescriptor}} |inputDescriptor|, run the following steps:
1686+
</summary>
1687+
1. Let |realm| be |context|'s [=relevant realm=].
1688+
1. Let |tensor| be a new {{MLConstantTensor}} in |realm|.
1689+
1. Set |tensor|.{{MLTensor/[[context]]}} to |context|.
1690+
1. Let |descriptor| be a new {{MLTensorDescriptor}}.
1691+
1. Set |descriptor|.{{MLTensorDescriptor/readable}} to true.
1692+
1. Set |descriptor|.{{MLTensorDescriptor/writable}} to false.
1693+
1. Set |descriptor|.{{MLOperandDescriptor/dataType}} to |inputDescriptor|.{{MLOperandDescriptor/dataType}}.
1694+
1. Set |descriptor|.{{MLOperandDescriptor/shape}} to |inputDescriptor|.{{MLOperandDescriptor/shape}}.
1695+
1. Set |tensor|.{{MLTensor/[[descriptor]]}} to |descriptor|.
1696+
1. Set |tensor|.{{MLTensor/[[isDestroyed]]}} to false.
1697+
1. Return |tensor|.
1698+
</details>
1699+
16301700
## {{MLGraphBuilder}} interface ## {#api-mlgraphbuilder}
16311701

16321702
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 +1719,9 @@ interface MLGraphBuilder {
16491719
// Create a scalar operand from the specified number of the specified type.
16501720
MLOperand constant(MLOperandDataType type, MLNumber value);
16511721

1722+
// Create an operand from a specified tensor.
1723+
MLOperand constant(MLConstantTensor tensor);
1724+
16521725
// Compile the graph up to the specified output operands asynchronously.
16531726
Promise<MLGraph> build(MLNamedOperands outputs);
16541727
};
@@ -1749,6 +1822,28 @@ Create a constant {{MLOperand}} of the specified data type and shape that contai
17491822
1. Return |operand|.
17501823
</details>
17511824

1825+
#### {{MLGraphBuilder/constant(tensor)}} #### {#api-mlgraphbuilder-constant-tensor}
1826+
Create a constant {{MLOperand}} of the specified data type and shape that contains the initialized data.
1827+
1828+
<div dfn-for="MLGraphBuilder/constant(tensor)" dfn-type=argument>
1829+
**Arguments:**
1830+
- <dfn>tensor</dfn>: an {{MLConstantTensor}}. The tensor containing the initialized data.
1831+
**Returns:** an {{MLOperand}}. The constant output tensor.
1832+
</div>
1833+
1834+
<details open algorithm>
1835+
<summary>
1836+
The <dfn method for=MLGraphBuilder>constant(|tensor|)</dfn> method steps are:
1837+
</summary>
1838+
1. If |tensor|.{{MLTensor/[[context]]}} is not [=this=], then [=exception/throw=] a {{TypeError}}.
1839+
1. If |tensor|.{{MLTensor/[[isDestroyed]]}} is true, then [=exception/throw=] a {{TypeError}}.
1840+
1. If [=this=] [=MLGraphBuilder/can not build=], then [=exception/throw=] an "{{InvalidStateError}}" {{DOMException}}.
1841+
1. *Make graph connections:*
1842+
1. Let |operand| be the result of [=creating an MLOperand=] given [=this=] and |tensor|.{{MLTensor/[[descriptor]]}}.
1843+
1. Add |operand| to [=this=]'s [=MLGraphBuilder/graph=]'s [=computational graph/constants=] with |tensor| as value.
1844+
1. Return |operand|.
1845+
</details>
1846+
17521847
#### {{MLGraphBuilder/constant(type, value)}} #### {#api-mlgraphbuilder-constant-type-value}
17531848
Create a scalar constant {{MLOperand}} of the specified value and data type.
17541849

0 commit comments

Comments
 (0)