class_docstr: Dual-path RNN module with MulCat blocks.
  
  Args:
      input_size: int, dimension of the input feature.
          The input should have shape (batch, seq_len, input_size).
      hidden_size: int, dimension of the hidden state.
      output_size: int, dimension of the output size.
      num_spk: int, the number of speakers in the output.
      dropout: float, the dropout rate in the LSTM layer. (Default: 0.0)
      bidirectional: bool, whether the RNN layers are bidirectional. (Default: True)
      num_layers: int, number of stacked MulCat blocks. (Default: 4)
      input_normalize: bool, whether to apply GroupNorm on the input Tensor.
          (Default: False)
docstr: Compute output after DPMulCat module.
  
  Args:
      input (torch.Tensor): The input feature.
          Tensor of shape (batch, N, dim1, dim2)
          Apply RNN on dim1 first and then dim2
  
  Returns:
      (list(torch.Tensor) or list(list(torch.Tensor))
          In training mode, the module returns output of each DPMulCat block.
          In eval mode, the module only returns output in the last block.
docstr_tok: ["Compute","output","after","DPMulCat","module",".","Args",":","input","(","torch.Tensor",")",":","The","input","feature",".","Tensor","of","shape","(","batch",",","N",",","dim1",",","dim2",")","Apply","RNN","on","dim1","first","and","then","dim2","Returns",":","(","list","(","torch.Tensor",")","or","list","(","list","(","torch.Tensor",")",")","In","training","mode",",","the","module","returns","output","of","each","DPMulCat","block",".","In","eval","mode",",","the","module","only","returns","output","in","the","last","block","."]
code: def forward(self, input):
      """Compute output after DPMulCat module.
  
      Args:
          input (torch.Tensor): The input feature.
              Tensor of shape (batch, N, dim1, dim2)
              Apply RNN on dim1 first and then dim2
  
      Returns:
          (list(torch.Tensor) or list(list(torch.Tensor))
              In training mode, the module returns output of each DPMulCat block.
              In eval mode, the module only returns output in the last block.
      """
      batch_size, _, d1, d2 = input.shape
      output = input
      output_all = []
      for i in range(len(self.rows_grnn)):
          row_input = (
              output.permute(0, 3, 2, 1)
              .contiguous()
              .view(batch_size * d2, d1, -1)
          )
          row_output = self.rows_grnn[i](row_input)
          row_output = (
              row_output.view(batch_size, d2, d1, -1)
              .permute(0, 3, 2, 1)
              .contiguous()
          )
          row_output = self.rows_normalization[i](row_output)
          # apply a skip connection
          output = output + row_output
          col_input = (
              output.permute(0, 2, 3, 1)
              .contiguous()
              .view(batch_size * d1, d2, -1)
          )
          col_output = self.cols_grnn[i](col_input)
          col_output = (
              col_output.view(batch_size, d1, d2, -1)
              .permute(0, 3, 1, 2)
              .contiguous()
          )
          col_output = self.cols_normalization[i](
              col_output
          ).contiguous()
          # apply a skip connection
          output = output + col_output
  
          # if training mode, it returns the output Tensor from all layers.
          # Otherwise, it only returns the one from the last layer.
          if self.training or i == (len(self.rows_grnn) - 1):
              output_i = self.output(output)
              output_all.append(output_i)
      return output_all
  
file_path: espnet/espnet2/enh/layers/dpmulcat.py
imports: import torch
  import torch.nn
label_desc: Use image node_id 2 for calling the DPMulCat obj's underlying member method code with example usage: obj.forward(input) and returns: output_all