def add_gru(
        self,
        name,
        W_h,
        W_x,
        b,
        hidden_size,
        input_size,
        input_names,
        output_names,
        activation="TANH",
        inner_activation="SIGMOID_HARD",
        output_all=False,
        reverse_input=False,
    ):
        """
        Add a Gated-Recurrent Unit (GRU) layer to the model.
        Refer to the ``GRULayerParams`` message in the specification
        (NeuralNetwork.proto) for more details.

        Parameters
        ----------
        name: str
            The name of this layer.
        W_h: [numpy.array]
            List of recursion weight matrices. The ordering is ``[R_z, R_r, R_o]``,
            where ``R_z``, ``R_r`` and ``R_o`` are weight matrices at update gate,
            reset gate and output gate.
            The shapes of these matrices are ``(hidden_size, hidden_size)``.
        W_x: [numpy.array]
            List of input weight matrices. The ordering is ``[W_z, W_r, W_o]``,
            where ``W_z``, ``W_r``, and ``W_o`` are weight matrices at update gate,
            reset gate and output gate.
            The shapes of these matrices are ``(hidden_size, input_size)``.
        b: [numpy.array] or None
            List of biases of the GRU layer. The ordering is ``[b_z, b_r, b_o]``,
            where ``b_z``, ``b_r``, and ``b_o`` are biases at update gate,
            reset gate and output 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.
        activation: str
            Activation function used at the output gate. Can be one of the following options:
            [``'RELU'``, ``'TANH'``, ``'SIGMOID'``, ``'SCALED_TANH'``, ``'SIGMOID_HARD'``, ``'LINEAR'``].
            Defaults to ``'TANH'``.
            See add_activation for more detailed description.
        inner_activation: str
            Inner activation function used at update and reset gates.
            Can be one of the following options:
            [``'RELU'``, ``'TANH'``, ``'SIGMOID'``, ``'SCALED_TANH'``, ``'SIGMOID_HARD'``, ``'LINEAR'``].
            Defaults to ``'SIGMOID_HARD'``.
            See add_activation for more detailed description.
        input_names: list of str
            The input blob names list of this layer, in the order of ``[x, h_input]``.
        output_names: list of str
            The output blob names list of this layer, in the order of ``[y, h_output]``.
        output_all: boolean
            Whether the recurrent 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.

        reverse_input: boolean
            Whether the recurrent 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_unilstm, add_bidirlstm
        """
        spec_layer = self._add_generic_layer(name, input_names, output_names)
        spec_layer_params = spec_layer.gru

        # set the parameters
        spec_layer_params.inputVectorSize = input_size
        spec_layer_params.outputVectorSize = hidden_size
        if b is not None:
            spec_layer_params.hasBiasVectors = True
        spec_layer_params.sequenceOutput = output_all
        spec_layer_params.reverseInput = reverse_input

        activation_f = spec_layer_params.activations.add()
        activation_g = spec_layer_params.activations.add()
        _set_recurrent_activation(activation_f, inner_activation)
        _set_recurrent_activation(activation_g, activation)

        # Write the weights
        R_z, R_r, R_o = W_h
        W_z, W_r, W_o = W_x

        spec_layer_params.updateGateWeightMatrix.floatValue.extend(W_z.flatten())
        spec_layer_params.resetGateWeightMatrix.floatValue.extend(W_r.flatten())
        spec_layer_params.outputGateWeightMatrix.floatValue.extend(W_o.flatten())

        spec_layer_params.updateGateRecursionMatrix.floatValue.extend(R_z.flatten())
        spec_layer_params.resetGateRecursionMatrix.floatValue.extend(R_r.flatten())
        spec_layer_params.outputGateRecursionMatrix.floatValue.extend(R_o.flatten())

        if b is not None:
            b_z, b_r, b_o = b
            spec_layer_params.updateGateBiasVector.floatValue.extend(b_z.flatten())
            spec_layer_params.resetGateBiasVector.floatValue.extend(b_r.flatten())
            spec_layer_params.outputGateBiasVector.floatValue.extend(b_o.flatten())
        return spec_layer

        Add a Gated-Recurrent Unit (GRU) layer to the model.
        Refer to the ``GRULayerParams`` message in the specification
        (NeuralNetwork.proto) for more details.

        Parameters
        ----------
        name: str
            The name of this layer.
        W_h: [numpy.array]
            List of recursion weight matrices. The ordering is ``[R_z, R_r, R_o]``,
            where ``R_z``, ``R_r`` and ``R_o`` are weight matrices at update gate,
            reset gate and output gate.
            The shapes of these matrices are ``(hidden_size, hidden_size)``.
        W_x: [numpy.array]
            List of input weight matrices. The ordering is ``[W_z, W_r, W_o]``,
            where ``W_z``, ``W_r``, and ``W_o`` are weight matrices at update gate,
            reset gate and output gate.
            The shapes of these matrices are ``(hidden_size, input_size)``.
        b: [numpy.array] or None
            List of biases of the GRU layer. The ordering is ``[b_z, b_r, b_o]``,
            where ``b_z``, ``b_r``, and ``b_o`` are biases at update gate,
            reset gate and output 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.
        activation: str
            Activation function used at the output gate. Can be one of the following options:
            [``'RELU'``, ``'TANH'``, ``'SIGMOID'``, ``'SCALED_TANH'``, ``'SIGMOID_HARD'``, ``'LINEAR'``].
            Defaults to ``'TANH'``.
            See add_activation for more detailed description.
        inner_activation: str
            Inner activation function used at update and reset gates.
            Can be one of the following options:
            [``'RELU'``, ``'TANH'``, ``'SIGMOID'``, ``'SCALED_TANH'``, ``'SIGMOID_HARD'``, ``'LINEAR'``].
            Defaults to ``'SIGMOID_HARD'``.
            See add_activation for more detailed description.
        input_names: list of str
            The input blob names list of this layer, in the order of ``[x, h_input]``.
        output_names: list of str
            The output blob names list of this layer, in the order of ``[y, h_output]``.
        output_all: boolean
            Whether the recurrent 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.

        reverse_input: boolean
            Whether the recurrent 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_unilstm, add_bidirlstm
        
coremltools/models/neural_network/builder.py