docs: def sg_lstm(tensor, opt):
      r"""Applies an LSTM.
  
      Args:
        tensor: A 3-D `Tensor` (automatically passed by decorator).
        opt:
          in_dim: A positive `integer`. The size of input dimension.
          dim: A positive `integer`. The size of output dimension.
          bias: Boolean. If True, biases are added.
          ln: Boolean. If True, layer normalization is applied.   
          init_state: A 2-D `Tensor`. If None, the initial state is set to zeros.
          last_only: Boolean. If True, the outputs in the last time step are returned.
          mask: Boolean 2-D `Tensor` or None(default).
              For false elements values are excluded from the calculation.
              As a result, the outputs for the locations become 0.
          summary: If True, summaries are added. The default is True.
  
      Returns:
        A `Tensor`. If last_only is True, the output tensor has shape [batch size, dim].
        Otherwise, [batch size, time steps, dim].
      """
      # layer normalization
      # noinspection PyPep8
      ln = lambda v: _ln_rnn(v, gamma, beta) if opt.ln else v
  
      # step func
      def step(hh, cc, x):
          # forget gate
          f = tf.sigmoid(ln(tf.matmul(x, w_f) + tf.matmul(hh, u_f) + (b_f if opt.bias else 0)))
          # input gate
          ii = tf.sigmoid(ln(tf.matmul(x, w_i) + tf.matmul(hh, u_i) + (b_i if opt.bias else 0)))
          # new cell value
          c_new = tf.tanh(ln(tf.matmul(x, w_c) + tf.matmul(hh, u_c) + (b_c if opt.bias else 0)))
          # out gate
          o = tf.sigmoid(ln(tf.matmul(x, w_o) + tf.matmul(hh, u_o) + (b_o if opt.bias else 0)))
          # cell update
          cell = f * cc + ii * c_new
          # final output
          y = o * tf.tanh(cell)
          return y, cell
  
      # parameter initialize
      w_i = tf.sg_initializer.orthogonal('W_i', (opt.in_dim, opt.dim), summary=opt.summary)
      u_i = tf.sg_initializer.identity('U_i', opt.dim, summary=opt.summary)
      w_f = tf.sg_initializer.orthogonal('W_f', (opt.in_dim, opt.dim), summary=opt.summary)
      u_f = tf.sg_initializer.identity('U_f', opt.dim, summary=opt.summary)
      w_o = tf.sg_initializer.orthogonal('W_o', (opt.in_dim, opt.dim), summary=opt.summary)
      u_o = tf.sg_initializer.identity('U_o', opt.dim, summary=opt.summary)
      w_c = tf.sg_initializer.orthogonal('W_c', (opt.in_dim, opt.dim), summary=opt.summary)
      u_c = tf.sg_initializer.identity('U_c', opt.dim, summary=opt.summary)
      if opt.bias:
          b_i = tf.sg_initializer.constant('b_i', opt.dim, summary=opt.summary)
          b_f = tf.sg_initializer.constant('b_f', opt.dim, summary=opt.summary)
          b_o = tf.sg_initializer.constant('b_o', opt.dim, value=1, summary=opt.summary)
          b_c = tf.sg_initializer.constant('b_c', opt.dim, summary=opt.summary)
  
      # layer normalization parameters
      if opt.ln:
          # offset, scale parameter
          beta = tf.sg_initializer.constant('beta', opt.dim, summary=opt.summary)
          gamma = tf.sg_initializer.constant('gamma', opt.dim, value=1, summary=opt.summary)
  
      # initial state
      init_h = opt.init_state if opt.init_state is not None \
          else tf.zeros((tensor.get_shape().as_list()[0], opt.dim), dtype=tf.sg_floatx)
  
      # do rnn loop
      h, c, out = init_h, init_h, []
      for i in range(tensor.get_shape().as_list()[1]):
          # apply step function
          h, c = step(h, c, tensor[:, i, :])
          # save result
          out.append(h.sg_expand_dims(axis=1))
  
      # merge tensor
      out = tf.concat(out, 1)
  
      # apply mask
      if opt.mask is None:
          if opt.last_only:
              return out[:, -1, :]
          else:
              return out
      else:
          # apply mask
          out *= opt.mask.sg_expand_dims(axis=2).sg_float()
  
          if opt.last_only:
              # calc sequence length using given mask
              seq_len = opt.mask.sg_int().sg_sum(axis=1)
              # get last output
              rev = tf.reverse_sequence(out, seq_len, seq_axis=1)
              return rev[:, 0, :]
          else:
              return out