Repository: keras-team/keras
Issue: keras.layers.Bidirectional constructor ignores trainable argument, causing models with trainable=False layers to incorrectly be cloned

**System information**.
- Have I written custom code (as opposed to using a stock example script provided in Keras): no
- OS Platform and Distribution (e.g., Linux Ubuntu 16.04): CentOS
- TensorFlow installed from (source or binary): PYPI
- TensorFlow version (use command below): 2.11.0
- Python version: 3.7

**Describe the problem**.

`keras.layers.Bidirectional` ignore the `trainable` argument, therefore cloning a model with Bidirectional layers, where the layer has been set to `trainable=False` will be cloned with `trainable` set to `True`.


**Describe the current behavior**.
The `trainable` property is set always to `True`.

**Describe the expected behavior**.
The `trainable` property should be set correctly.

**[Contributing](https://github.com/keras-team/keras/blob/master/CONTRIBUTING.md)**.

- Do you want to contribute a PR? (yes/no): yes
- If yes, please read [this page](https://github.com/keras-team/keras/blob/master/CONTRIBUTING.md) for instructions
- Briefly describe your candidate solution(if contributing):

Change `trainable = True` to `trainable = kwargs.get('trainable', True)` in https://github.com/keras-team/keras/blob/master/keras/layers/rnn/bidirectional.py#L178

**Standalone code to reproduce the issue**.

```python
import tensorflow as tf

inp = tf.keras.Input([None, 3])
rnn = tf.keras.layers.SimpleRNN(units=3)
bid = tf.keras.layers.Bidirectional(rnn)
model = tf.keras.Model(inp, bid(inp))

model.summary()

clone_trainable = tf.keras.models.clone_model(model)
assert clone_trainable.get_config() == model.get_config()

bid.trainable = False
clone_untrainable = tf.keras.models.clone_model(model)
assert clone_untrainable.get_config() == model.get_config()
```

Changed files:
keras/layers/rnn/bidirectional_test.py, keras/layers/rnn/bidirectional.py

diff --git a/keras/layers/rnn/bidirectional.py b/keras/layers/rnn/bidirectional.py
index 71b7320389..fe21524d7e 100644
--- a/keras/layers/rnn/bidirectional.py
+++ b/keras/layers/rnn/bidirectional.py
@@ -146,6 +146,7 @@ class Bidirectional(Wrapper):
             )
         else:
             self.backward_layer = backward_layer
+
             # Keep the custom backward layer config, so that we can save it
             # later. The layer's name might be updated below with prefix
             # 'backward_', and we want to preserve the original config.
@@ -175,7 +176,7 @@ class Bidirectional(Wrapper):
         self.return_sequences = layer.return_sequences
         self.return_state = layer.return_state
         self.supports_masking = True
-        self._trainable = True
+        self._trainable = kwargs.get("trainable", layer.trainable)
         self._num_constants = 0
         self.input_spec = layer.input_spec
 
diff --git a/keras/layers/rnn/bidirectional_test.py b/keras/layers/rnn/bidirectional_test.py
index 2819aef9f5..46ff1a251b 100644
--- a/keras/layers/rnn/bidirectional_test.py
+++ b/keras/layers/rnn/bidirectional_test.py
@@ -1020,6 +1020,47 @@ class BidirectionalTest(tf.test.TestCase, parameterized.TestCase):
         self.assertAllClose(output1, output3)
         self.assertNotAllClose(output1, output2)
 
+    def test_trainable_parameter_argument(self):
+        inp = keras.layers.Input([None, 3])
+
+        def test(fwd, bwd, **kwargs):
+            bid = keras.layers.Bidirectional(fwd, backward_layer=bwd, **kwargs)
+
+            model = keras.Model(inp, bid(inp))
+
+            clone = keras.models.clone_model(model)
+            self.assertEqual(clone.get_config(), model.get_config())
+
+        # test fetching trainable from `layer`
+        fwd = keras.layers.SimpleRNN(units=3)
+        bwd = keras.layers.SimpleRNN(units=3, go_backwards=True)
+
+        fwd.trainable = True
+        test(fwd, None)
+
+        fwd.trainable = False
+        test(fwd, None)
+
+        fwd.trainable = True
+        bwd.trainable = False
+        test(fwd, bwd)
+
+        fwd.trainable = False
+        bwd.trainable = True
+        test(fwd, bwd)
+
+        fwd.trainable = True
+        bwd.trainable = True
+        test(fwd, bwd)
+
+        fwd.trainable = False
+        bwd.trainable = False
+        test(fwd, bwd)
+
+        # test fetching trainable from `kwargs`
+        test(fwd, None, trainable=True)
+        test(fwd, None, trainable=False)
+
 
 def _to_list(ls):
     if isinstance(ls, list):