-
Notifications
You must be signed in to change notification settings - Fork 10
Introduce insert_nodes convenience function #63
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
base: main
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #63 +/- ##
==========================================
+ Coverage 76.74% 76.85% +0.11%
==========================================
Files 40 40
Lines 4816 4852 +36
Branches 952 961 +9
==========================================
+ Hits 3696 3729 +33
- Misses 827 829 +2
- Partials 293 294 +1 ☔ View full report in Codecov by Sentry. |
a81116e
to
7c37020
Compare
7996c44
to
680f2db
Compare
680f2db
to
ec140aa
Compare
out_val.name = val.name | ||
# Propagate relevant info from value to in_value. | ||
# TODO(Rama): Perhaps this should be a separate utility function. | ||
in_val.type = val.type |
Check failure
Code scanning / lintrunner
MYPY/union-attr Error
# Propagate relevant info from value to in_value. | ||
# TODO(Rama): Perhaps this should be a separate utility function. | ||
in_val.type = val.type | ||
in_val.shape = val.shape |
Check failure
Code scanning / lintrunner
MYPY/union-attr Error
in_val.type = val.type | ||
in_val.shape = val.shape | ||
# Rename each value, following each input. | ||
val.name = in_val.name |
Check failure
Code scanning / lintrunner
MYPY/union-attr Error
# 1. Reconnect the users of values to the outputs | ||
replace_all_uses_with(values, outputs) | ||
# 2. Reconnect the users of inputs to values | ||
replace_all_uses_with(inputs, values) |
Check failure
Code scanning / lintrunner
MYPY/arg-type Error
ec140aa
to
f077782
Compare
|
||
|
||
def insert_nodes_in_value( | ||
values: _core.Value | Sequence[_core.Value], new_nodes: Sequence[_core.Node] |
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.
Could you share a use case for this function? I am trying to think what the best api for it should be. Right now the order of appearance of the node inputs implicitly matches the values, which may not be ideal. Also the function name may be improved to be more accurate and succinct.
If we generalize this method, what should an “insert_nodes” api do?
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 thinking in some case that is needed to insert new nodes without remove previous ones. Following: microsoft/onnxscript#2064 discussion, this is not possible to do this with onnxscript.rewriter, since rewrite_pattern have to redefine target_pattern.
Moreover I believe with this helper it is easer to include new nodes with something like
for node in ir_model.graph:
if node.op_type == 'expected_op_type':
insert_node(node.outputs[0], [new_node])
I found this ease to understand/use.
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.
For your other comment (about order), do you have any suggestion ? When len(values) > 1, I though was a good idea to infer the inputs for the list of nodes keeping the order, being needed to change the position of nodes in the list if values need to be re-order.
Maybe it would be enough if it is better specified in the use of the function, right?
I wonder if something like this would make sense: def insert_nodes(values, nodes, incoming_values, outgoing_values) or if the new nodes are connected linearly
(we can constrain that the inputs only be the first node, and the outputs only be produced by the last node so that the intention is clear) |
@justinchuby I was thinking about this suggestion. I think I understand your point, but at the same time I believe it is unnecessary to pass both information (values and nodes). Therefore, how about changing the definition of the function to: def insert_nodes(values, incoming_values, outgoing_values): and then deduce all nodes through something like: nodes = []
new_nodes = ivalue.consumers()
while end_condition(new_nodes, outgoing_values):
nodes.extend(new_nodes)
new_nodes = new_nodes_next_step(new_nodes) Please let me know what do you think. |
Thanks for the reminder - I will need to think about this more carefully once I am done with the thing I am currently working on. I will get back to you hopefully by the end of this week? Your comment makes sense. Are there special consideration needed to ensure node order? (topologically sorted and deterministic). Also we need to ensure there is no loops and the values fully encloses the subgraph? |
Sorry @justinchuby I forget to answer you:
In the same way when there are multiple incoming/outgoing, I think traversing the graph to deduce the nodes would force to sort them indirectly. |
Signed-off-by: Johansmm <[email protected]>
Convenience function to insert a set of nodes in value(s). Signed-off-by: Johansmm <[email protected]>
Signed-off-by: Johansmm <[email protected]>
f077782
to
2e69b61
Compare
Hi @justinchuby, I'm back with this idea (sorry for the delay). I'd like to know how to rethink the tool to make this possible. I just did a push force to rebase in last main and removing |
My apology - This is a very useful feature which we want, but I am not sure when again I will have time to look into it due to my other priorities. I will try to find time when I can. My high level comment is that we would like (1) simple apis (2) efficient runtime and (3) fault tolerant behavior (can raise error if needed, but we should avoid silent errors). Graph traversal would be fine, as long as it is robust |
Convenience function to insert a set of nodes in an ir.Value(s).