class_docstr: Speech enhancement or separation Frontend model
code: def forward_enhance(
      self,
      speech_mix: torch.Tensor,
      speech_lengths: torch.Tensor,
      additional: Optional[Dict] = None,
      fs: Optional[int] = None,
  ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
      feature_mix, flens = self.encoder(
          speech_mix, speech_lengths, fs=fs
      )
      if self.mask_module is None:
          feature_pre, flens, others = self.separator(
              feature_mix, flens, additional
          )
      else:
          # Obtain bottleneck_feats from separator.
          # This is used for the input of diarization module in "enh + diar" task
          bottleneck_feats, bottleneck_feats_lengths = self.separator(
              feature_mix, flens
          )
          if additional.get("num_spk") is not None:
              feature_pre, flens, others = self.mask_module(
                  feature_mix,
                  flens,
                  bottleneck_feats,
                  additional["num_spk"],
              )
              others["bottleneck_feats"] = bottleneck_feats
              others[
                  "bottleneck_feats_lengths"
              ] = bottleneck_feats_lengths
          else:
              feature_pre = None
              others = {
                  "bottleneck_feats": bottleneck_feats,
                  "bottleneck_feats_lengths": bottleneck_feats_lengths,
              }
      if feature_pre is not None:
          # for models like SVoice that output multiple lists of separated signals
          pre_is_multi_list = isinstance(feature_pre[0], (list, tuple))
          if pre_is_multi_list:
              speech_pre = [
                  [
                      self.decoder(p, speech_lengths, fs=fs)[0]
                      for p in ps
                  ]
                  for ps in feature_pre
              ]
          else:
              speech_pre = [
                  self.decoder(ps, speech_lengths, fs=fs)[0]
                  for ps in feature_pre
              ]
      else:
          # some models (e.g. neural beamformer trained with mask loss)
          # do not predict time-domain signal in the training stage
          speech_pre = None
      return speech_pre, feature_mix, feature_pre, others
  
imports: import contextlib
  from typing import Dict, List, Optional, OrderedDict, Tuple
  import numpy
  import torch
  from packaging.version import parse
  from typeguard import check_argument_types
  from espnet2.diar.layers.abs_mask import AbsMask
  from espnet2.enh.decoder.abs_decoder import AbsDecoder
  from espnet2.enh.encoder.abs_encoder import AbsEncoder
  from espnet2.enh.loss.criterions.tf_domain import FrequencyDomainLoss
  from espnet2.enh.loss.criterions.time_domain import TimeDomainLoss
  from espnet2.enh.loss.wrappers.abs_wrapper import AbsLossWrapper
  from espnet2.enh.separator.abs_separator import AbsSeparator
  from espnet2.enh.separator.dan_separator import DANSeparator
  from espnet2.enh.separator.uses_separator import USESSeparator
  from espnet2.torch_utils.device_funcs import force_gatherable
  from espnet2.train.abs_espnet_model import AbsESPnetModel
label_desc: Use image node_id 3 for calling the ESPnetEnhancementModel obj's underlying member method code with example usage: obj.forward_enhance(speech_mix, speech_lengths, additional, fs) and returns: speech_pre,  feature_mix,  feature_pre,  others