Repository navigation
radio CUDA: fuse the tower's bias, activation and residual launches - #1141
Closed
plotarmordev wants to merge 1 commit into
Closed
plotarmordev wants to merge 1 commit into
plotarmordev wants to merge 1 commit into
Conversation
The RADIO tower ran a bias kernel and then a pointwise kernel at each of its bias sites. One kernel now does both, sharing the pointwise arithmetic so every output byte is the one the two-kernel path wrote; the kernel contract registers it as replacing tf_vit_bias then tf_vit_pointwise and compares bytes on every variant.
ashhart
added a commit
that referenced
this pull request
Oct 24, 2026
Owner
|
Landed on main as 9e6e5fa with a maintainer fix-up (cb09c36) that registers the omitted BF16 bias-round control, thank you @plotarmordev. The RADIO tower's bias, activation and residual launches are fused. Served cells were exact, and the full CUDA kernel contract passes on a GB10: the fused kernel is within its limits and the new control fails as planted. - Synthema, Ash's AI Assistant. |
Owner
|
This shipped in TensorFold 1.1.4: https://github.com/ashhart/TensorFold/releases/tag/v1.1.4 Thank you @plotarmordev for the contribution. - Synthema, Ash's AI Assistant. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One commit,
47ef1241, on maind1018b31(the same tree as the testedc8dc633c; only the commit message changed).Its speed was measured only together with "radio CUDA: reuse one pinned pixel stage for every image", both on #1057;
see Receipt.
What this changes
In every RADIO tower layer, three Linears end in a separate bias launch and a separate pointwise launch whenever
the cuBLASLt algorithm chosen for their shape does not take the bias epilogue: the attention projection
(
tf_vit_bias, thentf_vit_pointwiseadding the residual intoh), the first MLP Linear (bias, then erf GELU) andthe second (bias, then the residual).
tf_vit_biaswrites the bf16 sum of the f32 accumulator and the bias, andtf_vit_pointwisereads it back. The newtf_vit_bias_actdoes both in one launch and keeps that bf16-rounded valuein a register:
pointwise_atis the old body oftf_vit_pointwise, moved into a helper that both kernels call, so the activationrounding, the residual-first addition and the final bf16 rounding are the same code. One element a thread, the same
block layout as
tf_vit_bias. The SASS oftf_vit_pointwiseandtf_vit_biasis unchanged by the refactor (sm_121fatbins of main and of this branch,
gpu/sass.txt).vit.linearActreplaces those threelinear+pointwisepairs inTower.features. When the shape's plan takescuBLASLt's bias epilogue it runs exactly the old pair; otherwise it runs the same f32 GEMM as
linearand thentf_vit_bias_act. The QKV Linear, GEMM planning and algorithm choice, and the projector's own pointwise launch areunchanged. In the fused path the intermediate buffer is no longer written; its next readers (
layerNorm, the finalnorm,
project) write it before they read it.Kernel contract:
zig/tests/cuda/contract_vit_glue.zigregisterstf_vit_bias_actwithreplaces = "tf_vit_bias then tf_vit_pointwise", one spec per variant ({none, tanh GELU, erf GELU, relu²} × {no residual, residual, in-placeresidual}, 12 names) at the served width and rows (13,322 × 1,280 and × 5,120). The gates run the real original
launches on the same guarded inputs and compare bytes. The non-finite gate plants NaN, +Inf and −Inf in the
accumulator, NaN and +Inf in the bias, and +Inf and −Inf (no NaN) in the residual, and requires a non-finite output.
The contract runs the kernel alone, not
linearActinside the tower. The launch record (vit_records.zig,15/16/16/14/14 registers on sm_80/86/89/120/121 from nvcc 13.0) sits in the live registry, with a host test in the
qwen_served_recordspattern.docs/kernel-contract.mdlists the kernel under CUDA coverage.Receipt
Raw files: https://github.com/plotarmordev/TensorFold/tree/nemotron-receipts/receipts/nemotron/vision-fused-glue (
README.mdmaps every file;SHA256SUMS).Environment, with the TensorFold commit, MLX or PyTorch version, machine and GPU, checkpoint and revision: this
branch at
47ef1241on maind1018b31; it has the same tree asc8dc633c, the commit every receipt below wasmade from. GPU builds from detached checkouts (
env/PROVENANCE-*.txt),zig build fatbinsandzig build installwith
-Dtarget=aarch64-linux-gnu.2.28 -Dcpu=baseline -Doptimize=fast -Dstrip=true -Dsm=121 -Dversion=1.1.1 -Dnvcc=…(zig 0.17.0, nvcc 13.0.88): base =d1018b31+ nemotron cuda: a prompt pass with images runs the RADIO tower once, not twice #1057 (732b0e31; without nemotron cuda: a prompt pass with images runs the RADIO tower once, not twice #1057 every image runs throughthe tower twice); contract build = nemotron cuda: a prompt pass with images runs the RADIO tower once, not twice #1057 + this commit (
b4ae488c;tf-cuda-testsha256c8129813…179f29973);timing build "both" = nemotron cuda: a prompt pass with images runs the RADIO tower once, not twice #1057 + this commit + the pinned-stage pull request (
f6d8ba5a;tensorfold-native34fba744…a29cda, base5e70f78f…dcef69).env/commits.txtshows each measured commit's parent, tree andgit patch-id --stablenext to the submitted ones:47ef1241andc8dc633cshare tree2a07a5f1…;b4ae488candb7e05211(underf6d8ba5a) carry their patch-id; every nemotron cuda: a prompt pass with images runs the RADIO tower once, not twice #1057 copy carriese2357b58's. One DGX Spark (GB10,sm_121), driver 580.173.02, CUDA 13.0,
nvidia/NVIDIA-Nemotron-3.5-Super-VL-120B-A12B-NVFP4@82d93699acd3be9e4617c53360fe5b3f5dbeb1b3, every hold a freshprocess (and for servers a fresh
HOME) withTF_HEAT_HIGH=85 TF_HEAT_LOW=75, started at a zone of 60 °C or less.Kernel contract,
tf-cuda-test kernel-contracton the contract build:SUMMARY 97 kernels: 97 pass gates 1-4, 0 fail, 0 known findings; 7 controls: 7 red as planted, 0 missed; 1533 limit problems.tf_vit_bias_act, all four gates for each of the 12 variants, e.g.PASS nonfinite cuda vit tf_vit_bias_act gelu in-place residual: the stated rule holds: byte-identical to bias then pointwise, including non-finite inputsandPASS shapes … : 6 shapes bit-equal to the kernel it replaces (worst 0.000 of the bound), 0 edges refused by the kernel.PASS limits live vit tf_vit_bias_act: 256 threads launched, the driver allows 256; 14 registers, 0 + 0 shared bytes (recorded 14, 0);cuobjdump -res-usageon the sm_121 fatbin:REG:14 STACK:0 SHARED:0 LOCAL:0.main's source (this diff adds only
tf_vit_bias_act's record) thathave no nvcc 13.0 usage record: 877
<kernel> on <sm>: no compiled usage recordedand 656 live launches whoserecord reads
(recorded 0, 0). They are in DeepSeek V4.1 images (1200) and in Qwen 3.5, sampling, top-k, GLM,act_rows,gdn_prep,tree_round,qk_rowsandaffine4images (333);gpu/limit-problems.txtcounts themby image. None names a kernel this pull request adds or changes. Main's own
tf-cuda-testwas not run in thesame session, so an unchanged count on main is not shown; a green aggregate needs those records, or a waiver
for them.
compute-sanitizer --tool memcheck --error-exitcode 1over the same command:ERROR SUMMARY: 0 errors, the sameSUMMARY line (its exit 1 is the same limits gate).
Exactness, from
tools/bench_concurrent.py --alone --serialortoken_shaagainst"draft": false: with "both",every
image-ttftrequest (2048 x 1664 images,"draft": false, 8 a hold, 2 holds) gives541bca2d52751d8bb9c44b2af53ce8ff2dfb93745d8cb6bdb740442dad9735ecfor one image andef22b44ea1d731737c2d2a757d671d03b1269563d6bb505944e58608ecd444c4for four, the same as the base and as nemotron cuda: a prompt pass with images runs the RADIO tower once, not twice #1057'sreceipts.
bench.py decodeon "both" runs 11 prompts drafted (count, prose, code, image, multilingual and sixlanguages) plus count with
"draft": false; every drafted reply equals"draft": false, and the hashes equalmain's. Its
imageprompt carries one 320 x 208 picture, so that is the one drafted image request that ran throughthe fused tower. The full-size
image-ttftworkload was not run with drafts;bench_concurrent.py, resumed andconcurrent image requests were not run.
Decode speed before and after, from
tools/bench_openai.py: not measured. Decode rounds never run the tower; onlyan image prompt's prompt pass does.
Prompt speed before and after:
tools/bench_cache.pysends no images, so TTFT is the server'stime_to_first_tokenfrombench.py image-ttft(scripts/; one generated 2048 x 1664 PNG, then four copies,3,356 and 13,366-token prompts, a warmup and 3 measured requests each, greedy, thinking off,
"draft": false, 32tokens, cooled to 75 °C before every request; served with
--vision --vision-image-tokens 13312 --vision-max-images 4 --context 18432 --parallel 1 --prompt-cache-gib 0). Holds in the order base, both, base,both:
This commit alone was not timed, and nsys was not run on it, so its share of that gain, the fused launch counts
in a trace and the kernel's achieved bandwidth are not measured. The pinned-stage commit alone, under nsys, went
from 2.301 to 2.239 s (one image) and from 15.058 to 14.030 s (four). Every four-image request on every build paused
once at the heat gate inside its prompt pass (
heat_wait_s 8.0); the TTFTs include it.Tests run, with pass, fail and skip counts (CPU only, a DGX Spark,
-j1,nice -n 19, fresh caches), atc8dc633c(this tip's tree):
zig build test test-golden fuzz-cortheon compile-cuda-tests227/227 steps, 2971 of 2985 tests passed, 14skipped, 0 failed (
fuzz-cortheon11 of 11;test-golden26/26 and 306/319 equal to the frozen answers, 0unexpected differences;
compile-cuda-testsbuilds);zig build test-kernel-contract11/11 steps, 66 of 66 (47,9, 3 and 7);
zig fmt --checkon the seven changed Zig files clean;tools/zig/lean_check.py444 problems, 444 onmain, 0 new. Failing receipt: the live-registry test against an earlier, stale record (
expected 15, found 28; field regs incorrect); before this change the kernel is not in the registry at all.Not run, and why:
tf-cuda-test radiorow hashes on two image sizes: it needs float32 reference files we do not have. What isshown: the fused kernel's outputs equal the replaced launches' bytes on the contract's inputs, and the
end-to-end reply hashes equal the base's on the served workloads. No intermediate tower bytes were captured, so
whole-tower byte equality is not shown directly.
kernel-contract-limitson fatbins for sm_80/86/89/120: the GPU builds carry sm_121 only; the other recordscome from CPU
ptxasbuilds.Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (Measured: full-size image replies byte-equal to the base with"draft": false, and drafted equal to"draft": falseon 11 decode prompts, one with a 320 x 208 picture, with this commit in the build. Resumed and concurrent requests with images were not run.)tf_vit_biasthentf_vit_pointwisein all 12 variants on the contract's inputs, including the planted non-finite values listed above, and equal reply hashes on the served workloads.)SUMMARYline is in the receipt. (CUDA only. All 12 variants pass gates 1-4; the aggregate run exits 1 on 1533 limit problems, none in a launch this change adds or touches, see above.)tf-cuda-teston a GPU.)