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=({D},{H},{W}), grid=({gD},{gH},{gW}), size=({pD},{pH},{pW}).

What it means

With padding='valid', 3D reconstruct_tiles patches with no crop, so output_size must equal grid*patch on every axis: (D,H,W)==(gD*pD, gH*pH, gW*pW). Any mismatch raises.

Source

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

                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_d = gD * pD - D
        pad_total_h = gH * pH - H
        pad_total_w = gW * pW - W
        begin = [
            0,
            pad_total_d // 2,
            pad_total_h // 2,
            pad_total_w // 2,
            0,
        ]
        out_shape = [B, D, H, W, C]
        x = ops.slice(x, begin, out_shape)
    else:
        if gD * pD != D or gH * pH != H or gW * pW != W:
            raise ValueError(
                f"`padding='valid'` requires output_size to equal "
                f"size * grid. Got output_size=({D},{H},{W}), "
                f"grid=({gD},{gH},{gW}), size=({pD},{pH},{pW})."
            )

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


class MapCoordinates(Operation):
    def __init__(self, order, fill_mode="constant", fill_value=0, *, name=None):
        super().__init__(name=name)
        self.order = order
        self.fill_mode = fill_mode
        self.fill_value = fill_value

    def call(self, inputs, coordinates):

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Compute output_size from the patches grid: (gD*pD, gH*pH, gW*pW)
  2. If extraction used 'same', pass padding='same' with the original volume size
  3. Print patches.shape and size, then assert equality per axis

Example fix

# before
reconstruct_patches(p, size=(4,8,8), output_size=(10,28,28))

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

Strategy: validation

Validate before calling

gD, gH, gW = patches.shape[1], patches.shape[2], patches.shape[3]
expected = (gD*size[0], gH*size[1], gW*size[2])
assert tuple(output_size) == expected, f'{output_size} != {expected}'

Type guard

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

Prevention

When it happens

Trigger: reconstruct_patches(..., padding='valid') (default) on 3D patches with any axis of output_size != grid*patch for that axis.

Common situations: Default padding forgotten while passing the original same-padded volume size; extracting with 'same' but reconstructing with 'valid'; per-axis dimension mix-ups in (D,H,W).

Related errors


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