Repository: keras-team/keras

Issue:
Keras 3.0 load h5 model with Orthogonal initializer fails
Hi guys, 

I'm trying to load an h5 model that was working in earlier versions.

* This is a small part of the h5 file, where you can see (last part of the snippet) a recurrent initializer with a classname of **Orthogonal**.

```
{"name": "decoder_gru0", "class_name": "GRU", "config": {"name": "decoder_gru0", "trainable": true, "return_sequences": true, "return_state": false, "go_backwards": false, "stateful": false, "unroll": false, "implementation": 0, "units": 488, "activation": "tanh", "recurrent_activation": "hard_sigmoid", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "recurrent_initializer": {"class_name": "Orthogonal", "config": {"gain": 1.0, "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}
```


* The error returned is:


```bash
  File "..../keras/src/initializers/__init__.py", line 118, in get
    raise ValueError(
ValueError: Could not interpret initializer identifier: {'class_name': 'Orthogonal', 'config': {'gain': 1.0, 'seed': None}}
```

## Addition

I then added the Orthogonal initializer to the custom objects, and it seems to go further, but gets stuck here:

```bash
    raise ValueError(
ValueError: Unrecognized keyword arguments passed to GRU: {'implementation': 0}
```

Any ideas on how to fix this @mehtamansi29 ?


Discussion:
Hi @mahnehsilla -

Thanks for raising the issue. Can you share the code snippet and h5 model with me where you are getting this error ? So I can reproduce it and try to help you on this. 

Hey @mahnehsilla 

I have proposed a PR for this issue in #19844 
However, I don't have your h5 model to verify it.  Maybe you could try the branch of my fork to double-check this?

```bash
# Install
pip3 install --no-deps --force-reinstall git+https://github.com/james77777778/keras.git@fix-legacy
```
I'll test it. But should it fix also the second part I am writing (see OP):

```bash
    raise ValueError(
ValueError: Unrecognized keyword arguments passed to GRU: {'implementation': 0}
```
Are you satisfied with the resolution of your issue?
<a href="https://docs.google.com/forms/d/e/1FAIpQLSdHag0RVFS7UXzZkKcsFCKOcX8raCupKK9RHSlYxp5U8lSJbQ/viewform?entry.492125872=Yes&entry.243948740=https://github.com/keras-team/keras/issues/19828">Yes</a>
<a href="https://docs.google.com/forms/d/e/1FAIpQLSdHag0RVFS7UXzZkKcsFCKOcX8raCupKK9RHSlYxp5U8lSJbQ/viewform?entry.492125872=No&entry.243948740=https://github.com/keras-team/keras/issues/19828">No</a>




Patch:
diff --git a/keras/src/initializers/__init__.py b/keras/src/initializers/__init__.py
index af46b7ff9b8a..e7cf6f76e3ef 100644
--- a/keras/src/initializers/__init__.py
+++ b/keras/src/initializers/__init__.py
@@ -49,6 +49,7 @@
         "uniform": RandomUniform,
         "normal": RandomNormal,
         "orthogonal": OrthogonalInitializer,
+        "Orthogonal": OrthogonalInitializer,  # Legacy
         "one": Ones,
         "zero": Zeros,
     }
diff --git a/keras/src/layers/rnn/gru.py b/keras/src/layers/rnn/gru.py
index 8a516d0b4406..7372d769be86 100644
--- a/keras/src/layers/rnn/gru.py
+++ b/keras/src/layers/rnn/gru.py
@@ -500,6 +500,7 @@ def __init__(
             trainable=kwargs.get("trainable", True),
             name="gru_cell",
             seed=seed,
+            implementation=kwargs.pop("implementation", 2),
         )
         super().__init__(
             cell,


Test patch:
diff --git a/keras/src/initializers/random_initializers_test.py b/keras/src/initializers/random_initializers_test.py
index b58cf64ba610..c0fec3812ea8 100644
--- a/keras/src/initializers/random_initializers_test.py
+++ b/keras/src/initializers/random_initializers_test.py
@@ -147,6 +147,10 @@ def test_orthogonal_initializer(self):
 
         self.run_class_serialization_test(initializer)
 
+        # Test legacy class_name
+        initializer = initializers.get("Orthogonal")
+        self.assertIsInstance(initializer, initializers.OrthogonalInitializer)
+
     def test_get_method(self):
         obj = initializers.get("glorot_normal")
         self.assertTrue(obj, initializers.GlorotNormal)
diff --git a/keras/src/layers/rnn/gru_test.py b/keras/src/layers/rnn/gru_test.py
index 529220803ddf..d2c4f9656cf8 100644
--- a/keras/src/layers/rnn/gru_test.py
+++ b/keras/src/layers/rnn/gru_test.py
@@ -286,3 +286,26 @@ def test_masking(self):
             np.array([[0.11669192, 0.11669192], [0.28380975, 0.28380975]]),
             output,
         )
+
+    def test_legacy_implementation_argument(self):
+        sequence = np.arange(72).reshape((3, 6, 4)).astype("float32")
+        layer = layers.GRU(
+            3,
+            kernel_initializer=initializers.Constant(0.01),
+            recurrent_initializer=initializers.Constant(0.02),
+            bias_initializer=initializers.Constant(0.03),
+        )
+        config = layer.get_config()
+        config["implementation"] = 0  # Add legacy argument
+        layer = layers.GRU.from_config(config)
+        output = layer(sequence)
+        self.assertAllClose(
+            np.array(
+                [
+                    [0.5217289, 0.5217289, 0.5217289],
+                    [0.6371659, 0.6371659, 0.6371659],
+                    [0.39384964, 0.39384964, 0.3938496],
+                ]
+            ),
+            output,
+        )