Add a Uni-directional LSTM layer to the model.

        Parameters
        ----------
        name: str
            The name of this layer.
        W_h: [numpy.array]
            List of recursion weight matrices. The ordering is [R_i, R_f, R_o, R_z],
            where R_i, R_f, R_o, R_z are weight matrices at input gate, forget gate, output gate and cell gate.
            The shapes of these matrices are (hidden_size, hidden_size).
        W_x: [numpy.array]
            List of input weight matrices. The ordering is [W_i, W_f, W_o, W_z],
            where W_i, W_f, W_o, W_z are weight matrices at input gate, forget gate, output gate and cell gate.
            The shapes of these matrices are (hidden_size, input_size).
        b: [numpy.array] | None
            List of biases. The ordering is [b_i, b_f, b_o, b_z],
            where b_i, b_f, b_o, b_z are biases at input gate, forget gate, output gate and cell gate.
            If None, biases are ignored. Otherwise the shapes of the biases are (hidden_size, ).
        hidden_size: int
            Number of hidden units. This is equal to the number of channels of output shape.
        input_size: int
            Number of the number of channels of input shape.
        input_names: [str]
            The input blob name list of this layer, in the order of [x, h_input, c_input].
        output_names: [str]
            The output blob name list of this layer, in the order of [y, h_output, c_output].
        inner_activation: str
            Inner activation function used at input and forget gate. Can be one of the following option:
            ['RELU', 'TANH', 'SIGMOID', 'SCALED_TANH', 'SIGMOID_HARD', 'LINEAR'].
        cell_state_update_activation: str
            Cell state update activation function used at the cell state update gate.
            ['RELU', 'TANH', 'SIGMOID', 'SCALED_TANH', 'SIGMOID_HARD', 'LINEAR'].
        output_activation: str
            Activation function used at the output gate. Can be one of the following option:
            ['RELU', 'TANH', 'SIGMOID', 'SCALED_TANH', 'SIGMOID_HARD', 'LINEAR'].
        peep: [numpy.array] | None
            List of peephole vectors. The ordering is [p_i, p_f, p_o],
            where p_i, p_f, and p_o are peephole vectors at input gate, forget gate, output gate.
            The shapes of the peephole vectors are (hidden_size,).
        output_all: boolean
            Whether the LSTM layer should output at every time step.

            - If False, the output is the result after the final state update.
            - If True, the output is a sequence, containing outputs at all time steps.

        forget_bias: boolean
            If True, a vector of 1s is added to forget gate bias.
        coupled_input_forget_gate: boolean
            If True, the input gate and forget gate is coupled. i.e. forget gate is not used.
        cell_clip_threshold: float
            The limit on the maximum and minimum values on the cell state.
            If not provided, it is defaulted to 50.0.
        reverse_input: boolean
            Whether the LSTM layer should process the input sequence in the reverse order.

            - If False, the input sequence order is not reversed.
            - If True, the input sequence order is reversed.

        See Also
        --------
        add_activation, add_simple_rnn, add_gru, add_bidirlstm

