huggingface/pytorch-image-models · error · ValueError
Image size ({H}, {W}) must be divisible by (patch_size * poo
Error message
Image size ({H}, {W}) must be divisible by (patch_size * pooling_kernel_size) = ({cell_h}, {cell_w}) when global_pool='soft'. Resize to multiples of ({cell_h}, {cell_w}), or use global_pool='avg'/'none'. What it means
Gemma4ViT's forward paths assert the raw image is conformant with soft pooling: H and W must each be divisible by patch_size * pooling_kernel_size (the pooling cell). _assert_raw_img_conformant runs in forward_features/forward/forward_intermediates and raises with the exact required cell dimensions when the raw image is off-grid.
Source
Thrown at timm/models/gemma4_vit.py:816
reversible and checkpoint-safe).
"""
for mod in self.modules():
if isinstance(mod, Gemma4ClippableLinear):
mod.use_clipped = enabled
def _assert_raw_img_conformant(self, x: torch.Tensor) -> None:
"""When using the soft-token pooler, raw-image H/W must divide
by ``patch_size * pooling_kernel_size`` so the pool cell grid is integral.
Pre-patchified / NaFlex inputs are assumed to be conformant already.
"""
if x.ndim != 4 or self.global_pool != 'soft':
return
H, W = x.shape[-2:]
ph, pw = self.patch_size
k = self.pooling_kernel_size
cell_h, cell_w = ph * k, pw * k
if H % cell_h != 0 or W % cell_w != 0:
raise ValueError(
f"Image size ({H}, {W}) must be divisible by "
f"(patch_size * pooling_kernel_size) = ({cell_h}, {cell_w}) when global_pool='soft'. "
f"Resize to multiples of ({cell_h}, {cell_w}), or use global_pool='avg'/'none'."
)
def _encode(
self,
x: torch.Tensor,
position_ids: torch.Tensor,
padding_positions: torch.Tensor,
block_callback: Optional[Callable[[int, torch.Tensor], None]] = None,
max_block_index: Optional[int] = None,
) -> torch.Tensor:
"""RoPE + transformer-block pipeline over already-embedded tokens."""
B, N = x.shape[:2]
rope_cos, rope_sin = self.rotary_emb(x, position_ids)
attn_mask: Optional[torch.Tensor] = NoneView on GitHub (pinned to 9a5261e31b)
Solutions
- Resize/pad inputs to multiples of the reported cell (cell_h, cell_w) shown in the message
- Use global_pool='avg' or 'none' when arbitrary resolutions must be supported
- Validate image dims in the preprocessing step and reject or pad non-conformant sizes
Example fix
# before img = F.interpolate(img, size=(500, 500)) out = model(img) # 500 % 48 != 0 # after img = F.interpolate(img, size=(480, 480)) # multiple of 48 out = model(img)
Defensive patterns
Strategy: validation
Validate before calling
ph, pw = model.patch_size
cell = (ph * model.pooling_kernel_size, pw * model.pooling_kernel_size)
H, W = img.shape[-2:]
if H % cell[0] or W % cell[1]:
img = F.interpolate(img, size=((H // cell[0] + 1) * cell[0], (W // cell[1] + 1) * cell[1]))
out = model(img) Try / catch
try:
out = model(img)
except ValueError as e:
if 'must be divisible by' in str(e):
out = model(F.interpolate(img, size=(384, 384), mode='bilinear'))
else:
raise Prevention
- Validate image dimensions against patch_size*k in the dataloader
- Resize or pad uploads to valid multiples before inference
- Create an avg-pooled model variant for unconstrained-resolution use cases
When it happens
Trigger: Calling any forward method with global_pool='soft' active and a raw (B,C,H,W) image whose H or W is not a multiple of patch_size*k (e.g. 512 with cell 48).
Common situations: Deploying on arbitrary user-uploaded image sizes; fine-tuning with a resolution valid for the patch size but not the pooling grid; switching from avg-pooled to soft-pooled checkpoints without resizing the data pipeline.
Related errors
- Cannot pool {N} tokens with k={k}: N must be divisible by k^
- Input image must have positive dimensions, got H={height}, W
- All scheduled batch sizes must be positive integers.
- num_batches must be a positive integer when specified.
- A progressive schedule requires at least two choices.
AI-assisted analysis of huggingface/pytorch-image-models@9a5261e31b (2026-08-27).
Data as JSON: /api/errors/e7a2beebdceea71f.
Report an issue: GitHub.