class_docstr: Decoder module
  
  :param int eprojs: encoder projection units
  :param int odim: dimension of outputs
  :param str dtype: gru or lstm
  :param int dlayers: decoder layers
  :param int dunits: decoder units
  :param int sos: start of sequence symbol id
  :param int eos: end of sequence symbol id
  :param torch.nn.Module att: attention module
  :param int verbose: verbose level
  :param list char_list: list of character strings
  :param ndarray labeldist: distribution of label smoothing
  :param float lsm_weight: label smoothing weight
  :param float sampling_probability: scheduled sampling probability
  :param float dropout: dropout rate
  :param float context_residual: if True, use context vector for token generation
  :param float replace_sos: use for multilingual (speech/text) translation
class_docstr_tok: ["Decoder","module",":","param","int","eprojs",":","encoder","projection","units",":","param","int","odim",":","dimension","of","outputs",":","param","str","dtype",":","gru","or","lstm",":","param","int","dlayers",":","decoder","layers",":","param","int","dunits",":","decoder","units",":","param","int","sos",":","start","of","sequence","symbol","id",":","param","int","eos",":","end","of","sequence","symbol","id",":","param","torch.nn.Module","att",":","attention","module",":","param","int","verbose",":","verbose","level",":","param","list","char_list",":","list","of","character","strings",":","param","ndarray","labeldist",":","distribution","of","label","smoothing",":","param","float","lsm_weight",":","label","smoothing","weight",":","param","float","sampling_probability",":","scheduled","sampling","probability",":","param","float","dropout",":","dropout","rate",":","param","float","context_residual",":","if","True",",","use","context","vector","for","token","generation",":","param","float","replace_sos",":","use","for","multilingual","(","speech\/text",")","translation"]
docstr: Decoder forward
  
  :param torch.Tensor hs_pad: batch of padded hidden state sequences (B, Tmax, D)
                              [in multi-encoder case,
                              list of torch.Tensor,
                              [(B, Tmax_1, D), (B, Tmax_2, D), ..., ] ]
  :param torch.Tensor hlens: batch of lengths of hidden state sequences (B)
                             [in multi-encoder case, list of torch.Tensor,
                             [(B), (B), ..., ]
  :param torch.Tensor ys_pad: batch of padded character id sequence tensor
                              (B, Lmax)
  :param int strm_idx: stream index indicates the index of decoding stream.
  :param torch.Tensor lang_ids: batch of target language id tensor (B, 1)
  :return: attention loss value
  :rtype: torch.Tensor
  :return: accuracy
  :rtype: float
docstr_tok: ["Decoder","forward",":","param","torch.Tensor","hs_pad",":","batch","of","padded","hidden","state","sequences","(","B",",","Tmax",",","D",")","[","in","multi-encoder","case",",","list","of","torch.Tensor",",","[","(","B",",","Tmax_1",",","D",")",",","(","B",",","Tmax_2",",","D",")",",","...",",","]","]",":","param","torch.Tensor","hlens",":","batch","of","lengths","of","hidden","state","sequences","(","B",")","[","in","multi-encoder","case",",","list","of","torch.Tensor",",","[","(","B",")",",","(","B",")",",","...",",","]",":","param","torch.Tensor","ys_pad",":","batch","of","padded","character","id","sequence","tensor","(","B",",","Lmax",")",":","param","int","strm_idx",":","stream","index","indicates","the","index","of","decoding","stream",".",":","param","torch.Tensor","lang_ids",":","batch","of","target","language","id","tensor","(","B",",","1",")",":","return",":","attention","loss","value",":","rtype",":","torch.Tensor",":","return",":","accuracy",":","rtype",":","float"]
code: def forward(self, hs_pad, hlens, ys_pad, strm_idx=0, lang_ids=None):
      """Decoder forward
  
      :param torch.Tensor hs_pad: batch of padded hidden state sequences (B, Tmax, D)
                                  [in multi-encoder case,
                                  list of torch.Tensor,
                                  [(B, Tmax_1, D), (B, Tmax_2, D), ..., ] ]
      :param torch.Tensor hlens: batch of lengths of hidden state sequences (B)
                                 [in multi-encoder case, list of torch.Tensor,
                                 [(B), (B), ..., ]
      :param torch.Tensor ys_pad: batch of padded character id sequence tensor
                                  (B, Lmax)
      :param int strm_idx: stream index indicates the index of decoding stream.
      :param torch.Tensor lang_ids: batch of target language id tensor (B, 1)
      :return: attention loss value
      :rtype: torch.Tensor
      :return: accuracy
      :rtype: float
      """
      # to support mutiple encoder asr mode, in single encoder mode,
      # convert torch.Tensor to List of torch.Tensor
      if self.num_encs == 1:
          hs_pad = [hs_pad]
          hlens = [hlens]
  
      # TODO(kan-bayashi): need to make more smart way
      ys = [y[y != self.ignore_id] for y in ys_pad]  # parse padded ys
      # attention index for the attention module
      # in SPA (speaker parallel attention),
      # att_idx is used to select attention module. In other cases, it is 0.
      att_idx = min(strm_idx, len(self.att) - 1)
  
      # hlens should be list of list of integer
      hlens = [
          list(map(int, hlens[idx])) for idx in range(self.num_encs)
      ]
  
      self.loss = None
      # prepare input and output word sequences with sos/eos IDs
      eos = ys[0].new([self.eos])
      sos = ys[0].new([self.sos])
      if self.replace_sos:
          ys_in = [
              torch.cat([idx, y], dim=0) for idx, y in zip(lang_ids, ys)
          ]
      else:
          ys_in = [torch.cat([sos, y], dim=0) for y in ys]
      ys_out = [torch.cat([y, eos], dim=0) for y in ys]
  
      # padding for ys with -1
      # pys: utt x olen
      ys_in_pad = pad_list(ys_in, self.eos)
      ys_out_pad = pad_list(ys_out, self.ignore_id)
  
      # get dim, length info
      batch = ys_out_pad.size(0)
      olength = ys_out_pad.size(1)
      for idx in range(self.num_encs):
          logging.info(
              self.__class__.__name__
              + "Number of Encoder:{}; enc{}: input lengths: {}.".format(
                  self.num_encs, idx + 1, hlens[idx]
              )
          )
      logging.info(
          self.__class__.__name__
          + " output lengths: "
          + str([y.size(0) for y in ys_out])
      )
  
      # initialization
      c_list = [self.zero_state(hs_pad[0])]
      z_list = [self.zero_state(hs_pad[0])]
      for _ in range(1, self.dlayers):
          c_list.append(self.zero_state(hs_pad[0]))
          z_list.append(self.zero_state(hs_pad[0]))
      z_all = []
      if self.num_encs == 1:
          att_w = None
          self.att[att_idx].reset()  # reset pre-computation of h
      else:
          att_w_list = [None] * (self.num_encs + 1)  # atts + han
          att_c_list = [None] * (self.num_encs)  # atts
          for idx in range(self.num_encs + 1):
              self.att[
                  idx
              ].reset()  # reset pre-computation of h in atts and han
  
      # pre-computation of embedding
      eys = self.dropout_emb(self.embed(ys_in_pad))  # utt x olen x zdim
  
      # loop for an output sequence
      for i in range(olength):
          if self.num_encs == 1:
              att_c, att_w = self.att[att_idx](
                  hs_pad[0],
                  hlens[0],
                  self.dropout_dec[0](z_list[0]),
                  att_w,
              )
          else:
              for idx in range(self.num_encs):
                  att_c_list[idx], att_w_list[idx] = self.att[idx](
                      hs_pad[idx],
                      hlens[idx],
                      self.dropout_dec[0](z_list[0]),
                      att_w_list[idx],
                  )
              hs_pad_han = torch.stack(att_c_list, dim=1)
              hlens_han = [self.num_encs] * len(ys_in)
              att_c, att_w_list[self.num_encs] = self.att[
                  self.num_encs
              ](
                  hs_pad_han,
                  hlens_han,
                  self.dropout_dec[0](z_list[0]),
                  att_w_list[self.num_encs],
              )
          if i > 0 and random.random() < self.sampling_probability:
              logging.info(" scheduled sampling ")
              z_out = self.output(z_all[-1])
              z_out = np.argmax(z_out.detach().cpu(), axis=1)
              z_out = self.dropout_emb(
                  self.embed(to_device(hs_pad[0], z_out))
              )
              ey = torch.cat(
                  (z_out, att_c), dim=1
              )  # utt x (zdim + hdim)
          else:
              ey = torch.cat(
                  (eys[:, i, :], att_c), dim=1
              )  # utt x (zdim + hdim)
          z_list, c_list = self.rnn_forward(
              ey, z_list, c_list, z_list, c_list
          )
          if self.context_residual:
              z_all.append(
                  torch.cat(
                      (self.dropout_dec[-1](z_list[-1]), att_c), dim=-1
                  )
              )  # utt x (zdim + hdim)
          else:
              z_all.append(
                  self.dropout_dec[-1](z_list[-1])
              )  # utt x (zdim)
  
      z_all = torch.stack(z_all, dim=1).view(batch * olength, -1)
      # compute loss
      y_all = self.output(z_all)
      self.loss = F.cross_entropy(
          y_all,
          ys_out_pad.view(-1),
          ignore_index=self.ignore_id,
          reduction="mean",
      )
      # compute perplexity
      ppl = math.exp(self.loss.item())
      # -1: eos, which is removed in the loss computation
      self.loss *= np.mean([len(x) for x in ys_in]) - 1
      acc = th_accuracy(y_all, ys_out_pad, ignore_label=self.ignore_id)
      logging.info(
          "att loss:" + "".join(str(self.loss.item()).split("\n"))
      )
  
      # show predicted character sequence for debug
      if self.verbose > 0 and self.char_list is not None:
          ys_hat = y_all.view(batch, olength, -1)
          ys_true = ys_out_pad
          for (i, y_hat), y_true in zip(
              enumerate(ys_hat.detach().cpu().numpy()),
              ys_true.detach().cpu().numpy(),
          ):
              if i == MAX_DECODER_OUTPUT:
                  break
              idx_hat = np.argmax(
                  y_hat[y_true != self.ignore_id], axis=1
              )
              idx_true = y_true[y_true != self.ignore_id]
              seq_hat = [self.char_list[int(idx)] for idx in idx_hat]
              seq_true = [self.char_list[int(idx)] for idx in idx_true]
              seq_hat = "".join(seq_hat)
              seq_true = "".join(seq_true)
              logging.info("groundtruth[%d]: " % i + seq_true)
              logging.info("prediction [%d]: " % i + seq_hat)
  
      if self.labeldist is not None:
          if self.vlabeldist is None:
              self.vlabeldist = to_device(
                  hs_pad[0], torch.from_numpy(self.labeldist)
              )
          loss_reg = -torch.sum(
              (F.log_softmax(y_all, dim=1) * self.vlabeldist).view(-1),
              dim=0,
          ) / len(ys_in)
          self.loss = (
              1.0 - self.lsm_weight
          ) * self.loss + self.lsm_weight * loss_reg
  
      return self.loss, acc, ppl
  
imports: import logging
  import math
  import random
  from argparse import Namespace
  import numpy
  import torch
  import torch.nn.functional
  from espnet.nets.ctc_prefix_score import CTCPrefixScore, CTCPrefixScoreTH
  from espnet.nets.e2e_asr_common import end_detect
  from espnet.nets.pytorch_backend.nets_utils import mask_by_length, pad_list, th_accuracy, to_device
  from espnet.nets.pytorch_backend.rnn.attentions import att_to_numpy
  from espnet.nets.scorer_interface import ScorerInterface
label_desc: Use image node_id 4 for calling the Decoder obj's underlying member method code with example usage: obj.forward(hs_pad, hlens, ys_pad, strm_idx, lang_ids) and returns: self,  acc,  ppl