-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the clamp() algorithm #348
Conversation
During the call today, @huningxin you made a remark that an MLActivation is not needed when an MLOperator is returned. To me it seems it was needed in the impl, also for the step of connecting the op input/output. But welcome to suggest better steps here, thanks! |
We have a single algorithm for clamp() in JS, and we distinguish for the return values based on the arguments provided to the function. So the two impl need to be combined there. Of course in cpp the implementation can be polymorphic. AFAIK we cannot have 2 separate algorithms mirroring a cpp implementation. We need to figure out what we want in JS, and then implement in cpp. As this is the same case with almost every other function in the API, we need to get this right. |
Also, I will need to update #337 with internal constructors for MLOperand and MLActivation as needed in the steps of the clamp() algorithm. I think it's better to add those commits to that PR, not this one. |
I modified the algorithm like they would be when #337 is merged. This shows how the |
I am preparing the PR for input() and constant(), and that changes this PR, too. Moving it back to WiP. |
index.bs
Outdated
The {{MLGraphBuilder/clamp()}} method steps are: | ||
1. Let |arg1| be the first argument. | ||
1. If |arg1| is an instance of {{MLOperand}}, run the {{MLGraphBuilder/clamp(operand, options)}} steps with all the received arguments. | ||
1. Otherwise, run the {{MLGraphBuilder/clamp(options)}} steps with all received arguments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@huningxin : in general, for polymorphic functions, do we prefer adding these boilerplate lines, or just define the two forms separately?
index.bs
Outdated
<div class="note"> | ||
This step does not execute the clamp operation yet, it just prepares the operator. | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this note is needed because the same statement can also be made for all the other graph builder methods that add a given operation into the graph i.e. nothing is executed yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed it would be better to state that once for all the ops and remove the repetitive notes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
@wchao1115 concern addressed, PTAL. |
@huningxin @wchao1115 PTAL: squashed to one commit. |
Squashed from the following commits: Replace MLOperand.[[descriptor]] with type and dimensions Clarify the algorithm for only setting up the op Improve the clamp() algorithm, use the prose assuming the create steps for MLOperand and MLActivation Rework clamp with polymorphic behavior. Update for changes in MLOperand. Rework clamp() like constant(), polymorphic forms in separate sections, argument and return descriptions as notes. Fix platform related steps and reference to internal slots Address review, remove note Remove back quotes from title Signed-off-by: Zoltan Kis <[email protected]>
Signed-off-by: Zoltan Kis <[email protected]>
1. Set |activation|.{{MLActivation/[[builder]]}} to |builder|. | ||
1. Set |activation|.{{MLActivation/[[name]]}} to |name|. | ||
1. If |options| is an [=object=], set |activation|.{{MLActivation/[[options]]}} to |options|. | ||
1. Make a request to the underlying platform to bind the [=implementation-defined=] platform operator for |name| to |activation|.{{MLActivation/[[operator]]}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we leave the platform operator creation to each build method? Because I suppose the creation steps would be different, e.g. handling of options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Let's start with that assumption. We can always cleanly factor out common things when the opportunity comes.
1. If |operand| is not an instance of {{MLOperand}}, then throw a "{{TypeError}}" and stop. | ||
1. Let |result| be a new [=object=]. | ||
1. Set |result|.{{MLOperand/[[builder]]}} to |operand|.{{MLOperand/[[builder]]}}. | ||
1. Set |result|.{{MLOperand/[[descriptor]]}} to |operand|.{{MLOperand/[[descriptor]]}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we do deep copy of the descriptor? Would the change of original operand's descriptor impact the copied one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All internal slots should be immutable, i.e. only changeable with API calls, so assignments to internal slots should involve deep copies by default. I will check this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ECMAScript doesn't really shed light on this. Internal slots are supposed to be created and then not modified unless specified differently.
Now we seem to have 2 options:
- change every line that sets an internal slot to replace
the argument
with "a copy ofthe argument
" - or, create steps to "set the internal slot
[[name]]
to<arg>
" steps, where we say "set[[name]]
to a copy of<arg>
".
@anssiko @dontcallmedom any input here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@huningxin
Since this is a general issue for the spec, could we create an issue and fix it outside this PR, in all affected places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine to fix it in a separate issue. Please create that issue and add link into the spec. Thanks.
index.bs
Outdated
1. If running the <a>check clamp options</a> steps with |options| returns `false`, then throw a "{{TypeError}}" {{DOMException}} and abort these steps. | ||
1. Let |result| be the result of invoking the <a>copy MLOperand</a> steps given |operand|. | ||
1. If that throws an error, re-throw the error and abort these steps. | ||
1. Make a request to the underlying platform to connect |result| with the [=implementation-defined=] platform operator for clamp, and store a reference to the resulting [=implementation-defined=] platform operand object in |result|.{{MLOperand/[[operand]]}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose there are a few sub-steps:
- Make a request to the underlying platform to create an [=implementation-defined=] platform operator for clamp with |options|.{{MLClampOptions/minValue}} and |options|.{{MLClampOptions/minValue}}.
- Register the |operand|.{{MLOperand/[[operand]]}} as input to the platform operator for clamp.
- Register the |result|.{{MLOperand/[[operand]]}} as output to the platform operator for clamp.
- Store a reference to the platform operator for clamp in |result|.{{MLOperand/[[operator]]}}.
index.bs
Outdated
1. If running the <a>check clamp options</a> steps with |options| returns `false`, then throw a "{{TypeError}}" {{DOMException}} and abort these steps. | ||
1. Let |op| be the result of invoking the <a>create MLActivation</a> steps with `"clamp"` and |options|. | ||
1. If that throws an error, re-throw the error and abort these steps. | ||
1. Make a request to the underlying platform to connect |op| with the [=implementation-defined=] platform operator for clamp, and store a reference to the resulting [=implementation-defined=] platform operator object in |op|.{{MLActivation/[[operator]]}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we can leverage the steps of {{MLGraphBuilder/clamp(operand, options)}} method. The difference is here it doesn't need register input and output operand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for activation and let's try its own steps. Let's keep track if we could reuse these operand and activation platform-related steps in other methods and how to parametrize them. If there is an opportunity, we can factor them out later.
index.bs
Outdated
1. Let |result| be a new [=object=]. | ||
1. Set |result|.{{MLOperand/[[builder]]}} to |operand|.{{MLOperand/[[builder]]}}. | ||
1. Set |result|.{{MLOperand/[[descriptor]]}} to |operand|.{{MLOperand/[[descriptor]]}}. | ||
1. Set |result|.{{MLOperand/[[name]]}} to |operand|.{{MLOperand/[[name]]}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{{MLOperand/[[name]]}} is only valid for input operand, it should not be copied if the destination operand is not an input.
- an {{MLOperand}}. The output tensor of the same shape as *operand*. | ||
</div> | ||
<div algorithm=clamp> | ||
The {{MLGraphBuilder/clamp(operand, options)}} method steps are: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
operand
is commonly used, e.g. for MLOperand or platform operand etc. Should the variable name be more specific, like input
or x
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, so that was the reason for using x
. Well, input
is also a loaded name :).
Since it is an MLOperand, I think using operand
is just fine.
Signed-off-by: Zoltan Kis <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a follow-up for "deep-copy" issue.
1. If |operand| is not an instance of {{MLOperand}}, then throw a "{{TypeError}}" and stop. | ||
1. Let |result| be a new [=object=]. | ||
1. Set |result|.{{MLOperand/[[builder]]}} to |operand|.{{MLOperand/[[builder]]}}. | ||
1. Set |result|.{{MLOperand/[[descriptor]]}} to |operand|.{{MLOperand/[[descriptor]]}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine to fix it in a separate issue. Please create that issue and add link into the spec. Thanks.
Moved to #399 with new target branch. |
Add the clamp algorithm. Tracked in #347 (discussion there).
Depends on #336.
Preview | Diff