---
title: scheduling_self_forcing_flow_match
---

<div class="python-reference">
<a id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match-classes"></a>
<a id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match-functions"></a>
<a id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler-functions"></a>
<a id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match"></a>

<h2 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.init_logger"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.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.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler</code></h2>
<pre class="doc-signature"><code>BaseScheduler(*args, **kwargs)</code></pre>


<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler.set_shift"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler.set_shift</code></h3>
<pre class="doc-signature"><code>set_shift(shift: float) -&gt; None</code></pre>

<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler.set_timesteps"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler.set_timesteps</code></h3>
<pre class="doc-signature"><code>set_timesteps(*args, **kwargs) -&gt; None</code></pre>

<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler.scale_model_input"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.BaseScheduler.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.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchSchedulerOutput"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchSchedulerOutput</code></h2>
<pre class="doc-signature"><code>SelfForcingFlowMatchSchedulerOutput()</code></pre>
<p>Output class for the scheduler's <code>step</code> function output.</p>
<h3>Parameters</h3>
<dl>
<dt><code>prev_sample: `torch.FloatTensor` of shape `(batch_size, num_channels, height, width)` for images</code></dt><dd><p>Computed sample <code>(x_&#123;t-1&#125;)</code> of previous timestep. <code>prev_sample</code> should be used as next model input in the
denoising loop.</p></dd>
</dl>
<details><summary>Source</summary><pre><code>class SelfForcingFlowMatchSchedulerOutput(BaseOutput):
    &quot;&quot;&quot;
    Output class for the scheduler&#x27;s `step` function output.

    Args:
        prev_sample (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)` for images):
            Computed sample `(x_&#123;t-1&#125;)` of previous timestep. `prev_sample` should be used as next model input in the
            denoising loop.
    &quot;&quot;&quot;
    prev_sample: torch.FloatTensor</code></pre></details>
<h2 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler</code></h2>
<pre class="doc-signature"><code>SelfForcingFlowMatchScheduler(num_inference_steps = 100, num_train_timesteps = 1000, shift = 3.0, sigma_max = 1.0, sigma_min = 0.003 / 1.002, inverse_timesteps = False, extra_one_step = False, reverse_sigmas = False, training = False)</code></pre>


<details><summary>Source</summary><pre><code>class SelfForcingFlowMatchScheduler(BaseScheduler, ConfigMixin, SchedulerMixin):

    config_name = &quot;scheduler_config.json&quot;
    order = 1

    @register_to_config
    def __init__(self,
                 num_inference_steps=100,
                 num_train_timesteps=1000,
                 shift=3.0,
                 sigma_max=1.0,
                 sigma_min=0.003 / 1.002,
                 inverse_timesteps=False,
                 extra_one_step=False,
                 reverse_sigmas=False,
                 training=False):
        self.num_train_timesteps = num_train_timesteps
        self.shift = shift
        self.sigma_max = sigma_max
        self.sigma_min = sigma_min
        self.inverse_timesteps = inverse_timesteps
        self.extra_one_step = extra_one_step
        self.reverse_sigmas = reverse_sigmas
        self.set_timesteps(num_inference_steps, training=training)

    def set_timesteps(self,
                      num_inference_steps=100,
                      denoising_strength=1.0,
                      training=False,
                      return_dict=False,
                      **kwargs):
        sigma_start = self.sigma_min + \
            (self.sigma_max - self.sigma_min) * denoising_strength
        if self.extra_one_step:
            self.sigmas = torch.linspace(sigma_start, self.sigma_min, num_inference_steps + 1)&#91;:-1&#93;
        else:
            self.sigmas = torch.linspace(sigma_start, self.sigma_min, num_inference_steps)
        if self.inverse_timesteps:
            self.sigmas = torch.flip(self.sigmas, dims=&#91;0&#93;)
        self.sigmas = self.shift * self.sigmas / \
            (1 + (self.shift - 1) * self.sigmas)
        if self.reverse_sigmas:
            self.sigmas = 1 - self.sigmas
        self.timesteps = self.sigmas * self.num_train_timesteps
        if training:
            x = self.timesteps
            y = torch.exp(-2 * ((x - num_inference_steps / 2) / num_inference_steps)**2)
            y_shifted = y - y.min()
            bsmntw_weighing = y_shifted * \
                (num_inference_steps / y_shifted.sum())
            self.linear_timesteps_weights = bsmntw_weighing

    def step(self,
             model_output: torch.FloatTensor,
             timestep: torch.FloatTensor,
             sample: torch.FloatTensor,
             to_final=False,
             return_dict=False,
             **kwargs):
        if timestep.ndim == 2:
            timestep = timestep.flatten(0, 1)
        elif timestep.ndim == 0:
            # handles the case where timestep is a scalar, this occurs when we
            # use this scheduler for ODE trajectory
            timestep = timestep.unsqueeze(0)

        self.sigmas = self.sigmas.to(model_output.device)
        self.timesteps = self.timesteps.to(model_output.device)
        timestep = timestep.to(model_output.device)

        timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - timestep.unsqueeze(1)).abs(), dim=1)
        sigma = self.sigmas&#91;timestep_id&#93;.reshape(-1, 1, 1, 1)
        if to_final or (timestep_id + 1 &gt;= len(self.timesteps)).any():
            sigma_ = 1 if (self.inverse_timesteps or self.reverse_sigmas) else 0
        else:
            sigma_ = self.sigmas&#91;timestep_id + 1&#93;.reshape(-1, 1, 1, 1)
        prev_sample = sample + model_output * (sigma_ - sigma)
        if isinstance(prev_sample, torch.Tensor | float) and not return_dict:
            return (prev_sample, )
        return SelfForcingFlowMatchSchedulerOutput(prev_sample=prev_sample)

    @staticmethod
    def calculate_alpha_beta_high(sigma, sigma_bound):
        alpha = (1 - sigma) / (1 - sigma_bound)
        beta = torch.sqrt(sigma**2 - (alpha * sigma_bound)**2)
        return alpha, beta

    def add_noise(self, original_samples, noise, timestep):
        &quot;&quot;&quot;
        Diffusion forward corruption process.
        Input:
            - clean_latent: the clean latent with shape &#91;B*T, C, H, W&#93;
            - noise: the noise with shape &#91;B*T, C, H, W&#93;
            - timestep: the timestep with shape &#91;B*T&#93;
        Output: the corrupted latent with shape &#91;B*T, C, H, W&#93;
        &quot;&quot;&quot;
        if timestep.ndim == 2:
            timestep = timestep.flatten(0, 1)
        self.sigmas = self.sigmas.to(noise.device)
        self.timesteps = self.timesteps.to(noise.device)
        timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - timestep.unsqueeze(1)).abs(), dim=1)
        sigma = self.sigmas&#91;timestep_id&#93;.reshape(-1, 1, 1, 1)
        sample = (1 - sigma) * original_samples + sigma * noise
        return sample.type_as(noise)

    def add_noise_high(self, original_samples, noise, timestep, boundary_timestep):
        &quot;&quot;&quot;
        Diffusion forward corruption process.
        Input:
            - clean_latent: the clean latent with shape &#91;B*T, C, H, W&#93;
            - noise: the noise with shape &#91;B*T, C, H, W&#93;
            - timestep: the timestep with shape &#91;B*T&#93;
        Output: the corrupted latent with shape &#91;B*T, C, H, W&#93;
        &quot;&quot;&quot;
        if timestep.ndim == 2:
            timestep = timestep.flatten(0, 1)
        if boundary_timestep.ndim == 2:
            boundary_timestep = boundary_timestep.flatten(0, 1)
        self.sigmas = self.sigmas.to(noise.device)
        self.timesteps = self.timesteps.to(noise.device)
        timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - timestep.unsqueeze(1)).abs(), dim=1)
        sigma = self.sigmas&#91;timestep_id&#93;.reshape(-1, 1, 1, 1)

        boundary_timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - boundary_timestep.unsqueeze(1)).abs(), dim=1)
        sigma_boundary = self.sigmas&#91;boundary_timestep_id&#93;.reshape(-1, 1, 1, 1)
        alpha, beta = self.calculate_alpha_beta_high(sigma, sigma_boundary)
        sample = alpha * original_samples + beta * noise
        return sample.type_as(noise)

    def training_target(self, sample, noise, timestep):
        target = noise - sample
        return target

    def training_weight(self, timestep):
        &quot;&quot;&quot;
        Input:
            - timestep: the timestep with shape &#91;B*T&#93;
        Output: the corresponding weighting &#91;B*T&#93;
        &quot;&quot;&quot;
        if timestep.ndim == 2:
            timestep = timestep.flatten(0, 1)
        self.linear_timesteps_weights = self.linear_timesteps_weights.to(timestep.device)
        timestep_id = torch.argmin((self.timesteps.unsqueeze(1) - timestep.unsqueeze(0)).abs(), dim=0)
        weights = self.linear_timesteps_weights&#91;timestep_id&#93;
        return weights

    def scale_model_input(self, sample: torch.Tensor, timestep: int | None = None) -&gt; torch.Tensor:
        return sample

    def set_shift(self, shift: float) -&gt; None:
        self.shift = shift</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.set_timesteps"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.set_timesteps</code></h3>
