Repository: keras-team/keras

Issue:
ValueError when loading models that has reused weights
if I create a model wich reuses layers I get a Error when trying to load it again.

```python
import tensorflow as tf
from keras.models import load_model,save_model
from keras import layers

inputs = layers.Input(shape=(10,))
x=inputs

t=layers.Dense(10)
x = t(x)
x = layers.Dense(10)(x)
x = t(x)
model=tf.keras.Model(inputs, x)

model.summary()
save_model(model,'testmodel.keras')

model2=load_model('testmodel.keras')
model2.summary()
```

I also found out how to fix it:
https://github.com/keras-team/keras/blob/d3671cf276d838599dd8acec9616845ac262d52a/keras/src/models/functional.py#L687C3-L690C56

This ValueError has to be a IndexError (like in the legacy case in the code above).

That way it can be caught here:
https://github.com/keras-team/keras/blob/d3671cf276d838599dd8acec9616845ac262d52a/keras/src/models/functional.py#L517C1-L525C36

:)



Discussion:
Hi @K1521 -

Thanks for reporting this issue. Here While creating the model you can reuse the layer weight store in variable(t) `t=layers.Dense(10)` instead of declaring new layer `x = layers.Dense(10)(x)`. 
Attached [gist](https://colab.sandbox.google.com/gist/mehtamansi29/1c65dbaa96744ee79bb7f124c81fd587/20307-valueerror-when-loading-models-that-reuse-weights.ipynb) here for your reference. 
I know that it works if you feed the layer in itself, but that is not what i want to do. I have reduced a larger example down to this example.
As i have said , i have solved the problem by replacing the ValueError with a IndexError. That way the code is more similar to the legacy case here: https://github.com/keras-team/keras/blob/d3671cf276d838599dd8acec9616845ac262d52a/keras/src/models/functional.py#L662
i think somebody just translated the legacy case wrong
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/20307">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/20307">No</a>




Patch:
diff --git a/keras/src/models/functional.py b/keras/src/models/functional.py
index 3d3f2fd68f12..91de7b82f23e 100644
--- a/keras/src/models/functional.py
+++ b/keras/src/models/functional.py
@@ -699,7 +699,7 @@ def convert_revived_tensor(x):
             inbound_node_index = history[1]
             inbound_tensor_index = history[2]
             if len(layer._inbound_nodes) <= inbound_node_index:
-                raise ValueError(
+                raise IndexError(
                     "Layer node index out of bounds.\n"
                     f"inbound_layer = {layer}\n"
                     f"inbound_layer._inbound_nodes = {layer._inbound_nodes}\n"


Test patch:
diff --git a/keras/src/saving/saving_lib_test.py b/keras/src/saving/saving_lib_test.py
index 579b23478da7..5c90c9f6975e 100644
--- a/keras/src/saving/saving_lib_test.py
+++ b/keras/src/saving/saving_lib_test.py
@@ -723,6 +723,18 @@ def test_load_model_concurrently(self):
             pool.join()
         [r.get() for r in results]  # No error occurs here
 
+    def test_load_model_containing_reused_layer(self):
+        # https://github.com/keras-team/keras/issues/20307
+        inputs = keras.Input((4,))
+        reused_layer = keras.layers.Dense(4)
+        x = reused_layer(inputs)
+        x = keras.layers.Dense(4)(x)
+        outputs = reused_layer(x)
+        model = keras.Model(inputs, outputs)
+
+        self.assertLen(model.layers, 3)  # Input + 2 Dense layers
+        self._test_inference_after_instantiation(model)
+
 
 @pytest.mark.requires_trainable_backend
 class SavingAPITest(testing.TestCase):