class_docstr: This function implements a quaternion-valued Light GRU (liGRU).
  
  Ligru is single-gate GRU model based on batch-norm + relu
  activations + recurrent dropout. For more info see:
  
  "M. Ravanelli, P. Brakel, M. Omologo, Y. Bengio,
  Light Gated Recurrent Units for Speech Recognition,
  in IEEE Transactions on Emerging Topics in Computational Intelligence,
  2018" (https://arxiv.org/abs/1803.10225)
  
  To speed it up, it is compiled with the torch just-in-time compiler (jit)
  right before using it.
  
  It accepts in input tensors formatted as (batch, time, fea).
  In the case of 4d inputs like (batch, time, fea, channel) the tensor is
  flattened as (batch, time, fea*channel).
  
  Arguments
  ---------
  hidden_size : int
      Number of output neurons (i.e, the dimensionality of the output).
      Specified value is in term of quaternion-valued neurons. Thus, the output
      is 2*hidden_size.
  nonlinearity : str
      Type of nonlinearity (tanh, relu).
  normalization : str
      Type of normalization for the ligru model (batchnorm, layernorm).
      Every string different from batchnorm and layernorm will result
      in no normalization.
  num_layers : int
      Number of layers to employ in the RNN architecture.
  bias : bool
      If True, the additive bias b is adopted.
  dropout: float
      It is the dropout factor (must be between 0 and 1).
  bidirectional : bool
      If True, a bidirectional model that scans the sequence both
      right-to-left and left-to-right is used.
  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-valued
      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: "Deep quaternion Networks", Trabelsi C. 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 = QLiGRU(input_shape=inp_tensor.shape, hidden_size=16)
  >>> out_tensor = rnn(inp_tensor)
  >>>
  torch.Size([4, 10, 5])
class_docstr_tok: ["This","function","implements","a","quaternion-valued","Light","GRU","(","liGRU",")",".","Ligru","is","single-gate","GRU","model","based","on","batch-norm","+","relu","activations","+","recurrent","dropout",".","For","more","info","see",":","''","M.","Ravanelli",",","P.","Brakel",",","M.","Omologo",",","Y.","Bengio",",","Light","Gated","Recurrent","Units","for","Speech","Recognition",",","in","IEEE","Transactions","on","Emerging","Topics","in","Computational","Intelligence",",","2018","''","(","https",":","\/\/arxiv.org\/abs\/1803.10225",")","To","speed","it","up",",","it","is","compiled","with","the","torch","just-in-time","compiler","(","jit",")","right","before","using","it",".","It","accepts","in","input","tensors","formatted","as","(","batch",",","time",",","fea",")",".","In","the","case","of","4d","inputs","like","(","batch",",","time",",","fea",",","channel",")","the","tensor","is","flattened","as","(","batch",",","time",",","fea","*","channel",")",".","Arguments","--","--","--","--","-","hidden_size",":","int","Number","of","output","neurons","(","i.e",",","the","dimensionality","of","the","output",")",".","Specified","value","is","in","term","of","quaternion-valued","neurons",".","Thus",",","the","output","is","2","*","hidden_size",".","nonlinearity",":","str","Type","of","nonlinearity","(","tanh",",","relu",")",".","normalization",":","str","Type","of","normalization","for","the","ligru","model","(","batchnorm",",","layernorm",")",".","Every","string","different","from","batchnorm","and","layernorm","will","result","in","no","normalization",".","num_layers",":","int","Number","of","layers","to","employ","in","the","RNN","architecture",".","bias",":","bool","If","True",",","the","additive","bias","b","is","adopted",".","dropout",":","float","It","is","the","dropout","factor","(","must","be","between","0","and","1",")",".","bidirectional",":","bool","If","True",",","a","bidirectional","model","that","scans","the","sequence","both","right-to-left","and","left-to-right","is","used",".","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-valued","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",":","``","Deep","quaternion","Networks","''",",","Trabelsi","C.","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","=","QLiGRU","(","input_shape=inp_tensor.shape",",","hidden_size=16",")",">",">",">","out_tensor","=","rnn","(","inp_tensor",")",">",">",">","torch.Size","(","[","4",",","10",",","5","]",")"]
docstr: Returns the output of the quaternionliGRU.
  
  Arguments
  ---------
  x : torch.Tensor
      Input tensor.
docstr_tok: ["Returns","the","output","of","the","quaternionliGRU",".","Arguments","--","--","--","--","-","x",":","torch.Tensor","Input","tensor","."]
code: def _forward_ligru(self, x, hx: Optional[Tensor]):
      """Returns the output of the quaternionliGRU.
  
      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, ligru_lay in enumerate(self.rnn):
          if hx is not None:
              x = ligru_lay(x, hx=hx[i])
          else:
              x = ligru_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 QLiGRU obj's underlying member method code with example usage: obj._forward_ligru(x, hx) and returns: x,  h