<pre class="doc-signature"><code>set_timesteps(num_inference_steps = 100, denoising_strength = 1.0, training = False, return_dict = False, **kwargs)</code></pre>

<details><summary>Source</summary><pre><code>def set_timesteps(self,
                  num_inference_steps=100,
                  denoising_strength=1.0,
                  training=False,
                  return_dict=False,
                  **kwargs):
    sigma_start = self.sigma_min + \
        (self.sigma_max - self.sigma_min) * denoising_strength
    if self.extra_one_step:
        self.sigmas = torch.linspace(sigma_start, self.sigma_min, num_inference_steps + 1)&#91;:-1&#93;
    else:
        self.sigmas = torch.linspace(sigma_start, self.sigma_min, num_inference_steps)
    if self.inverse_timesteps:
        self.sigmas = torch.flip(self.sigmas, dims=&#91;0&#93;)
    self.sigmas = self.shift * self.sigmas / \
        (1 + (self.shift - 1) * self.sigmas)
    if self.reverse_sigmas:
        self.sigmas = 1 - self.sigmas
    self.timesteps = self.sigmas * self.num_train_timesteps
    if training:
        x = self.timesteps
        y = torch.exp(-2 * ((x - num_inference_steps / 2) / num_inference_steps)**2)
        y_shifted = y - y.min()
        bsmntw_weighing = y_shifted * \
            (num_inference_steps / y_shifted.sum())
        self.linear_timesteps_weights = bsmntw_weighing</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.step"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.step</code></h3>
<pre class="doc-signature"><code>step(model_output: torch.FloatTensor, timestep: torch.FloatTensor, sample: torch.FloatTensor, to_final = False, return_dict = False, **kwargs)</code></pre>

<details><summary>Source</summary><pre><code>def step(self,
         model_output: torch.FloatTensor,
         timestep: torch.FloatTensor,
         sample: torch.FloatTensor,
         to_final=False,
         return_dict=False,
         **kwargs):
    if timestep.ndim == 2:
        timestep = timestep.flatten(0, 1)
    elif timestep.ndim == 0:
        # handles the case where timestep is a scalar, this occurs when we
        # use this scheduler for ODE trajectory
        timestep = timestep.unsqueeze(0)

    self.sigmas = self.sigmas.to(model_output.device)
    self.timesteps = self.timesteps.to(model_output.device)
    timestep = timestep.to(model_output.device)

    timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - timestep.unsqueeze(1)).abs(), dim=1)
    sigma = self.sigmas&#91;timestep_id&#93;.reshape(-1, 1, 1, 1)
    if to_final or (timestep_id + 1 &gt;= len(self.timesteps)).any():
        sigma_ = 1 if (self.inverse_timesteps or self.reverse_sigmas) else 0
    else:
        sigma_ = self.sigmas&#91;timestep_id + 1&#93;.reshape(-1, 1, 1, 1)
    prev_sample = sample + model_output * (sigma_ - sigma)
    if isinstance(prev_sample, torch.Tensor | float) and not return_dict:
        return (prev_sample, )
    return SelfForcingFlowMatchSchedulerOutput(prev_sample=prev_sample)</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.calculate_alpha_beta_high"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.calculate_alpha_beta_high</code></h3>
