Repository: keras-team/keras-core

Issue:
keras.layers.CenterCrop raises AttributeError when passed a list of images
With tf.keras, the following code works, but not in Keras-Core:

```python
import keras_core as keras
import numpy as np

images = [
    np.random.rand(100, 100, 3),
    np.random.rand(100, 100, 3),
]
keras.layers.CenterCrop(height=60, width=50)(images)  #!!! AttributeError
```

Full stacktrace below:

<details>

```
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[21], line 8
      2 import numpy as np
      4 images = [
      5     np.random.rand(100, 100, 3),
      6     np.random.rand(100, 100, 3),
      7 ]
----> 8 keras.layers.CenterCrop(height=60, width=50)(images)

File ~/opt/miniconda3/envs/kerascore/lib/python3.8/site-packages/keras_core/src/layers/preprocessing/tf_data_layer.py:36, in TFDataLayer.__call__(self, inputs, **kwargs)
     34             self._convert_input_args = True
     35     return outputs
---> 36 return super().__call__(inputs, **kwargs)

File ~/opt/miniconda3/envs/kerascore/lib/python3.8/site-packages/keras_core/src/utils/traceback_utils.py:122, in filter_traceback.<locals>.error_handler(*args, **kwargs)
    119     filtered_tb = _process_traceback_frames(e.__traceback__)
    120     # To get the full stack trace, call:
    121     # `keras_core.config.disable_traceback_filtering()`
--> 122     raise e.with_traceback(filtered_tb) from None
    123 finally:
    124     del filtered_tb

File ~/opt/miniconda3/envs/kerascore/lib/python3.8/site-packages/keras_core/src/layers/preprocessing/center_crop.py:59, in CenterCrop.call(self, inputs)
     57     init_width = inputs.shape[-1]
     58 else:
---> 59     init_height = inputs.shape[-3]
     60     init_width = inputs.shape[-2]
     62 if init_height is None or init_width is None:
     63     # Dynamic size case. TODO.

AttributeError: Exception encountered when calling CenterCrop.call().

'list' object has no attribute 'shape'

Arguments received by CenterCrop.call():
  • inputs=['jnp.ndarray(shape=(100, 100, 3), dtype=float32)', 'jnp.ndarray(shape=(100, 100, 3), dtype=float32)']
```

</details>

A simple workaround is to stack the images:

```python
keras.layers.CenterCrop(height=60, width=50)(np.stack(images))
```

Not sure this can be considered a bug, but it's one of those little differences that may porting code from Keras 2.x to 3.0 a bit harder.


Discussion:

Resolving patch:
diff --git a/keras_core/layers/preprocessing/center_crop.py b/keras_core/layers/preprocessing/center_crop.py
--- a/keras_core/layers/preprocessing/center_crop.py
+++ b/keras_core/layers/preprocessing/center_crop.py
@@ -52,6 +52,7 @@ def __init__(self, height, width, data_format=None, **kwargs):
         self.data_format = backend.standardize_data_format(data_format)
 
     def call(self, inputs):
+        inputs = self.backend.cast(inputs, self.compute_dtype)
         if self.data_format == "channels_first":
             init_height = inputs.shape[-2]
             init_width = inputs.shape[-1]


Test patch:
diff --git a/keras_core/layers/preprocessing/center_crop_test.py b/keras_core/layers/preprocessing/center_crop_test.py
--- a/keras_core/layers/preprocessing/center_crop_test.py
+++ b/keras_core/layers/preprocessing/center_crop_test.py
@@ -102,3 +102,13 @@ def test_tf_data_compatibility(self):
         for output in ds.take(1):
             output = output.numpy()
         self.assertEqual(list(output.shape), [2, 8, 9, 3])
+
+    def test_list_compatibility(self):
+        images = [
+            np.random.rand(10, 10, 3),
+            np.random.rand(10, 10, 3),
+        ]
+        output = layers.CenterCrop(height=6, width=5)(images)
+        ref_output = tf.keras.layers.CenterCrop(6, 5)(images)
+        self.assertListEqual(list(output.shape), [2, 6, 5, 3])
+        self.assertAllClose(ref_output, output)