Skip to content

Commit e86f174

Browse files
committed
feat(wan): fast inference optimizations (fused cross-attention, token patch embed, chunked A2A, lane padding)
- Fused short KV text cross-attention Pallas kernel (wan_cross_attn_kernel='pallas'): Implements fused online softmax attention keeping 512-token text KV in VMEM, bypassing XLA dot-product fallback and saving 5.6s on v6e-8 and 3.4s on tpu7x-8. - Token-sharded patch embedding (wan_patch_embed_mode='tokens'): Replaces Conv3d patch embedding with token-sharded patch projection matmul, eliminating activation all-gather collectives on tpu7x-8 (-0.5s) and v6e-8 (-0.2s). - Chunked inverse Ulysses all-to-all (wan_ulysses_out_a2a='chunked'): Splits sequence-to-heads A2A over leading chunk axis to prevent XLA from generating costly layout conversions around the collective on v6e-8 (-1.8s). - Lane sequence padding (wan_seq_pad='lane'): Pads video tokens to 128-token multiple per shard (75,600 -> 75,776), enabling zero-copy Ulysses reshapes with TokenPadding masking in attention kernels (-1.1s v6e, -0.2s v7). - Tuned platform recipes & compiler flags in run_wan_fast_inference.sh: v6e-8: --xla_tpu_enable_ici_ag_pipelining=false --xla_tpu_enable_ag_backward_pipelining=false. tpu7x-8: --xla_tpu_enable_offloading_copy_to_sparsecore=false, BQ=4736. - Benchmark results (Wan 2.2 T2V-14B, 720p/81f/40-step, CP=4, DP=2): v6e-8: 132.0s -> 122.2s denoise (-7.4%) / 124.3s e2e tpu7x-8: 97.6s -> 93.2s denoise (-4.5%) / 95.7s e2e
1 parent 05d2e33 commit e86f174

15 files changed

Lines changed: 1461 additions & 40 deletions

‎end_to_end/tpu/run_wan_fast_inference.sh‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,15 @@ fi
7878

7979
# Keep LIBTPU flags single-line (literal backslashes truncate libtpu flag parsing).
8080
COMMON_LIBTPU=${COMMON_LIBTPU:-"--xla_tpu_spmd_rng_bit_generator_unsafe=true --xla_tpu_enable_async_collective_fusion=true --xla_tpu_enable_async_collective_fusion_fuse_all_gather=false --xla_tpu_enable_async_collective_fusion_multiple_steps=true --xla_tpu_memory_bound_loop_optimizer_options=enabled:true --xla_tpu_enable_dot_strength_reduction=true --xla_enable_async_collective_permute=true --xla_tpu_enable_data_parallel_all_reduce_opt=true --xla_tpu_data_parallel_opt_different_sized_ops=true --xla_tpu_overlap_compute_collective_tc=true --xla_enable_async_all_gather=true --xla_tpu_scoped_vmem_limit_kib=65536 --xla_tpu_enable_async_all_to_all=true --xla_tpu_enable_all_experimental_scheduler_features=true --xla_tpu_enable_scheduler_memory_pressure_tracking=true --xla_tpu_host_transfer_overlap_limit=24 --xla_tpu_aggressive_opt_barrier_removal=ENABLED --xla_lhs_prioritize_async_depth_over_stall=ENABLED --xla_should_allow_loop_variant_parameter_in_chain=ENABLED --xla_should_add_loop_invariant_op_in_chain=ENABLED --xla_tpu_enable_ici_ag_pipelining=true --xla_max_concurrent_host_send_recv=100 --xla_tpu_scheduler_percent_shared_memory_limit=100 --xla_latency_hiding_scheduler_rerun=2 --xla_tpu_use_minor_sharding_for_major_trivial_input=true --xla_tpu_relayout_group_size_threshold_for_reduce_scatter=1 --xla_tpu_enable_latency_hiding_scheduler=true --xla_tpu_enable_ag_backward_pipelining=true --xla_tpu_use_single_sparse_core_for_all_gather_offload=true --xla_tpu_sparse_core_all_gather_latency_multiplier=1 --xla_tpu_sparse_core_reduce_scatter_latency_multiplier=3 --xla_tpu_enable_sparse_core_collective_aggregator=true --xla_tpu_enable_sparse_core_offload_queuing_in_lhs=true --xla_tpu_enable_sparse_core_reduce_scatter_v2=true --xla_tpu_enable_sparse_core_collective_offload_all_gather=true --xla_tpu_enable_sparse_core_collective_offload_2d_all_gather=true --xla_tpu_enable_sparse_core_collective_offload_all_reduce=true --xla_tpu_enable_sparse_core_collective_offload_reduce_scatter=true --xla_tpu_enable_sparse_core_collective_offload_3d_all_gather=true --xla_tpu_enable_concurrent_sparse_core_offloading=true --xla_tpu_assign_all_reduce_scatter_layout=true"}
81-
V6E_LIBTPU=${V6E_LIBTPU:-"--xla_tpu_enable_async_collective_fusion=true --xla_tpu_enable_async_collective_fusion_fuse_all_gather=false"}
81+
V6E_LIBTPU=${V6E_LIBTPU:-"--xla_tpu_enable_async_collective_fusion=true --xla_tpu_enable_async_collective_fusion_fuse_all_gather=false --xla_tpu_enable_ici_ag_pipelining=false --xla_tpu_enable_ag_backward_pipelining=false"}
8282
# fuse_all_gather must stay false on v7: with true, libtpu fails backend init on
8383
# tpu7x ("Continuation fusion for AllGather ... not supported ... other than
8484
# Viperlite"). The tpu7x reference numbers below were measured with false.
85-
V7_LIBTPU=${V7_LIBTPU:-"--xla_tpu_enable_async_collective_fusion=true --xla_tpu_enable_async_collective_fusion_fuse_all_gather=false --xla_tpu_enable_megacore_fusion=true --xla_tpu_megacore_fusion_allow_ags=true --xla_tpu_dvfs_p_state=7"}
85+
V7_LIBTPU=${V7_LIBTPU:-"--xla_tpu_enable_async_collective_fusion=true --xla_tpu_enable_async_collective_fusion_fuse_all_gather=false --xla_tpu_enable_megacore_fusion=true --xla_tpu_megacore_fusion_allow_ags=true --xla_tpu_dvfs_p_state=7 --xla_tpu_enable_offloading_copy_to_sparsecore=false"}
8686