<pre class="doc-signature"><code>calculate_alpha_beta_high(sigma, sigma_bound)</code></pre>

<details><summary>Source</summary><pre><code>@staticmethod
def calculate_alpha_beta_high(sigma, sigma_bound):
    alpha = (1 - sigma) / (1 - sigma_bound)
    beta = torch.sqrt(sigma**2 - (alpha * sigma_bound)**2)
    return alpha, beta</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.add_noise"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.add_noise</code></h3>
<pre class="doc-signature"><code>add_noise(original_samples, noise, timestep)</code></pre>
<p>Diffusion forward corruption process.
Input:
    - clean_latent: the clean latent with shape [B<em>T, C, H, W]
    - noise: the noise with shape [B</em>T, C, H, W]
    - timestep: the timestep with shape [B<em>T]
Output: the corrupted latent with shape [B</em>T, C, H, W]</p>
<details><summary>Source</summary><pre><code>def add_noise(self, original_samples, noise, timestep):
    &quot;&quot;&quot;
    Diffusion forward corruption process.
    Input:
        - clean_latent: the clean latent with shape &#91;B*T, C, H, W&#93;
        - noise: the noise with shape &#91;B*T, C, H, W&#93;
        - timestep: the timestep with shape &#91;B*T&#93;
    Output: the corrupted latent with shape &#91;B*T, C, H, W&#93;
    &quot;&quot;&quot;
    if timestep.ndim == 2:
        timestep = timestep.flatten(0, 1)
    self.sigmas = self.sigmas.to(noise.device)
    self.timesteps = self.timesteps.to(noise.device)
    timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - timestep.unsqueeze(1)).abs(), dim=1)
    sigma = self.sigmas&#91;timestep_id&#93;.reshape(-1, 1, 1, 1)
    sample = (1 - sigma) * original_samples + sigma * noise
    return sample.type_as(noise)</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.add_noise_high"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.add_noise_high</code></h3>
