Repository navigation
Reconsider MLOperand methods #666
Description
The MLOperand interface looks like:
interface MLOperand {
MLOperandDataType dataType();
sequence<unsigned long> shape();
};Each of these methods meets the criteria for being an attribute (https://w3ctag.github.io/design-principles/#attributes-vs-methods), and are const once the MLOperand is constructed. Is we are to have an accessor on MLOperand for each key in the MLOperandDescriptor which created it, then these should be readonly attributes.
That being said, once we open this can of worms, there are several options we could choose from:
1. Getter which returns an MLOperandDescriptor
interface MLOperand {
- MLOperandDataType dataType();
- sequence<unsigned long> shape();
+ MLOperandDescriptor descriptor();
};This is my preferred option. Unfortunately, JavaScript dictionaries are not read-only so (unless we want to push to introduce FrozenDictionary) we should use a getter.
2. Naive conversion to readonly attribute
interface MLOperand {
- MLOperandDataType dataType();
+ readonly attribute MLOperandDataType dataType;
- sequence<unsigned long> shape();
+ readonly attribute sequence<unsigned long> shape;
};Seems reasonable. But why have an attribute called shape which refers to the same thing as MLOperandDescriptor.dimensions?
3. Rename shape to dimensions, or vice versa
dictionary MLOperandDescriptor {
required MLOperandDataType dataType;
- sequence<[EnforceRange] unsigned long> dimensions = [];
+ sequence<[EnforceRange] unsigned long> shape = [];
};
interface MLOperand {
- MLOperandDataType dataType();
+ readonly attribute MLOperandDataType dataType;
- sequence<unsigned long> shape();
+ readonly attribute sequence<unsigned long> shape;
};MLOperandDescriptor takes a dimensions field, while querying this field from an MLOperand is done with the shape() method. As per https://w3ctag.github.io/design-principles/#attribute-reuse, we should re-use terms rather than unnecessarily introducing new vocabulary.
A quick CTRL-F of the spec text shows:
- 139 instances of "dimensions", mostly due to
MLOperandDescriptor.dimensions - 483 instances of "shape", which seems to be used more commonly in prose (e.g. "the shape of the input tensor")
We should decide to use one or the other (and possibly continue this discussion on another issue regardless)
4. Make MLOperandDescriptor an interface
-dictionary MLOperandDescriptor {
+interface MLOperandDescriptor {
required MLOperandDataType dataType;
sequence<[EnforceRange] unsigned long> dimensions = [];
};
interface MLOperand {
- MLOperandDataType dataType();
- sequence<unsigned long> shape();
+ readonly attribute MLOperandDescriptor descriptor;
};This is my least favorite, but I figured I'd list this here for completeness.
Activity
zolkis commentedon Apr 30, 2024
m2c: 3(2|1)
(3 applied to 2 or 1) :)
a-sully commentedon Apr 30, 2024
I agree that we should do (3) regardless. Filed #669 to track that
Also filed #670 to track making
MLOperandDescriptor.dimensionsfrozen. We should do this anyways, but especially if we're providing a getter that returns anMLOperandDescriptorthen it would be nice if the array was frozen!Given those expected improvements, my preference is (1)
inexorabletash commentedon Jul 30, 2024
Re: (2) - sequences are disallowed as the type of an attribute: https://webidl.spec.whatwg.org/#idl-sequence
... which is a shame as a method does seem like overkill.
fdwr commentedon Aug 28, 2024
Doh, as a fan of internal consistency in API's, I should have originally proposed
dimensions()here for consistency 🤦♂️.interface MLOperand { MLOperandDataType dataType(); - sequence<unsigned long> shape(); + sequence<unsigned long> dimensions(); }Options:
(a) Change helper
MLOperand::shape()->MLOperand::dimensions()(b) Change field
MLOperandDesc::dimensions->MLOperandDesc::shapePros/Cons
(a) Change helper
MLOperand::shape()->MLOperand::dimensions()MLOperandDesc::dimensions.dims, ANNdimensions, DMLdimensionCountandsizes, MPSMPSNDArraySizes, CudNNCUDNN_ATTR_TENSOR_DIMENSIONS, OneDNNdnnl_dims_t.dimensionsmeans a list of explicit sizes - we speak of the paper dimensions 8x11 and dresser dimensions 45x20x14 ("a measurable extent of some kind, such as length, breadth, depth, or height ... the final dimensions of the pond were 14 ft. x 8 ft").shape()has limited scope.cats, it could either be a list cats (std::vector<Cats> cats) or a count of cats (uint32_t cats), and you can't tell from the field name alone.sions).(b) Change field
MLOperandDesc::dimensions->MLOperandDesc::shapeMLOperand::shape.sions).MLGraphBuilder::reshape()(though arguably that should have been namedresize).So it really doesn't look like
shapeis a clear win, but rather a toss-up, and semantically it remains dubious, even if a few other ML frameworks made such questionable naming decisions in the past. Also consider how we are going to define the word "shape" in the spec - it will literally be "a shape is a list of dimensions" 😉.fdwr commentedon Aug 28, 2024
p.s. Let's also be consistent in...
a-sully commentedon Sep 9, 2024
Hmm I'm still inclined to prefer
shapeoverdimensionsfor the following reasons:"dimensions" is ambiguous, since it can mean "some number of dimensions" (e.g. "the last two dimensions") or "shape" (e.g.
[3, 4]). Consider this paragraph from the description of Broadcasting (emphasis mine):Which definition of "dimensions" is being used here? Should the more precise term "ranks" be used here (if it's the former definition)? Or is this referring to "tensors of other shapes" (the latter)?
shapeis widely used by other ML frameworksMLMultiArrayshape()operatorI agree, which is why I think we should make this change while WebNN is still experimental :)
a-sully commentedon Sep 10, 2024
I forgot I'd filed a separate issue about this! Please feel free to respond on #669 :)
Regardless of what we name that field, at this point I'm quite convinced we should convert the getter methods on
MLOperandto readonly attributes, in line with theMLTensorinterface currently implemented in Chromium and proposed in #754interface MLOperand { - MLOperandDataType dataType(); + readonly attribute MLOperandDataType dataType; - sequence<unsigned long> shape(); + readonly attribute FrozenArray<unsigned long> shape; };fdwr commentedon Sep 17, 2024
@a-sully I'm not opposed to that (fewer parentheses to type), but what of Anssi's comment here? #670 (comment)
a-sully commentedon Sep 17, 2024
In this case we're using
FrozenArrayas areadonly attribute, so that's not relevant here. It would have potentially been relevant to this option:fdwr commentedon Oct 29, 2024
@a-sully: Do you consider
MLOperandDescriptorsufficiently complete, now that the struct looks like:https://www.w3.org/TR/webnn/#api-mloperanddescriptor
a-sully commentedon Oct 29, 2024
I'm now happy with
MLOperandDescriptor👍As I mentioned in #666 (comment), I still think the
MLOperandinterface needs to change:webnn: Deprecate MLOperand members in favor of readonly attributes
webnn: Deprecate MLOperand members in favor of readonly attributes
webnn: Deprecate MLOperand members in favor of readonly attributes
Bug 1928001 [wpt PR 48877] - webnn: Deprecate MLOperand members in fa…
Bug 1928001 [wpt PR 48877] - webnn: Deprecate MLOperand members in fa…
Bug 1928001 [wpt PR 48877] - webnn: Deprecate MLOperand members in fa…
Bug 1928001 [wpt PR 48877] - webnn: Deprecate MLOperand members in fa…
Bug 1928001 [wpt PR 48877] - webnn: Deprecate MLOperand members in fa…
Bug 1928001 [wpt PR 48877] - webnn: Deprecate MLOperand members in fa…