Repository navigation
[16/17] DLA public integration and reshape cleanup #2968
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
Draft
mgohil-png
wants to merge
13
commits into
dla/review-15-dla-topk-and-dtype-compatibility
from
dla/review-16-dla-public-integration-and-reshape-cleanup
+1,500
−1
Draft
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
c7bc775
[DLA_transforms_16] [16/17] DLA public integration and reshape cleanup
mgohil-png 675a166
Declare deferred output ranks in public rewrite fixtures
mgohil-png f14020c
Retain native rank views and runtime controls in final reshape cleanup
mgohil-png ed1d609
Document DLA finite-input and integration test contracts
mgohil-png 8c2eb2d
Collapse fixed legacy reshape chains with declared controls
mgohil-png ed30392
Verify native Gemm fallback in integration safety checks
mgohil-png cbf1dd9
Assert DLA reshape cleanup allocates distinct node names
mgohil-png 6a7c181
Preserve initializer input contracts during final DLA cleanup
mgohil-png 64ae770
Declare deferred rank stages in rewrite safety checks
mgohil-png 4d1cb90
Collapse interleaved reshape chains by data producer
mgohil-png 1a12926
Preserve existing targets when bypassing interleaved identity reshapes
mgohil-png 0d59938
Remove redundant mock-only dispatcher coverage
mgohil-png 1bad017
Clarify DLA entry points and signed-zero conversion contract
mgohil-png 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
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
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
123 changes: 123 additions & 0 deletions
123
modelopt/onnx/graph_surgery/dla_transforms/dla_remove_reshapes.py
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,123 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Collapse reshape chains at the final, inferred stage of the DLA pipeline.""" | ||
|
|
||
| from itertools import pairwise | ||
|
|
||
| import numpy as np | ||
| from onnx import TensorProto, helper | ||
|
|
||
| from ..utils.graph_utils import GraphCache, add_initializer, batch_replace_nodes | ||
| from .dla_constants_to_initializers import _add_legacy_initializer_inputs | ||
| from .dla_graph_cleanup import _subgraph_captures | ||
| from .dla_indexing import _operator_nodes | ||
| from .dla_rank_conversion import _runtime_input_names | ||
|
|
||
| __all__ = [] | ||
|
|
||
|
|
||
| def _apply_remove_reshapes(model): | ||
| """Collapse fixed reshape chains while retaining rank-sensitive consumers and runtime controls.""" | ||
| graph = model.graph | ||
| cache = GraphCache(graph) | ||
| runtime_inputs = _runtime_input_names(model) | ||
| reshapes = _operator_nodes(model, {"Reshape"}) | ||
| captured = _subgraph_captures(graph) | ||
| positions = {id(node): index for index, node in enumerate(reshapes)} | ||
| chains, tails = [], {} | ||
| for node in reshapes: | ||
| producer = cache.get_producer(node.input[0]) | ||
| chain = tails.pop(id(producer), None) | ||
| if chain is None: | ||
| chain = [] | ||
| chains.append(chain) | ||
| chain.append(node) | ||
| consumers = cache.get_consumers(node.output[0]) | ||
| if ( | ||
| node.output[0] not in cache.graph_output_names | captured | ||
| and len(consumers) == 1 | ||
| and consumers[0][1] == 0 | ||
| ): | ||
| tails[id(node)] = chain | ||
| replacements = {} | ||
| for chain in chains: | ||
| first, last = chain[0], chain[-1] | ||
| if any( | ||
| node.input[1] not in cache.init_names or node.input[1] in runtime_inputs | ||
| for node in chain | ||
| ): | ||
| continue | ||
| input_shape = cache.get_shape(first.input[0]) | ||
| output_shape = cache.get_shape(last.output[0]) | ||
| if ( | ||
| not input_shape | ||
| or not output_shape | ||
| or any(d <= 0 for d in [*input_shape, *output_shape]) | ||
| ): | ||
| continue | ||
| removable = input_shape == output_shape | ||
| if removable and last.output[0] not in cache.graph_output_names | captured: | ||
| for consumer, port in cache.get_consumers(last.output[0]): | ||
| consumer.input[port] = first.input[0] | ||
| elif input_shape == output_shape: | ||
| replacements[id(last)] = [ | ||
| helper.make_node( | ||
| "Identity", | ||
| [first.input[0]], | ||
| list(last.output), | ||
| name=cache.unique_name((last.name or last.output[0]) + "_identity"), | ||
| domain=last.domain, | ||
| ) | ||
| ] | ||
| elif len(chain) > 1: | ||
| if all(cache.get_shape(node.output[0]) == input_shape for node in chain[:-1]) and any( | ||
| positions[id(right)] != positions[id(left)] + 1 for left, right in pairwise(chain) | ||
| ): | ||
| # Interleaved identity prefixes need only bypassing; retain the existing target and attributes. | ||
| last.input[0] = first.input[0] | ||
| for node in chain[:-1]: | ||
| replacements[id(node)] = [] | ||
| continue | ||
| target = add_initializer( | ||
| graph, | ||
| cache.unique_name(last.name + "_reshape_shape"), | ||
| np.asarray(output_shape, dtype=np.int64), | ||
| dtype=TensorProto.INT64, | ||
| with_value_info=False, | ||
| ) | ||
| replacements[id(last)] = [ | ||
| helper.make_node( | ||
| "Reshape", | ||
| [first.input[0], target], | ||
| list(last.output), | ||
| name=cache.unique_name((last.name or last.output[0]) + "_reshape"), | ||
| domain=last.domain, | ||
| ) | ||
| ] | ||
| else: | ||
| continue | ||
| for node in chain: | ||
| replacements.setdefault(id(node), []) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| batch_replace_nodes( | ||
| graph, | ||
| { | ||
| index: ([node], replacements[id(node)]) | ||
| for index, node in enumerate(graph.node) | ||
| if id(node) in replacements | ||
| }, | ||
| ) | ||
| _add_legacy_initializer_inputs(model) | ||
| return model | ||
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.
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.
Script executed:
Repository: NVIDIA/Model-Optimizer
Length of output: 2121
Script executed:
Repository: NVIDIA/Model-Optimizer
Length of output: 10128
Call the legacy initializer helper in the Reshape-collapse path.
_apply_remove_reshapesadds a new INT64 initializer on the collapse branch. It never calls_add_legacy_initializer_inputs, which every other DLA transform calls after it changes initializers. The pipeline's finalonnx.checker.check_modelruns with no later call to the helper. For a model withir_version <= 3, the checker can reject the collapsed graph because the new initializer is not also a graph input. Call the helper once afterbatch_replace_nodes, and import it fromdla_constants_to_initializers.Proposed fix
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.
Cleanup now uses the existing runtime-input classification and registers generated controls with
_add_legacy_initializer_inputs. Previously, valid IR3 initializer declarations caused the chain to be skipped; the new regression verifies an actual collapse followed by full ONNX checking and exact CPU output. Modern overridable controls remain native. Both legacy/modern cases pass, including the new generated-target declaration.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.
🧩 Analysis chain
🏁 Script executed:
Length of output: 23800
🏁 Script executed:
Length of output: 19364
@mgohil-pngVerified the fix by code inspection. Cleanup now uses_runtime_input_namesand calls_add_legacy_initializer_inputsafter graph replacement.The regression requires an actual IR3 collapse and retains both Reshape nodes for IR9 overridable controls. It also performs full ONNX checking and exact CPU output comparison. I did not run the tests.
This addresses the finding. Repository policy leaves thread resolution to the reviewer.
You are interacting with an AI system.