---
title: kandinsky5
---

<div class="python-reference">
<a id="fastvideo.pipelines.stages.kandinsky5-classes"></a>
<a id="fastvideo.pipelines.stages.kandinsky5-functions"></a>
<a id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage-functions"></a>
<a id="fastvideo.pipelines.stages.kandinsky5"></a>

<h2 id="fastvideo.pipelines.stages.kandinsky5.LocalAttention"><code>fastvideo.pipelines.stages.kandinsky5.LocalAttention</code></h2>
<pre class="doc-signature"><code>LocalAttention(num_heads: int, head_size: int, num_kv_heads: int | None = None, softmax_scale: float | None = None, causal: bool = False, supported_attention_backends: tuple&#91;AttentionBackendEnum, ...&#93; | None = None, default_backend: AttentionBackendEnum | None = None, **extra_impl_args)</code></pre>
<p>Attention layer.</p>

<h3 id="fastvideo.pipelines.stages.kandinsky5.LocalAttention.forward"><code>fastvideo.pipelines.stages.kandinsky5.LocalAttention.forward</code></h3>
<pre class="doc-signature"><code>forward(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, freqs_cis: tuple&#91;torch.Tensor, torch.Tensor&#93; | None = None) -&gt; torch.Tensor</code></pre>
<p>Apply local attention between query, key and value tensors.</p>
<h4>Parameters</h4>
<dl>
<dt><code>q: torch.Tensor</code></dt><dd><p>Query tensor of shape [batch_size, seq_len, num_heads, head_dim]</p></dd>
<dt><code>k: torch.Tensor</code></dt><dd><p>Key tensor of shape [batch_size, seq_len, num_heads, head_dim] </p></dd>
<dt><code>v: torch.Tensor</code></dt><dd><p>Value tensor of shape [batch_size, seq_len, num_heads, head_dim]</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p>torch.Tensor: Output tensor after local attention</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.NablaAttentionMetadataBuilder"><code>fastvideo.pipelines.stages.kandinsky5.NablaAttentionMetadataBuilder</code></h2>
<pre class="doc-signature"><code>NablaAttentionMetadataBuilder()</code></pre>


<h3 id="fastvideo.pipelines.stages.kandinsky5.NablaAttentionMetadataBuilder.prepare"><code>fastvideo.pipelines.stages.kandinsky5.NablaAttentionMetadataBuilder.prepare</code></h3>
<pre class="doc-signature"><code>prepare() -&gt; None</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.NablaAttentionMetadataBuilder.build"><code>fastvideo.pipelines.stages.kandinsky5.NablaAttentionMetadataBuilder.build</code></h3>
<pre class="doc-signature"><code>build(current_timestep: int, sta_mask: torch.Tensor, P: float, visual_shape: tuple&#91;int, int, int&#93;, **kwargs: Any) -&gt; NablaAttentionMetadata</code></pre>

<h2 id="fastvideo.pipelines.stages.kandinsky5.component_attention_backend"><code>fastvideo.pipelines.stages.kandinsky5.component_attention_backend</code></h2>
<pre class="doc-signature"><code>component_attention_backend(component: object) -&gt; AttentionBackendEnum | _NoRequest</code></pre>
<p>Read back the decision :func:<code>record_resolved_attention_backend</code> wrote.</p>
<p>Returns <code>NO_REQUEST</code> unless the component recorded a <em>concrete</em> backend,
so a caller that passes this through only overrides the ambient fallback
when there is a real decision to override it with.</p>
<p><code>NO_REQUEST</code> rather than <code>None</code> for the no-decision case is deliberate,
and cannot be derived from the attribute's presence: <code>ModelConfig</code> declares
<code>_resolved_attention_backend</code> as a field defaulting to <code>None</code>, so the
attribute always exists and a <code>getattr</code> default can never fire. Worse,
<code>record_resolved_attention_backend</code> writes <code>None</code> whenever no scope is
active, so "resolved to automatic selection" and "never recorded" are the
same stored value. Neither state should suppress the environment variable at
a call site that previously honoured it, and collapsing both to
<code>NO_REQUEST</code> keeps that behavior identical.</p>
<h2 id="fastvideo.pipelines.stages.kandinsky5.get_local_torch_device"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.FastVideoArgs"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.FastVideoArgs.is_output_rank"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.FastVideoArgs.add_cli_args"><code>fastvideo.pipelines.stages.kandinsky5.FastVideoArgs.add_cli_args</code></h3>
<pre class="doc-signature"><code>add_cli_args(parser: FlexibleArgumentParser) -&gt; FlexibleArgumentParser</code></pre>

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

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

<h3 id="fastvideo.pipelines.stages.kandinsky5.FastVideoArgs.check_fastvideo_args"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.FastVideoArgs.finalize_device_offload_policy"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.FastVideoArgs.disable_offload_on_unified_memory"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.set_forward_context"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.init_logger"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.TransformerLoader"><code>fastvideo.pipelines.stages.kandinsky5.TransformerLoader</code></h2>
<pre class="doc-signature"><code>TransformerLoader(device = None)</code></pre>
<p>Loader for transformer.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.TransformerLoader.load"><code>fastvideo.pipelines.stages.kandinsky5.TransformerLoader.load</code></h3>
<pre class="doc-signature"><code>load(model_path: str, fastvideo_args: FastVideoArgs)</code></pre>
<p>Load the transformer based on the model path, and inference args.</p>
<h2 id="fastvideo.pipelines.stages.kandinsky5.VAELoader"><code>fastvideo.pipelines.stages.kandinsky5.VAELoader</code></h2>
<pre class="doc-signature"><code>VAELoader(device = None)</code></pre>
<p>Loader for VAE.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.VAELoader.load"><code>fastvideo.pipelines.stages.kandinsky5.VAELoader.load</code></h3>
<pre class="doc-signature"><code>load(model_path: str, fastvideo_args: FastVideoArgs)</code></pre>
<p>Load the VAE based on the model path, and inference args.</p>
<h2 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler</code></h2>
<pre class="doc-signature"><code>FlowMatchEulerDiscreteScheduler(num_train_timesteps: int = 1000, shift: float = 1.0, use_dynamic_shifting: bool = False, base_shift: float | None = 0.5, max_shift: float | None = 1.15, base_image_seq_len: int | None = 256, max_image_seq_len: int | None = 4096, invert_sigmas: bool = False, shift_terminal: float | None = None, use_karras_sigmas: bool | None = False, use_exponential_sigmas: bool | None = False, use_beta_sigmas: bool | None = False, time_shift_type: str = &#x27;exponential&#x27;, stochastic_sampling: bool = False, final_sigmas_type: str = &#x27;sigma_min&#x27;, sigma_max: float | None = None, sigma_min: float | None = None, sigma_data: float | None = None, use_reference_discrete_timesteps: bool = False)</code></pre>
<p>Euler scheduler.</p>
<p>This model inherits from [<code>SchedulerMixin</code>] and [<code>ConfigMixin</code>]. Check the superclass documentation for the generic
methods the library implements for all schedulers such as loading and saving.</p>
<h3>Parameters</h3>
<dl>
<dt><code>num_train_timesteps: `int`, defaults to 1000</code></dt><dd><p>The number of diffusion steps to train the model.</p></dd>
<dt><code>shift: `float`, defaults to 1.0</code></dt><dd><p>The shift value for the timestep schedule.</p></dd>
<dt><code>use_dynamic_shifting: `bool`, defaults to False</code></dt><dd><p>Whether to apply timestep shifting on-the-fly based on the image resolution.</p></dd>
<dt><code>base_shift: `float`, defaults to 0.5</code></dt><dd><p>Value to stabilize image generation. Increasing <code>base_shift</code> reduces variation and image is more consistent
with desired output.</p></dd>
<dt><code>max_shift: `float`, defaults to 1.15</code></dt><dd><p>Value change allowed to latent vectors. Increasing <code>max_shift</code> encourages more variation and image may be
more exaggerated or stylized.</p></dd>
<dt><code>base_image_seq_len: `int`, defaults to 256</code></dt><dd><p>The base image sequence length.</p></dd>
<dt><code>max_image_seq_len: `int`, defaults to 4096</code></dt><dd><p>The maximum image sequence length.</p></dd>
<dt><code>invert_sigmas: `bool`, defaults to False</code></dt><dd><p>Whether to invert the sigmas.</p></dd>
<dt><code>shift_terminal: `float`, defaults to None</code></dt><dd><p>The end value of the shifted timestep schedule.</p></dd>
<dt><code>use_karras_sigmas: `bool`, defaults to False</code></dt><dd><p>Whether to use Karras sigmas for step sizes in the noise schedule during sampling.</p></dd>
<dt><code>use_exponential_sigmas: `bool`, defaults to False</code></dt><dd><p>Whether to use exponential sigmas for step sizes in the noise schedule during sampling.</p></dd>
<dt><code>use_beta_sigmas: `bool`, defaults to False</code></dt><dd><p>Whether to use beta sigmas for step sizes in the noise schedule during sampling.</p></dd>
<dt><code>time_shift_type: `str`, defaults to &quot;exponential&quot;</code></dt><dd><p>The type of dynamic resolution-dependent timestep shifting to apply. Either "exponential" or "linear".</p></dd>
<dt><code>stochastic_sampling: `bool`, defaults to False</code></dt><dd><p>Whether to use stochastic sampling.</p></dd>
<dt><code>final_sigmas_type: `str`, defaults to &quot;sigma_min&quot;</code></dt><dd><p>The type of final sigmas to use. Either "sigma_min" or "zero".</p></dd>
<dt><code>sigma_max: `float`, *optional*</code></dt><dd><p>The maximum sigma value for the noise schedule.</p></dd>
<dt><code>sigma_min: `float`, *optional*</code></dt><dd><p>The minimum sigma value for the noise schedule.</p></dd>
<dt><code>sigma_data: `float`, *optional*</code></dt><dd><p>The sigma data value for scaling.</p></dd>
<dt><code>use_reference_discrete_timesteps: `bool`, defaults to False</code></dt><dd><p>Some reference schedulers (e.g. MMAudio) construct the timestep
schedule by linspacing <code>num_inference_steps + 1</code> points from
<code>t_max</code> to <code>t_min</code> and dropping the terminal point. Default
(<code>False</code>) preserves the original <code>np.linspace(t_max, t_min,
num_inference_steps)</code> (float64) behaviour used by every existing
model. Enable this flag only when matching a reference scheduler
that expects the +1 + drop-terminal construction.</p></dd>
</dl>

<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.shift"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.shift</code></h3>
<pre class="doc-signature"><code>shift: float</code></pre>
<p>The value used for shifting.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.step_index"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.step_index</code></h3>
<pre class="doc-signature"><code>step_index: int | None</code></pre>
<p>The index counter for current timestep. It will increase 1 after each scheduler step.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.begin_index"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.begin_index</code></h3>
<pre class="doc-signature"><code>begin_index: int | None</code></pre>
<p>The index for the first timestep. It should be set from pipeline with <code>set_begin_index</code> method.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.set_begin_index"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.set_begin_index</code></h3>
<pre class="doc-signature"><code>set_begin_index(begin_index: int = 0) -&gt; None</code></pre>
<p>Sets the begin index for the scheduler. This function should be run from pipeline before the inference.</p>
<h4>Parameters</h4>
<dl>
<dt><code>begin_index: `int`</code></dt><dd><p>The begin index for the scheduler.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.set_shift"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.set_shift</code></h3>
<pre class="doc-signature"><code>set_shift(shift: float) -&gt; None</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.scale_noise"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.scale_noise</code></h3>
<pre class="doc-signature"><code>scale_noise(sample: torch.FloatTensor, timestep: float | torch.FloatTensor, noise: torch.FloatTensor | None = None) -&gt; torch.FloatTensor</code></pre>
<p>Forward process in flow-matching</p>
<h4>Parameters</h4>
<dl>
<dt><code>sample: `torch.FloatTensor`</code></dt><dd><p>The input sample.</p></dd>
<dt><code>timestep: `int`, *optional*</code></dt><dd><p>The current timestep in the diffusion chain.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.FloatTensor</code></dt><dd><p><code>torch.FloatTensor</code>:
A scaled input sample.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.time_shift"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.time_shift</code></h3>
<pre class="doc-signature"><code>time_shift(mu: float, sigma: float, t: torch.Tensor | np.ndarray) -&gt; torch.Tensor | np.ndarray</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.stretch_shift_to_terminal"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.stretch_shift_to_terminal</code></h3>
<pre class="doc-signature"><code>stretch_shift_to_terminal(t: torch.Tensor) -&gt; torch.Tensor</code></pre>
<p>Stretches and shifts the timestep schedule to ensure it terminates at the configured <code>shift_terminal</code> config
value.</p>
<p>Reference:
https://github.com/Lightricks/LTX-Video/blob/a01a171f8fe3d99dce2728d60a73fecf4d4238ae/ltx_video/schedulers/rf.py#L51</p>
<h4>Parameters</h4>
<dl>
<dt><code>t: `torch.Tensor`</code></dt><dd><p>A tensor of timesteps to be stretched and shifted.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p><code>torch.Tensor</code>:
A tensor of adjusted timesteps such that the final value equals <code>self.config.shift_terminal</code>.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.set_timesteps"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.set_timesteps</code></h3>
<pre class="doc-signature"><code>set_timesteps(num_inference_steps: int | None = None, device: str | torch.device = None, sigmas: list&#91;float&#93; | None = None, mu: float | None = None, timesteps: list&#91;float&#93; | None = None) -&gt; None</code></pre>
<p>Sets the discrete timesteps used for the diffusion chain (to be run before inference).</p>
<h4>Parameters</h4>
<dl>
<dt><code>num_inference_steps: `int`, *optional*</code></dt><dd><p>The number of diffusion steps used when generating samples with a pre-trained model.</p></dd>
<dt><code>device: `str` or `torch.device`, *optional*</code></dt><dd><p>The device to which the timesteps should be moved to. If <code>None</code>, the timesteps are not moved.</p></dd>
<dt><code>sigmas: `List[float]`, *optional*</code></dt><dd><p>Custom values for sigmas to be used for each diffusion step. If <code>None</code>, the sigmas are computed
automatically.</p></dd>
<dt><code>mu: `float`, *optional*</code></dt><dd><p>Determines the amount of shifting applied to sigmas when performing resolution-dependent timestep
shifting.</p></dd>
<dt><code>timesteps: `List[float]`, *optional*</code></dt><dd><p>Custom values for timesteps to be used for each diffusion step. If <code>None</code>, the timesteps are computed
automatically.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.index_for_timestep"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.index_for_timestep</code></h3>
<pre class="doc-signature"><code>index_for_timestep(timestep: float | torch.FloatTensor, schedule_timesteps: torch.Tensor | None = None) -&gt; int</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.step"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.step</code></h3>
<pre class="doc-signature"><code>step(model_output: torch.FloatTensor, timestep: int | torch.Tensor, sample: torch.FloatTensor, s_churn: float = 0.0, s_tmin: float = 0.0, s_tmax: float = float(&#x27;inf&#x27;), s_noise: float = 1.0, generator: torch.Generator | None = None, per_token_timesteps: torch.Tensor | None = None, return_dict: bool = True) -&gt; FlowMatchEulerDiscreteSchedulerOutput | tuple&#91;torch.FloatTensor, ...&#93;</code></pre>
<p>Predict the sample from the previous timestep by reversing the SDE. This function propagates the diffusion
process from the learned model outputs (most often the predicted noise).</p>
<h4>Parameters</h4>
<dl>
<dt><code>model_output: `torch.FloatTensor`</code></dt><dd><p>The direct output from learned diffusion model.</p></dd>
<dt><code>timestep: `int` or `torch.Tensor`</code></dt><dd><p>The current discrete timestep in the diffusion chain.</p></dd>
<dt><code>sample: `torch.FloatTensor`</code></dt><dd><p>A current instance of a sample created by the diffusion process.</p></dd>
<dt><code>s_churn: `float`</code></dt><dd></dd>
<dt><code>s_tmin: `float`</code></dt><dd></dd>
<dt><code>s_tmax: `float`</code></dt><dd></dd>
<dt><code>s_noise: `float`, defaults to 1.0</code></dt><dd><p>Scaling factor for noise added to the sample.</p></dd>
<dt><code>generator: `torch.Generator`, *optional*</code></dt><dd><p>A random number generator.</p></dd>
<dt><code>per_token_timesteps: `torch.Tensor`, *optional*</code></dt><dd><p>The timesteps for each token in the sample.</p></dd>
<dt><code>return_dict: `bool`</code></dt><dd><p>Whether or not to return a
[<code>~schedulers.scheduling_flow_match_euler_discrete.FlowMatchEulerDiscreteSchedulerOutput</code>] or tuple.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>FlowMatchEulerDiscreteSchedulerOutput | tuple[torch.FloatTensor, ...]</code></dt><dd><p>[<code>~schedulers.scheduling_flow_match_euler_discrete.FlowMatchEulerDiscreteSchedulerOutput</code>] or <code>tuple</code>:
If return_dict is <code>True</code>,
[<code>~schedulers.scheduling_flow_match_euler_discrete.FlowMatchEulerDiscreteSchedulerOutput</code>] is returned,
otherwise a tuple is returned where the first element is the sample tensor.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.add_noise"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.add_noise</code></h3>
<pre class="doc-signature"><code>add_noise(clean_latent: torch.Tensor, noise: torch.Tensor, timestep: torch.IntTensor) -&gt; torch.Tensor</code></pre>
<h4>Parameters</h4>
<dl>
<dt><code>clean_latent: torch.Tensor</code></dt><dd><p>the clean latent with shape [B, C, H, W],
where B is batch_size or batch_size * num_frames</p></dd>
<dt><code>noise: torch.Tensor</code></dt><dd><p>the noise with shape [B, C, H, W]</p></dd>
<dt><code>timestep: torch.IntTensor</code></dt><dd><p>the timestep with shape [1] or [bs * num_frames] or [bs, num_frames]</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p>the corrupted latent with shape [B, C, H, W]</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.scale_model_input"><code>fastvideo.pipelines.stages.kandinsky5.FlowMatchEulerDiscreteScheduler.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>

<h2 id="fastvideo.pipelines.stages.kandinsky5.pred_noise_to_pred_video"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.ParallelTiledVAE"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE</code></h2>
<pre class="doc-signature"><code>ParallelTiledVAE(config: VAEConfig, **kwargs)</code></pre>


<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.to"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.to</code></h3>
<pre class="doc-signature"><code>to(device) -&gt; ParallelTiledVAE</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.encode"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.encode</code></h3>
<pre class="doc-signature"><code>encode(x: torch.Tensor) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.decode"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.decode</code></h3>
<pre class="doc-signature"><code>decode(z: torch.Tensor) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.blend_v"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.blend_v</code></h3>
<pre class="doc-signature"><code>blend_v(a: torch.Tensor, b: torch.Tensor, blend_extent: int) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.blend_h"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.blend_h</code></h3>
<pre class="doc-signature"><code>blend_h(a: torch.Tensor, b: torch.Tensor, blend_extent: int) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.blend_t"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.blend_t</code></h3>
<pre class="doc-signature"><code>blend_t(a: torch.Tensor, b: torch.Tensor, blend_extent: int) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.spatial_tiled_encode"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.spatial_tiled_encode</code></h3>
<pre class="doc-signature"><code>spatial_tiled_encode(x: torch.Tensor) -&gt; torch.Tensor</code></pre>
<p>Encode a batch of images using a tiled encoder.</p>
<h4>Parameters</h4>
<dl>
<dt><code>x: `torch.Tensor`</code></dt><dd><p>Input batch of videos.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p><code>torch.Tensor</code>:
The latent representation of the encoded videos.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.parallel_tiled_decode"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.parallel_tiled_decode</code></h3>
<pre class="doc-signature"><code>parallel_tiled_decode(z: torch.FloatTensor) -&gt; torch.FloatTensor</code></pre>
<p>Parallel version of tiled_decode that distributes both temporal and spatial computation across GPUs</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.spatial_tiled_decode"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.spatial_tiled_decode</code></h3>
<pre class="doc-signature"><code>spatial_tiled_decode(z: torch.Tensor) -&gt; torch.Tensor</code></pre>
<p>Decode a batch of images using a tiled decoder.</p>
<h4>Parameters</h4>
<dl>
<dt><code>z: `torch.Tensor`</code></dt><dd><p>Input batch of latent vectors.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p><code>torch.Tensor</code>:
The decoded images.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.tiled_encode"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.tiled_encode</code></h3>
<pre class="doc-signature"><code>tiled_encode(x: torch.Tensor) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.tiled_decode"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.tiled_decode</code></h3>
<pre class="doc-signature"><code>tiled_decode(z: torch.Tensor) -&gt; torch.Tensor</code></pre>

<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.enable_tiling"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.enable_tiling</code></h3>
<pre class="doc-signature"><code>enable_tiling(tile_sample_min_height: int | None = None, tile_sample_min_width: int | None = None, tile_sample_min_num_frames: int | None = None, tile_sample_stride_height: int | None = None, tile_sample_stride_width: int | None = None, tile_sample_stride_num_frames: int | None = None, blend_num_frames: int | None = None, use_tiling: bool | None = None, use_temporal_tiling: bool | None = None, use_parallel_tiling: bool | None = None) -&gt; None</code></pre>
<p>Enable tiled VAE decoding. When this option is enabled, the VAE will split the input tensor into tiles to
compute decoding and encoding in several steps. This is useful for saving a large amount of memory and to allow
processing larger images.</p>
<h4>Parameters</h4>
<dl>
<dt><code>tile_sample_min_height: `int`, *optional*</code></dt><dd><p>The minimum height required for a sample to be separated into tiles across the height dimension.</p></dd>
<dt><code>tile_sample_min_width: `int`, *optional*</code></dt><dd><p>The minimum width required for a sample to be separated into tiles across the width dimension.</p></dd>
<dt><code>tile_sample_min_num_frames: `int`, *optional*</code></dt><dd><p>The minimum number of frames required for a sample to be separated into tiles across the frame
dimension.</p></dd>
<dt><code>tile_sample_stride_height: `int`, *optional*</code></dt><dd><p>The minimum amount of overlap between two consecutive vertical tiles. This is to ensure that there are
no tiling artifacts produced across the height dimension.</p></dd>
<dt><code>tile_sample_stride_width: `int`, *optional*</code></dt><dd><p>The stride between two consecutive horizontal tiles. This is to ensure that there are no tiling
artifacts produced across the width dimension.</p></dd>
<dt><code>tile_sample_stride_num_frames: `int`, *optional*</code></dt><dd><p>The stride between two consecutive frame tiles. This is to ensure that there are no tiling artifacts
produced across the frame dimension.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.disable_tiling"><code>fastvideo.pipelines.stages.kandinsky5.ParallelTiledVAE.disable_tiling</code></h3>
<pre class="doc-signature"><code>disable_tiling() -&gt; None</code></pre>
<p>Disable tiled VAE decoding. If <code>enable_tiling</code> was previously enabled, this method will go back to computing
decoding in one step.</p>
<h2 id="fastvideo.pipelines.stages.kandinsky5.normalize"><code>fastvideo.pipelines.stages.kandinsky5.normalize</code></h2>
<pre class="doc-signature"><code>normalize(images: np.ndarray | torch.Tensor) -&gt; np.ndarray | torch.Tensor</code></pre>
<p>Normalize an image array to [-1,1].</p>
<h3>Parameters</h3>
<dl>
<dt><code>images: `np.ndarray` or `torch.Tensor`</code></dt><dd><p>The image array to normalize.</p></dd>
</dl>
<h3>Returns</h3>
<dl>
<dt><code>np.ndarray | torch.Tensor</code></dt><dd><p><code>np.ndarray</code> or <code>torch.Tensor</code>:
The normalized image array.</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.numpy_to_pt"><code>fastvideo.pipelines.stages.kandinsky5.numpy_to_pt</code></h2>
<pre class="doc-signature"><code>numpy_to_pt(images: np.ndarray) -&gt; torch.Tensor</code></pre>
<p>Convert a NumPy image to a PyTorch tensor.</p>
<h3>Parameters</h3>
<dl>
<dt><code>images: `np.ndarray`</code></dt><dd><p>The NumPy image array to convert to PyTorch format.</p></dd>
</dl>
<h3>Returns</h3>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p><code>torch.Tensor</code>:
A PyTorch tensor representation of the images.</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.pil_to_numpy"><code>fastvideo.pipelines.stages.kandinsky5.pil_to_numpy</code></h2>
<pre class="doc-signature"><code>pil_to_numpy(images: list&#91;PIL.Image.Image&#93; | PIL.Image.Image) -&gt; np.ndarray</code></pre>
<p>Convert a PIL image or a list of PIL images to NumPy arrays.</p>
<h3>Parameters</h3>
<dl>
<dt><code>images: `PIL.Image.Image` or `List[PIL.Image.Image]`</code></dt><dd><p>The PIL image or list of images to convert to NumPy format.</p></dd>
</dl>
<h3>Returns</h3>
<dl>
<dt><code>np.ndarray</code></dt><dd><p><code>np.ndarray</code>:
A NumPy array representation of the images.</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.resize"><code>fastvideo.pipelines.stages.kandinsky5.resize</code></h2>
<pre class="doc-signature"><code>resize(image: PIL.Image.Image | np.ndarray | torch.Tensor, height: int, width: int, resize_mode: str = &#x27;default&#x27;, resample: str = &#x27;lanczos&#x27;) -&gt; PIL.Image.Image | np.ndarray | torch.Tensor</code></pre>
<p>Resize image.</p>
<h3>Parameters</h3>
<dl>
<dt><code>image: `PIL.Image.Image`, `np.ndarray` or `torch.Tensor`</code></dt><dd><p>The image input, can be a PIL image, numpy array or pytorch tensor.</p></dd>
<dt><code>height: `int`</code></dt><dd><p>The height to resize to.</p></dd>
<dt><code>width: `int`</code></dt><dd><p>The width to resize to.</p></dd>
<dt><code>resize_mode: `str`, *optional*, defaults to `default`</code></dt><dd><p>The resize mode to use, can be one of <code>default</code> or <code>fill</code>. If <code>default</code>, will resize the image to fit
within the specified width and height, and it may not maintaining the original aspect ratio. If <code>fill</code>,
will resize the image to fit within the specified width and height, maintaining the aspect ratio, and
then center the image within the dimensions, filling empty with data from image. If <code>crop</code>, will resize
the image to fit within the specified width and height, maintaining the aspect ratio, and then center
the image within the dimensions, cropping the excess. Note that resize_mode <code>fill</code> and <code>crop</code> are only
supported for PIL image input.</p></dd>
</dl>
<h3>Returns</h3>
<dl>
<dt><code>PIL.Image.Image | np.ndarray | torch.Tensor</code></dt><dd><p><code>PIL.Image.Image</code>, <code>np.ndarray</code> or <code>torch.Tensor</code>:
The resized image.</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.ForwardBatch"><code>fastvideo.pipelines.stages.kandinsky5.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.pipelines.stages.kandinsky5.PipelineStage"><code>fastvideo.pipelines.stages.kandinsky5.PipelineStage</code></h2>
<pre class="doc-signature"><code>PipelineStage()</code></pre>
<p>Abstract base class for all pipeline stages.</p>
<p>A pipeline stage represents a discrete step in the diffusion process that can be
composed with other stages to create a complete pipeline. Each stage is responsible
for a specific part of the process, such as prompt encoding, latent preparation, etc.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.PipelineStage.verify_input"><code>fastvideo.pipelines.stages.kandinsky5.PipelineStage.verify_input</code></h3>
<pre class="doc-signature"><code>verify_input(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>
<p>Verify the input for the stage.</p>
<h4>Example</h4>
<p>from fastvideo.pipelines.stages.validators import V, VerificationResult</p>
<p>def verify_input(self, batch, fastvideo_args):
    result = VerificationResult()
    result.add_check("height", batch.height, V.positive_int_divisible(8))
    result.add_check("width", batch.width, V.positive_int_divisible(8))
    result.add_check("image_latent", batch.image_latent, V.is_tensor)
    return result</p>
<h4>Parameters</h4>
<dl>
<dt><code>batch: ForwardBatch</code></dt><dd><p>The current batch information.</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>The inference arguments.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>VerificationResult</code></dt><dd><p>A VerificationResult containing the verification status.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.PipelineStage.verify_output"><code>fastvideo.pipelines.stages.kandinsky5.PipelineStage.verify_output</code></h3>
<pre class="doc-signature"><code>verify_output(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>
<p>Verify the output for the stage.</p>
<h4>Parameters</h4>
<dl>
<dt><code>batch: ForwardBatch</code></dt><dd><p>The current batch information.</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>The inference arguments.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>VerificationResult</code></dt><dd><p>A VerificationResult containing the verification status.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.PipelineStage.device"><code>fastvideo.pipelines.stages.kandinsky5.PipelineStage.device</code></h3>
<pre class="doc-signature"><code>device: torch.device</code></pre>
<p>Get the device for this stage.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.PipelineStage.set_logging"><code>fastvideo.pipelines.stages.kandinsky5.PipelineStage.set_logging</code></h3>
<pre class="doc-signature"><code>set_logging(enable: bool)</code></pre>
<p>Enable or disable logging for this stage.</p>
<h4>Parameters</h4>
<dl>
<dt><code>enable: bool</code></dt><dd><p>Whether to enable logging.</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.PipelineStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.PipelineStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>
<p>Forward pass of the stage's processing.</p>
<p>This method should be implemented by subclasses to provide the forward
processing logic for the stage.</p>
<h4>Parameters</h4>
<dl>
<dt><code>batch: ForwardBatch</code></dt><dd><p>The current batch information.</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>The inference arguments.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>ForwardBatch</code></dt><dd><p>The updated batch information after this stage's processing.</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.DecodingStage"><code>fastvideo.pipelines.stages.kandinsky5.DecodingStage</code></h2>
<pre class="doc-signature"><code>DecodingStage(vae, pipeline = None)</code></pre>
<p>Stage for decoding latent representations into pixel space.</p>
<p>This stage handles the decoding of latent representations into the final
output format (e.g., pixel values).</p>

<h3 id="fastvideo.pipelines.stages.kandinsky5.DecodingStage.verify_input"><code>fastvideo.pipelines.stages.kandinsky5.DecodingStage.verify_input</code></h3>
<pre class="doc-signature"><code>verify_input(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>
<p>Verify decoding stage inputs.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.DecodingStage.verify_output"><code>fastvideo.pipelines.stages.kandinsky5.DecodingStage.verify_output</code></h3>
<pre class="doc-signature"><code>verify_output(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>
<p>Verify decoding stage outputs.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.DecodingStage.decode"><code>fastvideo.pipelines.stages.kandinsky5.DecodingStage.decode</code></h3>
<pre class="doc-signature"><code>decode(latents: torch.Tensor, fastvideo_args: FastVideoArgs) -&gt; torch.Tensor</code></pre>
<p>Decode latent representations into pixel space using VAE.</p>
<h4>Parameters</h4>
<dl>
<dt><code>latents: torch.Tensor</code></dt><dd><p>Input latent tensor with shape (batch, channels, frames, height_latents, width_latents)</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>Configuration containing:
- disable_autocast: Whether to disable automatic mixed precision (default: False)
- pipeline_config.vae_precision: VAE computation precision ("fp32", "fp16", "bf16")
- pipeline_config.vae_tiling: Whether to enable VAE tiling for memory efficiency</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p>Decoded video tensor with shape (batch, channels, frames, height, width), </p></dd>
<dt><code>torch.Tensor</code></dt><dd><p>normalized to [0, 1] range and moved to CPU as float32</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.DecodingStage.streaming_decode"><code>fastvideo.pipelines.stages.kandinsky5.DecodingStage.streaming_decode</code></h3>
<pre class="doc-signature"><code>streaming_decode(latents: torch.Tensor, fastvideo_args: FastVideoArgs, cache: list&#91;torch.Tensor | None&#93; | None = None, is_first_chunk: bool = False) -&gt; tuple&#91;torch.Tensor, list&#91;torch.Tensor | None&#93;&#93;</code></pre>
<p>Decode latent representations into pixel space using VAE with streaming cache.</p>
<h4>Parameters</h4>
<dl>
<dt><code>latents: torch.Tensor</code></dt><dd><p>Input latent tensor with shape (batch, channels, frames, height_latents, width_latents)</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>Configuration object.</p></dd>
<dt><code>cache: list[torch.Tensor | None] | None</code></dt><dd><p>VAE cache from previous call, or None to initialize a new cache.</p></dd>
<dt><code>is_first_chunk: bool</code></dt><dd><p>Whether this is the first chunk.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>tuple[torch.Tensor, list[torch.Tensor | None]]</code></dt><dd><p>A tuple of (decoded_frames, updated_cache).</p></dd>
</dl>
<h3 id="fastvideo.pipelines.stages.kandinsky5.DecodingStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.DecodingStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>
<p>Decode latent representations into pixel space.</p>
<p>This method processes the batch through the VAE decoder, converting latent
representations to pixel-space video/images. It also optionally decodes
trajectory latents for visualization purposes.</p>
<h4>Parameters</h4>
<dl>
<dt><code>batch: ForwardBatch</code></dt><dd><p>The current batch containing:
- latents: Tensor to decode (batch, channels, frames, height_latents, width_latents)
- return_trajectory_decoded (optional): Flag to decode trajectory latents
- trajectory_latents (optional): Latents at different timesteps
- trajectory_timesteps (optional): Corresponding timesteps</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>Configuration containing:
- output_type: "latent" to skip decoding, otherwise decode to pixels
- vae_cpu_offload: Whether to offload VAE to CPU after decoding
- model_loaded: Track VAE loading state
- model_paths: Path to VAE model if loading needed</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>ForwardBatch</code></dt><dd><p>Modified batch with:
- output: Decoded frames (batch, channels, frames, height, width) as CPU float32
- trajectory_decoded (if requested): List of decoded frames per timestep</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.EncodingStage"><code>fastvideo.pipelines.stages.kandinsky5.EncodingStage</code></h2>
<pre class="doc-signature"><code>EncodingStage(vae: ParallelTiledVAE)</code></pre>
<p>Stage for encoding pixel space representations into latent space.</p>
<p>This stage handles the encoding of pixel-space video/images into latent
representations for further processing in the diffusion pipeline.</p>

<h3 id="fastvideo.pipelines.stages.kandinsky5.EncodingStage.verify_input"><code>fastvideo.pipelines.stages.kandinsky5.EncodingStage.verify_input</code></h3>
<pre class="doc-signature"><code>verify_input(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>
<p>Verify encoding stage inputs.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.EncodingStage.verify_output"><code>fastvideo.pipelines.stages.kandinsky5.EncodingStage.verify_output</code></h3>
<pre class="doc-signature"><code>verify_output(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>
<p>Verify encoding stage outputs.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.EncodingStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.EncodingStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>
<p>Encode pixel space representations into latent space.</p>
<h4>Parameters</h4>
<dl>
<dt><code>batch: ForwardBatch</code></dt><dd><p>The current batch information.</p></dd>
<dt><code>fastvideo_args: FastVideoArgs</code></dt><dd><p>The inference arguments.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>ForwardBatch</code></dt><dd><p>The batch with encoded latents.</p></dd>
</dl>
<h2 id="fastvideo.pipelines.stages.kandinsky5.V"><code>fastvideo.pipelines.stages.kandinsky5.V</code></h2>
<pre class="doc-signature"><code>V()</code></pre>
<p>Common validators for pipeline stages.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.not_none"><code>fastvideo.pipelines.stages.kandinsky5.V.not_none</code></h3>
<pre class="doc-signature"><code>not_none(value: Any) -&gt; bool</code></pre>
<p>Check if value is not None.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.positive_int"><code>fastvideo.pipelines.stages.kandinsky5.V.positive_int</code></h3>
<pre class="doc-signature"><code>positive_int(value: Any) -&gt; bool</code></pre>
<p>Check if value is a positive integer.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.non_negative_int"><code>fastvideo.pipelines.stages.kandinsky5.V.non_negative_int</code></h3>
<pre class="doc-signature"><code>non_negative_int(value: Any) -&gt; bool</code></pre>
<p>Check if value is a non-negative integer (allows 0).</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.positive_float"><code>fastvideo.pipelines.stages.kandinsky5.V.positive_float</code></h3>
<pre class="doc-signature"><code>positive_float(value: Any) -&gt; bool</code></pre>
<p>Check if value is a positive float.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.non_negative_float"><code>fastvideo.pipelines.stages.kandinsky5.V.non_negative_float</code></h3>
<pre class="doc-signature"><code>non_negative_float(value: Any) -&gt; bool</code></pre>
<p>Check if value is a non-negative float.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.divisible_by"><code>fastvideo.pipelines.stages.kandinsky5.V.divisible_by</code></h3>
<pre class="doc-signature"><code>divisible_by(value: Any, divisor: int) -&gt; bool</code></pre>
<p>Check if value is divisible by divisor.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.is_tensor"><code>fastvideo.pipelines.stages.kandinsky5.V.is_tensor</code></h3>
<pre class="doc-signature"><code>is_tensor(value: Any) -&gt; bool</code></pre>
<p>Check if value is a torch tensor and doesn't contain NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.tensor_with_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.tensor_with_dims</code></h3>
<pre class="doc-signature"><code>tensor_with_dims(value: Any, dims: int) -&gt; bool</code></pre>
<p>Check if value is a tensor with specific dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.tensor_min_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.tensor_min_dims</code></h3>
<pre class="doc-signature"><code>tensor_min_dims(value: Any, min_dims: int) -&gt; bool</code></pre>
<p>Check if value is a tensor with at least min_dims dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.tensor_shape_matches"><code>fastvideo.pipelines.stages.kandinsky5.V.tensor_shape_matches</code></h3>
<pre class="doc-signature"><code>tensor_shape_matches(value: Any, expected_shape: tuple) -&gt; bool</code></pre>
<p>Check if tensor shape matches expected shape (None for any size) and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_not_empty"><code>fastvideo.pipelines.stages.kandinsky5.V.list_not_empty</code></h3>
<pre class="doc-signature"><code>list_not_empty(value: Any) -&gt; bool</code></pre>
<p>Check if value is a non-empty list.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_length"><code>fastvideo.pipelines.stages.kandinsky5.V.list_length</code></h3>
<pre class="doc-signature"><code>list_length(value: Any, length: int) -&gt; bool</code></pre>
<p>Check if list has specific length.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_min_length"><code>fastvideo.pipelines.stages.kandinsky5.V.list_min_length</code></h3>
<pre class="doc-signature"><code>list_min_length(value: Any, min_length: int) -&gt; bool</code></pre>
<p>Check if list has at least min_length items.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.string_not_empty"><code>fastvideo.pipelines.stages.kandinsky5.V.string_not_empty</code></h3>
<pre class="doc-signature"><code>string_not_empty(value: Any) -&gt; bool</code></pre>
<p>Check if value is a non-empty string.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.string_or_list_strings"><code>fastvideo.pipelines.stages.kandinsky5.V.string_or_list_strings</code></h3>
<pre class="doc-signature"><code>string_or_list_strings(value: Any) -&gt; bool</code></pre>
<p>Check if value is a string or list of strings.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.bool_value"><code>fastvideo.pipelines.stages.kandinsky5.V.bool_value</code></h3>
<pre class="doc-signature"><code>bool_value(value: Any) -&gt; bool</code></pre>
<p>Check if value is a boolean.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.generator_or_list_generators"><code>fastvideo.pipelines.stages.kandinsky5.V.generator_or_list_generators</code></h3>
<pre class="doc-signature"><code>generator_or_list_generators(value: Any) -&gt; bool</code></pre>
<p>Check if value is a Generator or list of Generators.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.is_list"><code>fastvideo.pipelines.stages.kandinsky5.V.is_list</code></h3>
<pre class="doc-signature"><code>is_list(value: Any) -&gt; bool</code></pre>
<p>Check if value is a list (can be empty).</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.is_tuple"><code>fastvideo.pipelines.stages.kandinsky5.V.is_tuple</code></h3>
<pre class="doc-signature"><code>is_tuple(value: Any) -&gt; bool</code></pre>
<p>Check if value is a tuple.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.none_or_tensor"><code>fastvideo.pipelines.stages.kandinsky5.V.none_or_tensor</code></h3>
<pre class="doc-signature"><code>none_or_tensor(value: Any) -&gt; bool</code></pre>
<p>Check if value is None or a tensor without NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_with_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_with_dims</code></h3>
<pre class="doc-signature"><code>list_of_tensors_with_dims(value: Any, dims: int) -&gt; bool</code></pre>
<p>Check if value is a non-empty list where all items are tensors with specific dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors"><code>fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors</code></h3>
<pre class="doc-signature"><code>list_of_tensors(value: Any) -&gt; bool</code></pre>
<p>Check if value is a non-empty list where all items are tensors without NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_with_min_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_with_min_dims</code></h3>
<pre class="doc-signature"><code>list_of_tensors_with_min_dims(value: Any, min_dims: int) -&gt; bool</code></pre>
<p>Check if value is a non-empty list where all items are tensors with at least min_dims dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.none_or_tensor_with_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.none_or_tensor_with_dims</code></h3>
<pre class="doc-signature"><code>none_or_tensor_with_dims(dims: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if value is None or a tensor with specific dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.none_or_list"><code>fastvideo.pipelines.stages.kandinsky5.V.none_or_list</code></h3>
<pre class="doc-signature"><code>none_or_list(value: Any) -&gt; bool</code></pre>
<p>Check if value is None or a list.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.none_or_positive_int"><code>fastvideo.pipelines.stages.kandinsky5.V.none_or_positive_int</code></h3>
<pre class="doc-signature"><code>none_or_positive_int(value: Any) -&gt; bool</code></pre>
<p>Check if value is None or a positive integer.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.with_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.with_dims</code></h3>
<pre class="doc-signature"><code>with_dims(dims: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if tensor has specific dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.min_list_length"><code>fastvideo.pipelines.stages.kandinsky5.V.min_list_length</code></h3>
<pre class="doc-signature"><code>min_list_length(min_length: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if a list has at least min_length items.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.min_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.min_dims</code></h3>
<pre class="doc-signature"><code>min_dims(min_dims: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if tensor has at least min_dims dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.divisible"><code>fastvideo.pipelines.stages.kandinsky5.V.divisible</code></h3>
<pre class="doc-signature"><code>divisible(divisor: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if value is divisible by divisor.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.positive_int_divisible"><code>fastvideo.pipelines.stages.kandinsky5.V.positive_int_divisible</code></h3>
<pre class="doc-signature"><code>positive_int_divisible(divisor: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if value is a positive integer divisible by divisor.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_dims</code></h3>
<pre class="doc-signature"><code>list_of_tensors_dims(dims: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if value is a list of tensors with specific dimensions and no NaN values.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_min_dims"><code>fastvideo.pipelines.stages.kandinsky5.V.list_of_tensors_min_dims</code></h3>
<pre class="doc-signature"><code>list_of_tensors_min_dims(min_dims: int) -&gt; Callable&#91;&#91;Any&#93;, bool&#93;</code></pre>
<p>Return a validator that checks if value is a list of tensors with at least min_dims dimensions and no NaN values.</p>
<h2 id="fastvideo.pipelines.stages.kandinsky5.VerificationResult"><code>fastvideo.pipelines.stages.kandinsky5.VerificationResult</code></h2>
<pre class="doc-signature"><code>VerificationResult()</code></pre>
<p>Wrapper class for stage verification results.</p>

<h3 id="fastvideo.pipelines.stages.kandinsky5.VerificationResult.add_check"><code>fastvideo.pipelines.stages.kandinsky5.VerificationResult.add_check</code></h3>
<pre class="doc-signature"><code>add_check(field_name: str, value: Any, validators: Callable&#91;&#91;Any&#93;, bool&#93; | list&#91;Callable&#91;&#91;Any&#93;, bool&#93;&#93;) -&gt; VerificationResult</code></pre>
<p>Add a validation check for a field.</p>
<h4>Parameters</h4>
<dl>
<dt><code>field_name: str</code></dt><dd><p>Name of the field being checked</p></dd>
<dt><code>value: Any</code></dt><dd><p>The actual value to validate</p></dd>
<dt><code>validators: Callable[[Any], bool] | list[Callable[[Any], bool]]</code></dt><dd><p>Single validation function or list of validation functions.
       Each function will be called with the value as its first argument.</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>VerificationResult</code></dt><dd><p>Self for method chaining</p></dd>
</dl>
<h4>Examples</h4>
<h1>Single validator</h1>
<p>result.add_check("tensor", my_tensor, V.is_tensor)</p>
<h1>Multiple validators (all must pass)</h1>
<p>result.add_check("latents", batch.latents, [V.is_tensor, V.with_dims(5)])</p>
<h1>Using partial functions for parameters</h1>
<p>result.add_check("height", batch.height, [V.not_none, V.divisible(8)])</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.VerificationResult.is_valid"><code>fastvideo.pipelines.stages.kandinsky5.VerificationResult.is_valid</code></h3>
<pre class="doc-signature"><code>is_valid() -&gt; bool</code></pre>
<p>Check if all validations passed.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.VerificationResult.get_failed_fields"><code>fastvideo.pipelines.stages.kandinsky5.VerificationResult.get_failed_fields</code></h3>
<pre class="doc-signature"><code>get_failed_fields() -&gt; list&#91;str&#93;</code></pre>
<p>Get list of fields that failed validation.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.VerificationResult.get_detailed_failures"><code>fastvideo.pipelines.stages.kandinsky5.VerificationResult.get_detailed_failures</code></h3>
<pre class="doc-signature"><code>get_detailed_failures() -&gt; dict&#91;str, list&#91;ValidationFailure&#93;&#93;</code></pre>
<p>Get detailed failure information for each failed field.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.VerificationResult.get_failure_summary"><code>fastvideo.pipelines.stages.kandinsky5.VerificationResult.get_failure_summary</code></h3>
<pre class="doc-signature"><code>get_failure_summary() -&gt; str</code></pre>
<p>Get a comprehensive summary of all validation failures.</p>
<h3 id="fastvideo.pipelines.stages.kandinsky5.VerificationResult.to_dict"><code>fastvideo.pipelines.stages.kandinsky5.VerificationResult.to_dict</code></h3>
<pre class="doc-signature"><code>to_dict() -&gt; dict</code></pre>
<p>Convert to dictionary for backward compatibility.</p>
<h2 id="fastvideo.pipelines.stages.kandinsky5.AttentionBackendEnum"><code>fastvideo.pipelines.stages.kandinsky5.AttentionBackendEnum</code></h2>
<pre class="doc-signature"><code>AttentionBackendEnum()</code></pre>

<h2 id="fastvideo.pipelines.stages.kandinsky5.get_mixed_precision_state"><code>fastvideo.pipelines.stages.kandinsky5.get_mixed_precision_state</code></h2>
<pre class="doc-signature"><code>get_mixed_precision_state() -&gt; MixedPrecisionState</code></pre>
<p>Get the current mixed precision state.</p>
<h2 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage</code></h2>
<pre class="doc-signature"><code>Kandinsky5LatentPreparationStage(scheduler, transformer)</code></pre>


<details><summary>Source</summary><pre><code>class Kandinsky5LatentPreparationStage(PipelineStage):

    def __init__(self, scheduler, transformer) -&gt; None:
        super().__init__()
        self.scheduler = scheduler
        self.transformer = transformer

    def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
        if batch.height is None or batch.width is None:
            raise ValueError(&quot;height and width must be provided for Kandinsky5.&quot;)
        height = int(batch.height)
        width = int(batch.width)
        num_frames = int(batch.num_frames)

        temporal_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio
        spatial_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.spatial_compression_ratio
        patch_size = fastvideo_args.pipeline_config.dit_config.arch_config.patch_size

        if num_frames % temporal_ratio != 1:
            num_frames = num_frames // temporal_ratio * temporal_ratio + 1
            batch.num_frames = num_frames

        required_divisor_h = spatial_ratio * patch_size&#91;1&#93;
        required_divisor_w = spatial_ratio * patch_size&#91;2&#93;
        if height % required_divisor_h != 0 or width % required_divisor_w != 0:
            raise ValueError(f&quot;Kandinsky5 height must be divisible by &#123;required_divisor_h&#125; and width by &quot;
                             f&quot;&#123;required_divisor_w&#125;; &quot;
                             f&quot;got height=&#123;height&#125;, width=&#123;width&#125;.&quot;)

        # NABLA sparse attention (Pro checkpoints) reshapes the post-patch grid
        # into 8x8 blocks; validate here instead of crashing mid-denoise after
        # all the encoding work is done.
        arch_cfg = getattr(self.transformer, &quot;config&quot;, None) or fastvideo_args.pipeline_config.dit_config.arch_config
        if getattr(arch_cfg, &quot;attention_type&quot;, &quot;regular&quot;) == &quot;nabla&quot;:
            nabla_divisor_h = required_divisor_h * 8
            nabla_divisor_w = required_divisor_w * 8
            if height % nabla_divisor_h != 0 or width % nabla_divisor_w != 0:
                raise ValueError(f&quot;Kandinsky5 NABLA checkpoints require height divisible by &#123;nabla_divisor_h&#125; and &quot;
                                 f&quot;width divisible by &#123;nabla_divisor_w&#125;; &quot;
                                 f&quot;got height=&#123;height&#125;, width=&#123;width&#125;.&quot;)

        if isinstance(batch.prompt, list):
            batch_size = len(batch.prompt)
        elif batch.prompt is not None:
            batch_size = 1
        else:
            batch_size = batch.prompt_embeds&#91;0&#93;.shape&#91;0&#93;
        batch_size *= batch.num_videos_per_prompt

        dtype = PRECISION_TO_TYPE&#91;fastvideo_args.pipeline_config.dit_precision&#93;
        device = get_local_torch_device()
        num_latent_frames = (num_frames - 1) // temporal_ratio + 1
        num_channels = getattr(
            self.transformer,
            &quot;in_visual_dim&quot;,
            fastvideo_args.pipeline_config.dit_config.arch_config.in_visual_dim,
        )
        shape = (
            batch_size,
            num_latent_frames,
            height // spatial_ratio,
            width // spatial_ratio,
            num_channels,
        )

        if isinstance(batch.generator, list) and len(batch.generator) != batch_size:
            raise ValueError(f&quot;generator list length &#123;len(batch.generator)&#125; does not match batch size &#123;batch_size&#125;.&quot;)

        visual_cond = getattr(self.transformer, &quot;visual_cond&quot;, False)

        if batch.latents is None:
            latents = randn_tensor(shape, generator=batch.generator, device=device, dtype=dtype)
            if hasattr(self.scheduler, &quot;init_noise_sigma&quot;):
                latents = latents * self.scheduler.init_noise_sigma
        else:
            valid_shapes = &#91;shape&#93;
            if visual_cond:
                valid_shapes.append((*shape&#91;:-1&#93;, num_channels * 2 + 1))
            if tuple(batch.latents.shape) not in valid_shapes:
                raise ValueError(f&quot;Provided latents shape &#123;list(batch.latents.shape)&#125; does not match expected &quot;
                                 f&quot;Kandinsky5 latent shape(s): &#123;&#91;list(s) for s in valid_shapes&#93;&#125;.&quot;)
            latents = batch.latents.to(device=device, dtype=dtype)

        if visual_cond and latents.shape&#91;-1&#93; == num_channels:
            cond = torch.zeros_like(latents)
            cond_mask = torch.zeros(
                (*latents.shape&#91;:-1&#93;, 1),
                device=latents.device,
                dtype=latents.dtype,
            )
            latents = torch.cat(&#91;latents, cond, cond_mask&#93;, dim=-1)

        # I2V image conditioning is placed by Kandinsky5ImageEncodingStage,
        # which runs AFTER this stage so the initial noise is the generator&#x27;s
        # first draw (matching the official kandinskylab/kandinsky-5 order).
        batch.latents = latents
        batch.raw_latent_shape = (
            batch_size,
            num_channels,
            num_latent_frames,
            height // spatial_ratio,
            width // spatial_ratio,
        )
        return batch

    def verify_input(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
        result = VerificationResult()
        result.add_check(&quot;num_frames&quot;, batch.num_frames, V.positive_int)
        result.add_check(&quot;height&quot;, batch.height, V.positive_int)
        result.add_check(&quot;width&quot;, batch.width, V.positive_int)
        result.add_check(&quot;latents&quot;, batch.latents, V.none_or_tensor)
        return result

    def verify_output(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
        result = VerificationResult()
        result.add_check(&quot;latents&quot;, batch.latents, &#91;V.is_tensor, V.with_dims(5)&#93;)
        return result</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
    if batch.height is None or batch.width is None:
        raise ValueError(&quot;height and width must be provided for Kandinsky5.&quot;)
    height = int(batch.height)
    width = int(batch.width)
    num_frames = int(batch.num_frames)

    temporal_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio
    spatial_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.spatial_compression_ratio
    patch_size = fastvideo_args.pipeline_config.dit_config.arch_config.patch_size

    if num_frames % temporal_ratio != 1:
        num_frames = num_frames // temporal_ratio * temporal_ratio + 1
        batch.num_frames = num_frames

    required_divisor_h = spatial_ratio * patch_size&#91;1&#93;
    required_divisor_w = spatial_ratio * patch_size&#91;2&#93;
    if height % required_divisor_h != 0 or width % required_divisor_w != 0:
        raise ValueError(f&quot;Kandinsky5 height must be divisible by &#123;required_divisor_h&#125; and width by &quot;
                         f&quot;&#123;required_divisor_w&#125;; &quot;
                         f&quot;got height=&#123;height&#125;, width=&#123;width&#125;.&quot;)

    # NABLA sparse attention (Pro checkpoints) reshapes the post-patch grid
    # into 8x8 blocks; validate here instead of crashing mid-denoise after
    # all the encoding work is done.
    arch_cfg = getattr(self.transformer, &quot;config&quot;, None) or fastvideo_args.pipeline_config.dit_config.arch_config
    if getattr(arch_cfg, &quot;attention_type&quot;, &quot;regular&quot;) == &quot;nabla&quot;:
        nabla_divisor_h = required_divisor_h * 8
        nabla_divisor_w = required_divisor_w * 8
        if height % nabla_divisor_h != 0 or width % nabla_divisor_w != 0:
            raise ValueError(f&quot;Kandinsky5 NABLA checkpoints require height divisible by &#123;nabla_divisor_h&#125; and &quot;
                             f&quot;width divisible by &#123;nabla_divisor_w&#125;; &quot;
                             f&quot;got height=&#123;height&#125;, width=&#123;width&#125;.&quot;)

    if isinstance(batch.prompt, list):
        batch_size = len(batch.prompt)
    elif batch.prompt is not None:
        batch_size = 1
    else:
        batch_size = batch.prompt_embeds&#91;0&#93;.shape&#91;0&#93;
    batch_size *= batch.num_videos_per_prompt

    dtype = PRECISION_TO_TYPE&#91;fastvideo_args.pipeline_config.dit_precision&#93;
    device = get_local_torch_device()
    num_latent_frames = (num_frames - 1) // temporal_ratio + 1
    num_channels = getattr(
        self.transformer,
        &quot;in_visual_dim&quot;,
        fastvideo_args.pipeline_config.dit_config.arch_config.in_visual_dim,
    )
    shape = (
        batch_size,
        num_latent_frames,
        height // spatial_ratio,
        width // spatial_ratio,
        num_channels,
    )

    if isinstance(batch.generator, list) and len(batch.generator) != batch_size:
        raise ValueError(f&quot;generator list length &#123;len(batch.generator)&#125; does not match batch size &#123;batch_size&#125;.&quot;)

    visual_cond = getattr(self.transformer, &quot;visual_cond&quot;, False)

    if batch.latents is None:
        latents = randn_tensor(shape, generator=batch.generator, device=device, dtype=dtype)
        if hasattr(self.scheduler, &quot;init_noise_sigma&quot;):
            latents = latents * self.scheduler.init_noise_sigma
    else:
        valid_shapes = &#91;shape&#93;
        if visual_cond:
            valid_shapes.append((*shape&#91;:-1&#93;, num_channels * 2 + 1))
        if tuple(batch.latents.shape) not in valid_shapes:
            raise ValueError(f&quot;Provided latents shape &#123;list(batch.latents.shape)&#125; does not match expected &quot;
                             f&quot;Kandinsky5 latent shape(s): &#123;&#91;list(s) for s in valid_shapes&#93;&#125;.&quot;)
        latents = batch.latents.to(device=device, dtype=dtype)

    if visual_cond and latents.shape&#91;-1&#93; == num_channels:
        cond = torch.zeros_like(latents)
        cond_mask = torch.zeros(
            (*latents.shape&#91;:-1&#93;, 1),
            device=latents.device,
            dtype=latents.dtype,
        )
        latents = torch.cat(&#91;latents, cond, cond_mask&#93;, dim=-1)

    # I2V image conditioning is placed by Kandinsky5ImageEncodingStage,
    # which runs AFTER this stage so the initial noise is the generator&#x27;s
    # first draw (matching the official kandinskylab/kandinsky-5 order).
    batch.latents = latents
    batch.raw_latent_shape = (
        batch_size,
        num_channels,
        num_latent_frames,
        height // spatial_ratio,
        width // spatial_ratio,
    )
    return batch</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage.verify_input"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage.verify_input</code></h3>
<pre class="doc-signature"><code>verify_input(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>

<details><summary>Source</summary><pre><code>def verify_input(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
    result = VerificationResult()
    result.add_check(&quot;num_frames&quot;, batch.num_frames, V.positive_int)
    result.add_check(&quot;height&quot;, batch.height, V.positive_int)
    result.add_check(&quot;width&quot;, batch.width, V.positive_int)
    result.add_check(&quot;latents&quot;, batch.latents, V.none_or_tensor)
    return result</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage.verify_output"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5LatentPreparationStage.verify_output</code></h3>
<pre class="doc-signature"><code>verify_output(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>

<details><summary>Source</summary><pre><code>def verify_output(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
    result = VerificationResult()
    result.add_check(&quot;latents&quot;, batch.latents, &#91;V.is_tensor, V.with_dims(5)&#93;)
    return result</code></pre></details>
<h2 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage</code></h2>
<pre class="doc-signature"><code>Kandinsky5DenoisingStage(transformer, scheduler)</code></pre>


<details><summary>Source</summary><pre><code>class Kandinsky5DenoisingStage(PipelineStage):

    def __init__(self, transformer, scheduler) -&gt; None:
        super().__init__()
        self.transformer = transformer
        self.scheduler = scheduler

    @staticmethod
    def _scale_factor(height: int, width: int) -&gt; tuple&#91;float, float, float&#93;:
        if 480 &lt;= height &lt;= 854 and 480 &lt;= width &lt;= 854:
            return (1.0, 2.0, 2.0)
        return (1.0, 3.16, 3.16)

    @staticmethod
    def _text_rope_pos(mask: torch.Tensor, device: torch.device) -&gt; torch.Tensor:
        seq_len = int(mask.sum(1).max().item())
        return torch.arange(seq_len, device=device)

    # Backends whose selection is all-or-nothing: fastvideo.platforms.cuda
    # raises ImportError immediately if the ATTN_QAT_TRAIN kernel isn&#x27;t
    # available (training must never silently de-quantize), rather than the
    # generic &quot;requested backend unsupported by this layer, falling back to
    # automatic selection&quot; path _cached_get_attn_backend takes for most
    # other backend names (see fastvideo/attention/selector.py).
    # ATTN_QAT_TRAIN is also always in Kandinsky5ArchConfig&#x27;s
    # _supported_attention_backends, so that generic fallback never applies
    # to it here. That combination makes an exact backend match a safe,
    # false-positive-free signal *only* for ATTN_QAT_TRAIN.
    # ATTN_QAT_INFER must NOT be in this set: fastvideo.platforms.cuda
    # deliberately resolves it to FlashAttention when the sm_120 kernel
    # isn&#x27;t built, and the QAD recipe README documents that fallback (&quot;on
    # other GPUs the attention falls back to a supported dense backend
    # while the FP4 linear layers still run&quot;) -- asserting an exact match
    # would abort inference on every non-sm_120 machine relying on it.
    # Any other FASTVIDEO_ATTENTION_BACKEND value (e.g. a backend meant for
    # a different model family sharing the same process/env var) can
    # likewise legitimately resolve to something other than what was
    # requested.
    _STRICT_BACKENDS = frozenset(&#123;
        AttentionBackendEnum.ATTN_QAT_TRAIN,
    &#125;)

    def _assert_local_attention_backend_engaged(self) -&gt; None:
        &quot;&quot;&quot;Guard against ``LocalAttention`` silently falling back to SDPA.

        ``Kandinsky5Attention.forward`` catches the ``AssertionError``
        ``LocalAttention`` raises when no pipeline forward context is set and
        falls back to plain ``F.scaled_dot_product_attention`` -- silently
        skipping the transformer&#x27;s recorded attention backend (the
        fake-quantized ``ATTN_QAT_TRAIN`` kernel).
        ``LocalAttention.backend`` is resolved once at module construction,
        independent of whether a forward context is later set, so this only
        catches a backend that failed to resolve to the recorded decision
        -- it does not prove forward context was present for a
        given forward call. Pair it with always wrapping the actual
        transformer call in ``set_forward_context`` (see the denoising loops
        below), which is what prevents the runtime fallback.

        Scoped to ``_STRICT_BACKENDS``: other backend names -- including
        ``ATTN_QAT_INFER``, whose FlashAttention fallback on non-sm_120
        GPUs is documented, intentional behavior -- can legitimately differ
        from what ``LocalAttention.backend`` resolved to (see
        ``_STRICT_BACKENDS``&#x27;s comment), so asserting on those would flag
        expected behavior as a bug.
        &quot;&quot;&quot;
        expected = component_attention_backend(self.transformer)
        if expected not in self._STRICT_BACKENDS:
            return
        for module in self.transformer.modules():
            if isinstance(module, LocalAttention):
                assert module.backend == expected, (
                    f&quot;Kandinsky5 local attention resolved to backend &#123;module.backend&#125;, expected &quot;
                    f&quot;&#123;expected&#125;, the transformer&#x27;s recorded attention backend. This likely means &quot;
                    &quot;LocalAttention&#x27;s missing-forward-context guard silently fell back to SDPA.&quot;)
                return

    def _resolve_target_dtype(self, fastvideo_args: FastVideoArgs) -&gt; torch.dtype:
        &quot;&quot;&quot;Resolve the transformer&#x27;s actual compute dtype.

        Trust ``pipeline_config.dit_precision`` directly for a normal,
        non-FSDP load -- ``TransformerLoader.load()`` asserts every
        parameter matches it exactly (``fastvideo/models/loader/
        component_loader.py``), so this holds for standalone T2V/I2V
        inference regardless of which precision (including fp32) was
        requested.

        FSDP2-wrapped modules are the one case where that assertion doesn&#x27;t
        carry forward: ``maybe_load_fsdp_model`` hardcodes its
        ``MixedPrecisionPolicy`` to ``param_dtype=torch.bfloat16`` (with
        ``cast_forward_inputs=False``) for every FSDP-wrapped load,
        independent of ``dit_precision`` -- this covers both the live
        transformer ``ValidationCallback`` reuses from training (whose
        ``pipeline_config.dit_precision`` reflects the fp32 master-weight
        load dtype, not the actual bf16 compute dtype) and multi-GPU
        ``use_fsdp_inference=True`` runs.

        For that FSDP case, read the policy itself
        (``set_mixed_precision_policy`` records it right before
        ``maybe_load_fsdp_model`` shards -- every FSDP wrap in this repo
        goes through that path), NOT the parameter storage dtypes:
        FSDP2 computes in the policy&#x27;s ``param_dtype`` regardless of what
        dtype the parameters are stored/loaded in, so e.g. an fp16-loaded
        FSDP model still runs its forward in bf16 -- scanning parameters
        would resolve fp16 and, with ``cast_forward_inputs=False`` and
        autocast keyed off the wrong dtype, hand bf16-computing modules
        fp16 inputs.
        &quot;&quot;&quot;
        declared_dtype = PRECISION_TO_TYPE&#91;fastvideo_args.pipeline_config.dit_precision&#93;
        try:
            from torch.distributed.fsdp import FSDPModule
        except Exception:  # pragma: no cover - FSDP not always available
            return declared_dtype

        if not isinstance(self.transformer, FSDPModule):
            return declared_dtype

        try:
            policy_dtype = get_mixed_precision_state().param_dtype
        except ValueError:
            policy_dtype = None
        # bf16 mirrors maybe_load_fsdp_model&#x27;s hardcoded param_dtype if the
        # (thread-local) policy state is somehow unset here.
        return policy_dtype if policy_dtype is not None else torch.bfloat16

    @staticmethod
    def fast_sta_nabla(
        T: int,
        H: int,
        W: int,
        wT: int = 3,
        wH: int = 3,
        wW: int = 3,
        device: torch.device | str = &quot;cuda&quot;,
    ) -&gt; torch.Tensor:
        &quot;&quot;&quot;
        Create a sparse temporal attention (STA) mask for efficient video generation.

        This method generates a mask that limits attention to nearby frames and spatial positions, reducing
        computational complexity for video generation.

        Args:
            T (int): Number of temporal frames
            H (int): Height in latent space
            W (int): Width in latent space
            wT (int): Temporal attention window size
            wH (int): Height attention window size
            wW (int): Width attention window size
            device (str): Device to create tensor on

        Returns:
            torch.Tensor: Sparse attention mask of shape (T*H*W, T*H*W)
        &quot;&quot;&quot;
        max_extent = int(torch.tensor(&#91;T, H, W&#93;, device=device).amax().item())
        r = torch.arange(0, max_extent, 1, dtype=torch.int16, device=device)
        mat = (r.unsqueeze(1) - r.unsqueeze(0)).abs()
        sta_t, sta_h, sta_w = (
            mat&#91;:T, :T&#93;.flatten(),
            mat&#91;:H, :H&#93;.flatten(),
            mat&#91;:W, :W&#93;.flatten(),
        )
        sta_t = sta_t &lt;= wT // 2
        sta_h = sta_h &lt;= wH // 2
        sta_w = sta_w &lt;= wW // 2
        sta_hw = (sta_h.unsqueeze(1) * sta_w.unsqueeze(0)).reshape(H, H, W, W).transpose(1, 2).flatten()
        sta = (sta_t.unsqueeze(1) * sta_hw.unsqueeze(0)).reshape(T, T, H * W, H * W).transpose(1, 2)
        return sta.reshape(T * H * W, T * H * W)

    def get_sparse_params(self, sample: torch.Tensor, device: torch.device) -&gt; dict&#91;str, Any&#93; | None:
        &quot;&quot;&quot;
        Generate sparse attention parameters for the transformer based on sample dimensions.

        This method computes the sparse attention configuration needed for efficient video processing in the
        transformer model.

        Args:
            sample (torch.Tensor): Input sample tensor
            device (torch.device): Device to place tensors on

        Returns:
            Dict: Dictionary containing sparse attention parameters
        &quot;&quot;&quot;
        assert self.transformer.config.patch_size&#91;0&#93; == 1
        _, T, H, W, _ = sample.shape
        T, H, W = (
            T // self.transformer.config.patch_size&#91;0&#93;,
            H // self.transformer.config.patch_size&#91;1&#93;,
            W // self.transformer.config.patch_size&#91;2&#93;,
        )
        if self.transformer.config.attention_type == &quot;nabla&quot;:
            sta_mask = self.fast_sta_nabla(
                T,
                H // 8,
                W // 8,
                self.transformer.config.attention_wT,
                self.transformer.config.attention_wH,
                self.transformer.config.attention_wW,
                device=device,
            )

            sparse_params = &#123;
                &quot;sta_mask&quot;: sta_mask.unsqueeze_(0).unsqueeze_(0),
                &quot;attention_type&quot;: self.transformer.config.attention_type,
                &quot;to_fractal&quot;: True,
                &quot;P&quot;: self.transformer.config.attention_P,
                &quot;wT&quot;: self.transformer.config.attention_wT,
                &quot;wW&quot;: self.transformer.config.attention_wW,
                &quot;wH&quot;: self.transformer.config.attention_wH,
                &quot;add_sta&quot;: self.transformer.config.attention_add_sta,
                &quot;visual_shape&quot;: (T, H, W),
                &quot;method&quot;: self.transformer.config.attention_method,
            &#125;
        else:
            sparse_params = None

        return sparse_params

    def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
        if batch.timesteps is None:
            raise ValueError(&quot;timesteps must be prepared before Kandinsky5 denoising.&quot;)
        if batch.latents is None:
            raise ValueError(&quot;latents must be prepared before Kandinsky5 denoising.&quot;)
        if not fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93;:
            loader = TransformerLoader()
            self.transformer = loader.load(fastvideo_args.model_paths&#91;&quot;transformer&quot;&#93;, fastvideo_args)
            fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93; = True
        self._assert_local_attention_backend_engaged()

        device = get_local_torch_device()
        target_dtype = self._resolve_target_dtype(fastvideo_args)
        autocast_enabled = target_dtype != torch.float32 and not fastvideo_args.disable_autocast
        latents = batch.latents
        num_channels = getattr(
            self.transformer,
            &quot;in_visual_dim&quot;,
            fastvideo_args.pipeline_config.dit_config.arch_config.in_visual_dim,
        )

        prompt_embeds = batch.prompt_embeds&#91;0&#93;.to(device=device, dtype=target_dtype)
        pooled = batch.prompt_embeds&#91;1&#93;.to(device=device, dtype=target_dtype)
        if batch.prompt_attention_mask is None or not batch.prompt_attention_mask:
            raise ValueError(&quot;Kandinsky5 requires Qwen prompt attention masks.&quot;)
        text_rope_pos = self._text_rope_pos(batch.prompt_attention_mask&#91;0&#93;.to(device), device)

        neg_prompt_embeds = None
        neg_pooled = None
        negative_text_rope_pos = None
        if batch.do_classifier_free_guidance and batch.negative_prompt_embeds:
            neg_prompt_embeds = batch.negative_prompt_embeds&#91;0&#93;.to(device=device, dtype=target_dtype)
            neg_pooled = batch.negative_prompt_embeds&#91;1&#93;.to(device=device, dtype=target_dtype)
            if batch.negative_attention_mask is None or not batch.negative_attention_mask:
                raise ValueError(&quot;Kandinsky5 requires Qwen negative attention masks for CFG.&quot;)
            negative_text_rope_pos = self._text_rope_pos(batch.negative_attention_mask&#91;0&#93;.to(device), device)

        height = int(batch.height)
        width = int(batch.width)
        temporal_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio
        spatial_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.spatial_compression_ratio
        num_latent_frames = (int(batch.num_frames) - 1) // temporal_ratio + 1
        visual_rope_pos = &#91;
            torch.arange(num_latent_frames, device=device),
            torch.arange(height // spatial_ratio // 2, device=device),
            torch.arange(width // spatial_ratio // 2, device=device),
        &#93;
        scale_factor = self._scale_factor(height, width)

        sparse_params = self.get_sparse_params(latents, device)

        # I2V keeps the first (conditioning) frame fixed during denoising.
        # Key off the actual image conditioning, not transformer.visual_cond:
        # official T2V checkpoints also ship visual_cond=True, and skipping
        # frame 0 for them leaves it as undenoised noise.
        cond_frames = 1 if batch.image_latent is not None else 0

        trajectory_timesteps: list&#91;torch.Tensor&#93; = &#91;&#93;
        trajectory_latents: list&#91;torch.Tensor&#93; = &#91;&#93;

        with tqdm(total=batch.num_inference_steps, desc=&quot;Kandinsky5 Denoising&quot;) as progress_bar:
            for i, timestep in enumerate(batch.timesteps):
                if hasattr(self, &quot;interrupt&quot;) and self.interrupt:
                    break

                t_expand = timestep.unsqueeze(0).repeat(latents.shape&#91;0&#93;).to(device=device, dtype=target_dtype)
                attn_metadata = None
                if sparse_params is not None:
                    attn_metadata = NablaAttentionMetadataBuilder().build(
                        current_timestep=i,
                        sta_mask=sparse_params&#91;&quot;sta_mask&quot;&#93;,
                        P=sparse_params&#91;&quot;P&quot;&#93;,
                        visual_shape=sparse_params&#91;&quot;visual_shape&quot;&#93;,
                    )
                autocast_ctx = (torch.autocast(device_type=&quot;cuda&quot;, dtype=target_dtype, enabled=autocast_enabled)
                                if device.type == &quot;cuda&quot; else contextlib.nullcontext())
                with set_forward_context(current_timestep=i, attn_metadata=attn_metadata,
                                         forward_batch=batch), autocast_ctx:
                    pred_velocity = self.transformer(
                        hidden_states=latents.to(dtype=target_dtype),
                        encoder_hidden_states=prompt_embeds,
                        pooled_projections=pooled,
                        timestep=t_expand,
                        visual_rope_pos=visual_rope_pos,
                        text_rope_pos=text_rope_pos,
                        scale_factor=scale_factor,
                        sparse_params=sparse_params,
                        return_dict=True,
                    ).sample

                    if neg_prompt_embeds is not None and neg_pooled is not None:
                        uncond_pred_velocity = self.transformer(
                            hidden_states=latents.to(dtype=target_dtype),
                            encoder_hidden_states=neg_prompt_embeds,
                            pooled_projections=neg_pooled,
                            timestep=t_expand,
                            visual_rope_pos=visual_rope_pos,
                            text_rope_pos=negative_text_rope_pos,
                            scale_factor=scale_factor,
                            sparse_params=sparse_params,
                            return_dict=True,
                        ).sample
                        pred_velocity = uncond_pred_velocity + batch.guidance_scale * (pred_velocity -
                                                                                       uncond_pred_velocity)

                latents&#91;:, cond_frames:, :, :, :num_channels&#93; = self.scheduler.step(
                    pred_velocity&#91;:, cond_frames:&#93;,
                    timestep,
                    latents&#91;:, cond_frames:, :, :, :num_channels&#93;,
                    return_dict=False,
                )&#91;0&#93;

                if batch.return_trajectory_latents:
                    trajectory_timesteps.append(timestep)
                    # latents is mutated in place, so snapshot a channels-first copy.
                    trajectory_latents.append(latents&#91;..., :num_channels&#93;.permute(0, 4, 1, 2, 3).cpu())

                if i == len(batch.timesteps) - 1 or (i + 1) % self.scheduler.order == 0:
                    progress_bar.update()

        if trajectory_latents:
            batch.trajectory_latents = torch.stack(trajectory_latents, dim=1)
            batch.trajectory_timesteps = torch.stack(trajectory_timesteps, dim=0).cpu()

        batch.latents = latents&#91;:, :, :, :, :num_channels&#93;
        return batch

    def verify_input(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
        result = VerificationResult()
        result.add_check(&quot;latents&quot;, batch.latents, &#91;V.is_tensor, V.with_dims(5)&#93;)
        result.add_check(&quot;prompt_embeds&quot;, batch.prompt_embeds, V.min_list_length(2))
        return result</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.fast_sta_nabla"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.fast_sta_nabla</code></h3>
<pre class="doc-signature"><code>fast_sta_nabla(T: int, H: int, W: int, wT: int = 3, wH: int = 3, wW: int = 3, device: torch.device | str = &#x27;cuda&#x27;) -&gt; torch.Tensor</code></pre>
<p>Create a sparse temporal attention (STA) mask for efficient video generation.</p>
<p>This method generates a mask that limits attention to nearby frames and spatial positions, reducing
computational complexity for video generation.</p>
<h4>Parameters</h4>
<dl>
<dt><code>T: int</code></dt><dd><p>Number of temporal frames</p></dd>
<dt><code>H: int</code></dt><dd><p>Height in latent space</p></dd>
<dt><code>W: int</code></dt><dd><p>Width in latent space</p></dd>
<dt><code>wT: int</code></dt><dd><p>Temporal attention window size</p></dd>
<dt><code>wH: int</code></dt><dd><p>Height attention window size</p></dd>
<dt><code>wW: int</code></dt><dd><p>Width attention window size</p></dd>
<dt><code>device: str</code></dt><dd><p>Device to create tensor on</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p>torch.Tensor: Sparse attention mask of shape (T<em>H</em>W, T<em>H</em>W)</p></dd>
</dl>
<details><summary>Source</summary><pre><code>@staticmethod
def fast_sta_nabla(
    T: int,
    H: int,
    W: int,
    wT: int = 3,
    wH: int = 3,
    wW: int = 3,
    device: torch.device | str = &quot;cuda&quot;,
) -&gt; torch.Tensor:
    &quot;&quot;&quot;
    Create a sparse temporal attention (STA) mask for efficient video generation.

    This method generates a mask that limits attention to nearby frames and spatial positions, reducing
    computational complexity for video generation.

    Args:
        T (int): Number of temporal frames
        H (int): Height in latent space
        W (int): Width in latent space
        wT (int): Temporal attention window size
        wH (int): Height attention window size
        wW (int): Width attention window size
        device (str): Device to create tensor on

    Returns:
        torch.Tensor: Sparse attention mask of shape (T*H*W, T*H*W)
    &quot;&quot;&quot;
    max_extent = int(torch.tensor(&#91;T, H, W&#93;, device=device).amax().item())
    r = torch.arange(0, max_extent, 1, dtype=torch.int16, device=device)
    mat = (r.unsqueeze(1) - r.unsqueeze(0)).abs()
    sta_t, sta_h, sta_w = (
        mat&#91;:T, :T&#93;.flatten(),
        mat&#91;:H, :H&#93;.flatten(),
        mat&#91;:W, :W&#93;.flatten(),
    )
    sta_t = sta_t &lt;= wT // 2
    sta_h = sta_h &lt;= wH // 2
    sta_w = sta_w &lt;= wW // 2
    sta_hw = (sta_h.unsqueeze(1) * sta_w.unsqueeze(0)).reshape(H, H, W, W).transpose(1, 2).flatten()
    sta = (sta_t.unsqueeze(1) * sta_hw.unsqueeze(0)).reshape(T, T, H * W, H * W).transpose(1, 2)
    return sta.reshape(T * H * W, T * H * W)</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.get_sparse_params"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.get_sparse_params</code></h3>
<pre class="doc-signature"><code>get_sparse_params(sample: torch.Tensor, device: torch.device) -&gt; dict&#91;str, Any&#93; | None</code></pre>
<p>Generate sparse attention parameters for the transformer based on sample dimensions.</p>
<p>This method computes the sparse attention configuration needed for efficient video processing in the
transformer model.</p>
<h4>Parameters</h4>
<dl>
<dt><code>sample: torch.Tensor</code></dt><dd><p>Input sample tensor</p></dd>
<dt><code>device: torch.device</code></dt><dd><p>Device to place tensors on</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>Dict: dict[str, Any] | None</code></dt><dd><p>Dictionary containing sparse attention parameters</p></dd>
</dl>
<details><summary>Source</summary><pre><code>def get_sparse_params(self, sample: torch.Tensor, device: torch.device) -&gt; dict&#91;str, Any&#93; | None:
    &quot;&quot;&quot;
    Generate sparse attention parameters for the transformer based on sample dimensions.

    This method computes the sparse attention configuration needed for efficient video processing in the
    transformer model.

    Args:
        sample (torch.Tensor): Input sample tensor
        device (torch.device): Device to place tensors on

    Returns:
        Dict: Dictionary containing sparse attention parameters
    &quot;&quot;&quot;
    assert self.transformer.config.patch_size&#91;0&#93; == 1
    _, T, H, W, _ = sample.shape
    T, H, W = (
        T // self.transformer.config.patch_size&#91;0&#93;,
        H // self.transformer.config.patch_size&#91;1&#93;,
        W // self.transformer.config.patch_size&#91;2&#93;,
    )
    if self.transformer.config.attention_type == &quot;nabla&quot;:
        sta_mask = self.fast_sta_nabla(
            T,
            H // 8,
            W // 8,
            self.transformer.config.attention_wT,
            self.transformer.config.attention_wH,
            self.transformer.config.attention_wW,
            device=device,
        )

        sparse_params = &#123;
            &quot;sta_mask&quot;: sta_mask.unsqueeze_(0).unsqueeze_(0),
            &quot;attention_type&quot;: self.transformer.config.attention_type,
            &quot;to_fractal&quot;: True,
            &quot;P&quot;: self.transformer.config.attention_P,
            &quot;wT&quot;: self.transformer.config.attention_wT,
            &quot;wW&quot;: self.transformer.config.attention_wW,
            &quot;wH&quot;: self.transformer.config.attention_wH,
            &quot;add_sta&quot;: self.transformer.config.attention_add_sta,
            &quot;visual_shape&quot;: (T, H, W),
            &quot;method&quot;: self.transformer.config.attention_method,
        &#125;
    else:
        sparse_params = None

    return sparse_params</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
    if batch.timesteps is None:
        raise ValueError(&quot;timesteps must be prepared before Kandinsky5 denoising.&quot;)
    if batch.latents is None:
        raise ValueError(&quot;latents must be prepared before Kandinsky5 denoising.&quot;)
    if not fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93;:
        loader = TransformerLoader()
        self.transformer = loader.load(fastvideo_args.model_paths&#91;&quot;transformer&quot;&#93;, fastvideo_args)
        fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93; = True
    self._assert_local_attention_backend_engaged()

    device = get_local_torch_device()
    target_dtype = self._resolve_target_dtype(fastvideo_args)
    autocast_enabled = target_dtype != torch.float32 and not fastvideo_args.disable_autocast
    latents = batch.latents
    num_channels = getattr(
        self.transformer,
        &quot;in_visual_dim&quot;,
        fastvideo_args.pipeline_config.dit_config.arch_config.in_visual_dim,
    )

    prompt_embeds = batch.prompt_embeds&#91;0&#93;.to(device=device, dtype=target_dtype)
    pooled = batch.prompt_embeds&#91;1&#93;.to(device=device, dtype=target_dtype)
    if batch.prompt_attention_mask is None or not batch.prompt_attention_mask:
        raise ValueError(&quot;Kandinsky5 requires Qwen prompt attention masks.&quot;)
    text_rope_pos = self._text_rope_pos(batch.prompt_attention_mask&#91;0&#93;.to(device), device)

    neg_prompt_embeds = None
    neg_pooled = None
    negative_text_rope_pos = None
    if batch.do_classifier_free_guidance and batch.negative_prompt_embeds:
        neg_prompt_embeds = batch.negative_prompt_embeds&#91;0&#93;.to(device=device, dtype=target_dtype)
        neg_pooled = batch.negative_prompt_embeds&#91;1&#93;.to(device=device, dtype=target_dtype)
        if batch.negative_attention_mask is None or not batch.negative_attention_mask:
            raise ValueError(&quot;Kandinsky5 requires Qwen negative attention masks for CFG.&quot;)
        negative_text_rope_pos = self._text_rope_pos(batch.negative_attention_mask&#91;0&#93;.to(device), device)

    height = int(batch.height)
    width = int(batch.width)
    temporal_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio
    spatial_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.spatial_compression_ratio
    num_latent_frames = (int(batch.num_frames) - 1) // temporal_ratio + 1
    visual_rope_pos = &#91;
        torch.arange(num_latent_frames, device=device),
        torch.arange(height // spatial_ratio // 2, device=device),
        torch.arange(width // spatial_ratio // 2, device=device),
    &#93;
    scale_factor = self._scale_factor(height, width)

    sparse_params = self.get_sparse_params(latents, device)

    # I2V keeps the first (conditioning) frame fixed during denoising.
    # Key off the actual image conditioning, not transformer.visual_cond:
    # official T2V checkpoints also ship visual_cond=True, and skipping
    # frame 0 for them leaves it as undenoised noise.
    cond_frames = 1 if batch.image_latent is not None else 0

    trajectory_timesteps: list&#91;torch.Tensor&#93; = &#91;&#93;
    trajectory_latents: list&#91;torch.Tensor&#93; = &#91;&#93;

    with tqdm(total=batch.num_inference_steps, desc=&quot;Kandinsky5 Denoising&quot;) as progress_bar:
        for i, timestep in enumerate(batch.timesteps):
            if hasattr(self, &quot;interrupt&quot;) and self.interrupt:
                break

            t_expand = timestep.unsqueeze(0).repeat(latents.shape&#91;0&#93;).to(device=device, dtype=target_dtype)
            attn_metadata = None
            if sparse_params is not None:
                attn_metadata = NablaAttentionMetadataBuilder().build(
                    current_timestep=i,
                    sta_mask=sparse_params&#91;&quot;sta_mask&quot;&#93;,
                    P=sparse_params&#91;&quot;P&quot;&#93;,
                    visual_shape=sparse_params&#91;&quot;visual_shape&quot;&#93;,
                )
            autocast_ctx = (torch.autocast(device_type=&quot;cuda&quot;, dtype=target_dtype, enabled=autocast_enabled)
                            if device.type == &quot;cuda&quot; else contextlib.nullcontext())
            with set_forward_context(current_timestep=i, attn_metadata=attn_metadata,
                                     forward_batch=batch), autocast_ctx:
                pred_velocity = self.transformer(
                    hidden_states=latents.to(dtype=target_dtype),
                    encoder_hidden_states=prompt_embeds,
                    pooled_projections=pooled,
                    timestep=t_expand,
                    visual_rope_pos=visual_rope_pos,
                    text_rope_pos=text_rope_pos,
                    scale_factor=scale_factor,
                    sparse_params=sparse_params,
                    return_dict=True,
                ).sample

                if neg_prompt_embeds is not None and neg_pooled is not None:
                    uncond_pred_velocity = self.transformer(
                        hidden_states=latents.to(dtype=target_dtype),
                        encoder_hidden_states=neg_prompt_embeds,
                        pooled_projections=neg_pooled,
                        timestep=t_expand,
                        visual_rope_pos=visual_rope_pos,
                        text_rope_pos=negative_text_rope_pos,
                        scale_factor=scale_factor,
                        sparse_params=sparse_params,
                        return_dict=True,
                    ).sample
                    pred_velocity = uncond_pred_velocity + batch.guidance_scale * (pred_velocity -
                                                                                   uncond_pred_velocity)

            latents&#91;:, cond_frames:, :, :, :num_channels&#93; = self.scheduler.step(
                pred_velocity&#91;:, cond_frames:&#93;,
                timestep,
                latents&#91;:, cond_frames:, :, :, :num_channels&#93;,
                return_dict=False,
            )&#91;0&#93;

            if batch.return_trajectory_latents:
                trajectory_timesteps.append(timestep)
                # latents is mutated in place, so snapshot a channels-first copy.
                trajectory_latents.append(latents&#91;..., :num_channels&#93;.permute(0, 4, 1, 2, 3).cpu())

            if i == len(batch.timesteps) - 1 or (i + 1) % self.scheduler.order == 0:
                progress_bar.update()

    if trajectory_latents:
        batch.trajectory_latents = torch.stack(trajectory_latents, dim=1)
        batch.trajectory_timesteps = torch.stack(trajectory_timesteps, dim=0).cpu()

    batch.latents = latents&#91;:, :, :, :, :num_channels&#93;
    return batch</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.verify_input"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DenoisingStage.verify_input</code></h3>
<pre class="doc-signature"><code>verify_input(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>

<details><summary>Source</summary><pre><code>def verify_input(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
    result = VerificationResult()
    result.add_check(&quot;latents&quot;, batch.latents, &#91;V.is_tensor, V.with_dims(5)&#93;)
    result.add_check(&quot;prompt_embeds&quot;, batch.prompt_embeds, V.min_list_length(2))
    return result</code></pre></details>
<h2 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DmdDenoisingStage"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DmdDenoisingStage</code></h2>
<pre class="doc-signature"><code>Kandinsky5DmdDenoisingStage(transformer, scheduler)</code></pre>
<p>DMD (few fixed steps, no CFG) variant of Kandinsky5DenoisingStage.</p>
<p>Reuses the parent's RoPE/scale_factor/sparse-params helpers; only the
denoising loop differs: a fixed short timestep schedule
(<code>pipeline_config.dmd_denoising_steps</code>) with a single forward pass per
step and no classifier-free-guidance branch, matching DMD's distilled
few-step generator.</p>
<p><code>dmd_denoising_steps</code> values (e.g. <code>[1000, 750, 500, 250]</code>) are
literal <em>final</em> target timesteps -- that's how <code>DMD2Method</code> on the
training side resolves them: nearest-sigma lookup against a scheduler
that has never had <code>set_timesteps</code> called on it, so e.g. "750" maps to
sigma 0.75. This stage therefore keeps a private
<code>FlowMatchEulerDiscreteScheduler</code> (same <code>shift</code> as the pipeline
scheduler) and drives it directly via predict-x0 + re-noise, exactly
mirroring <code>DMD2Method._student_rollout</code>'s "simulate" branch and Wan's
own <code>DmdDenoisingStage</code>. It must NOT reuse the pipeline's shared
<code>scheduler</code> object through <code>scheduler.step()</code>: by the time this
stage runs, <code>TimestepPreparationStage</code> has already called
<code>scheduler.set_timesteps(timesteps=dmd_denoising_steps)</code> on it, which
re-applies the flow-match <code>shift</code> warp on top of values that are
already final (e.g. sigma 0.75 -&gt; 0.9375 at shift=5) -- a double shift
that leaves every step far noisier than the student was trained for, so
the sampled video is still mostly noise after the last step instead of
converged.</p>

<details><summary>Source</summary><pre><code>class Kandinsky5DmdDenoisingStage(Kandinsky5DenoisingStage):
    &quot;&quot;&quot;DMD (few fixed steps, no CFG) variant of Kandinsky5DenoisingStage.

    Reuses the parent&#x27;s RoPE/scale_factor/sparse-params helpers; only the
    denoising loop differs: a fixed short timestep schedule
    (``pipeline_config.dmd_denoising_steps``) with a single forward pass per
    step and no classifier-free-guidance branch, matching DMD&#x27;s distilled
    few-step generator.

    ``dmd_denoising_steps`` values (e.g. ``&#91;1000, 750, 500, 250&#93;``) are
    literal *final* target timesteps -- that&#x27;s how ``DMD2Method`` on the
    training side resolves them: nearest-sigma lookup against a scheduler
    that has never had ``set_timesteps`` called on it, so e.g. &quot;750&quot; maps to
    sigma 0.75. This stage therefore keeps a private
    ``FlowMatchEulerDiscreteScheduler`` (same ``shift`` as the pipeline
    scheduler) and drives it directly via predict-x0 + re-noise, exactly
    mirroring ``DMD2Method._student_rollout``&#x27;s &quot;simulate&quot; branch and Wan&#x27;s
    own ``DmdDenoisingStage``. It must NOT reuse the pipeline&#x27;s shared
    ``scheduler`` object through ``scheduler.step()``: by the time this
    stage runs, ``TimestepPreparationStage`` has already called
    ``scheduler.set_timesteps(timesteps=dmd_denoising_steps)`` on it, which
    re-applies the flow-match ``shift`` warp on top of values that are
    already final (e.g. sigma 0.75 -&gt; 0.9375 at shift=5) -- a double shift
    that leaves every step far noisier than the student was trained for, so
    the sampled video is still mostly noise after the last step instead of
    converged.
    &quot;&quot;&quot;

    def __init__(self, transformer, scheduler) -&gt; None:
        super().__init__(transformer, scheduler)
        self._sample_scheduler = FlowMatchEulerDiscreteScheduler(shift=scheduler.shift)

    def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
        if batch.latents is None:
            raise ValueError(&quot;latents must be prepared before Kandinsky5 DMD denoising.&quot;)
        if not fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93;:
            loader = TransformerLoader()
            self.transformer = loader.load(fastvideo_args.model_paths&#91;&quot;transformer&quot;&#93;, fastvideo_args)
            fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93; = True
        self._assert_local_attention_backend_engaged()

        device = get_local_torch_device()
        target_dtype = self._resolve_target_dtype(fastvideo_args)
        autocast_enabled = target_dtype != torch.float32 and not fastvideo_args.disable_autocast
        latents = batch.latents
        num_channels = getattr(
            self.transformer,
            &quot;in_visual_dim&quot;,
            fastvideo_args.pipeline_config.dit_config.arch_config.in_visual_dim,
        )

        prompt_embeds = batch.prompt_embeds&#91;0&#93;.to(device=device, dtype=target_dtype)
        pooled = batch.prompt_embeds&#91;1&#93;.to(device=device, dtype=target_dtype)
        if batch.prompt_attention_mask is None or not batch.prompt_attention_mask:
            raise ValueError(&quot;Kandinsky5 DMD requires Qwen prompt attention masks.&quot;)
        text_rope_pos = self._text_rope_pos(batch.prompt_attention_mask&#91;0&#93;.to(device), device)

        height = int(batch.height)
        width = int(batch.width)
        temporal_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio
        spatial_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.spatial_compression_ratio
        num_latent_frames = (int(batch.num_frames) - 1) // temporal_ratio + 1
        visual_rope_pos = &#91;
            torch.arange(num_latent_frames, device=device),
            torch.arange(height // spatial_ratio // 2, device=device),
            torch.arange(width // spatial_ratio // 2, device=device),
        &#93;
        scale_factor = self._scale_factor(height, width)
        sparse_params = self.get_sparse_params(latents, device)

        dmd_steps = fastvideo_args.pipeline_config.dmd_denoising_steps
        if not dmd_steps:
            raise ValueError(&quot;Kandinsky5 DMD denoising requires &quot;
                             &quot;pipeline_config.dmd_denoising_steps to be set.&quot;)
        timesteps = torch.tensor(dmd_steps, dtype=torch.long, device=device)

        # I2V keeps the first (conditioning) frame fixed during denoising.
        # Key off the actual image conditioning, not transformer.visual_cond:
        # official T2V checkpoints also ship visual_cond=True, and skipping
        # frame 0 for them leaves it as undenoised noise (see the same fix
        # in Kandinsky5DenoisingStage.forward() above).
        cond_frames = 1 if batch.image_latent is not None else 0

        with tqdm(total=len(timesteps), desc=&quot;Kandinsky5 DMD Denoising&quot;) as progress_bar:
            for i, timestep in enumerate(timesteps):
                if hasattr(self, &quot;interrupt&quot;) and self.interrupt:
                    continue

                t_expand = timestep.unsqueeze(0).repeat(latents.shape&#91;0&#93;).to(device=device, dtype=target_dtype)
                attn_metadata = None
                if sparse_params is not None:
                    attn_metadata = NablaAttentionMetadataBuilder().build(
                        current_timestep=i,
                        sta_mask=sparse_params&#91;&quot;sta_mask&quot;&#93;,
                        P=sparse_params&#91;&quot;P&quot;&#93;,
                        visual_shape=sparse_params&#91;&quot;visual_shape&quot;&#93;,
                    )
                autocast_ctx = (torch.autocast(device_type=&quot;cuda&quot;, dtype=target_dtype, enabled=autocast_enabled)
                                if device.type == &quot;cuda&quot; else contextlib.nullcontext())
                with set_forward_context(current_timestep=i, attn_metadata=attn_metadata,
                                         forward_batch=batch), autocast_ctx:
                    pred_velocity = self.transformer(
                        hidden_states=latents.to(dtype=target_dtype),
                        encoder_hidden_states=prompt_embeds,
                        pooled_projections=pooled,
                        timestep=t_expand,
                        visual_rope_pos=visual_rope_pos,
                        text_rope_pos=text_rope_pos,
                        scale_factor=scale_factor,
                        sparse_params=sparse_params,
                        return_dict=True,
                    ).sample

                # Channel-last &#91;B, T&#x27;, H, W, C&#93; -&gt; channel-first &#91;B, T&#x27;, C, H, W&#93;
                # to match pred_noise_to_pred_video/add_noise&#x27;s expected layout
                # (same convention as Kandinsky5Model.add_noise/predict_x0).
                sample_cf = latents&#91;:, cond_frames:, :, :, :num_channels&#93;.permute(0, 1, 4, 2, 3)
                velocity_cf = pred_velocity&#91;:, cond_frames:&#93;.permute(0, 1, 4, 2, 3)
                b, t = sample_cf.shape&#91;:2&#93;
                step_timestep = timestep.reshape(1).to(device=device)
                pred_x0_cf = pred_noise_to_pred_video(
                    pred_noise=velocity_cf.flatten(0, 1),
                    noise_input_latent=sample_cf.flatten(0, 1),
                    timestep=step_timestep,
                    scheduler=self._sample_scheduler,
                ).unflatten(0, (b, t))

                if i &lt; len(timesteps) - 1:
                    next_timestep = timesteps&#91;i + 1&#93;.reshape(1).to(device=device)
                    noise = randn_tensor(
                        sample_cf.shape,
                        generator=batch.generator,
                        device=device,
                        dtype=pred_x0_cf.dtype,
                    )
                    next_cf = self._sample_scheduler.add_noise(
                        pred_x0_cf.flatten(0, 1),
                        noise.flatten(0, 1),
                        next_timestep,
                    ).unflatten(0, (b, t))
                else:
                    next_cf = pred_x0_cf

                latents&#91;:, cond_frames:, :, :, :num_channels&#93; = next_cf.permute(0, 1, 3, 4, 2).to(latents.dtype)
                progress_bar.update()

        batch.latents = latents&#91;:, :, :, :, :num_channels&#93;
        return batch</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DmdDenoisingStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DmdDenoisingStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
    if batch.latents is None:
        raise ValueError(&quot;latents must be prepared before Kandinsky5 DMD denoising.&quot;)
    if not fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93;:
        loader = TransformerLoader()
        self.transformer = loader.load(fastvideo_args.model_paths&#91;&quot;transformer&quot;&#93;, fastvideo_args)
        fastvideo_args.model_loaded&#91;&quot;transformer&quot;&#93; = True
    self._assert_local_attention_backend_engaged()

    device = get_local_torch_device()
    target_dtype = self._resolve_target_dtype(fastvideo_args)
    autocast_enabled = target_dtype != torch.float32 and not fastvideo_args.disable_autocast
    latents = batch.latents
    num_channels = getattr(
        self.transformer,
        &quot;in_visual_dim&quot;,
        fastvideo_args.pipeline_config.dit_config.arch_config.in_visual_dim,
    )

    prompt_embeds = batch.prompt_embeds&#91;0&#93;.to(device=device, dtype=target_dtype)
    pooled = batch.prompt_embeds&#91;1&#93;.to(device=device, dtype=target_dtype)
    if batch.prompt_attention_mask is None or not batch.prompt_attention_mask:
        raise ValueError(&quot;Kandinsky5 DMD requires Qwen prompt attention masks.&quot;)
    text_rope_pos = self._text_rope_pos(batch.prompt_attention_mask&#91;0&#93;.to(device), device)

    height = int(batch.height)
    width = int(batch.width)
    temporal_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.temporal_compression_ratio
    spatial_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.spatial_compression_ratio
    num_latent_frames = (int(batch.num_frames) - 1) // temporal_ratio + 1
    visual_rope_pos = &#91;
        torch.arange(num_latent_frames, device=device),
        torch.arange(height // spatial_ratio // 2, device=device),
        torch.arange(width // spatial_ratio // 2, device=device),
    &#93;
    scale_factor = self._scale_factor(height, width)
    sparse_params = self.get_sparse_params(latents, device)

    dmd_steps = fastvideo_args.pipeline_config.dmd_denoising_steps
    if not dmd_steps:
        raise ValueError(&quot;Kandinsky5 DMD denoising requires &quot;
                         &quot;pipeline_config.dmd_denoising_steps to be set.&quot;)
    timesteps = torch.tensor(dmd_steps, dtype=torch.long, device=device)

    # I2V keeps the first (conditioning) frame fixed during denoising.
    # Key off the actual image conditioning, not transformer.visual_cond:
    # official T2V checkpoints also ship visual_cond=True, and skipping
    # frame 0 for them leaves it as undenoised noise (see the same fix
    # in Kandinsky5DenoisingStage.forward() above).
    cond_frames = 1 if batch.image_latent is not None else 0

    with tqdm(total=len(timesteps), desc=&quot;Kandinsky5 DMD Denoising&quot;) as progress_bar:
        for i, timestep in enumerate(timesteps):
            if hasattr(self, &quot;interrupt&quot;) and self.interrupt:
                continue

            t_expand = timestep.unsqueeze(0).repeat(latents.shape&#91;0&#93;).to(device=device, dtype=target_dtype)
            attn_metadata = None
            if sparse_params is not None:
                attn_metadata = NablaAttentionMetadataBuilder().build(
                    current_timestep=i,
                    sta_mask=sparse_params&#91;&quot;sta_mask&quot;&#93;,
                    P=sparse_params&#91;&quot;P&quot;&#93;,
                    visual_shape=sparse_params&#91;&quot;visual_shape&quot;&#93;,
                )
            autocast_ctx = (torch.autocast(device_type=&quot;cuda&quot;, dtype=target_dtype, enabled=autocast_enabled)
                            if device.type == &quot;cuda&quot; else contextlib.nullcontext())
            with set_forward_context(current_timestep=i, attn_metadata=attn_metadata,
                                     forward_batch=batch), autocast_ctx:
                pred_velocity = self.transformer(
                    hidden_states=latents.to(dtype=target_dtype),
                    encoder_hidden_states=prompt_embeds,
                    pooled_projections=pooled,
                    timestep=t_expand,
                    visual_rope_pos=visual_rope_pos,
                    text_rope_pos=text_rope_pos,
                    scale_factor=scale_factor,
                    sparse_params=sparse_params,
                    return_dict=True,
                ).sample

            # Channel-last &#91;B, T&#x27;, H, W, C&#93; -&gt; channel-first &#91;B, T&#x27;, C, H, W&#93;
            # to match pred_noise_to_pred_video/add_noise&#x27;s expected layout
            # (same convention as Kandinsky5Model.add_noise/predict_x0).
            sample_cf = latents&#91;:, cond_frames:, :, :, :num_channels&#93;.permute(0, 1, 4, 2, 3)
            velocity_cf = pred_velocity&#91;:, cond_frames:&#93;.permute(0, 1, 4, 2, 3)
            b, t = sample_cf.shape&#91;:2&#93;
            step_timestep = timestep.reshape(1).to(device=device)
            pred_x0_cf = pred_noise_to_pred_video(
                pred_noise=velocity_cf.flatten(0, 1),
                noise_input_latent=sample_cf.flatten(0, 1),
                timestep=step_timestep,
                scheduler=self._sample_scheduler,
            ).unflatten(0, (b, t))

            if i &lt; len(timesteps) - 1:
                next_timestep = timesteps&#91;i + 1&#93;.reshape(1).to(device=device)
                noise = randn_tensor(
                    sample_cf.shape,
                    generator=batch.generator,
                    device=device,
                    dtype=pred_x0_cf.dtype,
                )
                next_cf = self._sample_scheduler.add_noise(
                    pred_x0_cf.flatten(0, 1),
                    noise.flatten(0, 1),
                    next_timestep,
                ).unflatten(0, (b, t))
            else:
                next_cf = pred_x0_cf

            latents&#91;:, cond_frames:, :, :, :num_channels&#93; = next_cf.permute(0, 1, 3, 4, 2).to(latents.dtype)
            progress_bar.update()

    batch.latents = latents&#91;:, :, :, :, :num_channels&#93;
    return batch</code></pre></details>
<h2 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DecodingStage"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DecodingStage</code></h2>
<pre class="doc-signature"><code>Kandinsky5DecodingStage(vae: ParallelTiledVAE, pipeline = None)</code></pre>


<details><summary>Source</summary><pre><code>class Kandinsky5DecodingStage(DecodingStage):

    def __init__(self, vae: ParallelTiledVAE, pipeline=None) -&gt; None:
        super().__init__(vae=vae, pipeline=pipeline)

    def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
        if batch.latents is None:
            raise ValueError(&quot;latents must be available before Kandinsky5 decoding.&quot;)
        # Kandinsky5 latents are channels-last &#91;B, T, H, W, C&#93;; the base stage
        # (and the trajectory latents recorded by the denoising stage) work
        # channels-first.
        batch.latents = batch.latents.permute(0, 4, 1, 2, 3).contiguous()
        return super().forward(batch, fastvideo_args)</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5DecodingStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5DecodingStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
    if batch.latents is None:
        raise ValueError(&quot;latents must be available before Kandinsky5 decoding.&quot;)
    # Kandinsky5 latents are channels-last &#91;B, T, H, W, C&#93;; the base stage
    # (and the trajectory latents recorded by the denoising stage) work
    # channels-first.
    batch.latents = batch.latents.permute(0, 4, 1, 2, 3).contiguous()
    return super().forward(batch, fastvideo_args)</code></pre></details>
<h2 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage</code></h2>
<pre class="doc-signature"><code>Kandinsky5ImageEncodingStage(vae: ParallelTiledVAE, pipeline = None)</code></pre>
<p>Encode the conditioning image into a VAE latent for I2V.</p>

<details><summary>Source</summary><pre><code>class Kandinsky5ImageEncodingStage(EncodingStage):
    &quot;&quot;&quot;Encode the conditioning image into a VAE latent for I2V.&quot;&quot;&quot;

    def __init__(self, vae: ParallelTiledVAE, pipeline=None) -&gt; None:
        super().__init__(vae=vae)

    @staticmethod
    def _preprocess(image, height: int, width: int) -&gt; torch.Tensor:
        if isinstance(image, PIL.Image.Image):
            image = resize(image, height, width)
            image = numpy_to_pt(pil_to_numpy(image))  # always lands in &#91;0, 1&#93;
            return normalize(image)  # &#91;0, 1&#93; -&gt; &#91;-1, 1&#93;
        # Tensor input: no reliable way to tell &#91;0, 1&#93; from an already
        # normalized &#91;-1, 1&#93; tensor whose values happen to be non-negative,
        # so mirror diffusers&#x27; heuristic and say what we assumed.
        if image.min() &gt;= 0:
            logger.warning(&quot;Kandinsky5 conditioning image tensor has no negative values; &quot;
                           &quot;assuming range &#91;0, 1&#93; and normalizing to &#91;-1, 1&#93;. &quot;
                           &quot;Pass a &#91;-1, 1&#93; tensor with negative values to skip normalization.&quot;)
            image = normalize(image)  # &#91;0, 1&#93; -&gt; &#91;-1, 1&#93;
        if image.ndim == 3:
            image = image.unsqueeze(0)
        if image.shape&#91;-2:&#93; != (height, width):
            image = torch.nn.functional.interpolate(image.float(),
                                                    size=(height, width),
                                                    mode=&quot;bilinear&quot;,
                                                    antialias=True)
        return image

    @torch.no_grad()
    def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
        if batch.pil_image is None:
            raise ValueError(&quot;Kandinsky5 I2V requires an input image.&quot;)

        if not fastvideo_args.model_loaded&#91;&quot;vae&quot;&#93;:
            vae = getattr(self, &quot;vae&quot;, None)
            if vae is None:
                loader = VAELoader()
                vae = loader.load(fastvideo_args.model_paths&#91;&quot;vae&quot;&#93;, fastvideo_args)
                self.vae = vae
            fastvideo_args.model_loaded&#91;&quot;vae&quot;&#93; = True

        device = get_local_torch_device()
        vae = self.vae.to(device)
        self.vae = vae
        vae_dtype = PRECISION_TO_TYPE&#91;fastvideo_args.pipeline_config.vae_precision&#93;
        vae_autocast_enabled = vae_dtype != torch.float32 and not fastvideo_args.disable_autocast

        # &#91;B, C, H, W&#93; -&gt; &#91;B, C, 1, H, W&#93;
        image = self._preprocess(batch.pil_image, int(batch.height), int(batch.width))
        image = image.to(device=device, dtype=torch.float32).unsqueeze(2)

        # Encode the single conditioning frame without tiling (matches diffusers).
        # The untested causal-VAE spatial_tiled_encode path corrupts the latent.
        prev_use_tiling = vae.use_tiling
        vae.use_tiling = False
        try:
            with torch.autocast(device_type=&quot;cuda&quot;, dtype=vae_dtype, enabled=vae_autocast_enabled):
                if not vae_autocast_enabled:
                    image = image.to(vae_dtype)
                # Sample with the batch generator (diffusers parity); mode()
                # would make seed-for-seed reproduction of the reference
                # pipeline impossible.
                generator = batch.generator
                if isinstance(generator, list) and len(generator) != image.shape&#91;0&#93;:
                    generator = generator&#91;0&#93;
                image_latent = vae.encode(image).sample(generator=generator)
        finally:
            vae.use_tiling = prev_use_tiling

        image_latent = image_latent * vae.scaling_factor
        # &#91;B, C, 1, H, W&#93; -&gt; &#91;B, 1, H, W, C&#93; to match channels-last latents
        batch.image_latent = image_latent.permute(0, 2, 3, 4, 1).contiguous()

        # Place the conditioning latent into the prepared latents: frame 0 of
        # the main channels, the visual_cond channel block, and the mask.
        # NOTE: the official kandinsky-5 repo leaves the visual_cond block
        # zeros (generation_utils.py generate()), while the diffusers port
        # copies the image latent into it. A same-seed A/B on
        # Kandinsky-5.0-I2V-Pro-distilled-5s-Diffusers showed the Diffusers
        # export requires the copy: zeroing the block produces smeared faces
        # mid-video. Keep the diffusers semantics for Diffusers-format
        # checkpoints.
        latents = batch.latents
        image_latent = batch.image_latent.to(device=latents.device, dtype=latents.dtype)
        num_channels = image_latent.shape&#91;-1&#93;
        latents&#91;:, 0:1, :, :, :num_channels&#93; = image_latent
        if latents.shape&#91;-1&#93; &gt; num_channels:
            latents&#91;:, 0:1, :, :, num_channels:2 * num_channels&#93; = image_latent
            latents&#91;:, 0:1, :, :, 2 * num_channels:&#93; = 1.0
        batch.latents = latents

        if fastvideo_args.vae_cpu_offload:
            vae.to(&quot;cpu&quot;)
        return batch

    def verify_input(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
        result = VerificationResult()
        result.add_check(&quot;pil_image&quot;, batch.pil_image, V.not_none)
        result.add_check(&quot;height&quot;, batch.height, V.positive_int)
        result.add_check(&quot;width&quot;, batch.width, V.positive_int)
        # This stage runs after latent preparation and writes into its output.
        result.add_check(&quot;latents&quot;, batch.latents, &#91;V.is_tensor, V.with_dims(5)&#93;)
        return result

    def verify_output(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
        result = VerificationResult()
        result.add_check(&quot;image_latent&quot;, batch.image_latent, &#91;V.is_tensor, V.with_dims(5)&#93;)
        return result</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>

<details><summary>Source</summary><pre><code>@torch.no_grad()
def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
    if batch.pil_image is None:
        raise ValueError(&quot;Kandinsky5 I2V requires an input image.&quot;)

    if not fastvideo_args.model_loaded&#91;&quot;vae&quot;&#93;:
        vae = getattr(self, &quot;vae&quot;, None)
        if vae is None:
            loader = VAELoader()
            vae = loader.load(fastvideo_args.model_paths&#91;&quot;vae&quot;&#93;, fastvideo_args)
            self.vae = vae
        fastvideo_args.model_loaded&#91;&quot;vae&quot;&#93; = True

    device = get_local_torch_device()
    vae = self.vae.to(device)
    self.vae = vae
    vae_dtype = PRECISION_TO_TYPE&#91;fastvideo_args.pipeline_config.vae_precision&#93;
    vae_autocast_enabled = vae_dtype != torch.float32 and not fastvideo_args.disable_autocast

    # &#91;B, C, H, W&#93; -&gt; &#91;B, C, 1, H, W&#93;
    image = self._preprocess(batch.pil_image, int(batch.height), int(batch.width))
    image = image.to(device=device, dtype=torch.float32).unsqueeze(2)

    # Encode the single conditioning frame without tiling (matches diffusers).
    # The untested causal-VAE spatial_tiled_encode path corrupts the latent.
    prev_use_tiling = vae.use_tiling
    vae.use_tiling = False
    try:
        with torch.autocast(device_type=&quot;cuda&quot;, dtype=vae_dtype, enabled=vae_autocast_enabled):
            if not vae_autocast_enabled:
                image = image.to(vae_dtype)
            # Sample with the batch generator (diffusers parity); mode()
            # would make seed-for-seed reproduction of the reference
            # pipeline impossible.
            generator = batch.generator
            if isinstance(generator, list) and len(generator) != image.shape&#91;0&#93;:
                generator = generator&#91;0&#93;
            image_latent = vae.encode(image).sample(generator=generator)
    finally:
        vae.use_tiling = prev_use_tiling

    image_latent = image_latent * vae.scaling_factor
    # &#91;B, C, 1, H, W&#93; -&gt; &#91;B, 1, H, W, C&#93; to match channels-last latents
    batch.image_latent = image_latent.permute(0, 2, 3, 4, 1).contiguous()

    # Place the conditioning latent into the prepared latents: frame 0 of
    # the main channels, the visual_cond channel block, and the mask.
    # NOTE: the official kandinsky-5 repo leaves the visual_cond block
    # zeros (generation_utils.py generate()), while the diffusers port
    # copies the image latent into it. A same-seed A/B on
    # Kandinsky-5.0-I2V-Pro-distilled-5s-Diffusers showed the Diffusers
    # export requires the copy: zeroing the block produces smeared faces
    # mid-video. Keep the diffusers semantics for Diffusers-format
    # checkpoints.
    latents = batch.latents
    image_latent = batch.image_latent.to(device=latents.device, dtype=latents.dtype)
    num_channels = image_latent.shape&#91;-1&#93;
    latents&#91;:, 0:1, :, :, :num_channels&#93; = image_latent
    if latents.shape&#91;-1&#93; &gt; num_channels:
        latents&#91;:, 0:1, :, :, num_channels:2 * num_channels&#93; = image_latent
        latents&#91;:, 0:1, :, :, 2 * num_channels:&#93; = 1.0
    batch.latents = latents

    if fastvideo_args.vae_cpu_offload:
        vae.to(&quot;cpu&quot;)
    return batch</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage.verify_input"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage.verify_input</code></h3>
<pre class="doc-signature"><code>verify_input(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>

<details><summary>Source</summary><pre><code>def verify_input(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
    result = VerificationResult()
    result.add_check(&quot;pil_image&quot;, batch.pil_image, V.not_none)
    result.add_check(&quot;height&quot;, batch.height, V.positive_int)
    result.add_check(&quot;width&quot;, batch.width, V.positive_int)
    # This stage runs after latent preparation and writes into its output.
    result.add_check(&quot;latents&quot;, batch.latents, &#91;V.is_tensor, V.with_dims(5)&#93;)
    return result</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage.verify_output"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5ImageEncodingStage.verify_output</code></h3>
<pre class="doc-signature"><code>verify_output(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult</code></pre>

<details><summary>Source</summary><pre><code>def verify_output(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; VerificationResult:
    result = VerificationResult()
    result.add_check(&quot;image_latent&quot;, batch.image_latent, &#91;V.is_tensor, V.with_dims(5)&#93;)
    return result</code></pre></details>
<h2 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5NormalizationStage"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5NormalizationStage</code></h2>
<pre class="doc-signature"><code>Kandinsky5NormalizationStage()</code></pre>
<p>Normalize the first latent frames to reduce I2V conditioning artifacts.</p>
<details><summary>Source</summary><pre><code>class Kandinsky5NormalizationStage(PipelineStage):
    &quot;&quot;&quot;Normalize the first latent frames to reduce I2V conditioning artifacts.&quot;&quot;&quot;

    COND_FRAMES = 4
    REFERENCE_FRAMES = 5

    @staticmethod
    def _adaptive_mean_std(source: torch.Tensor, reference: torch.Tensor) -&gt; torch.Tensor:
        source_mean = source.mean(dim=(1, 2, 3, 4), keepdim=True)
        source_std = source.std(dim=(1, 2, 3, 4), keepdim=True)
        # Magic constants limit how far the first frames may drift.
        ref_mean = torch.clamp(reference.mean(dim=(1, 2, 3, 4), keepdim=True), source_mean - 0.05, source_mean + 0.1)
        ref_std = torch.clamp(reference.std(dim=(1, 2, 3, 4), keepdim=True), source_std - 0.1, source_std + 0.25)
        normalized = (source - source_mean) / source_std
        return normalized * ref_std + ref_mean

    def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
        latents = batch.latents
        n = self.COND_FRAMES
        if latents is None or latents.shape&#91;1&#93; &lt;= n:
            return batch

        reference = latents&#91;:, n:n + min(self.REFERENCE_FRAMES, latents.shape&#91;1&#93; - 1)&#93;
        latents&#91;:, :n&#93; = self._adaptive_mean_std(latents&#91;:, :n&#93;.clone(), reference)
        batch.latents = latents
        return batch</code></pre></details>
<h3 id="fastvideo.pipelines.stages.kandinsky5.Kandinsky5NormalizationStage.forward"><code>fastvideo.pipelines.stages.kandinsky5.Kandinsky5NormalizationStage.forward</code></h3>
<pre class="doc-signature"><code>forward(batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, batch: ForwardBatch, fastvideo_args: FastVideoArgs) -&gt; ForwardBatch:
    latents = batch.latents
    n = self.COND_FRAMES
    if latents is None or latents.shape&#91;1&#93; &lt;= n:
        return batch

    reference = latents&#91;:, n:n + min(self.REFERENCE_FRAMES, latents.shape&#91;1&#93; - 1)&#93;
    latents&#91;:, :n&#93; = self._adaptive_mean_std(latents&#91;:, :n&#93;.clone(), reference)
    batch.latents = latents
    return batch</code></pre></details>
</div>
