LingBot-World 2.0 [1] is a 1.3-billion-parameter video world model: give it an image and a prompt, then drive the camera with WASD and it generates the world in front of you. The original paper's code runs it at 6 frames per second on an RTX 5090. Real time is 16. This repository gets there on the same card, the same weights and the same decoder.
| DiT | 1.62 s | → | 0.64 s |
| Decoder | 1.06 s | → | 0.34 s |
| GPU busy | 90% | → | 98% |
| Kernel launches | ~20,000 | → | ~4,800 |
| Host syncs | 110 | → | 2 |
DiT + decoder = s / chunk. GPU busy and kernel launches are per chunk, from the profiler traces of both configurations; host syncs per three chunks.
A chunk is 16 frames.
LingBot-World 2.0 [1] ships its code and weights. Run as released on one RTX 5090, it makes one second of video in 2.68 s, which plays at 6.0 FPS. This repository makes the same second in 0.98 s: 16.1 FPS, real time, same weights, same decoder, same picture.
Three public engines run this model. I measured each one as it ships, on the same card and at the same settings: 832×464, four denoising steps, one-second chunks, the original decoder, steady state after warm-up.
| Engine | s / chunk | FPS | Ours vs it |
|---|---|---|---|
| Original paper's code [1] | 2.68 | 6.0 | 2.7× |
| SGLang Diffusion [7] | 2.48 | 6.45 | 2.5× |
| LightX2V [9] | 2.07 | 7.73 | 2.1× |
| NVIDIA FlashDreams [8] | 1.85 | 8.65 | 1.9× |
| Ours | 0.98 | 16.1 | — |
FPS is 16 frames divided by the time to generate and decode one chunk. Nothing of mine was added to another engine. The scripts that produced each row, the settings that differ per engine, and the raw logs are in the repository.
Nothing about the model changed: same weights, same sampler, same decoder. I went through the inference stack layer by layer, cheapest and most general first, measured each step, and stopped where the only thing left would have been a custom GPU kernel. One chunk is one second of video; the original paper's code takes 2.68 s to make it, this repository 0.98 s.
| Step | Before | After | s / chunk |
|---|---|---|---|
| Host syncs | CPU↔GPU sync on every layer | bookkeeping on the GPU | 2.68 → 2.57 |
| Decoder | Wan 2.1 VAE in fp32 | fp16 with sub-pixel upsampling | 2.57 → 1.95 |
| Compiler | PyTorch eager | one compiled graph | 1.95 → 1.68 |
| Matmuls | bf16 linears | FP8 rowwise via torchao | 1.68 → 1.47 |
| Attention | FlashAttention-2 | SageAttention 2.2 | 1.47 → 1.04 |
| Kernel fusion | one kernel per operation | fused kernels for norm, RoPE, residual and FP8 quant | 1.04 → 0.98 |
| Total | 6.0 FPS | 16.1 FPS | 2.68 → 0.98 |
Seconds per chunk after each step, in the order applied. Each gain was measured on its own; the last step closes to the measured total. Custom kernels would be the step after fusion; the roofline below says they are not worth it here.
What is left runs inside four kernels written by others. Three of them are already near the card's peak. The one with room is attention. A hand-written attention kernel at 90 % of peak would gain about one frame per second, so there is no custom kernel [2].
| Kernel | Reached | Peak on RTX 5090 | of peak |
|---|---|---|---|
| FP8 matmuls | 390 TFLOP/s | 419 TFLOP/s FP8 | 90 % |
| Decoder convolutions | 173 TFLOP/s | 210 TFLOP/s FP16 | 83 % |
| Fused elementwise | ~1.3 TB/s | 1.8 TB/s memory | ~70 % |
| SageAttention | 543 TOPS | 838 TOPS INT8 | 65 % |
RTX 5090 peaks from NVIDIA's specification.
The speed is not bought with quality. Four of the six steps are bit-identical to the paper's code; the two that change the arithmetic, FP8 matrix multiplies and the INT8 attention kernel, were checked on identical inputs against the paper's decoder and sampler.
| Original paper | Ours | ||
|---|---|---|---|
| PSNR | reference | → | 43.6 dB |
| SSIM [6] | reference | → | 0.981 |
| LPIPS [5] | reference | → | 0.004 |
| MUSIQ [3] | 68.98 | → | 68.99 |
| CLIP-IQA [4] | 0.592 | → | 0.590 |
| Sharpness (Laplacian), first / last s | 1022 / 298 | → | 1023 / 298 |
| Colourfulness, first / last s | 41.9 / 50.2 | → | 41.9 / 50.2 |
| Brightness, first / last s | 0.692 / 0.384 | → | 0.692 / 0.384 |
| Flicker | 0.0381 | → | 0.0381 |
| DiT latents, exact preset | reference | → | bit-identical |
PSNR, SSIM and LPIPS: the same latents through the paper's fp32 decoder and ours, after the mp4 encoder (43.6 dB is above the 40 dB line usually called visually lossless). MUSIQ and CLIP-IQA are no-reference quality scores; sharpness is the variance of the Laplacian; flicker is the mean frame-to-frame difference; first / last second shows drift over the 22 s rollout. Same scene, seed 42. A causal model amplifies any numeric difference chunk by chunk, so the claim is made on paired latents and on quality metrics, not on the pixels of a long rollout; the FP8 and SageAttention stack is also not run-to-run deterministic.
The code, the setup instructions and the full experiment log, including every lever that did not work, are in the repository.