diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d6397b993a0..757215cd2e3 100755 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -192,6 +192,7 @@ Changelog **Bug Fixes** +- Fix corrupted ONNX external tensor data when exporting models on Windows by upgrading ONNX. Regenerate affected models from clean weights. - Fix ``import modelopt.torch`` failing with ``ModuleNotFoundError`` for ``requests`` or ``huggingface_hub`` when ``nvidia-modelopt`` is installed without the ``[hf]`` extra. - Harden the distributed object broadcast/allgather helpers and the Megatron expert-parallel export gather so a compromised peer rank can no longer execute code through a crafted pickle payload: payloads load with ``weights_only=True`` and the export gathers raw bytes instead of pickled objects. - Fix LSQ clamping small, representable FP8 block scales too aggressively, which could zero quantized values and suppress scale gradients. diff --git a/docs/source/getting_started/windows/_installation_windows_arm64.rst b/docs/source/getting_started/windows/_installation_windows_arm64.rst index 2bafcf0be4e..e50f039a303 100644 --- a/docs/source/getting_started/windows/_installation_windows_arm64.rst +++ b/docs/source/getting_started/windows/_installation_windows_arm64.rst @@ -101,7 +101,7 @@ explicit dependency installation avoids selecting the Windows x64 ``onnxruntime- & $PythonExe -m pip install ` cppimport cupy-cuda13x lief ml_dtypes ` - "onnx~=1.21.0" "onnx-graphsurgeon>=0.6.1" ` + "onnx~=1.23.2" "onnx-graphsurgeon>=0.6.1" ` "onnxconverter-common~=1.16.0" onnxscript ` "onnxslim>=0.1.76" "polygraphy>=0.49.22" ` "onnxruntime>=1.24.2" onnxruntime-ep-nv-tensorrt-rtx-cu13 diff --git a/pyproject.toml b/pyproject.toml index e585e7fb378..140e08d5ae0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,8 @@ onnx = [ "lief", "ml_dtypes", "onnx-graphsurgeon>=0.6.1", - "onnx~=1.21.0", + "onnx~=1.21.0; platform_system != 'Windows'", + "onnx~=1.23.2; platform_system == 'Windows'", "onnxconverter-common~=1.16.0", # Python 3.10 support for ModelOpt ONNX is deprecated and will be removed in a future release. # Native Windows ARM64 does not support ModelOpt ONNX on Python 3.10. diff --git a/tests/unit/onnx/test_external_data.py b/tests/unit/onnx/test_external_data.py new file mode 100644 index 00000000000..ddb77e997f8 --- /dev/null +++ b/tests/unit/onnx/test_external_data.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import onnx +import pytest + +from modelopt.onnx.utils import save_onnx + + +@pytest.mark.parametrize("last_byte", [0x00, 0x0A, 0x1A]) +def test_save_external_data_preserves_tensor_boundaries(tmp_path, last_byte): + # Windows text-mode file opening can truncate a trailing Ctrl-Z before append. + first = np.full(1024, 0x41, dtype=np.uint8) + first[-1] = last_byte + second = np.full(1024, 0x42, dtype=np.uint8) + tensors = [ + onnx.numpy_helper.from_array(value, name) + for name, value in [("first", first), ("second", second)] + ] + graph = onnx.helper.make_graph([], "external_data", [], [], initializer=tensors) + model = onnx.helper.make_model(graph) + path = tmp_path / "model.onnx" + + save_onnx(model, str(path), save_as_external_data=True) + + assert (tmp_path / "model.onnx_data").read_bytes() == first.tobytes() + second.tobytes() + restored = onnx.load(path) + for actual, expected in zip(restored.graph.initializer, [first, second], strict=True): + np.testing.assert_array_equal(onnx.numpy_helper.to_array(actual), expected)