Skip to content

Support common subexpression elimination pass (CSE) #2304

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

Merged
merged 23 commits into from
May 30, 2025

Conversation

titaiwangms
Copy link
Contributor

@titaiwangms titaiwangms commented May 13, 2025

Fix #2105

For the logic, this PR follows https://github.com/pytorch/pytorch/blob/main/torch/fx/passes/dialect/common/cse_pass.py.

Essentially, this PR traverses the original graph and examines whether the values or the nodes are duplicated. If it's not, the value or the node is saved in mappings, and added to the new graph. If it is duplicated, the value or the node is replaced with the mapped/saved value or node. (FunctionalPass)

CSE subgraph is not supported: #2345.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a common subexpression elimination (CSE) pass for ONNX graphs, updates the model serialization API to use metadata_props, and includes tests for the new pass.

  • Rename meta_data_props parameter to metadata_props in model constructors and deserialization.
  • Implement CommonSubexpressionEliminationPass in common_subexpression_elimination.py.
  • Add unit tests for the CSE pass in common_subexpression_elimination_test.py.

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
onnxscript/ir/serde.py Renamed meta_data_props to metadata_props
onnxscript/ir/_core.py Updated constructor parameter name to metadata_props
onnxscript/ir/passes/common/common_subexpression_elimination.py Added CSE functional pass implementation
onnxscript/ir/passes/common/common_subexpression_elimination_test.py Added tests covering CSE behavior
Comments suppressed due to low confidence (1)

onnxscript/ir/passes/common/common_subexpression_elimination.py:45

  • [nitpick] Variable name input shadows the built-in input() function. Consider renaming to graph_input or similar for clarity.
        for input in old_graph.inputs:

Copy link

codecov bot commented May 13, 2025

Codecov Report

Attention: Patch coverage is 76.63043% with 43 lines in your changes missing coverage. Please review.

Project coverage is 70.16%. Comparing base (143c531) to head (9fd8948).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...es/common/common_subexpression_elimination_test.py 69.40% 41 Missing ⚠️
.../passes/common/common_subexpression_elimination.py 95.91% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2304      +/-   ##
==========================================
+ Coverage   70.11%   70.16%   +0.04%     
==========================================
  Files         196      198       +2     
  Lines       24662    24846     +184     
  Branches     2656     2670      +14     
==========================================
+ Hits        17292    17433     +141     
- Misses       6453     6495      +42     
- Partials      917      918       +1     

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

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@xadupre
Copy link
Member

xadupre commented May 14, 2025

I don't know what the best is, but: what about changing inplace the node input (if two results are the same, then the second one can be replaced inplace with the first one). And then add a pass to remove the unused nodes.

@titaiwangms titaiwangms marked this pull request as ready for review May 16, 2025 21:52
@titaiwangms
Copy link
Contributor Author

Changed to inplace pass. Subgraph is not yet tackled.

@justinchuby
Copy link
Collaborator

I think it is ok to leave subgraphs untouched.

@justinchuby
Copy link
Collaborator

justinchuby commented May 29, 2025

Also: once the PR is done feel free to create one in onnx/ir-py to include the same logic. We can release 0.1 then.

It would be better to move the PR to https://github.com/onnx/ir-py at this point, after all tests passing

@titaiwangms
Copy link
Contributor Author

Also: once the PR is done feel free to create one in onnx/ir-py to include the same logic. We can release 0.1 then.

It would be better to move the PR to https://github.com/onnx/ir-py at this point, after all tests passing

Optimizer seems still using the current repo passes.

@justinchuby justinchuby modified the milestones: 0.3, 0.3.1 May 29, 2025
@justinchuby
Copy link
Collaborator

Also: once the PR is done feel free to create one in onnx/ir-py to include the same logic. We can release 0.1 then.

It would be better to move the PR to onnx/ir-py at this point, after all tests passing

Optimizer seems still using the current repo passes.

Hopefully fixed by #2324, but let me know if not

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.

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

@titaiwangms
Copy link
Contributor Author

Now I have to land the PR in onnx-ir first.

@titaiwangms titaiwangms merged commit 2f04ea8 into microsoft:main May 30, 2025
27 of 32 checks passed
for idx, graph_output in enumerate(graph.outputs):
if graph_output in replacement_mapping:
new_value = replacement_mapping[graph_output]
if new_value.is_graph_output():
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can't rename it if is a graph input also. We could change this condition to new_value.is_graph_output() or new_value.is_graph_input() ... I think it won't show up in CSE, but will be necessary if we move this as an IR utility used in other scenarios.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a kind of case that we would cse graph inputs? In this PR, it's deleting nodes and affecting their outputs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see what you mean

Copy link
Contributor Author

@titaiwangms titaiwangms May 30, 2025

Choose a reason for hiding this comment

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

I will add that in onnx/ir-py#36

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gramalingam I don't see how new_value here could be graph_input. It has to be from a node output. Does that sound right?

justinchuby added a commit to onnx/ir-py that referenced this pull request Jun 2, 2025
CSE pass from microsoft/onnxscript#2304

---------

Signed-off-by: Ti-Tai Wang <titaiwang@microsoft.com>
Signed-off-by: Justin Chu <justinchuby@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Justin Chu <justinchuby@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
bmehta001 pushed a commit to bmehta001/onnxscript that referenced this pull request Jun 5, 2025
Fix microsoft#2105 

For the logic, this PR follows
https://github.com/pytorch/pytorch/blob/main/torch/fx/passes/dialect/common/cse_pass.py.

Essentially, this PR traverses the original graph and examines whether
the values or the nodes are duplicated. If it's not, the value or the
node is saved in mappings, and added to the new graph. If it is
duplicated, the value or the node is replaced with the mapped/saved
value or node. (FunctionalPass)

CSE subgraph is not supported:
microsoft#2345.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
bmehta001 pushed a commit to bmehta001/onnxscript that referenced this pull request Jun 5, 2025
Fix microsoft#2105 

For the logic, this PR follows
https://github.com/pytorch/pytorch/blob/main/torch/fx/passes/dialect/common/cse_pass.py.

Essentially, this PR traverses the original graph and examines whether
the values or the nodes are duplicated. If it's not, the value or the
node is saved in mappings, and added to the new graph. If it is
duplicated, the value or the node is replaced with the mapped/saved
value or node. (FunctionalPass)

CSE subgraph is not supported:
microsoft#2345.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

CSE pass
4 participants