8787
# Reference benchmarks (Wan 2.2 T2V-A14B, 720p/81f/40-step, CP=4, DP=2):
88-
# v6e-8: 131.7s e2e (denoise 129.6s)
89-
# tpu7x-8: 99.4s e2e (denoise 96.7s)
88+
# v6e-8: 124.3s e2e (denoise 122.2s)
89+
# tpu7x-8: 95.7s e2e (denoise 93.2s)
9090
case "$TPU_PROFILE" in
9191
v6e)
9292
PLATFORM_LIBTPU="$V6E_LIBTPU"
@@ -102,12 +102,13 @@ case "$TPU_PROFILE" in
102102
DEFAULT_BATCHED_TE=true
103103
DEFAULT_VAE_CHUNK=1
104104
DEFAULT_VAE_SPATIAL=8
105+
DEFAULT_ULYSSES_OUT_A2A=chunked
105106
;;
106107
v7)
107108
PLATFORM_LIBTPU="$V7_LIBTPU"
108109
DEFAULT_ATTENTION="ulysses_ring_custom_fixed_m"
109110
DEFAULT_U=2
110-
DEFAULT_BQ=6400
111+
DEFAULT_BQ=4736
111112
DEFAULT_BKV=2048
112113
DEFAULT_BKV_COMPUTE=2048
113114
DEFAULT_BKV_COMPUTE_IN=2048
@@ -117,6 +118,7 @@ case "$TPU_PROFILE" in
117118
DEFAULT_BATCHED_TE=true
118119
DEFAULT_VAE_CHUNK=1
119120
DEFAULT_VAE_SPATIAL=8
121+
DEFAULT_ULYSSES_OUT_A2A=flat
120122
;;
121123
*)
122124
echo "== warning: unrecognised accelerator '${ACCEL_TYPE:-unknown}';" \
@@ -134,6 +136,7 @@ case "$TPU_PROFILE" in
134136
DEFAULT_BATCHED_TE=true
135137
DEFAULT_VAE_CHUNK=1
136138
DEFAULT_VAE_SPATIAL=8
139+
DEFAULT_ULYSSES_OUT_A2A=flat
137140
;;
138141
esac
139142

