class_docstr: ## DDIM Sampler
  
  This extends the [`DiffusionSampler` base class](index.html).
  
  DDIM samples images by repeatedly removing noise by sampling step by step using,
  
  egin{align}
  x_{ au_{i-1}} &= \sqrt{lpha_{      au_{i-1}}}\Bigg(
          rac{x_{    au_i} - \sqrt{1 - lpha_{       au_i}}\epsilon_ heta(x_{        au_i})}{\sqrt{lpha_{   au_i}}}
          \Bigg) \
          &+ \sqrt{1 - lpha_{        au_{i- 1}} - \sigma_{   au_i}^2} \cdot \epsilon_        heta(x_{        au_i}) \
          &+ \sigma_{ au_i} \epsilon_{        au_i}
  \end{align}
  
  where $\epsilon_{   au_i}$ is random noise,
  $   au$ is a subsequence of $[1,2,\dots,T]$ of length $S$,
  and
  $$\sigma_{  au_i} =
  \eta \sqrt{rac{1 - lpha_{ au_{i-1}}}{1 - lpha_{  au_i}}}
  \sqrt{1 - rac{lpha_{      au_i}}{lpha_{  au_{i-1}}}}$$
  
  Note that, $lpha_t$ in DDIM paper refers to ${\color{lightgreen}arlpha_t}$ from [DDPM](ddpm.html).
docstr: ### Sampling Loop
  
  :param shape: is the shape of the generated images in the
      form `[batch_size, channels, height, width]`
  :param cond: is the conditional embeddings $c$
  :param temperature: is the noise temperature (random noise gets multiplied by this)
  :param x_last: is $x_{  au_S}$. If not provided random noise will be used.
  :param uncond_scale: is the unconditional guidance scale $s$. This is used for
      $\epsilon_  heta(x_t, c) = s\epsilon_       ext{cond}(x_t, c) + (s - 1)\epsilon_    ext{cond}(x_t, c_u)$
  :param uncond_cond: is the conditional embedding for empty prompt $c_u$
  :param skip_steps: is the number of time steps to skip $i'$. We start sampling from $S - i'$.
      And `x_last` is then $x_{   au_{S - i'}}$.
docstr_tok: ["#","#","#","Sampling","Loop",":","param","shape",":","is","the","shape","of","the","generated","images","in","the","form","`","[","batch_size",",","channels",",","height",",","width","]","`",":","param","cond",":","is","the","conditional","embeddings","$","c","$",":","param","temperature",":","is","the","noise","temperature","(","random","noise","gets","multiplied","by","this",")",":","param","x_last",":","is","$","x_","{","au_S","}","$",".","If","not","provided","random","noise","will","be","used",".",":","param","uncond_scale",":","is","the","unconditional","guidance","scale","$","s","$",".","This","is","used","for","$","\\epsilon_","heta","(","x_t",",","c",")","=","s\\epsilon_","ext","{","cond","}","(","x_t",",","c",")","+","(","s","-","1",")","\\epsilon_","ext","{","cond","}","(","x_t",",","c_u",")","$",":","param","uncond_cond",":","is","the","conditional","embedding","for","empty","prompt","$","c_u","$",":","param","skip_steps",":","is","the","number","of","time","steps","to","skip","$","i","'","$",".","We","start","sampling","from","$","S","-","i","'","$",".","And","`","x_last","`","is","then","$","x_","{","au_","{","S","-","i","'","}","}","$","."]
code: def sample(
      self,
      shape: List[int],
      cond: torch.Tensor,
      repeat_noise: bool = False,
      temperature: float = 1.0,
      x_last: Optional[torch.Tensor] = None,
      uncond_scale: float = 1.0,
      uncond_cond: Optional[torch.Tensor] = None,
      skip_steps: int = 0,
  ):
      """
      ### Sampling Loop
  
      :param shape: is the shape of the generated images in the
          form `[batch_size, channels, height, width]`
      :param cond: is the conditional embeddings $c$
      :param temperature: is the noise temperature (random noise gets multiplied by this)
      :param x_last: is $x_{\tau_S}$. If not provided random noise will be used.
      :param uncond_scale: is the unconditional guidance scale $s$. This is used for
          $\epsilon_\theta(x_t, c) = s\epsilon_\text{cond}(x_t, c) + (s - 1)\epsilon_\text{cond}(x_t, c_u)$
      :param uncond_cond: is the conditional embedding for empty prompt $c_u$
      :param skip_steps: is the number of time steps to skip $i'$. We start sampling from $S - i'$.
          And `x_last` is then $x_{\tau_{S - i'}}$.
      """
  
      # Get device and batch size
      device = self.model.device
      bs = shape[0]
  
      # Get $x_{\tau_S}$
      x = (
          x_last
          if x_last is not None
          else torch.randn(shape, device=device)
      )
  
      # Time steps to sample at $\tau_{S - i'}, \tau_{S - i' - 1}, \dots, \tau_1$
      time_steps = np.flip(self.time_steps)[skip_steps:]
  
      for i, step in monit.enum("Sample", time_steps):
          # Index $i$ in the list $[\tau_1, \tau_2, \dots, \tau_S]$
          index = len(time_steps) - i - 1
          # Time step $\tau_i$
          ts = x.new_full((bs,), step, dtype=torch.long)
  
          # Sample $x_{\tau_{i-1}}$
          x, pred_x0, e_t = self.p_sample(
              x,
              cond,
              ts,
              step,
              index=index,
              repeat_noise=repeat_noise,
              temperature=temperature,
              uncond_scale=uncond_scale,
              uncond_cond=uncond_cond,
          )
  
      # Return $x_0$
      return x
  
file_path: annotated_deep_learning_paper_implementations/labml_nn/diffusion/stable_diffusion/sampler/ddim.py
imports: from typing import Optional, List
  import numpy
  import torch
  from labml import monit
  from labml_nn.diffusion.stable_diffusion.latent_diffusion import LatentDiffusion
  from labml_nn.diffusion.stable_diffusion.sampler import DiffusionSampler
label_desc: Use image node_id 2 for calling the DDIMSampler obj's underlying member method code with example usage: obj.sample(shape, cond, repeat_noise, temperature, x_last, uncond_scale, uncond_cond, skip_steps) and returns: x