Roadmap / Diffusion & Multimodal Models

✓

Vision Transformer Patch Embedding

easymultimodaltransformer

The problem

A transformer reads a sequence of vectors. To read an image, the ViT (Vision Transformer; Dosovitskiy et al., 2021) cuts it into square patches, flattens each patch into a vector, and treats the patches as tokens, like words in a sentence. You will write the cutting and the embedding.

For images of shape (B,H,W,C)(B, H, W, C) (batch, height, width, channels) and patch size PP (dividing HH and WW):

  1. Cut each image into N=(H/P)(W/P)N = (H/P)(W/P) patches of P×PP \times P pixels, in row-major order: left to right, then top to bottom.
  2. Flatten each patch into P⋅P⋅CP \cdot P \cdot C numbers, in the order patch[row, col, channel].
  3. Project with a learned matrix EE of shape (P2C,D)(P^2 C, D): each patch becomes a vector of DD numbers.
  4. Prepend the learned class embedding (shape (D,)(D,)) and add the position embeddings (shape (N+1,D)(N + 1, D)).

Example. A toy image of 4×44 \times 4 pixels, one channel, with the pixels numbered 0,…,150, \dots, 15 row by row, and P=2P = 2:

 0  1  2  3
 4  5  6  7
 8  9 10 11
12 13 14 15

There are N=4N = 4 patches of 44 numbers each. In row-major order: [0, 1, 4, 5] (top-left), [2, 3, 6, 7] (top-right), [8, 9, 12, 13] (bottom-left), [10, 11, 14, 15] (bottom-right). The result of patchify has shape (1,4,4)(1, 4, 4).

A real image of 224×224224 \times 224 pixels with 3 channels and P=16P = 16 gives 14⋅14=19614 \cdot 14 = 196 patches of 16⋅16⋅3=76816 \cdot 16 \cdot 3 = 768 numbers, and 197 tokens with the class token.

Cutting without loops

With one reshape and one transpose:

  1. x.reshape(B, H // P, P, W // P, P, C): the axes are now (batch, patch row, pixel row inside the patch, patch column, pixel column inside the patch, channel).
  2. transpose(0, 1, 3, 2, 4, 5): bring the two patch-grid axes together, then the two pixel axes: (batch, patch row, patch column, pixel row, pixel column, channel).
  3. reshape(B, N, P * P * C): flatten the grid into a list of patches and each patch into a vector.

What to implement

  • patchify(images, P): shape (B,N,P2C)(B, N, P^2 C).
  • vit_embed(images, P, E, cls, pos): shape (B,N+1,D)(B, N + 1, D).

Requirements

  • No Python loops.
  • Raise ValueError if PP does not divide HH and WW.
solution.py
Python idle

Press Run (⌘/Ctrl + Enter) to test your code.