cell class for the gru layer this class processes one step within the whole time sequence input whereas keras layer gru processes the whole sequence args units positive integer dimensionality of the output space activation activation function to use default hyperbolic tangent tanh if you pass none no activation is applied ie linear activation ax x recurrentactivation activation function to use for the recurrent step default sigmoid sigmoid if you pass none no activation is applied ie linear activation ax x usebias boolean default true whether the layer should use a bias vector kernelinitializer initializer for the kernel weights matrix used for the linear transformation of the inputs default glorotuniform recurrentinitializer initializer for the recurrentkernel weights matrix used for the linear transformation of the recurrent state default orthogonal biasinitializer initializer for the bias vector default zeros kernelregularizer regularizer function applied to the kernel weights matrix default none recurrentregularizer regularizer function applied to the recurrentkernel weights matrix default none biasregularizer regularizer function applied to the bias vector default none kernelconstraint constraint function applied to the kernel weights matrix default none recurrentconstraint constraint function applied to the recurrentkernel weights matrix default none biasconstraint constraint function applied to the bias vector default none dropout float between 0 and 1 fraction of the units to drop for the linear transformation of the inputs default 0 recurrentdropout float between 0 and 1 fraction of the units to drop for the linear transformation of the recurrent state default 0 resetafter gru convention whether to apply reset gate after or before matrix multiplication false before true after default and cudnn compatible seed random seed for dropout call arguments inputs a 2d tensor with shape batch features states a 2d tensor with shape batch units which is the state from the previous time step training python boolean indicating whether the layer should behave in training mode or in inference mode only relevant when dropout or recurrentdropout is used example inputs np random random32 10 8 rnn keras layers rnnkeras layers grucell4 output rnninputs output shape 32 4 rnn keras layers rnn keras layers grucell4 returnsequencestrue returnstatetrue wholesequenceoutput finalstate rnninputs wholesequenceoutput shape 32 10 4 finalstate shape 32 4 separate biases for input and recurrent kernels note the shape is intentionally different from cudnngru biases 2 3 self units so that we can distinguish the classes when loading and converting saved weights reset gate applied afterbefore matrix multiplication inputs projected by all gate matrices at once biases biaszi biasri biashi hidden state projected by all gate matrices at once hidden state projected separately for updatereset and new previous and candidate state mixed by update gate gated recurrent unit cho et al 2014 based on available runtime hardware and constraints this layer will choose different implementations cudnnbased or backendnative to maximize the performance if a gpu is available and all the arguments to the layer meet the requirement of the cudnn kernel see below for details the layer will use a fast cudnn implementation when using the tensorflow backend the requirements to use the cudnn implementation are 1 activation tanh 2 recurrentactivation sigmoid 3 dropout 0 and recurrentdropout 0 4 unroll is false 5 usebias is true 6 resetafter is true 7 inputs if use masking are strictly rightpadded 8 eager execution is enabled in the outermost context there are two variants of the gru implementation the default one is based on v3https arxiv orgabs1406 1078v3 and has reset gate applied to hidden state before matrix multiplication the other one is based on originalhttps arxiv orgabs1406 1078v1 and has the order reversed the second variant is compatible with cudnngru gpuonly and allows inference on cpu thus it has separate biases for kernel and recurrentkernel to use this variant set resetaftertrue and recurrentactivation sigmoid for example inputs np random random32 10 8 gru keras layers gru4 output gruinputs output shape 32 4 gru keras layers gru4 returnsequencestrue returnstatetrue wholesequenceoutput finalstate gruinputs wholesequenceoutput shape 32 10 4 finalstate shape 32 4 args units positive integer dimensionality of the output space activation activation function to use default hyperbolic tangent tanh if you pass none no activation is applied ie linear activation ax x recurrentactivation activation function to use for the recurrent step default sigmoid sigmoid if you pass none no activation is applied ie linear activation ax x usebias boolean default true whether the layer should use a bias vector kernelinitializer initializer for the kernel weights matrix used for the linear transformation of the inputs default glorotuniform recurrentinitializer initializer for the recurrentkernel weights matrix used for the linear transformation of the recurrent state default orthogonal biasinitializer initializer for the bias vector default zeros kernelregularizer regularizer function applied to the kernel weights matrix default none recurrentregularizer regularizer function applied to the recurrentkernel weights matrix default none biasregularizer regularizer function applied to the bias vector default none activityregularizer regularizer function applied to the output of the layer its activation default none kernelconstraint constraint function applied to the kernel weights matrix default none recurrentconstraint constraint function applied to the recurrentkernel weights matrix default none biasconstraint constraint function applied to the bias vector default none dropout float between 0 and 1 fraction of the units to drop for the linear transformation of the inputs default 0 recurrentdropout float between 0 and 1 fraction of the units to drop for the linear transformation of the recurrent state default 0 seed random seed for dropout returnsequences boolean whether to return the last output in the output sequence or the full sequence default false returnstate boolean whether to return the last state in addition to the output default false gobackwards boolean default false if true process the input sequence backwards and return the reversed sequence stateful boolean default false if true the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch unroll boolean default false if true the network will be unrolled else a symbolic loop will be used unrolling can speedup a rnn although it tends to be more memoryintensive unrolling is only suitable for short sequences resetafter gru convention whether to apply reset gate after or before matrix multiplication false is before true is after default and cudnn compatible call arguments inputs a 3d tensor with shape batch timesteps feature mask binary tensor of shape samples timesteps indicating whether a given timestep should be masked optional an individual true entry indicates that the corresponding timestep should be utilized while a false entry indicates that the corresponding timestep should be ignored defaults to none training python boolean indicating whether the layer should behave in training mode or in inference mode this argument is passed to the cell when calling it this is only relevant if dropout or recurrentdropout is used optional defaults to none initialstate list of initial state tensors to be passed to the first call of the cell optional none causes creation of zerofilled initial state tensors defaults to none backends are allowed to specify optionally optimized implementation of the inner gru loop in the case of tf for instance it will leverage cudnn when feasible and it will raise notimplementederror otherwise we disable jitcompile for the model in this case since cudnn ops aren t xla compatible cell class for the gru layer this class processes one step within the whole time sequence input whereas keras layer gru processes the whole sequence args units positive integer dimensionality of the output space activation activation function to use default hyperbolic tangent tanh if you pass none no activation is applied ie linear activation a x x recurrent_activation activation function to use for the recurrent step default sigmoid sigmoid if you pass none no activation is applied ie linear activation a x x use_bias boolean default true whether the layer should use a bias vector kernel_initializer initializer for the kernel weights matrix used for the linear transformation of the inputs default glorot_uniform recurrent_initializer initializer for the recurrent_kernel weights matrix used for the linear transformation of the recurrent state default orthogonal bias_initializer initializer for the bias vector default zeros kernel_regularizer regularizer function applied to the kernel weights matrix default none recurrent_regularizer regularizer function applied to the recurrent_kernel weights matrix default none bias_regularizer regularizer function applied to the bias vector default none kernel_constraint constraint function applied to the kernel weights matrix default none recurrent_constraint constraint function applied to the recurrent_kernel weights matrix default none bias_constraint constraint function applied to the bias vector default none dropout float between 0 and 1 fraction of the units to drop for the linear transformation of the inputs default 0 recurrent_dropout float between 0 and 1 fraction of the units to drop for the linear transformation of the recurrent state default 0 reset_after gru convention whether to apply reset gate after or before matrix multiplication false before true after default and cudnn compatible seed random seed for dropout call arguments inputs a 2d tensor with shape batch features states a 2d tensor with shape batch units which is the state from the previous time step training python boolean indicating whether the layer should behave in training mode or in inference mode only relevant when dropout or recurrent_dropout is used example inputs np random random 32 10 8 rnn keras layers rnn keras layers grucell 4 output rnn inputs output shape 32 4 rnn keras layers rnn keras layers grucell 4 return_sequences true return_state true whole_sequence_output final_state rnn inputs whole_sequence_output shape 32 10 4 final_state shape 32 4 separate biases for input and recurrent kernels note the shape is intentionally different from cudnngru biases 2 3 self units so that we can distinguish the classes when loading and converting saved weights previous state reset gate applied after before matrix multiplication inputs projected by all gate matrices at once biases bias_z_i bias_r_i bias_h_i hidden state projected by all gate matrices at once hidden state projected separately for update reset and new previous and candidate state mixed by update gate gated recurrent unit cho et al 2014 based on available runtime hardware and constraints this layer will choose different implementations cudnn based or backend native to maximize the performance if a gpu is available and all the arguments to the layer meet the requirement of the cudnn kernel see below for details the layer will use a fast cudnn implementation when using the tensorflow backend the requirements to use the cudnn implementation are 1 activation tanh 2 recurrent_activation sigmoid 3 dropout 0 and recurrent_dropout 0 4 unroll is false 5 use_bias is true 6 reset_after is true 7 inputs if use masking are strictly right padded 8 eager execution is enabled in the outermost context there are two variants of the gru implementation the default one is based on v3 https arxiv org abs 1406 1078v3 and has reset gate applied to hidden state before matrix multiplication the other one is based on original https arxiv org abs 1406 1078v1 and has the order reversed the second variant is compatible with cudnngru gpu only and allows inference on cpu thus it has separate biases for kernel and recurrent_kernel to use this variant set reset_after true and recurrent_activation sigmoid for example inputs np random random 32 10 8 gru keras layers gru 4 output gru inputs output shape 32 4 gru keras layers gru 4 return_sequences true return_state true whole_sequence_output final_state gru inputs whole_sequence_output shape 32 10 4 final_state shape 32 4 args units positive integer dimensionality of the output space activation activation function to use default hyperbolic tangent tanh if you pass none no activation is applied ie linear activation a x x recurrent_activation activation function to use for the recurrent step default sigmoid sigmoid if you pass none no activation is applied ie linear activation a x x use_bias boolean default true whether the layer should use a bias vector kernel_initializer initializer for the kernel weights matrix used for the linear transformation of the inputs default glorot_uniform recurrent_initializer initializer for the recurrent_kernel weights matrix used for the linear transformation of the recurrent state default orthogonal bias_initializer initializer for the bias vector default zeros kernel_regularizer regularizer function applied to the kernel weights matrix default none recurrent_regularizer regularizer function applied to the recurrent_kernel weights matrix default none bias_regularizer regularizer function applied to the bias vector default none activity_regularizer regularizer function applied to the output of the layer its activation default none kernel_constraint constraint function applied to the kernel weights matrix default none recurrent_constraint constraint function applied to the recurrent_kernel weights matrix default none bias_constraint constraint function applied to the bias vector default none dropout float between 0 and 1 fraction of the units to drop for the linear transformation of the inputs default 0 recurrent_dropout float between 0 and 1 fraction of the units to drop for the linear transformation of the recurrent state default 0 seed random seed for dropout return_sequences boolean whether to return the last output in the output sequence or the full sequence default false return_state boolean whether to return the last state in addition to the output default false go_backwards boolean default false if true process the input sequence backwards and return the reversed sequence stateful boolean default false if true the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch unroll boolean default false if true the network will be unrolled else a symbolic loop will be used unrolling can speed up a rnn although it tends to be more memory intensive unrolling is only suitable for short sequences reset_after gru convention whether to apply reset gate after or before matrix multiplication false is before true is after default and cudnn compatible call arguments inputs a 3d tensor with shape batch timesteps feature mask binary tensor of shape samples timesteps indicating whether a given timestep should be masked optional an individual true entry indicates that the corresponding timestep should be utilized while a false entry indicates that the corresponding timestep should be ignored defaults to none training python boolean indicating whether the layer should behave in training mode or in inference mode this argument is passed to the cell when calling it this is only relevant if dropout or recurrent_dropout is used optional defaults to none initial_state list of initial state tensors to be passed to the first call of the cell optional none causes creation of zero filled initial state tensors defaults to none backends are allowed to specify optionally optimized implementation of the inner gru loop in the case of tf for instance it will leverage cudnn when feasible and it will raise notimplementederror otherwise we disable jit_compile for the model in this case since cudnn ops aren t xla compatible
import tree

