Skip to content

Add New Metadata and Pattern Features #2271

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

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

jsmonson
Copy link

@jsmonson jsmonson commented May 5, 2025

This PR will add new metadata and pattern features.

import onnx

from onnxscript import ir
from onnxscript import rewriter

Check notice

Code scanning / CodeQL

Unused import Note

Import of 'rewriter' is not used.
Comment on lines +48 to +49
#else:
# vp_outputs = builder.__getattr__(node.op_type)(*ninputs)

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.

return ReplacementPatternGraph(g)

def get_iterator_index(self):

Check notice

Code scanning / CodeQL

Explicit returns mixed with implicit (fall through) returns Note

Mixing implicit and explicit returns may indicate an error as implicit returns always return None.
# Skip the (all) Activation inputs (have been swapped to beginning of the list)
for index in range(activations, len(nodes[0].inputs)):
inputs = []
producers = []

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable producers is not used.
cinput = LoopBody.function.inputs[index]
noutput = vdisconnect(copy.copy(cinput))
noutput._uses = {}
update_node_outputs = False

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable update_node_outputs is not used.
inputs.add(ninput)
elif any(ninput is init for init in node.graph.initializers):
initializers.add(ninput)
elif ninput.producer() == None:

Check notice

Code scanning / CodeQL

Testing equality to None Note

Testing for None should use the 'is' operator.
@@ -0,0 +1,190 @@
import pytest

Check notice

Code scanning / CodeQL

Unused import Note test

Import of 'pytest' is not used.
import ast

import onnx
from onnxscript import script

Check notice

Code scanning / CodeQL

Unused import Note test

Import of 'script' is not used.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed unused import

Comment on lines +147 to +152
# for rule in tracer.best_matches_map:
# matches = tracer.best_matches_map[rule]
# for match in matches:
# print(f'Reason: {match.match_result.reason}')
# print(f'root_node: {match.root_node}')
# pdb.set_trace()

Check notice

Code scanning / CodeQL

Commented-out code Note test

This comment appears to contain commented-out code.
Comment on lines +166 to +168
# for node in ir.traversal.RecursiveGraphIterator(mypipeline_model.graph):
# if node.domain == '':
# print(node)

Check notice

Code scanning / CodeQL

Commented-out code Note test

This comment appears to contain commented-out code.
Copy link

codecov bot commented May 5, 2025

Codecov Report

Attention: Patch coverage is 6.72131% with 569 lines in your changes missing coverage. Please review.

Project coverage is 61.98%. Comparing base (2f04ea8) to head (2492dca).

Files with missing lines Patch % Lines
onnxscript/rewriter/pattern_builder_jsm.py 1.90% 309 Missing ⚠️
onnxscript/utils/graph_view_utils.py 15.69% 145 Missing ⚠️
onnxscript/utils/test_PytorchHierarchyNode.py 6.50% 115 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2271      +/-   ##
==========================================
- Coverage   70.16%   61.98%   -8.18%     
==========================================
  Files         198      201       +3     
  Lines       24846    25456     +610     
  Branches     2670     2779     +109     
==========================================
- Hits        17432    15779    -1653     
- Misses       6496     8824    +2328     
+ Partials      918      853      -65     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lintrunner found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@justinchuby justinchuby self-assigned this May 5, 2025
else:
return self.class_metadata[depth]

class PytorchHierarchyNode:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is useful! Let me see how we can provide the functionality to users.

Comment on lines +204 to +216
def append_output_to_node(node, output):
output._producer = node
output._index = node.outputs[-1]._index + 1
node._outputs = (*node._outputs, output)
node._num_outputs = len(node._outputs)

def prepend_output_to_node(node, output):
output._producer = node
output._index = 0
for outp in node._outputs:
outp._index += 1
node._outputs = (output, *node._outputs)
node._num_outputs = len(node._outputs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add this to node so there is no need to modify internal states

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact we recommend creating new nodes if you want to update inputs and outputs. This way invariance of the graph is maintained. You may consider accumulating the inputs and outputs into two lists before constructing the node.

Comment on lines +320 to +333
Ident = ir.Node(domain='',
op_type='Identity',
inputs = [cinput],
outputs = [noutput],
num_outputs =1)
LoopBody.function.append(Ident)

#Add Output to Function Call Nodes
for i,node in enumerate(nodes):
output_copy = copy.copy(noutput)

#preserve single_assignment
output_copy.name += f'_{i}'
append_output_to_node(node,output_copy)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to collect all outputs before constructing the node?

vmap[input] = ValuePattern(input.name)

for init in graph.initializers:
vmap[init] = ValuePattern(init.name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you want to map constants and initializers to unconstrained variables in the pattern? I wonder if it would make sense to map them to "Constants" in the pattern that require a matching contstant-value in the graph for a successful match? That makes reasonable, at least for simple and small constants. If it should be abstracted, wouldn't it be better for the user themselves to do that explicitly by mapping them to graph inputs?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Thanks for this suggestion. I think we should do this. This would provide a good level of control for the user.

ninputs.append(vmap[ninput])

#if len(node.outputs) > 1:
vp_outputs = builder.__getattr__(node.op_type)(*ninputs,_domain=node.domain, _outputs=len(node.outputs))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, the attributes of the node are abstracted away, and not matched?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. We ought to match the attributes. I'll make these changes.

node._outputs = (output, *node._outputs)
node._num_outputs = len(node._outputs)

def prepend_input_to_node(node, input):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifying private fields is not recommended. I would consider initializing a new node

golden_results = ort_run_graph(args.filename, input_dict, outputs[0].name)


LoopBody = LoopBodyTemplate(args.patternfilename)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LoopBody = LoopBodyTemplate(args.patternfilename)
loop_body = LoopBodyTemplate(args.patternfilename)

note: always use snake_case for variable names

return [output, used_output]


def bGraphView(name, nodes):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: snake case for function names. Is this build_graph_view?

usage.add("EXTERNAL")
return usage

def find_subgraph_inputs(nodes):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is useful. I wonder if we should put it in ir.convenience https://github.com/onnx/ir-py/blob/main/src/onnx_ir/_convenience/__init__.py

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As well as the one below for outputs and bGraphView

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

3 participants