---
title: matrixgame2_self_forcing_distillation_pipeline
---

<div class="python-reference">
<a id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline-classes"></a>
<a id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline-functions"></a>
<a id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline-functions"></a>
<a id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline"></a>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam</code></h2>
<pre class="doc-signature"><code>SamplingParam(data_type: str = &#x27;video&#x27;, image_path: str | None = None, pil_image: Any | None = None, last_image: Any | None = None, references: list&#91;Any&#93; | None = None, video_path: str | None = None, pose_video_path: str | None = None, face_video_path: str | None = None, background_video_path: str | None = None, mask_video_path: str | None = None, animate_mode: str | None = None, audio_path: str | None = None, latents: Any | None = None, audio_latents: Any | None = None, mouse_cond: Any | None = None, keyboard_cond: Any | None = None, grid_sizes: Any | None = None, pose: str | None = None, prompt_attention_mask: list = list(), negative_attention_mask: list = list(), c2ws_plucker_emb: Any | None = None, action_path: str | None = None, t_thresh: float = 0.5, num_cond_frames: int = 0, prompt: str | list&#91;str&#93; | None = None, negative_prompt: str = &#x27;Bright tones, overexposed, static, blurred details, subtitles, style, works, paintings, images, static, overall gray, worst quality, low quality, JPEG compression residue, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn faces, deformed, disfigured, misshapen limbs, fused fingers, still picture, messy background, three legs, many people in the background, walking backwards&#x27;, max_sequence_length: int | None = None, prompt_path: str | None = None, output_path: str = &#x27;outputs/&#x27;, output_video_name: str | None = None, num_videos_per_prompt: int = 1, seed: int = 1024, num_frames: int = 125, height: int = 720, width: int = 1280, height_sr: int = 1072, width_sr: int = 1920, fps: int = 24, num_inference_steps: int = 50, num_inference_steps_sr: int = 50, guidance_scale: float = 1.0, batch_cfg: bool = False, guidance_scale_2: float | None = None, use_embedded_guidance: bool = False, true_cfg_scale: float = 1.0, guidance_rescale: float = 0.0, boundary_ratio: float | None = None, sigmas: list&#91;float&#93; | None = None, pyramid_num_inference_steps_list: list&#91;int&#93; | None = None, history_sizes: list&#91;int&#93; | None = None, num_latent_frames_per_chunk: int = 9, keep_first_frame: bool = True, is_skip_first_chunk: bool = False, use_zero_init: bool = True, zero_steps: int = 1, is_amplify_first_chunk: bool = False, enable_teacache: bool = False, trajectory_type: str | None = None, movement_distance: float | None = None, camera_rotation: str | None = None, ltx2_cfg_scale_video: float = 1.0, ltx2_cfg_scale_audio: float = 1.0, ltx2_modality_scale_video: float = 1.0, ltx2_modality_scale_audio: float = 1.0, ltx2_rescale_scale: float = 0.0, ltx2_stg_scale_video: float = 0.0, ltx2_stg_scale_audio: float = 0.0, ltx2_stg_blocks_video: list&#91;int&#93; = (lambda: &#91;29&#93;)(), ltx2_stg_blocks_audio: list&#91;int&#93; = (lambda: &#91;29&#93;)(), ltx2_use_ancestral_sampler: bool = False, ltx2_images: list&#91;tuple&#91;str, int, float&#93;&#93; | None = None, ltx2_image_crf: float = 33.0, ltx2_conditioning_latent_stage1: Any | None = None, ltx2_conditioning_latent_stage2: Any | None = None, ltx2_video_conditions: list&#91;tuple&#91;list&#91;str&#93;, int, float&#93;&#93; | None = None, audio_start_in_s: float | None = None, audio_end_in_s: float | None = None, init_audio: Any = None, init_audio_strength: float | None = None, init_noise_level: float | None = None, inpaint_audio: Any = None, inpaint_mask: Any = None, continuation_state: ContinuationState | None = None, return_continuation_state: bool = False, save_video: bool = True, return_frames: bool = True, return_trajectory_latents: bool = False, return_trajectory_decoded: bool = False, *, return_samples: bool = False)</code></pre>
<p>Sampling parameters for video generation.</p>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.check_sampling_param"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.check_sampling_param</code></h3>
<pre class="doc-signature"><code>check_sampling_param() -&gt; None</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.update"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.update</code></h3>
<pre class="doc-signature"><code>update(source_dict: dict&#91;str, Any&#93;) -&gt; None</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.from_pretrained"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.from_pretrained</code></h3>
<pre class="doc-signature"><code>from_pretrained(model_path: str) -&gt; SamplingParam</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.add_cli_args"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SamplingParam.add_cli_args</code></h3>
<pre class="doc-signature"><code>add_cli_args(parser: Any) -&gt; Any</code></pre>
<p>Add CLI arguments for SamplingParam fields</p>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.get_local_torch_device"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.get_local_torch_device</code></h2>
<pre class="doc-signature"><code>get_local_torch_device() -&gt; torch.device</code></pre>
<p>Return the torch device for the current rank.</p>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs</code></h2>
<pre class="doc-signature"><code>FastVideoArgs(model_path: str, mode: ExecutionMode = ExecutionMode.INFERENCE, workload_type: WorkloadType = WorkloadType.T2V, distributed_executor_backend: str = &#x27;mp&#x27;, enable_streaming_ipc_queues: bool = False, ray_placement_group: PlacementGroup | None = None, ray_runtime_env: RuntimeEnv | None = None, inference_mode: bool = True, trust_remote_code: bool = False, revision: str | None = None, num_gpus: int = 1, tp_size: int = -1, sp_size: int = -1, hsdp_replicate_dim: int = 1, hsdp_shard_dim: int = -1, dist_timeout: int | None = None, pipeline_config: PipelineConfig = PipelineConfig(), preprocess_config: PreprocessConfig | None = None, lora_path: str | None = None, lora_nickname: str = &#x27;default&#x27;, lora_strength: float = 1.0, lora_target_modules: list&#91;str&#93; | None = None, output_type: str = &#x27;pil&#x27;, attention_backend: str | None = None, dit_cpu_offload: bool = True, use_fsdp_inference: bool = False, dit_layerwise_offload: bool = True, text_encoder_cpu_offload: bool = True, image_encoder_cpu_offload: bool = True, vae_cpu_offload: bool = True, pin_cpu_memory: bool = True, h3_sequential_load: bool | None = None, h3_encoder_split: bool | None = None, h3_encoder_nodes: int = -1, h3_encoder_workers: int = 0, video_decode_backend: str = &#x27;h3-vae&#x27;, taeh3_checkpoint: str | None = None, taeh3_chunk_size: int = 5, h3_vae_nvfp4_decoder: str | None = None, lazy_module_load: bool | None = None, vae_parallel_decode: bool = False, vae_parallel_encode: bool = False, vae_parallel_decode_strategy: str | None = None, enable_torch_compile: bool = False, regional_compile: bool = False, enable_torch_compile_text_encoder: bool = False, enable_torch_compile_vae: bool = False, enable_torch_compile_audio_vae: bool = False, torch_compile_kwargs: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_dit: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_text_encoder: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_vae: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_audio_vae: dict&#91;str, Any&#93; = dict(), inference_torch_compile: bool = False, h3_vsa_fp4: dict&#91;str, Any&#93; = dict(), disable_autocast: bool = False, VSA_sparsity: float | None = None, VSA_tile_size: int | None = None, moba_config_path: str | None = None, moba_config: dict&#91;str, Any&#93; = dict(), master_port: int | None = None, enable_stage_verification: bool = True, prompt_txt: str | None = None, ltx2_vae_tiling: bool | None = None, ltx2_vae_spatial_tile_size_in_pixels: int | None = None, ltx2_vae_spatial_tile_overlap_in_pixels: int | None = None, ltx2_vae_temporal_tile_size_in_frames: int | None = None, ltx2_vae_temporal_tile_overlap_in_frames: int | None = None, ltx2_initial_latent_path: str | None = None, ltx2_audio_latent_path: str | None = None, refine_enabled: bool | None = None, refine_upsampler_path: str | None = None, refine_transformer_path: str | None = None, refine_lora_path: str | None = None, refine_num_inference_steps: int | None = None, refine_guidance_scale: float | None = None, refine_add_noise: bool | None = None, refine_noise_path: str | None = None, refine_audio_noise_path: str | None = None, ltx2_refine_enabled: bool = False, ltx2_refine_upsampler_path: str | None = None, ltx2_refine_transformer_path: str | None = None, ltx2_refine_lora_path: str | None = None, ltx2_refine_num_inference_steps: int = 3, ltx2_refine_guidance_scale: float = 1.0, ltx2_refine_add_noise: bool = True, ltx2_refine_noise_path: str | None = None, ltx2_refine_audio_noise_path: str | None = None, ltx2_legacy_native_noise_order: bool = False, ltx2_use_distilled_sigmas: bool = True, model_paths: dict&#91;str, str&#93; = dict(), model_loaded: dict&#91;str, bool&#93; = (lambda: &#123;&#x27;transformer&#x27;: True, &#x27;vae&#x27;: True, &#x27;upsampler&#x27;: True&#125;)(), override_text_encoder_safetensors: str | None = None, override_text_encoder_quant: QuantizationMethods = None, transformer_quant: Any | None = None, override_transformer_cls_name: str | None = None, init_weights_from_safetensors: str = &#x27;&#x27;, init_weights_from_safetensors_2: str = &#x27;&#x27;, override_pipeline_cls_name: str | None = None, boundary_ratio: float | None = 0.875)</code></pre>


<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.is_output_rank"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.is_output_rank</code></h3>
<pre class="doc-signature"><code>is_output_rank: bool</code></pre>
<p>Whether this process may materialize user-facing outputs.</p>
<p>This is runtime state assigned by an SPMD executor, not a public
configuration field, so dataclass serialization and typed config
parsing deliberately ignore it.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.add_cli_args"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.add_cli_args</code></h3>
<pre class="doc-signature"><code>add_cli_args(parser: FlexibleArgumentParser) -&gt; FlexibleArgumentParser</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.from_cli_args"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.from_cli_args</code></h3>
<pre class="doc-signature"><code>from_cli_args(args: argparse.Namespace) -&gt; FastVideoArgs</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.from_kwargs"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.from_kwargs</code></h3>
<pre class="doc-signature"><code>from_kwargs(**kwargs: Any) -&gt; FastVideoArgs</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.check_fastvideo_args"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.check_fastvideo_args</code></h3>
<pre class="doc-signature"><code>check_fastvideo_args() -&gt; None</code></pre>
<p>Validate inference arguments for consistency</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.finalize_device_offload_policy"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.finalize_device_offload_policy</code></h3>
<pre class="doc-signature"><code>finalize_device_offload_policy(device_id: int = 0) -&gt; bool</code></pre>
<p>Apply device-local memory policy, then resolve incompatible modes.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.disable_offload_on_unified_memory"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.FastVideoArgs.disable_offload_on_unified_memory</code></h3>
<pre class="doc-signature"><code>disable_offload_on_unified_memory(device_id: int = 0, *, offload_flag: str | None = None) -&gt; bool</code></pre>
<p>Disable host offload after a worker has selected its device.</p>
<p>CUDA's unified-memory probe reads runtime device properties and may
initialize a CUDA context. Callers must therefore use this only inside
a device-owning process, after selecting and binding <code>device_id</code>.
Returning the classification lets direct component-loader callers
apply the same policy to explicit per-call overrides. When
<code>offload_flag</code> is given, the return value says whether this policy
covers that component role.</p>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingArgs"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingArgs</code></h2>
<pre class="doc-signature"><code>TrainingArgs(model_path: str, mode: ExecutionMode = ExecutionMode.INFERENCE, workload_type: WorkloadType = WorkloadType.T2V, distributed_executor_backend: str = &#x27;mp&#x27;, enable_streaming_ipc_queues: bool = False, ray_placement_group: PlacementGroup | None = None, ray_runtime_env: RuntimeEnv | None = None, inference_mode: bool = True, trust_remote_code: bool = False, revision: str | None = None, num_gpus: int = 1, tp_size: int = -1, sp_size: int = -1, hsdp_replicate_dim: int = 1, hsdp_shard_dim: int = -1, dist_timeout: int | None = None, pipeline_config: PipelineConfig = PipelineConfig(), preprocess_config: PreprocessConfig | None = None, lora_path: str | None = None, lora_nickname: str = &#x27;default&#x27;, lora_strength: float = 1.0, lora_target_modules: list&#91;str&#93; | None = None, output_type: str = &#x27;pil&#x27;, attention_backend: str | None = None, dit_cpu_offload: bool = True, use_fsdp_inference: bool = False, dit_layerwise_offload: bool = True, text_encoder_cpu_offload: bool = True, image_encoder_cpu_offload: bool = True, vae_cpu_offload: bool = True, pin_cpu_memory: bool = True, h3_sequential_load: bool | None = None, h3_encoder_split: bool | None = None, h3_encoder_nodes: int = -1, h3_encoder_workers: int = 0, video_decode_backend: str = &#x27;h3-vae&#x27;, taeh3_checkpoint: str | None = None, taeh3_chunk_size: int = 5, h3_vae_nvfp4_decoder: str | None = None, lazy_module_load: bool | None = None, vae_parallel_decode: bool = False, vae_parallel_encode: bool = False, vae_parallel_decode_strategy: str | None = None, enable_torch_compile: bool = False, regional_compile: bool = False, enable_torch_compile_text_encoder: bool = False, enable_torch_compile_vae: bool = False, enable_torch_compile_audio_vae: bool = False, torch_compile_kwargs: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_dit: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_text_encoder: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_vae: dict&#91;str, Any&#93; = dict(), torch_compile_kwargs_audio_vae: dict&#91;str, Any&#93; = dict(), inference_torch_compile: bool = False, h3_vsa_fp4: dict&#91;str, Any&#93; = dict(), disable_autocast: bool = False, VSA_sparsity: float | None = None, VSA_tile_size: int | None = None, moba_config_path: str | None = None, moba_config: dict&#91;str, Any&#93; = dict(), master_port: int | None = None, enable_stage_verification: bool = True, prompt_txt: str | None = None, ltx2_vae_tiling: bool | None = None, ltx2_vae_spatial_tile_size_in_pixels: int | None = None, ltx2_vae_spatial_tile_overlap_in_pixels: int | None = None, ltx2_vae_temporal_tile_size_in_frames: int | None = None, ltx2_vae_temporal_tile_overlap_in_frames: int | None = None, ltx2_initial_latent_path: str | None = None, ltx2_audio_latent_path: str | None = None, refine_enabled: bool | None = None, refine_upsampler_path: str | None = None, refine_transformer_path: str | None = None, refine_lora_path: str | None = None, refine_num_inference_steps: int | None = None, refine_guidance_scale: float | None = None, refine_add_noise: bool | None = None, refine_noise_path: str | None = None, refine_audio_noise_path: str | None = None, ltx2_refine_enabled: bool = False, ltx2_refine_upsampler_path: str | None = None, ltx2_refine_transformer_path: str | None = None, ltx2_refine_lora_path: str | None = None, ltx2_refine_num_inference_steps: int = 3, ltx2_refine_guidance_scale: float = 1.0, ltx2_refine_add_noise: bool = True, ltx2_refine_noise_path: str | None = None, ltx2_refine_audio_noise_path: str | None = None, ltx2_legacy_native_noise_order: bool = False, ltx2_use_distilled_sigmas: bool = True, model_paths: dict&#91;str, str&#93; = dict(), model_loaded: dict&#91;str, bool&#93; = (lambda: &#123;&#x27;transformer&#x27;: True, &#x27;vae&#x27;: True, &#x27;upsampler&#x27;: True&#125;)(), override_text_encoder_safetensors: str | None = None, override_text_encoder_quant: QuantizationMethods = None, transformer_quant: Any | None = None, override_transformer_cls_name: str | None = None, init_weights_from_safetensors: str = &#x27;&#x27;, init_weights_from_safetensors_2: str = &#x27;&#x27;, override_pipeline_cls_name: str | None = None, boundary_ratio: float | None = 0.875, pipeline_class: str = &#x27;&#x27;, pipeline_module: str = &#x27;&#x27;, data_path: str = &#x27;&#x27;, dataloader_num_workers: int = 0, num_height: int = 0, num_width: int = 0, num_frames: int = 0, train_batch_size: int = 0, num_latent_t: int = 0, group_frame: bool = False, group_resolution: bool = False, pretrained_model_name_or_path: str = &#x27;&#x27;, real_score_model_path: str = &#x27;&#x27;, fake_score_model_path: str = &#x27;&#x27;, ema_decay: float = 0.0, ema_start_step: int = 0, training_cfg_rate: float = 0.0, precondition_outputs: bool = False, validation_dataset_file: str = &#x27;&#x27;, validation_preprocessed_path: str = &#x27;&#x27;, validation_sampling_steps: str = &#x27;&#x27;, validation_guidance_scale: str = &#x27;&#x27;, validation_steps: float = 0.0, log_validation: bool = False, trackers: list&#91;str&#93; = list(), tracker_project_name: str = &#x27;&#x27;, wandb_run_name: str = &#x27;&#x27;, seed: int | None = None, output_dir: str = &#x27;&#x27;, checkpoints_total_limit: int = 0, resume_from_checkpoint: str = &#x27;&#x27;, num_train_epochs: int = 0, max_train_steps: int = 0, gradient_accumulation_steps: int = 0, learning_rate: float = 0.0, scale_lr: bool = False, lr_scheduler: str = &#x27;constant&#x27;, lr_warmup_steps: int = 0, max_grad_norm: float = 0.0, enable_gradient_checkpointing_type: str | None = None, selective_checkpointing: float = 0.0, mixed_precision: str = &#x27;&#x27;, train_sp_batch_size: int = 0, fsdp_sharding_startegy: str = &#x27;&#x27;, weighting_scheme: str = &#x27;&#x27;, logit_mean: float = 0.0, logit_std: float = 1.0, mode_scale: float = 0.0, num_euler_timesteps: int = 0, lr_num_cycles: int = 0, lr_power: float = 0.0, min_lr_ratio: float = 0.5, not_apply_cfg_solver: bool = False, distill_cfg: float = 0.0, scheduler_type: str = &#x27;&#x27;, linear_quadratic_threshold: float = 0.0, linear_range: float = 0.0, weight_decay: float = 0.0, betas: str = &#x27;0.9,0.999&#x27;, use_ema: bool = False, multi_phased_distill_schedule: str = &#x27;&#x27;, pred_decay_weight: float = 0.0, pred_decay_type: str = &#x27;&#x27;, hunyuan_teacher_disable_cfg: bool = False, master_weight_type: str = &#x27;&#x27;, VSA_decay_rate: float = 0.01, VSA_decay_interval_steps: int = 1, VSA_cache_tile_buf: bool = False, lora_rank: int | None = None, lora_alpha: int | None = None, lora_training: bool = False, ltx2_first_frame_conditioning_p: float = 0.1, generator_update_interval: int = 5, dfake_gen_update_ratio: int = 5, min_timestep_ratio: float = 0.2, max_timestep_ratio: float = 0.98, real_score_guidance_scale: float = 3.5, fake_score_learning_rate: float = 0.0, fake_score_lr_scheduler: str = &#x27;constant&#x27;, fake_score_betas: str = &#x27;0.9,0.999&#x27;, training_state_checkpointing_steps: int = 0, weight_only_checkpointing_steps: int = 0, log_visualization: bool = False, visualization_steps: int = 0, simulate_generator_forward: bool = False, warp_denoising_step: bool = False, num_frame_per_block: int = 3, independent_first_frame: bool = False, enable_gradient_masking: bool = True, gradient_mask_last_n_frames: int = 21, same_step_across_blocks: bool = False, last_step_only: bool = False, context_noise: int = 0)</code></pre>
<p>Training arguments. Inherits from FastVideoArgs and adds training-specific
arguments. If there are any conflicts, the training arguments will take
precedence.</p>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingArgs.from_cli_args"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingArgs.from_cli_args</code></h3>
<pre class="doc-signature"><code>from_cli_args(args: argparse.Namespace) -&gt; TrainingArgs</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingArgs.add_cli_args"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingArgs.add_cli_args</code></h3>
<pre class="doc-signature"><code>add_cli_args(parser: FlexibleArgumentParser) -&gt; FlexibleArgumentParser</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.set_forward_context"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.set_forward_context</code></h2>
<pre class="doc-signature"><code>set_forward_context(current_timestep, attn_metadata, forward_batch: Optional&#91;ForwardBatch&#93; = None)</code></pre>
<p>A context manager that stores the current forward context,
can be attention metadata, etc.
Here we can inject common logic for every model forward pass.</p>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.init_logger"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.init_logger</code></h2>
<pre class="doc-signature"><code>init_logger(name: str) -&gt; _FastvideoLogger</code></pre>
<p>The main purpose of this function is to ensure that loggers are
retrieved in such a way that we can be sure the root fastvideo logger has
already been configured.</p>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler</code></h2>
<pre class="doc-signature"><code>SelfForcingFlowMatchScheduler(num_inference_steps = 100, num_train_timesteps = 1000, shift = 3.0, sigma_max = 1.0, sigma_min = 0.003 / 1.002, inverse_timesteps = False, extra_one_step = False, reverse_sigmas = False, training = False)</code></pre>


<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.set_timesteps"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.set_timesteps</code></h3>
<pre class="doc-signature"><code>set_timesteps(num_inference_steps = 100, denoising_strength = 1.0, training = False, return_dict = False, **kwargs)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.step"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.step</code></h3>
<pre class="doc-signature"><code>step(model_output: torch.FloatTensor, timestep: torch.FloatTensor, sample: torch.FloatTensor, to_final = False, return_dict = False, **kwargs)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.calculate_alpha_beta_high"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.calculate_alpha_beta_high</code></h3>
<pre class="doc-signature"><code>calculate_alpha_beta_high(sigma, sigma_bound)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.add_noise"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.add_noise</code></h3>
<pre class="doc-signature"><code>add_noise(original_samples, noise, timestep)</code></pre>
<p>Diffusion forward corruption process.
Input:
    - clean_latent: the clean latent with shape [B<em>T, C, H, W]
    - noise: the noise with shape [B</em>T, C, H, W]
    - timestep: the timestep with shape [B<em>T]
Output: the corrupted latent with shape [B</em>T, C, H, W]</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.add_noise_high"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.add_noise_high</code></h3>
<pre class="doc-signature"><code>add_noise_high(original_samples, noise, timestep, boundary_timestep)</code></pre>
<p>Diffusion forward corruption process.
Input:
    - clean_latent: the clean latent with shape [B<em>T, C, H, W]
    - noise: the noise with shape [B</em>T, C, H, W]
    - timestep: the timestep with shape [B<em>T]
Output: the corrupted latent with shape [B</em>T, C, H, W]</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.training_target"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.training_target</code></h3>
<pre class="doc-signature"><code>training_target(sample, noise, timestep)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.training_weight"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.training_weight</code></h3>
<pre class="doc-signature"><code>training_weight(timestep)</code></pre>
<h4>Input</h4>
<ul>
<li>timestep: the timestep with shape [B*T]</li>
</ul>
<p>Output: the corresponding weighting [B*T]</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.scale_model_input"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.scale_model_input</code></h3>
<pre class="doc-signature"><code>scale_model_input(sample: torch.Tensor, timestep: int | None = None) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.set_shift"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingFlowMatchScheduler.set_shift</code></h3>
<pre class="doc-signature"><code>set_shift(shift: float) -&gt; None</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.pred_noise_to_pred_video"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.pred_noise_to_pred_video</code></h2>
<pre class="doc-signature"><code>pred_noise_to_pred_video(pred_noise: torch.Tensor, noise_input_latent: torch.Tensor, timestep: torch.Tensor, scheduler: Any) -&gt; torch.Tensor</code></pre>
<p>Convert predicted noise to clean latent.</p>
<p>pred_noise: the predicted noise with shape [B, C, H, W]
    where B is batch_size or batch_size * num_frames
noise_input_latent: the noisy latent with shape [B, C, H, W],
timestep: the timestep with shape [1] or [bs * num_frames] or [bs, num_frames]
scheduler: the scheduler</p>
<h3>Returns</h3>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p>the predicted video with shape [B, C, H, W]</p></dd>
</dl>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase</code></h2>
<pre class="doc-signature"><code>ComposedPipelineBase(model_path: str, fastvideo_args: FastVideoArgs | TrainingArgs, required_config_modules: list&#91;str&#93; | None = None, loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None)</code></pre>
<p>Base class for pipelines composed of multiple stages.</p>
<p>This class provides the framework for creating pipelines by composing multiple
stages together. Each stage is responsible for a specific part of the diffusion
process, and the pipeline orchestrates the execution of these stages.</p>
<p>Initialize the pipeline. After <strong>init</strong>, the pipeline should be ready to
use. The pipeline should be stateless and not hold any batch state.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.get_hf_download_component_dirs"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.get_hf_download_component_dirs</code></h3>
<pre class="doc-signature"><code>get_hf_download_component_dirs() -&gt; tuple&#91;str, ...&#93; | None</code></pre>
<p>Return component directories for an opt-in partial Hub download.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.get_hf_download_allow_patterns"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.get_hf_download_allow_patterns</code></h3>
<pre class="doc-signature"><code>get_hf_download_allow_patterns() -&gt; list&#91;str&#93; | None</code></pre>
<p>Return Hub patterns for the manifest and selected components.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.set_trainable"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.set_trainable</code></h3>
<pre class="doc-signature"><code>set_trainable() -&gt; None</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.post_init"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.post_init</code></h3>
<pre class="doc-signature"><code>post_init() -&gt; None</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.initialize_training_pipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.initialize_training_pipeline</code></h3>
<pre class="doc-signature"><code>initialize_training_pipeline(training_args: TrainingArgs)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.initialize_validation_pipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.initialize_validation_pipeline</code></h3>
<pre class="doc-signature"><code>initialize_validation_pipeline(training_args: TrainingArgs)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.from_pretrained"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.from_pretrained</code></h3>
<pre class="doc-signature"><code>from_pretrained(model_path: str, device: str | None = None, torch_dtype: torch.dtype | None = None, pipeline_config: str | PipelineConfig | None = None, args: argparse.Namespace | None = None, required_config_modules: list&#91;str&#93; | None = None, loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None, **kwargs) -&gt; ComposedPipelineBase</code></pre>
<p>Load a pipeline from a pretrained model.
loaded_modules: Optional[Dict[str, torch.nn.Module]] = None,
If provided, loaded_modules will be used instead of loading from config/pretrained weights.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.get_module"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.get_module</code></h3>
<pre class="doc-signature"><code>get_module(module_name: str, default_value: Any = None) -&gt; Any</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.add_module"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.add_module</code></h3>
<pre class="doc-signature"><code>add_module(module_name: str, module: Any)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.required_config_modules"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.required_config_modules</code></h3>
<pre class="doc-signature"><code>required_config_modules: list&#91;str&#93;</code></pre>
<p>List of modules that are required by the pipeline. The names should match
the diffusers directory and model_index.json file. These modules will be
loaded using the PipelineComponentLoader and made available in the
modules dictionary. Access these modules using the get_module method.</p>
<p>class ConcretePipeline(ComposedPipelineBase):
    _required_config_modules = ["vae", "text_encoder", "transformer", "scheduler", "tokenizer"]</p>
<pre><code>@property
def required_config_modules(self):
    return self._required_config_modules
</code></pre>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.stages"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.stages</code></h3>
<pre class="doc-signature"><code>stages: list&#91;PipelineStage&#93;</code></pre>
<p>List of stages in the pipeline.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.create_pipeline_stages"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.create_pipeline_stages</code></h3>
<pre class="doc-signature"><code>create_pipeline_stages(fastvideo_args: FastVideoArgs)</code></pre>
<p>Create the inference pipeline stages.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.create_training_stages"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.create_training_stages</code></h3>
<pre class="doc-signature"><code>create_training_stages(training_args: TrainingArgs)</code></pre>
<p>Create the training pipeline stages.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.initialize_pipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.initialize_pipeline</code></h3>
<pre class="doc-signature"><code>initialize_pipeline(fastvideo_args: FastVideoArgs)</code></pre>
<p>Initialize the pipeline.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.load_modules"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.load_modules</code></h3>
<pre class="doc-signature"><code>load_modules(fastvideo_args: FastVideoArgs, loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None) -&gt; dict&#91;str, Any&#93;</code></pre>
<p>Load the modules from the config.
loaded_modules: Optional[Dict[str, torch.nn.Module]] = None, 
If provided, loaded_modules will be used instead of loading from config/pretrained weights.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.add_stage"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.add_stage</code></h3>
<pre class="doc-signature"><code>add_stage(stage_name: str, stage: PipelineStage)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.forward"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>
<p>Generate a video or image using the pipeline.</p>
<h4>Parameters</h4>
<dl>
<dt><code>batch: ForwardBatch</code></dt><dd><p>The batch to generate from.</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>The inference arguments.</p></dd>
</dl>
<p>Returns:
    ForwardBatch: The batch with the generated video or image.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.train"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.train</code></h3>
<pre class="doc-signature"><code>train() -&gt; None</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.close"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ComposedPipelineBase.close</code></h3>
<pre class="doc-signature"><code>close() -&gt; None</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline</code></h2>
<pre class="doc-signature"><code>MatrixGame2CausalDMDPipeline(*args, **kwargs)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.create_pipeline_stages"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.create_pipeline_stages</code></h3>
<pre class="doc-signature"><code>create_pipeline_stages(fastvideo_args: FastVideoArgs) -&gt; None</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.streaming_reset"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.streaming_reset</code></h3>
<pre class="doc-signature"><code>streaming_reset(batch: ForwardBatch, fastvideo_args: FastVideoArgs)</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.streaming_step"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.streaming_step</code></h3>
<pre class="doc-signature"><code>streaming_step(keyboard_action, mouse_action) -&gt; ForwardBatch</code></pre>

<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.streaming_clear"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2CausalDMDPipeline.streaming_clear</code></h3>
<pre class="doc-signature"><code>streaming_clear() -&gt; None</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ForwardBatch"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.ForwardBatch</code></h2>
<pre class="doc-signature"><code>ForwardBatch(data_type: str, generator: torch.Generator | list&#91;torch.Generator&#93; | None = None, image_path: str | None = None, image_embeds: list&#91;torch.Tensor&#93; = list(), pil_image: torch.Tensor | PIL.Image.Image | None = None, last_image: torch.Tensor | PIL.Image.Image | None = None, references: list&#91;Any&#93; | None = None, preprocessed_image: torch.Tensor | None = None, prompt: str | list&#91;str&#93; | None = None, negative_prompt: str | list&#91;str&#93; | None = None, prompt_path: str | None = None, output_path: str = &#x27;outputs/&#x27;, output_video_name: str | None = None, video_path: str | None = None, video_latent: torch.Tensor | None = None, pose_video_path: str | None = None, face_video_path: str | None = None, background_video_path: str | None = None, mask_video_path: str | None = None, animate_mode: str | None = None, pose_latents: torch.Tensor | None = None, face_pixel_values: torch.Tensor | None = None, audio_path: str | None = None, audio_embeds: torch.Tensor | None = None, t_thresh: float = 0.5, num_cond_frames: int = 0, prompt_embeds: list&#91;torch.Tensor&#93; = list(), negative_prompt_embeds: list&#91;torch.Tensor&#93; | None = None, prompt_attention_mask: list&#91;torch.Tensor&#93; | None = None, negative_attention_mask: list&#91;torch.Tensor&#93; | None = None, clip_embedding_pos: list&#91;torch.Tensor&#93; | None = None, clip_embedding_neg: list&#91;torch.Tensor&#93; | None = None, max_sequence_length: int | None = None, prompt_template: dict&#91;str, Any&#93; | None = None, do_classifier_free_guidance: bool = False, use_embedded_guidance: bool = False, true_cfg_scale: float = 1.0, batch_size: int | None = None, num_videos_per_prompt: int = 1, seed: int | None = None, seeds: list&#91;int&#93; | None = None, is_prompt_processed: bool = False, latents: torch.Tensor | None = None, audio_latents: torch.Tensor | None = None, lq_latents: torch.Tensor | None = None, raw_latent_shape: tuple&#91;int, ...&#93; | None = None, noise_pred: torch.Tensor | None = None, image_latent: torch.Tensor | None = None, first_frame_latent: torch.Tensor | None = None, helios_latent_chunks: list&#91;torch.Tensor&#93; | None = None, mouse_cond: torch.Tensor | None = None, keyboard_cond: torch.Tensor | None = None, grid_sizes: torch.Tensor | None = None, num_iterations: int | None = None, use_base_model: bool = False, pose: str | None = None, c2ws_plucker_emb: torch.Tensor | None = None, action_path: str | None = None, trajectory_type: str | None = None, movement_distance: float | None = None, camera_rotation: str | None = None, height_latents: list&#91;int&#93; | int | None = None, width_latents: list&#91;int&#93; | int | None = None, num_frames: list&#91;int&#93; | int = 1, height: list&#91;int&#93; | int | None = None, width: list&#91;int&#93; | int | None = None, height_sr: list&#91;int&#93; | int | None = None, width_sr: list&#91;int&#93; | int | None = None, fps: list&#91;int&#93; | int | None = None, timesteps: torch.Tensor | None = None, timestep: torch.Tensor | float | int | None = None, step_index: int | None = None, boundary_ratio: float | None = None, num_inference_steps: int = 50, num_inference_steps_sr: int = 50, guidance_scale: float = 1.0, batch_cfg: bool = False, guidance_scale_2: float | None = None, guidance_rescale: float = 0.0, eta: float = 0.0, sigmas: list&#91;float&#93; | None = None, pyramid_num_inference_steps_list: list&#91;int&#93; | None = None, history_sizes: list&#91;int&#93; | None = None, num_latent_frames_per_chunk: int = 9, keep_first_frame: bool = True, is_skip_first_chunk: bool = False, use_zero_init: bool = True, zero_steps: int = 1, is_amplify_first_chunk: bool = False, enable_teacache: bool = False, ltx2_cfg_scale_video: float = 1.0, ltx2_cfg_scale_audio: float = 1.0, ltx2_modality_scale_video: float = 1.0, ltx2_modality_scale_audio: float = 1.0, ltx2_rescale_scale: float = 0.0, ltx2_stg_scale_video: float = 0.0, ltx2_stg_scale_audio: float = 0.0, ltx2_stg_blocks_video: list&#91;int&#93; = list(), ltx2_stg_blocks_audio: list&#91;int&#93; = list(), ltx2_use_ancestral_sampler: bool = False, ltx2_images: list&#91;tuple&#91;str, int, float&#93;&#93; | None = None, ltx2_image_crf: float = 33.0, ltx2_conditioning_latent_stage1: torch.Tensor | None = None, ltx2_conditioning_latent_stage2: torch.Tensor | None = None, ltx2_video_conditions: list&#91;tuple&#91;list&#91;str&#93;, int, float&#93;&#93; | None = None, audio_start_in_s: float | None = None, audio_end_in_s: float | None = None, init_audio: Any = None, init_audio_strength: float | None = None, init_noise_level: float | None = None, inpaint_audio: Any = None, inpaint_mask: Any = None, n_tokens: int | None = None, extra_step_kwargs: dict&#91;str, Any&#93; = dict(), modules: dict&#91;str, Any&#93; = dict(), output: torch.Tensor | None = None, return_trajectory_latents: bool = False, return_trajectory_decoded: bool = False, trajectory_timesteps: list&#91;torch.Tensor&#93; | None = None, trajectory_latents: torch.Tensor | None = None, trajectory_decoded: list&#91;torch.Tensor&#93; | None = None, continuation_state: ContinuationState | None = None, return_continuation_state: bool = False, extra: dict&#91;str, Any&#93; = dict(), save_video: bool = True, return_frames: bool = False, is_cfg_negative: bool = False, VSA_sparsity: float = 0.0, logging_info: PipelineLoggingInfo = PipelineLoggingInfo(), *, return_samples: bool = False)</code></pre>
<p>Complete state passed through the pipeline execution.</p>
<p>This dataclass contains all information needed during the diffusion pipeline
execution, allowing methods to update specific components without needing
to manage numerous individual parameters.</p>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingBatch"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.TrainingBatch</code></h2>
<pre class="doc-signature"><code>TrainingBatch(current_timestep: int = 0, current_vsa_sparsity: float = 0.0, latents: torch.Tensor | None = None, raw_latent_shape: tuple&#91;int, ...&#93; | None = None, noise_latents: torch.Tensor | None = None, encoder_hidden_states: torch.Tensor | None = None, encoder_attention_mask: torch.Tensor | None = None, audio_latents: torch.Tensor | None = None, audio_noisy_model_input: torch.Tensor | None = None, audio_timesteps: torch.Tensor | None = None, audio_sigmas: torch.Tensor | None = None, audio_noise: torch.Tensor | None = None, audio_encoder_hidden_states: torch.Tensor | None = None, audio_encoder_attention_mask: torch.Tensor | None = None, conditioning_mask: torch.Tensor | None = None, preprocessed_image: torch.Tensor | None = None, image_embeds: torch.Tensor | None = None, image_latents: torch.Tensor | None = None, infos: list&#91;dict&#91;str, Any&#93;&#93; | None = None, mask_lat_size: torch.Tensor | None = None, trajectory_latents: torch.Tensor | None = None, trajectory_timesteps: torch.Tensor | None = None, noisy_model_input: torch.Tensor | None = None, timesteps: torch.Tensor | None = None, sigmas: torch.Tensor | None = None, noise: torch.Tensor | None = None, training_target: torch.Tensor | None = None, minimax_h3_layout: Any | None = None, attn_metadata_vsa: AttentionMetadata | None = None, attn_metadata: AttentionMetadata | None = None, input_kwargs: dict&#91;str, Any&#93; | None = None, loss: torch.Tensor | None = None, total_loss: float | None = None, grad_norm: float | None = None, encoder_hidden_states_neg: torch.Tensor | None = None, encoder_attention_mask_neg: torch.Tensor | None = None, conditional_dict: dict&#91;str, Any&#93; | None = None, unconditional_dict: dict&#91;str, Any&#93; | None = None, generator_loss: float = 0.0, fake_score_loss: float = 0.0, dmd_latent_vis_dict: dict&#91;str, Any&#93; = dict(), latent_vis_dict: dict&#91;str, Any&#93; = dict(), fake_score_latent_vis_dict: dict&#91;str, Any&#93; = dict(), minimax_h3_condition_video_rows: torch.Tensor | None = None, minimax_h3_condition_audio_rows: torch.Tensor | None = None, minimax_h3_dmd_layout: Any | None = None, minimax_h3_document_video_latents: tuple&#91;torch.Tensor, ...&#93; | None = None, minimax_h3_document_audio_latents: tuple&#91;torch.Tensor, ...&#93; | None = None, minimax_h3_text_attn_metadata: AttentionMetadata | None = None, sequence_packing_num_documents: int = 1, sequence_packing_num_tokens: int = 0, sequence_padded_num_tokens: int = 0, sequence_padding_ratio: float | None = None, sequence_packing_loss_scale: float = 1.0, sequence_packing_data_forced_ratio: float | None = None)</code></pre>


<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline</code></h2>
<pre class="doc-signature"><code>SelfForcingDistillationPipeline(model_path: str, fastvideo_args: TrainingArgs, required_config_modules: list&#91;str&#93; | None = None, loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None)</code></pre>
<p>A self-forcing distillation pipeline that alternates between training
the generator and critic based on the self-forcing methodology.</p>
<p>This implementation follows the self-forcing approach where:
1. Generator and critic are trained in alternating steps
2. Generator loss uses DMD-style loss with the critic as fake score
3. Critic loss trains the fake score model to distinguish real vs fake</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.initialize_training_pipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.initialize_training_pipeline</code></h3>
<pre class="doc-signature"><code>initialize_training_pipeline(training_args: TrainingArgs)</code></pre>
<p>Initialize the self-forcing training pipeline.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.generate_and_sync_list"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.generate_and_sync_list</code></h3>
<pre class="doc-signature"><code>generate_and_sync_list(num_blocks: int, num_denoising_steps: int, device: torch.device) -&gt; list&#91;int&#93;</code></pre>
<p>Generate and synchronize random exit flags across distributed processes.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.generator_loss"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.generator_loss</code></h3>
<pre class="doc-signature"><code>generator_loss(training_batch: TrainingBatch) -&gt; tuple&#91;torch.Tensor, dict&#91;str, Any&#93;&#93;</code></pre>
<p>Compute generator loss using DMD-style approach.
The generator tries to fool the critic (fake_score_transformer).</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.critic_loss"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.critic_loss</code></h3>
<pre class="doc-signature"><code>critic_loss(training_batch: TrainingBatch) -&gt; tuple&#91;torch.Tensor, dict&#91;str, Any&#93;&#93;</code></pre>
<p>Compute critic loss using flow matching between noise and generator output.
The critic learns to predict the flow from noise to the generator's output.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.train_one_step"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.train_one_step</code></h3>
<pre class="doc-signature"><code>train_one_step(training_batch: TrainingBatch) -&gt; TrainingBatch</code></pre>
<p>Self-forcing training step that alternates between generator and critic training.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.visualize_intermediate_latents"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.visualize_intermediate_latents</code></h3>
<pre class="doc-signature"><code>visualize_intermediate_latents(training_batch: TrainingBatch, training_args: TrainingArgs, step: int)</code></pre>
<p>Add visualization data to tracker logging and save frames to disk.</p>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.train"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.SelfForcingDistillationPipeline.train</code></h3>
<pre class="doc-signature"><code>train() -&gt; None</code></pre>
<p>Main training loop with self-forcing specific logging.</p>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.shift_timestep"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.shift_timestep</code></h2>
<pre class="doc-signature"><code>shift_timestep(timestep: torch.Tensor, shift: float, num_train_timestep: float) -&gt; torch.Tensor</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.is_vsa_available"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.is_vsa_available</code></h2>
<pre class="doc-signature"><code>is_vsa_available() -&gt; bool</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.shallow_asdict"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.shallow_asdict</code></h2>
<pre class="doc-signature"><code>shallow_asdict(obj) -&gt; dict&#91;str, Any&#93;</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline</code></h2>
<pre class="doc-signature"><code>MatrixGame2SelfForcingDistillationPipeline(model_path: str, fastvideo_args: TrainingArgs, required_config_modules: list&#91;str&#93; | None = None, loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None)</code></pre>
<p>A self-forcing distillation pipeline for Matrix-Game 2.0 that uses the self-forcing methodology
with DMD for video generation.</p>
<details><summary>Source</summary><pre><code>class MatrixGame2SelfForcingDistillationPipeline(SelfForcingDistillationPipeline):
    &quot;&quot;&quot;
    A self-forcing distillation pipeline for Matrix-Game 2.0 that uses the self-forcing methodology
    with DMD for video generation.
    &quot;&quot;&quot;
    _required_config_modules = &#91;
        &quot;scheduler&quot;,
        &quot;transformer&quot;,
        &quot;vae&quot;,
        &quot;image_encoder&quot;,
        &quot;image_processor&quot;,
    &#93;

    def set_schemas(self):
        self.train_dataset_schema = pyarrow_schema_matrixgame2

    def load_modules(
        self,
        fastvideo_args: FastVideoArgs,
        loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None,
    ) -&gt; dict&#91;str, Any&#93;:
        modules = ComposedPipelineBase.load_modules(
            self,
            fastvideo_args,
            loaded_modules,
        )
        training_args = cast(TrainingArgs, fastvideo_args)
        old_override = training_args.override_transformer_cls_name
        training_args.override_transformer_cls_name = &quot;MatrixGame2WanModel&quot;
        try:
            if loaded_modules is not None and &quot;real_score_transformer&quot; in loaded_modules:
                self.real_score_transformer = loaded_modules&#91;&quot;real_score_transformer&quot;&#93;
            elif training_args.real_score_model_path:
                logger.info(
                    &quot;Loading real score transformer from: %s&quot;,
                    training_args.real_score_model_path,
                )
                self.real_score_transformer = self.load_module_from_path(
                    training_args.real_score_model_path,
                    &quot;transformer&quot;,
                    training_args,
                )
            else:
                raise ValueError(&quot;real_score_model_path is required for DMD distillation pipeline&quot;)
            modules&#91;&quot;real_score_transformer&quot;&#93; = self.real_score_transformer

            if loaded_modules is not None and &quot;fake_score_transformer&quot; in loaded_modules:
                self.fake_score_transformer = loaded_modules&#91;&quot;fake_score_transformer&quot;&#93;
            elif training_args.fake_score_model_path:
                logger.info(
                    &quot;Loading fake score transformer from: %s&quot;,
                    training_args.fake_score_model_path,
                )
                self.fake_score_transformer = self.load_module_from_path(
                    training_args.fake_score_model_path,
                    &quot;transformer&quot;,
                    training_args,
                )
            else:
                raise ValueError(&quot;fake_score_model_path is required for DMD distillation pipeline&quot;)
            modules&#91;&quot;fake_score_transformer&quot;&#93; = self.fake_score_transformer
        finally:
            training_args.override_transformer_cls_name = old_override

        self.real_score_transformer_2 = None
        self.fake_score_transformer_2 = None
        return modules

    def _build_matrixgame_cond_concat(
        self,
        image_latents: torch.Tensor,
    ) -&gt; torch.Tensor:
        if image_latents.ndim != 5:
            raise ValueError(&quot;first_frame_latent must have shape &#91;B, C, T, H, W&#93;, got &quot;
                             f&quot;&#123;tuple(image_latents.shape)&#125;&quot;)
        if image_latents.shape&#91;1&#93; != 16:
            raise ValueError(&quot;Matrix-Game 2.0 cond conversion expects a 16-channel &quot;
                             f&quot;first_frame_latent, got &#123;image_latents.shape&#91;1&#93;&#125; channels.&quot;)

        temporal_compression_ratio = (
            self.training_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio)
        num_latent_t = image_latents.shape&#91;2&#93;
        num_frames = ((num_latent_t - 1) * temporal_compression_ratio + 1)
        batch_size, _, _, latent_height, latent_width = image_latents.shape

        mask_lat_size = torch.ones(
            batch_size,
            1,
            num_frames,
            latent_height,
            latent_width,
            device=image_latents.device,
            dtype=image_latents.dtype,
        )
        mask_lat_size&#91;:, :, 1:&#93; = 0

        first_frame_mask = mask_lat_size&#91;:, :, :1&#93;
        first_frame_mask = torch.repeat_interleave(
            first_frame_mask,
            dim=2,
            repeats=temporal_compression_ratio,
        )
        mask_lat_size = torch.cat(
            &#91;first_frame_mask, mask_lat_size&#91;:, :, 1:&#93;&#93;,
            dim=2,
        )
        mask_lat_size = mask_lat_size.view(
            batch_size,
            -1,
            temporal_compression_ratio,
            latent_height,
            latent_width,
        )
        mask_lat_size = mask_lat_size.transpose(1, 2).to(
            image_latents.device,
            dtype=image_latents.dtype,
        )

        return torch.cat(&#91;mask_lat_size, image_latents&#93;, dim=1)

    def _initialize_simulation_caches(
        self,
        batch_size: int,
        dtype: torch.dtype,
        device: torch.device,
    ) -&gt; tuple&#91;list&#91;dict&#91;str, Any&#93;&#93;, list&#91;dict&#91;str, Any&#93;&#93;, list&#91;dict&#91;str, Any&#93; | None&#93;, list&#91;dict&#91;str, Any&#93; | None&#93;&#93;:
        &quot;&quot;&quot;Initialize KV cache and cross-attention cache for multi-step simulation.&quot;&quot;&quot;
        num_transformer_blocks = len(self.transformer.blocks)
        latent_shape = self.video_latent_shape_sp
        _, num_frames, _, height, width = latent_shape

        _, p_h, p_w = self.transformer.patch_size
        post_patch_height = height // p_h
        post_patch_width = width // p_w

        frame_seq_length = post_patch_height * post_patch_width
        self.frame_seq_length = frame_seq_length

        # Get model configuration parameters - handle FSDP wrapping
        num_attention_heads = getattr(self.transformer, &#x27;num_attention_heads&#x27;, None)
        attention_head_dim = getattr(self.transformer, &#x27;attention_head_dim&#x27;, None)

        # 1 CLS token + 256 patch tokens = 257
        text_len = 257

        action_config = getattr(self.transformer, &#x27;action_config&#x27;, &#123;&#125;)
        action_blocks = action_config.get(&#x27;blocks&#x27;, &#91;&#93;) if action_config else &#91;&#93;
        local_attn_size = getattr(self.transformer, &quot;local_attn_size&quot;,
                                  action_config.get(&#x27;local_attn_size&#x27;, 6) if action_config else 6)

        if local_attn_size &lt;= 0:
            raise ValueError(&quot;Matrix-Game 2.0 self-forcing requires transformer.local_attn_size &gt; 0&quot;)
        kv_cache_size = local_attn_size * frame_seq_length

        kv_cache = &#91;&#93;
        for _ in range(num_transformer_blocks):
            kv_cache.append(&#123;
                &quot;k&quot;:
                torch.zeros(&#91;batch_size, kv_cache_size, num_attention_heads, attention_head_dim&#93;,
                            dtype=dtype,
                            device=device),
                &quot;v&quot;:
                torch.zeros(&#91;batch_size, kv_cache_size, num_attention_heads, attention_head_dim&#93;,
                            dtype=dtype,
                            device=device),
                &quot;global_end_index&quot;:
                torch.tensor(&#91;0&#93;, dtype=torch.long, device=device),
                &quot;local_end_index&quot;:
                torch.tensor(&#91;0&#93;, dtype=torch.long, device=device)
            &#125;)

        # Initialize cross-attention cache
        crossattn_cache = &#91;&#93;
        for _ in range(num_transformer_blocks):
            crossattn_cache.append(&#123;
                &quot;k&quot;:
                torch.zeros(&#91;batch_size, text_len, num_attention_heads, attention_head_dim&#93;, dtype=dtype,
                            device=device),
                &quot;v&quot;:
                torch.zeros(&#91;batch_size, text_len, num_attention_heads, attention_head_dim&#93;, dtype=dtype,
                            device=device),
                &quot;is_init&quot;:
                False
            &#125;)

        # Initialize action module KV caches
        action_heads_num = action_config.get(&#x27;heads_num&#x27;, 16) if action_config else 16
        mouse_hidden_dim = action_config.get(&#x27;mouse_hidden_dim&#x27;, 1024) if action_config else 1024
        keyboard_hidden_dim = action_config.get(&#x27;keyboard_hidden_dim&#x27;, 1024) if action_config else 1024

        mouse_head_dim = mouse_hidden_dim // action_heads_num
        keyboard_head_dim = keyboard_hidden_dim // action_heads_num

        kv_cache_mouse: list&#91;dict&#91;str, Any&#93; | None&#93; = &#91;&#93;
        kv_cache_keyboard: list&#91;dict&#91;str, Any&#93; | None&#93; = &#91;&#93;
        for block_idx in range(num_transformer_blocks):
            if block_idx in action_blocks:
                kv_cache_mouse.append(&#123;
                    &quot;k&quot;:
                    torch.zeros(&#91;batch_size * frame_seq_length, local_attn_size, action_heads_num, mouse_head_dim&#93;,
                                dtype=dtype,
                                device=device),
                    &quot;v&quot;:
                    torch.zeros(&#91;batch_size * frame_seq_length, local_attn_size, action_heads_num, mouse_head_dim&#93;,
                                dtype=dtype,
                                device=device),
                    &quot;global_end_index&quot;:
                    torch.tensor(&#91;0&#93;, dtype=torch.long, device=device),
                    &quot;local_end_index&quot;:
                    torch.tensor(&#91;0&#93;, dtype=torch.long, device=device)
                &#125;)
                kv_cache_keyboard.append(&#123;
                    &quot;k&quot;:
                    torch.zeros(&#91;batch_size, local_attn_size, action_heads_num, keyboard_head_dim&#93;,
                                dtype=dtype,
                                device=device),
                    &quot;v&quot;:
                    torch.zeros(&#91;batch_size, local_attn_size, action_heads_num, keyboard_head_dim&#93;,
                                dtype=dtype,
                                device=device),
                    &quot;global_end_index&quot;:
                    torch.tensor(&#91;0&#93;, dtype=torch.long, device=device),
                    &quot;local_end_index&quot;:
                    torch.tensor(&#91;0&#93;, dtype=torch.long, device=device)
                &#125;)
            else:
                kv_cache_mouse.append(None)
                kv_cache_keyboard.append(None)

        return kv_cache, crossattn_cache, kv_cache_mouse, kv_cache_keyboard

    def _reset_simulation_caches(self, kv_cache: list&#91;dict&#91;str, Any&#93;&#93;, crossattn_cache: list&#91;dict&#91;str, Any&#93;&#93;,
                                 kv_cache_mouse: list&#91;dict&#91;str, Any&#93;
                                                      | None&#93; | None, kv_cache_keyboard: list&#91;dict&#91;str, Any&#93;
                                                                                              | None&#93; | None) -&gt; None:
        &quot;&quot;&quot;Reset KV cache, cross-attention cache, and action caches to clean state.&quot;&quot;&quot;
        if kv_cache is not None:
            for cache_dict in kv_cache:
                cache_dict&#91;&quot;global_end_index&quot;&#93;.fill_(0)
                cache_dict&#91;&quot;local_end_index&quot;&#93;.fill_(0)
                cache_dict&#91;&quot;k&quot;&#93;.zero_()
                cache_dict&#91;&quot;v&quot;&#93;.zero_()

        if crossattn_cache is not None:
            for cache_dict in crossattn_cache:
                cache_dict&#91;&quot;is_init&quot;&#93; = False
                cache_dict&#91;&quot;k&quot;&#93;.zero_()
                cache_dict&#91;&quot;v&quot;&#93;.zero_()

        for opt_caches in (kv_cache_mouse, kv_cache_keyboard):
            if opt_caches is None:
                continue
            for opt_cache in opt_caches:
                if opt_cache is None:
                    continue
                opt_cache&#91;&quot;global_end_index&quot;&#93;.fill_(0)
                opt_cache&#91;&quot;local_end_index&quot;&#93;.fill_(0)
                opt_cache&#91;&quot;k&quot;&#93;.zero_()
                opt_cache&#91;&quot;v&quot;&#93;.zero_()

    @staticmethod
    def _snapshot_streaming_kv_cache(
        kv_cache: Iterable&#91;dict&#91;str, Any&#93; | None&#93; | None, ) -&gt; list&#91;dict&#91;str, Any&#93; | None&#93; | None:
        # Per-block index clone for checkpoint-safe recompute.
        if kv_cache is None:
            return None
        snapshot: list&#91;dict&#91;str, Any&#93; | None&#93; = &#91;&#93;
        for block_cache in kv_cache:
            if block_cache is None:
                snapshot.append(None)
                continue
            copied = dict(block_cache)
            for key in (&quot;global_end_index&quot;, &quot;local_end_index&quot;):
                tensor = block_cache.get(key)
                if isinstance(tensor, torch.Tensor):
                    copied&#91;key&#93; = tensor.detach().clone()
            snapshot.append(copied)
        return snapshot

    def _generator_multi_step_simulation_forward(self,
                                                 training_batch: TrainingBatch,
                                                 return_sim_steps: bool = False) -&gt; torch.Tensor:
        &quot;&quot;&quot;Forward pass through student transformer matching inference procedure with KV cache management.

        This function is adapted from the reference self-forcing implementation&#x27;s inference_with_trajectory
        and includes gradient masking logic for dynamic frame generation.
        &quot;&quot;&quot;
        latents = training_batch.latents
        dtype = latents.dtype
        batch_size = latents.shape&#91;0&#93;

        num_training_frames = getattr(self.training_args, &#x27;num_latent_t&#x27;, 21)
        min_num_frames = 20 if self.independent_first_frame else 21
        max_num_frames = num_training_frames - 1 if self.independent_first_frame else num_training_frames
        assert max_num_frames % self.num_frame_per_block == 0
        assert min_num_frames % self.num_frame_per_block == 0
        max_num_blocks = max_num_frames // self.num_frame_per_block
        min_num_blocks = min_num_frames // self.num_frame_per_block

        # Sample number of blocks and sync across processes
        num_generated_blocks = torch.randint(min_num_blocks, max_num_blocks + 1, (1, ), device=self.device)
        if dist.is_initialized():
            dist.broadcast(num_generated_blocks, src=0)
        num_generated_blocks = num_generated_blocks.item()
        num_generated_frames = num_generated_blocks * self.num_frame_per_block
        if self.independent_first_frame:
            num_generated_frames += 1
            min_num_frames += 1

        noise_shape = &#91;batch_size, num_generated_frames, *self.video_latent_shape&#91;2:&#93;&#93;
        noise = torch.randn(noise_shape, device=self.device, dtype=dtype)
        if self.sp_world_size &gt; 1:
            noise = rearrange(noise, &quot;b (n t) c h w -&gt; b n t c h w&quot;, n=self.sp_world_size).contiguous()
            noise = noise&#91;:, self.rank_in_sp_group, :, :, :, :&#93;

        batch_size, num_frames, num_channels, height, width = noise.shape

        if self.independent_first_frame:
            assert (num_frames - 1) % self.num_frame_per_block == 0
            num_blocks = (num_frames - 1) // self.num_frame_per_block
        else:
            assert num_frames % self.num_frame_per_block == 0
            num_blocks = num_frames // self.num_frame_per_block

        num_output_frames = num_frames
        output = torch.zeros(&#91;batch_size, num_output_frames, num_channels, height, width&#93;,
                             device=noise.device,
                             dtype=noise.dtype)

        # Step 1: Initialize KV cache to all zeros
        (self.kv_cache1, self.crossattn_cache, self.kv_cache_mouse,
         self.kv_cache_keyboard) = self._initialize_simulation_caches(batch_size, dtype, self.device)

        # Step 2: Temporal denoising loop
        current_start_frame = 0
        all_num_frames = &#91;self.num_frame_per_block&#93; * num_blocks
        if self.independent_first_frame:
            all_num_frames = &#91;1&#93; + all_num_frames
        num_denoising_steps = len(self.denoising_step_list)
        exit_flags = self.generate_and_sync_list(len(all_num_frames), num_denoising_steps, device=noise.device)
        start_gradient_frame_index = max(0, num_output_frames - 21)

        for block_index, current_num_frames in enumerate(all_num_frames):
            noisy_input = noise&#91;:, current_start_frame:current_start_frame + current_num_frames&#93;

            # Step 3.1: Spatial denoising loop
            for index, current_timestep in enumerate(self.denoising_step_list):
                exit_flag = (index == exit_flags&#91;0&#93;) if self.same_step_across_blocks else (index
                                                                                           == exit_flags&#91;block_index&#93;)

                timestep = torch.ones(&#91;batch_size, current_num_frames&#93;, device=noise.device,
                                      dtype=torch.int64) * current_timestep

                if self.boundary_timestep is not None and current_timestep &lt; self.boundary_timestep and self.transformer_2 is not None:
                    current_model = self.transformer_2
                else:
                    current_model = self.transformer

                if not exit_flag:
                    with torch.no_grad():
                        # Build input kwargs
                        training_batch_temp = self._build_distill_input_kwargs(noisy_input,
                                                                               timestep,
                                                                               training_batch.conditional_dict,
                                                                               training_batch,
                                                                               frame_start=current_start_frame,
                                                                               frame_end=current_start_frame +
                                                                               current_num_frames,
                                                                               num_frame_per_block=current_num_frames)

                        pred_flow = current_model(**training_batch_temp.input_kwargs,
                                                  kv_cache=self.kv_cache1,
                                                  kv_cache_mouse=self.kv_cache_mouse,
                                                  kv_cache_keyboard=self.kv_cache_keyboard,
                                                  crossattn_cache=self.crossattn_cache,
                                                  current_start=current_start_frame * self.frame_seq_length,
                                                  start_frame=current_start_frame).permute(0, 2, 1, 3, 4)

                        denoised_pred = pred_noise_to_pred_video(pred_noise=pred_flow.flatten(0, 1),
                                                                 noise_input_latent=noisy_input.flatten(0, 1),
                                                                 timestep=timestep,
                                                                 scheduler=self.noise_scheduler).unflatten(
                                                                     0, pred_flow.shape&#91;:2&#93;)

                        next_timestep = self.denoising_step_list&#91;index + 1&#93;
                        noisy_input = self.noise_scheduler.add_noise(
                            denoised_pred.flatten(0, 1), torch.randn_like(denoised_pred.flatten(0, 1)),
                            next_timestep * torch.ones(
                                &#91;batch_size * current_num_frames&#93;, device=noise.device, dtype=torch.long)).unflatten(
                                    0, denoised_pred.shape&#91;:2&#93;)
                else:
                    # Final prediction with gradient control
                    if current_start_frame &lt; start_gradient_frame_index:
                        with torch.no_grad():
                            training_batch_temp = self._build_distill_input_kwargs(
                                noisy_input,
                                timestep,
                                training_batch.conditional_dict,
                                training_batch,
                                frame_start=current_start_frame,
                                frame_end=current_start_frame + current_num_frames,
                                num_frame_per_block=current_num_frames)

                            pred_flow = current_model(**training_batch_temp.input_kwargs,
                                                      kv_cache=self.kv_cache1,
                                                      kv_cache_mouse=self.kv_cache_mouse,
                                                      kv_cache_keyboard=self.kv_cache_keyboard,
                                                      crossattn_cache=self.crossattn_cache,
                                                      current_start=current_start_frame * self.frame_seq_length,
                                                      start_frame=current_start_frame).permute(0, 2, 1, 3, 4)
                    else:
                        training_batch_temp = self._build_distill_input_kwargs(noisy_input,
                                                                               timestep,
                                                                               training_batch.conditional_dict,
                                                                               training_batch,
                                                                               frame_start=current_start_frame,
                                                                               frame_end=current_start_frame +
                                                                               current_num_frames,
                                                                               num_frame_per_block=current_num_frames)

                        # Snapshot streaming caches for checkpoint-safe recompute.
                        snap_kv_cache = self._snapshot_streaming_kv_cache(self.kv_cache1)
                        snap_kv_cache_mouse = self._snapshot_streaming_kv_cache(self.kv_cache_mouse)
                        snap_kv_cache_keyboard = self._snapshot_streaming_kv_cache(self.kv_cache_keyboard)

                        pred_flow = current_model(**training_batch_temp.input_kwargs,
                                                  kv_cache=snap_kv_cache,
                                                  kv_cache_mouse=snap_kv_cache_mouse,
                                                  kv_cache_keyboard=snap_kv_cache_keyboard,
                                                  crossattn_cache=self.crossattn_cache,
                                                  current_start=current_start_frame * self.frame_seq_length,
                                                  start_frame=current_start_frame).permute(0, 2, 1, 3, 4)

                    denoised_pred = pred_noise_to_pred_video(pred_noise=pred_flow.flatten(0, 1),
                                                             noise_input_latent=noisy_input.flatten(0, 1),
                                                             timestep=timestep,
                                                             scheduler=self.noise_scheduler).unflatten(
                                                                 0, pred_flow.shape&#91;:2&#93;)
                    break

            # Step 3.2: record the model&#x27;s output
            output&#91;:, current_start_frame:current_start_frame + current_num_frames&#93; = denoised_pred

            # Step 3.3: rerun with timestep zero to update the cache
            context_timestep = torch.ones_like(timestep) * self.context_noise
            denoised_pred = self.noise_scheduler.add_noise(denoised_pred.flatten(0, 1),
                                                           torch.randn_like(denoised_pred.flatten(0, 1)),
                                                           context_timestep).unflatten(0, denoised_pred.shape&#91;:2&#93;)

            with torch.no_grad():
                training_batch_temp = self._build_distill_input_kwargs(denoised_pred,
                                                                       context_timestep,
                                                                       training_batch.conditional_dict,
                                                                       training_batch,
                                                                       frame_start=current_start_frame,
                                                                       frame_end=current_start_frame +
                                                                       current_num_frames,
                                                                       num_frame_per_block=current_num_frames)

                # context_timestep is 0 so we use transformer_2
                current_model = self.transformer_2 if self.transformer_2 is not None else self.transformer
                current_model(**training_batch_temp.input_kwargs,
                              kv_cache=self.kv_cache1,
                              kv_cache_mouse=self.kv_cache_mouse,
                              kv_cache_keyboard=self.kv_cache_keyboard,
                              crossattn_cache=self.crossattn_cache,
                              current_start=current_start_frame * self.frame_seq_length,
                              start_frame=current_start_frame)

            # Step 3.4: update the start and end frame indices
            current_start_frame += current_num_frames

        # Handle last 21 frames logic
        pred_image_or_video = output

        # Slice last 21 frames if we generated more
        gradient_mask = None
        if pred_image_or_video.shape&#91;1&#93; &gt; 21:
            with torch.no_grad():
                # Re-encode to get image latent
                latent_to_decode = pred_image_or_video&#91;:, :-20, ...&#93;
                # Decode to video
                latent_to_decode = latent_to_decode.permute(0, 2, 1, 3, 4)  # &#91;B, C, F, H, W&#93;

                # Apply VAE scaling and shift factors
                if isinstance(self.vae.scaling_factor, torch.Tensor):
                    latent_to_decode = latent_to_decode / self.vae.scaling_factor.to(
                        latent_to_decode.device, latent_to_decode.dtype)
                else:
                    latent_to_decode = latent_to_decode / self.vae.scaling_factor

                if hasattr(self.vae, &quot;shift_factor&quot;) and self.vae.shift_factor is not None:
                    if isinstance(self.vae.shift_factor, torch.Tensor):
                        latent_to_decode += self.vae.shift_factor.to(latent_to_decode.device, latent_to_decode.dtype)
                    else:
                        latent_to_decode += self.vae.shift_factor

                # Decode to pixels
                pixels = self.vae.decode(latent_to_decode)
                frame = pixels&#91;:, :, -1:, :, :&#93;.to(dtype)  # Last frame &#91;B, C, 1, H, W&#93;

                # Encode frame back to get image latent
                image_latent = self.vae.encode(frame).to(dtype)
                image_latent = image_latent.permute(0, 2, 1, 3, 4)  # &#91;B, F, C, H, W&#93;

            pred_image_or_video_last_21 = torch.cat(&#91;image_latent, pred_image_or_video&#91;:, -20:, ...&#93;&#93;, dim=1)
        else:
            pred_image_or_video_last_21 = pred_image_or_video

        # Set up gradient mask if we generated more than minimum frames
        if num_generated_frames != min_num_frames:
            # Currently, we do not use gradient for the first chunk, since it contains image latents
            gradient_mask = torch.ones_like(pred_image_or_video_last_21, dtype=torch.bool)
            if self.independent_first_frame:
                gradient_mask&#91;:, :1&#93; = False
            else:
                gradient_mask&#91;:, :self.num_frame_per_block&#93; = False

        # Apply gradient masking if needed
        final_output = pred_image_or_video_last_21.to(dtype)
        if gradient_mask is not None:
            # Apply gradient masking: detach frames that shouldn&#x27;t contribute gradients
            final_output = torch.where(
                gradient_mask,
                pred_image_or_video_last_21,  # Keep original values where gradient_mask is True
                pred_image_or_video_last_21.detach()  # Detach where gradient_mask is False
            )

        # Store visualization data
        training_batch.dmd_latent_vis_dict&#91;&quot;generator_timestep&quot;&#93; = torch.as_tensor(
            self.denoising_step_list&#91;exit_flags&#91;0&#93;&#93;,
            dtype=torch.float32,
            device=self.device,
        ).detach().clone()

        # Store gradient mask information for debugging
        if gradient_mask is not None:
            training_batch.dmd_latent_vis_dict&#91;&quot;gradient_mask&quot;&#93; = gradient_mask.float()
            training_batch.dmd_latent_vis_dict&#91;&quot;num_generated_frames&quot;&#93; = torch.tensor(num_generated_frames,
                                                                                      dtype=torch.float32,
                                                                                      device=self.device)
            training_batch.dmd_latent_vis_dict&#91;&quot;min_num_frames&quot;&#93; = torch.tensor(min_num_frames,
                                                                                dtype=torch.float32,
                                                                                device=self.device)

        # Clean up caches
        assert self.kv_cache1 is not None
        assert self.crossattn_cache is not None
        self._reset_simulation_caches(self.kv_cache1, self.crossattn_cache, self.kv_cache_mouse, self.kv_cache_keyboard)

        return final_output if gradient_mask is not None else pred_image_or_video

    def initialize_validation_pipeline(self, training_args: TrainingArgs):
        logger.info(&quot;Initializing validation pipeline...&quot;)
        args_copy = deepcopy(training_args)
        args_copy.inference_mode = True
        # Use the same flow-matching scheduler as training for consistent validation.
        validation_scheduler = SelfForcingFlowMatchScheduler(shift=args_copy.pipeline_config.flow_shift,
                                                             sigma_min=0.0,
                                                             extra_one_step=True)
        validation_scheduler.set_timesteps(num_inference_steps=1000, training=True)
        # Warm start validation with current transformer
        self.validation_pipeline = MatrixGame2CausalDMDPipeline.from_pretrained(
            training_args.model_path,
            args=args_copy,  # type: ignore
            inference_mode=True,
            loaded_modules=&#123;
                &quot;transformer&quot;: self.get_module(&quot;transformer&quot;),
                &quot;vae&quot;: self.get_module(&quot;vae&quot;),
                &quot;scheduler&quot;: validation_scheduler,
            &#125;,
            tp_size=training_args.tp_size,
            sp_size=training_args.sp_size,
            num_gpus=training_args.num_gpus,
            pin_cpu_memory=training_args.pin_cpu_memory,
            dit_cpu_offload=True)

        if not hasattr(self.validation_pipeline, &quot;prompt_encoding_stage&quot;):
            # validation expects a prompt stage
            def _prompt_encoding_stage(batch: ForwardBatch, _args: TrainingArgs) -&gt; ForwardBatch:
                if not batch.prompt_embeds:
                    batch.prompt_embeds = &#91;None&#93;
                if batch.prompt_attention_mask is None or not batch.prompt_attention_mask:
                    batch.prompt_attention_mask = &#91;None&#93;
                return batch

            self.validation_pipeline.prompt_encoding_stage = _prompt_encoding_stage  # type: ignore&#91;attr-defined&#93;

    def _get_next_batch(self, training_batch: TrainingBatch) -&gt; TrainingBatch:
        batch = next(self.train_loader_iter, None)  # type: ignore
        if batch is None:
            self.current_epoch += 1
            # Reset iterator for next epoch
            self.train_loader_iter = iter(self.train_dataloader)
            # Get first batch of new epoch
            batch = next(self.train_loader_iter)

        clip_feature = batch&#91;&#x27;clip_feature&#x27;&#93;
        first_frame_latent = batch&#91;&#x27;first_frame_latent&#x27;&#93;
        keyboard_cond = batch.get(&#x27;keyboard_cond&#x27;, None)
        mouse_cond = batch.get(&#x27;mouse_cond&#x27;, None)
        infos = batch&#91;&#x27;info_list&#x27;&#93;

        batch_size = clip_feature.shape&#91;0&#93;
        vae_config = self.training_args.pipeline_config.vae_config.arch_config
        num_channels = vae_config.z_dim
        spatial_compression_ratio = vae_config.spatial_compression_ratio

        latent_height = self.training_args.num_height // spatial_compression_ratio
        latent_width = self.training_args.num_width // spatial_compression_ratio

        latents = torch.randn(batch_size, num_channels, self.training_args.num_latent_t, latent_height,
                              latent_width).to(get_local_torch_device(), dtype=torch.bfloat16)

        training_batch.latents = latents.to(get_local_torch_device(), dtype=torch.bfloat16)
        training_batch.encoder_hidden_states = None
        training_batch.encoder_attention_mask = None
        training_batch.image_embeds = clip_feature.to(get_local_torch_device(), dtype=torch.bfloat16)
        training_batch.image_latents = first_frame_latent.to(get_local_torch_device(), dtype=torch.bfloat16)
        # Action conditioning
        if keyboard_cond is not None and keyboard_cond.numel() &gt; 0:
            keyboard_cond_full = keyboard_cond.to(get_local_torch_device(), dtype=torch.bfloat16)
            training_batch.keyboard_cond = keyboard_cond_full  # For Teacher/Critic (dim=6)
        else:
            training_batch.keyboard_cond = None
        if mouse_cond is not None and mouse_cond.numel() &gt; 0:
            training_batch.mouse_cond = mouse_cond.to(get_local_torch_device(), dtype=torch.bfloat16)
        else:
            training_batch.mouse_cond = None
        training_batch.infos = infos
        return training_batch

    def _prepare_dit_inputs(self, training_batch: TrainingBatch) -&gt; TrainingBatch:
        &quot;&quot;&quot;Override to properly handle I2V concatenation - call parent first, then concatenate image conditioning.&quot;&quot;&quot;
        # First, call parent method to prepare noise, timesteps, etc. for video latents
        training_batch = super()._prepare_dit_inputs(training_batch)

        assert isinstance(training_batch.image_latents, torch.Tensor)
        image_latents = training_batch.image_latents.to(get_local_torch_device(), dtype=torch.bfloat16)

        # cond_concat = &#91;mask(4), image_latent(16)&#93; with 20 channels.
        expected_cond_channels = 20
        if image_latents.shape&#91;1&#93; == 16:
            image_latents = self._build_matrixgame_cond_concat(image_latents)
        elif image_latents.shape&#91;1&#93; != expected_cond_channels:
            raise ValueError(&quot;Unexpected first_frame_latent channels, &quot;
                             &quot;Expected &#123;expected_cond_channels&#125; (cond_concat), got &#123;image_latents.shape&#91;1&#93;&#125;.&quot;)

        if self.sp_world_size &gt; 1:
            total_frames = image_latents.shape&#91;2&#93;
            # Split cond latents to local SP shard only when tensor is still global.
            if total_frames == self.training_args.num_latent_t:
                if total_frames % self.sp_world_size != 0:
                    raise ValueError(&quot;image_latents temporal dim is not divisible by SP world size: &quot;
                                     f&quot;frames=&#123;total_frames&#125;, sp_world_size=&#123;self.sp_world_size&#125;&quot;)
                image_latents = rearrange(image_latents, &quot;b c (n t) h w -&gt; b c n t h w&quot;,
                                          n=self.sp_world_size).contiguous()
                image_latents = image_latents&#91;:, :, self.rank_in_sp_group, :, :, :&#93;

        training_batch.image_latents = image_latents

        return training_batch

    def _build_distill_input_kwargs(self,
                                    noise_input: torch.Tensor,
                                    timestep: torch.Tensor,
                                    text_dict: dict&#91;str, torch.Tensor&#93; | None,
                                    training_batch: TrainingBatch,
                                    frame_start: int | None = None,
                                    frame_end: int | None = None,
                                    num_frame_per_block: int | None = None) -&gt; TrainingBatch:
        # Image Embeds for conditioning
        image_embeds = training_batch.image_embeds
        assert image_embeds is not None
        assert torch.isnan(image_embeds).sum() == 0
        image_embeds = image_embeds.to(get_local_torch_device(), dtype=torch.bfloat16)
        image_embeds = &#91;image_embeds&#93;

        image_latents = training_batch.image_latents
        if frame_start is not None and frame_end is not None:
            image_latents = image_latents&#91;:, :, frame_start:frame_end, :, :&#93;

        vae_temporal_compression_ratio = 4
        if frame_end is not None:
            action_frame_end = (frame_end - 1) * vae_temporal_compression_ratio + 1
            keyboard_cond_sliced = training_batch.keyboard_cond&#91;:, :
                                                                action_frame_end, :&#93; if training_batch.keyboard_cond is not None else None
            mouse_cond_sliced = training_batch.mouse_cond&#91;:, :
                                                          action_frame_end, :&#93; if training_batch.mouse_cond is not None else None
        else:
            keyboard_cond_sliced = training_batch.keyboard_cond
            mouse_cond_sliced = training_batch.mouse_cond

        noisy_model_input = torch.cat(&#91;noise_input, image_latents.permute(0, 2, 1, 3, 4)&#93;, dim=2)

        training_batch.input_kwargs = &#123;
            &quot;hidden_states&quot;: noisy_model_input.permute(0, 2, 1, 3, 4),  # bs, c, t, h, w
            &quot;encoder_hidden_states&quot;: None,
            &quot;timestep&quot;: timestep,
            &quot;encoder_hidden_states_image&quot;: image_embeds,
            &quot;keyboard_cond&quot;: keyboard_cond_sliced,
            &quot;mouse_cond&quot;: mouse_cond_sliced,
            &quot;num_frame_per_block&quot;: num_frame_per_block if num_frame_per_block is not None else self.num_frame_per_block,
        &#125;
        training_batch.noise_latents = noise_input

        return training_batch

    def _dmd_forward(self, generator_pred_video: torch.Tensor, training_batch: TrainingBatch) -&gt; torch.Tensor:
        &quot;&quot;&quot;Compute DMD (Diffusion Model Distillation) loss for Matrix-Game 2.0.&quot;&quot;&quot;
        original_latent = generator_pred_video
        with torch.no_grad():
            timestep = torch.randint(0, self.num_train_timestep, &#91;1&#93;, device=self.device, dtype=torch.long)

            timestep = shift_timestep(timestep, self.timestep_shift, self.num_train_timestep)

            timestep = timestep.clamp(self.min_timestep, self.max_timestep)

            noise = torch.randn(self.video_latent_shape, device=self.device, dtype=generator_pred_video.dtype)

            noisy_latent = self.noise_scheduler.add_noise(generator_pred_video.flatten(0, 1), noise.flatten(
                0, 1), timestep).detach().unflatten(0, (generator_pred_video.shape&#91;0&#93;, generator_pred_video.shape&#91;1&#93;))

            # Non-causal models expect 1D timestep (batch_size,)
            critic_timestep = timestep.expand(noisy_latent.shape&#91;0&#93;)

            self._build_distill_input_kwargs(noisy_latent, critic_timestep, None, training_batch)

            # fake_score_transformer forward
            current_fake_score_transformer = self._get_fake_score_transformer(timestep)
            fake_score_pred_noise = current_fake_score_transformer(**training_batch.input_kwargs).permute(0, 2, 1, 3, 4)

            faker_score_pred_video = pred_noise_to_pred_video(pred_noise=fake_score_pred_noise.flatten(0, 1),
                                                              noise_input_latent=noisy_latent.flatten(0, 1),
                                                              timestep=timestep,
                                                              scheduler=self.noise_scheduler).unflatten(
                                                                  0, fake_score_pred_noise.shape&#91;:2&#93;)

            # real_score_transformer forward
            current_real_score_transformer = self._get_real_score_transformer(timestep)
            real_score_pred_noise = current_real_score_transformer(**training_batch.input_kwargs).permute(0, 2, 1, 3, 4)

            real_score_pred_video = pred_noise_to_pred_video(pred_noise=real_score_pred_noise.flatten(0, 1),
                                                             noise_input_latent=noisy_latent.flatten(0, 1),
                                                             timestep=timestep,
                                                             scheduler=self.noise_scheduler).unflatten(
                                                                 0, real_score_pred_noise.shape&#91;:2&#93;)

            # No CFG for Matrix-Game 2.0 - use real_score_pred_video directly
            grad = (faker_score_pred_video - real_score_pred_video) / torch.abs(original_latent -
                                                                                real_score_pred_video).mean()
            grad = torch.nan_to_num(grad)

        dmd_loss = 0.5 * F.mse_loss(original_latent.float(), (original_latent.float() - grad.float()).detach())

        training_batch.dmd_latent_vis_dict.update(&#123;
            &quot;training_batch_dmd_fwd_clean_latent&quot;: training_batch.latents,
            &quot;generator_pred_video&quot;: original_latent.detach(),
            &quot;real_score_pred_video&quot;: real_score_pred_video.detach(),
            &quot;faker_score_pred_video&quot;: faker_score_pred_video.detach(),
            &quot;dmd_timestep&quot;: timestep.detach(),
        &#125;)

        return dmd_loss

    def faker_score_forward(self, training_batch: TrainingBatch) -&gt; tuple&#91;TrainingBatch, torch.Tensor&#93;:
        &quot;&quot;&quot;Forward pass for critic training with Matrix-Game 2.0 action conditioning.&quot;&quot;&quot;
        with torch.no_grad(), set_forward_context(current_timestep=training_batch.timesteps,
                                                  attn_metadata=training_batch.attn_metadata_vsa):
            if self.training_args.simulate_generator_forward:
                generator_pred_video = self._generator_multi_step_simulation_forward(training_batch)
            else:
                generator_pred_video = self._generator_forward(training_batch)

        fake_score_timestep = torch.randint(0, self.num_train_timestep, &#91;1&#93;, device=self.device, dtype=torch.long)

        fake_score_timestep = shift_timestep(fake_score_timestep, self.timestep_shift, self.num_train_timestep)

        fake_score_timestep = fake_score_timestep.clamp(self.min_timestep, self.max_timestep)

        fake_score_noise = torch.randn(self.video_latent_shape, device=self.device, dtype=generator_pred_video.dtype)

        noisy_generator_pred_video = self.noise_scheduler.add_noise(
            generator_pred_video.flatten(0, 1), fake_score_noise.flatten(0, 1),
            fake_score_timestep).unflatten(0, (generator_pred_video.shape&#91;0&#93;, generator_pred_video.shape&#91;1&#93;))

        # Non-causal critic expects 1D timestep (batch_size,), not 2D (batch_size, num_frames).
        expanded_fake_score_timestep = fake_score_timestep.expand(noisy_generator_pred_video.shape&#91;0&#93;)

        self._build_distill_input_kwargs(noisy_generator_pred_video, expanded_fake_score_timestep, None, training_batch)

        with set_forward_context(current_timestep=training_batch.timesteps, attn_metadata=training_batch.attn_metadata):
            current_fake_score_transformer = self._get_fake_score_transformer(fake_score_timestep)
            fake_score_pred_noise = current_fake_score_transformer(**training_batch.input_kwargs).permute(0, 2, 1, 3, 4)

        target = fake_score_noise - generator_pred_video
        flow_matching_loss = torch.mean((fake_score_pred_noise - target)**2)

        training_batch.fake_score_latent_vis_dict = &#123;
            &quot;training_batch_fakerscore_fwd_clean_latent&quot;: training_batch.latents,
            &quot;generator_pred_video&quot;: generator_pred_video,
            &quot;fake_score_timestep&quot;: fake_score_timestep,
        &#125;

        return training_batch, flow_matching_loss

    def _prepare_validation_batch(self, sampling_param: SamplingParam, training_args: TrainingArgs,
                                  validation_batch: dict&#91;str, Any&#93;, num_inference_steps: int) -&gt; ForwardBatch:
        sampling_param.prompt = validation_batch&#91;&#x27;prompt&#x27;&#93;
        sampling_param.height = training_args.num_height
        sampling_param.width = training_args.num_width
        sampling_param.image_path = validation_batch.get(&#x27;image_path&#x27;) or validation_batch.get(&#x27;video_path&#x27;)
        sampling_param.num_inference_steps = num_inference_steps
        sampling_param.data_type = &quot;video&quot;
        assert self.seed is not None
        sampling_param.seed = self.seed

        latents_size = &#91;(sampling_param.num_frames - 1) // 4 + 1, sampling_param.height // 8, sampling_param.width // 8&#93;
        n_tokens = latents_size&#91;0&#93; * latents_size&#91;1&#93; * latents_size&#91;2&#93;
        temporal_compression_factor = training_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio
        num_frames = (training_args.num_latent_t - 1) * temporal_compression_factor + 1
        sampling_param.num_frames = num_frames
        batch = ForwardBatch(
            **shallow_asdict(sampling_param),
            generator=torch.Generator(device=&quot;cpu&quot;).manual_seed(self.seed),
            n_tokens=n_tokens,
            eta=0.0,
            VSA_sparsity=training_args.VSA_sparsity,
        )
        if &quot;image&quot; in validation_batch and validation_batch&#91;&quot;image&quot;&#93; is not None:
            batch.pil_image = validation_batch&#91;&quot;image&quot;&#93;

        if &quot;keyboard_cond&quot; in validation_batch and validation_batch&#91;&quot;keyboard_cond&quot;&#93; is not None:
            keyboard_cond = validation_batch&#91;&quot;keyboard_cond&quot;&#93;
            keyboard_cond = torch.tensor(keyboard_cond, dtype=torch.bfloat16)
            keyboard_cond = keyboard_cond.unsqueeze(0)
            batch.keyboard_cond = keyboard_cond

        if &quot;mouse_cond&quot; in validation_batch and validation_batch&#91;&quot;mouse_cond&quot;&#93; is not None:
            mouse_cond = validation_batch&#91;&quot;mouse_cond&quot;&#93;
            mouse_cond = torch.tensor(mouse_cond, dtype=torch.bfloat16)
            mouse_cond = mouse_cond.unsqueeze(0)
            batch.mouse_cond = mouse_cond

        return batch</code></pre></details>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.set_schemas"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.set_schemas</code></h3>
<pre class="doc-signature"><code>set_schemas()</code></pre>

<details><summary>Source</summary><pre><code>def set_schemas(self):
    self.train_dataset_schema = pyarrow_schema_matrixgame2</code></pre></details>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.load_modules"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.load_modules</code></h3>
<pre class="doc-signature"><code>load_modules(fastvideo_args: FastVideoArgs, loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None) -&gt; dict&#91;str, Any&#93;</code></pre>

<details><summary>Source</summary><pre><code>def load_modules(
    self,
    fastvideo_args: FastVideoArgs,
    loaded_modules: dict&#91;str, torch.nn.Module&#93; | None = None,
) -&gt; dict&#91;str, Any&#93;:
    modules = ComposedPipelineBase.load_modules(
        self,
        fastvideo_args,
        loaded_modules,
    )
    training_args = cast(TrainingArgs, fastvideo_args)
    old_override = training_args.override_transformer_cls_name
    training_args.override_transformer_cls_name = &quot;MatrixGame2WanModel&quot;
    try:
        if loaded_modules is not None and &quot;real_score_transformer&quot; in loaded_modules:
            self.real_score_transformer = loaded_modules&#91;&quot;real_score_transformer&quot;&#93;
        elif training_args.real_score_model_path:
            logger.info(
                &quot;Loading real score transformer from: %s&quot;,
                training_args.real_score_model_path,
            )
            self.real_score_transformer = self.load_module_from_path(
                training_args.real_score_model_path,
                &quot;transformer&quot;,
                training_args,
            )
        else:
            raise ValueError(&quot;real_score_model_path is required for DMD distillation pipeline&quot;)
        modules&#91;&quot;real_score_transformer&quot;&#93; = self.real_score_transformer

        if loaded_modules is not None and &quot;fake_score_transformer&quot; in loaded_modules:
            self.fake_score_transformer = loaded_modules&#91;&quot;fake_score_transformer&quot;&#93;
        elif training_args.fake_score_model_path:
            logger.info(
                &quot;Loading fake score transformer from: %s&quot;,
                training_args.fake_score_model_path,
            )
            self.fake_score_transformer = self.load_module_from_path(
                training_args.fake_score_model_path,
                &quot;transformer&quot;,
                training_args,
            )
        else:
            raise ValueError(&quot;fake_score_model_path is required for DMD distillation pipeline&quot;)
        modules&#91;&quot;fake_score_transformer&quot;&#93; = self.fake_score_transformer
    finally:
        training_args.override_transformer_cls_name = old_override

    self.real_score_transformer_2 = None
    self.fake_score_transformer_2 = None
    return modules</code></pre></details>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.initialize_validation_pipeline"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.initialize_validation_pipeline</code></h3>
<pre class="doc-signature"><code>initialize_validation_pipeline(training_args: TrainingArgs)</code></pre>

<details><summary>Source</summary><pre><code>def initialize_validation_pipeline(self, training_args: TrainingArgs):
    logger.info(&quot;Initializing validation pipeline...&quot;)
    args_copy = deepcopy(training_args)
    args_copy.inference_mode = True
    # Use the same flow-matching scheduler as training for consistent validation.
    validation_scheduler = SelfForcingFlowMatchScheduler(shift=args_copy.pipeline_config.flow_shift,
                                                         sigma_min=0.0,
                                                         extra_one_step=True)
    validation_scheduler.set_timesteps(num_inference_steps=1000, training=True)
    # Warm start validation with current transformer
    self.validation_pipeline = MatrixGame2CausalDMDPipeline.from_pretrained(
        training_args.model_path,
        args=args_copy,  # type: ignore
        inference_mode=True,
        loaded_modules=&#123;
            &quot;transformer&quot;: self.get_module(&quot;transformer&quot;),
            &quot;vae&quot;: self.get_module(&quot;vae&quot;),
            &quot;scheduler&quot;: validation_scheduler,
        &#125;,
        tp_size=training_args.tp_size,
        sp_size=training_args.sp_size,
        num_gpus=training_args.num_gpus,
        pin_cpu_memory=training_args.pin_cpu_memory,
        dit_cpu_offload=True)

    if not hasattr(self.validation_pipeline, &quot;prompt_encoding_stage&quot;):
        # validation expects a prompt stage
        def _prompt_encoding_stage(batch: ForwardBatch, _args: TrainingArgs) -&gt; ForwardBatch:
            if not batch.prompt_embeds:
                batch.prompt_embeds = &#91;None&#93;
            if batch.prompt_attention_mask is None or not batch.prompt_attention_mask:
                batch.prompt_attention_mask = &#91;None&#93;
            return batch

        self.validation_pipeline.prompt_encoding_stage = _prompt_encoding_stage  # type: ignore&#91;attr-defined&#93;</code></pre></details>
<h3 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.faker_score_forward"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.MatrixGame2SelfForcingDistillationPipeline.faker_score_forward</code></h3>
<pre class="doc-signature"><code>faker_score_forward(training_batch: TrainingBatch) -&gt; tuple&#91;TrainingBatch, torch.Tensor&#93;</code></pre>
<p>Forward pass for critic training with Matrix-Game 2.0 action conditioning.</p>
<details><summary>Source</summary><pre><code>def faker_score_forward(self, training_batch: TrainingBatch) -&gt; tuple&#91;TrainingBatch, torch.Tensor&#93;:
    &quot;&quot;&quot;Forward pass for critic training with Matrix-Game 2.0 action conditioning.&quot;&quot;&quot;
    with torch.no_grad(), set_forward_context(current_timestep=training_batch.timesteps,
                                              attn_metadata=training_batch.attn_metadata_vsa):
        if self.training_args.simulate_generator_forward:
            generator_pred_video = self._generator_multi_step_simulation_forward(training_batch)
        else:
            generator_pred_video = self._generator_forward(training_batch)

    fake_score_timestep = torch.randint(0, self.num_train_timestep, &#91;1&#93;, device=self.device, dtype=torch.long)

    fake_score_timestep = shift_timestep(fake_score_timestep, self.timestep_shift, self.num_train_timestep)

    fake_score_timestep = fake_score_timestep.clamp(self.min_timestep, self.max_timestep)

    fake_score_noise = torch.randn(self.video_latent_shape, device=self.device, dtype=generator_pred_video.dtype)

    noisy_generator_pred_video = self.noise_scheduler.add_noise(
        generator_pred_video.flatten(0, 1), fake_score_noise.flatten(0, 1),
        fake_score_timestep).unflatten(0, (generator_pred_video.shape&#91;0&#93;, generator_pred_video.shape&#91;1&#93;))

    # Non-causal critic expects 1D timestep (batch_size,), not 2D (batch_size, num_frames).
    expanded_fake_score_timestep = fake_score_timestep.expand(noisy_generator_pred_video.shape&#91;0&#93;)

    self._build_distill_input_kwargs(noisy_generator_pred_video, expanded_fake_score_timestep, None, training_batch)

    with set_forward_context(current_timestep=training_batch.timesteps, attn_metadata=training_batch.attn_metadata):
        current_fake_score_transformer = self._get_fake_score_transformer(fake_score_timestep)
        fake_score_pred_noise = current_fake_score_transformer(**training_batch.input_kwargs).permute(0, 2, 1, 3, 4)

    target = fake_score_noise - generator_pred_video
    flow_matching_loss = torch.mean((fake_score_pred_noise - target)**2)

    training_batch.fake_score_latent_vis_dict = &#123;
        &quot;training_batch_fakerscore_fwd_clean_latent&quot;: training_batch.latents,
        &quot;generator_pred_video&quot;: generator_pred_video,
        &quot;fake_score_timestep&quot;: fake_score_timestep,
    &#125;

    return training_batch, flow_matching_loss</code></pre></details>
<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.main"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.main</code></h2>
<pre class="doc-signature"><code>main(args) -&gt; None</code></pre>

<h2 id="fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.build_parser"><code>fastvideo.training.matrixgame2_self_forcing_distillation_pipeline.build_parser</code></h2>
<pre class="doc-signature"><code>build_parser(pipeline_class: str | None = None, pipeline_module: str | None = None) -&gt; FlexibleArgumentParser</code></pre>
<p>Build the training-runner CLI parser.</p>
<p>When <code>pipeline_class</code>/<code>pipeline_module</code> are given they become optional defaults,
so the deprecated per-pipeline <code>__main__</code> blocks keep working without the flags.</p>
</div>
