class_docstr: Stochastic duration predictor with Spline Flows.
  
  It applies Variational Dequantization and Variational Data Augmentation.
  
  Paper:
      SDP: https://arxiv.org/pdf/2106.06103.pdf
      Spline Flow: https://arxiv.org/abs/1906.04032
  
  ::
      ## Inference
  
      x -> TextCondEncoder() -> Flow() -> dr_hat
      noise ----------------------^
  
      ## Training
                                                                            |---------------------|
      x -> TextCondEncoder() -> + -> PosteriorEncoder() -> split() -> z_u, z_v -> (d - z_u) -> concat() -> Flow() -> noise
      d -> DurCondEncoder()  -> ^                                                    |
      |------------------------------------------------------------------------------|
  
  Args:
      in_channels (int): Number of input tensor channels.
      hidden_channels (int): Number of hidden channels.
      kernel_size (int): Kernel size of convolutional layers.
      dropout_p (float): Dropout rate.
      num_flows (int, optional): Number of flow blocks. Defaults to 4.
      cond_channels (int, optional): Number of channels of conditioning tensor. Defaults to 0.
docstr: Shapes:
      - x: :math:`[B, C, T]`
      - x_mask: :math:`[B, 1, T]`
      - dr: :math:`[B, 1, T]`
      - g: :math:`[B, C]`
docstr_tok: ["Shapes",":","-","x",":",":","math",":","`","[","B",",","C",",","T","]","`","-","x_mask",":",":","math",":","`","[","B",",","1",",","T","]","`","-","dr",":",":","math",":","`","[","B",",","1",",","T","]","`","-","g",":",":","math",":","`","[","B",",","C","]","`"]
code: def forward(
      self,
      x,
      x_mask,
      dr=None,
      g=None,
      lang_emb=None,
      reverse=False,
      noise_scale=1.0,
  ):
      """
      Shapes:
          - x: :math:`[B, C, T]`
          - x_mask: :math:`[B, 1, T]`
          - dr: :math:`[B, 1, T]`
          - g: :math:`[B, C]`
      """
      # condition encoder text
      x = self.pre(x)
      if g is not None:
          x = x + self.cond(g)
  
      if lang_emb is not None:
          x = x + self.cond_lang(lang_emb)
  
      x = self.convs(x, x_mask)
      x = self.proj(x) * x_mask
  
      if not reverse:
          flows = self.flows
          assert dr is not None
  
          # condition encoder duration
          h = self.post_pre(dr)
          h = self.post_convs(h, x_mask)
          h = self.post_proj(h) * x_mask
          noise = (
              torch.randn(dr.size(0), 2, dr.size(2)).to(
                  device=x.device, dtype=x.dtype
              )
              * x_mask
          )
          z_q = noise
  
          # posterior encoder
          logdet_tot_q = 0.0
          for idx, flow in enumerate(self.post_flows):
              z_q, logdet_q = flow(z_q, x_mask, g=(x + h))
              logdet_tot_q = logdet_tot_q + logdet_q
              if idx > 0:
                  z_q = torch.flip(z_q, [1])
  
          z_u, z_v = torch.split(z_q, [1, 1], 1)
          u = torch.sigmoid(z_u) * x_mask
          z0 = (dr - u) * x_mask
  
          # posterior encoder - neg log likelihood
          logdet_tot_q += torch.sum(
              (F.logsigmoid(z_u) + F.logsigmoid(-z_u)) * x_mask, [1, 2]
          )
          nll_posterior_encoder = (
              torch.sum(
                  -0.5
                  * (math.log(2 * math.pi) + (noise**2))
                  * x_mask,
                  [1, 2],
              )
              - logdet_tot_q
          )
  
          z0 = torch.log(torch.clamp_min(z0, 1e-5)) * x_mask
          logdet_tot = torch.sum(-z0, [1, 2])
          z = torch.cat([z0, z_v], 1)
  
          # flow layers
          for idx, flow in enumerate(flows):
              z, logdet = flow(z, x_mask, g=x, reverse=reverse)
              logdet_tot = logdet_tot + logdet
              if idx > 0:
                  z = torch.flip(z, [1])
  
          # flow layers - neg log likelihood
          nll_flow_layers = (
              torch.sum(
                  0.5 * (math.log(2 * math.pi) + (z**2)) * x_mask,
                  [1, 2],
              )
              - logdet_tot
          )
          return nll_flow_layers + nll_posterior_encoder
  
      flows = list(reversed(self.flows))
      flows = flows[:-2] + [flows[-1]]  # remove a useless vflow
      z = (
          torch.randn(x.size(0), 2, x.size(2)).to(
              device=x.device, dtype=x.dtype
          )
          * noise_scale
      )
      for flow in flows:
          z = torch.flip(z, [1])
          z = flow(z, x_mask, g=x, reverse=reverse)
  
      z0, _ = torch.split(z, [1, 1], 1)
      logw = z0
      return logw
  
imports: import math
  import torch
  from torch import nn
  from torch.nn import functional
  from TTS.tts.layers.generic.normalization import LayerNorm2
  from TTS.tts.layers.vits.transforms import piecewise_rational_quadratic_transform
label_desc: Use image node_id 2 for calling the StochasticDurationPredictor obj's underlying member method code with example usage: obj.forward(x, x_mask, dr, g, lang_emb, reverse, noise_scale) and returns: logw, unknown