def add_unilstm(self, name, W_h, W_x, b, hidden_size, input_size, input_names, output_names,
                    inner_activation = 'SIGMOID',
                    cell_state_update_activation = 'TANH',
                    output_activation = 'TANH',
                    peep = None,
                    output_all = False,
                    forget_bias = False, coupled_input_forget_gate = False,
                    cell_clip_threshold = 50000.0, reverse_input = False):
        """
        Add a Uni-directional LSTM layer to the model.

        Parameters
        ----------
        name: str
            The name of this layer.
        W_h: [numpy.array]
            List of recursion weight matrices. The ordering is [R_i, R_f, R_o, R_z],
            where R_i, R_f, R_o, R_z are weight matrices at input gate, forget gate, output gate and cell gate.
            The shapes of these matrices are (hidden_size, hidden_size).
        W_x: [numpy.array]
            List of input weight matrices. The ordering is [W_i, W_f, W_o, W_z],
            where W_i, W_f, W_o, W_z are weight matrices at input gate, forget gate, output gate and cell gate.
            The shapes of these matrices are (hidden_size, input_size).
        b: [numpy.array] | None
            List of biases. The ordering is [b_i, b_f, b_o, b_z],
            where b_i, b_f, b_o, b_z are biases at input gate, forget gate, output gate and cell gate.
            If None, biases are ignored. Otherwise the shapes of the biases are (hidden_size, ).
        hidden_size: int
            Number of hidden units. This is equal to the number of channels of output shape.
        input_size: int
            Number of the number of channels of input shape.
        input_names: [str]
            The input blob name list of this layer, in the order of [x, h_input, c_input].
        output_names: [str]
            The output blob name list of this layer, in the order of [y, h_output, c_output].
        inner_activation: str
            Inner activation function used at input and forget gate. Can be one of the following option:
            ['RELU', 'TANH', 'SIGMOID', 'SCALED_TANH', 'SIGMOID_HARD', 'LINEAR'].
        cell_state_update_activation: str
            Cell state update activation function used at the cell state update gate.
            ['RELU', 'TANH', 'SIGMOID', 'SCALED_TANH', 'SIGMOID_HARD', 'LINEAR'].
        output_activation: str
            Activation function used at the output gate. Can be one of the following option:
            ['RELU', 'TANH', 'SIGMOID', 'SCALED_TANH', 'SIGMOID_HARD', 'LINEAR'].
        peep: [numpy.array] | None
            List of peephole vectors. The ordering is [p_i, p_f, p_o],
            where p_i, p_f, and p_o are peephole vectors at input gate, forget gate, output gate.
            The shapes of the peephole vectors are (hidden_size,).
        output_all: boolean
            Whether the LSTM layer should output at every time step.

            - If False, the output is the result after the final state update.
            - If True, the output is a sequence, containing outputs at all time steps.

        forget_bias: boolean
            If True, a vector of 1s is added to forget gate bias.
        coupled_input_forget_gate: boolean
            If True, the input gate and forget gate is coupled. i.e. forget gate is not used.
        cell_clip_threshold: float
            The limit on the maximum and minimum values on the cell state.
            If not provided, it is defaulted to 50.0.
        reverse_input: boolean
            Whether the LSTM layer should process the input sequence in the reverse order.

            - If False, the input sequence order is not reversed.
            - If True, the input sequence order is reversed.

        See Also
        --------
        add_activation, add_simple_rnn, add_gru, add_bidirlstm
        """
        spec = self.spec
        nn_spec = self.nn_spec

        # Add a new Layer
        spec_layer = nn_spec.layers.add()
        spec_layer.name = name
        for name in input_names:
            spec_layer.input.append(name)
        for name in output_names:
            spec_layer.output.append(name)
        spec_layer_params = spec_layer.uniDirectionalLSTM
        params = spec_layer_params.params
        weight_params = spec_layer_params.weightParams

        # set the parameters
        spec_layer_params.inputVectorSize = input_size
        spec_layer_params.outputVectorSize = hidden_size
        params.sequenceOutput = output_all
        params.forgetBias = False
        if b is not None:
            params.hasBiasVectors = True
        if peep is not None:
            params.hasPeepholeVectors = True
        params.coupledInputAndForgetGate = coupled_input_forget_gate
        params.cellClipThreshold = cell_clip_threshold
        params.forgetBias = forget_bias

        spec_layer_params.reverseInput = reverse_input

        activation_f = spec_layer_params.activations.add()
        activation_g = spec_layer_params.activations.add()
        activation_h = spec_layer_params.activations.add()
        _set_recurrent_activation(activation_f, inner_activation)
        _set_recurrent_activation(activation_g, cell_state_update_activation)
        _set_recurrent_activation(activation_h, output_activation)

        # Write the weights
        R_i, R_f, R_o, R_z = W_h
        W_i, W_f, W_o, W_z = W_x

        weight_params.inputGateWeightMatrix.floatValue.extend(map(float, W_i.flatten()))
        weight_params.forgetGateWeightMatrix.floatValue.extend(map(float, W_f.flatten()))
        weight_params.outputGateWeightMatrix.floatValue.extend(map(float, W_o.flatten()))
        weight_params.blockInputWeightMatrix.floatValue.extend(map(float, W_z.flatten()))

        weight_params.inputGateRecursionMatrix.floatValue.extend(map(float, R_i.flatten()))
        weight_params.forgetGateRecursionMatrix.floatValue.extend(map(float, R_f.flatten()))
        weight_params.outputGateRecursionMatrix.floatValue.extend(map(float, R_o.flatten()))
        weight_params.blockInputRecursionMatrix.floatValue.extend(map(float, R_z.flatten()))

        if b is not None:
            b_i, b_f, b_o, b_z = b
            weight_params.inputGateBiasVector.floatValue.extend(map(float, b_i.flatten()))
            weight_params.forgetGateBiasVector.floatValue.extend(map(float, b_f.flatten()))
            weight_params.outputGateBiasVector.floatValue.extend(map(float, b_o.flatten()))
            weight_params.blockInputBiasVector.floatValue.extend(map(float, b_z.flatten()))

        if peep is not None:
            p_i, p_f, p_o = peep
            weight_params.inputGatePeepholeVector.floatValue.extend(map(float, p_i.flatten()))
            weight_params.forgetGatePeepholeVector.floatValue.extend(map(float, p_f.flatten()))
            weight_params.outputGatePeepholeVector.floatValue.extend(map(float, p_o.flatten()))