Skip to content

Commit 27eda58

Browse files
committed
Fix VAE timing regression for large batch sizes
**Root Cause:** In commit 7b28885, an optimization was added to prevent OOM errors for large batch sizes (`batch_size > 2`) by batch-sharding the latents and disabling sequential slicing. However, this logic used an `elif replicate_vae:` block, which caused the explicit replication of VAE weights to be entirely skipped for large batch sizes. Without explicit weight replication, the XLA SPMD partitioner attempts to match the sharding of the input `latents` (which are batch-sharded) with the VAE decode computation. Because `vae.decode` involves fully-replicated noise injection and massive 3D convolutions, XLA heuristically decides to insert enormous amounts of cross-device communication (AllGather/AllReduce) to shard the weights or activations, ballooning the execution time from ~2.8s to ~68.5s for non-upsampled latents. (Note: For upsampled latents, the memory layout generated by the JIT-compiled upsampler bypasses this XLA heuristic trap, allowing it to execute quickly in ~1.5s, which masked the issue). **Fix:** This PR decouples the batch-sharding of `latents` from the replication of VAE weights. It explicitly applies a full replication constraint `NamedSharding(mesh, P())` to the VAE weights in all cases where `replicate_vae` is True, even if `latents` are batch-sharded. This forces XLA into the optimal data-parallel compilation path, restoring the fast ~1.5s - ~2.8s execution time for all scenarios without risking the concatenation-related OOMs.
1 parent 4a3ec4f commit 27eda58

1 file changed

Lines changed: 9 additions & 3 deletions

File tree

src/maxdiffusion/pipelines/ltx2/ltx2_pipeline.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,10 +1818,9 @@ def convert_to_vel(lat, x0, sig):
18181818
enable_dynamic_vae_sharding = (
18191819
getattr(self.config, "enable_dynamic_vae_sharding", True) if hasattr(self, "config") else True
18201820
)
1821-
18221821
if enable_dynamic_vae_sharding and batch_size > 2:
18231822
max_logging.log(
1824-
f"[Tuning] Skipping VAE replication and disabling slicing to prevent HBM OOM for batch_size {batch_size} > 2"
1823+
f"[Tuning] Disabling VAE slicing and applying dynamic batch sharding to prevent HBM OOM for batch_size {batch_size} > 2"
18251824
)
18261825
try:
18271826
# Disable sequential slicing to avoid JAX concatenating 17GB arrays on the TPU
@@ -1847,14 +1846,21 @@ def convert_to_vel(lat, x0, sig):
18471846
mesh = latents.sharding.mesh
18481847
replicated_sharding = NamedSharding(mesh, P())
18491848
latents = jax.lax.with_sharding_constraint(latents, replicated_sharding)
1849+
except Exception as e: # pylint: disable=broad-exception-caught
1850+
max_logging.log(f"[Tuning] Failed to apply replicate VAE latents sharding: {e}")
1851+
1852+
if replicate_vae:
1853+
try:
1854+
mesh = latents.sharding.mesh
1855+
replicated_sharding = NamedSharding(mesh, P())
18501856
# Replicate VAE weights
18511857
graphdef, state = nnx.split(self.vae)
18521858
state = jax.tree_util.tree_map(
18531859
lambda x: jax.lax.with_sharding_constraint(x, replicated_sharding) if isinstance(x, jax.Array) else x, state
18541860
)
18551861
self.vae = nnx.merge(graphdef, state)
18561862
except Exception as e: # pylint: disable=broad-exception-caught
1857-
max_logging.log(f"[Tuning] Failed to apply sharding constraint: {e}")
1863+
max_logging.log(f"[Tuning] Failed to replicate VAE weights: {e}")
18581864

18591865
latent_processing_time += time.perf_counter() - t0_latent_processing
18601866
timings["Latent Processing"] = latent_processing_time

0 commit comments

Comments
 (0)