Skip to content

Add NVIDIA Nemotron Parse 2.0 support - #473

Open
justinchuby wants to merge 3 commits into
mainfrom
justinchuby-add-nemotron-parse
Open

Add NVIDIA Nemotron Parse 2.0 support#473
justinchuby wants to merge 3 commits into
mainfrom
justinchuby-add-nemotron-parse

Conversation

@justinchuby

@justinchuby justinchuby commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

Add end-to-end support for nvidia/NVIDIA-Nemotron-Parse-2.0 (model_type: nemotron_parse) as a two-model image-to-text package.

Architecture

  • C-RADIOv2-H vision backbone: linear patch projection emitted as Conv, cropped CPE positions, eight register/teacher tokens, 32 ViT-H blocks, and three flattened teacher summaries.
  • Nemotron feature neck: 1280→1024 projection, horizontal 1×4 convolutional compression, summary-token projection, and LayerNorms.
  • Position-free scaled-embedding mBART decoder: 10 pre-norm self/cross-attention layers, causal self KV cache, exact GELU FFN, tied LM head.
  • Standardized package keys: vision_encoder and decoder.
  • Vision graph accepts the official processor's float32 pixels and casts internally for f16/bf16 weights.
  • Config/registry/task wiring, Conv2d asymmetric kernels, CLI/runtime guard, real document fixture, L1-L5 tests, and committed real-image goldens.

Validation

GPU: NVIDIA RTX A1000, 8188 MiB, driver 573.44. CUDA runs explicitly requested CUDAExecutionProvider; sessions reported ['CUDAExecutionProvider', 'CPUExecutionProvider'] (CPU is retained for ORT shape operations).

Gate Exact result
L1 graph 4 passed, 1350 deselected in 8.74s
Weight alignment 1 passed, 226 deselected in 8.80s
L2 YAML schema 237 passed in 1.94s
L3 synthetic fp32 parity 1 passed, 203 deselected in 7.43s at rtol=atol=1e-3 (ONNX vision output fed to ONNX decoder)
Real-image BF16 HF/ONNX CUDA parity 1 passed, 122 deselected in 71.49s (74.683s wall); encoder cosine >0.99, logits cosine >0.995, identical argmax
L4 + deterministic L5 CUDA 2 passed, 377 deselected in 103.13s (106.441s wall); real nonzero image, exact L4 top-1 and exact 24-token L5 golden
Regression suite 3638 passed, 57 skipped in 47.45s
Lint initialized lintrunner; lintrunner -a: ok No lint issues
Automated review final code-review agent: no significant issues

CUDA CLI and dtype matrix

All three exports used mobius build --model nvidia/NVIDIA-Nemotron-Parse-2.0 --trust-remote-code --dtype <dtype> --ep cuda and produced vision_encoder/model.onnx plus decoder/model.onnx.

  • bf16: export 52.083s; saved package 1,806,874,350 bytes; float32 processor input; vision load+run 5.631s, decoder load+prefill 1.664s; golden top-1 50251 matched.
  • f16: export 51.423s; full CUDA load+prefill 8.032s; golden top-1 50251 matched.
  • f32: export 51.346s; saved package 3,613,010,525 bytes; full CUDA load+prefill 24.155s; golden top-1 50251 matched.

Olive

Olive 0.13.0 OnnxBnb4Quantization NF4 quantized the final f16 decoder successfully in 29.320s (237,677,671-byte model). CUDA generation produced 24 non-degenerate OCR tokens in 7.112s:

# MOBIUS OCR VALIDATION ... Nemotron Parse 2.

Checklist

  • Microsoft/MIT headers, model docstrings, Multimodal metadata, public component imports, no explicit protobuf APIs
  • Registry/export/task/config extraction and representative tiny config
  • Identity weight alignment
  • L1 graph construction and L2 schema/config
  • L3 synthetic and real-weight parity
  • Real-image BF16 CUDA L4 golden
  • Deterministic greedy 24-token CUDA L5 golden
  • fp32/fp16/bf16 CUDA CLI exports and exact real-image top-1 match
  • CUDA CLI artifact reload/runtime
  • Olive NF4 quantization and non-degenerate CUDA generation
  • Initialized lintrunner -a clean
  • Final automated code review clean

Narrow waivers / limitations

  • ORT GenAI: waived. Installed ORT GenAI 0.15.2 has no generic image-to-text vision-encoder-decoder pipeline/schema for this two-model package (it is not the supported VLM decoder+embedding+vision contract). Emitting a genai_config.json would create an unloadable artifact, so export explicitly raises NotImplementedError; the guard test passed (1 passed, 76 deselected in 7.08s). Direct ONNX CUDA runtime is fully validated above.
  • Foundry Local: waived. Foundry Local 0.10.2 consumes ORT GenAI packages and therefore cannot load this package without the unsupported GenAI configuration above. The installed CLI was checked; fabricating registration metadata would not make the image-to-text pipeline executable.
  • Cross-attention projection cache: the shared EncoderDecoderAttention contract currently recomputes encoder K/V projections per decode token. Adding a lazy cross-cache requires a broader split-prefill/decode redesign; this is a performance limitation, not a correctness gap, and the exact 24-token CUDA L5 run passes.