<pre class="doc-signature"><code>add_noise_high(original_samples, noise, timestep, boundary_timestep)</code></pre>
<p>Diffusion forward corruption process.
Input:
    - clean_latent: the clean latent with shape [B<em>T, C, H, W]
    - noise: the noise with shape [B</em>T, C, H, W]
    - timestep: the timestep with shape [B<em>T]
Output: the corrupted latent with shape [B</em>T, C, H, W]</p>
<details><summary>Source</summary><pre><code>def add_noise_high(self, original_samples, noise, timestep, boundary_timestep):
    &quot;&quot;&quot;
    Diffusion forward corruption process.
    Input:
        - clean_latent: the clean latent with shape &#91;B*T, C, H, W&#93;
        - noise: the noise with shape &#91;B*T, C, H, W&#93;
        - timestep: the timestep with shape &#91;B*T&#93;
    Output: the corrupted latent with shape &#91;B*T, C, H, W&#93;
    &quot;&quot;&quot;
    if timestep.ndim == 2:
        timestep = timestep.flatten(0, 1)
    if boundary_timestep.ndim == 2:
        boundary_timestep = boundary_timestep.flatten(0, 1)
    self.sigmas = self.sigmas.to(noise.device)
    self.timesteps = self.timesteps.to(noise.device)
    timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - timestep.unsqueeze(1)).abs(), dim=1)
    sigma = self.sigmas&#91;timestep_id&#93;.reshape(-1, 1, 1, 1)

    boundary_timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - boundary_timestep.unsqueeze(1)).abs(), dim=1)
    sigma_boundary = self.sigmas&#91;boundary_timestep_id&#93;.reshape(-1, 1, 1, 1)
    alpha, beta = self.calculate_alpha_beta_high(sigma, sigma_boundary)
    sample = alpha * original_samples + beta * noise
    return sample.type_as(noise)</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.training_target"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.training_target</code></h3>
<pre class="doc-signature"><code>training_target(sample, noise, timestep)</code></pre>

<details><summary>Source</summary><pre><code>def training_target(self, sample, noise, timestep):
    target = noise - sample
    return target</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.training_weight"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.training_weight</code></h3>
<pre class="doc-signature"><code>training_weight(timestep)</code></pre>
<h4>Input</h4>
<ul>
<li>timestep: the timestep with shape [B*T]</li>
</ul>
<p>Output: the corresponding weighting [B*T]</p>
<details><summary>Source</summary><pre><code>def training_weight(self, timestep):
    &quot;&quot;&quot;
    Input:
        - timestep: the timestep with shape &#91;B*T&#93;
    Output: the corresponding weighting &#91;B*T&#93;
    &quot;&quot;&quot;
    if timestep.ndim == 2:
        timestep = timestep.flatten(0, 1)
    self.linear_timesteps_weights = self.linear_timesteps_weights.to(timestep.device)
    timestep_id = torch.argmin((self.timesteps.unsqueeze(1) - timestep.unsqueeze(0)).abs(), dim=0)
    weights = self.linear_timesteps_weights&#91;timestep_id&#93;
    return weights</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.scale_model_input"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.scale_model_input</code></h3>
<pre class="doc-signature"><code>scale_model_input(sample: torch.Tensor, timestep: int | None = None) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def scale_model_input(self, sample: torch.Tensor, timestep: int | None = None) -&gt; torch.Tensor:
    return sample</code></pre></details>
<h3 id="fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.set_shift"><code>fastvideo.models.schedulers.scheduling_self_forcing_flow_match.SelfForcingFlowMatchScheduler.set_shift</code></h3>
<pre class="doc-signature"><code>set_shift(shift: float) -&gt; None</code></pre>

<details><summary>Source</summary><pre><code>def set_shift(self, shift: float) -&gt; None:
    self.shift = shift</code></pre></details>
</div>
