Paper · 2021-03-30 · cs.CV
Rethinking Spatial Dimensions of Vision Transformers
Pooling-based Vision Transformer (PiT) adds ResNet-style spatial reduction to ViT. Two depth-wise convolution pooling layers shrink the token grid (27, 14, 7 for the tiny to small models) while channels grow with the head count. Author-reported: PiT-S reaches 80.9% ImageNet top-1 with the DeiT recipe vs 79.8% for ViT-S, with fewer FLOPs.
Vision Transformer (ViT) backbonesHierarchical vision transformersKnowledge distillationarchitecturevision-transformerpoolingimage-classificationobject-detectionrobustness
arXivPDFCodeMarkdown13 min read
AI-compiled by claude-haiku-5-5 on 2026-10-24, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
A Vision Transformer (ViT) cuts a picture into small square patches and treats every patch the same way from the first layer to the last. Convolutional networks do something different: as they go deeper they make the picture smaller and give it more channels. That shrinking is a long-standing design habit, and ViT skips it.
This paper asks whether the habit helps transformers too. Its answer is a variant called PiT. It adds small pooling steps between groups of transformer layers. Each step makes the grid of patches coarser and widens the features, which lets the later layers work on a smaller map with more information per position.
The authors report that this makes the model better at the same compute cost, and that it generalizes better. It also does better on object detection and on a few robustness tests. Results are reported for the ImageNet classification benchmark and are the authors' own.
TL;DR
PiT inserts two pooling layers into ViT, so the token grid shrinks in two steps and the channel count grows. The pooling uses a depth-wise convolution for the spatial tokens and a linear layer for the class token. On ImageNet, PiT beats ViT at comparable or lower FLOPs and throughput is also higher, under the authors' settings. Use it when you need a ViT-style backbone at a fixed compute budget. Check the Pitfalls first: the paper's text and its code disagree on patch size for the base model.
Problem
ViT keeps the same number of spatial tokens in every layer §1. Its self-attention lets every token interact with every other, but the size of the area a token can attend to is still set by the token count, and the paper argues that a fixed grid lacks the reduction that makes CNNs generalize well §3.2. The authors report that ViT's validation accuracy stops improving as training accuracy rises, which they read as weak generalization at ImageNet scale §3.2 fig. 3.
Method
PiT is a ViT with two pooling layers. The layers split the sequence of transformer blocks into three stages with three spatial scales §3.2. The Transformer blocks work on the same token layout as ViT. Between stages, the pooling layer:
- turns the spatial tokens back into a 3-D map §3.2;
- applies a depth-wise convolution that halves the spatial size and increases the channels §3.2 fig. 4;
- flattens the map back into tokens for the next stage §3.2;
- passes the class token (which has no spatial position) through an extra fully connected layer that changes its channel count §3.2.
Channel growth is produced by adding attention heads: the channels of each stage are the base width times the head count of that stage §3.4 tab. 1. The paper also analyses ViT and PiT through two attention statistics. The first is the entropy of each attention map, the second is the mean spatial distance between a query token and the tokens it attends to, using relative positions §3.3 eq. 1 eq. 2. Both are averaged over validation images and heads, skip the class token and skip the final block §3.3. The paper reports this as a figure, not as numbers fig. 5.
# PiT forward pass [§3.2] [code: pit.py#L168-L187]
# Input: images (B, 3, 224, 224)
# Output: class logits (B, num_classes)
def pit_forward(images):
# Patch embedding: strided conv, patch 16, stride 8 in the text [§3.4]
feature_map = patch_embed(images) # (B, C0, 27, 27)
# Learned position embedding, added once before the first stage
# [code: pit.py#L102-L105] [code: pit.py#L171-L172]
feature_map = feature_map + pos_embed
# One learned class token per image [code: pit.py#L173]
class_tokens = expand(cls_token, batch_size) # (B, 1, C0)
for stage in range(num_pools):
# Transformer blocks on spatial plus class tokens [§3.2]
# [code: pit.py#L38-L51]
feature_map, class_tokens = transformer[stage](
feature_map, class_tokens)
# Pooling halves the spatial size and widens channels [§3.2]
# [code: pit.py#L64-L69]
feature_map, class_tokens = pool[stage](
feature_map, class_tokens)
# The last stage has no pooling after it [code: pit.py#L178]
feature_map, class_tokens = transformer[num_pools](
feature_map, class_tokens)
# LayerNorm is applied to the class token only [code: pit.py#L180]
class_tokens = layer_norm(class_tokens)
# Linear classifier on the first class token [code: pit.py#L186]
return head(class_tokens[:, 0])# Pooling layer between two stages [§3.2] [fig. 4]
# Input: feature_map (B, C0, H0, W0), class_tokens (B, n, C0)
# Output: feature_map (B, C1, H0/2, W0/2), class_tokens (B, n, C1)
def pool(feature_map, class_tokens):
# Depth-wise conv, kernel 3, stride 2, padding 1, groups C0
# Pattern from the code, not stated in the paper [code: pit.py#L59-L61]
feature_map = depthwise_conv(feature_map, groups=C0)
# Linear map on the class tokens; no spatial change [code: pit.py#L62]
# [code: pit.py#L66-L67]
class_tokens = linear(class_tokens)
return feature_map, class_tokensHyperparameters
Architecture: the paper gives the spatial size, block count, head count and channel width of each stage tab. 1. FLOPs are measured at 224 x 224 input §3.4. The code sets a base width per model (32 for Ti, 48 for XS and S, 64 for B) and multiplies it by the head count of each stage [code: pit.py#L214-L285].
| Model | Stage | Spatial size | # blocks | # heads | Channels | FLOPs | Source |
|---|---|---|---|---|---|---|---|
| ViT-Ti | - | 14 x 14 | 12 | 3 | 192 | 1.3B | tab. 1 |
| PiT-Ti | 1 / 2 / 3 | 27 x 27 / 14 x 14 / 7 x 7 | 2 / 6 / 4 | 2 / 4 / 8 | 64 / 128 / 256 | 0.7B | tab. 1 |
| PiT-XS | 1 / 2 / 3 | 27 x 27 / 14 x 14 / 7 x 7 | 2 / 6 / 4 | 2 / 4 / 8 | 96 / 192 / 384 | 1.4B | tab. 1 |
| ViT-S | - | 14 x 14 | 12 | 6 | 384 | 4.6B | tab. 1 |
| PiT-S | 1 / 2 / 3 | 27 x 27 / 14 x 14 / 7 x 7 | 2 / 6 / 4 | 3 / 6 / 12 | 144 / 288 / 576 | 2.9B | tab. 1 |
| ViT-B | - | 14 x 14 | 12 | 12 | 768 | 17.6B | tab. 1 |
| PiT-B | 1 / 2 / 3 | 31 x 31 / 16 x 16 / 8 x 8 | 3 / 6 / 4 | 4 / 8 / 16 | 256 / 512 / 1024 | 12.5B | tab. 1 |
Patch and embedding settings. The paper's text says patch size 16 and stride 8 for all PiT sizes §3.4. The code uses those values for Ti, XS and S, and patch 14 with stride 7 for B pit.py. Table 1 lists 31 x 31 for PiT-B, which matches the code's value and not the text's value (see Paper vs code).
| Name | Value | Where | Notes |
|---|---|---|---|
| input resolution | 224 x 224 | §3.4 tab. 1 | FLOPs and spatial sizes measured here |
| fine-tune resolution | 384 x 384 | tab. 4 | ViT-B and PiT-B only |
| patch size | 16 (Ti, XS, S); text for B | §3.4 | code uses 14 for B pit.py |
| embedding stride | 8 (Ti, XS, S); text for B | §3.4 | code uses 7 for B pit.py |
| pooling layers | 2 (3 scales) | §3.2 tab. 1 | |
| pooling stride | 2 | tab. 1 pit.py | spatial halving; stated only via tab. 1 sizes |
| pooling kernel and padding | kernel 3, padding 1 | pit.py | not stated in paper |
| MLP ratio | 4 | pit.py | not stated in paper |
| qkv bias | True | pit.py | not stated in paper |
| LayerNorm epsilon | 1e-6 | pit.py | not stated in paper |
| optimizer | AdamP | §4.1 | |
| learning rate, weight decay, warmup | not stated | §4.1 | "same as DeiT §4.1"; values are not in this paper |
| epochs, vanilla and CutMix | 100 | §4.1 | |
| epochs, DeiT and distillation | 300 | §4.1 | |
| epochs, long training | 1000 | tab. 4 | |
| Repeated Augment | Base models only | §4.1 | the paper found it hurt small models |
| distillation teacher | RegNetY-16GF | §4.1 | distillation token plus distillation loss |
| distillation loss form | not stated | §4.1 | cites Hinton et al.; soft or hard not said |
| training batch size | not stated | §4.1 | 128 is used only for throughput |
| throughput hardware | 1 x NVIDIA V100, batch 128 | §4.1 | images per second |
| detection backbone | Deformable DETR, two-stage, box refinement | §4.2 | |
| detection epochs and LR drop | 50 epochs, x0.1 at epoch 40 | §4.2 | |
| detection image size | half of the original | §4.2 | exact size not stated |
| detection ViT-S features | layers 2, 8 and 12 | §4.2 | matches PiT pooling positions |
| occlusion benchmark | centre 112 x 112 zeroed | §4.3 | |
| attention analysis | val set, all heads, no class token, no last block | §3.3 | |
| dropout, drop-path | not stated for training | pit.py | constructor defaults are 0.0 |
| weight init | trunc-normal (0.02) on position and class tokens | pit.py | other layers keep framework defaults |
Results
Author-reported. ImageNet-1k classification at 224 x 224 unless noted. The vanilla, CutMix, DeiT and distillation columns are four training settings §4.1. FLOPs and throughput are in the paper's units. Throughput was measured on one V100 with batch 128 §4.1.
ImageNet, same training recipe as ViT tab. 2
| Architecture | FLOPs | # params | Throughput (img/s) | Vanilla | +CutMix | +DeiT | +Distill |
|---|---|---|---|---|---|---|---|
| ViT-Ti | 1.3 B | 5.7 M | 2564 | 68.7% | 68.5% | 72.2% | 74.5% |
| PiT-Ti | 0.7 B | 4.9 M | 3030 | 71.3% | 72.6% | 73.0% | 74.6% |
| PiT-XS | 1.4 B | 10.6 M | 2128 | 72.4% | 76.8% | 78.1% | 79.1% |
| ViT-S | 4.6 B | 22.1 M | 980 | 68.7% | 76.5% | 79.8% | 81.2% |
| PiT-S | 2.9 B | 23.5 M | 1266 | 73.3% | 79.0% | 80.9% | 81.9% |
| ViT-B | 17.6 B | 86.6 M | 303 | 69.3% | 75.3% | 81.8% | 83.4% |
| PiT-B | 12.5 B | 73.8 M | 348 | 76.1% | 79.9% | 82.0% | 84.0% |
Comparison with CNNs and ViT, best reported settings tab. 3
Throughput was re-measured on the same V100 §4.1. Entries marked with a dagger use distillation.
| Architecture | # params | Throughput (img/s) | Accuracy |
|---|---|---|---|
| ResNet18 | 11.7M | 4545 | 72.5% |
| MobileNetV2 | 3.5M | 3846 | 72.0% |
| MobileNetV3 | 5.5M | 3846 | 75.2% |
| EfficientNet-B0 | 5.3M | 2857 | 77.1% |
| ViT-Ti | 5.7M | 2564 | 72.2% |
| PiT-Ti | 4.9M | 3030 | 73.0% |
| ViT-Ti dagger | 5.7M | 2564 | 74.5% |
| PiT-Ti dagger | 4.9M | 3030 | 74.6% |
| ResNet34 | 21.8M | 2631 | 75.1% |
| ResNet34D | 21.8M | 2325 | 77.1% |
| EfficientNet-B1 | 7.8M | 1754 | 79.1% |
| PiT-XS | 10.6M | 2128 | 78.1% |
| PiT-XS dagger | 10.6M | 2128 | 79.1% |
| ResNet50 | 25.6M | 1266 | 80.2% |
| ResNet101 | 44.6M | 757 | 81.6% |
| ResNet50D | 25.6M | 1176 | 80.5% |
| EfficientNet-B2 | 9.2M | 1333 | 80.1% |
| EfficientNet-B3 | 12.2M | 806 | 81.6% |
| RegNetY-4GF | 20.6M | 1136 | 79.4% |
| ResNeSt50 | 27.5M | 877 | 81.1% |
| ViT-S | 22.1M | 980 | 79.8% |
| PiT-S | 23.5M | 1266 | 80.9% |
| ViT-S dagger | 22.1M | 980 | 81.2% |
| PiT-S dagger | 23.5M | 1266 | 81.9% |
| ResNet152 | 60.2M | 420 | 81.9% |
| ResNet101D | 44.6M | 354 | 83.0% |
| ResNet152D | 60.2M | 251 | 83.7% |
| EfficientNet-B4 | 19.3M | 368 | 82.9% |
| RegNetY-16GF | 83.6M | 352 | 80.4% |
| ResNeSt101 | 48.3M | 398 | 83.0% |
| ViT-B | 86.6M | 303 | 81.8% |
| PiT-B | 73.8M | 348 | 82.0% |
| ViT-B dagger | 86.6M | 303 | 83.4% |
| PiT-B dagger | 73.8M | 348 | 84.0% |
Longer training and larger resolution tab. 4
| Setting | Architecture | Throughput (img/s) | Accuracy |
|---|---|---|---|
| Long training, 1000 epochs | ViT-Ti dagger | 2564 | 76.6% |
| Long training, 1000 epochs | PiT-Ti dagger | 3030 | 76.4% |
| Long training, 1000 epochs | PiT-XS dagger | 2128 | 80.6% |
| Long training, 1000 epochs | ViT-S dagger | 980 | 82.6% |
| Long training, 1000 epochs | PiT-S dagger | 1266 | 82.7% |
| Long training, 1000 epochs | ViT-B dagger | 303 | 84.2% |
| Long training, 1000 epochs | PiT-B dagger | 348 | 84.5% |
| 384 x 384 fine-tune | ViT-B | 91 | 83.1% |
| 384 x 384 fine-tune | PiT-B | 82 | 83.0% |
| 384 x 384 fine-tune | ViT-B dagger | 91 | 84.5% |
| 384 x 384 fine-tune | PiT-B dagger | 82 | 84.6% |
COCO object detection, Deformable DETR, half resolution tab. 5
Latency is single-image, on a random noise image at 600 x 400 §4.2.
| Backbone | AP | AP50 | AP75 | Params | Latency (ms / img) |
|---|---|---|---|---|---|
| ResNet50 | 41.5 | 60.5 | 44.3 | 41.0 M | 49.7 |
| ViT-S | 36.9 | 57.0 | 38.0 | 34.9 M | 55.2 |
| PiT-S | 39.4 | 58.8 | 41.5 | 36.6 M | 46.9 |
ImageNet robustness tab. 6
The caption names PiT-B, but the PiT row is labelled PiT-S and the text matches PiT-S (see Paper vs code).
| Model | Standard | Occ | IN-A | BGC | FGSM |
|---|---|---|---|---|---|
| PiT-S | 80.8 | 74.6 | 21.7 | 21.0 | 29.5 |
| ViT-S | 79.8 | 73.0 | 19.1 | 17.6 | 27.2 |
| ResNet50 | 76.0 | 52.2 | 0.0 | 22.3 | 7.1 |
| ResNet50 dagger | 79.0 | 67.1 | 5.4 | 32.7 | 24.7 |
Headline claims, as the paper states them: PiT beats ViT in every robustness benchmark despite similar standard accuracy §4.3; PiT-S beats the ViT-S detector by 2.5 AP tab. 5; and at 384 x 384 fine-tuning PiT does not beat ViT §4.1 tab. 4. The paper says PiT is superior to ViT in the vanilla and CutMix settings, and comparable or better under the DeiT and distillation settings §4.1.
Paper vs code
The official code is naver-ai/pit, linked from the abstract.
It was cloned at commit 9d97a62e6a2a72a86685003998fcae700f952e18. The
repository contains only the model definitions in pit.py, plus a README. It
has no training script, no evaluation script and no attention-analysis script.
Pretrained weights are linked from the README, not in the repo.
- Patch size and stride for PiT-B. The paper's text says patch 16 and
stride 8 for all PiT sizes §3.4. The code uses patch 14 and stride 7 for
pit_bandpit_b_distilledpit.py pit.py. Table 1 lists 31 x 31 spatial size for PiT-B tab. 1. The code's values give a 31 x 31 map at 224 input, and the text's values give 27 x 27. The code therefore matches Table 1. Follow the code for B. - Position embedding. The paper does not describe a position embedding. The code adds a learned position embedding of shape (1, C0, H0, W0) to the feature map before the first stage pit.py [code: pit.py#L171-L172]. It is not pooled again.
- Class token pooling. The paper says a fully connected layer adjusts the class token §3.2. The code uses a plain linear layer with bias, with no activation pit.py pit.py.
- Pooling convolution details. The paper says depth-wise convolution §3.2 fig. 4. The code uses kernel 3, stride 2, padding 1, and groups equal to the input channels, with a bias pit.py. With groups equal to the input channels and more output channels, each input channel feeds several outputs. The paper does not give kernel size or padding.
- Final normalization. The code applies LayerNorm to the class token only, after the last stage pit.py. The spatial tokens are not normalized before the classifier. The paper does not say this.
- Distillation head. The paper describes a distillation token trained with a distillation loss §4.1. The code keeps two class tokens and two linear heads pit.py. In training it returns both logits. In evaluation it returns the average of the two logits pit.py. The paper does not mention averaging at test time. The distillation loss itself is not in the repo.
- Initialization. The code initializes position and class tokens with a truncated normal (std 0.02) and LayerNorm to weight 1 and bias 0 [code: pit.py#L145-L152]. Linear and convolution layers keep the framework default. The paper does not state an initialization.
- Transformer block. The code builds each block from timm's
vision_transformer.Blockwithqkv_bias=True, MLP ratio 4 and LayerNorm epsilon 1e-6 pit.py. Activation and normalization placement therefore come from timm, which is an external dependency. The paper does not state these. I did not check timm's source. - FLOPs units. The paper's tables write FLOPs in B tab. 1 tab. 2. The README writes 0.71 G for PiT-Ti, and the paper writes 0.7 B. The values agree.
- Training recipe. The paper defers the learning rate, weight decay and warmup to the DeiT paper §4.1. The repository has no training code, so these values cannot be checked here.
The repository was taken from the link in the abstract, so no GitHub search was needed and no third-party reimplementation was used. Apart from the items above, I found no discrepancies between the paper's text and the code.
Pitfalls
- Patch size for PiT-B. Text and code disagree (see Paper vs code). Table 1 matches the code. A model built from the text alone gets the wrong grid for B.
- Attention normalization axis. The paper defines attention values with "sum over i of alpha_ij = 1" §3.3. The usual softmax normalizes each query row over keys. The paper's axis is the transpose. Which axis the softmax runs over is not stated in the text, so check both conventions against the entropy values in fig. 5.
- Matrix sizes. The paper writes A as M x N but then sums over N tokens with 1/N eq. 1 eq. 2. The dimension names are not tied to the query and key axes. The log base in the entropy is not stated.
- Attention distance uses relative coordinates. Positions are (x/W, y/H), and the distance is an L1 norm between them §3.3 eq. 2. A pixel-based distance would give different numbers.
- Pooling convolution is not fully specified. Kernel size, padding, bias and groups are not stated. The code uses kernel 3, padding 1, depth-wise groups and a bias pit.py.
- Hidden cost at 384 x 384. PiT-B throughput falls to 82 img/s against 91 for ViT-B at 384 x 384 tab. 4. The paper says the design targets 224 x 224 §4.1. Do not assume the saving carries to larger inputs.
- Gains depend on the recipe. At the vanilla setting PiT-S leads ViT-S by 4.6 points (73.3 vs 68.7). With full DeiT plus distillation the lead is 0.7 points (81.9 vs 81.2) tab. 2. Compare on the same recipe.
- Small models trail CNNs. The paper says CNNs at the Ti scale beat ViT-Ti and PiT-Ti §4.1 tab. 3.
- Detection does not beat ResNet50. PiT-S detector is 2.1 AP below ResNet50 but has lower latency tab. 5 §4.2.
- Resolution for detection. The paper halves the image resolution for all backbones and does not state the exact size §4.2. Results are not directly comparable to standard COCO numbers.
- Mixed measurement setups. Table 3 mixes CNN numbers reported by other papers with throughput the authors re-measured §4.1. Accuracy for CNNs uses their best published setting, while PiT and ViT use the DeiT-style recipe.
- Single numbers. Results are single runs as far as the paper reports. No variance is given.
- Architecture search. PiT was not chosen by neural architecture search, and the authors say it could improve with one §3.4.
- Figure-number references. Figure and table numbers in this card follow the order of the LaTeX source, not a compiled PDF. Fig. 1 is the schematic in the introduction. Fig. 2 is the ResNet experiment in related work. Fig. 3 is the ViT experiment in section 3, fig. 4 the pooling layer, fig. 5 the attention plots.
Lineage
- Builds on: ViT, the transformer baseline it modifies §1; the DeiT training recipe and distillation method used for the main tables §4.1.
- Motivated by: CNN dimension conventions with stride-2 downsampling and pooling, which the paper reviews §2.
- Compared against: ResNet, MobileNet, EfficientNet, RegNet and ResNeSt on ImageNet tab. 3; Deformable DETR detection with ViT-S backbone tab. 5; ViT-S and ResNet50 on robustness tab. 6.
- Superseded by: not stated.
Source and license
Adapted from “Rethinking Spatial Dimensions of Vision Transformers” by Byeongho Heo, Sangdoo Yun, Dongyoon Han, Sanghyuk Chun, Junsuk Choe, Seong Joon Oh (arXiv:2103.16302), used under CC BY-SA 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. This page is licensed under CC BY-SA 4.0. Code citations refer to https://github.com/naver-ai/pit at commit 9d97a62e6a2a (Apache-2.0). Any quoted code is shown under that license.