perf(hy_worldplay): longer video bench + HY model card#231
Conversation
|
/ok to test 1e7a2a3 |
|
The visual results here in the native column is choppy -- this seems to indicate something is wrong with the current implementation. Needs revisit and fix. Let's not add this to the public-facing doc until we are sure it is correctly implemented. |
There was a problem hiding this comment.
Lets not check in videos into this repo. you can send me the videos on slack and I will host them.
There was a problem hiding this comment.
Done — removed the checked-in .mp4s from the repo; I'll send the clips over Slack for hosting.
| # Run the reconstituted-context prefill once at the first | ||
| # denoising step of each chunk past the first; the | ||
| # ``prefill_completed_for_chunk`` latch suppresses re-runs on | ||
| # subsequent scheduler steps within the chunk. |
There was a problem hiding this comment.
This slipped through my previous review. Why would we need prefill_memory_kv? The BlockKVCache in flashdreams should naturally work with CUDAGraph.
I traced it and it seems to lead to HyWorldPlayMemoryKVCache, which stored roped K and roped V. What's the reason we can't use BlockKVCache for that? And what's the reason it can't be compatible with cudagraph like other models?
There was a problem hiding this comment.
HyWorldPlayMemoryKVCache is separate because memory isn't a rolling window, it's a per-chunk re-selection of non-contiguous frames, so BlockKVCache doesn't map directly. The non-graphability is just a stopgap; since the selected set is always exactly 16, a fixed-size in-place buffer is graph-compatible. This path also causes the choppy output, where the memory keys sit at collapsed RoPE positions [0..16) regardless of identity, so on the first window slide a frame's encoding shifts and the scene jolts.
I'll rework it into a fixed-size, consistently-positioned in-place buffer to fix both, and numerically diff vs vendor's prefill first. Do you think we should: gather K/V from retained history or re-prefill each chunk (vendor re-prefills)? @liruilong940607
Pull request was converted to draft
Greptile SummaryThis PR lands two correctness fixes for
Confidence Score: 4/5Safe to merge; the two runtime fixes are narrowly scoped to the memory-engaged path and are guarded by the same condition they test against. The
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["predict_flow()"] --> B["Evaluate memory_engaged\n(cache populated + memory indices present)"]
B --> C["self._hy_memory_engaged = memory_engaged"]
C --> D{memory_engaged AND\nprefill not done\nfor this chunk?}
D -- yes --> E["prefill_memory_kv_cache()\n(unwrap _orig_mod to reach raw network)"]
E --> F["cache.prefill_completed_for_chunk = ar_idx"]
D -- no --> G["super().predict_flow()"]
F --> G
G --> H["_select_network(uncond)"]
H --> I{_use_cuda_graph AND\n_hy_memory_engaged?}
I -- yes --> J["return network_call.drain\n(eager, no CUDA graph replay)"]
I -- no --> K["super()._select_network()"]
K --> L{filling phase?\nar_idx < capture_idx}
L -- yes --> M["return wrapper.drain\n(filling / autotune)"]
L -- no --> N["return wrapper\n(CUDA graph capture/replay)"]
Reviews (1): Last reviewed commit: "docs(hy_worldplay): un-check-in sample v..." | Re-trigger Greptile |
| <a class="model-link-button" href="https://github.com/Tencent-Hunyuan/HY-WorldPlay" target="_blank" rel="noopener noreferrer">Project page</a> | ||
| <a class="model-link-button" href="https://github.com/Tencent-Hunyuan/HY-WorldPlay" target="_blank" rel="noopener noreferrer">Official code</a> | ||
| </div> |
There was a problem hiding this comment.
Duplicate "Project page" and "Official code" URLs
Both link buttons resolve to the same https://github.com/Tencent-Hunyuan/HY-WorldPlay URL. If there is no separate landing/demo page then the "Project page" label is misleading; the redundant button should either be removed or its href updated to the canonical project page (e.g., a Hugging Face space or a paper link) once one is available. As-is, readers who click both buttons land on identical content with no way to reach a distinct artifact.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
… native output) The reconstituted-context memory prefill modulated the selected memory frames at collapsed RoPE positions [0, K) — i.e. the buffer slot index — regardless of which frames were chosen. Because the memory set is re-selected each chunk, a given frame's slot (and thus its RoPE position) changed between chunks, so its key's positional phase shifted and the scene jolted on each window slide. That's the choppiness Ruilong flagged on PR #231 (native choppy, vendor smooth). Fix: build the memory RoPE freqs at each frame's true temporal position (its clean-latent-history index), which is the same absolute coordinate frame the main path uses via `shift_t` (offset = ar_idx * len_t). A frame's encoding is now stable across chunks regardless of its slot. Renames `_build_collapsed_rope_freqs` -> `_build_memory_rope_freqs` and updates the now-inaccurate "collapsed position" docs. Adds a CPU regression test asserting the prefill driver passes the selected frame indices (not arange(K)) and that a frame keeps its position across re-selection. Full HY CPU suite passes; ruff clean. Numerical parity vs the vendor prefill still to be confirmed on GPU. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-stage and per-input perf + parity (PR #231 format) for num_chunk=8, pose=w-31, prompt "a person walking", over HY-WorldPlay/assets/img/ {1,2,5,6,10} on GB300. Native (use_cuda_graph=False after the memory-prefill corruption fix) is 5.5x faster DiT diffuse and ~4x faster DiT+VAE per chunk than vendor; median parity 36.0/255 with all chunks rendering cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
… native output) The reconstituted-context memory prefill modulated the selected memory frames at collapsed RoPE positions [0, K) — i.e. the buffer slot index — regardless of which frames were chosen. Because the memory set is re-selected each chunk, a given frame's slot (and thus its RoPE position) changed between chunks, so its key's positional phase shifted and the scene jolted on each window slide. That's the choppiness Ruilong flagged on PR #231 (native choppy, vendor smooth). Fix: build the memory RoPE freqs at each frame's true temporal position (its clean-latent-history index), which is the same absolute coordinate frame the main path uses via `shift_t` (offset = ar_idx * len_t). A frame's encoding is now stable across chunks regardless of its slot. Renames `_build_collapsed_rope_freqs` -> `_build_memory_rope_freqs` and updates the now-inaccurate "collapsed position" docs. Adds a CPU regression test asserting the prefill driver passes the selected frame indices (not arange(K)) and that a frame keeps its position across re-selection. Full HY CPU suite passes; ruff clean. Numerical parity vs the vendor prefill still to be confirmed on GPU. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-stage and per-input perf + parity (PR #231 format) for num_chunk=8, pose=w-31, prompt "a person walking", over HY-WorldPlay/assets/img/ {1,2,5,6,10} on GB300. Native (use_cuda_graph=False after the memory-prefill corruption fix) is 5.5x faster DiT diffuse and ~4x faster DiT+VAE per chunk than vendor; median parity 36.0/255 with all chunks rendering cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…choppy native output) + Re-evaluated perfs (NVIDIA#318) * fix(hy_worldplay): RoPE memory frames at true positions (fixes choppy native output) The reconstituted-context memory prefill modulated the selected memory frames at collapsed RoPE positions [0, K) — i.e. the buffer slot index — regardless of which frames were chosen. Because the memory set is re-selected each chunk, a given frame's slot (and thus its RoPE position) changed between chunks, so its key's positional phase shifted and the scene jolted on each window slide. That's the choppiness Ruilong flagged on PR NVIDIA#231 (native choppy, vendor smooth). Fix: build the memory RoPE freqs at each frame's true temporal position (its clean-latent-history index), which is the same absolute coordinate frame the main path uses via `shift_t` (offset = ar_idx * len_t). A frame's encoding is now stable across chunks regardless of its slot. Renames `_build_collapsed_rope_freqs` -> `_build_memory_rope_freqs` and updates the now-inaccurate "collapsed position" docs. Adds a CPU regression test asserting the prefill driver passes the selected frame indices (not arange(K)) and that a frame keeps its position across re-selection. Full HY CPU suite passes; ruff clean. Numerical parity vs the vendor prefill still to be confirmed on GPU. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hy_worldplay): disable CUDA-graph capture on memory-prefill path The CUDAGraphWrapper captures pointers into the KV cache, but HY-WorldPlay re-runs prefill_memory_kv_cache every chunk: it resets and repopulates each PRoPE block's memory KV from a different FOV-selected frame set (select_mem_frames_wan), reallocating the underlying storage. A graph captured on one chunk then replays against another chunk's stale/freed memory-KV slots, decoding to a deterministic "shatter" of speckle corruption on the captured/replayed chunks (independent of seed and prompt). Set use_cuda_graph=False so the rollout keeps torch.compile (Inductor) -- still ~5x faster diffuse than vendor -- without the unsafe replay. Also unwrap torch.compile's OptimizedModule (_orig_mod) before the HyWorldPlayWanDiTNetwork isinstance assert in prefill_memory_kv_cache; with compile_network=True the wrapper otherwise trips the assert at the first memory-prefill step (AR 1). Parity vs vendor (8-chunk, matched prompt) improves 80.4 -> 44.9 / 255 as the corruption is removed. Test harness: keep HF_HOME local in bench.sh (avoids ~/.cache permission errors on shared machines) and add torchvision to the vendor heavy-deps in run.sh. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(hy_worldplay): 8-chunk native-vs-vendor perf across 5 inputs Per-stage and per-input perf + parity (PR NVIDIA#231 format) for num_chunk=8, pose=w-31, prompt "a person walking", over HY-WorldPlay/assets/img/ {1,2,5,6,10} on GB300. Native (use_cuda_graph=False after the memory-prefill corruption fix) is 5.5x faster DiT diffuse and ~4x faster DiT+VAE per chunk than vendor; median parity 36.0/255 with all chunks rendering cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(hy_worldplay): refresh parity after Wan 2.2 VAE fix (NVIDIA#338) Re-measured native-vs-vendor mean |Δ| with the VAE patchify channel-order fix on the native leg (native regenerated, vendor reused unchanged). The ~2px decode checkerboard removal drops median parity 36.0 -> 24.0 / 255 (per-image 36->28, 28->23, 36->26, 21->17, 47->24). Perf/speedup table is unchanged — the fix is a zero-cost einops axis swap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(hy_worldplay): drop unused imports and dead test var (lint) Surfaced after rebasing onto current main: an unused ``typing.Any`` import in ``_camera.py`` and an unused ``HyWorldPlayPRoPESelfAttention`` instantiation + ``HyWorldPlayCtrl`` import in ``test_prefill.py``. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: jmccaffrey <jmccaffrey@nvidia.com> Co-authored-by: Ruilong Li(李瑞龙) <ruilongl@nvidia.com>
Follow-up to #155 for #203: GB300 perf re-bench, the
hy_worldplaymodel card, and twonum_chunk≥4fixes the larger GPU surfaced.Changes
_action.py: unwrap thetorch.compileOptimizedModuleinprefill_memory_kv_cache; run memory-engaged chunks eager under CUDA graphs (the data-dependent memorytorch.catcan't replay in a graph captured pre-memory). Both reachable only atnum_chunk≥4.bench.sh: defaultHY_VENDOR_SDPA=1(vendor on cuDNN SDPA, matching native).run.sh: addtorchvisionto the vendor deps.models/hy_worldplay.rst(LingBot-style) +perf-0530.md+ native sample videos; registered in the toctree; clean undersphinx-build -W.Bench
Native vs
wan/generate.py:num_chunk=8 / pose=w-31 / seed=0 / 704×1280, warmup-discard 5, DiT+VAE scope, both legs cuDNN SDPA +torch.compile, single GB300. Post-warmup medians (chunks 5–7):Per
data_local/input:|Δ|1.png2.png6.jpegcat_surf.jpgNative ~1.91× on DiT, parity on VAE, input-independent (native DiT 628–632 ms across inputs). Parity
|Δ|is cumulative bf16 AR drift (chunk-0 ≈14 matches #155's 12.91, ramps to ~49 by chunk-7, no jump at memory engagement); highest on the off-aspectcat_surf(625×350 upscaled).Native vs vendor video pairs
1.pnghy-worldplay-wan-i2v-5b.mp4
hy-worldplay-wan-i2v-5b.mp4
2.pnghy-worldplay-wan-i2v-5b.mp4
hy-worldplay-wan-i2v-5b.mp4
6.jpeghy-worldplay-wan-i2v-5b.mp4
hy-worldplay-wan-i2v-5b.mp4
cat_surf.jpghy-worldplay-wan-i2v-5b.mp4
hy-worldplay-wan-i2v-5b.mp4