class_docstr: CTC module
  
  :param int odim: dimension of outputs
  :param int eprojs: number of encoder projection units
  :param float dropout_rate: dropout rate (0.0 ~ 1.0)
  :param str ctc_type: builtin
  :param bool reduce: reduce the CTC loss into a scalar
docstr: CTC forward
  
  :param torch.Tensor hs_pad: batch of padded hidden state sequences (B, Tmax, D)
  :param torch.Tensor hlens: batch of lengths of hidden state sequences (B)
  :param torch.Tensor ys_pad:
      batch of padded character id sequence tensor (B, Lmax)
  :return: ctc loss value
  :rtype: torch.Tensor
docstr_tok: ["CTC","forward",":","param","torch.Tensor","hs_pad",":","batch","of","padded","hidden","state","sequences","(","B",",","Tmax",",","D",")",":","param","torch.Tensor","hlens",":","batch","of","lengths","of","hidden","state","sequences","(","B",")",":","param","torch.Tensor","ys_pad",":","batch","of","padded","character","id","sequence","tensor","(","B",",","Lmax",")",":","return",":","ctc","loss","value",":","rtype",":","torch.Tensor"]
code: def forward(self, hs_pad, hlens, ys_pad):
      """CTC forward
  
      :param torch.Tensor hs_pad: batch of padded hidden state sequences (B, Tmax, D)
      :param torch.Tensor hlens: batch of lengths of hidden state sequences (B)
      :param torch.Tensor ys_pad:
          batch of padded character id sequence tensor (B, Lmax)
      :return: ctc loss value
      :rtype: torch.Tensor
      """
      # TODO(kan-bayashi): need to make more smart way
      ys = [y[y != self.ignore_id] for y in ys_pad]  # parse padded ys
  
      # zero padding for hs
      ys_hat = self.ctc_lo(self.dropout(hs_pad))
      if self.ctc_type != "gtnctc":
          ys_hat = ys_hat.transpose(0, 1)
  
      if self.ctc_type == "builtin":
          olens = to_device(
              ys_hat, torch.LongTensor([len(s) for s in ys])
          )
          hlens = hlens.long()
          ys_pad = torch.cat(
              ys
          )  # without this the code breaks for asr_mix
          self.loss = self.loss_fn(ys_hat, ys_pad, hlens, olens)
      else:
          self.loss = None
          hlens = torch.from_numpy(np.fromiter(hlens, dtype=np.int32))
          olens = torch.from_numpy(
              np.fromiter((x.size(0) for x in ys), dtype=np.int32)
          )
          # zero padding for ys
          ys_true = torch.cat(ys).cpu().int()  # batch x olen
          # get ctc loss
          # expected shape of seqLength x batchSize x alphabet_size
          dtype = ys_hat.dtype
          if self.ctc_type == "cudnnctc":
              # use GPU when using the cuDNN implementation
              ys_true = to_device(hs_pad, ys_true)
          if self.ctc_type == "gtnctc":
              # keep as list for gtn
              ys_true = ys
          self.loss = to_device(
              hs_pad, self.loss_fn(ys_hat, ys_true, hlens, olens)
          ).to(dtype=dtype)
  
      # get length info
      logging.info(
          self.__class__.__name__
          + " input lengths:  "
          + "".join(str(hlens).split("\n"))
      )
      logging.info(
          self.__class__.__name__
          + " output lengths: "
          + "".join(str(olens).split("\n"))
      )
  
      if self.reduce:
          self.loss = self.loss.sum()
          logging.info("ctc loss:" + str(float(self.loss)))
  
      return self.loss
  
file_path: espnet/espnet/nets/pytorch_backend/ctc.py
imports: import logging
  import numpy
  import torch
  import torch.nn.functional
  from packaging.version import parse
  from espnet.nets.pytorch_backend.nets_utils import to_device
label_desc: Use image node_id 3 for calling the CTC obj's underlying member method code with example usage: obj.forward(hs_pad, hlens, ys_pad) and returns: self