Hierarchical and efficient vision backbones
A vision backbone is the network that turns an image into feature vectors for a task head to read. A classifier needs one vector for the whole image, but a detector or a segmenter needs a vector for every region, at several sizes, because the objects it must find come in every size. This section builds backbones that give exactly that, a stack of feature maps from fine to coarse, at a cost that grows only linearly with the number of pixels. Almost every detection, segmentation, and video model you will build or be asked about sits on one of them.
Start with what a plain Vision Transformer (ViT) gives you. §27.2 built it. It cuts the image into 16 by 16 pixel patches, turns each patch into a token, and runs a stack of identical Transformer blocks on the sequence. It also counted the cost in multiply-adds (MACs). One multiply-add is one multiplication plus one addition, and it is the unit that vision papers report as "FLOPs". A block on tokens of width costs multiply-adds in its linear layers, the four attention projections and an MLP that widens to . Attention itself, the scores and the weighted sum, costs .
Now ask ViT-B/16, the base model with width 768 and 12 blocks, to segment a 1024 by 1024 street scene. The cell adds up the cost at three resolutions.
So the question is whether a Transformer can give what the ResNet gives, maps at several scales for a cost linear in the image area. This section answers yes, in three ways, and then asks which to choose.
- The Swin Transformer attends only inside small windows, shifts the windows between layers so that information crosses their borders, and merges neighboring tokens between stages.
- ConvNeXt asks how much of Swin's success came from attention at all. It rebuilds a ResNet with Transformer-era choices until it matches Swin.
- Hybrids put convolutions early in the network and attention late, each where it works best.
Then come two later results. With strong pretraining on unlabeled images, a plain ViT with a few windows becomes the best dense backbone again. And a trained plain ViT can run about twice as fast if you merge similar tokens instead of changing its attention. The section ends with why counted FLOPs do not predict speed, and how to choose a backbone.
Why dense prediction wants a pyramid
Dense prediction means producing an output at every location of the image. Detection draws a box around each object and names it. Segmentation gives every pixel a label. Both read a feature map, a grid of vectors in which each vector describes one region of the image. The stride of a map is the number of pixels between neighboring vectors, so a map at stride 32 has one vector per 32 by 32 block of pixels.
Objects come in every size. On COCO, the standard detection benchmark of everyday photos with boxes and masks for 80 kinds of object, a car can be 20 pixels wide or 600. A map at stride 32 carries rich context but cannot place a 20-pixel object, which is smaller than one of its cells. A map at stride 4 is precise, but each of its vectors has seen only a small neighborhood, unless the network runs many expensive layers at that resolution. The answer is a pyramid of maps, fine ones for small objects and coarse ones for large ones.
Convolutional networks build that pyramid as they go. Recall from §0.8 that a ResNet is a stack of convolutional blocks with residual connections. Its first layers, its stem, turn a 224 by 224 image into a 56 by 56 map. Its four stages then produce maps of 56, 28, 14, and 7 cells a side, at strides 4, 8, 16, and 32, with more channels as the maps shrink. A detection head such as a feature pyramid network (Lin et al. 2017) reads all four maps and combines them, and §27.6 builds one.
In plain words, each stage halves the map in both directions and doubles the channels. A small count shows why those two go together. A block whose cost is dominated by per-token linear layers costs about for some constant . At stage 1 of a 224-pixel image with , million. At stage 2 it is , again 28.9 million, because the map lost a factor of 4 and gained a factor of 4. So one block costs the same in every stage, and designers spend compute across scales by choosing how many blocks each stage gets.
A plain ViT misses both halves of this design. It keeps one map, so a detector must invent the other scales. And its cost per block, , has set by the finest resolution it must see, so the quadratic term eventually dominates. The Swin Transformer (Liu et al. 2021) fixes the cost with windows and the single map with patch merging, and we take them in that order. An interviewer often opens with "why can't a detector read a plain ViT's output as it is?" The two answers are the missing scales and the quadratic cost.
Window attention, and what it costs
Window attention cuts the token map into small squares, called windows, and runs ordinary attention inside each one. A token sees only the tokens of its own window. Here is the saving on a map small enough to count.
Why squares that do not overlap? §12.6 made attention cheap for language with a sliding window, in which each token sees only the few tokens just before it. The 2-D version gives every query its own square of keys centered on itself. That is cheap in FLOPs but awkward on a GPU, because neighboring queries share most but not all of their keys, so the keys cannot be packed into one dense matrix multiply. With windows that do not overlap, each window is a small, dense attention problem, and all of them run together as one batched matrix multiply.
The first piece of code every Swin implementation needs cuts the map into windows and puts it back together.
Window partition and its inverse
Implement window_partition(x, M). The input x is a batch of token maps of shape (B, H, W, d), and M divides both H and W. Return an array of shape (B * n_w, M * M, d), with windows per image. Order the windows by image first, then by window row, then by window column, and list the tokens inside each window in raster order.
Then implement window_reverse(windows, M, H, W), which undoes the partition and returns (B, H, W, d). Use reshapes and one transpose in each function, and no Python loops. The classic bug is a single reshape with no transpose. It runs without error but mixes rows of different windows.
Window attention is also global attention with a mask. Recall from §4.4 that an additive mask adds 0 to the scores that are allowed and to the rest, so blocked keys get zero weight after the softmax. Here the mask is 0 between tokens of the same window and otherwise. If you sort the tokens by window, the mask is block diagonal, one block per window. The cell runs both computations on the 8 by 12 map above and counts the scores each one computes.
The outputs agree exactly, and the windows compute 1,536 scores where global attention computes 9,216. In general the saving in the attention term is a factor , the number of windows. Here is the exact cost.
Here is where each term comes from. The four projections are each a by product, multiply-adds each, so in total, the same in both layers. For the scores, head forms . In global attention that is queries times keys times numbers, so per head and over the heads, since . The weighted sum , with the attention weights, costs the same, which gives . In window attention each query meets only the keys of its window, so the two products cost each per head and in total.
In plain words, windows leave the projections alone and replace the in the attention term by the window size . The cell evaluates both costs for the first stage of Swin-T, the smallest Swin model. Swin-T cuts the image into 4 by 4 pixel patches, embeds them at width , and uses windows of tokens.
The widget plots the cost of one whole block, attention plus MLP, against resolution, for global attention, window attention, a ConvNeXt block (met later in this section), and a dense convolution.
In practice, window attention is what makes a Transformer affordable at stride 4. The cost of a block becomes a fixed multiple of the number of tokens, like a convolution's. The interview question is the derivation above, and the follow-up is "what did you lose?" The next subsection answers it.
Shifted windows let information cross borders
Windows have a flaw that the cost formula hides. A token never sees a token in the next window, in this layer or in any later one, because every layer uses the same windows. The receptive field of a token is the set of input tokens its output depends on. Stack as many window layers as you like, and every token's receptive field stays its own window.
Swin's ablation, an experiment that removes one part and measures the damage, puts a price on that flaw (Liu et al. 2021, Table 4, Swin-T). It reports three scores. ImageNet top-1 is the share of images whose highest-scoring class is correct. COCO box AP measures detection on a scale of 0 to 100, and ADE20K mIoU measures how well predicted segments overlap the true ones on a scene-parsing benchmark. §27.6 defines both. Without the fix below, top-1 drops from 81.3% to 80.2%, box AP from 50.5 to 47.7, and mIoU from 46.1 to 43.3. The dense tasks suffer most.
The fix is to alternate two partitions. Odd layers use the regular windows. Even layers use windows moved by tokens down and to the right. With , a window that covers rows 0 to 3 in one layer is followed by one that covers rows 2 to 5. Each new window straddles a border of the old ones. Here is what that does on one row of tokens.
Swin uses pre-LN blocks, which apply LayerNorm (LN) at the start of each residual branch (§5.2). So a consecutive pair of Swin blocks is
Here is the token map after block , and SW-MSA is window attention over the shifted partition.
How fast does the receptive field grow in general? Look at one axis. The regular windows are the intervals , and the shifted ones are . With , every shifted window overlaps exactly two regular windows, and every regular window overlaps exactly two shifted ones. So each layer joins two neighboring windows of the layer before, as the example showed.
∂ Proof of the receptive-field theorem
Both partitions are products of a partition of the rows and a partition of the columns. So the set a token depends on is a product of a row interval and a column interval, and it suffices to prove the 1-D statement, that the dependency set has length .
Every token of a window attends to every token of that window. The MLP, the norms, and the residual act on each token separately. So after layer , all tokens of a layer- window depend on the same set, the union of the sets of the layer- windows it overlaps.
For that set is the window itself, an interval of length . Suppose that after layers every window's set is an interval of length . Windows of one partition are translates of each other by multiples of , so the sets of two adjacent windows are intervals of length offset by . A layer- window overlaps exactly two adjacent windows of layer , so its set is the union of two such intervals. Since , the two intervals overlap or touch, and their union is one interval of length .
Without the shift, each window overlaps only itself in the previous layer, so the set never grows.
In plain words, each layer adds one window width to the receptive field along each axis. That is the same linear growth with depth that §12.6 proved for 1-D sliding windows and that §0.8 computed for stacked convolutions. Patch merging, later in this section, then doubles every receptive field measured in pixels at each stage boundary, which is how Swin's last stage sees the whole image. The cell walks the dependency set backward through the layers on a 56 by 56 map with .
The widget shows the same thing on a small map. Click a token and watch the shaded set it depends on grow, one window per layer.
The cyclic shift, and the mask that makes it exact
The shifted windows are ragged at the borders. Take an 8 by 8 map with and . Along each axis the shifted windows cover rows 0 and 1, then rows 2 to 5, then rows 6 and 7. That makes 3 by 3 = 9 windows instead of 4, and only the middle one is a full 4 by 4. In general an map has shifted windows instead of , and the border ones are smaller than .
You could pad every small window to full size and mask the padding. In this example that is 9 windows of work instead of 4, 2.25 times as much. On a large map the extra row and column of windows cost less, but the work is still wasted, and the shifted layers then have a different number of windows from the regular ones.
Swin's trick is to move the image instead of the windows. Roll the map cyclically by toward the top left, so that whatever falls off the top edge comes back at the bottom, and the same for columns. This wrap-around shift is the circular translation that §27.3 used to state translation equivariance exactly. Then cut the rolled map into the regular windows, attend with a mask, and roll the result back.
See it on one axis first. Rolling the rows by puts them in the order . The first regular window of the rolled map holds rows 2 to 5, exactly the full shifted window. The second holds rows 6, 7, 0, 1, which glues the bottom piece (rows 6 and 7) to the top piece (rows 0 and 1). Those two pieces were never neighbors in the original map, so a mask must keep them from attending to each other. The example below does this in 2-D by hand.
The widget runs the roll on the same map. Press the button, then click a token to see which keys its mask keeps.
The cell checks the hand computation, reusing the row labels of the receptive-field cell.
The last line shows the price of the trick. In this tiny map the bottom-right window blocks 75% of its score entries, which are computed and then thrown away. On Swin-T's 56 by 56 first stage only the last row and the last column of windows need a mask at all, 15 of the 64 windows. Here is the construction in general, and the proof that it is exact.
With the labels in hand, the whole layer is three steps, roll, attend with the mask, and roll back. The claim is that these steps compute exactly what attention over the ragged shifted windows would, border pieces and position biases included, with nothing approximated.
∂ Proof that the cyclic shift is exact
Look at rows. Columns work the same way. Rolled row lies in rolled window , and .
For , rolled window holds rows . These are original rows , with no wrap-around, and that is exactly shifted window .
The last rolled window, , holds original rows , the cut-short bottom window, together with the wrapped rows , the cut-short top window.
So every rolled window is either one whole shifted window or a union of up to four cut-short ones (two pieces per axis), and the mask keeps exactly the pairs inside the same piece. Attention with a mask confined to one piece is attention over that piece, since blocked keys get weight and the softmax renormalizes over the rest.
Within one piece every token was moved by the same amount, either or . So row differences, and with them the relative position bias, are the same in rolled and original coordinates. Masked pairs may have wrong offsets, but they get zero weight. Rolling back returns every output to its token.
In plain words, the roll glues the ragged border pieces into full-size windows, and the mask keeps the glued pieces from talking to each other. It is also fast. In Swin's speed test on a V100 GPU, the cyclic version ran Swin-T at 755 images per second, against 670 with padding. A naive sliding-window implementation managed 183, and a custom sliding-window kernel 488. The sliding window was about as accurate, 0.1 points higher on ImageNet and 0.3 lower in COCO box AP and ADE20K mIoU (Liu et al. 2021, Tables 5 and 6).
Interviewers like this question because the answer has three parts, roll, mask, and roll back, and each part has a classic bug. The next exercise builds the mask, the middle part.
The shifted-window attention mask
Implement shifted_window_mask(H, W, M, shift). The token map is H by W, the window side M divides both, and the shift satisfies 0 <= shift < M. Return a float array of shape (n_w, M * M, M * M), one additive mask for each window of the map after it is rolled by (-shift, -shift). Order the windows and the tokens as in Exercise 27.5a.
Entry [k, i, j] is 0 when tokens i and j of rolled window k belong to the same shifted window of the original map, and -100.0 otherwise. Swin's code uses -100 in place of , because after the softmax a blocked weight is then about , zero for every practical purpose. With shift = 0 every entry is 0.
Relative position bias in a window
Attention by itself does not know where tokens are. Swin tells it by adding a learned number to each score, chosen by the offset between the query and the key. One number might mean "the key is two rows up and one column left of the query". It adds no absolute position embedding to the tokens at all.
§5.4 met the 1-D version for text, in which each head adds one learned number per distance to its scores, as in T5 (Raffel et al. 2020). There, large distances had to share buckets, because offsets in a sentence are unbounded. Inside a window they are not. Take , a window of four tokens at . Each axis offset is , , or , so there are only possible 2-D offsets, and a 3 by 3 table holds one learned number for each. In general an window has offsets per axis, so Swin can afford one parameter for every 2-D offset.
In plain words, the bias is a learned score for each relative placement of key and query. It is the same for every window and every image, so it is translation equivariant within a window, the property that §27.3 showed a ViT with absolute positions lacks. For the table has entries per head, so a three-head block in Swin-T's first stage spends 507 parameters on it. Since the bias depends only on differences of coordinates, is constant along every diagonal of equal offsets. It is a block-Toeplitz matrix with Toeplitz blocks.
The cell builds the index for , small enough to check every entry by hand, and confirms for that equal offsets get equal biases.
For the center of the 3 by 3 table, index 4, is the zero offset, which sits on the diagonal. Row 0 reads 4, 3, 1, 0. The query is at and every key is right of it or below it, so and are 0 or , and the indices count down from the center.
Swin's relative position index
Implement relative_position_index(M). It returns an integer array of shape (M * M, M * M) whose entry [i, j] is . Token i sits at window coordinates divmod(i, M), and is the coordinate of token i minus that of token j (query minus key). Use no loops over tokens.
How much does the bias matter? Swin-T with it reaches 81.3% top-1, 50.5 box AP, and 46.1 mIoU. With no position information at all the numbers are 80.1%, 49.2, and 43.8. With ViT's absolute embedding instead they are 80.5%, 49.0, and 43.2. So the absolute embedding helps classification a little and hurts both dense tasks. Adding it on top of the relative bias leaves top-1 at 81.3% but costs 0.3 box AP and 2.1 mIoU, which is why Swin uses the bias alone (Liu et al. 2021, Table 4). Dense tasks care more about translation equivariance than classification does.
Indexing the table by offset has a practical consequence. Fine-tuning at a larger resolution usually means a larger window. The released Swin-B at 384 pixels uses , so its 13 by 13 table is resized to 23 by 23 by bicubic interpolation, the same move as resizing a ViT's position table in §27.1. Stretching a table far beyond its trained range works badly, and Swin V2 fixed that. In an interview, "how does Swin encode position, and what breaks when the window grows?" has exactly this answer.
Patch merging, and Swin counted to the last parameter
Windows make the cost linear. The pyramid comes from merging neighboring tokens between stages, which halves the map and doubles the channels.
In plain words, every 2 by 2 block of tokens becomes one token with twice the channels. Concatenating a 2 by 2 block and applying a linear map is the patch embedding of §27.1 applied to tokens instead of pixels. So patch merging is a LayerNorm over each 2 by 2 block followed by a 2 by 2 convolution with stride 2 and no bias.
Now the whole network. Swin first cuts the image into 4 by 4 pixel patches of 48 numbers each (16 pixels times 3 colors). It projects them to width , exactly a ViT patch embedding with . Swin calls this step "patch partition". Four stages follow, separated by three patch merges. Every head has channels, and the MLP expands the width 4 times. The table counts all four sizes exactly, with a 1,000-class head at 224 pixels and . The counts include every weight and bias and match the timm library's, and they sit next to the paper's numbers.
| model | blocks per stage | heads per stage | parameters (exact) | multiply-adds | ImageNet-1k top-1 | |
|---|---|---|---|---|---|---|
| Swin-T | 96 | 2, 2, 6, 2 | 3, 6, 12, 24 | 28,288,354 | 4.5G | 81.3% |
| Swin-S | 96 | 2, 2, 18, 2 | 3, 6, 12, 24 | 49,606,258 | 8.7G | 83.0% |
| Swin-B | 128 | 2, 2, 18, 2 | 4, 8, 16, 32 | 87,768,224 | 15.4G | 83.5% (84.5% at 384) |
| Swin-L | 192 | 2, 2, 18, 2 | 6, 12, 24, 48 | 196,532,476 | 34.5G | 87.3% at 384 (103.9G), ImageNet-21k pretraining |
The accuracies are from Liu et al. (2021), Table 1. Every model but Swin-L was trained on ImageNet-1k alone (1.28 million images in 1,000 classes). The recipe was the one of §27.4, 300 epochs of AdamW with strong augmentation, Mixup and CutMix, and stochastic depth. Stochastic depth skips whole residual branches at random during training, here at rates 0.2, 0.3, and 0.5 for T, S, and B. That recipe was introduced by DeiT (Touvron et al. 2021). Swin-L was pretrained on ImageNet-21k, the full ImageNet of 14.2 million images in about 21,800 classes, which the Swin paper calls ImageNet-22K. The paper rounds the parameter counts to 29M, 50M, 88M, and 197M. The ConvNeXt paper lists Swin-T as 28M, so even the rounding varies by one, which is a good reason to count.
The cell repeats the count for all four sizes.
The cost of a Swin backbone
First implement attention_macs(H_p, W_p, d, M=None), the multiply-adds of one attention layer from the cost theorem, projections included. It is global attention when M is None and window attention otherwise.
Then implement swin_macs(img, P, d1, depths, M=7, mlp_ratio=4, n_classes=1000) for a square image of side img. It returns a dict with the keys "embed", "attn", "mlp", "merge", "head", "total", and "stages". Count only matrix multiplies, with these rules.
- The patch embedding costs .
- Each block of stage adds
attention_macsat that stage to"attn"and to"mlp". The window side is , because Swin shrinks the window when the map is smaller than it. - Each merge costs , and the head costs .
"stages"is the list of .
Use Python integers.
A Swin block in PyTorch
Production code does exactly what we derived. The block below runs one shifted-window layer with torch.roll, the region mask, and the relative bias. It then compares the result with a slow reference that gathers each true shifted window of the original map and attends inside it. Agreement is the cyclic-shift theorem checked numerically.
Shifted window attention, end to end
Put the pieces together. Implement shifted_window_attention(x, Wqkv, Wo, table, M, shift, h) for one token map x of shape (H, W, d), and return an array of shape (H, W, d). The arguments follow these conventions.
Wqkvhas shape(d, 3d). Its firstdcolumns make the queries, the nextdthe keys, and the lastdthe values. Each block ofdcolumns splits intohheads ofd // hconsecutive columns.Wohas shape(d, d), and there are no biases.tablehas shape(h, (2M - 1)**2)and is read with the index of Exercise 27.5c.- Scale the scores by , with .
- If
shift > 0, roll by(-shift, -shift), add the mask of Exercise 27.5b, and roll the output back.
The setup provides working copies of the earlier exercises, ws_partition(x, M) (for (H, W, d) maps), ws_reverse(w, M, H, W), ws_rel_index(M), and ws_mask(H, W, M, shift). The tests compare your output with attention computed directly inside each shifted window of the original map, with no roll at all.
Swin delivered what it promised. The results below come from standard detection and segmentation heads that §27.6 explains (Cascade Mask R-CNN and HTC++ on COCO, UperNet on ADE20K), with the backbone as the only thing changed. With ImageNet-21k pretraining, Swin-L reached 58.7 box AP and 51.1 mask AP on COCO test-dev and 53.5 mIoU on ADE20K, all three with multi-scale testing, the best results of early 2021. At similar size and FLOPs, Swin-T beat a ResNet-50 on COCO by 4.2 box AP, 50.5 against 46.3 (Liu et al. 2021, Tables 2 and 3).
ConvNeXt rebuilds a ResNet with Transformer-era choices
Swin's results raise a question. Was it attention that won, or everything that came with it? Compared with a ResNet, Swin changed many things at once. It used 4 by 4 patches, a different share of blocks per stage, a wide MLP, LayerNorm, the GELU activation, and fewer nonlinearities. It was also trained with the long, heavily regularized recipe described above.
Liu et al. (2022b) tested this the way a careful experimenter should. They started from ResNet-50 and changed one thing at a time toward Swin-T. They kept the network a pure convolutional network and the compute near 4.5G multiply-adds, and trained every step with three random seeds. The result is called ConvNeXt.
Read the table as an argument. The largest single gain, 2.7 points, is the training recipe of §27.4, before any change to the architecture. Then each choice borrowed from Transformers maps to a convolutional one.
- Patchify stem. A 4 by 4 convolution with stride 4 is the patch embedding of §27.1 with . It replaces the ResNet stem's overlapping 7 by 7 stride-2 convolution and max pooling (§0.8).
- Depthwise convolution. A depthwise convolution filters each channel on its own, so it mixes information only across space. A 1 by 1 convolution mixes only across channels. That is the same split as attention (space) and the MLP (channels) in a Transformer block.
- Inverted bottleneck. The block widens to 4 times its channels in the middle and narrows back, like the Transformer MLP. A ResNet bottleneck does the opposite.
- Depthwise convolution moved to the top. This mirrors putting attention before the MLP, and it lets the spatial operation run on channels instead of .
- 7 by 7 kernel. This is the size of a Swin window. Larger kernels gave no further gain.
- Fewer activations and norms. One GELU, one LayerNorm, and separate downsampling layers with their own norm copy the Transformer block's sparing use of nonlinearities and norms. BatchNorm, which normalizes each channel with statistics of the batch (§0.7), gives way to LayerNorm, which normalizes each position over its channels.
In plain words, filter each channel over a 7 by 7 neighborhood, normalize, run a Transformer MLP at every position, scale the result by a tiny learned gain, and add it back. Count the parameters to see where the comes from. The depthwise weights and bias are , the LayerNorm , the two MLP biases , and LayerScale , which sums to , next to the of the two matrices. Because LayerScale starts at , the residual branch starts scaled almost to zero. Every block therefore begins as nearly the identity, the same reason LayerScale helped deep ViTs train in §27.4.
A short count checks the claim that ConvNeXt-T and Swin-T have the same compute. Per position, a Swin block costs plus a little attention, and a ConvNeXt block costs plus . Swin-T has 2, 2, 6, 2 blocks per stage and ConvNeXt-T has 3, 3, 9, 3. In units of , the stages cost in both networks. The extra depth of ConvNeXt pays exactly for its cheaper blocks.
A ConvNeXt block in NumPy
Implement convnext_block(x, params) for x of shape (H, W, d), exactly as the definition says. The dict params holds these arrays.
"dw"of shape(7, 7, d), applied as a cross-correlation, which is the PyTorch convention. The output at isdw[a, b] * x[r + a - 3, c + b - 3]for each channel, with zeros outside the map."dw_b","ln_g", and"ln_b", each of shape(d,). The LayerNorm runs over channels with and the biased variance."W1"of shape(d, 4d),"b1","W2"of shape(4d, d),"b2", and"gamma"of shape(d,).
Use the exact GELU, , with scipy.special.erf. Use no loops over positions or channels. A loop over the 49 kernel taps is fine.
In PyTorch the depthwise convolution is nn.Conv2d(d, d, 7, padding=3, groups=d). The official code permutes the map to channels-last, so that LayerNorm and the two linear layers act on the last axis. The block below builds the layer and checks it against a NumPy version written inside the same block.
nn.Linear stores its weight as (output, input), the transpose of this chapter's , which is why the NumPy check multiplies by .T.
The result held beyond ImageNet. ConvNeXt-T reached 82.1% at 4.5G against Swin-T's 81.3%, and ConvNeXt-B reached 83.8% against Swin-B's 83.5%. With ImageNet-21k pretraining, ConvNeXt-XL reached 87.8% at 384 pixels. On COCO with Cascade Mask R-CNN, ConvNeXt-T and Swin-T tie at 50.4 box AP, and with ImageNet-21k pretraining ConvNeXt-B leads Swin-B by 1.0 box AP, 54.0 against 53.0. On ADE20K with UperNet, ConvNeXt is ahead at every size by 0.1 to 1.4 mIoU (Liu et al. 2022b, Tables 1, 3, and 4).
The paper's own conclusion is the one to remember. Both networks beat a plain ViT on efficiency because they compute locally, an inductive bias, and not because of self-attention as such. §27.3 reached the same lesson, where carefully trained convolutional networks matched ViTs at equal compute. If an interviewer asks "is attention necessary for a strong vision backbone?", ConvNeXt is the answer to cite, with its recipe gain of 2.7 points as the headline.
Hybrids put convolutions early and attention late
Convolutions suit the early layers of a network, where features are local and maps are large, because they are cheap and need less data. Attention suits the late layers, where the map is small and mixing that depends on the input pays for itself. Many designs use both on purpose. Here are the three ideas worth knowing.
Convolutional stems. Xiao et al. (2021) replaced ViT's 16 by 16 patchify stem with about five convolutions. These are a stack of 3 by 3 convolutions with BatchNorm and ReLU, in the smaller models four of them with stride 2 to reach stride 16, and a final 1 by 1 convolution to width . The stem costs about as much as one Transformer block, which they removed to keep the FLOPs equal. The ViT became far less sensitive to the choice of optimizer, its learning rate, and the schedule length, and gained about 1 to 2 points of ImageNet top-1. The authors' explanation is that a first layer with a large kernel and a large stride, unusual for a convolution, makes optimization harder.
Relative attention. Dai et al. (2021) observed that depthwise convolution and attention are both weighted sums of other positions. A depthwise convolution computes , with a fixed weight per offset over a local window. Attention computes , with weights that depend on the input, over everything. Adding a learned scalar to the attention scores before the softmax combines the two. The offset term gives translation equivariance, and the dot product gives weights that adapt to the input. This is the same relative bias Swin uses, applied globally. Their network, CoAtNet, stacks two convolutional stages and then two Transformer stages (C-C-T-T). It reached 86.0% on ImageNet-1k alone and 88.56% with ImageNet-21k pretraining, which matched a ViT-H/14 pretrained on 300 million images (JFT-300M, a Google-internal labeled set) with 23 times less data. With 3 billion images (JFT-3B) it reached 90.88%.
Spatial-reduction attention. The Pyramid Vision Transformer (Wang et al. 2021) kept global attention in a four-stage pyramid. To make it affordable, it shrinks the keys and values by a factor per side before attending, so the score term drops from to . Each query still sees the whole image, but through a coarser grid of keys.
On phones and embedded chips the target is measured latency, the time per image on the device, and the winning designs mix cheap convolutions with a little attention. The box below lists the main ones, and the far end of the spectrum, a network with no attention at all.
The table puts the designs side by side. The cost column is how the token-mixing step grows with the token count .
| design | token mixing | cost in tokens | changes resolution freely | example result |
|---|---|---|---|---|
| plain ViT | global attention | needs position interpolation | ViT-B/16 on IN-1k alone, 77.9% at 384 (2020 recipe), 81.8% at 224 (DeiT) | |
| Swin | window attention plus shift | relative bias, window may need resizing | Swin-T 81.3%, 4.5G | |
| ConvNeXt | 7 by 7 depthwise convolution | yes, fully convolutional | ConvNeXt-T 82.1%, 4.5G | |
| CoAtNet | convolution early, relative attention late | early, late on small maps | relative bias | 86.0% IN-1k alone |
| PVT | attention with reduced keys and values | position interpolation | PVT-Small, 40.4 AP with RetinaNet (1x schedule) on COCO val | |
| MLP-Mixer | MLP across tokens | (a weight) | no, fixed | 87.94% with JFT-300M |
Plain ViTs return with self-supervised pretraining
By 2022 the story seemed settled, with hierarchical backbones for dense tasks and plain ViTs for classification. Then self-supervised pretraining, which learns from images without labels, changed the economics. The method that mattered most is the masked autoencoder, MAE (He et al. 2022), which §28.5 develops. MAE hides 75% of the patches and trains the ViT to reconstruct them from the rest.
That is natural for a plain ViT, which reads any set of tokens, and awkward for windows and convolutions, which want a full grid. If pretraining can teach a plain ViT locality and scale, the backbone may not need them built in.
ViTDet (Li et al. 2022a) tested this for detection. It took an MAE-pretrained plain ViT and changed it only during fine-tuning, in three ways.
- Most blocks use window attention without any shift, with windows the size of the pretraining grid (14 by 14 tokens).
- Four blocks, spread evenly through the network, use global attention so that information crosses the windows.
- Instead of a feature pyramid network, a simple feature pyramid is built from the last stride-16 map alone. A 2 by 2 max pooling of stride 2 gives stride 32, and one or two 2 by 2 transposed convolutions (learned upsampling layers) give strides 8 and 4.
With ViT-H and MAE pretraining on ImageNet-1k alone, ViTDet with a Cascade Mask R-CNN head reached 60.4 box AP on COCO with single-scale testing and 61.3 with multi-scale testing. That beat every hierarchical-backbone result in its comparison, including those pretrained on ImageNet-21k with labels.
The same recipe now runs inside widely used models. SAM, the promptable segmentation model of §27.6, has an image encoder that §27.2 counted. It uses 14 by 14 windows plus four global blocks on a 64 by 64 grid. So does the vision encoder of the Qwen2.5-VL vision-language model (Bai et al. 2025), a 32-block ViT of width 1,280 with 14-pixel patches that reads images at their native resolution. Its blocks 7, 15, 23, and 31 (counting from 0) attend globally. The other 28 attend within windows of at most 112 by 112 pixels, 8 by 8 patches, with 2-D rotary position embeddings (§27.1). An image of any size and shape therefore costs attention linear in its area in all but four blocks, and §31.5 follows its tokens into the language model.
Hiera (Ryali et al. 2023) did the same for hierarchical models. It started from MViTv2 (Li et al. 2022b), a strong hierarchical ViT that shrinks its maps by pooling inside attention. With MAE pretraining it removed MViTv2's convolutions, its relative position embeddings, and its other vision-specific modules one by one, without losing accuracy. What remains is a stack of standard ViT blocks with three changes. The first two stages attend locally inside mask units, the blocks of 8 by 8 tokens (32 by 32 pixels) that MAE hides or keeps as a whole. Later stages attend globally. And the queries are max-pooled 2 by 2 at each stage transition, which halves the map.
Hiera-B reached 84.5% on ImageNet-1k at 9G multiply-adds. That is more accurate than Swin-B at about 60% of its FLOPs, and it ran faster in wall-clock time than earlier hierarchical models. Hiera became the image encoder of SAM 2 (Ravi et al. 2024).
The trend continued with scale. DINOv3 (Siméoni et al. 2025) trained a 6.7B-parameter plain ViT without labels, by the self-distillation that §28.4 teaches. With that backbone frozen, a set-prediction detector in the style of DETR (§27.6) reached 66.1 box AP on COCO. A Mask2Former segmentation head on the same frozen backbone reached 63.0 mIoU on ADE20K. Both numbers use test-time augmentation, and without it they are 65.6 and 62.6. Both were among the strongest published results when they appeared. Its weights were also distilled into smaller ViTs and into ConvNeXt-T, S, B, and L, for devices where a 7B model cannot run.
Real-time detectors show the same split. RF-DETR (Robinson et al. 2026) builds on a DINOv2 ViT with interleaved windowed and global attention. DEIMv2 (Huang et al. 2025) uses DINOv3 ViTs, pretrained or distilled, for its larger models and a pruned convolutional backbone, HGNetv2, for its smallest ones.
So the current answer is neither "hierarchical beats plain" nor the reverse. Priors and pretraining substitute for each other. With little data, build locality and scale into the architecture. With massive self-supervised pretraining, a plain ViT learns them, and its simplicity and scalability win, as long as windows or a few global blocks keep high-resolution fine-tuning affordable. That trade-off is the core of the "plain or hierarchical?" interview question.
Fewer tokens instead of cheaper attention
Everything so far made each token cheaper, either by limiting what it attends to or by replacing attention with a convolution. The other lever keeps a trained plain ViT exactly as it is and gives it fewer tokens. A block costs , at least linear in , so every token removed saves at least multiply-adds in each block it would have passed through. This matters because the strongest available weights are often a plain ViT (from MAE, CLIP, or DINOv2), and retraining one with windows costs more than most teams can spend.
Removing tokens is natural for a plain ViT and awkward for a hierarchical one, for three reasons. Each token has carried its position since the input embedding (§27.1), so it needs no neighbors to say where it is. Attention and the MLP are permutation equivariant (§4.6), meaning that reordering the input tokens only reorders the outputs, so a block runs on any set of tokens in any order. And a classifier reads only the class token. Windows, shifted windows, and convolutions all need the full grid in every layer.
There are three ways to use fewer tokens.
- Bigger patches cut the count from the start, by a factor for patch side instead of . FlexiViT (§27.1) lets one trained model run at several patch sizes. But a bigger patch coarsens every region equally, the sky as much as a face.
- Pruning deletes the tokens that some score calls unimportant.
- Merging averages tokens that carry nearly the same information, so a flat sky collapses into a few tokens while a detailed region is left alone.
Token Merging, or ToMe (Bolya et al. 2023), is the standard way to merge, and it works on a trained model with no retraining at all. Here is its idea on seven tokens before the definition.
In plain words, every token of proposes its closest token of , and the most confident proposals are accepted. Each choice has a reason, and ToMe's ablations put a number on each (Bolya et al. 2023, Table 1). They use an MAE ViT-L/16 off the shelf, at 85.96% top-1 before merging, and merge tokens per block.
- Two sets. A destination is never itself merged away, so there are no chains and no clustering. The work is one similarity matrix and a sort, which runs nearly as fast as dropping tokens at random.
- Alternating positions. Tokens next to each other in raster order land in opposite sets, so horizontally adjacent patches can merge. This scores 84.25%, against 81.07% when is the first half of the sequence and the second.
- Keys. The keys summarize what attention already uses to compare tokens, while the features carry much else. Keys score 84.25%, the features after attention 83.70%, and those before it 83.02%.
- Size weighting. If and are averages of the and patch vectors they stand for, the size-weighted average is exactly the average of all of them. A plain average would let one stray patch count as much as ten merged ones. Weighting scores 84.25%, against 83.57%.
One step of token merging
Implement tome_merge(X, K, sizes, r), one step of bipartite soft matching on one image, exactly as the definition says. X has shape (n, d) with the class token in row 0, K has shape (n, d_k) (the keys, already averaged over heads), and sizes has shape (n,). Return (X_new, sizes_new) of shapes (n - r, d) and (n - r,), with these conventions.
- Keep the surviving tokens in their original order, so the class token stays in row 0. ToMe's own code returns the survivors of followed by those of . A Transformer does not mind, since attention is permutation equivariant, but the tests expect the original order.
- Break ties by the lower index, with a stable sort.
- Use no Python loops over tokens.
This is a favorite inference-efficiency question. Its classic slips are matching within one set, averaging without the sizes, comparing features instead of keys, and merging the class token.
Why does a merged token need the term in later attention? Without it, a token that stands for patches gets the weight of one.
∂ Proof of the proportional-attention identity
The copies of token contribute to both the numerator and the denominator, which is the identity.
For the consequence, copies have equal queries, keys, and values, so by the identity they receive equal attention outputs. The rest of a block (the norms, the MLP, the residual) acts on each token separately, so copies that enter a block leave it as copies. By induction over the blocks they stay copies. Their size-weighted average therefore equals each of them, and by the identity every other token's attention sees the merged token exactly as it saw the copies.
In plain words, merging costs nothing when the merged tokens were identical, and little when they were close, as long as the merged token keeps the weight of all its parts. In practice the term matters for some weights and not others. It helped supervised weights, a ViT-L/16 trained with the augmentation and regularization recipe of Steiner et al. (2021), which went from 82.15% to 83.51% with it. It did not help MAE weights used off the shelf (84.25% without, 83.84% with), so ToMe turns it off for those. The cell checks the identity on five distinct tokens with 11 copies in all.
How much does merging save? ToMe merges the same tokens in every block, so every image keeps the same count and batches stay rectangular.
∂ Proof of the merging cost
By the global case of the attention cost theorem above, the attention branch on tokens costs , and the MLP on tokens costs . Their sum is the term shown.
The matching itself, about multiply-adds for the similarities, is of the attention term and is left out.
Since falls with , the bound is tightest in the last block, where it reads , that is .
In plain words, at the largest allowed the token count falls almost linearly from to nearly zero. The linear layers then do about half their usual work, and the attention scores, which go with , about a third. When is larger than the bound allows, ToMe's code merges fewer tokens in the last blocks, as many as the bound permits. The cell evaluates the theorem for the two models of ToMe's headline result.
The measured speedup tracks the count because a plain ViT's work is large dense matrix multiplies. Those are limited by arithmetic rather than by memory, as the section on latency below makes precise. Smaller models lose more. Off the shelf at twice the speed, ViT-B, S, and Ti drop about 4 to 5 points. Training with merging in place recovers much of that. Fine-tuned with ToMe at twice the throughput, MAE models lose 0.4 points for ViT-H, 0.6 for ViT-L, and 1.7 for ViT-B. Bolya et al. attribute the gentler loss of large models to their depth, which lets features change more gradually between merges.
| method | decides by | needs training | tokens per image | survivors keep a grid position | reported result |
|---|---|---|---|---|---|
| bigger patches (FlexiViT) | position only | one model trained for many patch sizes | fixed, of the original | yes, on a coarser grid | one set of weights for patch sizes 8 to 48 |
| pruning by class attention (EViT) | the class token's attention | yes | fixed keep rate | kept tokens yes, the fused token no | DeiT-S 50% faster for 0.3 points |
| learned pruning (DynamicViT) | a learned score | yes, fine-tuned from a trained model | fixed keep ratio | yes | 31 to 37% fewer FLOPs for at most 0.5 points |
| merging (ToMe) | similarity of keys | no, though training helps | fixed, at the end | no, a merged token spans patches | ViT-L and ViT-H 2 times faster for 0.26 and 0.30 points |
Merging has a cost that classification hides. A merged token can stand for patches far apart, so the output is no longer a grid, and a dense head has nothing to put at each pixel. ToMe for Stable Diffusion (Bolya and Hoffman 2023) handles this by unmerging. It merges tokens before a layer, then copies each merged output back to every token it absorbed before the residual addition. By default it does this only around self-attention, and only in the highest-resolution blocks. That keeps the full grid and still removes up to 60% of the tokens there. Pruning keeps the survivors on the grid but leaves holes, and it needs a class token, or some other score, to rank by. And a vision-language model must give every image token a row and a column for its positions. That is why §31.5, when it compresses image tokens for a language model, compares merging by content with merging by position.
FLOPs are not latency
Every comparison so far counted multiply-adds. Wall-clock time is a different matter, for the reason §11.2 made precise. An operation's arithmetic intensity is the FLOPs it does per byte it moves to and from memory. A GPU's ridge point is its peak FLOPs per second divided by its memory bandwidth in bytes per second, about 295 FLOPs per byte for an H100 in dense bfloat16. An operation whose intensity is below the ridge point is memory-bound, so its speed is set by memory bandwidth instead of arithmetic. Here are three vision operators measured that way.
That is why the ConvNeXt paper notes that models with depthwise convolutions are known to run slower than their FLOPs suggest, and why it compares measured throughput too. On a V100, ConvNeXt-T ran 774.7 images per second against Swin-T's 757.9, nearly equal. On an A100 it ran 1,943.5 against 1,325.6, 47% faster (Liu et al. 2022b, Appendix E). That A100 test used TF32, a reduced-precision format that the A100's matrix units run fast, and PyTorch's channels-last memory layout, which stores the channels of each position next to each other.
The FLOPs and the networks were the same. The gap depends on the GPU, the number format, and the memory layout, because memory-bound operators are only as fast as their kernels, and standard convolutions have far better kernels than window shuffles. The same fact explains why Hiera got faster by deleting specialized modules, and why mobile hybrids optimize latency on the target chip directly. Always measure on your hardware.
How to choose a backbone
Five questions narrow the choice.
- How many tokens will the input make? That decides whether global attention is affordable.
- Are strong pretrained weights available? They usually matter more than the architecture.
- Does the head need several scales natively?
- What is the latency budget on the target hardware, measured rather than counted?
- Will the resolution or aspect ratio change between training and deployment? Convolutions and relative biases transfer, while absolute position tables need interpolation.
Read more
- Liu et al. (2021). Swin Transformer: Hierarchical Vision Transformer using Shifted Windows. Equations 1 and 2 for the cost, Figure 4 for the cyclic shift, and Tables 4 to 6 for the ablations of shifting, position bias, and implementations.
- Liu et al. (2022a). Swin Transformer V2: Scaling Up Capacity and Resolution. Res-post-norm, scaled cosine attention, and the log-spaced continuous position bias that let windows change size.
- Liu et al. (2022b). A ConvNet for the 2020s. The step-by-step modernization of ResNet-50 (Figure 2 and Table 10) is a model of a controlled architecture study.
- Woo et al. (2023). ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoders. Masked pretraining for ConvNets and global response normalization.
- Dai et al. (2021). CoAtNet: Marrying Convolution and Attention for All Data Sizes. Depthwise convolution and attention unified by a relative bias, and the C-C-T-T layout.
- Li et al. (2022a). Exploring Plain Vision Transformer Backbones for Object Detection. ViTDet, the simple feature pyramid, and window attention with four global blocks.
- Ryali et al. (2023). Hiera: A Hierarchical Vision Transformer without the Bells-and-Whistles. How MAE pretraining lets a hierarchical ViT drop its vision-specific modules and get faster.
- Bolya et al. (2023). Token Merging: Your ViT But Faster. Bipartite soft matching and proportional attention, with the ablations (Table 1) behind every design choice and the full speed and accuracy tables in Appendix A.