docstr: X should be of shape (n,b,input_size), where n = length of sequence, b = batch size
docstr_tok: ["X","should","be","of","shape","(","n",",","b",",","input_size",")",",","where","n","=","length","of","sequence",",","b","=","batch","size"]
code: def forward(X, WLSTM, c0=None, h0=None):
      """
      X should be of shape (n,b,input_size), where n = length of sequence, b = batch size
      """
      n, b, input_size = X.shape
      d = WLSTM.shape[1] // 4  # hidden size
      if c0 is None:
          c0 = np.zeros((b, d))
      if h0 is None:
          h0 = np.zeros((b, d))
  
      # Perform the LSTM forward pass with X as the input
      xphpb = WLSTM.shape[0]  # x plus h plus bias, lol
      # input [1, xt, ht-1] to each tick of the LSTM
      Hin = np.zeros((n, b, xphpb))
      # hidden representation of the LSTM (gated cell content)
      Hout = np.zeros((n, b, d))
      IFOG = np.zeros(
          (n, b, d * 4)
      )  # input, forget, output, gate (IFOG)
      IFOGf = np.zeros((n, b, d * 4))  # after nonlinearity
      C = np.zeros((n, b, d))  # cell content
      Ct = np.zeros((n, b, d))  # tanh of cell content
      for t in range(n):
          # concat [x,h] as input to the LSTM
          prevh = Hout[t - 1] if t > 0 else h0
          Hin[t, :, 0] = 1  # bias
          Hin[t, :, 1 : input_size + 1] = X[t]
          Hin[t, :, input_size + 1 :] = prevh
          # compute all gate activations. dots: (most work is this line)
  
          IFOG[t] = Hin[t].dot(WLSTM)
          # non-linearities
          # sigmoids; these are the gates
          IFOGf[t, :, : 3 * d] = 1.0 / (
              1.0 + np.exp(-IFOG[t, :, : 3 * d])
          )
          IFOGf[t, :, 3 * d :] = np.tanh(IFOG[t, :, 3 * d :])  # tanh
          # compute the cell activation
          prevc = C[t - 1] if t > 0 else c0
          C[t] = (
              IFOGf[t, :, :d] * IFOGf[t, :, 3 * d :]
              + IFOGf[t, :, d : 2 * d] * prevc
          )
          Ct[t] = np.tanh(C[t])
          Hout[t] = IFOGf[t, :, 2 * d : 3 * d] * Ct[t]
  
      cache = {}
      cache["WLSTM"] = WLSTM
      cache["Hout"] = Hout
      cache["IFOGf"] = IFOGf
      cache["IFOG"] = IFOG
      cache["C"] = C
      cache["Ct"] = Ct
      cache["Hin"] = Hin
      cache["c0"] = c0
      cache["h0"] = h0
  
      # return C[t], as well so we can continue LSTM with prev state init if
      # needed
      return Hout, C[t], Hout[t], cache
  
file_path: neon/tests/lstm_ref.py
imports: from builtins import input
  import numpy
  from neon import logger
  from utils import allclose_with_out
label_desc: Use image node_id 2 for calling the LSTM obj's underlying member method code with example usage: obj.forward(X, WLSTM, c0, h0) and returns: Hout,  C,  Hout,  cache