@@ -161,6 +164,7 @@ COMPILE_TE=${COMPILE_TE:-$DEFAULT_COMPILE_TE}
161164
USE_BATCHED_TE=${USE_BATCHED_TE:-$DEFAULT_BATCHED_TE}
162165
VAE_SPATIAL=${VAE_SPATIAL:-$DEFAULT_VAE_SPATIAL}
163166
VAE_DECODE_CHUNK=${VAE_DECODE_CHUNK:-$DEFAULT_VAE_CHUNK}
167+
WAN_ULYSSES_OUT_A2A=${WAN_ULYSSES_OUT_A2A:-$DEFAULT_ULYSSES_OUT_A2A}
164168

165169
# Mesh: context parallelism carries the Ulysses shards, data parallelism takes
166170
# whatever chips remain. Defaults to CP=4 / DP=2 on an 8-chip slice. On a slice
@@ -222,6 +226,10 @@ python src/maxdiffusion/generate_wan.py "$CONFIG" \
222226
text_encoder_dtype=bfloat16 compile_text_encoder="$COMPILE_TE" use_batched_text_encoder="$USE_BATCHED_TE" \
223227
use_kv_cache=true use_base2_exp=true use_experimental_scheduler=true \
224228
use_fused_rope_kernel=true \
229+
wan_cross_attn_kernel="${WAN_CROSS_ATTN_KERNEL:-pallas}" \
230+
wan_patch_embed_mode="${WAN_PATCH_EMBED_MODE:-tokens}" \
231+
wan_ulysses_out_a2a="${WAN_ULYSSES_OUT_A2A}" \
232+
wan_seq_pad="${WAN_SEQ_PAD:-lane}" \
225233
fps=16 "${GUIDANCE_ARGS[@]}" \
226234
seed="${SEED:-12345}" \
227235
flash_block_sizes="$FLASH_BLOCK_SIZES" \

‎src/maxdiffusion/configs/base_wan_14b.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,23 @@ wan_cfg_before_unpatchify: True
133133
wan_cross_attn_prescale_kv: False
134134
# Fused RoPE accumulation: "auto" (measured per-platform default), "dtype", "f32".
135135
wan_rope_accum: "auto"
136+
# Text cross-attention backend where it would otherwise fall back to XLA dot-product
137+
# (KV shorter than flash_min_seq_length): "xla", or "pallas" for the fused kernel that
138+
# keeps the KV in VMEM (within bf16 rounding of "xla", not bit-identical).
139+
wan_cross_attn_kernel: "xla"
140+
# Patch embedding: "conv" (nnx.Conv; its channel-sharded output is resharded by
141+
# token, an all-gather on tpu7x) or "tokens" (token-sharded patches times the
142+
# replicated kernel, no activation collective; equal up to accumulation order).
143+
wan_patch_embed_mode: "conv"
144+
# Inverse Ulysses all-to-all (attention output, sequence -> heads): "flat" splits
145+
# the sequence axis directly; "chunked" exchanges over an explicit leading chunk
146+
# axis so XLA does not relayout the output around the collective. Same values.
147+
wan_ulysses_out_a2a: "flat"
148+
# Self-attention token padding: "off", or "lane" to pad each context shard of the
149+
# video token sequence to a multiple of 128 tokens (per ring segment on the ring
150+
# path). Aligned shards make the Ulysses all-to-all reshapes free; the custom
151+
# kernels mask the pad keys. Only the custom Ulysses / Ulysses-ring kernels use it.
152+
wan_seq_pad: "off"
136153
# For attention=ulysses_ring, hidden Ulysses shard count; ring shards are context / this.
137154
ulysses_shards: -1
138155
# Splits Ulysses all-to-all into head-group chunks. The last chunk carries any remainder.

