From bc45bcc889910da81f5ff72aa78e97f22d8c6043 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sat, 9 Aug 2025 18:22:01 +0200 Subject: [PATCH 01/15] Proposed fix for issue #21519: Reshape layer does not handle -1 shape infor dynamically. --- keras/src/layers/reshaping/reshape.py | 38 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/keras/src/layers/reshaping/reshape.py b/keras/src/layers/reshaping/reshape.py index abd00d915112..6a9f88dd8780 100644 --- a/keras/src/layers/reshaping/reshape.py +++ b/keras/src/layers/reshaping/reshape.py @@ -3,7 +3,7 @@ from keras.src.backend.common.keras_tensor import KerasTensor from keras.src.layers.layer import Layer from keras.src.ops import operation_utils - +import math @keras_export("keras.layers.Reshape") class Reshape(Layer): @@ -37,7 +37,19 @@ class Reshape(Layer): def __init__(self, target_shape, **kwargs): super().__init__(**kwargs) - self.target_shape = tuple(target_shape) + target_shape = tuple(target_shape) + # test validity of target_shape + if target_shape.count(-1) > 1: + raise ValueError( + "The `target_shape` argument must not contain more than one " + "`-1` value. Received: target_shape={}".format(target_shape) + ) + self.target_shape = target_shape + # precalculate all values that might be required + self.need_explicit_shape_for_batch_size_None = (target_shape.count(-1) == 1) + self.new_size_no_minus_one = math.prod( + d for d in target_shape if d != -1 + ) def compute_output_shape(self, input_shape): return ( @@ -53,19 +65,23 @@ def compute_output_spec(self, inputs): shape=output_shape, dtype=inputs.dtype, sparse=inputs.sparse ) - def build(self, input_shape): - sample_output_shape = operation_utils.compute_reshape_output_shape( - input_shape[1:], self.target_shape, "target_shape" - ) - self._resolved_target_shape = tuple( - -1 if d is None else d for d in sample_output_shape - ) - def call(self, inputs): + target_shape = self.target_shape + if self.need_explicit_shape_for_batch_size_None and (inputs.shape[0] is None): + input_nonbatch_shape = tuple(inputs.shape[1:]) + if input_nonbatch_shape.count(None) == 0: + # If the input shape is fully defined, we can compute the desired target_shape + if True: + inp_nonbatch_size = math.prod(inputs.shape[1:]) + else: + inp_nonbatch_size = ops.prod(ops.shape(inputs)[1:]) + target_shape = tuple(d if d != -1 else (inp_nonbatch_size // self.new_size_no_minus_one) for d in self.target_shape) + return ops.reshape( - inputs, (ops.shape(inputs)[0],) + self._resolved_target_shape + inputs, (ops.shape(inputs)[0],) + target_shape ) + def get_config(self): config = {"target_shape": self.target_shape} base_config = super().get_config() From a502050de53c15e00fc5e1e6f7206d24e29347a5 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sun, 10 Aug 2025 00:58:37 +0200 Subject: [PATCH 02/15] Removed unused part of the code. The code in the fix should deal exclusively with the case that is not properly handled by ops.reshape. This is when the batch dimension does not have a static shape (shape == None) but all other dimensions have static shape. In that case we can determine the static shape of the dimension containing -1 form all dimensions that are not the batch dimension. --- keras/src/layers/reshaping/reshape.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/keras/src/layers/reshaping/reshape.py b/keras/src/layers/reshaping/reshape.py index 6a9f88dd8780..218e18cc4d74 100644 --- a/keras/src/layers/reshaping/reshape.py +++ b/keras/src/layers/reshaping/reshape.py @@ -70,11 +70,7 @@ def call(self, inputs): if self.need_explicit_shape_for_batch_size_None and (inputs.shape[0] is None): input_nonbatch_shape = tuple(inputs.shape[1:]) if input_nonbatch_shape.count(None) == 0: - # If the input shape is fully defined, we can compute the desired target_shape - if True: - inp_nonbatch_size = math.prod(inputs.shape[1:]) - else: - inp_nonbatch_size = ops.prod(ops.shape(inputs)[1:]) + inp_nonbatch_size = math.prod(inputs.shape[1:]) target_shape = tuple(d if d != -1 else (inp_nonbatch_size // self.new_size_no_minus_one) for d in self.target_shape) return ops.reshape( From 49e664639f9c167bfbb386a1b7e40fa9e4c7365e Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sun, 10 Aug 2025 11:38:29 +0200 Subject: [PATCH 03/15] applied changes according to pre-commit hook --- keras/src/layers/reshaping/reshape.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/keras/src/layers/reshaping/reshape.py b/keras/src/layers/reshaping/reshape.py index 218e18cc4d74..b1f459c9073d 100644 --- a/keras/src/layers/reshaping/reshape.py +++ b/keras/src/layers/reshaping/reshape.py @@ -1,9 +1,11 @@ +import math + from keras.src import ops from keras.src.api_export import keras_export from keras.src.backend.common.keras_tensor import KerasTensor from keras.src.layers.layer import Layer from keras.src.ops import operation_utils -import math + @keras_export("keras.layers.Reshape") class Reshape(Layer): @@ -46,7 +48,9 @@ def __init__(self, target_shape, **kwargs): ) self.target_shape = target_shape # precalculate all values that might be required - self.need_explicit_shape_for_batch_size_None = (target_shape.count(-1) == 1) + self.need_explicit_shape_for_batch_size_None = ( + target_shape.count(-1) == 1 + ) self.new_size_no_minus_one = math.prod( d for d in target_shape if d != -1 ) @@ -67,16 +71,20 @@ def compute_output_spec(self, inputs): def call(self, inputs): target_shape = self.target_shape - if self.need_explicit_shape_for_batch_size_None and (inputs.shape[0] is None): + if self.need_explicit_shape_for_batch_size_None and ( + inputs.shape[0] is None + ): input_nonbatch_shape = tuple(inputs.shape[1:]) if input_nonbatch_shape.count(None) == 0: inp_nonbatch_size = math.prod(inputs.shape[1:]) - target_shape = tuple(d if d != -1 else (inp_nonbatch_size // self.new_size_no_minus_one) for d in self.target_shape) - - return ops.reshape( - inputs, (ops.shape(inputs)[0],) + target_shape - ) + target_shape = tuple( + d + if d != -1 + else (inp_nonbatch_size // self.new_size_no_minus_one) + for d in self.target_shape + ) + return ops.reshape(inputs, (ops.shape(inputs)[0],) + target_shape) def get_config(self): config = {"target_shape": self.target_shape} From d6ebdce76a8b5d8bca25b63c1fc1eacfd2d40f48 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Tue, 12 Aug 2025 01:00:05 +0200 Subject: [PATCH 04/15] Added reshape_test test case that fails with original implementation and succeeds with fix. --- keras/src/layers/reshaping/reshape_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index 24c41c0f1c37..b72a9879854e 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -1,6 +1,7 @@ import pytest from absl.testing import parameterized +from keras.src import ops from keras.src import backend from keras.src import layers from keras.src import testing @@ -100,6 +101,16 @@ def test_reshape_with_dynamic_batch_size_and_minus_one(self): reshaped = backend.compute_output_spec(layer.__call__, input) self.assertEqual(reshaped.shape, (None, 3, 8)) + def test_reshape_with_varying_static_batch_size_and_minus_one(self): + input = KerasTensor((None, 6, 4)) + layer = layers.Reshape((-1, 8)) + layer.build(input.shape) + layer(ops.ones((1, 6, 4), dtype="float32")) + layer(ops.ones((1, 10, 4), dtype="float32")) + reshaped = backend.compute_output_spec(layer.__call__, input) + self.assertEqual(reshaped.shape, (None, 3, 8)) + + def test_reshape_with_dynamic_dim_and_minus_one(self): input = KerasTensor((4, 6, None, 3)) layer = layers.Reshape((-1, 3)) From 05483ffbfbab7239ce1c25e7bae2eed2a3101b25 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Tue, 12 Aug 2025 01:05:18 +0200 Subject: [PATCH 05/15] Added asserts for expected result. --- keras/src/layers/reshaping/reshape_test.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index b72a9879854e..ee7b831b2542 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -105,11 +105,10 @@ def test_reshape_with_varying_static_batch_size_and_minus_one(self): input = KerasTensor((None, 6, 4)) layer = layers.Reshape((-1, 8)) layer.build(input.shape) - layer(ops.ones((1, 6, 4), dtype="float32")) - layer(ops.ones((1, 10, 4), dtype="float32")) - reshaped = backend.compute_output_spec(layer.__call__, input) - self.assertEqual(reshaped.shape, (None, 3, 8)) - + res = layer(ops.ones((1, 6, 4), dtype="float32")) + self.assertEqual(res.shape, (1, 3, 8)) + res = layer(ops.ones((1, 10, 4), dtype="float32")) + self.assertEqual(res.shape, (1, 5, 8)) def test_reshape_with_dynamic_dim_and_minus_one(self): input = KerasTensor((4, 6, None, 3)) From 223ce9553903beaf3db4ae72de182497f6cbc221 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Tue, 12 Aug 2025 01:28:02 +0200 Subject: [PATCH 06/15] Fixed test name and added a further test with custom Model and Conv1D layer. --- keras/src/layers/reshaping/reshape_test.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index ee7b831b2542..fa4b84025a8a 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -1,6 +1,7 @@ import pytest from absl.testing import parameterized +from keras.src import Model from keras.src import ops from keras.src import backend from keras.src import layers @@ -101,7 +102,7 @@ def test_reshape_with_dynamic_batch_size_and_minus_one(self): reshaped = backend.compute_output_spec(layer.__call__, input) self.assertEqual(reshaped.shape, (None, 3, 8)) - def test_reshape_with_varying_static_batch_size_and_minus_one(self): + def test_reshape_layer_with_varying_input_size_and_minus_one(self): input = KerasTensor((None, 6, 4)) layer = layers.Reshape((-1, 8)) layer.build(input.shape) @@ -110,6 +111,23 @@ def test_reshape_with_varying_static_batch_size_and_minus_one(self): res = layer(ops.ones((1, 10, 4), dtype="float32")) self.assertEqual(res.shape, (1, 5, 8)) + def test_custom_reshape_model_with_varying_input_size_and_minus_one(self): + class MM(layers.Layer): + def __init__(self): + super().__init__() + self.conv = layers.Conv1D(4, 3, padding="same") + self.reshape = layers.Reshape((-1, 8)) + + def call(self, inputs): + x = self.conv(inputs) + return self.reshape(x) + + m = MM() + res = m(ops.ones((1, 6, 2), dtype="float32")) + self.assertEqual(res.shape, (1, 3, 8)) + res = m(ops.ones((1, 10, 2), dtype="float32")) + self.assertEqual(res.shape, (1, 5, 8)) + def test_reshape_with_dynamic_dim_and_minus_one(self): input = KerasTensor((4, 6, None, 3)) layer = layers.Reshape((-1, 3)) From 72255048ffe39f2332505790e076c730a721666d Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Tue, 12 Aug 2025 02:13:29 +0200 Subject: [PATCH 07/15] applied changes according to pre-commit hook --- keras/src/layers/reshaping/reshape_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index fa4b84025a8a..60bc789d273f 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -1,10 +1,9 @@ import pytest from absl.testing import parameterized -from keras.src import Model -from keras.src import ops from keras.src import backend from keras.src import layers +from keras.src import ops from keras.src import testing from keras.src.backend.common.keras_tensor import KerasTensor From 1145fb864d03721351c7c7eb90b3129fa0a86e83 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Tue, 12 Aug 2025 11:55:14 +0200 Subject: [PATCH 08/15] Fixed test to use a custom model and not a custom layer as indicated in the test name. --- keras/src/layers/reshaping/reshape_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index 60bc789d273f..d8a279de3e61 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -1,6 +1,7 @@ import pytest from absl.testing import parameterized +from keras.src import Model from keras.src import backend from keras.src import layers from keras.src import ops @@ -111,7 +112,7 @@ def test_reshape_layer_with_varying_input_size_and_minus_one(self): self.assertEqual(res.shape, (1, 5, 8)) def test_custom_reshape_model_with_varying_input_size_and_minus_one(self): - class MM(layers.Layer): + class MM(Model): def __init__(self): super().__init__() self.conv = layers.Conv1D(4, 3, padding="same") From d4c8e9d6876ccba0091b7453a2e015a783a07eb0 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sun, 24 Aug 2025 20:34:40 +0200 Subject: [PATCH 09/15] Implemented suggested changes: - Use original implementation from build method to avoid repeating the implementation in compute_reshape_output_shape. - Set the self.built attribute to True in __init__ because no further build is required. Additional change: - Mention the optional use of -1 for a single dimension of the target_shape. --- keras/src/layers/reshaping/reshape.py | 48 +++++++++++---------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/keras/src/layers/reshaping/reshape.py b/keras/src/layers/reshaping/reshape.py index b1f459c9073d..faa36f2221fd 100644 --- a/keras/src/layers/reshaping/reshape.py +++ b/keras/src/layers/reshaping/reshape.py @@ -1,5 +1,3 @@ -import math - from keras.src import ops from keras.src.api_export import keras_export from keras.src.backend.common.keras_tensor import KerasTensor @@ -13,11 +11,13 @@ class Reshape(Layer): Args: target_shape: Target shape. Tuple of integers, does not include the - samples dimension (batch size). + samples dimension (batch size). One element of the target_shape can be -1 + in which case the missing value is inferred from the length of the array + and remaining dimensions. Input shape: - Arbitrary, although all dimensions in the input shape must be - known/fixed. Use the keyword argument `input_shape` (tuple of integers, + Arbitrary, but required to be compatible with target shape. + Use the keyword argument `input_shape` (tuple of integers, does not include the samples/batch size axis) when using this layer as the first layer in a model. @@ -31,7 +31,7 @@ class Reshape(Layer): >>> y.shape (None, 3, 4) - >>> # also supports shape inference using `-1` as dimension + >>> # another example with shape inference using `-1` as dimension >>> y = keras.layers.Reshape((-1, 2, 2))(x) >>> y.shape (None, 3, 2, 2) @@ -44,16 +44,10 @@ def __init__(self, target_shape, **kwargs): if target_shape.count(-1) > 1: raise ValueError( "The `target_shape` argument must not contain more than one " - "`-1` value. Received: target_shape={}".format(target_shape) + f"`-1` value. Received: target_shape={target_shape}" ) self.target_shape = target_shape - # precalculate all values that might be required - self.need_explicit_shape_for_batch_size_None = ( - target_shape.count(-1) == 1 - ) - self.new_size_no_minus_one = math.prod( - d for d in target_shape if d != -1 - ) + self.built = True def compute_output_shape(self, input_shape): return ( @@ -70,21 +64,17 @@ def compute_output_spec(self, inputs): ) def call(self, inputs): - target_shape = self.target_shape - if self.need_explicit_shape_for_batch_size_None and ( - inputs.shape[0] is None - ): - input_nonbatch_shape = tuple(inputs.shape[1:]) - if input_nonbatch_shape.count(None) == 0: - inp_nonbatch_size = math.prod(inputs.shape[1:]) - target_shape = tuple( - d - if d != -1 - else (inp_nonbatch_size // self.new_size_no_minus_one) - for d in self.target_shape - ) - - return ops.reshape(inputs, (ops.shape(inputs)[0],) + target_shape) + potentially_resolved_target_shape = ( + operation_utils.compute_reshape_output_shape( + tuple(inputs.shape)[1:], self.target_shape, "target_shape" + ) + ) + potentially_resolved_target_shape = tuple( + -1 if d is None else d for d in potentially_resolved_target_shape + ) + return ops.reshape( + inputs, (ops.shape(inputs)[0],) + potentially_resolved_target_shape + ) def get_config(self): config = {"target_shape": self.target_shape} From efa8cb405a552eb2413892793ff4fe6544981e8f Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sun, 24 Aug 2025 20:42:16 +0200 Subject: [PATCH 10/15] Implemented suggested changes: - removed explicit call to layer.build from the tests, - changed the new test to use Model.compile and Model.fit to cover the corresponding API in the tests. --- keras/src/layers/reshaping/reshape_test.py | 38 ++++++++++------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index d8a279de3e61..ffc868eba897 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -1,7 +1,7 @@ import pytest from absl.testing import parameterized -from keras.src import Model +from keras.src import Sequential from keras.src import backend from keras.src import layers from keras.src import ops @@ -98,40 +98,20 @@ def test_reshape_with_dynamic_batch_size(self): def test_reshape_with_dynamic_batch_size_and_minus_one(self): input = KerasTensor((None, 6, 4)) layer = layers.Reshape((-1, 8)) - layer.build(input.shape) reshaped = backend.compute_output_spec(layer.__call__, input) self.assertEqual(reshaped.shape, (None, 3, 8)) def test_reshape_layer_with_varying_input_size_and_minus_one(self): input = KerasTensor((None, 6, 4)) layer = layers.Reshape((-1, 8)) - layer.build(input.shape) res = layer(ops.ones((1, 6, 4), dtype="float32")) self.assertEqual(res.shape, (1, 3, 8)) res = layer(ops.ones((1, 10, 4), dtype="float32")) self.assertEqual(res.shape, (1, 5, 8)) - def test_custom_reshape_model_with_varying_input_size_and_minus_one(self): - class MM(Model): - def __init__(self): - super().__init__() - self.conv = layers.Conv1D(4, 3, padding="same") - self.reshape = layers.Reshape((-1, 8)) - - def call(self, inputs): - x = self.conv(inputs) - return self.reshape(x) - - m = MM() - res = m(ops.ones((1, 6, 2), dtype="float32")) - self.assertEqual(res.shape, (1, 3, 8)) - res = m(ops.ones((1, 10, 2), dtype="float32")) - self.assertEqual(res.shape, (1, 5, 8)) - def test_reshape_with_dynamic_dim_and_minus_one(self): input = KerasTensor((4, 6, None, 3)) layer = layers.Reshape((-1, 3)) - layer.build(input.shape) reshaped = backend.compute_output_spec(layer.__call__, input) self.assertEqual(reshaped.shape, (4, None, 3)) @@ -140,3 +120,19 @@ def test_reshape_sets_static_shape(self): reshaped = layers.Reshape((3, 5))(input_layer) # Also make sure the batch dim is not lost after reshape. self.assertEqual(reshaped.shape, (2, 3, 5)) + + def test_reshape_model_fit_with_varying_input_size_and_minus_one(self): + def generator(): + yield ( + ops.ones((1, 12, 2), dtype="float32"), + ops.zeros((1, 3, 8), dtype="float32"), + ) + yield ( + ops.ones((1, 20, 2), dtype="float32"), + ops.zeros((1, 5, 8), dtype="float32"), + ) + + layer = layers.Reshape((-1, 8)) + model = Sequential([layer]) + model.compile(loss="mean_squared_error") + model.fit(generator(), steps_per_epoch=2, epochs=1) From 8c3d239482337896dbef1954f8d5fe337ec0ee49 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sun, 24 Aug 2025 20:46:22 +0200 Subject: [PATCH 11/15] Remove unused variable. --- keras/src/layers/reshaping/reshape_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index ffc868eba897..6fd3874c1e3e 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -102,7 +102,6 @@ def test_reshape_with_dynamic_batch_size_and_minus_one(self): self.assertEqual(reshaped.shape, (None, 3, 8)) def test_reshape_layer_with_varying_input_size_and_minus_one(self): - input = KerasTensor((None, 6, 4)) layer = layers.Reshape((-1, 8)) res = layer(ops.ones((1, 6, 4), dtype="float32")) self.assertEqual(res.shape, (1, 3, 8)) From 8c3c16bba1e2182cb59d10b1a42c981582af33e9 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sun, 24 Aug 2025 20:50:52 +0200 Subject: [PATCH 12/15] Fixed line lengths in doc string. --- keras/src/layers/reshaping/reshape.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keras/src/layers/reshaping/reshape.py b/keras/src/layers/reshaping/reshape.py index faa36f2221fd..be64381cdb8c 100644 --- a/keras/src/layers/reshaping/reshape.py +++ b/keras/src/layers/reshaping/reshape.py @@ -11,9 +11,9 @@ class Reshape(Layer): Args: target_shape: Target shape. Tuple of integers, does not include the - samples dimension (batch size). One element of the target_shape can be -1 - in which case the missing value is inferred from the length of the array - and remaining dimensions. + samples dimension (batch size). One element of the target_shape can + be -1 in which case the missing value is inferred from the length + of the array and remaining dimensions. Input shape: Arbitrary, but required to be compatible with target shape. From b0076a84907ce40ab8941bc79766a2cb976cdc60 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Sun, 24 Aug 2025 21:02:32 +0200 Subject: [PATCH 13/15] Marked test which uses fit method to require a trainable backend. --- keras/src/layers/reshaping/reshape_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/keras/src/layers/reshaping/reshape_test.py b/keras/src/layers/reshaping/reshape_test.py index 6fd3874c1e3e..823fb8fc672d 100644 --- a/keras/src/layers/reshaping/reshape_test.py +++ b/keras/src/layers/reshaping/reshape_test.py @@ -120,6 +120,7 @@ def test_reshape_sets_static_shape(self): # Also make sure the batch dim is not lost after reshape. self.assertEqual(reshaped.shape, (2, 3, 5)) + @pytest.mark.requires_trainable_backend def test_reshape_model_fit_with_varying_input_size_and_minus_one(self): def generator(): yield ( From c63392e8c7d8b72c4df6298960140f44212e3b87 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Mon, 25 Aug 2025 23:44:46 +0200 Subject: [PATCH 14/15] Docs: - Adapted according to review. - Additionally, replaced "length" with "size" when referring to total number of elements. --- keras/src/layers/reshaping/reshape.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/keras/src/layers/reshaping/reshape.py b/keras/src/layers/reshaping/reshape.py index be64381cdb8c..39d6ea3533e2 100644 --- a/keras/src/layers/reshaping/reshape.py +++ b/keras/src/layers/reshaping/reshape.py @@ -11,15 +11,12 @@ class Reshape(Layer): Args: target_shape: Target shape. Tuple of integers, does not include the - samples dimension (batch size). One element of the target_shape can - be -1 in which case the missing value is inferred from the length + samples dimension (batch size). One element of the `target_shape` can + be -1 in which case the missing value is inferred from the size of the array and remaining dimensions. Input shape: - Arbitrary, but required to be compatible with target shape. - Use the keyword argument `input_shape` (tuple of integers, - does not include the samples/batch size axis) when using this layer as - the first layer in a model. + Arbitrary, but required to be compatible with `target_shape`. Output shape: `(batch_size, *target_shape)` From fa108c691c7206ede8d1c46ed534d14adf508268 Mon Sep 17 00:00:00 2001 From: Axel Roebel Date: Mon, 25 Aug 2025 23:48:25 +0200 Subject: [PATCH 15/15] Fixed line length. --- keras/src/layers/reshaping/reshape.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keras/src/layers/reshaping/reshape.py b/keras/src/layers/reshaping/reshape.py index 39d6ea3533e2..46cfb3ec507e 100644 --- a/keras/src/layers/reshaping/reshape.py +++ b/keras/src/layers/reshaping/reshape.py @@ -11,9 +11,9 @@ class Reshape(Layer): Args: target_shape: Target shape. Tuple of integers, does not include the - samples dimension (batch size). One element of the `target_shape` can - be -1 in which case the missing value is inferred from the size - of the array and remaining dimensions. + samples dimension (batch size). One element of the `target_shape` + can be -1 in which case the missing value is inferred from the + size of the array and remaining dimensions. Input shape: Arbitrary, but required to be compatible with `target_shape`.