docstr: Forward.
  
  Args:
      input (torch.Tensor or ComplexTensor): Encoded feature [B, T, F]
      ilens (torch.Tensor): input lengths [Batch]
  
  Returns:
      masked (List[Union(torch.Tensor, ComplexTensor)]): [(B, T, N), ...]
      ilens (torch.Tensor): (B,)
      others predicted data, e.g. V: OrderedDict[
          others predicted data, e.g. masks: OrderedDict[
          'mask_spk1': torch.Tensor(Batch, Frames, Freq),
          'mask_spk2': torch.Tensor(Batch, Frames, Freq),
          ...
          'mask_spkn': torch.Tensor(Batch, Frames, Freq),
      ]
code: def forward(
      self,
      input: Union[torch.Tensor, ComplexTensor],
      ilens: torch.Tensor,
      additional: Optional[Dict] = None,
  ) -> Tuple[
      List[Union[torch.Tensor, ComplexTensor]],
      torch.Tensor,
      OrderedDict,
  ]:
      """Forward.
  
      Args:
          input (torch.Tensor or ComplexTensor): Encoded feature [B, T, F]
          ilens (torch.Tensor): input lengths [Batch]
  
      Returns:
          masked (List[Union(torch.Tensor, ComplexTensor)]): [(B, T, N), ...]
          ilens (torch.Tensor): (B,)
          others predicted data, e.g. V: OrderedDict[
              others predicted data, e.g. masks: OrderedDict[
              'mask_spk1': torch.Tensor(Batch, Frames, Freq),
              'mask_spk2': torch.Tensor(Batch, Frames, Freq),
              ...
              'mask_spkn': torch.Tensor(Batch, Frames, Freq),
          ]
      """
  
      # if complex spectrum,
      if is_complex(input):
          feature = abs(input)
      else:
          feature = input
      B, T, F = input.shape
  
      # 1st Stage
      # x:(B, T, F)
      x, ilens, _ = self.blstm(feature, ilens)
      # x:(B, T, F*D)
      x = self.linear(x)
      # x:(B, T, F*D)
      x = self.nonlinear(x)
      V = x.view(B, -1, self.D)
  
      # Soft KMeans
      centers = V[:, : self.num_outputs, :]
      gamma = torch.zeros(
          B, T * F, self.num_outputs, device=input.device
      )
      count = 0
      while True:
          # Compute weight
          gamma_exp = torch.empty(
              B, T * F, self.num_outputs, device=input.device
          )
          new_centers = torch.empty(
              B, self.num_outputs, self.D, device=input.device
          )
          for i in range(self.num_outputs):
              gamma_exp[:, :, i] = torch.exp(
                  -self.alpha
                  * torch.sum(
                      V - centers[:, i, :].unsqueeze(1) ** 2, dim=2
                  )
              )
          # To avoid grad becomes nan, we add a small constant in denominator
          gamma = gamma_exp / (
              torch.sum(gamma_exp, dim=2, keepdim=True) + 1.0e-8
          )
          # Update centers
          for i in range(self.num_outputs):
              new_centers[:, i, :] = torch.sum(
                  V * gamma[:, :, i].unsqueeze(2), dim=1
              ) / (
                  torch.sum(gamma[:, :, i].unsqueeze(2), dim=1) + 1.0e-8
              )
  
          if (
              torch.pow(new_centers - centers, 2).sum() < self.threshold
              or count > self.max_iteration
          ):
              break
  
          count += 1
          centers = new_centers
  
      masks = (
          gamma.contiguous()
          .view(B, T, F, self.num_outputs)
          .unbind(dim=3)
      )
      masked = [feature * m for m in masks]
      masked.append(feature)
  
      # 2nd Stage
      # cat_source:(B, T, (spks+1)*F)
      cat_source = torch.cat(masked, dim=2)
      # cat_x:(B, T, spks*F)
      cat_x, ilens, _ = self.enh_blstm(cat_source, ilens)
      # z:(B, T, spks*F)
      z = self.enh_linear(cat_x)
      z = z.contiguous().view(B, T, F, self.num_outputs)
  
      enh_masks = torch.softmax(z, dim=3).unbind(dim=3)
      if self.predict_noise:
          *enh_masks, mask_noise = enh_masks
      enh_masked = [input * m for m in enh_masks]
  
      others = OrderedDict(
          zip(
              [
                  "mask_spk{}".format(i + 1)
                  for i in range(len(enh_masks))
              ],
              enh_masks,
          )
      )
      if self.predict_noise:
          others["noise1"] = input * mask_noise
  
      return enh_masked, ilens, others
  
file_path: espnet/espnet2/enh/separator/dpcl_e2e_separator.py
imports: from collections import OrderedDict
  from typing import Dict, List, Optional, Tuple, Union
  import torch
  from torch_complex.tensor import ComplexTensor
  from espnet2.enh.layers.complex_utils import is_complex
  from espnet2.enh.separator.abs_separator import AbsSeparator
  from espnet.nets.pytorch_backend.rnn.encoders import RNN
label_desc: Use image node_id 2 for calling the DPCLE2ESeparator obj's underlying member method code with example usage: obj.forward(input, ilens, additional) and returns: enh_masked,  ilens,  others