‎src/maxdiffusion/configs/base_wan_1_3b.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,23 @@ wan_cfg_before_unpatchify: True
130130
wan_cross_attn_prescale_kv: False
131131
# Fused RoPE accumulation: "auto" (measured per-platform default), "dtype", "f32".
132132
wan_rope_accum: "auto"
133+
# Text cross-attention backend where it would otherwise fall back to XLA dot-product
134+
# (KV shorter than flash_min_seq_length): "xla", or "pallas" for the fused kernel that
135+
# keeps the KV in VMEM (within bf16 rounding of "xla", not bit-identical).
136+
wan_cross_attn_kernel: "xla"
137+
# Patch embedding: "conv" (nnx.Conv; its channel-sharded output is resharded by
138+
# token, an all-gather on tpu7x) or "tokens" (token-sharded patches times the
139+
# replicated kernel, no activation collective; equal up to accumulation order).
140+
wan_patch_embed_mode: "conv"
141+
# Inverse Ulysses all-to-all (attention output, sequence -> heads): "flat" splits
142+
# the sequence axis directly; "chunked" exchanges over an explicit leading chunk
143+
# axis so XLA does not relayout the output around the collective. Same values.
144+
wan_ulysses_out_a2a: "flat"
145+
# Self-attention token padding: "off", or "lane" to pad each context shard of the
146+
# video token sequence to a multiple of 128 tokens (per ring segment on the ring
147+
# path). Aligned shards make the Ulysses all-to-all reshapes free; the custom
148+
# kernels mask the pad keys. Only the custom Ulysses / Ulysses-ring kernels use it.
149+
wan_seq_pad: "off"
133150
# For attention=ulysses_ring, hidden Ulysses shard count; ring shards are context / this.
134151
ulysses_shards: -1
135152
# Splits Ulysses all-to-all into head-group chunks. The last chunk carries any remainder.

‎src/maxdiffusion/configs/base_wan_27b.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,23 @@ wan_cfg_before_unpatchify: True
155155
wan_cross_attn_prescale_kv: False
156156
# Fused RoPE accumulation: "auto" (measured per-platform default), "dtype", "f32".
157157
wan_rope_accum: "auto"
158+
# Text cross-attention backend where it would otherwise fall back to XLA dot-product
159+
# (KV shorter than flash_min_seq_length): "xla", or "pallas" for the fused kernel that
160+
# keeps the KV in VMEM (within bf16 rounding of "xla", not bit-identical).
161+
wan_cross_attn_kernel: "xla"
162+
# Patch embedding: "conv" (nnx.Conv; its channel-sharded output is resharded by
163+
# token, an all-gather on tpu7x) or "tokens" (token-sharded patches times the
164+
# replicated kernel, no activation collective; equal up to accumulation order).
165+
wan_patch_embed_mode: "conv"
166+
# Inverse Ulysses all-to-all (attention output, sequence -> heads): "flat" splits
167+
# the sequence axis directly; "chunked" exchanges over an explicit leading chunk
168+
# axis so XLA does not relayout the output around the collective. Same values.
169+
wan_ulysses_out_a2a: "flat"
170+
# Self-attention token padding: "off", or "lane" to pad each context shard of the
171+
# video token sequence to a multiple of 128 tokens (per ring segment on the ring
172+
# path). Aligned shards make the Ulysses all-to-all reshapes free; the custom
173+
# kernels mask the pad keys. Only the custom Ulysses / Ulysses-ring kernels use it.
174+
wan_seq_pad: "off"
158175
# For attention=ulysses_ring*, hidden Ulysses shard count; ring shards are context / this.
159176
ulysses_shards: -1
160177
# Splits Ulysses all-to-all into head-group chunks. The last chunk carries any remainder.

‎src/maxdiffusion/configs/base_wan_animate.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ wan_cfg_before_unpatchify: True
112112
wan_cross_attn_prescale_kv: False
113113
# Fused RoPE accumulation: "auto" (measured per-platform default), "dtype", "f32".
114114
wan_rope_accum: "auto"
115+
# Text cross-attention backend where it would otherwise fall back to XLA dot-product
116+
# (KV shorter than flash_min_seq_length): "xla", or "pallas" for the fused kernel that
117+
# keeps the KV in VMEM (within bf16 rounding of "xla", not bit-identical).
118+
wan_cross_attn_kernel: "xla"
119+
# Patch embedding: "conv" (nnx.Conv; its channel-sharded output is resharded by
120+
# token, an all-gather on tpu7x) or "tokens" (token-sharded patches times the
121+
# replicated kernel, no activation collective; equal up to accumulation order).
122+
wan_patch_embed_mode: "conv"
123+
# Inverse Ulysses all-to-all (attention output, sequence -> heads): "flat" splits
124+
# the sequence axis directly; "chunked" exchanges over an explicit leading chunk
125+
# axis so XLA does not relayout the output around the collective. Same values.
126+
wan_ulysses_out_a2a: "flat"
127+
# Self-attention token padding: "off", or "lane" to pad each context shard of the
128+
# video token sequence to a multiple of 128 tokens (per ring segment on the ring
129+
# path). Aligned shards make the Ulysses all-to-all reshapes free; the custom
130+
# kernels mask the pad keys. Only the custom Ulysses / Ulysses-ring kernels use it.
131+
wan_seq_pad: "off"
115132
# For attention=ulysses_ring, hidden Ulysses shard count; ring shards are context / this.
116133
ulysses_shards: -1
117134
# Splits Ulysses all-to-all into head-group chunks. The last chunk carries any remainder.

