Drills
Five tasks, from easy to harder. You do not need to create any files — write
and run everything in a python console or a throwaway scratch.py. Each one
has a check: a number you should get.
1. The output size of a convolution
Write conv_out_size(size, kernel, padding=0, stride=1) returning the output
width. Derive the formula yourself from what you saw: 6 − 3 + 1 = 4. Remember
that padding is added on both sides.
Check:
conv_out_size(28, 3) → 26
conv_out_size(28, 3, padding=1) → 28
conv_out_size(28, 5) → 24
conv_out_size(26, 2, stride=2) → 13
conv_out_size(7, 3, padding=1, stride=2) → 4
conv_out_size(224, 7, padding=3, stride=2) → 112
Check the last one against a real nn.Conv2d(1, 1, 7, stride=2, padding=3) and
torch.zeros(1, 1, 224, 224).
2. Counting parameters without running anything
Write conv_params(in_ch, out_ch, k). Remember: each of the out_ch filters has
in_ch × k × k weights and one bias.
Check: conv_params(1, 16, 3) → 160, conv_params(16, 32, 3) → 4,640.
Now add up the whole CNN by hand: two convolutional layers and
Linear(32·7·7, 10) (that is 1568 × 10 + 10). You should get 20,490 and
compare it with count_parameters(CNN()).
3. Show what the network "does not see"
You already have conv2d_by_hand. Take the picture with the square from step 2
and the filter EDGE.T (the same filter flipped, i.e. for horizontal edges).
Guess first which rows of the map will be zero and what sign the square's top edge will have. Then run it. You should get:
[[ 27, 36, 27, 9],
[ 0, 0, 0, 0],
[-27, -36, -27, -9],
[-27, -36, -27, -9]]
Compare with the vertical filter: there a column was zero, here a row is. One filter responds to one direction; that is why a network needs many — 16 in the first layer.
4. How many numbers one picture has
Without running anything: how many numbers (not parameters, but values) does
one picture have after each CNN layer, given channels × height × width?
Check: after the first Conv2d — 12,544, after the first MaxPool2d —
3,136, after the second Conv2d — 6,272, after the second MaxPool2d —
1,568.
Notice that the largest number (12,544) is in the first layer, not the last. In a batch of 64 pictures that layer alone holds 64 × 12,544 = 802,816 numbers — about 39 times more than all of the network's parameters (20,490). A small network does not mean small memory.
5. 5 × 5 instead of 3 × 3
In your CNN class (model.py) change both kernel_size=3 to 5 and both
padding=1 to padding=2 — and before running, work out with
conv_params how many parameters the new network will have.
Check: 28,938 (416 + 12,832 + 15,690). Run
python train.py --model cnn --epochs 15 --dropout 0.3 and compare with 87.4 %.
Write down a guess first: better, about the same or worse? The answer depends
on your seed and machine — if the difference is under ~1 point it is
indistinguishable from noise (see step 5). When you go back to 3 × 3, restore
the padding too.