Skip to content

feat(groot): GR00T N1.6 × Jetson Thor (SM110) — HF parity, 12 bug fixes, 130→28.5 ms - #177

Open
DXICM wants to merge 4 commits into
flashrt-project:mainfrom
DXICM:feat/groot-n16-thor
Open

feat(groot): GR00T N1.6 × Jetson Thor (SM110) — HF parity, 12 bug fixes, 130→28.5 ms#177
DXICM wants to merge 4 commits into
flashrt-project:mainfrom
DXICM:feat/groot-n16-thor

Conversation

@DXICM

@DXICM DXICM commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

GR00T N1.6-3B full adaptation for Jetson AGX Thor (SM110): HF numerical parity, 12 real bug fixes, and FA4/NVFP4 full-kernelization bringing E2E inference from ~130 ms to 28.5 ms (median 27.7 ms, p95 28.5 ms on Thor).

No inference hyperparameters changed (4-step flow-matching, 252×252, T=50, bf16 math). All speedup comes from kernelization / quantization / graph fusion.

Precision vs HF eager (denormalized action space): cos 0.999933 / maxd 0.059.

Commits

Commit Scope
fix(groot) 12 HF-alignment bug fixes in the Thor frontend (+1461 lines)
perf(groot) New fused FP4 kernels + FA4/NVFP4 full-kernelization (130→28.5 ms)
docs(groot) Authoritative adaptation doc + companion docs
fix(fa4) Upstream FA4 dispatch bug: CUTE_DSL_ARCH set after cutlass-dsl import (SM110 NVVM ICE)

The 12 Bug Fixes

Upstream N1.6 frontend inherited openpi-family (Pi0/Pi0.5) vision/kernel assumptions that do not hold for GR00T N1.6's HF behaviour:

# Root cause Fix
1 Tokenization: bare encode() vs Eagle chat template Reproduce HF template token-by-token
2 Resolution: 224 vs HF eval chain 252×252 image_size=252 default
3 SigLIP attention: per-view vs HF cross-view full attention batch=1 single 648-token sequence
4 Patch flatten order: (C,ph,pw) vs HF NaFlex (ph,pw,C) permute fix
5 Strided FMHA divergence on non-pow2 seq + real data parity routes through torch sdpa
6 CKernelQwen3 diverges from HF on real sequences parity runs HF-native Qwen3Model
7 Wild pointer after graph re-capture (local tensors) persistent attributes + finiteness guard
8 adaLN chunk order reversed: (scale,shift) vs HF (shift,scale) swap
9 Single-frame FP8 calibration too narrow multi-frame calibrate (8 frames, p99.9)
10 Prompt switch rejected after graph bake detect → reset → re-capture
11 Idle-first-frame garbage (Thor GPU reset) replay finiteness self-check + re-capture
12 Prompt-switch re-capture device-side assert stale DiT buffers rebuilt

Performance (all tiers ON, Thor SM110)

Component Before After Method
SigLIP encoder 10.3 ms 6.5 ms FA4 + NVFP4 fused epilogue + embeddings in-graph
Qwen3 (16L) 12.7 ms 5.0 ms NVFP4 fused norm/rope/GQA
DiT (32L × 4 steps) 36.6 ms 15.2 ms NVFP4 fused epilogue (8 kernels/layer)
Preprocessing 11 ms 2.8 ms apply_state direct + thread pool + GPU norm
E2E total ~130 ms 28.5 ms CUDA Graph capture

Bandwidth ceiling: Thor measured 252–255 GB/s (~93% of 273 GB/s spec). DiT 15.2 ms is weight-bandwidth-bound floor for this config.

Precision Tier Switches

Switch Default Effect
FLASHRT_N16_DIT_FP4 1 (ON) DiT NVFP4 fused chain
FLASHRT_N16_QWEN3_FP4 1 (ON) Qwen3 NVFP4 fused layers (norm/rope/GQA)
FLASHRT_N16_SIGLIP_FP4 1 (ON) SigLIP encoder fp4 layers
FLASHRT_N16_FA4 1 (ON) SigLIP FA4 attention (auto-fallback if missing)
FLASHRT_N16_DIT_STEPS 4 Flow-matching steps (do not reduce in production)

All tiers independently fall back to bf16/torch when disabled or unavailable.

