From 89077a23dec3af7aec274ccd458d24dab2ccbe31 Mon Sep 17 00:00:00 2001 From: laudney <106273+laudney@users.noreply.github.com> Date: Mon, 2 Nov 2026 10:59:27 +0000 Subject: [PATCH 1/8] feat(nemotron_parse): add checkpoint and image preparation Nemotron 3.5 Parse needs its own family before any device work, so this validates the Parse config graph and every stored tensor of the checkpoint, and ports its image processor with the same resize, white padding, normalization and patch order. A host test checks the processor against independent Pillow and NumPy fingerprints that the new nemotron_parse_reference.py processor subcommand prints, and the script keeps NVIDIA's OpenMDW notice with its license under LICENSES. --- LICENSES/NVIDIA-OpenMDW-1.1.txt | 57 +++++ build.zig | 1 + tools/zig/nemotron_parse_reference.py | 63 ++++++ zig/build/nemotron_parse.zig | 22 ++ .../families/nemotron_parse/checkpoint.zig | 42 ++++ zig/src/families/nemotron_parse/config.zig | 131 +++++++++++ .../nemotron_parse/fixtures/processor.json | 85 +++++++ zig/src/families/nemotron_parse/host_test.zig | 207 ++++++++++++++++++ zig/src/families/nemotron_parse/processor.zig | 100 +++++++++ zig/src/families/nemotron_parse/root.zig | 6 + zig/src/families/nemotron_parse/schema.zig | 89 ++++++++ 11 files changed, 803 insertions(+) create mode 100644 LICENSES/NVIDIA-OpenMDW-1.1.txt create mode 100644 tools/zig/nemotron_parse_reference.py create mode 100644 zig/build/nemotron_parse.zig create mode 100644 zig/src/families/nemotron_parse/checkpoint.zig create mode 100644 zig/src/families/nemotron_parse/config.zig create mode 100644 zig/src/families/nemotron_parse/fixtures/processor.json create mode 100644 zig/src/families/nemotron_parse/host_test.zig create mode 100644 zig/src/families/nemotron_parse/processor.zig create mode 100644 zig/src/families/nemotron_parse/root.zig create mode 100644 zig/src/families/nemotron_parse/schema.zig diff --git a/LICENSES/NVIDIA-OpenMDW-1.1.txt b/LICENSES/NVIDIA-OpenMDW-1.1.txt new file mode 100644 index 0000000000..3618e26f59 --- /dev/null +++ b/LICENSES/NVIDIA-OpenMDW-1.1.txt @@ -0,0 +1,57 @@ +Unless separately indicated, the model weights and NVIDIA-provided source code +and documentation are licensed under the OpenMDW-1.1 License. +The tokenizer included with this model is separately licensed under the +MIT license. See TOKENIZER_ATTRIBUTION.md for the license text, +original copyright notice, source, and NVIDIA modification history. + +------------ +Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + + +OpenMDW License Agreement, version 1.1 (OpenMDW-1.1) + +By exercising rights granted to you under this agreement, you accept and agree +to its terms. + +As used in this agreement, "Model Materials" means the materials provided to +you under this agreement, consisting of: (1) one or more machine learning +models (including architecture and parameters); and (2) all related artifacts +(including associated data, documentation and software) that are provided to +you hereunder. + +Subject to your compliance with this agreement, permission is hereby granted, +free of charge, to deal in the Model Materials without restriction, including +under all copyright, patent, database, and trade secret rights included or +embodied therein. + +If you distribute any portion of the Model Materials, you shall retain in your +distribution (1) a copy of this agreement, and (2) all copyright notices and +other notices of origin included in the Model Materials that are applicable to +your distribution. +If you file, maintain, or voluntarily participate in a lawsuit against any +person or entity asserting that the Model Materials directly or indirectly +infringe any patent or copyright, then all rights and grants made to you +hereunder are terminated, unless that lawsuit was in response to a +corresponding lawsuit first brought against you. + +This agreement does not impose any restrictions or obligations with respect to +any use, modification, or sharing of any outputs generated by using the Model +Materials. + +THE MODEL MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE, NONINFRINGEMENT, ACCURACY, OR THE +ABSENCE OF LATENT OR OTHER DEFECTS OR ERRORS, WHETHER OR NOT DISCOVERABLE, ALL +TO THE GREATEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW. + +YOU ARE SOLELY RESPONSIBLE FOR (1) CLEARING RIGHTS OF OTHER PERSONS THAT MAY +APPLY TO THE MODEL MATERIALS OR ANY USE THEREOF, INCLUDING WITHOUT LIMITATION +ANY PERSON'S COPYRIGHTS OR OTHER RIGHTS INCLUDED OR EMBODIED IN THE MODEL +MATERIALS; (2) OBTAINING ANY NECESSARY CONSENTS, PERMISSIONS OR OTHER RIGHTS +REQUIRED FOR ANY USE OF THE MODEL MATERIALS; OR (3) PERFORMING ANY DUE +DILIGENCE OR UNDERTAKING ANY OTHER INVESTIGATIONS INTO THE MODEL MATERIALS OR +ANYTHING INCORPORATED OR EMBODIED THEREIN. +IN NO EVENT SHALL THE PROVIDERS OF THE MODEL MATERIALS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MODEL MATERIALS, THE +USE THEREOF OR OTHER DEALINGS THEREIN. diff --git a/build.zig b/build.zig index e78cd0bbcb..6f47553a25 100644 --- a/build.zig +++ b/build.zig @@ -191,6 +191,7 @@ pub fn build(b: *std.Build) void { const with_hip = b.option(bool, "hip", "Enable the opt-in HIP backend and its host/device targets") orelse false; const hip_options = hip_build.options(b); // declared on every target (#1165), used only with -Dhip=true hip_build.loaderTests(b, test_step); + @import("zig/build/nemotron_parse.zig").hostTests(b, test_step); if (with_hip) hip_build.steps(b, target, optimize, build_options, test_step, hip_options); const with_vulkan = b.option(bool, "vulkan", "Enable the opt-in Vulkan backend and its host/device targets") orelse false; const vulkan_options = vulkan_build.options(b); // declared on every target, used only with -Dvulkan=true diff --git a/tools/zig/nemotron_parse_reference.py b/tools/zig/nemotron_parse_reference.py new file mode 100644 index 0000000000..34a3e8df82 --- /dev/null +++ b/tools/zig/nemotron_parse_reference.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +# SPDX-License-Identifier: OpenMDW-1.1 + +"""Offline Nemotron Parse references for native tests: HF example, positions, processor fingerprints, compare.""" + +import argparse +import hashlib +import json + +REVISION = '4035ffb1d8f8bafcdb867dfaf6f7514f101464f9' + + +# Formulas of nvidia/Nemotron-3.5-Parse@4035ffb1d8f8bafcdb867dfaf6f7514f101464f9 processor; no native code. +PROCESSOR_CASES = [(1, 1), (17, 65), (31, 129), (113, 97), (2049, 101), (99, 2001), (2201, 1777), (2048, 1664)] + + +def processor_case(np, Image, height, width): + mean = np.array([0.48145466, 0.4578275, 0.40821073], dtype=np.float32) + std = np.array([0.26862954, 0.26130258, 0.27577711], dtype=np.float32) + y, x, ch = np.indices((height, width, 3), dtype=np.uint32) + rgb = ((y * 17 + x * 29 + ch * 83) % 256).astype(np.uint8) + ratio = width / height + h, w = height, width + if h > 2048: + h = 2048 + w = int(h * ratio) + if w > 1664: + w = 1664 + h = int(w / ratio) + image = Image.fromarray(rgb) + if (h, w) != (height, width): + image = image.resize((w, h), Image.Resampling.BILINEAR) + content = np.array(image) + padded = np.pad(content, ((0, -h % 16), (0, -w % 64), (0, 0)), constant_values=255) + # ToTensor divides float32 by 255; Normalize uses two separate float32 operations. + normalized = (padded.astype(np.float32) / np.float32(255.0) - mean) / std + ph, pw = padded.shape[:2] + patches = normalized.reshape(ph // 16, 16, pw // 16, 16, 3).transpose(0, 2, 4, 1, 3) + data = patches.astype('