@@ -158,8 +158,12 @@ def __call__(
158158 magcache_thresh : float = 0.04 ,
159159 magcache_K : int = 2 ,
160160 retention_ratio : float = 0.2 ,
161+ output_type : str = "np" ,
161162 ):
162163 config = getattr (self , "config" , None )
164+ if output_type not in ["np" , "latent" ]:
165+ raise ValueError (f"output_type must be one of ['np', 'latent'], got { output_type } " )
166+
163167 if max_sequence_length is None :
164168 max_sequence_length = getattr (config , "max_sequence_length" , 512 )
165169
@@ -254,6 +258,9 @@ def __call__(
254258 latents .block_until_ready ()
255259 trace ["denoise_total" ] = time .perf_counter () - t_denoise_start
256260
261+ if output_type == "latent" :
262+ return latents , trace
263+
257264 t_decode_start = time .perf_counter ()
258265 video = self ._decode_latents_to_video (latents , trace = trace )
259266 if hasattr (video , "block_until_ready" ):
@@ -307,6 +314,19 @@ def run_inference_2_2(
307314 do_classifier_free_guidance = guidance_scale_low > 1.0 or guidance_scale_high > 1.0
308315 bsz = latents .shape [0 ]
309316
317+ data_shards = 1
318+ try :
319+ if hasattr (latents , "sharding" ) and hasattr (latents .sharding , "mesh" ):
320+ data_shards = latents .sharding .mesh .shape ["data" ] * latents .sharding .mesh .shape .get ("fsdp" , 1 )
321+ except Exception :
322+ pass
323+
324+ if use_cfg_cache and do_classifier_free_guidance and bsz % data_shards != 0 :
325+ max_logging .log (
326+ f"Warning: Disabling CFG cache because batch size { bsz } is not divisible by data shards { data_shards } . This often happens with data_parallelism > 1 and per_device_batch_size = 1."
327+ )
328+ use_cfg_cache = False
329+
310330 prompt_embeds_combined = (
311331 jnp .concatenate ([prompt_embeds , negative_prompt_embeds ], axis = 0 ) if do_classifier_free_guidance else prompt_embeds
312332 )
@@ -333,7 +353,6 @@ def run_inference_2_2(
333353
334354 high_transformer = nnx .merge (high_noise_graphdef , high_noise_state , high_noise_rest )
335355 kv_cache_high , encoder_attention_mask_high = high_transformer .compute_kv_cache (prompt_embeds_combined )
336-
337356 # ── MagCache path (Ma et al., https://github.com/Zehong-Ma/MagCache) ──
338357 # Skips the transformer blocks on steps whose accumulated magnitude-ratio error
339358 # stays below `magcache_thresh`, reusing the cached block residual instead.
@@ -439,6 +458,8 @@ def run_inference_2_2(
439458 )
440459 return latents
441460
461+ timesteps = jnp .array (scheduler_state .timesteps , dtype = jnp .int32 )
462+
442463 # ── SenCache path (arXiv:2602.24208) ──
443464 if use_sen_cache and do_classifier_free_guidance :
444465 timesteps_np = np .array (scheduler_state .timesteps , dtype = np .int32 )
@@ -463,16 +484,18 @@ def run_inference_2_2(
463484 num_train_timesteps = float (scheduler .config .num_train_timesteps )
464485
465486 # SenCache state
466- ref_noise_pred = None # y^r: cached denoiser output
467- ref_latent = None # x^r: latent at last cache refresh
468- ref_timestep = 0.0 # t^r: timestep (normalized to [0,1]) at last cache refresh
469- accum_dx = 0.0 # accumulated ||Δx|| since last refresh
470- accum_dt = 0.0 # accumulated |Δt| since last refresh
471- reuse_count = 0 # consecutive cache reuses
472- cache_count = 0
487+ ref_noise_pred = jnp .zeros (
488+ (bsz * 2 , latents .shape [1 ], latents .shape [2 ], latents .shape [3 ], latents .shape [4 ]), dtype = latents .dtype
489+ )
490+ ref_latent = jnp .zeros_like (latents )
491+ ref_timestep = jnp .array (0.0 , dtype = jnp .float32 )
492+ accum_dx = jnp .array (0.0 , dtype = jnp .float32 )
493+ accum_dt = jnp .array (0.0 , dtype = jnp .float32 )
494+ reuse_count = jnp .array (0 , dtype = jnp .int32 )
495+ cache_count = jnp .array (0 , dtype = jnp .int32 )
473496
474497 for step in range (num_inference_steps ):
475- t = jnp . array ( scheduler_state . timesteps , dtype = jnp . int32 ) [step ]
498+ t = timesteps [step ]
476499 t_float = float (timesteps_np [step ]) / num_train_timesteps # normalize to [0, 1]
477500
478501 # Select transformer and guidance scale
@@ -518,10 +541,10 @@ def run_inference_2_2(
518541 )
519542 ref_noise_pred = noise_pred
520543 ref_latent = latents
521- ref_timestep = t_float
522- accum_dx = 0.0
523- accum_dt = 0.0
524- reuse_count = 0
544+ ref_timestep = jnp . array ( t_float , dtype = jnp . float32 )
545+ accum_dx = jnp . array ( 0.0 , dtype = jnp . float32 )
546+ accum_dt = jnp . array ( 0.0 , dtype = jnp . float32 )
547+ reuse_count = jnp . array ( 0 , dtype = jnp . int32 )
525548 latents , scheduler_state = scheduler .step (scheduler_state , noise_pred , t , latents ).to_tuple ()
526549 continue
527550
@@ -535,12 +558,10 @@ def run_inference_2_2(
535558 score = alpha_x * accum_dx + alpha_t * accum_dt
536559
537560 if score <= sen_epsilon and reuse_count < max_reuse :
538- # Cache hit: reuse previous output
539561 noise_pred = ref_noise_pred
540562 reuse_count += 1
541563 cache_count += 1
542564 else :
543- # Cache miss: full CFG forward pass
544565 latents_doubled = jnp .concatenate ([latents ] * 2 )
545566 timestep = jnp .broadcast_to (t , bsz * 2 )
546567 noise_pred , _ , _ = transformer_forward_pass_full_cfg (
@@ -630,7 +651,7 @@ def run_inference_2_2(
630651 cached_noise_uncond = None
631652
632653 for step in range (num_inference_steps ):
633- t = jnp . array ( scheduler_state . timesteps , dtype = jnp . int32 ) [step ]
654+ t = timesteps [step ]
634655 is_cache_step = step_is_cache [step ]
635656
636657 # Select transformer and guidance scale based on precomputed schedule
@@ -767,8 +788,6 @@ def low_noise_branch(operands):
767788 )
768789
769790 if scan_diffusion_loop :
770- timesteps = jnp .array (scheduler_state .timesteps , dtype = jnp .int32 )
771-
772791 scheduler_state = scheduler_state .replace (last_sample = jnp .zeros_like (latents ), step_index = jnp .array (0 , dtype = jnp .int32 ))
773792
774793 def scan_body (carry , t ):
@@ -817,7 +836,7 @@ def scan_body(carry, t):
817836 profiler = max_utils .Profiler (config )
818837 profiler .start ()
819838
820- t = jnp . array ( scheduler_state . timesteps , dtype = jnp . int32 ) [step ]
839+ t = timesteps [step ]
821840
822841 if step_uses_high [step ]:
823842 graphdef , state , rest = (
0 commit comments