Skip to content

cuda: dots.mocr's vision rotary and patch bias kernels - #2767

Merged
ashhart merged 3 commits into
ashhart:mainfrom
laudney:pr-dots-a
Nov 14, 2026
Merged

ashhart merged 3 commits into
ashhart:mainfrom
laudney:pr-dots-a

Conversation

@laudney

@laudney laudney commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor
Before (#2673) After
dots.mocr's tower rotary (2-D, by patch row and column) on CUDA no kernel tf_dots_vision_rope: FP32 cos and sin, q and k rounded to BF16, as Transformers
dots.mocr's patch bias on CUDA no kernel tf_dots_patch_bias: bf16(bf16(y) + b), the rounding the GB10 reference uses on all 29,982,720 elements
Kernel contract, GB10 (kernel-contract dots) 1 kernel 3 kernels pass gates 1-4; 3 planted controls red
Launch records tf_dots_qkv_rope also the two new launches, nvcc 13.0 images for five SMs
Served behavior text only unchanged: nothing launches the new kernels until the tower lands (piece d)

What this changes

dots.mocr's image tower needs two launches that the shared vit kernels do not have. This adds them, with their contract, controls and records; no served path calls them yet.

  • tf_dots_vision_rope (zig/kernels/cuda/dots_vision.cuh): the 2-D rotary over the q|k|v rows in place. The cosines and sines stay FP32 and are not rounded; q and k are rounded to BF16, as Transformers does.

  • tf_dots_patch_bias: o = bf16(bf16(y) + b). The GB10 reference rounds the patch bias twice on every one of its 29,982,720 elements, so the kernel does the same.

  • Both kernels are our own code, written to the reference's rounding points.

  • cuda_kernels.zig loads and launches them (visionRope, patchBias); the contract runner is zig/tests/cuda/contract_dots_vision.zig; the controls live in contract_dense_controls.cuh.

  • Model licence: n/a, no weights are read.

  • Issue: Refs Native OCR models on HIP: dots.mocr, GLM-OCR, LightOnOCR-3 and Nemotron Parse, CUDA to follow (tracker) #1927 (item 11). Remaining after this stack: Nemotron Parse and GLM-OCR on this engine.

  • Stacked on: cuda: a shared engine for dense decoders, with dots.mocr's text decoder on it #2673 (head eba945fd5). This PR's commits: 661a5a76a feat(cuda): dots.mocr's vision rotary and patch bias kernels; 4cea19ea3 chore(cuda): name dots.mocr's vision kernels in the build list. Piece 1 of 7; the engine's image path stacks on it.

  • Conflicts: a local test merge of the stack's top cd1cb0baa into main 6b739dd5e is clean (git merge-tree).

Checks on this head

  • Head commit: 4cea19ea3
  • Review fixes (Ash's 21:08 points) are new commits on this piece, listed above. On this head (Linux x86_64): zig build test-cuda-host (cuda_disk_test, the known load flake, failed once and passed on the rerun), check-native-cuda-host 7/7, test-kernel-contract, zig fmt --check and git diff --check pass; lean 386 / 386, 0 new against cuda: a shared engine for dense decoders, with dots.mocr's text decoder on it #2673's head. On the GB10 at the stack's head cd1cb0baa: dots-image and dots-text (with --vision and text only) equal their pins; the projection check passes 24 of 24 and fails a planted value two BF16 steps off. The checks below ran on the earlier heads, whose code equals this head's but for these fixes.
  • Lean checker, python3 tools/zig/lean_check.py, on the base (cuda: a shared engine for dense decoders, with dots.mocr's text decoder on it #2673's head 05e5e5fdd) and on this head: 386 / 386, 0 new.
  • Tests run (Linux x86_64, no GPU):
    • zig build test-cuda-host: 375/375 steps; 5,996 of 6,023 tests passed, 27 skipped, 0 failed (uncached; the base 05e5e5fdd gives 5,989 of 6,016).
    • zig build test-cuda-dense-host: 15/15 passed, uncached. zig build test-dots-mocr-cuda-host: 10/10 passed, uncached.
    • zig build check-native-cuda-host: 7/7 steps. zig build test-kernel-contract: 32/32 steps, 238/238 tests. zig build compile-cuda-tests (the GB10 runner compiles): 10/10 steps.
    • zig fmt --check build.zig zig, git diff --check: pass.
  • CI: pending on this head.
  • zig build test test-golden (Linux x86_64) on the stack's top 6bb38b3a1: 662/665 steps, 8,692/8,760 tests passed, 67 skipped; the one failure is cuda_disk_test, whose write deadline fails on the base too under load.
  • Not run, and why: the GB10 device checks: the kernel contract here and the receipts of pieces d and e.

Receipt

n/a: no served path launches these kernels in this piece (the tower that calls them lands in piece d, its receipt in piece e). Their exactness is the kernel contract below.

Kernel contract
  • New kernels: tf_dots_vision_rope (64 threads, grid rows × 24) and tf_dots_patch_bias (256 threads). They replace nothing. Contract: rows 4, 196, 4,096 and 19,520; positions 0, 1, 239 and 3,393; an FP64 reference at Transformers' rounding points with the FP32 cos/sin window; gate 4 stresses sums BF16 or FP16 cannot hold. The patch bias covers every BF16 input pattern and its ties.
  • Planted controls: tf_ctl_dots_vision_rope (cos and sin rounded to BF16) and tf_ctl_dots_patch_bias (one rounding), each red at gate 3.
  • GB10, nvcc 13.4, tf-cuda-test kernel-contract dots: (filtered) SUMMARY 3 kernels: 3 pass gates 1-4, 0 fail, 0 known findings; 3 controls: 3 red as planted, 0 missed; 2 limit problems. The two are the live 13.4 lines of tf_dots_qkv_rope (cuda: dots.mocr's q|k|v bias and rotary in Torch's rounding #2709 states it) and tf_dots_vision_rope (30 registers against 25): both compile to 25 under 13.0, 13.2 and 13.3, and main has no 13.4 set.
  • Records, nvcc 13.0 five-SM fatbins: tf_dots_vision_rope 28 / 22 / 22 / 25 / 25 registers, tf_dots_patch_bias 11 / 11 / 11 / 12 / 12, 0 shared bytes; 13.2 and 13.3 compile both alike (10 lines record current each), so no entries.
  • Chips not run: sm_80, sm_86, sm_89 and sm_120 devices.

Checklist

  • The title and description match the head commit, including the receipt and the stack.
  • New tests fail before the change, pass after it, and skip cleanly without their dependency.
  • Comments and docstrings are one line. No measurements or history in the source.
  • No personal data, machine names, internal hosts or local paths in the diff or its commits. No AI attribution lines.

@ashhart

ashhart commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Thanks @laudney, this reads cleanly. The two kernels round at the points the description gives, each has a planted control with host tests showing it must go red, the records cover both launches, and nothing on a served path launches them until the tower lands. One optional nit: the comment beside the dots_mocr entry in zig/build/cuda_kernels.zig still lists only the text RoPE. From our side this piece is ready.

  • Synthena (Ash's Agent)

@laudney

laudney commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. The build list's dots_mocr comment now names the vision rotary and patch bias kernels too (4cea19ea3). The stack above is restacked on it.

@ashhart

ashhart commented Nov 11, 2026

Copy link
Copy Markdown
Owner

Thanks @laudney, the build list now names all three kernels. Ready from our side; it lands after #2673.

  • Synthena (Ash's Agent)

@ashhart

ashhart commented Nov 12, 2026

Copy link
Copy Markdown
Owner

@laudney, a heads-up on the dots.mocr stack (#2767 to #2773): #2673 landed today, so we rebased all seven branches onto main ourselves and force-pushed them, to save you the round trip.

The seven are queued to land in order once CI is green on the new heads. If you had local work on these branches, please rebase it onto the new heads rather than pushing over them.

  • Synthena (Ash's Agent)

laudney and others added 3 commits November 14, 2026 03:00
dots.mocr's image tower rotates its queries and keys by the patch's
row and column with FP32 cosines and sines, and adds the patch
embedding's bias after the projection has already rounded to BF16.
Two CUDA kernels now do this in Transformers' rounding: the 2-D
rotary in place over the q|k|v rows, and the patch bias as
bf16(y + b). Each has a planted control (BF16 cosines and sines; one
rounding of the FP32 sum) and a contract against an FP64 reference
at up to 19,520 rows and positions to 3,393, with every BF16 input
pattern and tie for the bias. Their launch records come from nvcc
13.0 images for the five SMs, which 13.2 and 13.3 compile the same.
The comment beside the dots_mocr entry in the CUDA kernel list named
only the text q|k|v bias and RoPE, though dots_mocr.cu now also
builds the vision tower's 2-D rotary and patch bias launches, so the
comment names all three.
@ashhart
ashhart merged commit d1cb581 into ashhart:main Nov 14, 2026
1 of 9 checks passed
@ashhart

ashhart commented Nov 14, 2026

Copy link
Copy Markdown
Owner

Thank you @laudney. This is merged into main with your commits under your own name, so you're listed as a TensorFold contributor. It ships in the next release, credited to you in the changelog and the release notes.

@ashhart ashhart mentioned this pull request Nov 14, 2026
4 tasks done
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.

2 participants