diff --git a/v2/recipes/matrixgame2/loop.py b/v2/recipes/matrixgame2/loop.py index c66819e43..b3bd5c419 100644 --- a/v2/recipes/matrixgame2/loop.py +++ b/v2/recipes/matrixgame2/loop.py @@ -291,6 +291,11 @@ class MatrixGame2CausalDMDLoop: # advance # # --------------------------------------------------------------------- # def advance(self, st: LoopState, result: StepResult) -> LoopState: + # Monotonic progress counter: this loop drives control flow off block_idx/dmd_idx/phase (in + # scratch), but the runtime's no-progress watchdog (engine ProgramRunner._progress) keys on + # st.step_idx. Bump it on EVERY executed work unit (each DMD step AND each clean-context pass) + # so a multi-block causal rollout is seen to advance — every other recipe loop does the same. + st.step_idx += 1 out = result.output start, num = out["start"], out["num"] # Write the (denoised or unchanged) block back into the full latent. diff --git a/v2/recipes/matrixgame3/loop.py b/v2/recipes/matrixgame3/loop.py index 2d86034f7..22bbd2732 100644 --- a/v2/recipes/matrixgame3/loop.py +++ b/v2/recipes/matrixgame3/loop.py @@ -60,6 +60,12 @@ MG3_NUM_TRAIN_TIMESTEPS = 1000 # FlowUniPC timestep ~ sigma * num_train_timeste MG3_CLIP_FRAME = 56 MG3_FIRST_CLIP_FRAME = MG3_CLIP_FRAME + 1 # 57 MG3_PAST_FRAME = 16 +# DiT patch stride on the spatial latent dims (patch_size (1,2,2)). The 5B MatrixGame3WanModel folds +# (H/2, W/2) tokens, so the latent H/W must be patch-aligned (even) before denoise or the unpatchified +# velocity comes back one row/col short of the noise latent (faithful to MatrixGame3DenoisingStage's +# ``latent_h_aligned = (latent_h // patch_h) * patch_h`` crop). 720px -> latent_h 45 (odd) -> 44. +MG3_PATCH_H = 2 +MG3_PATCH_W = 2 def _toy_latent_shape(req) -> tuple[int, int, int, int]: @@ -76,7 +82,14 @@ def _toy_latent_shape(req) -> tuple[int, int, int, int]: def _gpu_latent_shape(req, channels: int, spatial_ratio: int, temporal_ratio: int) -> tuple[int, int, int, int]: d = req.diffusion t = (max(1, d.num_frames) - 1) // temporal_ratio + 1 - return (channels, max(1, t), max(1, d.height // spatial_ratio), max(1, d.width // spatial_ratio)) + h = max(1, d.height // spatial_ratio) + w = max(1, d.width // spatial_ratio) + # Patch-align the spatial latent dims to the DiT patch stride (faithful to MatrixGame3DenoisingStage): + # an odd latent_h/w (e.g. 720px -> 45) would otherwise leave the unpatchified velocity one row short + # of the noise latent and break the flow-match step's elementwise add. + h = max(MG3_PATCH_H, (h // MG3_PATCH_H) * MG3_PATCH_H) + w = max(MG3_PATCH_W, (w // MG3_PATCH_W) * MG3_PATCH_W) + return (channels, max(1, t), h, w) def _cond_compatible(latent: np.ndarray, img_cond: np.ndarray) -> bool: