Repository navigation
[perf] Batch H3 vision frames with PyTorch varlen attention - #2050
leo2ultimate wants to merge 11 commits into
Conversation
Merge Protections🔴 1 of 1 protections blocking · waiting on 👀 reviews and 🤖 CI
🔴 PR merge requirementsWaiting for
This rule is failing.
|
647785f to
e9c708c
Compare
[Medium impact] No new blocking issue was found in the changes since the previous review.
|
a2b8ff6 to
67a23ee
Compare
|
@fv-superagent review Please review head The change replaces the per-frame SDPA loop with one native PyTorch 2.12 Verified inputs Reuse the repository's
Images use Pillow Case A: I1 + V1. Case B: I1 + I2 + I3 + V1 + V2 + V3, in that order. B is a controlled stress case derived from the same two assets, not six independent scenes. Actual CPU calls to H3's Requested measurements
Please use a benchmark-only runner if additional instrumentation is needed; if GPU, weights, the exact schedule, or a trustworthy encoder/end-to-end runner are unavailable, report those gaps first. CI note: the prior |
|
/test pre-commit |
There was a problem hiding this comment.
fv-superagent score: 3/5
Tight diff, and the semantic CPU tests plus the honestly-scoped benchmark are good work. Two issues need an answer before this is merge-ready, both because the swap goes unconditional.
1. It breaks the contract in the H3 official-parity test for image/video. tests/local_tests/encoders/test_minimax_h3_qwen3_vl_parity.py:251 asserts atol=0.0, rtol=0.0 against the official Qwen3-VL stack for text, image and video. The official vision path splits frames and calls SDPA per chunk — exactly what the base loop did, which is why it was bit-exact. One packed varlen_attn over all frames is a different reduction and will not match. That test is MINIMAX_H3_RUN_ENCODER_PARITY=1-gated and outside the Encoder lane, so "34 passed / 5 skipped" does not cover it. The analogous DiT swap is opt-in for this exact reason (FASTVIDEO_MINIMAX_H3_FA4_PACKED_VARLEN, fastvideo/envs.py:359); this one has no opt-out.
2. The accepted fp32 text-encoder precision now hard-fails. --text-encoder-precisions accepts fp32 (fastvideo/configs/pipelines/base.py:183), which builds the vision tower in fp32; varlen_attn is fp16/bf16-only and has no CPU kernel, so an H3 ref2va run at fp32 — or any CPU vision forward — now raises where the base revision worked. If dropping fp32/CPU vision is intended, it needs an explicit guard and a doc line rather than a silent failure. (The default bf16 path is unaffected.)
CI. pre-commit was a draft-era skip that would not have re-run on its own, so I sent /test pre-commit; it passed. Greptile re-reviewed 67a23ee5 and found no new defect. buildkite/pr-fastcheck #2292 Encoder passed: 140 passed, 1 skipped (base was 127 passed, 1 skipped), so all five new CUDA tests ran on the DGX Spark GB10 and matched the per-frame SDPA loop within tolerance — the real kernel works on sm_121, which closes the "kernel untested" and contiguity concerns. Those tests use atol=8e-3, rtol=2e-2, which does not satisfy the atol=0/rtol=0 parity contract in item 1.
Repro commands, test-coverage note, and the requested benchmark
Parity repro: MINIMAX_H3_RUN_ENCODER_PARITY=1 pytest tests/local_tests/encoders/test_minimax_h3_qwen3_vl_parity.py -v -s
The committed tests/local_tests/encoders/benchmark_minimax_h3_vision_attention.py has no measurement bug: it reproduces the base loop with identical weights/inputs and pre-builds the packed metadata outside timing. Minor coverage note: the CPU test's non-contiguity assertion exercises the Linear input, not the strided q/k/v that .unbind(1) hands to the kernel — the CUDA tests now cover that in CI.
On the larger A/B you asked for: it needs a maintainer to clear a GPU run on a fork branch, so I left it; the five CUDA tests are already green in the Encoder lane. For that comparison, report a numeric feature diff together with the bf16 noise floor rather than a binary parity, and keep the two versions serialized on one GPU so timings don't overlap.
— fv-superagent, automated maintainer run by aryan5v
|
@fv-superagent review Pushed Local checks: 38 passed, 6 CUDA skipped, applicable changed-file pre-commit checks and On your exact-parity concern: we have not changed the official-parity test's zero tolerances, and we are not claiming that real-checkpoint GPU outputs already pass Could you run or inspect the gated official-parity test on the base and this head with identical weights/inputs, and report whether exact equality actually fails, plus max/mean absolute differences and the BF16 numerical noise floor? If the differences are consistent with expected kernel rounding, would tolerance-based image/video parity be acceptable, or is bit-exact official parity a required contract here? We should establish that before changing any threshold. Please return any remaining correctness/readiness concerns first. If the real-checkpoint GPU comparison requires maintainer clearance, identify that requirement rather than treating CPU tests as GPU evidence. |
fv-superagent
left a comment
There was a problem hiding this comment.
fv-superagent score: 4/5 (was 3/5)
Re-reviewed the delta from 67a23ee5 to 95c6c1c9.
Resolved — fp32/CPU compatibility. _can_use_vision_varlen now gates the packed call on ROCm exclusion, fp16/bf16 dtype, head_dim % 8, and PyTorch's can_use_flash_attention; everything else takes the original per-frame SDPA loop. The new tests exercise the real fallback on CPU fp32/bf16 and CUDA fp32 with atol=0 against the legacy loop, and the benchmark reports a skip instead of counting a fallback as a varlen result. That closes my earlier item 2.
Still open — exact image/video parity is a contract decision, not a code fix. On CUDA bf16 the fast path is eligible, so tests/local_tests/encoders/test_minimax_h3_qwen3_vl_parity.py:251 cannot stay at atol=0/rtol=0 for image/video; text-only is untouched. Your proposal — keep text exact, use a dtype-appropriate tolerance for the optimized image/video path, backed by measured feature differences — is reasonable, but it changes a repo contract, so a maintainer owns it. The earlier request-changes stands until that is settled.
On running the gated parity test. It needs CUDA bf16, the official text_encoder/ checkpoint and the Transformers stack, and this is a fork branch: the GPU runner requires a maintainer's /agent gpu-ok <full sha> comment before it will fetch fork code. I have a base-SHA job queued to validate the harness and establish the noise floor, and the head run is waiting on that marker. I'll report the measured max/mean differences once both land; I am not treating the CPU tests as GPU evidence.
CI. Greptile re-reviewed 95c6c1c9 and found no new issue. pre-commit passed on the push. buildkite/pr-fastcheck #2296 is queued behind an agent backlog; the previous head's Encoder lane was green (140 passed, 1 skipped).
— fv-superagent · CPU is back on the guest list · run by aryan5v
Purpose
Batch supported H3 Qwen3-VL reference-frame inputs in one variable-length attention call per vision layer, including frames with different token lengths. Preserve the original per-frame SDPA path for unsupported inputs.
Changes
Before: a separate SDPA call for every frame (simplified; each frame's Q/K/V has shape
[1, heads, tokens, head_dim]):After: for supported CUDA inputs, one call over packed Q/K/V, with boundaries keeping frames independent:
Frame boundaries are built once per vision forward and reused across layers. RoPE precision, scaling and token order are preserved.
The fast path reuses PyTorch's public
can_use_flash_attentioncapability check, with the native varlen dtype/alignment constraints. CPU/FP32 and other ineligible inputs retain the original per-frame SDPA loop. Actual kernel errors and OOMs propagate; they are not caught and retried.Test Plan
Local CPU checks:
Test Results
git diff --check: passed. Fullpre-commit run --all-filespassed earlier in this PR.CPU tests cover the real SDPA fallback and use a semantic substitute for CUDA varlen packing. Native GPU correctness, real-checkpoint numerical closeness, speedup and memory impact remain unverified. The existing official-parity test's zero tolerances are unchanged.
Checklist
pre-commit run --all-filesand fixed all issuesFor model/pipeline changes, also check:
For new models or serving runtimes: