ViT Patch Embeddings - PyTorch Basics
Implement ViT Patch Embeddings in Python with NumPy. medium exercise with examples, hints, and instant feedback. No setup or signup required.
ViT Patch Embeddings
What you'll build: patch_embed(...), the input layer of a Vision Transformer: cut an image into square patches, flatten and project each one to a token, prepend a learnable CLS token and add positional embeddings.
Background
A transformer consumes a sequence of vectors. ViT (Dosovitskiy et al., 2020) turns an image into one by treating each P x P patch as a "word": a 224x224 image with P = 16 becomes 196 tokens. The extra CLS token gathers information from all patches through attention, and its final state feeds the classifier. Positional embeddings tell the model where each patch came from, since attention itself ignores order.
Algorithm
For an image (C, H, W) with H and W divisible by P:
- Split it into
num_patches = (H / P) * (W / P)patches of shape(C, P, P), ordered row-major: left to right along the top row of patches, then the next row. - Flatten each patch in
(C, P, P)order (channel first, then row, then column) to a vector of lengthC * P * P. - Project:
tokens = patches @ W_proj, shape(num_patches, embed_dim). - Prepend the CLS token:
[cls_token; tokens], shape(num_patches + 1, embed_dim). - Add the positional embeddings:
+ pos_embed.
Steps 1 to 3 are exactly a Conv2d(C, embed_dim, kernel_size=P, stride=P), which is how real ViT code implements them.
Inputs
image: float array(C, H, W).patch_size:P, which dividesHandW.embed_dim:D, the token size (equal toW_proj.shape[1]).W_proj:(C * P * P, D);cls_token:(D,);pos_embed:(num_patches + 1, D).
Expected Return Format
An array of shape (num_patches + 1, D). Row 0 is cls_token + pos_embed[0]; row 1 + i * (W / P) + j comes from the patch in patch-row i, patch-column j.
Constraints
- Vectorise the patch extraction with
reshapeandtranspose(loops over patches are acceptable in NumPy, but slow). - PyTorch track: use
reshape/permute(orTensor.unfold); don't usenn.Conv2d.
Follow-up
- How many tokens does a 224x224 image give with
P = 14, and how does attention cost scale withP? - How do you use a model trained at 224x224 on 384x384 images, given
pos_embedhas a fixed length?
Examples
Input: image (3, 8, 8), patch_size=4, embed_dim=16, W_proj (48, 16), cls_token (16,), pos_embed (5, 16) Output: shape (5, 16)
8 / 4 = 2 patches per side, 2 * 2 = 4 patches, plus the CLS token.
Input: patch_embed(np.zeros((1, 4, 4)), 2, 3, np.ones((4, 3)), np.array([1.0, 2.0, 3.0]), np.full((5, 3), 0.5)) Output: array([[1.5, 2.5, 3.5], [0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.5, 0.5]])
A blank image projects to zero tokens, so only the CLS token (row 0) and the positions remain.
Practice in Python
import numpy as np
def patch_embed(image, patch_size, embed_dim, W_proj, cls_token, pos_embed):
"""
Create ViT patch embeddings.
Args:
image: Input image (C, H, W)
patch_size: Size P of each square patch (divides H and W)
embed_dim: Dimension D of the embeddings
W_proj: Projection matrix (C*P*P, D)
cls_token: CLS token embedding (D,)
pos_embed: Positional embeddings (num_patches+1, D)
Returns:
Embeddings (num_patches + 1, D): CLS first, then patches in row-major order
"""
# Your code here
pass
The interactive editor loads with Python and NumPy. Run your implementation against 6 tests, or use the progressive hints.