Skip to content

Improvement in WAN VAE Performance - #464

Open
Toshi-31 wants to merge 6 commits into
AI-Hypercomputer:mainfrom
Toshi-31:clean-vae-pr
Open

Improvement in WAN VAE Performance#464
Toshi-31 wants to merge 6 commits into
AI-Hypercomputer:mainfrom
Toshi-31:clean-vae-pr

Conversation

@Toshi-31

@Toshi-31 Toshi-31 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Improvement in WAN VAE Performance

Changes made:

  1. Using jnp.repeat in WAN Upsample instead of resize
  2. VAE Spatial and Temporal Parallelism (vae_spatial=8 & vae_decode_chunk=5)
  3. Host Formatting Changes: Pushes Classifier-Free Guidance (CFG) tensor duplication inside the JIT-compiled device graph to completely eliminate Python host overhead.

Performance Impact:
Tested on v6e-8 for 720p, 81-frame video. These changes reduced step timings from:

Before:

  • VAE Decode: 3.2s
    • TPU Compute: 2.8s
    • Host Formatting: 0.4s

After:

  • VAE Decode: 0.8s
    • TPU Compute: 0.8s
    • Host Formatting: 0.0s

Leading to a 75% improvement in latency.

@Toshi-31
Toshi-31 requested a review from entrpn as a code owner August 19, 2026 05:48

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the Wan pipeline and autoencoder models to support conditional sharding constraints, optimize classifier-free guidance by avoiding redundant latent concatenations, and adapt the caching logic in inference pipelines to be fully compatible with JAX tracing. The review feedback highlights several critical areas for improvement: removing @nnx.jit from VAE encoding/decoding may cause silent performance regressions in the VACE pipeline; the new nearest-neighbor upsampling using jnp.repeat needs to guard against non-integer scale factors; the use of addressable_data should be replaced with standard JAX APIs like addressable_shards to avoid slow fallbacks; and cache_count must be updated within the JAX-compatible caching loops to ensure accurate cache ratio logging.

Comment thread src/maxdiffusion/models/wan/autoencoder_kl_wan.py
Comment on lines +224 to +231
if self.method == "nearest":
scale_h = int(self.scale_factor[0])
scale_w = int(self.scale_factor[1])
out = jnp.repeat(jnp.repeat(x, scale_h, axis=1), scale_w, axis=2)
else:
out = jax.image.resize(x.astype(jnp.float32), (n, target_h, target_w, c), method=self.method)
out = out.astype(input_dtype)
return out

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If self.scale_factor contains non-integer values (e.g., fractional scaling), using int(self.scale_factor[0]) with jnp.repeat will truncate the scale factor and produce an incorrect output shape, leading to shape mismatches. We should ensure that jnp.repeat is only used when the scale factors are indeed integers, falling back to jax.image.resize otherwise.

Suggested change
if self.method == "nearest":
scale_h = int(self.scale_factor[0])
scale_w = int(self.scale_factor[1])
out = jnp.repeat(jnp.repeat(x, scale_h, axis=1), scale_w, axis=2)
else:
out = jax.image.resize(x.astype(jnp.float32), (n, target_h, target_w, c), method=self.method)
out = out.astype(input_dtype)
return out
if self.method == "nearest" and self.scale_factor[0] == int(self.scale_factor[0]) and self.scale_factor[1] == int(self.scale_factor[1]):
scale_h = int(self.scale_factor[0])
scale_w = int(self.scale_factor[1])
out = jnp.repeat(jnp.repeat(x, scale_h, axis=1), scale_w, axis=2)
else:
out = jax.image.resize(x.astype(jnp.float32), (n, target_h, target_w, c), method=self.method)
out = out.astype(input_dtype)
return out

Comment on lines +942 to +945
if hasattr(video, "addressable_data"):
video = np.asarray(video.addressable_data(0))
else:
video = np.asarray(video)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In standard public JAX, jax.Array does not have an addressable_data method. This will cause hasattr(video, "addressable_data") to always evaluate to False, silently falling back to np.asarray(video) which can trigger slow cross-device transfers on multi-host setups. Consider using addressable_shards[0].data instead, which is the standard JAX API to retrieve the local numpy array of the first addressable shard.

Suggested change
if hasattr(video, "addressable_data"):
video = np.asarray(video.addressable_data(0))
else:
video = np.asarray(video)
if hasattr(video, "addressable_shards") and len(video.addressable_shards) > 0:
video = np.asarray(video.addressable_shards[0].data)
else:
video = np.asarray(video)

Comment thread src/maxdiffusion/pipelines/wan/wan_pipeline_2_2.py
Comment thread src/maxdiffusion/pipelines/wan/wan_pipeline_i2v_2p2.py
Comment thread src/maxdiffusion/models/wan/autoencoder_kl_wan.py
Comment thread src/maxdiffusion/pipelines/wan/wan_pipeline.py
…g, teacache stats, and multi-host addressable data
@Toshi-31
Toshi-31 requested a review from csgoogle August 19, 2026 11:03

@Perseus14 Perseus14 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few minor changes requested.

Please squash the commits.

if axis_name in mesh.shape:
mesh_axis_size *= mesh.shape[axis_name]
if x.shape[axis_idx] % mesh_axis_size != 0:
import logging

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use our custom max_logging here.

out = jnp.repeat(jnp.repeat(x, scale_h, axis=1), scale_w, axis=2)
else:
if self.method == "nearest":
import logging

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

)
self.mesh = mesh

@nnx.jit

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might need to keep this as WAN VACE directly uses _encode

return (posterior,)
return FlaxAutoencoderKLOutput(latent_dist=posterior)

@nnx.jit

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

@Perseus14
Perseus14 requested a review from ninatu August 19, 2026 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants