keras-team/keras · error · ValueError

Expected the input image to be rank 3 or 4. Received inputs.

Error message

Expected the input image to be rank 3 or 4. Received inputs.shape={images_shape}

What it means

RandomBrightness.get_random_transformation computes a brightness delta shaped by input rank: rank 3 (single image) or rank 4 (batched). Images of any other rank (e.g. rank 2 grayscale without channels, or rank 5) raise this ValueError.

Source

Thrown at keras/src/layers/preprocessing/image_preprocessing/random_brightness.py:104

                + f"Received: value_range={value_range}"
            )
        self.value_range = sorted(value_range)

    def get_random_transformation(self, data, training=True, seed=None):
        if isinstance(data, dict):
            images = data["images"]
        else:
            images = data
        images_shape = self.backend.shape(images)
        rank = len(images_shape)
        if rank == 3:
            rgb_delta_shape = (1, 1, 1)
        elif rank == 4:
            # Keep only the batch dim. This will ensure to have same adjustment
            # with in one image, but different across the images.
            rgb_delta_shape = [images_shape[0], 1, 1, 1]
        else:
            raise ValueError(
                "Expected the input image to be rank 3 or 4. Received "
                f"inputs.shape={images_shape}"
            )
        if not training:
            return {"rgb_delta": self.backend.numpy.zeros(rgb_delta_shape)}

        if seed is None:
            seed = self._get_seed_generator(self.backend._backend)
        rgb_delta = self.backend.random.uniform(
            minval=self.factor[0],
            maxval=self.factor[1],
            shape=rgb_delta_shape,
            seed=seed,
        )
        rgb_delta = rgb_delta * (self.value_range[1] - self.value_range[0])
        return {"rgb_delta": rgb_delta}

    def transform_images(self, images, transformation, training=True):

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Add a channel axis: images[..., None] for grayscale rank-2 inputs
  2. Remove stray leading dims: images = np.squeeze(images, axis=0)
  3. Feed (H, W, C) or (batch, H, W, C) consistently

Example fix

# before
images = np.array(img.convert('L'))  # (H, W) rank 2
out = layer(images)
# after
images = np.array(img.convert('L'))[..., None]  # (H, W, 1)
out = layer(images)
Defensive patterns

Strategy: validation

Validate before calling

if len(images.shape) == 2:
    images = images[..., None]
assert len(images.shape) in (3, 4), images.shape

Type guard

def is_rank3or4(x):
    return len(getattr(x, 'shape', ())) in (3, 4)

Prevention

When it happens

Trigger: Calling the layer on a (224, 224) grayscale array with no channel axis, or a rank-5 tensor from an extra batch dim.

Common situations: Grayscale images loaded without keepdims, e.g. PIL Image.convert('L') then np.array giving (H, W); stacking an already-batched tensor.

Related errors


AI-assisted analysis of keras-team/keras@7a34a03db6 (2026-08-25). Data as JSON: /api/errors/44fa25b29e97dbe0. Report an issue: GitHub.