-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Annotation based partitioning along with resource accounting #27595
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
Changes from all commits
Commits
Show all changes
63 commits
Select commit
Hold shift + click to select a range
18b5d2b
Introduce annotation query function
yuslepukhin 1eeba1a
Wire annotations to partitioning interface.
yuslepukhin debc8dd
Fix up annotations with Transpose Optimizer
yuslepukhin 8f0ff86
Add ORT_EXTENDED_MINIMAL build
yuslepukhin f7a422e
Move rules and matcher inside the index
yuslepukhin 1ef4078
Add Update with tests
yuslepukhin 828eca3
TODO: Consider not removing annotations
yuslepukhin 1626d5c
Clear annotations after partitioning
yuslepukhin f33bab1
Merge branch 'main' into yuslepukhin/layering
yuslepukhin b3ecb39
Address accountant bug
yuslepukhin b5ea1c6
Annotate tiny_gpt2_beamsearch by layers
yuslepukhin 9a422ba
Refactor Graph_GetGraphView to make it a utility
yuslepukhin a1caf93
Introduce a graph utility to create an IndexedSubgraph
yuslepukhin e1b1c4f
Merge branch 'main' into yuslepukhin/layering
yuslepukhin acec402
Fix lint in python script.
yuslepukhin 31dd7a8
Merge branch 'main' into yuslepukhin/layering
yuslepukhin 9fa4849
Merge branch 'main' into yuslepukhin/layering
yuslepukhin 50c58c9
Merge branch 'main' into yuslepukhin/layering
yuslepukhin e445b60
Fix build errors and address Copilt comments
yuslepukhin 358f7df
Reject duplicate rules
yuslepukhin 653fb8b
Move methods to .cc
yuslepukhin 23a8ecf
Remove code duplication
yuslepukhin ef1227e
Add missing include
yuslepukhin b0b2396
Fix matching bug
yuslepukhin b9e13cf
Change index parsing
yuslepukhin add0227
Remove wrong comment
yuslepukhin 17e3525
Address minimal build issues
yuslepukhin 1b1a7db
Fix unused arg
yuslepukhin 88c2c47
Add logging
yuslepukhin 9b0b529
Make sure the annotation is copied on node copy
yuslepukhin dab76bc
Adjust error message
yuslepukhin b39a487
Copy Annotations when copying nodes and inlining functions
yuslepukhin 4e260bc
Update LayeringIndex after function inlining
yuslepukhin 5214350
Add intermediate buffers accounting + temp coefficient
yuslepukhin 3fb1d1e
Merge branch 'main' into yuslepukhin/layering
yuslepukhin cd73b56
Address MakeNodeUnassigned feedback
yuslepukhin dfe4d13
Address InlineNodes feedback
yuslepukhin 62f3d11
Fix underaccounting for shared weights in fused nodes
yuslepukhin 3cab988
Update onnxruntime/python/tools/layering/layer_annotate.py
yuslepukhin e6cb75f
Lint
yuslepukhin b2ef9a2
Flip = prefix to exact match
yuslepukhin fde6300
Adjust comments for duplicate annotations
yuslepukhin 7871afa
Remove bad comment
yuslepukhin 16ec921
Adjust EpWithNoLayeringRulesSeesAllUnassignedNodes
yuslepukhin 4da5c3b
Throw on multiple annotations
yuslepukhin 01e4506
Make sure annotations are propagated on function inlining
yuslepukhin 3e52f14
Update include/onnxruntime/core/session/onnxruntime_session_options_c…
yuslepukhin 24a46e8
Update onnxruntime/core/framework/graph_partitioner.cc
yuslepukhin e745e02
Update onnxruntime/core/graph/graph_utils.h
yuslepukhin 59b5ccd
Fix issues in python
yuslepukhin 054f894
Address undercounting problem
yuslepukhin 09967c3
Add copyright header
yuslepukhin d23ee08
Update onnxruntime/core/framework/graph_partitioner.cc
yuslepukhin 9e8be7a
Adjust doc and implementaton for fetching layering ann
yuslepukhin f636138
Make GetContainingGraph public
yuslepukhin fcda524
Adjust accounting for fused node and remove stray local var
yuslepukhin 2da1394
Address flaky test
yuslepukhin c0c5e51
Update onnxruntime/core/providers/cuda/cuda_execution_provider.cc
yuslepukhin c55bb6e
Update onnxruntime/core/graph/graph_utils.cc
yuslepukhin cdd9faa
Address review issues
yuslepukhin 67a947b
Fix potential perf issue
yuslepukhin 44c6904
Address review comments
yuslepukhin 927a0ef
Add documentation for ann and ep propagation. Fix L1 optimizers, add …
yuslepukhin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| # Optimizer Layering Annotations | ||
|
|
||
| ## Overview | ||
|
|
||
| Layering annotations are per-node metadata strings that guide graph partitioning by indicating which execution provider (EP) layer a node belongs to. They are loaded from the ONNX model's `NodeProto` metadata (key `"layer_ann"`) and consumed during the partitioning phase to influence EP assignment. | ||
|
|
||
| ## Execution Pipeline | ||
|
|
||
| Graph optimizers run in ordered levels: | ||
|
|
||
| ``` | ||
| Level 0 (Basic) ─► Level 1 (Extended) ─► Partitioning ─► Level 2+ (Layout, etc.) | ||
| ``` | ||
|
|
||
| 1. **Level 0 and Level 1** optimizers run **before** partitioning. At this point, layering annotations are present on nodes and must be preserved through any graph transformations. | ||
| 2. **Partitioning** reads the annotations to assign nodes to execution providers. | ||
| 3. After partitioning, `Graph::RemoveAllLayeringAnnotations()` clears all annotations. | ||
| 4. **Level 2, 3, and 4** optimizers run **after** annotations have been cleared. They do not need to handle annotations. | ||
|
|
||
| **Key rule: Only Level 1 (and Level 0) optimizers need to propagate layering annotations.** | ||
|
|
||
| ## Why Propagation Matters | ||
|
|
||
| When an optimizer replaces, fuses, or decomposes nodes, the original annotated node is removed and new nodes are created. If the new nodes do not carry the original annotation, partitioning loses the assignment hint for that subgraph, potentially causing incorrect EP placement. | ||
|
|
||
| ## How to Propagate Annotations | ||
|
|
||
| ### Preferred: Use the `AddNode` Overload with `annotation_source` | ||
|
|
||
| `Graph::AddNode` provides overloads that accept a `const Node& annotation_source` parameter. The new node automatically inherits the layering annotation from the source node. | ||
|
|
||
| ```cpp | ||
| // Instead of: | ||
| Node& new_node = graph.AddNode(name, op_type, description, inputs, outputs); | ||
| // Missing annotation propagation! | ||
|
|
||
| // Use: | ||
| Node& new_node = graph.AddNode(name, op_type, description, inputs, outputs, | ||
| original_node); // annotation_source | ||
| ``` | ||
|
|
||
| All standard `AddNode` signatures have a corresponding `annotation_source` variant: | ||
|
|
||
| ```cpp | ||
| // With const NodeAttributes* | ||
| Node& AddNode(name, op_type, description, | ||
| gsl::span<NodeArg* const> inputs, | ||
| gsl::span<NodeArg* const> outputs, | ||
| const Node& annotation_source, | ||
| const NodeAttributes* attributes = nullptr, | ||
| const std::string& domain = kOnnxDomain); | ||
|
|
||
| // With NodeAttributes&& | ||
| Node& AddNode(name, op_type, description, | ||
| gsl::span<NodeArg* const> inputs, | ||
| gsl::span<NodeArg* const> outputs, | ||
| const Node& annotation_source, | ||
| NodeAttributes&& attributes, | ||
| const std::string& domain = kOnnxDomain); | ||
|
|
||
| // initializer_list variants also available | ||
| ``` | ||
|
|
||
| ### Legacy: `DuplicateNodeAnnotation` | ||
|
|
||
| The utility function `optimizer_utils::DuplicateNodeAnnotation(src, dst)` copies annotations between existing nodes. This is still used when the annotation source is conditional (e.g., when the source node pointer may be null). Prefer the `AddNode` overload for unconditional propagation. | ||
|
|
||
| ### Automatic Propagation | ||
|
|
||
| `Graph::AddNode(const Node& other)` — the copy overload used for duplicating nodes — automatically copies annotations. No additional action is needed when duplicating a node via this overload. | ||
|
|
||
| ## Post-Partitioning: Propagating EP Assignments | ||
|
|
||
| Although Level 2+ optimizers do not deal with layering annotations directly (they have been cleared), they must still propagate **execution provider (EP) assignments**. EP assignments are the downstream result of the annotation-driven partitioning step. After partitioning, each node carries an EP assignment (e.g., `CUDAExecutionProvider`, `CPUExecutionProvider`) that determines where the node's kernel runs. | ||
|
|
||
| When a Level 2+ optimizer creates new nodes that replace or derive from existing ones, it must copy the EP assignment from the source node: | ||
|
|
||
| ```cpp | ||
| Node& new_node = graph.AddNode(name, op_type, description, inputs, outputs); | ||
| new_node.SetExecutionProviderType(original_node.GetExecutionProviderType()); | ||
| ``` | ||
|
|
||
| Failing to propagate the EP assignment causes the new node to fall back to the default provider (typically CPU), silently breaking the intended placement and potentially degrading performance or correctness. This requirement predates the layering annotation feature and applies to all optimizers that run after partitioning. | ||
|
|
||
| > **Note:** The `AddNode` overload with `annotation_source` propagates both the layering annotation *and* nothing else — EP assignment is still set separately. Layering annotations and EP assignments serve different stages of the pipeline and are managed independently. | ||
|
|
||
| ## When You Do NOT Need to Propagate Annotations | ||
|
|
||
| - **Level 2+ optimizers** — annotations have already been consumed and cleared (but EP assignments must still be propagated, see above). | ||
| - **Training optimizers** — training runs after partitioning. | ||
| - **Optimizers that only remove nodes** (e.g., identity elimination) — no new nodes are created. | ||
| - **Optimizers that modify nodes in-place** — the annotation remains on the existing node. | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Fusion (replacing multiple nodes with one) | ||
|
|
||
| ```cpp | ||
| // GeluFusion: fusing Div + Erf + Add + Mul + Mul into a single Gelu | ||
| Node& gelu_node = graph.AddNode( | ||
| graph.GenerateNodeName("Gelu"), | ||
| "Gelu", "fused Gelu subgraphs", | ||
| {gelu_input}, {gelu_output}, | ||
| div_node); // propagate annotation from the root matched node | ||
| ``` | ||
|
|
||
| ### Decomposition (replacing one node with many) | ||
|
|
||
| ```cpp | ||
| // STFT decomposition: each new node inherits from the original STFT node | ||
| auto [reshape_node, reshape_out] = AddNode(graph, "Reshape", ep, inputs, &stft); | ||
| auto [conv_node, conv_out] = AddNode(graph, "Conv", ep, conv_inputs, &stft); | ||
| auto [concat_node, concat_out] = AddNode(graph, "Concat", ep, concat_inputs, &stft); | ||
| ``` | ||
|
|
||
| ### Conditional source (use DuplicateNodeAnnotation) | ||
|
|
||
| ```cpp | ||
| Node& q_node = graph.AddNode(...); | ||
| if (src_node) { | ||
| optimizer_utils::DuplicateNodeAnnotation(*src_node, q_node); | ||
| } | ||
| ``` | ||
|
|
||
| ## Checklist for New Level 1 Optimizers | ||
|
|
||
| 1. Identify the "source" node whose annotation should propagate (typically the root of the matched pattern). | ||
| 2. For every `graph.AddNode(...)` call that creates a replacement node, use the `annotation_source` overload. | ||
| 3. If the source is conditional (may be null), use `optimizer_utils::DuplicateNodeAnnotation` after the `AddNode` call. | ||
| 4. Test with an annotated model to verify annotations survive the transformation. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.