Arnab, Dehghani, Heigold, Sun, Lučić, Schmid (Google Research) — ICCV 2021

ViViT: A Video Vision Transformer

How do you give a Transformer a sense of time? ViViT cuts a video into spatio-temporal "tubelets," flattens them into a pure-attention model, and then factorizes the giant 3D attention four different ways so it actually fits on a GPU — and regularizes hard so it trains on data far smaller than ImageNet.

Prerequisites: Self-attention / ViT patch embedding + Softmax + Matrix multiplication. We re-derive the rest.
10
Chapters
9
Simulations
2
Code Labs

Chapter 0: The Video Problem

You are watching a ten-second clip. In one frame, a person stands holding a bow. In the next, the arm draws back. A few frames later, the arrow is in flight. No single frame tells you the action is "archery shooting" — the standing pose alone could be a dozen things. The label lives in the change between frames: the motion, the temporal order, the way one pose flows into the next. That is the whole difficulty of video understanding. The signal is not in the pixels; it is in how the pixels move.

By 2021, image classification had been quietly conquered. The Vision Transformer (ViT, Dosovitskiy et al. 2021) had shown you could throw away convolutions entirely: chop an image into 16×16 patches, linearly embed each patch into a token, add a learned position, and run a plain Transformer encoder. With enough pre-training data it matched or beat the best ResNets. The natural question — the one ViViT asks — is brutally simple: can we do the same for video? Just attention, no 3D convolutions, no optical flow, no two-stream networks.

The trouble is the third dimension. An image is a 2D grid. A video is a 3D volume: height × width × time. If you naively extend ViT — treat every frame independently as a bag of patches — you have thrown away exactly the thing that makes a video a video. So you must let tokens from different times talk to each other. The instant you do that, two problems appear, and the entire paper is the answer to them:

Problem 1 — Tokenization
How do you turn a 3D pixel volume into a 1D sequence of tokens that already carries motion?
Problem 2 — Cost
A video has hundreds of times more tokens than an image. Self-attention is O(N²). N² for video is catastrophic.
Problem 3 — Data
Transformers are data-hungry. Video datasets (Kinetics ~250k clips) are tiny next to image pre-training corpora.

What was broken before? The dominant video models were 3D CNNs (C3D, I3D, SlowFast). They worked, but inherited the convolution's weaknesses: a small, fixed receptive field that grows only slowly with depth, so a token in frame 1 cannot directly influence a token in frame 32 — the signal has to propagate through many layers. Attention, by contrast, connects any spatio-temporal location to any other in a single layer. The path length between "bow drawn" and "arrow released" is O(1). That is exactly the long-range temporal reasoning video needs.

Image → Video: the dimension that breaks everything

Left: ViT sees a single 2D grid of patches. Right: a video is a stack of those grids over time — and a meaningful action only emerges when tokens across frames can attend to one another. Drag the slider to add frames and watch the token count grow.

Frames T 8

A first worked count. Take a clip of 32 RGB frames at 224×224. ViT-style spatial patches of 16×16 give 224/16 = 14 patches per side, so 14×14 = 196 patches per frame. Across 32 frames that is 196 × 32 = 6,272 tokens. A single self-attention layer builds an attention matrix of size 6,272×6,272 ≈ 39.3 million entries — per layer, per head. For a 16×16 image patch ViT, the count was a comfortable 196×196 ≈ 38k. Video is a thousandfold heavier. That number, 6,272 tokens, is the dragon the rest of the paper is built to slay.

Common misconception: "Video is just images with one more axis, so a video Transformer is just ViT with bigger inputs." It is not. The extra axis multiplies the token count, and because attention is quadratic in the token count, a "small" linear increase in input (32 frames) becomes a roughly thousandfold increase in attention compute. ViViT's four model variants exist entirely to undo that quadratic blow-up while keeping enough cross-time attention to actually read motion.

ViViT's contributions, which this Veanor walks through in order, are exactly three: (1) tubelet embedding — a tokenizer that bakes motion into each token from the very first layer; (2) four factorizations of spatio-temporal attention, trading cross-time expressivity against compute; and (3) a regularization recipe (initialize from an image model, heavy stochastic depth, mixup, label smoothing) that lets these data-hungry models train on mid-sized video datasets without overfitting. Let us build the tokenizer first.

Why can't you just feed a video into a standard ViT by treating each frame independently?

Chapter 1: Tubelet Embedding

To run a Transformer you first need tokens: a sequence of vectors. ViViT proposes two ways to extract them from a video volume of shape T × H × W × C (frames, height, width, channels). The naive one is uniform frame sampling: independently embed 2D patches from each frame exactly like ViT, then concatenate all the per-frame tokens into one long sequence. It works, but each token is still purely spatial — it has seen no motion at all. Any sense of time has to be reconstructed later by the attention layers.

