text: # coding: utf-8
  from __future__ import with_statement, print_function, absolute_import
  
  import math
  import numpy as np
  
  import torch
  from wavenet_vocoder import conv
  from torch import nn
  from torch.nn import functional as F
  
  
  def Conv1d(in_channels, out_channels, kernel_size, dropout=0, std_mul=4.0, **kwargs):
      m = conv.Conv1d(in_channels, out_channels, kernel_size, **kwargs)
      std = math.sqrt((std_mul * (1.0 - dropout)) / (m.kernel_size[0] * in_channels))
      m.weight.data.normal_(mean=0, std=std)
      m.bias.data.zero_()
      return nn.utils.weight_norm(m)
  
  
  def Embedding(num_embeddings, embedding_dim, padding_idx, std=0.01):
      m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx)
      m.weight.data.normal_(0, std)
      return m
  
  
  def ConvTranspose2d(in_channels, out_channels, kernel_size,
                      weight_normalization=True, **kwargs):
      freq_axis_kernel_size = kernel_size[0]
      m = nn.ConvTranspose2d(in_channels, out_channels, kernel_size, **kwargs)
      m.weight.data.fill_(1.0 / freq_axis_kernel_size)
      m.bias.data.zero_()
      if weight_normalization:
          return nn.utils.weight_norm(m)
      else:
          return m
  
  
  def Conv1d1x1(in_channels, out_channels, bias=True, weight_normalization=True):
      """1-by-1 convolution layer
      """
      if weight_normalization:
          assert bias
          return Conv1d(in_channels, out_channels, kernel_size=1, padding=0,
                        dilation=1, bias=bias, std_mul=1.0)
      else:
          return conv.Conv1d(in_channels, out_channels, kernel_size=1, padding=0,
                             dilation=1, bias=bias)
  
  
  def _conv1x1_forward(conv, x, is_incremental):
      """Conv1x1 forward
      """
      if is_incremental:
          x = conv.incremental_forward(x)
      else:
          x = conv(x)
      return x
  
  
  class ResidualConv1dGLU(nn.Module):
      """Residual dilated conv1d + Gated linear unit
  
      Args:
          residual_channels (int): Residual input / output channels
          gate_channels (int): Gated activation channels.
          kernel_size (int): Kernel size of convolution layers.
          skip_out_channels (int): Skip connection channels. If None, set to same
            as ``residual_channels``.
          cin_channels (int): Local conditioning channels. If negative value is
            set, local conditioning is disabled.
          gin_channels (int): Global conditioning channels. If negative value is
            set, global conditioning is disabled.
          dropout (float): Dropout probability.
          padding (int): Padding for convolution layers. If None, proper padding
            is computed depends on dilation and kernel_size.
          dilation (int): Dilation factor.
          weight_normalization (bool): If True, DeepVoice3-style weight
            normalization is applied.
      """
  
      def __init__(self, residual_channels, gate_channels, kernel_size,
                   skip_out_channels=None,
                   cin_channels=-1, gin_channels=-1,
                   dropout=1 - 0.95, padding=None, dilation=1, causal=True,
                   bias=True, weight_normalization=True, *args, **kwargs):
          super(ResidualConv1dGLU, self).__init__()
          self.dropout = dropout
          if skip_out_channels is None:
              skip_out_channels = residual_channels
          if padding is None:
              # no future time stamps available
              if causal:
                  padding = (kernel_size - 1) * dilation
              else:
                  padding = (kernel_size - 1) // 2 * dilation
          self.causal = causal
  
          if weight_normalization:
              assert bias
              self.conv = Conv1d(residual_channels, gate_channels, kernel_size,
                                 padding=padding, dilation=dilation,
                                 bias=bias, std_mul=1.0, *args, **kwargs)
          else:
              self.conv = conv.Conv1d(residual_channels, gate_channels, kernel_size,
                                      padding=padding, dilation=dilation,
                                      bias=bias, *args, **kwargs)
  
          # local conditioning
          if cin_channels > 0:
              self.conv1x1c = Conv1d1x1(cin_channels, gate_channels,
                                        bias=bias,
                                        weight_normalization=weight_normalization)
          else:
              self.conv1x1c = None
  
          # global conditioning
          if gin_channels > 0:
              self.conv1x1g = Conv1d1x1(gin_channels, gate_channels, bias=bias,
                                        weight_normalization=weight_normalization)
          else:
              self.conv1x1g = None
  
          # conv output is split into two groups
          gate_out_channels = gate_channels // 2
          self.conv1x1_out = Conv1d1x1(gate_out_channels, residual_channels, bias=bias,
                                       weight_normalization=weight_normalization)
          self.conv1x1_skip = Conv1d1x1(gate_out_channels, skip_out_channels, bias=bias,
                                        weight_normalization=weight_normalization)
  
      def forward(self, x, c=None, g=None):
          return self._forward(x, c, g, False)
  
      def incremental_forward(self, x, c=None, g=None):
          return self._forward(x, c, g, True)
  
      def _forward(self, x, c, g, is_incremental):
          """Forward
  
          Args:
              x (Tensor): B x C x T
              c (Tensor): B x C x T, Local conditioning features
              g (Tensor): B x C x T, Expanded global conditioning features
              is_incremental (Bool) : Whether incremental mode or not
  
          Returns:
              Tensor: output
          """
          residual = x
          x = F.dropout(x, p=self.dropout, training=self.training)
          if is_incremental:
              splitdim = -1
              x = self.conv.incremental_forward(x)
          else:
              splitdim = 1
              x = self.conv(x)
              # remove future time steps
              x = x[:, :, :residual.size(-1)] if self.causal else x
  
          a, b = x.split(x.size(splitdim) // 2, dim=splitdim)
  
          # local conditioning
          if c is not None:
              assert self.conv1x1c is not None
              c = _conv1x1_forward(self.conv1x1c, c, is_incremental)
              ca, cb = c.split(c.size(splitdim) // 2, dim=splitdim)
              a, b = a + ca, b + cb
  
          # global conditioning
          if g is not None:
              assert self.conv1x1g is not None
              g = _conv1x1_forward(self.conv1x1g, g, is_incremental)
              ga, gb = g.split(g.size(splitdim) // 2, dim=splitdim)
              a, b = a + ga, b + gb
  
          x = F.tanh(a) * F.sigmoid(b)
  
          # For skip connection
          s = _conv1x1_forward(self.conv1x1_skip, x, is_incremental)
  
          # For residual connection
          x = _conv1x1_forward(self.conv1x1_out, x, is_incremental)
  
          x = (x + residual) * math.sqrt(0.5)
          return x, s
  
      def clear_buffer(self):
          for c in [self.conv, self.conv1x1_out, self.conv1x1_skip,
                    self.conv1x1c, self.conv1x1g]:
              if c is not None:
                  c.clear_buffer()
  