keras-team/keras · error · ValueError

`padding='valid'` requires output_size to equal size * grid.

Error message

`padding='valid'` requires output_size to equal size * grid. Got output_size=({H},{W}), grid=({gH},{gW}), size=({pH},{pW}).

What it means

With padding='valid' (the default), reconstruct_patches (2D) tiles patches back with no padding to crop, so the result is exactly grid*patch per axis. The op raises when output_size != (gH*pH, gW*pW), since that size cannot be produced from this patch grid.

Source

Thrown at keras/src/ops/image.py:1308

                f"Got: gH={static_gH}, pH={pH}."
            )
        if isinstance(static_gW, int) and not (
            static_gW * pW - pW < W <= static_gW * pW
        ):
            raise ValueError(
                f"For `padding='same'`, `output_size` width ({W}) must "
                f"be in the range ((gW-1)*pW, gW*pW], i.e. "
                f"({static_gW * pW - pW}, {static_gW * pW}]. "
                f"Got: gW={static_gW}, pW={pW}."
            )
        pad_total_h = gH * pH - H
        pad_total_w = gW * pW - W
        begin = [0, pad_total_h // 2, pad_total_w // 2, 0]
        out_shape = [B, H, W, C]
        x = ops.slice(x, begin, out_shape)
    else:
        if gH * pH != H or gW * pW != W:
            raise ValueError(
                f"`padding='valid'` requires output_size to equal "
                f"size * grid. Got output_size=({H},{W}), "
                f"grid=({gH},{gW}), size=({pH},{pW})."
            )

    if _unbatched:
        x = backend.numpy.squeeze(x, axis=0)
    return x


def _reconstruct_patches_3d(
    patches,
    size,
    output_size,
    strides=None,
    padding="valid",
    data_format=None,
):

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Derive output_size from the patches tensor: (gH*pH, gW*pW) with gH,gW = patches.shape[1], patches.shape[2]
  2. If patches were extracted with padding='same', pass padding='same' and the original image size
  3. Verify strides: with strides<size the grid*patch exceeds the image and 'same' is required to crop

Example fix

# before
reconstruct_patches(patches, size=(8,8), output_size=(28,28))

# after
gH, gW = patches.shape[1], patches.shape[2]
reconstruct_patches(patches, size=(8,8), output_size=(gH*8, gW*8))
Defensive patterns

Strategy: validation

Validate before calling

gH, gW = patches.shape[1], patches.shape[2]
output_size = (gH*size[0], gW*size[1])  # valid: derive, don't guess

Type guard

def valid_size_consistent(patches, size, output_size) -> bool:
    return (patches.shape[1]*size[0], patches.shape[2]*size[1]) == tuple(output_size)

Prevention

When it happens

Trigger: reconstruct_patches(patches, size, output_size) (padding defaults to 'valid') with output_size not equal to (gH*pH, gW*pW), e.g. (B,4,4,64) patches, size=(8,8), output_size=(28,28) instead of (32,32).

Common situations: Forgetting the default is 'valid' and passing the original same-padded image size; extracting with padding='same' but reconstructing with 'valid'; using non-overlapping strides and assuming output equals original image size.

Related errors


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