diff --git a/tools/onnx-graphsurgeon/CHANGELOG.md b/tools/onnx-graphsurgeon/CHANGELOG.md index 3d18b72d0..117af7fa8 100644 --- a/tools/onnx-graphsurgeon/CHANGELOG.md +++ b/tools/onnx-graphsurgeon/CHANGELOG.md @@ -3,6 +3,14 @@ Dates are in YYYY-MM-DD format. +## vNext + +### Fixed +- Fixed `Graph.fold_constants()` lowering `Constant` nodes specified with `value_float` or + `value_floats` into float64 (`DOUBLE`) constants. ONNX defines these attributes as float32, + and the folded constants now match, producing models that ONNX Runtime accepts. + + ## v0.6.2 (2026-05-21) ### Added diff --git a/tools/onnx-graphsurgeon/onnx_graphsurgeon/ir/graph.py b/tools/onnx-graphsurgeon/onnx_graphsurgeon/ir/graph.py index c7ce3b6ff..81609328f 100644 --- a/tools/onnx-graphsurgeon/onnx_graphsurgeon/ir/graph.py +++ b/tools/onnx-graphsurgeon/onnx_graphsurgeon/ir/graph.py @@ -823,6 +823,9 @@ def should_exclude_node(node): continue elif isinstance(attr_val, Constant): arr = attr_val._values # Using ._values avoids copying + elif attr_name in ("value_float", "value_floats"): + # ONNX defines these attributes as float32 + arr = np.array(attr_val, dtype=np.float32) else: arr = np.array(attr_val) tensor.to_constant(arr) diff --git a/tools/onnx-graphsurgeon/tests/ir/test_graph.py b/tools/onnx-graphsurgeon/tests/ir/test_graph.py index 47ed2a2ef..3d8b0dc32 100644 --- a/tools/onnx-graphsurgeon/tests/ir/test_graph.py +++ b/tools/onnx-graphsurgeon/tests/ir/test_graph.py @@ -1360,6 +1360,30 @@ def test_with_invalid_nodes(self, foldable_with_invalid_node): tensor_map["c"].values == (np.ones(shape=(1, 3), dtype=np.float32) * 2) ) + @pytest.mark.parametrize( + "attrs", + [{"value_float": 1.5}, {"value_floats": [1.5, 2.5]}], + ) + def test_value_float_attrs_fold_as_float32(self, attrs): + # ONNX defines value_float and value_floats as float32 attributes. + graph = Graph(ir_version=10) + inp = Variable("input", shape=(2,), dtype=np.float32) + const_out = Variable("c") + graph.nodes.append(Node(op="Constant", attrs=attrs, outputs=[const_out])) + out = graph.add(inp, const_out, name="out") + graph.inputs = [inp] + graph.outputs = [out] + + graph.fold_constants().cleanup() + + assert len(graph.nodes) == 1 + folded = graph.nodes[0].inputs[1] + attr_name = "value_float" if "value_float" in attrs else "value_floats" + expected = np.array(attrs[attr_name], dtype=np.float32) + assert folded.dtype == np.float32 + assert folded.values.shape == expected.shape + assert np.array_equal(folded.values, expected) + def test_with_invalid_nodes_no_recursive(self, foldable_with_invalid_node): # No folding should take place without recursive partitioning original = foldable_with_invalid_node.copy()