class_docstr: This function implements a quaternion-valued LSTM as first introduced
  in : "Quaternion Recurrent Neural Networks", Parcollet T. et al.
  
  Input format is (batch, time, fea) or (batch, time, fea, channel).
  In the latter shape, the two last dimensions will be merged:
  (batch, time, fea * channel)
  
  Arguments
  ---------
  hidden_size : int
      Number of output neurons (i.e, the dimensionality of the output).
      Specified value is in terms of quaternion-valued neurons. Thus, the output
      is 4*hidden_size.
  num_layers : int, optional
      Number of layers to employ in the RNN architecture (default 1).
  bias : bool, optional
      If True, the additive bias b is adopted (default True).
  dropout : float, optional
      It is the dropout factor (must be between 0 and 1) (default 0.0).
  bidirectional : bool, optional
      If True, a bidirectional model that scans the sequence both
      right-to-left and left-to-right is used (default False).
  init_criterion : str , optional
      (glorot, he).
      This parameter controls the initialization criterion of the weights.
      It is combined with weights_init to build the initialization method of
      the quaternion-valued weights (default "glorot").
  weight_init : str, optional
      (quaternion, unitary).
      This parameter defines the initialization procedure of the
      quaternion-valued weights. "quaternion" will generate random quaternion
      weights following the init_criterion and the quaternion polar form.
      "unitary" will normalize the weights to lie on the unit circle (default "quaternion").
      More details in: "Quaternion Recurrent Neural Networks",
      Parcollet T. et al.
  autograd : bool, optional
      When True, the default PyTorch autograd will be used. When False, a
      custom backpropagation will be used, reducing by a factor 3 to 4 the
      memory consumption. It is also 2x slower (default True).
  
  
  Example
  -------
  >>> inp_tensor = torch.rand([10, 16, 40])
  >>> rnn = QLSTM(hidden_size=16, input_shape=inp_tensor.shape)
  >>> out_tensor = rnn(inp_tensor)
  >>>
  torch.Size([10, 16, 64])
class_docstr_tok: ["This","function","implements","a","quaternion-valued","LSTM","as","first","introduced","in",":","``","Quaternion","Recurrent","Neural","Networks","''",",","Parcollet","T.","et","al",".","Input","format","is","(","batch",",","time",",","fea",")","or","(","batch",",","time",",","fea",",","channel",")",".","In","the","latter","shape",",","the","two","last","dimensions","will","be","merged",":","(","batch",",","time",",","fea","*","channel",")","Arguments","--","--","--","--","-","hidden_size",":","int","Number","of","output","neurons","(","i.e",",","the","dimensionality","of","the","output",")",".","Specified","value","is","in","terms","of","quaternion-valued","neurons",".","Thus",",","the","output","is","4","*","hidden_size",".","num_layers",":","int",",","optional","Number","of","layers","to","employ","in","the","RNN","architecture","(","default","1",")",".","bias",":","bool",",","optional","If","True",",","the","additive","bias","b","is","adopted","(","default","True",")",".","dropout",":","float",",","optional","It","is","the","dropout","factor","(","must","be","between","0","and","1",")","(","default","0.0",")",".","bidirectional",":","bool",",","optional","If","True",",","a","bidirectional","model","that","scans","the","sequence","both","right-to-left","and","left-to-right","is","used","(","default","False",")",".","init_criterion",":","str",",","optional","(","glorot",",","he",")",".","This","parameter","controls","the","initialization","criterion","of","the","weights",".","It","is","combined","with","weights_init","to","build","the","initialization","method","of","the","quaternion-valued","weights","(","default","``","glorot","''",")",".","weight_init",":","str",",","optional","(","quaternion",",","unitary",")",".","This","parameter","defines","the","initialization","procedure","of","the","quaternion-valued","weights",".","``","quaternion","''","will","generate","random","quaternion","weights","following","the","init_criterion","and","the","quaternion","polar","form",".","``","unitary","''","will","normalize","the","weights","to","lie","on","the","unit","circle","(","default","``","quaternion","''",")",".","More","details","in",":","``","Quaternion","Recurrent","Neural","Networks","''",",","Parcollet","T.","et","al",".","autograd",":","bool",",","optional","When","True",",","the","default","PyTorch","autograd","will","be","used",".","When","False",",","a","custom","backpropagation","will","be","used",",","reducing","by","a","factor","3","to","4","the","memory","consumption",".","It","is","also","2x","slower","(","default","True",")",".","Example","--","--","--","-",">",">",">","inp_tensor","=","torch.rand","(","[","10",",","16",",","40","]",")",">",">",">","rnn","=","QLSTM","(","hidden_size=16",",","input_shape=inp_tensor.shape",")",">",">",">","out_tensor","=","rnn","(","inp_tensor",")",">",">",">","torch.Size","(","[","10",",","16",",","64","]",")"]
docstr: Returns the output of the vanilla QuaternionRNN.
  
  Arguments
  ---------
  x : torch.Tensor
      Input tensor.
docstr_tok: ["Returns","the","output","of","the","vanilla","QuaternionRNN",".","Arguments","--","--","--","--","-","x",":","torch.Tensor","Input","tensor","."]
code: def _forward_rnn(self, x, hx: Optional[Tensor]):
      """Returns the output of the vanilla QuaternionRNN.
  
      Arguments
      ---------
      x : torch.Tensor
          Input tensor.
      """
  
      h = []
      if hx is not None:
          if self.bidirectional:
              hx = hx.reshape(
                  self.num_layers, self.batch_size * 2, self.hidden_size
              )
  
      # Processing the different layers
      for i, rnn_lay in enumerate(self.rnn):
          if hx is not None:
              x = rnn_lay(x, hx=hx[i])
          else:
              x = rnn_lay(x, hx=None)
          h.append(x[:, -1, :])
      h = torch.stack(h, dim=1)
  
      if self.bidirectional:
          h = h.reshape(h.shape[1] * 2, h.shape[0], self.hidden_size)
      else:
          h = h.transpose(0, 1)
  
      return x, h
  
imports: import torch
  import logging
  from speechbrain.nnet.quaternion_networks.q_linear import QLinear
  from speechbrain.nnet.quaternion_networks.q_normalization import QBatchNorm
  from torch import Tensor
  from typing import Optional
label_desc: Use image node_id 4 for calling the QLSTM obj's underlying member method code with example usage: obj._forward_rnn(x, hx) and returns: x,  h