Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/onnxruntime/core/graph/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -1843,6 +1843,12 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi
std::unordered_map<std::string_view, NodeIndex> node_name_to_index;
std::unordered_set<Node*> nodes_with_subgraphs;

// Subgraphs that already had type/shape inferencing performed during this Resolve pass via the
// containing op's inference function (e.g. Scan/If/Loop). The "verify subgraphs" loop in
// VerifyNodeAndOpMatch uses this to avoid redundantly re-verifying the same subgraph, which
// would otherwise cause exponential re-traversal of deeply nested subgraphs.
std::unordered_set<const Graph*> inferred_subgraphs;

// check if the provided name is an input/initialize/node output of this Graph instance during Graph::Resolve.
// Graph::node_args_ can have stale entries so we can't rely on that.
bool IsLocalValue(const std::string& name) const;
Expand All @@ -1856,6 +1862,7 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi
inputs_and_initializers.clear();
node_name_to_index.clear();
nodes_with_subgraphs.clear();
inferred_subgraphs.clear();
}

private:
Expand Down
19 changes: 18 additions & 1 deletion onnxruntime/core/graph/graph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ using namespace ::onnxruntime::common;
namespace onnxruntime {

#if !defined(ORT_MINIMAL_BUILD)

#define NO_CHANGE_ON_SYNC_FLAG(...) \
do { \
const bool sync_needed = GraphProtoSyncNeeded(); \
Expand Down Expand Up @@ -3179,6 +3180,15 @@ Status Graph::InferAndVerifySubgraphTypes(const Node& node, Graph& subgraph,
status = subgraph.PerformTypeAndShapeInferencing(options);
ORT_RETURN_IF_ERROR(status);

// Record that this subgraph had type/shape inferencing (and thus node/op verification via
// VerifyNodeAndOpMatch) performed here through the containing op's inference function
// (Scan/If/Loop and similar). The parent's "verify subgraphs" loop uses this to skip a redundant
// VerifyNodeAndOpMatch on the same subgraph, avoiding exponential re-traversal of deeply nested
// subgraphs.
if (subgraph.parent_graph_ != nullptr) {
subgraph.parent_graph_->resolve_context_.inferred_subgraphs.insert(&subgraph);
}

auto& subgraph_outputs = subgraph.GetOutputs();
for (const auto* output : subgraph_outputs) {
output_types.push_back(output->TypeAsProto());
Expand Down Expand Up @@ -3672,7 +3682,14 @@ Status Graph::VerifyNodeAndOpMatch(const ResolveOptions& options) {
}
}

ORT_RETURN_IF_ERROR(subgraph->VerifyNodeAndOpMatch(options));
// Skip verification if this subgraph already had type/shape inferencing (and node/op
// verification) performed via the containing op's inference function (e.g. Scan/If/Loop).
// This avoids exponential re-traversal of deeply nested subgraphs. Ops whose inference
// function does not descend into subgraphs (e.g. BeamSearch) are not recorded, so their
// subgraphs are still verified here.
if (resolve_context_.inferred_subgraphs.count(subgraph) == 0) {
ORT_RETURN_IF_ERROR(subgraph->VerifyNodeAndOpMatch(options));
}
Comment thread
skottmckay marked this conversation as resolved.
}
}

Expand Down
Loading