New Kernels

  • csrc/fused_fp4/silu_mul_fp4_sfa_bf16.{cu,cuh} — SiLU(gate)×up (bf16) → NVFP4+SFA, bit-exact vs torch
  • csrc/fused_fp4/dit_norm_fp4_sfa.cu — AdaLN / no-affine LN / weighted RMSNorm → NVFP4+SFA (bf16 variants)
  • csrc/kernels/qk_norm_rope_rotate_half_bf16.{cu,cuh} — fused per-head RMSNorm + rotate-half RoPE
  • csrc/gemm/fp4/cutlass_fp4_gemm_bias_bf16_sm100.cu — bias / bias+res / bias+GELU+fp4out epilogues
  • csrc/quantize/quantize_fp4_sfa_bf16.cu — vectorized bf16 dynamic quantize

Upstream Bug Fixed (fix(fa4) commit)

fa4_backend.py imported cutlass-dsl (which caches device arch as sm_110a) BEFORE setting CUTE_DSL_ARCH=sm_101a. Combined with #164 (7fd75d20) extending the hd256 2CTA dispatch to SM110 without validation, this triggers an NVVM ICE on Thor. Fix: set env var before any cutlass import + restrict hd256 2CTA to SM100 + restore _fa4_trimmed lazy loader. Requires nvidia-cutlass-dsl >= 4.5.

Files Changed (17 files, +2588 / -134)

  • Frontend: flash_rt/frontends/torch/groot_thor.py (core, +1461)
  • Attention backend: flash_rt/hardware/thor/attn_backend_groot.py
  • Pipeline: flash_rt/models/groot/pipeline_thor.py
  • FA4 backend fix: flash_rt/hardware/thor/fa4_backend.py
  • FA4 vendor fix: csrc/attention/flash_attn_4_src/flashrt_fa4/cute/interface_fwd_sm100.py
  • New kernels: csrc/fused_fp4/, csrc/gemm/fp4/, csrc/quantize/, csrc/kernels/
  • Build: CMakeLists.txt, csrc/bindings.cpp, csrc/fp4_bindings.cpp
  • Docs: docs/groot_n16_thor_sm110.md, docs/groot_transformers5_weight_corruption.md, docs/thor_gpu_idle_reset_workaround.md

Test Plan

  • Full kernel build on Thor SM110 (CUDA 13.0, cutlass-dsl 4.5.1) — zero errors
  • Weight load: GR00T-N1.6-3B base checkpoint, 2.1s
  • E2E all tiers ON: median 27.7 ms, p95 28.5 ms, actions (50, 128) all finite
  • E2E parity (all tiers OFF): 62 ms, finite
  • FA4 patch verified: no NVVM ICE without external env override
  • HF eager numerical parity (cos/maxd) — requires same-input A/B run
  • Simulation task completion (closed-loop)

Notes

  • pipeline_thor.py contains pre-existing upstream TODO/FIXME in the legacy kernel path (parity=False); this PR does not modify that path.
  • Weight layout transforms (transpose, QKV fuse) are handled internally by the frontend at load time — no offline conversion step needed.
  • Serving layer (serving/groot_n16/) is maintained separately and not included in this PR.

DXICM added 4 commits August 18, 2026 11:51
Root-cause and fix 12 real bugs where the upstream N1.6 frontend
inherited openpi-family (Pi0/Pi0.5) vision/kernel assumptions that
do not hold for GR00T N1.6's HF behaviour:

 1. Tokenization: reproduce Eagle chat template (system/user headers,
    formalize, per-view image blocks) instead of bare encode()
 2. Resolution: HF eval chain outputs 252x252, not 224
 3. SigLIP attention scope: HF(sdpa) does cross-view full attention
    on the packed 648-token sequence, not per-view
 4. Patch flatten order: HF NaFlex uses (ph,pw,C), not (C,ph,pw)
 5. Strided FMHA divergence on non-power-of-2 seq with real data:
    parity mode routes SigLIP attention through torch sdpa
 6. CKernelQwen3 diverges from HF on real sequences: parity mode
    runs HF-native Qwen3Model (bf16, sdpa, graph-captured)
 7. Wild pointer after re-capture: Qwen3 graph-captured LN referenced
    local tensors; promote to persistent attributes + finiteness guard
 8. adaLN chunk order reversed: HF proj_out_1 is (shift, scale)
 9. Single-frame FP8 calibration too narrow: multi-frame calibrate
    (current + 7 synthetic frames, percentile=99.9)
