{"record":{"id":"c8bab2a7cbba6f73","repo":"huggingface/pytorch-image-models","slug":"expected-input-ndim-in-3-4-5-got-x-ndim","errorCode":null,"errorMessage":"Expected input ndim in (3, 4, 5); got {x.ndim}.","messagePattern":"Expected input ndim in \\(3, 4, 5\\); got (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"timm/models/gemma4_vit.py","lineNumber":320,"sourceCode":"        ph, pw = self.patch_size\n        if x.ndim == 4:\n            # Raw (B, C, H, W): patchify to C-Ph-Pw (Gemma4 native layout).\n            B, _, H, W = x.shape\n            if patch_coord is None:\n                patch_coord, patch_valid = self._default_patch_coord(B, H // ph, W // pw, x.device)\n            x, _ = batch_patchify(x, (ph, pw), pad=False, channels_last=False)  # (B, N, C*Ph*Pw)\n        elif x.ndim == 5:\n            # (B, N, Ph, Pw, C) pre-patchified unflattened (NaFlex loader convention).\n            # Permute channels in from last to second to produce C-Ph-Pw flat.\n            x = x.permute(0, 1, 4, 2, 3).reshape(x.shape[0], x.shape[1], -1)\n        elif x.ndim == 3:\n            # (B, N, Ph*Pw*C) pre-patchified flat in NaFlex P-P-C layout; reinterpret as\n            # (B, N, Ph, Pw, C) then permute to C-Ph-Pw flat so input_proj matches layout.\n            B, N, PPC = x.shape\n            C = PPC // (ph * pw)\n            x = x.view(B, N, ph, pw, C).permute(0, 1, 4, 2, 3).reshape(B, N, PPC)\n        else:\n            raise ValueError(\n                f\"Expected input ndim in (3, 4, 5); got {x.ndim}.\"\n            )\n\n        if patch_coord is None:\n            raise ValueError(\"patch_coord is required for pre-patchified input.\")\n\n        if patch_valid is None:\n            sentinel = (patch_coord == -1).all(dim=-1)\n            if sentinel.any():\n                patch_valid = ~sentinel\n            else:\n                patch_valid = torch.ones(\n                    patch_coord.shape[:2], dtype=torch.bool, device=patch_coord.device,\n                )\n\n        # Scale [0, 1] pixels to [-1, 1] (matches original Gemma4's `2 * (pixel_values - 0.5)`)\n        x = 2 * (x - 0.5)\n        x = self.input_proj(x.to(self.input_proj.weight.dtype))","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/huggingface/pytorch-image-models/blob/9a5261e31b3b5128526eb2658333b4c0a54464ae/timm/models/gemma4_vit.py#L302-L338","documentation":"Gemma4Vit (NaFlex ViT supporting variable-resolution patchified input) accepts only 3D, 4D, or 5D tensors in patch embedding forward: (B,N,Ph*Pw*C) pre-patchified, image-like, or (B,C,Ph,Pw,N) layouts. Any other rank raises ValueError with the observed ndim.","triggerScenarios":"Calling model.forward_features / forward on Gemma4ViT with a 2D or 6D tensor, e.g. flattened (N, C) embeddings or a double-batched 6D array.","commonSituations":"Pipeline bugs where tensors are squeezed/unsqueezed incorrectly (loss of batch dim making input 3D image-like when pre-patchified 3D expected, or extra dims from video (B,T,C,H,W)); feeding raw embeddings instead of images or patch grids.","solutions":["Check x.ndim and x.shape before calling the model; add/collapse the batch dimension so ndim is 3-5","For raw images pass (B, C, H, W) (4D); for pre-patchified input pass (B, N, Ph*Pw*C) with patch_coord","Log shapes at the boundary of your data pipeline to find where the rank changes"],"exampleFix":"# before\nfeats = model(x)  # x.shape == (C, H, W), ndim=3 image-like mixed up with patch input\n# after\nx = x.unsqueeze(0)  # (1, N, Ph*Pw*C) pre-patchified, ndim=3 with patch_coord passed\nfeats = model(x, patch_coord=coords)","handlingStrategy":"type-guard","validationCode":"assert x.ndim in (3, 4, 5), f'expected ndim 3-5, got {x.ndim}'\nif x.ndim == 3:\n    assert patch_coord is not None, '3D pre-patchified input requires patch_coord'\nout = model(x, patch_coord=patch_coord)","typeGuard":"def is_valid_gemma4_input(x: torch.Tensor) -> bool:\n    return isinstance(x, torch.Tensor) and x.ndim in (3, 4, 5)","tryCatchPattern":"try:\n    out = model(x)\nexcept ValueError as e:\n    if 'Expected input ndim' in str(e):\n        raise ValueError(f'pipeline produced ndim={x.ndim}; check squeeze/unsqueeze ops') from e\n    raise","preventionTips":["Assert tensor rank at model boundaries in debug builds","Keep (image, patch_coord, patch_valid) bundled in a dataclass to avoid rank confusion","Unit-test preprocessing with representative shapes"],"tags":["timm","gemma4-vit","tensor-shape","input-validation"],"backgroundTag":"invalid-input-tensor-rank","analyzedSha":"9a5261e31b3b5128526eb2658333b4c0a54464ae","analyzedAt":"2026-08-27T02:34:25.417Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}