Baseline note

Before validation, .pytest_cache/v/cache/lastfailed contained only tests/synthetic_parity_test.py::test_synthetic_parity[granitemoehybrid]. That cached unrelated baseline was not treated as a Nemotron failure; targeted Nemotron parity and the full non-integration regression suite pass as reported above.

Post-push CI baseline status

The repository-wide GitHub matrix and L3 jobs currently fail only the untouched bamba_0/bamba_1 synthetic cases on every Python/OS matrix entry (max_abs_diff=0.001375 / 0.001662, argmax matches, cosine ≥0.999996). Nemotron's affected-model L1 job passes, and its targeted local L1-L5 results are above. The benchmark-base job separately failed while finalizing an artifact with GitHub 403 Forbidden; benchmark head passed. These unrelated failures are not masked or changed in this PR.

Implement the C-RADIO vision encoder, compressed visual neck, and cross-attentive mBART decoder as a standardized vision encoder-decoder package. Add config and registry integration, real-image CUDA goldens, synthetic and real-weight parity, processor/generation support, and explicit ORT GenAI runtime guarding.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby
justinchuby requested review from a team and a lite review from Copilot August 10, 2026 19:15
Comment thread src/mobius/models/nemotron_parse.py Fixed
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Performance Comparison

Comparing 78437cd74868ff

Model Metric Baseline Current Delta
bert (feature-extraction) model_size_bytes 359 KB 359 KB +0.0%
bert (feature-extraction) num_nodes 60 60 +0.0%
falcon model_size_bytes 364 KB 364 KB +0.0%
falcon num_nodes 68 68 +0.0%
gemma2 model_size_bytes 428 KB 428 KB +0.0%
gemma2 num_nodes 107 107 +0.0%
gpt2 model_size_bytes 388 KB 388 KB +0.0%
gpt2 num_nodes 54 54 +0.0%
llama model_size_bytes 425 KB 425 KB +0.0%
llama num_nodes 62 62 +0.0%
llama (static-cache) model_size_bytes 425 KB 425 KB +0.0%
llama (static-cache) num_nodes 58 58 +0.0%
mamba (ssm-text-generation) model_size_bytes 296 KB 296 KB +0.0%
mamba (ssm-text-generation) num_nodes 98 98 +0.0%
phi3 model_size_bytes 421 KB 421 KB +0.0%
phi3 num_nodes 60 60 +0.0%
phi3 (static-cache) model_size_bytes 421 KB 421 KB +0.0%
phi3 (static-cache) num_nodes 56 56 +0.0%
qwen2 model_size_bytes 425 KB 425 KB +0.0%
qwen2 num_nodes 62 62 +0.0%
qwen2 (static-cache) model_size_bytes 425 KB 425 KB +0.0%
qwen2 (static-cache) num_nodes 58 58 +0.0%
qwen3_5_moe (hybrid-text-generation) model_size_bytes 506 KB 506 KB +0.0%
qwen3_5_moe (hybrid-text-generation) num_nodes 275 275 +0.0%
qwen3_5_text (hybrid-text-generation) model_size_bytes 458 KB 458 KB +0.0%
qwen3_5_text (hybrid-text-generation) num_nodes 129 129 +0.0%
qwen3_5_vl (hybrid-qwen-vl) model_size_bytes 977 KB 977 KB +0.0%
qwen3_5_vl (hybrid-qwen-vl) num_nodes 431 431 +0.0%
t5 (seq2seq) model_size_bytes 836 KB 836 KB +0.0%
t5 (seq2seq) num_nodes 166 166 +0.0%
whisper (speech-to-text) model_size_bytes 1008 KB 1008 KB +0.0%
whisper (speech-to-text) num_nodes 128 128 +0.0%

No performance regressions.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing 78437cd74868ff

Model Sub-model Changes Status
bert (feature-extraction) model 0
falcon model 0
gemma2 model 0
gemma4 (gemma4) decoder 0
gemma4 (gemma4) embedding 0
gemma4 (gemma4) vision_encoder 0
gemma4_text model 0
gpt2 model 0
llama model 0
llama (static-cache) model 0
mamba (ssm-text-generation) model 0
phi3 model 0
phi3 (static-cache) model 0
qwen model 0
qwen (static-cache) model 0
qwen2 model 0
qwen2 (static-cache) model 0
qwen2_moe model 0
qwen2_moe (static-cache) model 0
qwen3 model 0
qwen3 (static-cache) model 0
qwen3_5_moe (hybrid-text-generation) model 0
qwen3_5_text (hybrid-text-generation) model 0
qwen3_5_vl (hybrid-qwen-vl) decoder 0
qwen3_5_vl (hybrid-qwen-vl) embedding 0
qwen3_5_vl (hybrid-qwen-vl) vision_encoder 0
qwen3_moe model 0
qwen3_moe (static-cache) model 0
qwen3_next (hybrid-text-generation) model 0
t5 (seq2seq) decoder 0
t5 (seq2seq) encoder 0
whisper (speech-to-text) decoder 0
whisper (speech-to-text) encoder 0

