huggingface/pytorch-image-models · error · ValueError
Cannot pool {N} tokens with k={k}: N must be divisible by k^
Error message
Cannot pool {N} tokens with k={k}: N must be divisible by k^2={k_squared}. Both grid dimensions must be divisible by k. What it means
Gemma4ViT's soft pooling (global_pool='soft') average-pools k x k blocks of patch tokens, so the token count N must be divisible by k^2 (pooling_kernel_size squared). If the sequence length does not evenly tile into k-by-k cells, pooling is geometrically undefined and ValueError is raised in _avg_pool_by_positions.
Source
Thrown at timm/models/gemma4_vit.py:579
self.root_hidden_size = hidden_size**0.5
self.pooling_kernel_size = pooling_kernel_size
def _avg_pool_by_positions(
self,
hidden_states: torch.Tensor,
position_ids: torch.Tensor,
) -> Tuple[torch.Tensor, torch.Tensor]:
"""2D spatial pooling on a ``k × k`` grid (k = ``self.pooling_kernel_size``).
``N`` patches are binned into ``k^2``-sized cells, so the pool requires
``N % k^2 == 0`` (caller ensures both grid dims divide by k upstream).
``position_ids`` follows the Gemma4-internal ``(x, y)`` convention.
"""
N = hidden_states.shape[1]
k = self.pooling_kernel_size
k_squared = k * k
if N % k_squared != 0:
raise ValueError(
f"Cannot pool {N} tokens with k={k}: N must be divisible by k^2={k_squared}. "
f"Both grid dimensions must be divisible by k."
)
output_length = N // k_squared
clamped_positions = position_ids.clamp(min=0)
max_x = clamped_positions[..., 0].max(dim=-1, keepdim=True)[0] + 1
kernel_idxs = torch.div(clamped_positions, k, rounding_mode='floor')
kernel_idxs = kernel_idxs[..., 0] + (max_x // k) * kernel_idxs[..., 1]
weights = F.one_hot(kernel_idxs.long(), output_length).float() / k_squared
output = weights.transpose(1, 2) @ hidden_states.float()
mask = torch.logical_not((weights == 0).all(dim=1))
return output.to(hidden_states.dtype), mask
def forward(
self,
hidden_states: torch.Tensor,View on GitHub (pinned to 9a5261e31b)
Solutions
- Resize/crop the input so H and W are multiples of patch_size * pooling_kernel_size (e.g. multiples of 48 for patch 16, k=3)
- Or switch pooling: create the model with global_pool='avg' or 'none', which does not require grid alignment
- Pad the image to the next valid multiple before inference
Example fix
# before
model = timm.create_model('gemma4_vit_soft', pretrained=True)
out = model(torch.randn(1, 3, 224, 224)) # 224 % 48 != 0 -> error
# after
model = timm.create_model('gemma4_vit_soft', pretrained=True)
out = model(torch.randn(1, 3, 240, 240)) # 240 divisible by 48 Defensive patterns
Strategy: validation
Validate before calling
cell = model.patch_size[0] * model.pooling_kernel_size # e.g. 16*3=48
H, W = img.shape[-2:]
if H % cell or W % cell:
H2, W2 = (H // cell + 1) * cell, (W // cell + 1) * cell
img = F.pad(img, (0, W2 - W, 0, H2 - H))
out = model(img) Try / catch
try:
out = model(x)
except ValueError as e:
if 'divisible by k^2' in str(e) or 'divisible' in str(e):
x = F.interpolate(x, size=(round_up(H, 48), round_up(W, 48)))
out = model(x)
else:
raise Prevention
- Precompute the pooling cell size (patch_size * pooling_kernel_size) in preprocessing
- Snap training/inference resolutions to multiples of the cell
- Offer a global_pool='avg' fallback config for arbitrary-size inputs
When it happens
Trigger: Calling forward on a Gemma4ViT with global_pool='soft' (the default for these models) where the input image's H and W are divisible by patch_size but not by patch_size * pooling_kernel_size, e.g. 224px input with patch 16 and k=3 (needs multiples of 48).
Common situations: Fine-tuning at a different resolution than pretraining (e.g. 224 instead of 384) without respecting the pooling grid; NaFlex variable-resolution inputs that happen to be off-grid; test images with odd dimensions.
Related errors
- Image size ({H}, {W}) must be divisible by (patch_size * poo
- Input image must have positive dimensions, got H={height}, W
- Expected input ndim in (3, 4, 5); got {x.ndim}.
- patch_coord is required for pre-patchified input.
- Gemma4VitEncoder does not support classification use cases.
AI-assisted analysis of huggingface/pytorch-image-models@9a5261e31b (2026-08-27).
Data as JSON: /api/errors/279b6d6e7637099c.
Report an issue: GitHub.