How do you give a video network the visual wisdom of ImageNet? You inflate a 2D image ConvNet into 3D — copying its trained filters along the time axis — and pretrain on the new, enormous Kinetics dataset. The result, I3D, doubled the state of the art overnight.
Picture two grainy clips. In the first, a person bends at the waist, hands reaching toward the floor. In the second, the same person, same gym, same lighting, is straightening up, hands rising from the floor. A single frame from the middle of either clip looks nearly identical: a half-bent body. Yet one is "sitting down" and the other is "standing up." The difference lives entirely in how the pixels move over time — the direction of the motion — not in any single image.
By 2017, image recognition was a solved-feeling problem. A 2D ConvNet pretrained on ImageNet — millions of labeled photographs across a thousand object categories — could be fine-tuned to recognize almost anything in a still picture. The trained filters in those networks were a kind of universal visual prior: edge detectors, texture detectors, part detectors, all learned for free. Every new image task got to stand on the shoulders of ImageNet.
Video had no such giant to stand on. Action-recognition benchmarks of the day — UCF-101 (13,320 clips, 101 actions) and HMDB-51 (6,766 clips, 51 actions) — were tiny by ImageNet standards. Networks trained from scratch on them overfit almost immediately. And the motion information that distinguishes "sit down" from "stand up" was something a 2D ConvNet, which sees one frame at a time, simply could not represent.
A figure passes through a half-bent pose. Scrub the slider: forward in time it reads as "stand up," backward as "sit down." The middle frame (highlighted) is identical for both — only the temporal order disambiguates the action. This is the information a 2D ConvNet throws away.
The paper that closed this gap is titled, with a wry nod to the Latin phrase, "Quo Vadis, Action Recognition? A New Model and a New Dataset" (Carreira & Zisserman, CVPR 2017). "Quo vadis?" — "where are you going?" — is also the question the model must answer about the bent figure. The paper delivers two things at once:
But a 3D ConvNet has many more parameters than its 2D cousin, and the video datasets were too small to train it from scratch. So the central engineering question of the paper becomes: how do we give a 3D ConvNet the ImageNet prior that 2D ConvNets enjoy for free? The answer — filter inflation — is the heart of this lesson. Let's first survey what people had already tried.
Before I3D, the field had converged on a handful of competing recipes for turning a stack of frames into an action label. The paper's first contribution is to evaluate all of them under one roof — same backbone, same data, same training — so the comparison is finally apples-to-apples. Understanding these four baselines is the best way to understand what I3D inherits and what it fixes.
| Approach | How it sees time | Weakness I3D fixes |
|---|---|---|
| (a) 2D ConvNet + LSTM | 2D ConvNet per frame → LSTM aggregates the per-frame features over time | The 2D ConvNet still discards low-level motion; the LSTM only sees high-level features, too late to model fine motion |
| (b) 3D ConvNet (C3D-style) | Genuine 3D convolutions over (H, W, T) at every layer | Too many parameters, no ImageNet pretraining available → overfits on small video sets, trains from scratch |
| (c) Two-Stream | One 2D net on a single RGB frame, a second 2D net on a stack of optical-flow frames; predictions averaged | Only a snapshot of motion (a short flow stack); no long-range temporal reasoning; 2D throughout |
| (d) 3D-Fused Two-Stream | Two-stream features fused by a small 3D ConvNet near the end | 3D reasoning happens only late and shallowly |
| (e) Two-Stream I3D | 3D convolutions everywhere, two streams (RGB + flow), filters inflated from ImageNet | — this is the proposal — |
Notice the two axes everyone was trading off. Axis 1 — where does time enter? Early (the input), late (an LSTM or fusion at the end), or throughout (3D convolutions). Axis 2 — can we reuse ImageNet? 2D approaches can; the pure 3D ConvNet (b) could not, because there were no pretrained 3D weights and no dataset big enough to learn them. I3D's insight is that you do not have to choose: inflation lets a fully-3D network inherit 2D ImageNet weights.
Click each baseline to see, schematically, where temporal information is mixed (warm = 2D blocks, teal = 3D blocks / temporal mixing, purple = optical-flow input). I3D pushes the teal (3D mixing) all the way down the stack and runs two of them.
A worked back-of-envelope shows why the pure 3D ConvNet (b) was stuck. Take a single 2D convolutional layer with a 3×3 kernel mapping 64 input channels to 64 output channels: that is 3×3×64×64 = 36,864 weights. Inflate it to a 3×3×3 kernel (adding a time dimension of 3) and it becomes 3×3×3×64×64 = 110,592 weights — exactly 3× more. Multiply that across an entire deep network and you have triple the parameters with one-tenth the labeled data. Without pretraining, it could not win. Inflation is what makes the parameter count affordable, because the weights arrive already trained.
To understand inflation we must first nail down exactly what a 3D convolution computes, with real tensor shapes. A video clip fed to I3D is a 5D tensor:
Where N is the batch size, C the input channels (3 for RGB, or 2 for optical flow's x/y velocity), T the number of frames, and H, W the spatial height and width. I3D trains on 64-frame clips at 224×224, so a single RGB clip is [1, 3, 64, 224, 224].
A 2D convolution uses a kernel of shape [Cout, Cin, kh, kw] and slides it over (H, W) only — it processes each frame independently and has no idea two frames are even related. A 3D convolution uses a kernel of shape:
and slides it over (T, H, W). The extra dimension kt is the kernel's temporal extent — how many frames it spans. Each output value is a sum over a little spatiotemporal cube of the input. Formally, the output at output-channel o, time t, position (y, x) is:
The only new piece compared to 2D is the inner sum over τ (the time offset). When kt = 1, the time sum has a single term and the 3D convolution degenerates into a 2D convolution applied frame-by-frame. When kt > 1, the kernel mixes information across frames — that is the whole point. A kernel that fires when "a bright edge at position p in frame τ is followed by a bright edge slightly to the right in frame τ+1" is a learned motion detector. Stack many such layers and the network builds motion features as hierarchically as a 2D ConvNet builds shape features.
Let's compute one output value to make the cube concrete. Take a single input channel, a tiny 2-frame × 3×3 patch, and a 3D kernel of temporal extent kt = 2, spatial 1×1 (so it only mixes time). Suppose the kernel is W[τ=0] = -1, W[τ=1] = +1 — a "later minus earlier" difference, i.e. a motion/change detector.
A positive 7 means "this pixel got brighter over time." Flip the kernel to W = [+1, -1] and the same input yields -7: "got darker." This sign is the temporal direction — exactly the signal that distinguishes sit-down from stand-up. A 2D convolution, seeing only one frame, can never produce this number. That single sign is the entire reason 3D convolution exists.
A 3D kernel (warm cube) slides over a stack of frames. Each frame is a grid; the kernel spans kt frames in depth. Drag the slider to move the kernel through time and watch which spatiotemporal voxels it currently covers. A 2D kernel would be flat (kt = 1); the 3D kernel has depth.
python import torch import torch.nn as nn # A 3D conv: in 3 channels (RGB), out 64, kernel 3x7x7 (t,h,w) conv3d = nn.Conv3d(in_channels=3, out_channels=64, kernel_size=(3, 7, 7), stride=(2, 2, 2), padding=(1, 3, 3)) clip = torch.randn(1, 3, 64, 224, 224) # [N,C,T,H,W] out = conv3d(clip) print(out.shape) # [1, 64, 32, 112, 112] - time AND space halved by stride 2 # Parameter count = Cout * Cin * kt * kh * kw (+ bias) print(64 * 3 * 3 * 7 * 7) # 28,224 weights # the 2D version (kt=1) would have 64*3*1*7*7 = 9,408 - exactly 1/3
Here is the idea the whole paper turns on, stated as plainly as possible. We have a 2D ConvNet trained on ImageNet — every one of its filters is a polished visual feature detector. We want a 3D ConvNet. So we take the exact same architecture, replace every N×N 2D filter with an N×N×N 3D filter, and — the trick — initialize each 3D filter by copying the 2D filter across the time dimension. We inflate the 2D weights into 3D.
Concretely, a 2D kernel has shape [Cout, Cin, kh, kw]. We want a 3D kernel of shape [Cout, Cin, kt, kh, kw]. We build it by repeating the 2D kernel kt times along the new time axis, and then dividing by kt:
Two operations: (1) repeat the 2D filter kt times along time, (2) rescale by 1/kt. Why divide by kt? This is the genuinely clever part, and the paper calls it the "bootstrapping" criterion. Read on.
Imagine feeding the inflated 3D ConvNet a boring video — a still image repeated on every frame. We want the inflated network to behave exactly like the original 2D network behaved on that single image. That way, on day zero of fine-tuning, I3D already has ImageNet's full accuracy on appearance; it only has to learn the new motion part on top.
Walk through one neuron. The 2D conv on the still image computes some response r = ∑c,i,j W2D[o,c,i,j] · X[c,i,j]. Now the 3D conv on the boring video sums the same spatial response over all kt identical frames:
Because every frame is identical and every time-slice of the filter is the same copy, this is just kt copies of the 2D response, each scaled by the filter's own scale:
The kt from summing over identical frames cancels the 1/kt we baked into the weights. The 3D activation on a boring video equals the 2D activation on the still image — exactly. The same algebra carries through pooling and the final classifier (those are linear or order-statistics), so the whole inflated network reproduces the 2D network's output on a constant video. This is the bootstrapping property: I3D boots up with ImageNet performance already intact.
Left: a learned 2D 3×3 filter (an edge detector). Right: its inflated 3D version — kt copies along time, each rescaled by 1/kt. Drag kt to add time slices; notice each slice dims as kt grows, so the sum over a boring video stays constant.
A real ConvNet is not only convolutions. Inception, the backbone I3D inflates, also has pooling layers. The paper inflates those too — a 2D max-pool over (h, w) becomes a 3D pool over (t, h, w) — but with one careful exception discussed in the next chapter. The principle is uniform: every 2D operation gets a third (time) dimension, initialized so that a constant-in-time input reproduces the 2D behavior.
I3D does not inflate just any 2D network — it inflates Inception-v1 (GoogLeNet with batch normalization), the strong, efficient ImageNet classifier from Szegedy et al. Why Inception rather than, say, a VGG or ResNet? Inception's modular blocks and aggressive use of 1×1 convolutions keep the inflated parameter count and compute manageable, and at the time it was the best accuracy-per-FLOP backbone available with public ImageNet weights. The whole network — stem convolutions, every Inception module, the pooling — is inflated.
The result, end to end, is a clip in and a 400-way (Kinetics) softmax out. Tracing the data flow for one 64-frame RGB clip:
This is the paper's most-cited subtlety, and it is pure engineering taste. Space and time are not symmetric in video. A 224×224 frame is sampled densely in space, so pooling space early (downsampling 224 → 112 → 56) loses little. But time is sampled relatively coarsely — frames are tens of milliseconds apart — and two nearby frames may capture distinct, fast motion phases (a foot down, then a foot up). If you pool time too aggressively in the early layers, you average away exactly the fast motion you are trying to detect, before any motion detector has had a chance to fire.
A concrete consequence: with 64 input frames, the temporal dimension is preserved through the early network and only collapses near the end, so the final classifier integrates motion over the entire clip. Compare this with the CNN+LSTM baseline, where the 2D ConvNet has already destroyed low-level motion frame-by-frame before the LSTM ever runs.
How the (T, H, W) dimensions shrink as a clip passes through I3D. Toggle between the naive symmetric schedule (pool time and space together from layer 1) and I3D's asymmetric schedule (hold time, pool space early). Watch the temporal axis: the naive plan collapses it too soon.
Numerically, a back-of-envelope on temporal extent: if every one of the 9 strided stages halved time, 64 frames would collapse to 64/29 < 1 — nonsense. By holding time stride 1 in the first stages and only pooling time later, I3D ends with a handful of temporal slices feeding the classifier, each summarizing a chunk of the action. That is the whole motivation: keep time alive long enough to learn motion.
You might think a fully-3D network, free to learn motion from raw RGB, would no longer need the hand-crafted optical-flow stream. Carreira & Zisserman tested exactly this — and found, perhaps surprisingly, that adding a second, optical-flow I3D stream still helps. The final model is two I3D networks trained separately and combined at test time by averaging their predictions.
Why does the flow stream still pay off when the RGB stream is already 3D? Because optical flow is a strong, noise-suppressing prior on motion. Computing flow (the paper uses the TV-L1 algorithm) is a small optimization that explicitly enforces smoothness and brightness-constancy — it cancels out static background, lighting, and texture, leaving a clean velocity field. The 3D RGB network could in principle learn to do this, but learning robust motion estimation from raw pixels is hard and data-hungry. Flow gives the temporal stream a head start that even a 3D network benefits from. The two streams make different errors, so averaging them is a genuine ensemble gain, not redundancy.
There is a small but telling detail. The RGB stream's first layer inflates straight from ImageNet's 3-channel input conv. The flow stream needs a 2-channel input, so its first-layer weights are adapted (the paper sums/averages the RGB-channel weights to seed the 2 flow channels) before inflation. Both streams are then trained on Kinetics. At test time, the average of two confident-but-independent classifiers is more accurate and more calibrated than either alone — the classic two-stream result, now lifted into 3D.
Two I3D streams produce class probabilities for the same clip. Drag the slider to set how confident the flow stream is on the true class. Watch how averaging the two distributions sharpens the final prediction even when one stream is uncertain — the ensemble effect.
python # Two-stream inference: run both I3D nets, average their softmaxes import torch rgb_logits = i3d_rgb(rgb_clip) # [1, 400] flow_logits = i3d_flow(flow_clip) # [1, 400] # Average the PROBABILITIES (post-softmax), not the raw logits p_rgb = rgb_logits.softmax(dim=-1) p_flow = flow_logits.softmax(dim=-1) p = (p_rgb + p_flow) / 2 pred = p.argmax(dim=-1) # the predicted action class
Inflation is only half the contribution. A 3D network, even bootstrapped from ImageNet, still has a large new set of temporal parameters to learn, and it needs video-scale data to learn them. So the same paper introduces Kinetics (often "Kinetics-400"): roughly 300,000 clips spanning 400 human action classes, each clip about 10 seconds, sourced from YouTube and human-verified. It is to video what ImageNet is to images — large, diverse, and the missing pretraining substrate.
The recipe is now a two-stage transfer, and the gains compound:
This is the deeper message of the title's question, "Quo Vadis?" The field had been stuck partly because of architectures and partly because of data. The paper argues you cannot fix one without the other: a great 3D architecture starved of data overfits; a great dataset fed to a 2D-bottlenecked model wastes the motion signal. Kinetics + I3D are designed as a matched pair.
Schematic accuracy on a small target benchmark as you give it more pretraining. The from-scratch I3D (warm) overfits and plateaus low; the Kinetics-pretrained I3D (teal) starts far higher and keeps climbing. The gap is the value of the dataset. Drag to vary how much target-set fine-tuning data you have.
| Dataset | Role | Scale |
|---|---|---|
| ImageNet | Stage-0 appearance pretraining (2D) | ~1.2M images, 1000 classes |
| Kinetics-400 | Stage-1 motion pretraining (3D) — the new contribution | ~300K clips, 400 classes |
| UCF-101 | Stage-2 fine-tune target benchmark | 13,320 clips, 101 classes |
| HMDB-51 | Stage-2 fine-tune target benchmark | 6,766 clips, 51 classes |
The paper's experiments answer three questions in order. (1) Among the five architecture families, which wins under a fair, identical-training comparison? (2) How much does Kinetics pretraining add to each? (3) Does the flow stream still help once everything is 3D and Kinetics-pretrained?
Trained and evaluated identically, the ordering is clear: the fully-3D, inflated, two-stream model (I3D) is the strongest, and the LSTM and early-fusion 3D baselines trail. The single most important design choice is making the network 3D throughout rather than mixing time late. Inflation is what makes this affordable — recall the parameter count tripled, and only a pretrained init makes that trainable on video-scale data.
For every architecture, adding Kinetics pretraining helps — but it helps the 3D models the most. This is the key ablation: it disentangles "is I3D good because of the architecture, or because of the data?" Answer: both, and they multiply. The 3D architecture has the capacity; Kinetics supplies the supervision to fill it.
Yes. Even with a Kinetics-pretrained 3D RGB stream, adding the flow stream gives a consistent further bump. The RGB stream alone is already strong; RGB + flow is the best. The honest takeaway the authors offer: a fully-3D network reduces but does not eliminate the value of explicit optical flow.
| Ablation knob | Effect when present | Why |
|---|---|---|
| 3D throughout vs late-fusion | Large gain | Builds hierarchical motion features, not a late patch-up |
| Inflation (ImageNet init) | Large gain over random-init 3D | Inherits appearance prior; tripled params become trainable |
| Kinetics pretraining | Large gain, biggest for 3D models | Supplies the video-scale supervision the temporal params need |
| Asymmetric early temporal pooling | Moderate gain | Preserves fast motion the early layers would otherwise average away |
| Optical-flow stream | Consistent further gain | Clean motion prior; ensemble of differently-erring nets |
Suppose for a "shaking hands" clip the true class gets probability 0.55 from RGB and 0.65 from flow, while a confusable class "high five" gets 0.30 from RGB and 0.10 from flow. Average the streams: true class → (0.55+0.65)/2 = 0.60; confuser → (0.30+0.10)/2 = 0.20. The margin grows from 0.25 (RGB alone) to 0.40 (averaged). Because the streams disagree on the confuser, averaging suppresses it more than it suppresses the true class — that is the ensemble mechanism in arithmetic.
A schematic accuracy "ladder": start from a from-scratch 2D baseline and switch on each I3D ingredient one at a time. Click each rung to add it and watch the bar climb. (Heights are illustrative of the paper's qualitative ordering, not exact reported numbers.)
This is the payoff. Below is a live, multi-control playground for the paper's two core mechanisms together: filter inflation and 3D convolution. On the left, a learned 2D filter; you inflate it into 3D with a chosen kt and choose whether to apply the 1/kt rescale. On the right, a small video — either a "boring" (constant) clip or a "moving edge" clip. The lab runs the inflated 3D filter over the clip and shows you the response. Two things to verify with your own eyes:
Left: the inflated 3D kernel, slice by slice. Right: the input clip and the 3D-conv response. The big number is the response at the center voxel; compare it to the "2D baseline" number. With rescale ON and a boring clip, they match for every kt — that is bootstrapping, live.
Play with it until the bootstrapping invariant feels obvious — that intuition (a rescaled inflation is invisible on constant input, but comes alive on motion) is the single most important idea in the paper, and it is why I3D could inherit ImageNet and still learn to see time. The two Code Labs below let you implement both halves yourself in NumPy.
I3D was the decisive step that made video models inherit the image world's pretraining advantage, and Kinetics + inflation became the default starting point for years of video research. But it is worth being clear-eyed about what it does not solve.
| Lesson | Relationship to I3D |
|---|---|
| Convolutional Networks (Gleam) | The 2D convolution and ImageNet ConvNets that I3D inflates — start here if 3D conv felt fast |
| Action Recognition (Gleam) | The task I3D solves, and the two-stream / 3D landscape, at Gleam depth |
| Video Understanding (Gleam) | The broader problem space: clips, temporal sampling, evaluation protocols |
| VideoMAE V2 (Veanor) | Masked-autoencoder pretraining for video transformers — the post-convolution, self-supervised successor to Kinetics-supervised I3D |
| VideoMamba (Veanor) | State-space sequence models for video — an alternative to both 3D conv and attention for long temporal context |
| Vision Transformer (Veanor) | The attention backbone that, extended to spacetime patches, displaced 3D conv in many video benchmarks |
| Concept | One-line summary |
|---|---|
| Problem | Video lacked an ImageNet-scale prior; 2D ConvNets discard motion; pure 3D ConvNets overfit small video sets |
| 3D convolution | Kernel [Cout, Cin, kt, kh, kw] slides over (T,H,W); the time sum lets one kernel detect motion |
| Filter inflation | W3D[τ] = W2D / kt for all τ — repeat the 2D filter across time, rescale by 1/kt |
| Bootstrapping | On a constant ("boring") video the ×kt sum cancels the ÷kt scale, so the 3D net reproduces the 2D net exactly → starts at ImageNet accuracy |
| Asymmetric pooling | Temporal stride 1 in early pools (don't average away fast motion); pool time only deeper |
| Two streams | RGB I3D + optical-flow I3D; average softmaxes → ensemble gain even though RGB is already 3D |
| Kinetics | ~300K clips, 400 classes — the video pretraining substrate; helps 3D models most |
| Backbone | Inflated Inception-v1 (with BN); best accuracy-per-FLOP image net with public ImageNet weights |