Based on the description in CS231n, we know, that a conv layer with a kernel size of 3 and no padding will reduce the spatial size by ones pixel on each side.
Max pooling with a kernel size and stride of 2 will halve the spatial size.
Let’s have a look at the model and split the layers to calculate the shape based on these assumptions.
Have a look at the comments to see the output shape:
class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        # 1 input image channel, 6 output channels, 3x3 square convolution
        # kernel
        self.conv1 = nn.Conv2d(1, 6, 3)
        self.conv2 = nn.Conv2d(6, 16, 3)
        # an affine operation: y = Wx + b
        self.fc1 = nn.Linear(16 * 6 * 6, 120)  # 6*6 from image dimension
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # assuming input is [N, 1, 32, 32]
        x = F.relu(self.conv1(x)) # outputs [N, 6, 30, 30]
        x = F.max_pool2d(x, (2, 2)) # outputs [N, 6, 15, 15]
        x = F.relu(self.conv2(x)) # outputs [N, 16, 13, 13]
        x = F.max_pool2d(x, 2) # outputs [N, 16, 6, 6]
        x = x.view(-1, self.num_flat_features(x)) # flattens x to [N, 16*6*6]
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:]  # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features




 Machupicchu:

Also, I don’t understand why it accepts inputs like 30x30 and 31x31


For an input of 31x31 and 30x30, we’ll get the following shapes:
# For x = [N, 1, 31, 31]:
[N, 6, 29, 29]
[N, 6, 14, 14]
[N, 16, 12, 12]
[N, 16, 6, 6 ]

# For x = [N, 1, 30, 30]:
[N, 6, 28, 28]
[N, 6, 14, 14]
[N, 16, 12, 12]
[N, 16, 6, 6 ]

So we got lucky, that the final result is the same. 
As you can see, the reason for the equal output shapes is that the pooling layer uses floor for odd input shapes as described in the docs 4.
You can change it by setting ceil_mode=True, if necessary.