Drills

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.