Repository navigation
MOSS-Image: the denoiser on CUDA (GB10, RTX 5090) - #1528
BobClawblaw wants to merge 3 commits into
Conversation
157a75d to
6fd6cca
Compare
|
Hi @BobClawblaw, a status update on #1528. One fix is needed before it can land, and we have it ready if you'd like us to carry it. The four MOSS records After that, what's owed is a run on one GB10: the build with the moss_image fatbin, |
|
Thanks for catching that, please carry it. Adding |
MOSS-Image's transformer on the CUDA runtime beside the Metal family, from the same bf16 checkpoint and driven by the same tf-moss-image case driver (now shared by both backends: zig/tests/moss_image_run.zig). - Projections: cuBLASLt bf16 GEMMs with fp32 sums (vit.Gemms); biased ones add the bias before one rounding. - Attention: prefill_attention.cu's full vision_kernel at head dim 128, a new instance; the existing instances' SASS is unchanged (sm_80, 86, 89, 120, 121; nvcc 13.0, 13.2 and 13.3). - Glue: moss_image.cu, moss_image.metal's kernels op for op (modulated RMSNorm, q/k norm and rotary into packed rows, situ, gated add), built with the glue flags. - Kernel contract: the four kernels in each launched form and the head-128 attention pass gates 1-4, five controls red, gate-5 records current on nvcc 13.0, 13.2 and 13.3 (tf-cuda-test moss-contract). - Model.load refuses GPUs other than sm_120 and sm_121, the two it was checked on. Against the publisher's pipeline on the Metal doc's two cases (fox 1024x1024, sticky note 1200x880): per-step cosine 0.99967 to 0.99998 on a GB10 and an RTX 5090, as close to a float32 run as torch's own bf16; pictures 44.0 to 45.9 dB and 32.8 to 34.5 dB PSNR from torch's. 50 guided steps at 1024x1024: 69.6 s on a GB10 (2.03x torch), 24.6 s on an RTX 5090 (1.26x torch). docs/recipes/moss-image-cuda.md has the details.
…aches its summary The four MOSS-Image records name the image moss_image, which contract_limits.zig's image() did not know: on a CUDA machine kernel-contract stopped in the live limits with UnknownContractImage. main's host test that every registered CUDA launch and control resolves now passes with them.
6fd6cca to
5ded79a
Compare
|
Thanks @ashhart. Rebased onto main (5ded79a), and no need to carry the fix: main's new host test that every registered CUDA launch resolves (from d704476) caught On this head, |
|
Thanks @BobClawblaw, and thanks for adding One more fix is needed before the GPU run. You can reproduce it from any host with The simplest fix is the platform shim the other CUDA code uses. The module already imports const c = @import("sys").c;
var ts: c.timespec = undefined;
_ = c.clock_gettime(c.CLOCK.MONOTONIC, &ts);(as After that, what's owed is the same as before, and we'll run it ourselves on one GB10: the build with the moss_image fatbin, |
|
Fixed in 667839f: |
|
An RTX 4090 (sm_89) run of this family, for reference. Setup: RTX 4090 24 GB, Windows 11, driver 616.56, nvcc 13.3,
Values are fox / sticky note. Against the float32 runs, ours is the closer at 25 and 20 of the fox's 50 steps (prompt, negative) and 22 and 23 of the sticky note's. The same step run twice, with another between, gives identical bytes, and repeated runs give identical latents. The sticky note's handwritten text comes out the same. Against a float32 run of the whole schedule, over 8 cases (both prompts, seeds 42/7, 1, 2, 3), ours is the closer in 5, at a mean of 31.62 dB PSNR against torch bf16's 31.35 dB (table). Fox, 1024x1024, seed 42: the pipeline (left), ours (right) Sticky note, 1200x880, seed 7: the pipeline (left), ours (right) Every case's run.json, engine log, float32 picture and side-by-side are in the evidence folder, with four more prompts in the gallery. |


Closes #1518.
MOSS-Image's transformer (
OpenMOSS-Team/MOSS-Image-Base@85975793d8b3d432f1b6e27f352abaa4c2a4c0d3, the released bf16 weights as published) on the CUDA runtime, beside the Metal family and driven by the sametf-moss-imagecase driver. The driver is now shared by both backends (zig/tests/moss_image_run.zig); on Metal it gives latents identical byte for byte to main's tool on the fox case.Like the Metal family it is a denoiser, not a token family: the prompt encoder and image decoder stay in torch (
tools/zig/moss_image_case.py), and nothing registers with the lane engine, the server orfamilies.detect. Details:docs/recipes/moss-image-cuda.md.What it adds
zig/src/families/moss_image/cuda*.zig: the model, the weights (the released geometry only; any tensor left unread is refused), and the launchers. The config, rotary tables and the timestep's modulation are shared with Metal.zig/kernels/cuda/moss_image.cu:moss_image.metal's four kernels op for op (modulated RMSNorm, q/k norm and rotary into packed rows, situ, gated add), built with the glue flags (--fmad=false, IEEE division and square root).vit.Gemms/vit.linear). Attention usesprefill_attention.cu's fullvision_kernel, which gets a new instance at head dim 128.Model.loadrefuses GPUs other than sm_120 and sm_121, the two it was checked on.Kernel contract
tf-cuda-test moss-contractregisters the four kernels in each launched form, plus the head-128 attention. It passes on a GB10 (nvcc 13.0 and 13.2) and on an RTX 5090 (nvcc 13.3):Gate-5 records are in
zig/src/core/contract/moss_image_cuda_records.zig(sm_80, 86, 89, 120, 121).kernel-contract-limitsfinds all 25 MOSS lines current on nvcc 13.0, 13.2 and 13.3, so no later release needs its own set. The audit's other problems are other families' records and are the same with and without this PR.Shared code
prefill_attention.cu: one new instance,vision_kernel<128, 8>. The six existing functions compile to identical SASS before and after on sm_80, 86, 89, 120 and 121, under nvcc 13.0, 13.2 and 13.3.vit.zig:fullsgains dim 128. As a result, every tower'sAttention.load(SigLIP2 in gemma4 and lfm2, RADIO) also resolves the head-128 function and opts it into 69,632 B of dynamic shared memory. Dispatch at dims 72 and 80 is unchanged.tf-cuda-test lfm2-visionandradio-kernels: the same output apart from timings.radio-attention(head-dim-80 tower attention at five sizes): 0.008/0.012/0.152/2.975/12.884 ms on main vs 0.008/0.011/0.151/2.973/12.950 ms on the branch.Measured
Two cases with the Metal doc's prompts and seeds: a fox at 1024x1024 (seed 42) and the card's sticky note at 1200x880 (seed 7). The card's defaults apply (50 Euler steps, guidance 3). The reference is the checkpoint's
pipeline_moss_image.pyin bf16 (torch 2.11 on the GB10, torch 2.13 on the 5090; diffusers 0.38).Values are fox / sticky note. Against the float32 run, ours is the closer of the two bf16 pipelines at about half the steps on each case. The same step run twice, with another between, gives identical bytes, and repeated runs give identical latents. The sticky note's handwritten text comes out the same; fine detail differs, as on Metal. Scratch is 0.51 GB at 1024x1024 with a 34-row prompt, computed from the allocations. The 5090's latents differ from the GB10's in their low bits because cuBLASLt picks different GEMM kernels on each card.
Checks
test-cuda-hostpasses;moss-contractgives the summary above; the 512x512 fox case's latents are byte-identical to before the rebase;zig fmtis clean;lean_check.pyreports 427 problems, the same 427 as main, with none in these files. There is nogetenvin the diff.git range-diffreports=), and none of main's new commits touch the CUDA runtime,vit.zigorprefill_attention.cu.Not covered
Overlap
atc overlaplists #1439, #1508 and #1524 as conflicting. The conflicts are in shared registration lists:zig/build/cuda.zig,cuda_kernels.zig,kernels.zig,registry.zig,contract_controls.cu,tests/cuda/main.zig,kernel-contract.md, andprefill_attention.cu's instance list, where #1508 adds differentpattn_kernelinstances. Whichever PR lands second needs a trivial rebase.