class_docstr: RNN with projection layer module
  
  :param int idim: dimension of inputs
  :param int elayers: number of encoder layers
  :param int cdim: number of rnn units (resulted in cdim * 2 if bidirectional)
  :param int hdim: number of projection units
  :param np.ndarray subsample: list of subsampling numbers
  :param float dropout: dropout rate
  :param str typ: The RNN type
docstr: RNNP forward
  
  :param torch.Tensor xs_pad: batch of padded input sequences (B, Tmax, idim)
  :param torch.Tensor ilens: batch of lengths of input sequences (B)
  :param torch.Tensor prev_state: batch of previous RNN states
  :return: batch of hidden state sequences (B, Tmax, hdim)
  :rtype: torch.Tensor
docstr_tok: ["RNNP","forward",":","param","torch.Tensor","xs_pad",":","batch","of","padded","input","sequences","(","B",",","Tmax",",","idim",")",":","param","torch.Tensor","ilens",":","batch","of","lengths","of","input","sequences","(","B",")",":","param","torch.Tensor","prev_state",":","batch","of","previous","RNN","states",":","return",":","batch","of","hidden","state","sequences","(","B",",","Tmax",",","hdim",")",":","rtype",":","torch.Tensor"]
code: def forward(self, xs_pad, ilens, prev_state=None):
      """RNNP forward
  
      :param torch.Tensor xs_pad: batch of padded input sequences (B, Tmax, idim)
      :param torch.Tensor ilens: batch of lengths of input sequences (B)
      :param torch.Tensor prev_state: batch of previous RNN states
      :return: batch of hidden state sequences (B, Tmax, hdim)
      :rtype: torch.Tensor
      """
      logging.debug(
          self.__class__.__name__ + " input lengths: " + str(ilens)
      )
      elayer_states = []
      for layer in range(self.elayers):
          if not isinstance(ilens, torch.Tensor):
              ilens = torch.tensor(ilens)
          xs_pack = pack_padded_sequence(
              xs_pad, ilens.cpu(), batch_first=True
          )
          rnn = getattr(
              self, ("birnn" if self.bidir else "rnn") + str(layer)
          )
          if self.training:
              rnn.flatten_parameters()
          if prev_state is not None and rnn.bidirectional:
              prev_state = reset_backward_rnn_state(prev_state)
          ys, states = rnn(
              xs_pack,
              hx=None if prev_state is None else prev_state[layer],
          )
          elayer_states.append(states)
          # ys: utt list of frame x cdim x 2 (2: means bidirectional)
          ys_pad, ilens = pad_packed_sequence(ys, batch_first=True)
          sub = self.subsample[layer + 1]
          if sub > 1:
              ys_pad = ys_pad[:, ::sub]
              ilens = torch.tensor([int(i + 1) // sub for i in ilens])
          # (sum _utt frame_utt) x dim
          projection_layer = getattr(self, "bt%d" % layer)
          projected = projection_layer(
              ys_pad.contiguous().view(-1, ys_pad.size(2))
          )
          xs_pad = projected.view(ys_pad.size(0), ys_pad.size(1), -1)
          if layer < self.elayers - 1:
              xs_pad = torch.tanh(F.dropout(xs_pad, p=self.dropout))
  
      return xs_pad, ilens, elayer_states
  
imports: import logging
  import numpy
  import torch
  import torch.nn.functional
  from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence
  from espnet.nets.e2e_asr_common import get_vgg2l_odim
  from espnet.nets.pytorch_backend.nets_utils import make_pad_mask, to_device
label_desc: Use image node_id 2 for calling the RNNP obj's underlying member method code with example usage: obj.forward(xs_pad, ilens, prev_state) and returns: xs_pad,  ilens,  elayer_states