from keras import activations
from keras import backend
from keras import constraints
from keras import initializers
from keras import ops
from keras import regularizers
from keras.api_export import keras_export
from keras.layers.input_spec import InputSpec
from keras.layers.layer import Layer
from keras.layers.rnn.dropout_rnn_cell import DropoutRNNCell
from keras.layers.rnn.rnn import RNN


@keras_export("keras.layers.GRUCell")
class GRUCell(Layer, DropoutRNNCell):
    

    def __init__(
        self,
        units,
        activation="tanh",
        recurrent_activation="sigmoid",
        use_bias=True,
        kernel_initializer="glorot_uniform",
        recurrent_initializer="orthogonal",
        bias_initializer="zeros",
        kernel_regularizer=None,
        recurrent_regularizer=None,
        bias_regularizer=None,
        kernel_constraint=None,
        recurrent_constraint=None,
        bias_constraint=None,
        dropout=0.0,
        recurrent_dropout=0.0,
        reset_after=True,
        seed=None,
        **kwargs,
    ):
        if units <= 0:
            raise ValueError(
                "Received an invalid value for argument `units`, "
                f"expected a positive integer, got {units}."
            )
        implementation = kwargs.pop("implementation", 2)
        super().__init__(**kwargs)
        self.implementation = implementation
        self.units = units
        self.activation = activations.get(activation)
        self.recurrent_activation = activations.get(recurrent_activation)
        self.use_bias = use_bias

        self.kernel_initializer = initializers.get(kernel_initializer)
        self.recurrent_initializer = initializers.get(recurrent_initializer)
        self.bias_initializer = initializers.get(bias_initializer)

        self.kernel_regularizer = regularizers.get(kernel_regularizer)
        self.recurrent_regularizer = regularizers.get(recurrent_regularizer)
        self.bias_regularizer = regularizers.get(bias_regularizer)

        self.kernel_constraint = constraints.get(kernel_constraint)
        self.recurrent_constraint = constraints.get(recurrent_constraint)
        self.bias_constraint = constraints.get(bias_constraint)

        self.dropout = min(1.0, max(0.0, dropout))
        self.recurrent_dropout = min(1.0, max(0.0, recurrent_dropout))
        self.seed = seed
        self.seed_generator = backend.random.SeedGenerator(seed=seed)

        self.reset_after = reset_after
        self.state_size = self.units
        self.output_size = self.units

    def build(self, input_shape):
        super().build(input_shape)
        input_dim = input_shape[-1]
        self.kernel = self.add_weight(
            shape=(input_dim, self.units * 3),
            name="kernel",
            initializer=self.kernel_initializer,
            regularizer=self.kernel_regularizer,
            constraint=self.kernel_constraint,
        )
        self.recurrent_kernel = self.add_weight(
            shape=(self.units, self.units * 3),
            name="recurrent_kernel",
            initializer=self.recurrent_initializer,
            regularizer=self.recurrent_regularizer,
            constraint=self.recurrent_constraint,
        )

        if self.use_bias:
            if not self.reset_after:
                bias_shape = (3 * self.units,)
            else:
                
                
                
                
                bias_shape = (2, 3 * self.units)
            self.bias = self.add_weight(
                shape=bias_shape,
                name="bias",
                initializer=self.bias_initializer,
                regularizer=self.bias_regularizer,
                constraint=self.bias_constraint,
            )
        else:
            self.bias = None
        self.built = True

    def call(self, inputs, states, training=False):
        h_tm1 = (
            states[0] if tree.is_nested(states) else states
        )  

        dp_mask = self.get_dropout_mask(inputs)
        rec_dp_mask = self.get_recurrent_dropout_mask(h_tm1)

        if self.use_bias:
            if not self.reset_after:
                input_bias, recurrent_bias = self.bias, None
            else:
                input_bias, recurrent_bias = (
                    ops.squeeze(e, axis=0)
                    for e in ops.split(self.bias, self.bias.shape[0], axis=0)
                )

        if training and 0.0 < self.dropout < 1.0:
            inputs *= dp_mask
        if training and 0.0 < self.recurrent_dropout < 1.0:
            h_tm1 *= rec_dp_mask

        if self.implementation == 1:
            inputs_z = inputs
            inputs_r = inputs
            inputs_h = inputs

            x_z = ops.matmul(inputs_z, self.kernel[:, : self.units])
            x_r = ops.matmul(
                inputs_r, self.kernel[:, self.units : self.units * 2]
            )
            x_h = ops.matmul(inputs_h, self.kernel[:, self.units * 2 :])

            if self.use_bias:
                x_z += input_bias[: self.units]
                x_r += input_bias[self.units : self.units * 2]
                x_h += input_bias[self.units * 2 :]

            h_tm1_z = h_tm1
            h_tm1_r = h_tm1
            h_tm1_h = h_tm1

            recurrent_z = ops.matmul(
                h_tm1_z, self.recurrent_kernel[:, : self.units]
            )
            recurrent_r = ops.matmul(
                h_tm1_r, self.recurrent_kernel[:, self.units : self.units * 2]
            )
            if self.reset_after and self.use_bias:
                recurrent_z += recurrent_bias[: self.units]
                recurrent_r += recurrent_bias[self.units : self.units * 2]

            z = self.recurrent_activation(x_z + recurrent_z)
            r = self.recurrent_activation(x_r + recurrent_r)

            
            if self.reset_after:
                recurrent_h = ops.matmul(
                    h_tm1_h, self.recurrent_kernel[:, self.units * 2 :]
                )
                if self.use_bias:
                    recurrent_h += recurrent_bias[self.units * 2 :]
                recurrent_h = r * recurrent_h
            else:
                recurrent_h = ops.matmul(
                    r * h_tm1_h, self.recurrent_kernel[:, self.units * 2 :]
                )

            hh = self.activation(x_h + recurrent_h)
        else:
            
            matrix_x = ops.matmul(inputs, self.kernel)
            if self.use_bias:
                
                matrix_x += input_bias

            x_z, x_r, x_h = ops.split(matrix_x, 3, axis=-1)

            if self.reset_after:
                
                matrix_inner = ops.matmul(h_tm1, self.recurrent_kernel)
                if self.use_bias:
                    matrix_inner += recurrent_bias
            else:
                
                matrix_inner = ops.matmul(
                    h_tm1, self.recurrent_kernel[:, : 2 * self.units]
                )

            recurrent_z = matrix_inner[:, : self.units]
            recurrent_r = matrix_inner[:, self.units : self.units * 2]
            recurrent_h = matrix_inner[:, self.units * 2 :]

            z = self.recurrent_activation(x_z + recurrent_z)
            r = self.recurrent_activation(x_r + recurrent_r)

            if self.reset_after:
                recurrent_h = r * recurrent_h
            else:
                recurrent_h = ops.matmul(
                    r * h_tm1, self.recurrent_kernel[:, 2 * self.units :]
                )

            hh = self.activation(x_h + recurrent_h)

        
        h = z * h_tm1 + (1 - z) * hh
        new_state = [h] if tree.is_nested(states) else h
        return h, new_state

    def get_config(self):
        config = {
            "units": self.units,
            "activation": activations.serialize(self.activation),
            "recurrent_activation": activations.serialize(
                self.recurrent_activation
            ),
            "use_bias": self.use_bias,
            "kernel_initializer": initializers.serialize(
                self.kernel_initializer
            ),
            "recurrent_initializer": initializers.serialize(
                self.recurrent_initializer
            ),
            "bias_initializer": initializers.serialize(self.bias_initializer),
            "kernel_regularizer": regularizers.serialize(
                self.kernel_regularizer
            ),
            "recurrent_regularizer": regularizers.serialize(
                self.recurrent_regularizer
            ),
            "bias_regularizer": regularizers.serialize(self.bias_regularizer),
            "kernel_constraint": constraints.serialize(self.kernel_constraint),
            "recurrent_constraint": constraints.serialize(
                self.recurrent_constraint
            ),
            "bias_constraint": constraints.serialize(self.bias_constraint),
            "dropout": self.dropout,
            "recurrent_dropout": self.recurrent_dropout,
            "reset_after": self.reset_after,
            "seed": self.seed,
        }
        base_config = super().get_config()
        return {**base_config, **config}

    def get_initial_state(self, batch_size=None):
        return [
            ops.zeros((batch_size, self.state_size), dtype=self.compute_dtype)
        ]