No architecture changes detected.


Legend: ⚪ No change · 🔵 Minor (attrs/inits) · 🟡 Moderate (nodes added/removed) · 🔴 Major (interface changed)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class support for NVIDIA Nemotron Parse 2.0 as a two-model vision-encoder + cross-attentive decoder package, including C‑RADIOv2‑H vision backbone, weight preprocessing, and extensive synthetic/real validation plus golden generation support.

Changes:

  • Introduce nemotron_parse model + config extraction (NemotronParseConfig) and register it in the model registry.
  • Add a new vision-encoder-decoder task that exports vision_encoder and decoder components (self-attention KV cache only).
  • Expand test + golden infrastructure to cover image-to-text prefill/generation and ORT GenAI export guarding.

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/weight_alignment_test.py Adds Nemotron Parse weight-alignment identity roundtrip coverage.
tests/synthetic_parity_test.py Adds L3 synthetic parity for tiny C‑RADIO + mBART-style decoder path.
tests/integration_test.py Adds CUDA BF16 real-weight parity test against Hugging Face Nemotron Parse.
tests/e2e_golden_test.py Adds “image-to-text” golden prefill + greedy generation execution path.
tests/build_graph_test.py Updates build assertions to accept 2-model vision-encoder-decoder packages.
tests/_test_configs.py Adds tiny nemotron_parse config to VL test matrix.
testdata/golden/vision-language/nemotron-parse-2.json Adds L4 golden logits reference for Nemotron Parse.
testdata/golden/vision-language/nemotron-parse-2_generation.json Adds L5 golden generation tokens/text for Nemotron Parse.
testdata/cases/vision-language/nemotron-parse-2.yaml Adds real-image Nemotron Parse test case metadata and params.
src/mobius/tasks/_vision_encoder_decoder.py Implements a split vision-encoder/decoder task for image-to-text.
src/mobius/tasks/init.py Exposes and registers the new task name vision-encoder-decoder.
src/mobius/models/nemotron_parse.py Adds Nemotron Parse model implementation + weight preprocessing.
src/mobius/models/init.py Exports the Nemotron Parse model class.
src/mobius/integrations/ort_genai/auto_export.py Adds explicit guard rejecting unsupported generic vision encoder-decoder packages.
src/mobius/integrations/ort_genai/auto_export_test.py Adds unit test verifying the ORT GenAI guard prevents artifact emission.
src/mobius/components/_radio_vision.py Adds C‑RADIO ViT components (patch generator, blocks, summaries).
src/mobius/components/_conv.py Extends Conv2d/Conv2dNoBias to support asymmetric (h, w) kernel/stride/padding.
src/mobius/components/_conv_test.py Adds tests for asymmetric Conv2d/Conv2dNoBias parameterization.
src/mobius/components/init.py Exports RadioVisionModel from components public API.
src/mobius/_registry.py Registers nemotron_parse model_type and default model id.
src/mobius/_configs/_base.py Adds NemotronParseConfig extraction from HF config (decoder aliases, image sizing).
src/mobius/_configs/_base_test.py Adds config extraction regression test for MBART decoder head aliases.
src/mobius/_configs/init.py Exports NemotronParseConfig.
scripts/generate_golden.py Adds golden-generation routine for image-to-text (Nemotron Parse-style).
README.md Lists Nemotron Parse under supported multimodal models.
Suppressed comments (2)

tests/synthetic_parity_test.py:989

  • Same as above: feed onnx_encoder into the ONNX decoder so the unpadded/padded invariance checks validate the real vision_encoder outputs, not the torch reference tensor.
                "encoder_hidden_states": torch_encoder.numpy(),

tests/synthetic_parity_test.py:998

  • Same as above: padded_logits should use onnx_encoder to ensure the padding-mask invariance test covers the full ONNX pipeline.
                "encoder_hidden_states": torch_encoder.numpy(),

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/mobius/components/_radio_vision.py
Comment thread tests/integration_test.py
Comment thread tests/synthetic_parity_test.py Outdated
Expose the official processor's float32 pixel tensors at the vision graph boundary and cast internally for reduced-precision models. Update graph and GPU parity tests to exercise the deployment contract directly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby justinchuby changed the title Add Nemotron Parse vision-language support Add NVIDIA Nemotron Parse 2.0 support Aug 10, 2026
Feed the ONNX vision encoder output into the ONNX decoder so L3 covers the exported two-model data path while preserving independent stage parity checks.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants