Skip to content

Commit dc52443

Browse files
gramalingamCopilot
andcommitted
feat: store all initializers in root graph, not just cached constants
Extend the root-graph invariant to the initializer() method itself, not just the cached literal path in _get_or_create_constant(). Now every call to builder.initializer() registers the value in self._root._graph, ensuring that direct initializer creation from sub-builders also goes to the root graph. This maintains a clean invariant: all initializers live in the root graph, regardless of which builder created them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: G Ramalingam <grama@microsoft.com>
1 parent be51b98 commit dc52443

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

onnxscript/_internal/builder.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,14 @@ def graph(self) -> ir.Graph:
318318
def initializer(
319319
self, tensor: ir.TensorProtocol, name: str | None = None, *, qualify: bool = True
320320
) -> ir.Value:
321-
"""Register a tensor as a graph initializer, returning the corresponding ir.Value."""
321+
"""Register a tensor as a graph initializer in the **root** graph.
322+
323+
All initializers are stored in the root graph so that inner scopes
324+
(subgraphs) can reference them via ONNX's outer-scope visibility
325+
rules. For function bodies (which cannot have initializers), apply
326+
:func:`lift_initializers_to_constants` before wrapping in
327+
:class:`ir.Function`.
328+
"""
322329
if name is None:
323330
name = tensor.name
324331
if qualify:
@@ -327,7 +334,7 @@ def initializer(
327334
value = ir.Value(
328335
name=name, shape=shape, type=ir.TensorType(tensor.dtype), const_value=tensor
329336
)
330-
self._graph.register_initializer(value)
337+
self._root._graph.register_initializer(value)
331338
return value
332339

333340
def input(

onnxscript/_internal/builder_test.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,29 @@ def body2(op, x):
15041504
const_names = [n for n in root_graph.initializers if "const_2.0" in n]
15051505
self.assertEqual(len(const_names), 1, f"Expected 1 shared initializer: {const_names}")
15061506

1507+
def test_direct_initializer_in_subgraph_goes_to_root(self):
1508+
"""builder.initializer() called on a sub-builder registers in root graph."""
1509+
import numpy as np
1510+
1511+
root_graph = ir.Graph(
1512+
name="main",
1513+
inputs=[],
1514+
outputs=[],
1515+
nodes=[],
1516+
opset_imports={"": _default_opset_version},
1517+
)
1518+
root_builder = builder.GraphBuilder(root_graph)
1519+
1520+
def body(op, x):
1521+
tensor = ir.Tensor(np.array([1.0, 2.0], dtype=np.float32))
1522+
bias = op.builder.initializer(tensor, name="my_bias")
1523+
return op.Add(x, bias)
1524+
1525+
sub = root_builder.subgraph(body, inputs=[FLOAT[3]], outputs=[FLOAT[3]])
1526+
# Initializer should be in root, not subgraph
1527+
self.assertIn("my_bias", root_graph.initializers)
1528+
self.assertEqual(len(sub.initializers), 0)
1529+
15071530
def test_lift_initializers_to_constants_converts_all(self):
15081531
"""lift_initializers_to_constants replaces initializers with Constant nodes."""
15091532
graph = ir.Graph(

0 commit comments

Comments
 (0)