ShelfNet v3 — the shape of the image classifier
Every layer of the product-photo classifier we ship, what it does, and how wide it is.
ShelfNet v3 is the convolutional network behind the "what product is this?" call in the mobile app. It takes one 224×224 RGB photo and returns one of 12 product categories. The network is small on purpose because it runs on the phone. Every layer is sized for a 30 ms budget on a mid-range CPU, not for leaderboard accuracy.
Assumptions
Headline numbers
The weight file is under 10 MB in fp16, which is what lets the model ship inside the app bundle instead of behind an API. The last conv block holds 73% of all parameters; it is the first place to prune if the bundle must shrink.
Layer by layer
Each conv block halves the spatial size and doubles the channel count. The tensor keeps roughly the same number of values while the features get more abstract. Global average pooling replaces the flatten step, so the network accepts any input size at inference, but the app always sends 224×224.
ShelfNet v3
What each layer does and how wide it is
Width in the table is the output tensor: height × width × channels. Every conv layer uses padding that keeps the spatial size; only stride and pooling shrink it. Batch norm follows every conv and is folded into the conv weights at export, so it costs nothing at inference.
| Layer | Kernel / stride | Output shape | Params | What it does |
|---|---|---|---|---|
| Input | — | 224 × 224 × 3 | 0 | RGB photo, scaled to [0, 1] and mean-centred per channel |
| Stem conv | 7×7, stride 2, 32 filters | 112 × 112 × 32 | 4.8K | Detects edges, corners, and flat colour regions at a coarse scale |
| Conv block 1 | 2 × 3×3, 64 filters, then max pool 2×2 | 56 × 56 × 64 | 55.7K | Combines edges into textures such as fabric weave and print dots |
| Conv block 2 | 2 × 3×3, 128 filters, then max pool 2×2 | 28 × 28 × 128 | 222K | Finds parts: a bottle cap, a label corner, a handle |
| Conv block 3 | 2 × 3×3, 256 filters, then max pool 2×2 | 14 × 14 × 256 | 886K | Assembles parts into object regions and their layout |
| Conv block 4 | 2 × 3×3, 512 filters, no pool | 7 × 7 × 512 | 3.54M | Encodes whole-object identity; holds 73% of all parameters |
| Global avg pool | 7×7 mean per channel | 512 | 0 | Collapses the map to one 512-wide vector, position-independent |
| Dense | 512 → 256 | 256 | 131K | Mixes channels into a compact category embedding |
| Dropout 0.4 | — | 256 | 0 | Zeroes 40% of activations during training; identity at inference |
| Output | 256 → 12 | 12 | 3.1K | Softmax over the 12 product categories |
Params include biases and batch-norm scale and shift. Total: 4.85M.
The output vector is 12 probabilities that sum to 1. The app accepts the top class only when its probability is at least 0.6; below that it asks the user to retake the photo. Changing the class list means retraining only the last two layers, which takes under an hour on one GPU.