@keras_export("keras.layers.GRU")
class GRU(RNN):
    

    def __init__(
        self,
        units,
        activation="tanh",
        recurrent_activation="sigmoid",
        use_bias=True,
        kernel_initializer="glorot_uniform",
        recurrent_initializer="orthogonal",
        bias_initializer="zeros",
        kernel_regularizer=None,
        recurrent_regularizer=None,
        bias_regularizer=None,
        activity_regularizer=None,
        kernel_constraint=None,
        recurrent_constraint=None,
        bias_constraint=None,
        dropout=0.0,
        recurrent_dropout=0.0,
        seed=None,
        return_sequences=False,
        return_state=False,
        go_backwards=False,
        stateful=False,
        unroll=False,
        reset_after=True,
        **kwargs,
    ):
        cell = GRUCell(
            units,
            activation=activation,
            recurrent_activation=recurrent_activation,
            use_bias=use_bias,
            kernel_initializer=kernel_initializer,
            recurrent_initializer=recurrent_initializer,
            bias_initializer=bias_initializer,
            kernel_regularizer=kernel_regularizer,
            recurrent_regularizer=recurrent_regularizer,
            bias_regularizer=bias_regularizer,
            kernel_constraint=kernel_constraint,
            recurrent_constraint=recurrent_constraint,
            bias_constraint=bias_constraint,
            dropout=dropout,
            recurrent_dropout=recurrent_dropout,
            reset_after=reset_after,
            dtype=kwargs.get("dtype", None),
            trainable=kwargs.get("trainable", True),
            name="gru_cell",
            seed=seed,
        )
        super().__init__(
            cell,
            return_sequences=return_sequences,
            return_state=return_state,
            go_backwards=go_backwards,
            stateful=stateful,
            unroll=unroll,
            activity_regularizer=activity_regularizer,
            **kwargs,
        )
        self.input_spec = InputSpec(ndim=3)
        if backend.backend() == "tensorflow" and backend.cudnn_ok(
            cell.activation,
            cell.recurrent_activation,
            self.unroll,
            cell.use_bias,
            reset_after=reset_after,
        ):
            self.supports_jit = False

    def inner_loop(self, sequences, initial_state, mask, training=False):
        if tree.is_nested(initial_state):
            initial_state = initial_state[0]
        if tree.is_nested(mask):
            mask = mask[0]

        if not self.dropout and not self.recurrent_dropout:
            try:
                
                
                
                
                out = backend.gru(
                    sequences,
                    initial_state,
                    mask,
                    kernel=self.cell.kernel,
                    recurrent_kernel=self.cell.recurrent_kernel,
                    bias=self.cell.bias,
                    activation=self.cell.activation,
                    recurrent_activation=self.cell.recurrent_activation,
                    return_sequences=self.return_sequences,
                    go_backwards=self.go_backwards,
                    unroll=self.unroll,
                    reset_after=self.cell.reset_after,
                )
                
                
                if backend.backend() == "tensorflow":
                    self.supports_jit = False
                return out
            except NotImplementedError:
                pass
        return super().inner_loop(
            sequences, initial_state, mask=mask, training=training
        )

    def call(self, sequences, initial_state=None, mask=None, training=False):
        return super().call(
            sequences, mask=mask, training=training, initial_state=initial_state
        )

    @property
    def units(self):
        return self.cell.units

    @property
    def activation(self):
        return self.cell.activation

    @property
    def recurrent_activation(self):
        return self.cell.recurrent_activation

    @property
    def use_bias(self):
        return self.cell.use_bias

    @property
    def kernel_initializer(self):
        return self.cell.kernel_initializer

    @property
    def recurrent_initializer(self):
        return self.cell.recurrent_initializer

    @property
    def bias_initializer(self):
        return self.cell.bias_initializer

    @property
    def kernel_regularizer(self):
        return self.cell.kernel_regularizer

    @property
    def recurrent_regularizer(self):
        return self.cell.recurrent_regularizer

    @property
    def bias_regularizer(self):
        return self.cell.bias_regularizer

    @property
    def kernel_constraint(self):
        return self.cell.kernel_constraint

    @property
    def recurrent_constraint(self):
        return self.cell.recurrent_constraint

    @property
    def bias_constraint(self):
        return self.cell.bias_constraint

    @property
    def dropout(self):
        return self.cell.dropout

    @property
    def recurrent_dropout(self):
        return self.cell.recurrent_dropout

    @property
    def reset_after(self):
        return self.cell.reset_after

    def get_config(self):
        config = {
            "units": self.units,
            "activation": activations.serialize(self.activation),
            "recurrent_activation": activations.serialize(
                self.recurrent_activation
            ),
            "use_bias": self.use_bias,
            "kernel_initializer": initializers.serialize(
                self.kernel_initializer
            ),
            "recurrent_initializer": initializers.serialize(
                self.recurrent_initializer
            ),
            "bias_initializer": initializers.serialize(self.bias_initializer),
            "kernel_regularizer": regularizers.serialize(
                self.kernel_regularizer
            ),
            "recurrent_regularizer": regularizers.serialize(
                self.recurrent_regularizer
            ),
            "bias_regularizer": regularizers.serialize(self.bias_regularizer),
            "activity_regularizer": regularizers.serialize(
                self.activity_regularizer
            ),
            "kernel_constraint": constraints.serialize(self.kernel_constraint),
            "recurrent_constraint": constraints.serialize(
                self.recurrent_constraint
            ),
            "bias_constraint": constraints.serialize(self.bias_constraint),
            "dropout": self.dropout,
            "recurrent_dropout": self.recurrent_dropout,
            "reset_after": self.reset_after,
            "seed": self.cell.seed,
        }
        base_config = super().get_config()
        del base_config["cell"]
        return {**base_config, **config}

    @classmethod
    def from_config(cls, config):
        return cls(**config)