constructor(attrs = {}) {
    super(attrs)
    this.layerClass = 'LSTM'

    const {
      units = 1,
      activation = 'tanh',
      use_bias = true,
      recurrent_activation = 'hard_sigmoid',
      return_sequences = false,
      go_backwards = false,
      stateful = false
    } = attrs

    this.units = units

    // keep this.activation and this.recurrentActivation for Bidirectional wrapper layer to use
    this.activation = activation
    this.recurrentActivation = recurrent_activation
    this.activationFunc = activations[activation]
    this.recurrentActivationFunc = activations[recurrent_activation]

    this.use_bias = use_bias

    this.returnSequences = return_sequences
    this.goBackwards = go_backwards
    this.stateful = stateful

    // Layer weights specification
    this.params = this.use_bias ? ['kernel', 'recurrent_kernel', 'bias'] : ['kernel', 'recurrent_kernel']

    this.description = `output dimensions: ${this.units}`
    this.description += this.activation !== 'linear' ? `, ${this.activation} activation` : ''
    this.description +=
      this.recurrentActivation !== 'linear' ? `, ${this.recurrentActivation} recurrent activation` : ''
    this.description += this.returnSequences ? `, return sequences` : ''
    this.description += this.goBackwards ? `, backward direction` : ''
    this.description += this.stateful ? `, stateful` : ''

    // GPU setup
    if (this.gpu) {
      this.copyTextureProgram = webgl2.compileProgram(copyTextureProgramSource)
      this.matMulProgram = webgl2.compileProgram(matMulProgramSource)
      this.activationProgram = webgl2.compileProgram(activationProgramSources[this.activation])
      this.recurrentActivationProgram = webgl2.compileProgram(activationProgramSources[this.recurrentActivation])
      this.gateSummationProgram = webgl2.compileProgram(gateSummationProgramSource)
      this.gateProductProgram = webgl2.compileProgram(gateProductProgramSource)
      this.timestepReadProgram = webgl2.compileProgram(timestepReadProgramSource)
      this.timestepWriteProgram = webgl2.compileProgram(timestepWriteProgramSource)
      this.updateProgram = webgl2.compileProgram(updateProgramSource)
    }
  }
Creates a LSTM layer

@param {Object} [attrs] - layer attributes
@param {number} [attrs.units] - output dimensionality
@param {number} [attrs.activation] - activation function
@param {number} [attrs.recurrent_activation] - inner activation function
@param {number} [attrs.use_bias] - use bias
@param {number} [attrs.return_sequences] - return the last output in the output sequence or the full sequence
@param {number} [attrs.go_backwards] - process the input sequence backwards
@param {number} [attrs.stateful] - whether to save the last state as the initial state for the next pass