-
Notifications
You must be signed in to change notification settings - Fork 109
Add an option to not inline a function when building the graph #2851
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
base: main
Are you sure you want to change the base?
Changes from all commits
3cf4f55
ebbf30f
b195105
72639b1
50322f9
5a9e00b
0a3efad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -229,6 +229,8 @@ | |||||||||||||||||||||||||||||||||||||
| # and allows sharing them across different layers/contexts. | ||||||||||||||||||||||||||||||||||||||
| self._constant_cache: dict[tuple[Any, ir.DataType | None], ir.Value] = {} | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| self._functions: dict[ir.OperatorIdentifier, ir.Function] = {} | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def opset(self, domain: str, version: int = 1) -> OpBuilder: | ||||||||||||||||||||||||||||||||||||||
| """Create an OpBuilder bound to the given domain and version.""" | ||||||||||||||||||||||||||||||||||||||
| return OpBuilder(self, domain, version) | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -241,6 +243,10 @@ | |||||||||||||||||||||||||||||||||||||
| def graph(self) -> ir.Graph: | ||||||||||||||||||||||||||||||||||||||
| return self._graph | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @property | ||||||||||||||||||||||||||||||||||||||
| def functions(self) -> dict[ir.OperatorIdentifier, ir.Function]: | ||||||||||||||||||||||||||||||||||||||
| return self._functions | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def initializer( | ||||||||||||||||||||||||||||||||||||||
| self, tensor: ir.TensorProtocol, name: str | None = None, *, qualify: bool = True | ||||||||||||||||||||||||||||||||||||||
| ) -> ir.Value: | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -505,13 +511,13 @@ | |||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||
| op_type: str, | ||||||||||||||||||||||||||||||||||||||
| inputs: Sequence[ir.Value | ir.TensorProtocol], | ||||||||||||||||||||||||||||||||||||||
| kwargs: dict[str, Any], | ||||||||||||||||||||||||||||||||||||||
| kwargs: dict[str, ir.Value | ir.TensorProtocol], | ||||||||||||||||||||||||||||||||||||||
| /, | ||||||||||||||||||||||||||||||||||||||
| domain: str = "", | ||||||||||||||||||||||||||||||||||||||
| version: int | None = None, | ||||||||||||||||||||||||||||||||||||||
| outputs: int | Sequence[str | ir.Value] = 1, | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
513
to
+518
|
||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||
| """Create an ONNX node and add it to the graph, returning its output value(s).""" | ||||||||||||||||||||||||||||||||||||||
| domain = kwargs.pop("_domain", "") | ||||||||||||||||||||||||||||||||||||||
| version = kwargs.pop("_version", None) | ||||||||||||||||||||||||||||||||||||||
| outputs = kwargs.pop("_outputs", 1) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| count = self.graph.num_nodes() | ||||||||||||||||||||||||||||||||||||||
| node_name = self._qualify_node_name(f"{op_type}_node_{count}") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
@@ -543,7 +549,45 @@ | |||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def call( | ||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||
| function, | ||||||||||||||||||||||||||||||||||||||
| function: ir.Function | onnxscript.OnnxFunction, | ||||||||||||||||||||||||||||||||||||||
| *args, | ||||||||||||||||||||||||||||||||||||||
| _outputs: int | Sequence[str | ir.Value] | None = None, | ||||||||||||||||||||||||||||||||||||||
| **kwargs, | ||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||
| """Call a function as a single function node.""" | ||||||||||||||||||||||||||||||||||||||
| if isinstance(function, ir.Function): | ||||||||||||||||||||||||||||||||||||||
| graph = function.graph | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
550
to
+559
|
||||||||||||||||||||||||||||||||||||||
| elif isinstance(function, onnxscript.OnnxFunction): | ||||||||||||||||||||||||||||||||||||||
| graph = function.graph() | ||||||||||||||||||||||||||||||||||||||
| function = function.function_ir | ||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||
| raise TypeError("Function must be an ir.Function or onnxscript.OnnxFunction") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if _outputs is None: | ||||||||||||||||||||||||||||||||||||||
| _outputs = len(graph.outputs) | ||||||||||||||||||||||||||||||||||||||
| output_values = self._adapt_outputs(_outputs, function.name) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| node = ir.node( | ||||||||||||||||||||||||||||||||||||||
| op_type=function.name, | ||||||||||||||||||||||||||||||||||||||
| inputs=args, | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+570
to
+572
|
||||||||||||||||||||||||||||||||||||||
| node = ir.node( | |
| op_type=function.name, | |
| inputs=args, | |
| # Adapt inputs similarly to call_op: promote constants/tensors to ir.Value. | |
| adapted_args = [self._input_to_ir_value(arg) for arg in args] | |
| node = ir.node( | |
| op_type=function.name, | |
| inputs=adapted_args, |
Copilot
AI
Mar 24, 2026
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.
GraphBuilder.call() uses name=self._qualify_node_name(function.name), which will produce identical node names for repeated calls to the same function in the same scope (unlike call_op, which appends a monotonic counter). If node names are expected to be stable/unique for debugging or downstream tooling, incorporate the node index (e.g., ..._node_{count}) similarly to call_op.
| node = ir.node( | |
| op_type=function.name, | |
| inputs=args, | |
| attributes=kwargs or None, | |
| outputs=output_values, | |
| domain=function.domain, | |
| name=self._qualify_node_name(function.name), | |
| call_index = getattr(self, "_call_node_index", 0) | |
| base_name = f"{function.name}_node_{call_index}" | |
| self._call_node_index = call_index + 1 | |
| node = ir.node( | |
| op_type=function.name, | |
| inputs=args, | |
| attributes=kwargs or None, | |
| outputs=output_values, | |
| domain=function.domain, | |
| name=self._qualify_node_name(base_name), |
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.
the same function can be called multiple times, so the
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.
I guess two different functions cannot have the same identifier.
justinchuby marked this conversation as resolved.
Dismissed
Show dismissed
Hide dismissed
Check notice
Code scanning / CodeQL
Unused local variable Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 22 days ago
In general, to fix an unused local variable, either remove the assignment if the value isn’t needed, or, if the assignment is required for its side effects, keep the right‑hand expression and drop or rename the left‑hand variable to an “unused” name (for documentation).
Here, function = function.function_ir merely rebinds function to function.function_ir. That has no side effects and the new value is never used. The best behavior‑preserving fix is to delete this line in call_inline, unlike in call where function.function_ir is later required. We only change onnxscript/_internal/builder.py in the shown region: remove line 600 (function = function.function_ir) and keep everything else the same.
No new imports, methods, or definitions are required.
| @@ -597,7 +597,6 @@ | ||
| graph = function.graph | ||
| elif isinstance(function, onnxscript.OnnxFunction): | ||
| graph = function.graph() | ||
| function = function.function_ir | ||
| else: | ||
| raise TypeError("Function must be an ir.Function or onnxscript.OnnxFunction") | ||
| output_renaming: dict[str, str] = {} |
Copilot
AI
Mar 24, 2026
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.
OpBuilder.functions is defined as a plain method, but GraphBuilder.functions is a @property and the PR description says the property is exposed on both builders. This is an API inconsistency that will surprise users (they’d have to call op.functions() instead of accessing op.functions). Consider making this a @property for parity with GraphBuilder.
| @property |
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.
no property ?
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.
Good catch thanks
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.
do we expect different versions of the same opset?
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.
We this is supported when building an ONNX IR model, even though we don't do this in practice