10. Prompt switch rejected after graph bake: detect change, reset
    graph runtime, re-set prompt, re-capture
11. Idle-first-frame garbage: Thor GPU idle reset invalidates captured
    graphs; add replay finiteness self-check + re-capture retry
12. Prompt-switch re-capture device-side assert: stale DiT static
    buffers/indices not rebuilt; add to stale list

Precision vs HF eager: cos 0.999933 / maxd 0.059 (denormalized action).
No inference hyperparameters changed (4-step, 252x252, T=50, bf16).

Also adds tools/convert_groot_n16_hf_checkpoint.py for HF safetensors
to FlashRT layout conversion (Qwen3 16-layer truncation, DiT repack,
SigLIP mlp1 layout).
New CUDA kernels for the N1.6 Thor NVFP4 pipeline:

- fused_fp4/silu_mul_fp4_sfa_bf16: SiLU(gate)*up (bf16) direct to
  NVFP4+SFA, bit-exact vs torch two-step chain
- fused_fp4/dit_norm_fp4_sfa: AdaLN / no-affine LN / weighted RMSNorm
  direct to NVFP4+SFA (bf16 input variants)
- gemm/fp4/cutlass_fp4_gemm_bias_bf16_sm100: bias / bias+residual /
  bias+tanh-GELU+fp4out epilogue variants
- quantize/quantize_fp4_sfa_bf16: vectorized bf16 dynamic quantize
- kernels/qk_norm_rope_rotate_half_bf16: fused per-head RMSNorm +
  rotate-half RoPE (bf16, in-place, one launch per Q/K)

Performance rounds (no hyperparameter changes):
- DiT NVFP4 fused epilogue: 36.6 -> 15.7 ms (8 kernels/layer)
- Qwen3 fused norm/rope/GQA: 12.7 -> 5.0 ms (cos 0.999986)
- SigLIP FA4 + fp4 encoder: 10.3 -> 6.9 ms (cos 0.999988)
- SigLIP embeddings in-graph: 34 -> 28.5 ms (bit-exact)
- E2E total: 130 -> 28.5 ms (4-step, 2-camera, 252x252, T=50)

Bandwidth ceiling: Thor measured 252-255 GB/s (~93% of 273 spec);
DiT 15.2 ms is weight-bandwidth-bound floor for this config.

Tier switches (all default ON, independently fall back):
  FLASHRT_N16_DIT_FP4, FLASHRT_N16_QWEN3_FP4,
  FLASHRT_N16_SIGLIP_FP4, FLASHRT_N16_FA4
- docs/groot_n16_thor_sm110.md: single authoritative document covering
  architecture facts, 12-bug root-cause table, falsified hypotheses,
  full optimization record (130 -> 28.5 ms), roofline/bandwidth ceiling
  analysis (252-255 GB/s, ~93% of spec), precision tier switches, and
  verification methodology.
- docs/groot_transformers5_weight_corruption.md: transformers>=5 silent
  weight corruption via _initialize_missing_keys re-randomizing SigLIP2
  vision tower (282 tensors). One-line fix + integrity guard.
- docs/thor_gpu_idle_reset_workaround.md: Thor GPU idle reset defect and
  three-layer CUDA Graph protection (keepalive, idle reinit, finiteness).
cutlass-dsl caches the device arch at import time. The previous code
imported cutlass to check its version, then set CUTE_DSL_ARCH=sm_101a
— too late; NVVM already cached sm_110a and ICEs on the hd256 2CTA
kernel (introduced in flashrt-project#164, commit 7fd75d2).

Fix: set CUTE_DSL_ARCH=sm_101a unconditionally before any cutlass
import. Also revert the hd256 2CTA dispatch to SM100-only (the
dedicated kernel was never validated on SM110) and restore the
_fa4_trimmed lazy loader for BlackwellFusedMultiHeadAttentionForward.

Verified: all-tier E2E on Thor — median 27.7 ms, p95 28.5 ms,
actions finite, cos 0.999933 vs HF eager.
@DXICM
DXICM force-pushed the feat/groot-n16-thor branch from 817cbf7 to 4cae6c0 Compare August 18, 2026 03:52
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.

1 participant