‎src/maxdiffusion/configs/base_wan_i2v_14b.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ wan_cfg_before_unpatchify: True
114114
wan_cross_attn_prescale_kv: False
115115
# Fused RoPE accumulation: "auto" (measured per-platform default), "dtype", "f32".
116116
wan_rope_accum: "auto"
117+
# Text cross-attention backend where it would otherwise fall back to XLA dot-product
118+
# (KV shorter than flash_min_seq_length): "xla", or "pallas" for the fused kernel that
119+
# keeps the KV in VMEM (within bf16 rounding of "xla", not bit-identical).
120+
wan_cross_attn_kernel: "xla"
121+
# Patch embedding: "conv" (nnx.Conv; its channel-sharded output is resharded by
122+
# token, an all-gather on tpu7x) or "tokens" (token-sharded patches times the
123+
# replicated kernel, no activation collective; equal up to accumulation order).
124+
wan_patch_embed_mode: "conv"
125+
# Inverse Ulysses all-to-all (attention output, sequence -> heads): "flat" splits
126+
# the sequence axis directly; "chunked" exchanges over an explicit leading chunk
127+
# axis so XLA does not relayout the output around the collective. Same values.
128+
wan_ulysses_out_a2a: "flat"
129+
# Self-attention token padding: "off", or "lane" to pad each context shard of the
130+
# video token sequence to a multiple of 128 tokens (per ring segment on the ring
131+
# path). Aligned shards make the Ulysses all-to-all reshapes free; the custom
132+
# kernels mask the pad keys. Only the custom Ulysses / Ulysses-ring kernels use it.
133+
wan_seq_pad: "off"
117134
# For attention=ulysses_ring, hidden Ulysses shard count; ring shards are context / this.
118135
ulysses_shards: -1
119136
# Splits Ulysses all-to-all into head-group chunks. The last chunk carries any remainder.

‎src/maxdiffusion/configs/base_wan_i2v_27b.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ wan_cfg_before_unpatchify: True
114114
wan_cross_attn_prescale_kv: False
115115
# Fused RoPE accumulation: "auto" (measured per-platform default), "dtype", "f32".
116116
wan_rope_accum: "auto"
117+
# Text cross-attention backend where it would otherwise fall back to XLA dot-product
118+
# (KV shorter than flash_min_seq_length): "xla", or "pallas" for the fused kernel that
119+
# keeps the KV in VMEM (within bf16 rounding of "xla", not bit-identical).
120+
wan_cross_attn_kernel: "xla"
121+
# Patch embedding: "conv" (nnx.Conv; its channel-sharded output is resharded by
122+
# token, an all-gather on tpu7x) or "tokens" (token-sharded patches times the
123+
# replicated kernel, no activation collective; equal up to accumulation order).
124+
wan_patch_embed_mode: "conv"
125+
# Inverse Ulysses all-to-all (attention output, sequence -> heads): "flat" splits
126+
# the sequence axis directly; "chunked" exchanges over an explicit leading chunk
127+
# axis so XLA does not relayout the output around the collective. Same values.
128+
wan_ulysses_out_a2a: "flat"
129+
# Self-attention token padding: "off", or "lane" to pad each context shard of the
130+
# video token sequence to a multiple of 128 tokens (per ring segment on the ring
131+
# path). Aligned shards make the Ulysses all-to-all reshapes free; the custom
132+
# kernels mask the pad keys. Only the custom Ulysses / Ulysses-ring kernels use it.
133+
wan_seq_pad: "off"
117134
# For attention=ulysses_ring, hidden Ulysses shard count; ring shards are context / this.
118135
ulysses_shards: -1
119136
# Splits Ulysses all-to-all into head-group chunks. The last chunk carries any remainder.

0 commit comments

Comments
 (0)