//  [python]
def __init__(self, n_in_channels, cond_in_channels, hparams):
        super(WN, self).__init__()
        assert(hparams.wn_kernel_size % 2 == 1), 'kernel_size must be an odd number'
        assert(hparams.wn_n_channels % 2 == 0), 'n_channels must be a multiple of 2'
        assert(hparams.wn_cond_layers > 0), 'cond_layers must be greater than 0'
        assert hparams.wn_res_skip or hparams.wn_merge_res_skip, "Cannot remove res_skip without using merge_res_skip"
        self.n_layers = hparams.wn_n_layers
        self.n_channels = hparams.wn_n_channels
        self.speaker_embed_dim = 0
        self.merge_res_skip = hparams.wn_merge_res_skip
        self.first_wn = hparams.first_wn
        
        self.in_layers = nn.ModuleList()
        
        start = nn.Conv1d(n_in_channels, self.n_channels, 1)# first 1x1 Conv
        if weight_norm: start = nn.utils.weight_norm(start, name='weight')
        self.start = start
        
        end = nn.Conv1d(self.n_channels, 2*n_in_channels, 1) # last 1x1 Conv
        end.weight.data.zero_()
        end.weight.data.zero_()
        end.bias.data.zero_()
        self.end = end
        
        self.cond_layers = nn.ModuleList()
        if hparams.wn_cond_layers:
            cond_in_channels = cond_in_channels + self.speaker_embed_dim
            cond_pad = int((hparams.wn_cond_kernel_size - 1)/2)
            cond_output_channels = 2*self.n_channels*self.n_layers
            # messy initialization for arbitrary number of layers, input dims and output dims
            dimensions = [cond_in_channels,]+[hparams.wn_cond_hidden_channels]*(hparams.wn_cond_layers-1)+[cond_output_channels,]
            in_dims = dimensions[:-1]
            out_dims = dimensions[1:]
            
            for i in range(len(in_dims)):
                indim = in_dims[i]
                outim = out_dims[i]
                cond_layer = nn.Conv1d(indim, outim, hparams.wn_cond_kernel_size, padding=cond_pad, padding_mode=hparams.wn_cond_padding_mode)
                if weight_norm: cond_layer = nn.utils.weight_norm(cond_layer, name='weight')
                self.cond_layers.append(cond_layer)
            
            hparams.wn_cond_act_func = hparams.wn_cond_act_func.lower()
            if hparams.wn_cond_act_func == 'none':
                pass
            elif hparams.wn_cond_act_func == 'lrelu':
                self.wn_cond_act_func = torch.nn.functional.relu
            elif hparams.wn_cond_act_func == 'relu':
                assert negative_slope, "negative_slope not defined in wn_config"
                self.wn_cond_act_func = torch.nn.LeakyReLU(negative_slope=0.2, inplace=False)
            elif hparams.wn_cond_act_func == 'tanh':
                self.wn_cond_act_func = torch.nn.functional.tanh
            elif hparams.wn_cond_act_func == 'sigmoid':
                self.wn_cond_act_func = torch.nn.functional.sigmoid
            else:
                raise NotImplementedError('hparams.wn_cond_act_func is invalid')
        
        self.res_skip_layers = nn.ModuleList()
        if type(hparams.wn_dilations_w) == int:
            hparams.wn_dilations_w = [hparams.wn_dilations_w,]*self.n_layers # constant dilation if using int
        self.wn_padding_value = hparams.decoder_padding_value if self.first_wn else 0.0
        self.padding = []
        for i in range(self.n_layers):
            dilation = 2 ** i if hparams.wn_dilations_w is None else hparams.wn_dilations_w[i]
            self.padding.append( int((hparams.wn_kernel_size*dilation - dilation)/2) )
            if (not hparams.wn_seperable_conv) or (hparams.wn_kernel_size == 1):
                in_layer = nn.Conv1d(self.n_channels, 2*self.n_channels, hparams.wn_kernel_size, dilation=dilation, padding=0, padding_mode='zeros')
                if weight_norm: in_layer = nn.utils.weight_norm(in_layer, name='weight')
            else:
                depthwise = nn.Conv1d(self.n_channels, self.n_channels, hparams.wn_kernel_size, dilation=dilation, padding=0, padding_mode='zeros', groups=self.n_channels)
                if weight_norm: depthwise = nn.utils.weight_norm(depthwise, name='weight')
                pointwise = nn.Conv1d(self.n_channels, 2*self.n_channels, 1,
                                    dilation=dilation, padding=0)
                if weight_norm: pointwise = nn.utils.weight_norm(pointwise, name='weight')
                in_layer = torch.nn.Sequential(depthwise, pointwise)
            self.in_layers.append(in_layer)
            
            # last one is not necessary
            if i < self.n_layers - 1 and not self.merge_res_skip:
                res_skip_channels = 2*self.n_channels
            else:
                res_skip_channels = self.n_channels
            
            if hparams.wn_res_skip:
                res_skip_layer = nn.Conv1d(self.n_channels, res_skip_channels, 1)
                if weight_norm: res_skip_layer = nn.utils.weight_norm(res_skip_layer, name='weight')
                self.res_skip_layers.append(res_skip_layer)