class_docstr: A latent diffusion wrapper. Latent diffusion is denoising diffusion
  applied to a latent space instead of the original data space
  
  Arguments
  ---------
  autoencoder: speechbrain.nnet.autoencoders.Autoencoder
      An autoencoder converting the original space to a latent space
  
  diffusion: speechbrian.nnet.diffusion.Diffuser
      A diffusion wrapper
  
  latent_downsample_factor: int
      The factor that latent space dimensions need to be divisible
      by. This is useful if the underlying model for the diffusion
      wrapper is based on a UNet-like architecture where the inputs
      are progressively downsampled and upsampled by factors of two
  
  latent_pad_dims: int|list[int]
      the dimension(s) along which the latent space will be
      padded
  
  Example
  -------
  >>> import torch
  >>> from torch import nn
  >>> from speechbrain.nnet.CNN import Conv2d
  >>> from speechbrain.nnet.autoencoders import NormalizingAutoencoder
  >>> from speechbrain.nnet.unet import UNetModel
  
  Set up a simple autoencoder (a real autoencoder would be a
  deep neural network)
  
  >>> ae_enc = Conv2d(
  ...     kernel_size=3,
  ...     stride=4,
  ...     in_channels=1,
  ...     out_channels=1,
  ...     skip_transpose=True,
  ... )
  >>> ae_dec = nn.ConvTranspose2d(
  ...     kernel_size=3,
  ...     stride=4,
  ...     in_channels=1,
  ...     out_channels=1,
  ...     output_padding=1
  ... )
  >>> ae = NormalizingAutoencoder(
  ...     encoder=ae_enc,
  ...     decoder=ae_dec,
  ... )
  
  Construct a diffusion model with a UNet architecture
  
  >>> unet = UNetModel(
  ...     in_channels=1,
  ...     model_channels=16,
  ...     norm_num_groups=4,
  ...     out_channels=1,
  ...     num_res_blocks=1,
  ...     attention_resolutions=[]
  ... )
  >>> diff = DenoisingDiffusion(
  ...     model=unet,
  ...     timesteps=5
  ... )
  >>> latent_diff = LatentDiffusion(
  ...     autoencoder=ae,
  ...     diffusion=diff,
  ...     latent_downsample_factor=4,
  ...     latent_pad_dim=2
  ... )
  >>> x = torch.randn(4, 1, 64, 64)
  >>> latent_sample = latent_diff.train_sample_latent(x)
  >>> diff_sample, ae_sample = latent_sample
  >>> pred, noise, noisy_sample = diff_sample
  >>> pred.shape
  torch.Size([4, 1, 16, 16])
  >>> noise.shape
  torch.Size([4, 1, 16, 16])
  >>> noisy_sample.shape
  torch.Size([4, 1, 16, 16])
  >>> ae_sample.latent.shape
  torch.Size([4, 1, 16, 16])
  
  Create a few samples (the shape given should be the shape
  of the latent space)
  
  >>> sample = latent_diff.sample((2, 1, 16, 16))
  >>> sample.shape
  torch.Size([2, 1, 64, 64])
code: def __init__(
      self,
      autoencoder,
      diffusion,
      latent_downsample_factor=None,
      latent_pad_dim=1,
  ):
      super().__init__()
      self.autencoder = autoencoder
      self.diffusion = diffusion
      self.latent_downsample_factor = latent_downsample_factor
      if isinstance(latent_pad_dim, int):
          latent_pad_dim = [latent_pad_dim]
      self.latent_pad_dim = latent_pad_dim
  
imports: from collections import namedtuple
  import torch
  from torch import nn
  from torch.nn import functional
  from tqdm.auto import tqdm
  from speechbrain.utils.data_utils import unsqueeze_as
  from speechbrain.dataio.dataio import length_to_mask
  from speechbrain.utils import data_utils
label_desc: Use image node_id 1 to create a new LatentDiffusion object from inherited base classes: nn with example: obj = LatentDiffusion(autoencoder, diffusion, latent_downsample_factor, latent_pad_dim)