The better idea — the one ViViT contributes — is tubelet embedding. Instead of cutting 2D squares out of single frames, you cut out small 3D bricks that span several frames at once. A tubelet of size t × h × w grabs h×w pixels of spatial extent across t consecutive frames. Each such brick is flattened and linearly projected to a token of dimension d. Because a single token now contains pixels from multiple time-steps, motion is fused at the input layer — the projection itself can learn to respond to a moving edge, before any attention has happened.

tokens N = (T / t) × (H / h) × (W / w)

This is just a 3D generalization of ViT's patchify. Where ViT divides a 2D image into a grid of non-overlapping squares, tubelet embedding divides a 3D volume into a grid of non-overlapping cuboids. Mechanically it is a single 3D convolution with kernel size t×h×w and stride t×h×w (kernel = stride = no overlap), output channels = d. The paper calls this projection E; each output position is one token z = E·x + b.

A worked example, every number

Take a clip T=32, H=W=224, C=3 and a tubelet t=2, h=w=16, embedding dimension d=768 (ViViT's default, inherited from ViT-Base).

AxisInputTubeletTokens along axis
TimeT = 32t = 232 / 2 = 16
HeightH = 224h = 16224 / 16 = 14
WidthW = 224w = 16224 / 16 = 14

So the token grid is 16 × 14 × 14, giving N = 16 × 14 × 14 = 3,136 tokens. Each token is the flattening of t·h·w·C = 2·16·16·3 = 1,536 raw pixel values, linearly mapped to a 768-dimensional vector. After embedding, the sequence tensor has shape [N, d] = [3,136, 768] (plus a class token, giving 3,137).

Notice the temporal halving: with t=2 we already cut the token count in half compared to per-frame embedding (where the time axis would contribute 32, not 16). Tubelets are thus a tokenizer and a first line of defense against the token explosion of Chapter 0 — bigger t means fewer, motion-richer tokens.

Why fuse motion at the input instead of letting attention do it? An attention layer can in principle relate frame 1 to frame 2, but it must first spend capacity discovering that two spatially-aligned tokens at adjacent times are related, then learn what their difference means. Tubelet embedding hands the model that relationship for free: the linear projection E sees both frames simultaneously and can directly compute a motion-sensitive feature (an edge moving right looks different from an edge moving left). The paper shows tubelet embedding consistently beats uniform frame sampling — fusing time early is strictly better.

Adding position

Like ViT, the raw tubelet tokens carry no notion of where they sit in space or time — self-attention is permutation-invariant. ViViT adds a learned positional embedding p of shape [N, d] to the token sequence: z = [zcls; E·x1; ...; E·xN] + p. The class token zcls, also borrowed from ViT/BERT, is a learned vector prepended to the sequence; its final-layer output is the clip-level representation fed to the classifier. (Some ViViT variants pool over all tokens instead; we will see why in Chapter 3.)

Tubelet embedding: carving a 3D grid from the volume

The clip on the left is sliced into non-overlapping tubelets of size t×h×w. Each brick (right) is flattened and projected to one token. Adjust the temporal tubelet size t and watch the token count — and the motion captured per token — change.

Temporal size t 2
python
# Tubelet embedding = a single strided 3D convolution
import torch
import torch.nn as nn

class TubeletEmbed(nn.Module):
    def __init__(self, d=768, t=2, h=16, w=16, c=3):
        super().__init__()
        # kernel == stride  ->  non-overlapping cuboids
        self.proj = nn.Conv3d(c, d, kernel_size=(t, h, w), stride=(t, h, w))

    def forward(self, x):
        # x: [B, C, T, H, W]  e.g. [B, 3, 32, 224, 224]
        x = self.proj(x)            # [B, d, T/t, H/h, W/w] = [B, 768, 16, 14, 14]
        B, d = x.shape[0], x.shape[1]
        x = x.flatten(2).transpose(1, 2)  # [B, N, d] = [B, 3136, 768]
        return x

clip = torch.randn(1, 3, 32, 224, 224)
tok = TubeletEmbed()(clip)
# tok.shape -> [1, 3136, 768]   (N = 16 * 14 * 14)
Realization check: tubelet embedding is not a new operator — it is exactly the 3D analog of ViT patchify, implementable as one Conv3d with kernel=stride. The single design decision that matters is t>1: it both shrinks the sequence (fewer tokens) and injects motion (each token sees several frames). Everything downstream is a standard Transformer encoder.
What is the key advantage of tubelet embedding over uniform frame sampling?

Chapter 2: The Token Explosion & Model 1

Now we have a clean sequence of N tubelet tokens. The simplest possible video Transformer — ViViT's Model 1, the "Spatio-temporal attention" model — does the obvious thing: prepend a class token, add positions, and run a plain ViT encoder over all N tokens jointly. Every token attends to every other token, regardless of whether they are separated in space, in time, or both. This is the most expressive option: it can model any spatio-temporal interaction in a single layer. It is also the most expensive.

Why expensive? Self-attention forms an attention matrix A of shape [N, N]. Its compute and memory cost scale as O(N²·d) — quadratic in the number of tokens. For images, N≈200 is fine. For video, N is in the thousands, and N² is in the millions.

cost(Model 1)  ∝  N²  =  (nt · ns

where nt = number of temporal tokens (T/t) and ns = number of spatial tokens per frame (H/h · W/w). The product is squared. This is the crux. The whole reason ViViT has four models is that Model 1's N² is unaffordable past short clips, so Models 2-4 each find a different way to factorize the attention so the cost drops from quadratic-in-the-product to roughly quadratic-in-each-factor-separately.

Worked cost comparison

Use our running numbers: nt = 16 temporal tokens, ns = 14×14 = 196 spatial tokens, so N = 16·196 = 3,136.

QuantityExpressionValue
Total tokens Nnt · ns16 · 196 = 3,136
Model 1 joint attentionN² = (nt ns3,136² ≈ 9.83 M
Spatial-only attention (per frame)nt · ns²16 · 196² ≈ 0.61 M
Temporal-only attention (per location)ns · nt²196 · 16² ≈ 0.05 M
Factorized (spatial + temporal)nt ns² + ns nt²0.66 M

Read that last row against Model 1: factorizing the attention into a spatial pass plus a temporal pass costs about 0.66 M vs 9.83 M — roughly a 15× reduction in pairwise-comparison count, and the gap widens as the clip gets longer (longer clips raise nt, and joint attention pays for nt inside the square while factorized pays for it linearly). This single arithmetic fact is the engine behind Models 2, 3, and 4.

The factorization insight, stated once: a spatio-temporal interaction can be approximated by composing a spatial interaction with a temporal interaction. "Which patches in this frame matter, and how do those summaries evolve over time?" Instead of one giant N×N attention, you do several small spatial attentions (within each frame) and several small temporal attentions (across frames), and you compose them. You lose the ability to directly relate, in one shot, patch-in-frame-3 to a different patch-in-frame-9 — but you regain it across layers, at a fraction of the cost.

Model 1 in code, and its data flow

python
# Model 1: joint space-time attention (plain ViT over all N tokens)
import torch, torch.nn as nn

class JointSpaceTime(nn.Module):
    def __init__(self, d=768, heads=12, depth=12):
        super().__init__()
        layer = nn.TransformerEncoderLayer(d, heads, batch_first=True)
        self.enc = nn.TransformerEncoder(layer, depth)
        self.cls = nn.Parameter(torch.randn(1, 1, d))

    def forward(self, tok):       # tok: [B, N, d] = [B, 3136, 768]
        B = tok.shape[0]
        cls = self.cls.expand(B, -1, -1)
        z = torch.cat([cls, tok], dim=1)   # [B, 3137, 768]
        z = self.enc(z)               # attention is [3137 x 3137] per layer/head!
        return z[:, 0]               # class token -> [B, 768]
N² vs factorized: the cost gap as the clip grows

Holding the spatial tokens fixed at 196/frame, watch how Model 1's joint attention (warm) and the factorized cost (teal) diverge as you add temporal tokens. Drag the slider to lengthen the clip; the log-scale gap is the reason the rest of the paper exists.

Temporal tokens n_t 16
Common misconception: "Factorized models are cheaper because they have fewer parameters." No — they often have similar or even more parameters (an extra temporal Transformer in Model 2). What drops is the attention computation: you replace one O(N²) matrix with a sum of smaller O(ns²) and O(nt²) matrices. Parameters and FLOPs are different axes; ViViT's factorizations buy FLOPs and memory, not weights.
Why does the joint spatio-temporal model (Model 1) become impractical for longer video clips?

Chapter 3: Model 2 — Factorized Encoder

The first and most influential factorization is the Factorized Encoder. The idea is a clean two-stage pipeline that mirrors how a person might describe a clip: "first, what is in each frame; then, how do those per-frame summaries change over time." It uses two separate Transformers stacked in series.

Stage 1 — Spatial encoder (Ls layers)
Runs independently on each frame's ns spatial tokens. Within a frame, every patch attends to every other patch — but NOT across frames. Output: one summary token per frame (the per-frame class token).
↓ collect the nt per-frame summaries into a sequence
Stage 2 — Temporal encoder (Lt layers)
Runs over the nt frame-summary tokens. These attend across time. Output: a single clip representation → classifier.

Concretely: the spatial encoder treats the video as nt independent images. For each frame it produces a representation hi (the frame-level class-token output, dimension d). You now have nt such vectors — a short sequence of frame summaries. The temporal encoder is a second Transformer that attends over just these nt tokens to fuse them into a clip-level vector. This is architecturally close to the classic "CNN per frame + temporal model on top" recipe of older video work — except both stages are now pure Transformers.

The data flow, with shapes

Start from tubelet tokens of shape [B, nt, ns, d] = [B, 16, 196, 768] (reshaped so the frame axis is explicit).

StepOperationTensor shape
1. Reshape for spatialfold frames into batch[B·16, 196, 768]
2. Spatial encoderLs-layer ViT, attends over 196 tokens[B·16, 197, 768] (with frame cls)
3. Take frame clsper-frame summary[B·16, 768] → [B, 16, 768]
4. Temporal encoderLt-layer Transformer, attends over 16 tokens[B, 17, 768] (with clip cls)
5. Take clip clsfinal representation[B, 768] → classifier

The cost. The spatial encoder pays nt · ns² (a separate 196×196 attention for each of 16 frames). The temporal encoder pays ns · nt² (one 16×16 attention per location). With our numbers: 16·196² + 16² ≈ 614k + 256 ≈ 0.61 M pairwise comparisons, versus Model 1's 9.83 M. The temporal encoder is almost free because nt is small. The FLOPs are dominated entirely by the spatial encoder, which is just a per-frame image ViT — so the Factorized Encoder costs scarcely more than running an image model on each frame. This is why, in the paper, Model 2 is the most FLOP-efficient of the four and a very strong accuracy/cost trade-off.

Why this is the practical favorite: The Factorized Encoder is the variant most people reach for. It is the cheapest (temporal stage is tiny), it reuses an image ViT almost verbatim for the spatial stage (so all the pretraining transfers cleanly — Chapter 6), and on the largest video datasets it actually matches or beats the expensive joint Model 1. The price is the lowest cross-time expressivity of the four models: fine-grained motion that needs patch-to-patch interaction across frames must be summarized away into a single per-frame vector before the temporal stage ever sees it.
Factorized Encoder: spatial stage then temporal stage

Watch the two-stage flow. Stage 1 (teal) runs a ViT inside each frame and emits one summary token per frame. Stage 2 (warm) runs a second Transformer across those summaries. Click "Step" to advance the animation; the highlighted stage shows where attention is happening.

Stage 0 — input tubelets
python
# Model 2: Factorized Encoder — spatial ViT then temporal Transformer
class FactorizedEncoder(nn.Module):
    def __init__(self, d=768, heads=12, Ls=12, Lt=4):
        super().__init__()
        sl = nn.TransformerEncoderLayer(d, heads, batch_first=True)
        tl = nn.TransformerEncoderLayer(d, heads, batch_first=True)
        self.spatial  = nn.TransformerEncoder(sl, Ls)
        self.temporal = nn.TransformerEncoder(tl, Lt)

    def forward(self, tok):       # tok: [B, n_t, n_s, d] = [B, 16, 196, 768]
        B, nt, ns, d = tok.shape
        # Stage 1: fold frames into batch, attend WITHIN each frame
        x = tok.reshape(B * nt, ns, d)   # [B*16, 196, 768]
        x = self.spatial(x)               # cheap: 196x196 per frame
        x = x.mean(dim=1)               # frame summary -> [B*16, 768]
        # Stage 2: attend ACROSS the 16 frame summaries
        x = x.reshape(B, nt, d)        # [B, 16, 768]
        x = self.temporal(x)              # cheap: 16x16
        return x.mean(dim=1)            # clip vector -> [B, 768]
In the Factorized Encoder, why is the temporal stage almost computationally free?

Chapter 4: Model 3 — Factorized Self-Attention

Model 2 factorized at the encoder level: two whole Transformers in series. Model 3 factorizes inside each Transformer block instead. It keeps a single stack of layers operating on the full set of N tokens, but within every block it splits the one self-attention operation into two sequential attentions: first attend only over tokens from the same temporal index (spatial), then attend only over tokens at the same spatial index (temporal).

block(z) = z + Temporal( Spatial(z) )

The trick is purely a matter of reshaping. The token tensor is logically [B, nt, ns, d]. To do spatial attention, you reshape so the spatial axis is the sequence and the temporal axis is folded into the batch: [B·nt, ns, d] — now standard self-attention only mixes tokens within a frame. To do temporal attention, you reshape the other way: [B·ns, nt, d] — now self-attention only mixes tokens across time at a fixed spatial location. No token-to-token interaction is lost permanently; it just happens in two steps within the block, and is recombined as the block repeats over depth.

The reshape, made concrete

With nt=16, ns=196, d=768 and batch B:

Sub-stepReshapeAttention is overMatrix size
Spatial[B, 16, 196, 768] → [16B, 196, 768]196 patches within a frame196 × 196
Temporal[B, 16, 196, 768] → [196B, 16, 768]16 times at one location16 × 16

The combined cost per block is again nt ns² + ns nt² ≈ 0.66 M — the same dramatic reduction from Model 1's N². The number of parameters is identical to Model 1 (it has the same total set of attention projections), but the compute is factorized. The paper notes Model 3 has the same number of layers as Model 1 yet, because the two attentions are split, the per-block FLOPs drop.

Ordering and why it barely matters: You can do spatial-then-temporal or temporal-then-spatial. The paper finds the order does not significantly change accuracy — what matters is that both happen each block, so over the full depth every pair of tokens gets an indirect path: token A → (spatial) → some shared token → (temporal) → token B. The factorization is an approximation to full attention that becomes tighter with more layers.
Common misconception: "Factorized self-attention can never relate a patch in frame 3 to a different patch in frame 9, so it must be strictly worse than joint attention." In a single block, true — there is no direct A-to-B edge. But stacked blocks compose spatial and temporal mixing, so the information does flow across both axes, just along a two-hop path. With enough depth the approximation is close, which is why Models 3 and 4 land near Model 1's accuracy at a fraction of the cost.
Factorized self-attention: two reshapes inside one block

The grid is the [n_t × n_s] token field. Toggle between the spatial sub-step (each frame's tokens attend among themselves — rows light up) and the temporal sub-step (each spatial column attends across time — columns light up). The same tokens, two different groupings.

Spatial: attend within each frame
python
# Model 3: factorized self-attention inside a single block
def factorized_block(z, spatial_attn, temporal_attn, B, nt, ns, d):
    # z: [B, nt*ns, d]  (the N tokens of one clip)
    # --- spatial: fold time into batch, attend within each frame ---
    zs = z.reshape(B, nt, ns, d).reshape(B * nt, ns, d)
    zs = spatial_attn(zs)                 # 196x196 attention
    z  = zs.reshape(B, nt, ns, d)
    # --- temporal: fold space into batch, attend across time ---
    zt = z.permute(0, 2, 1, 3).reshape(B * ns, nt, d)
    zt = temporal_attn(zt)                # 16x16 attention
    z  = zt.reshape(B, ns, nt, d).permute(0, 2, 1, 3)
    return z.reshape(B, nt * ns, d)
How does Model 3 (Factorized Self-Attention) differ from Model 2 (Factorized Encoder)?

Chapter 5: Model 4 — Factorized Dot-Product

Models 2 and 3 factorize across operations (two encoders, or two attentions in series). Model 4 factorizes at the most granular level possible: inside a single multi-head attention, across the heads. Half the attention heads attend spatially; the other half attend temporally. They run in parallel, and their outputs are concatenated — exactly the standard multi-head concat. There is only one attention operation per block, same depth as Model 1, but each head sees a different neighborhood.

Recall scaled dot-product attention: Attention(Q,K,V) = softmax(QKT/√dk)V. The only thing that determines which tokens a head can attend to is the set of keys K (and values V) it is given. Model 4's move: for the spatial heads, restrict K and V to tokens sharing the same temporal index as the query; for the temporal heads, restrict K and V to tokens sharing the same spatial index. The queries Q are unchanged. So a spatial head computes softmax(Q·KsT/√dk)Vs and a temporal head computes softmax(Q·KtT/√dk)Vt, where the subscript denotes the restricted key/value set.

Ys = Attention(Q, Ks, Vs)    Yt = Attention(Q, Kt, Vt)    Y = Concat(Ys, Yt) WO

Why this is even cheaper in the right sense

Crucially, Model 4 has the same number of parameters and the same number of layers as Model 1, but each head's attention is over a smaller key set (ns or nt instead of N). Because the spatial and temporal heads run in parallel within the one attention op — not in series as in Model 3 — Model 4 fuses space and time in a single step per block, without the extra serial reshape-attend of Model 3. It is, in a sense, the most "native" multi-head factorization: it changes nothing about the Transformer except which keys each head looks at.

ModelHow it factorizesExtra params vs Model 1Cross-time reach
1 — Jointnone (full N×N attention)Direct, any pair
2 — Fact. Encodertwo encoders in series+ a temporal TransformerOnly via frame summaries
3 — Fact. Self-Attntwo attentions per block (series)noneTwo-hop across layers
4 — Fact. Dot-Productheads split spatial / temporal (parallel)noneTwo-hop across layers
The unifying picture: all four models compute the same conceptual thing — a spatio-temporal representation — but spend their attention budget differently. Model 1 pays full N² for direct everything-to-everything. Models 2-4 each approximate that with cheaper components: an encoder split (2), a serial attention split (3), or a head split (4). The paper's experiments show that Model 1 is best when data and compute are plentiful, but the factorized models close most of the gap at a fraction of the cost — and Model 2 is the best all-round trade-off.

A 3-token worked dot-product split

Suppose a query token sits at (time=1, space=2). Its spatial key set is all tokens with time=1; its temporal key set is all tokens with space=2. If the field has nt=3 times and ns=4 spaces, a spatial head compares the query against 4 keys, a temporal head against 3 keys — never against the full 12. Two small softmaxes replace one large one.

Factorized dot-product: heads split spatial vs temporal keys

The query token is fixed (warm). Spatial heads (teal) only see keys in the query's row (same time); temporal heads (purple) only see keys in the query's column (same space). Drag to move the query and watch each head's key set follow. Two small key sets, run in parallel, replace the full grid.

Query position t1,s2
python
# Model 4: factorized dot-product — half the heads spatial, half temporal
def factorized_dot_product(Q, K, V, idx_t, idx_s, n_heads=12):
    # Q,K,V: [B, n_heads, N, d_k];  idx_t/idx_s give each token's (time, space) id
    half = n_heads // 2
    Ys = attn_restrict(Q[:, :half], K[:, :half], V[:, :half],   # spatial heads:
                       same_index=idx_t)   # keys must share the query's TIME
    Yt = attn_restrict(Q[:, half:], K[:, half:], V[:, half:],   # temporal heads:
                       same_index=idx_s)   # keys must share the query's SPACE
    return torch.cat([Ys, Yt], dim=1)   # concat heads, then W_O (standard MHA)
What is the distinguishing idea of Model 4 (Factorized Dot-Product Attention)?

Chapter 6: Regularizing on Small Data

There is a reason ViTs were not used for video earlier: Transformers have no built-in inductive bias. A CNN bakes in translation-equivariance and locality — it "knows" nearby pixels are related before it sees any data. A Transformer assumes nothing; it must learn even basic locality from examples. That is why ViT needed enormous datasets (JFT-300M) to beat CNNs. Video datasets are far smaller — Kinetics-400 has ~250k clips, Epic-Kitchens and Something-Something fewer still. Train a fresh ViViT on that and it overfits catastrophically. The paper's third contribution is the recipe that makes it work anyway.

Lever 1 — Initialize from an image model

The single most important trick: do not train from scratch — initialize from a ViT pre-trained on images (ImageNet-21k or JFT). The spatial parts of ViViT are architecturally identical to image ViT, so their weights transfer directly. But two pieces have no image counterpart and need careful initialization:

Positional embeddings
Image ViT has ns positions; video has nt·ns. ViViT repeats the image positional embedding across all temporal indices, so every frame starts from the same spatial layout the image model already understands.
Tubelet embedding filter E
Image ViT has a 2D patch filter; tubelets need a 3D filter. ViViT initializes it by "inflation" — replicate the 2D filter across the t temporal positions and divide by t, so at init the tubelet behaves like averaging the 2D embedding over its frames (the "central frame init" is an alternative: put all weight on the middle frame).

Filter inflation, in numbers. Suppose the image patch filter is a 2D weight E2D mapping a 16×16×3 patch to a 768-vector. For a tubelet with t=2, the 3D filter E3D maps a 2×16×16×3 brick. Inflation sets E3D[τ] = E2D/t for each of the t=2 temporal slices. Then at step 0, the tubelet token equals the average of the 2D embeddings of its t frames — a sensible warm start that exactly reproduces the image model when the frames are identical.

Levers 2-4 — Strong regularization

Even with a good init, mid-sized video data overfits a big Transformer. ViViT stacks the standard heavy-regularization toolkit, and the ablations show each one matters:

TechniqueWhat it doesWhy it helps video
Stochastic depthRandomly drop whole residual blocks during training (drop prob grows with depth)Acts like training an ensemble of shallower nets; the single biggest regularizer in the ablation
MixupTrain on convex blends of two clips and their labelsSmooths the decision boundary; very effective on small data
Label smoothingSoften one-hot targets toward a uniform floorPrevents over-confident logits, improves calibration
RandAugment / rand-erasingRandom photometric + geometric augmentationsMultiplies effective dataset size
The headline ablation result: ViViT shows that on the smaller datasets, adding these regularizers (especially stochastic depth and mixup) lifts accuracy by a large margin — on Something-Something or Epic-Kitchens the gain from regularization alone is several points of top-1, and without it the from-scratch Transformer is well behind the CNN baselines. On the large dataset (Kinetics with JFT init) the regularizers help less, because abundant data already prevents overfitting. Regularization need is inversely proportional to data size — exactly what you would predict.
Regularization vs dataset size: train/val gap

Schematic of the overfitting story. Without regularization (warm), validation accuracy peaks early then degrades as the model memorizes — and the smaller the dataset, the worse the collapse. With ViViT's recipe (teal), the gap shrinks. Drag the slider to shrink the dataset and watch the unregularized curve fall apart.

Dataset size 60%
Common misconception: "Bigger model always means better — just scale ViViT up." On Kinetics with massive pretraining, yes. But on a small target dataset, a bigger un-regularized Transformer overfits harder and ends up worse than a smaller model or a CNN. ViViT's lesson is that for video, the architecture is only half the story; the training recipe (image-model init + heavy regularization) is what unlocks the Transformer on realistic dataset sizes.
Why does ViViT initialize from an image-pretrained ViT and rely heavily on regularization?

Chapter 7: Experiments & Ablations

ViViT was evaluated on the standard video classification benchmarks: Kinetics-400 and Kinetics-600 (large, appearance-heavy action recognition), Epic-Kitchens-100 (egocentric, fine-grained verbs and nouns), Something-Something v2 (motion-centric — actions defined by how things move, where appearance alone is useless), and Moments in Time. The headline: ViViT, particularly the large model initialized from JFT, set state-of-the-art accuracy on Kinetics-400/600 at the time, surpassing the strong 3D-CNN baselines (SlowFast and friends).

What the four models cost and deliver

The paper's model comparison is the practical takeaway. Reported qualitatively:

ModelAccuracyCompute (FLOPs)When to use
1 — JointHighest (with enough data/compute)Highest (full N²)Best accuracy, ample budget
2 — Fact. EncoderVery close to Model 1Lowest — dominated by per-frame spatial ViTBest accuracy/FLOP trade-off; the default
3 — Fact. Self-AttnSlightly below Model 1ModerateSame params as Model 1, cheaper compute
4 — Fact. Dot-ProductComparable to Model 3ModerateSingle-step parallel head split

Tubelet ablation. Tubelet embedding (t>1, fuse motion at input) consistently beats uniform frame sampling. And a bigger temporal tubelet means fewer tokens, so accuracy trades against compute: larger t is cheaper but coarser; the paper's sweet spot is a small t (2). Central-frame initialization of the 3D filter slightly edges out plain inflation in some settings.

Test-time views. Like 3D-CNN evaluation protocols, ViViT samples multiple temporal "views" (and spatial crops) from each test video and averages their predictions. More views = higher accuracy at higher inference cost; the paper reports the standard multi-view evaluation. This is why a "model accuracy" number is always paired with a view count.

The motion test: Something-Something v2

Kinetics is notoriously appearance-biased — many actions are guessable from a single frame ("playing guitar" has a guitar in it). Something-Something is the opposite: classes like "moving X up" vs "moving X down" are identical in appearance and differ only in motion direction. This is the dataset that punishes a model with weak temporal modeling. Here the more expressive models (joint, and factorized variants with genuine cross-time attention) and tubelet embedding matter most — appearance shortcuts do not save you.

Accuracy vs compute: the four models on one plane

A schematic Pareto view (relative, not exact paper numbers): each model is a point in (compute, accuracy). Model 2 sits at the efficient knee; Model 1 buys the last bit of accuracy at high cost. Click a model to highlight it and read its trade-off.

Model 1: highest accuracy, highest cost

A worked multi-view inference count. Say inference uses 4 temporal views × 3 spatial crops = 12 forward passes per clip, each averaged. If a single forward pass of Model 1 costs C, the joint model pays 12C at test time. Model 2's per-pass cost is roughly 15× smaller (Chapter 2), so it pays ~12C/15 ≈ 0.8C — a full multi-view evaluation of the factorized encoder is cheaper than a single pass of the joint model. That is the deployment argument for Model 2.

Common misconception: "ViViT beats CNNs, so 3D convolutions are obsolete." The paper is more careful. ViViT wins decisively on large, appearance-driven benchmarks where its big-data pretraining shines. On smaller, motion-heavy datasets the margin narrows and the regularization recipe is doing heavy lifting. The honest reading: attention is a competitive, scalable alternative — not a free lunch that dominates everywhere regardless of data.
According to ViViT's experiments, which model offers the best accuracy-per-FLOP trade-off, and why?

Chapter 8: The Variant Explorer

This is the payoff chapter. Pick a clip configuration (temporal tubelet size, clip length) and a model variant, and watch the whole pipeline come alive: tokens get carved, attention gets factorized, and the cost meter responds. Everything here is computed live from the same arithmetic we derived — N = (T/t)·ns, and each model's attention-comparison count. Use it to build a gut feel for how the four design choices trade compute against cross-time expressivity.

ViViT Variant Explorer — tokens, attention pattern, and cost

Top: the [n_t × n_s] token field with the selected model's attention pattern drawn over it (which tokens a query reaches). Bottom: the live pairwise-comparison count for this configuration, on a log scale, with Model 1 (joint) shown as the dashed reference. Change the model, the clip length, and the tubelet size.

Clip frames T 32
Tubelet t 2
N = 3136 tokens · Model 1 · ~9.83M comparisons

Drive it a moment. Set the model to M1 Joint and drag clip frames up — the comparison count rockets, because nt lives inside the square. Now switch to M2 Fact-Enc with the same long clip — the count barely moves, because the temporal stage is cheap and the spatial cost is per-frame. Then raise the tubelet t: every model gets cheaper at once, because fewer tokens means a smaller N for all of them — the tokenizer and the attention factorization are independent levers you can pull together.

The mental model to keep: ViViT gives you two dials. The tubelet dial (t) controls how many tokens exist and how much motion each carries — it shrinks N before attention even runs. The factorization dial (Model 1→4) controls how the attention over those tokens is decomposed — it shrinks the N² cost given a fixed N. Real systems tune both: a moderate tubelet to thin the sequence, plus the Factorized Encoder to make the remaining attention affordable.

Chapter 9: Limits & Connections

ViViT proved that a pure-attention model can lead video understanding — but it also exposed the tensions the next wave of papers would resolve. Knowing the limits is as important as knowing the method.

Limitations

Still expensive at the top end
Model 1's joint attention is unaffordable for long clips; even factorized models grow with clip length. ViViT processes short clips and averages views — it does not natively reason over minutes of video.
Data-hungry without the recipe
Strong results lean on large-scale image pretraining (ImageNet-21k / JFT) plus heavy regularization. Train from scratch on a small video set and CNNs are competitive or better.
Global, not local-first
Unlike a CNN, ViViT has no built-in locality. The factorized variants reintroduce structure by hand (split space vs time), hinting that pure global attention over a 3D volume is wasteful — a clue the next architectures exploit.

What came next

Video Swin Transformer brought hierarchical, windowed attention (local spatio-temporal windows that shift between layers) — recovering the CNN's locality bias inside a Transformer and improving accuracy/efficiency. MViT (Multiscale Vision Transformers) built a feature pyramid by pooling keys/values, giving the model multiple resolutions like a CNN backbone. TimeSformer (concurrent with ViViT) explored the same factorization space — "divided space-time attention" is essentially Model 3. And the masked-autoencoding line (VideoMAE) attacked the data-hunger directly: self-supervised pretraining on video itself, reducing the dependence on image pretraining.

Cheat sheet

ConceptOne-line summary
Tubelet embeddingTokenize the video with 3D bricks (t×h×w); one Conv3d with kernel=stride. Fuses motion at input.
Token count NN = (T/t)(H/h)(W/w) = nt·ns. Bigger tubelet → fewer tokens.
Model 1 (Joint)Full attention over all N tokens. Most expressive, O(N²), most expensive.
Model 2 (Fact. Encoder)Spatial ViT per frame → temporal Transformer over frame summaries. Cheapest, best trade-off.
Model 3 (Fact. Self-Attn)One stack; each block does spatial attention then temporal attention (reshape). Same params as M1.
Model 4 (Fact. Dot-Product)Half the heads attend spatially, half temporally, in parallel within one MHA. Same params as M1.
Regularization recipeImage-ViT init (repeat pos-emb, inflate 3D filter) + stochastic depth + mixup + label smoothing. Essential on small data.
Cost savingFactorizing turns (ntns)² into ntns² + nsnt² — ~15× fewer comparisons at our default config.

Continue learning

Closing thought: ViViT's lasting idea is not any single one of its four models — it is the framing. Video is a 3D volume; tokenizing it is a choice (tubelets), and attending over the tokens is a budget you can spend along the spatial axis, the temporal axis, or both. Once you see attention as a divisible resource laid over a structured grid, every later video Transformer — windowed, multiscale, masked — is just a different way of spending the same budget.