Skip to content

Commit 2aae7d4

Browse files
justinchubyCopilot
andauthored
Update the graph initializers dictionary when renaming Value (#197)
This pull request enhances the handling of value renaming within the ONNX IR core: When a value (especially an initializer) is renamed, all relevant references—including the graph's initializer dictionary—are consistently updated. This reduces the risk of stale or inconsistent state when manipulating graph initializers. Key changes: **Core logic improvements:** * The `Value` class now ensures that renaming a value also updates the corresponding entry in the graph's `initializers` dictionary, maintaining consistency between the value's name and its registration in the graph. An error is raised if an initializer's name is set to `None`. * The `__init__` method docstring for `Value` has been updated to document this new behavior, clarifying that renaming a value also updates the graph initializer entry if applicable. **Code simplification:** * In `naming.py`, redundant logic for manually updating the `initializers` dictionary after a value rename has been removed, since this is now handled automatically by the `Value` class. This makes the code cleaner and less error-prone. --------- Signed-off-by: Justin Chu <justinchuby@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 3f6eecf commit 2aae7d4

File tree

3 files changed

+127
-7
lines changed

3 files changed

+127
-7
lines changed

src/onnx_ir/_core.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,6 +2031,14 @@ def __init__(
20312031
) -> None:
20322032
"""Initialize a value.
20332033
2034+
When assigning a name to the value, the name of the backing `const_value` (Tensor)
2035+
will also be updated. If the value is an initializer of a graph, the initializers
2036+
dictionary of the graph will also be updated.
2037+
2038+
.. versionchanged:: 0.1.10
2039+
Assigning a name to the value will also update the graph initializer entry
2040+
if the value is an initializer of a graph.
2041+
20342042
Args:
20352043
producer: The node that produces the value.
20362044
It can be ``None`` when the value is initialized first than its producer.
@@ -2179,7 +2187,23 @@ def name(self) -> str | None:
21792187
def name(self, value: str | None) -> None:
21802188
if self._const_value is not None:
21812189
self._const_value.name = value
2190+
old_name = self._name
21822191
self._name = value
2192+
if self.is_initializer():
2193+
if value is None:
2194+
raise ValueError(
2195+
"Initializer value cannot have name set to None. Please pop() the value from initializers first"
2196+
)
2197+
# Rename the initializer entry in the graph
2198+
graph = self._graph
2199+
assert graph is not None
2200+
assert old_name is not None
2201+
if value in graph.initializers and graph.initializers[value] is not self:
2202+
raise ValueError(
2203+
f"Cannot rename initializer to '{value}': an initializer with that name already exists."
2204+
)
2205+
graph.initializers.pop(old_name)
2206+
graph.initializers[value] = self
21832207

21842208
@property
21852209
def type(self) -> _protocols.TypeProtocol | None:

src/onnx_ir/_core_test.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,108 @@ def test_consumers(self):
779779
self.assertEqual(self.node.outputs[0].consumers(), ())
780780
self.assertEqual(self.node.outputs[1].consumers(), ())
781781

782+
def test_name_setter_updates_const_value_name(self):
783+
"""Test that setting a Value's name also updates the const_value's name if it exists."""
784+
tensor = ir.tensor([1, 2, 3], name="original_tensor_name")
785+
value = _core.Value(name="original_value_name", const_value=tensor)
786+
787+
# Verify initial state
788+
self.assertEqual(value.name, "original_value_name")
789+
self.assertEqual(value.const_value.name, "original_tensor_name")
790+
791+
# Update the value's name and verify const_value name is also updated
792+
value.name = "new_name"
793+
self.assertEqual(value.name, "new_name")
794+
self.assertEqual(value.const_value.name, "new_name")
795+
796+
# Test setting name to None
797+
value.name = None
798+
self.assertIsNone(value.name)
799+
self.assertIsNone(value.const_value.name)
800+
801+
def test_name_setter_without_const_value(self):
802+
"""Test that setting a Value's name works normally when no const_value exists."""
803+
value = _core.Value(name="original_name")
804+
805+
# Verify initial state
806+
self.assertEqual(value.name, "original_name")
807+
self.assertIsNone(value.const_value)
808+
809+
# Update the name
810+
value.name = "new_name"
811+
self.assertEqual(value.name, "new_name")
812+
813+
# Set to None
814+
value.name = None
815+
self.assertIsNone(value.name)
816+
817+
def test_initializer_name_setter_raises_when_set_to_none(self):
818+
"""Test that setting an initializer value's name to None raises ValueError."""
819+
tensor = ir.tensor([1, 2, 3])
820+
value = _core.Value(name="initializer1", const_value=tensor)
821+
_core.Graph(inputs=(), outputs=(), nodes=(), initializers=[value])
822+
823+
# Verify the value is an initializer
824+
self.assertTrue(value.is_initializer())
825+
826+
# Attempt to set name to None should raise ValueError
827+
with self.assertRaisesRegex(
828+
ValueError,
829+
"Initializer value cannot have name set to None. Please pop\\(\\) the value from initializers first",
830+
):
831+
value.name = None
832+
833+
def test_initializer_name_setter_updates_graph_initializers_dict(self):
834+
"""Test that renaming an initializer value updates the graph's initializers dictionary."""
835+
tensor = ir.tensor([1, 2, 3])
836+
value = _core.Value(name="old_name", const_value=tensor)
837+
graph = _core.Graph(inputs=(), outputs=(), nodes=(), initializers=[value])
838+
839+
# Verify initial state
840+
self.assertTrue(value.is_initializer())
841+
self.assertIn("old_name", graph.initializers)
842+
self.assertIs(graph.initializers["old_name"], value)
843+
self.assertEqual(value.name, "old_name")
844+
845+
# Rename the value and verify the graph's initializers dict is updated
846+
value.name = "new_name"
847+
848+
# Old key should be removed, new key should be added
849+
self.assertNotIn("old_name", graph.initializers)
850+
self.assertIn("new_name", graph.initializers)
851+
self.assertIs(graph.initializers["new_name"], value)
852+
self.assertEqual(value.name, "new_name")
853+
self.assertEqual(value.const_value.name, "new_name")
854+
855+
def test_non_initializer_name_setter_works_normally(self):
856+
"""Test that name changes work normally for values that are not initializers."""
857+
# Test regular value (not part of any graph)
858+
tensor = ir.tensor([1, 2, 3])
859+
value = _core.Value(name="original_name", const_value=tensor)
860+
861+
self.assertFalse(value.is_initializer())
862+
863+
# Should be able to change name without issues
864+
value.name = "new_name"
865+
self.assertEqual(value.name, "new_name")
866+
self.assertEqual(value.const_value.name, "new_name")
867+
868+
# Should be able to set to None without issues
869+
value.name = None
870+
self.assertIsNone(value.name)
871+
self.assertIsNone(value.const_value.name)
872+
873+
# Test graph input
874+
input_value = _core.Value(name="input1")
875+
_core.Graph(inputs=[input_value], outputs=(), nodes=())
876+
877+
self.assertTrue(input_value.is_graph_input())
878+
self.assertFalse(input_value.is_initializer())
879+
880+
# Should be able to rename input without issues
881+
input_value.name = "renamed_input"
882+
self.assertEqual(input_value.name, "renamed_input")
883+
782884
# TODO(justinchuby): Test all methods
783885

784886

src/onnx_ir/passes/common/naming.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,8 @@ def _process_value(
193193
if not value.name:
194194
modified = self._assign_value_name(value, used_value_names, value_counter)
195195
else:
196-
old_name = value.name
197196
modified = self._fix_duplicate_value_name(value, used_value_names, value_counter)
198-
if modified:
199-
assert value.graph is not None
200-
if value.is_initializer():
201-
value.graph.initializers.pop(old_name)
202-
# Add the initializer back with the new name
203-
value.graph.initializers.add(value)
197+
# initializers dictionary is updated automatically when the Value is renamed
204198

205199
# Record the final name for this value
206200
assert value.name is not None

0 commit comments

Comments
 (0)