Unexpected result of convolution operation
Here is code I wrote to perform a single convolution and output the shape.

Using formula from http://cs231n.github.io/convolutional-networks/ to calculate output size : 


  You can convince yourself that the correct formula for calculating how
  many neurons “fit” is given by (W−F+2P)/S+1


The formula for computing the output size has been implemented below as 

def output_size(w , f , stride , padding) : 
        return (((w - f) + (2 * padding)) / stride) + 1


The issue is output_size computes a size of 2690.5 which differs to the result of the convolution which is 1350 : 

%reset -f

import torch
import torch.nn.functional as F
import numpy as np
from PIL import Image
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from pylab import plt
plt.style.use('seaborn')
%matplotlib inline

width = 60
height = 30
kernel_size_param = 5
stride_param = 2
padding_param = 2

img = Image.new('RGB', (width, height), color = 'red')

in_channels = 3
out_channels = 3

class ConvNet(nn.Module):
    def __init__(self):
        super(ConvNet, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(in_channels, 
                      out_channels, 
                      kernel_size=kernel_size_param, 
                      stride=stride_param, 
                      padding=padding_param))

    def forward(self, x):
        out = self.layer1(x)

        return out

# w : input volume size
# f : receptive field size of the Conv Layer neurons
# output_size computes spatial size of output volume - spatial dimensions are (width, height)
def output_size(w , f , stride , padding) : 
    return (((w - f) + (2 * padding)) / stride) + 1

w = width * height * in_channels
f = kernel_size_param * kernel_size_param

print('output size :' , output_size(w , f , stride_param , padding_param))

model = ConvNet()

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=.001)

img_a = np.array(img)
img_pt = torch.tensor(img_a).float()
result = model(img_pt.view(3, width , height).unsqueeze_(0))
an = result.view(30 , 15 , out_channels).data.numpy()

# print(result.shape)
# print(an.shape)

# print(np.amin(an.flatten('F')))

print(30 * 15 * out_channels)


Have I implemented output_size correctly ? How to amend this model so the result of Conv2d has same shape as result of output_size ?

The problem is that your input image is not a square, so you should apply the formula on the width and the heigth of the input image.
And also you should not use the nb_channels in the formula because we are explicitly defining how many channels we want in the output.
Then you use your f=kernel_size and not f=kernel_size*kernel_size as described in the formula.

w = width 
h = height
f = kernel_size_param
output_w =  int(output_size(w , f , stride_param , padding_param))
output_h =  int(output_size(h , f , stride_param , padding_param))
print("Output_size", [out_channels, output_w, output_h]) #--&gt; [1, 3, 30 ,15]


And then output size :

print("Output size", result.shape)  #--&gt; [1, 3, 30 ,15]  


Formula source : http://cs231n.github.io/convolutional-networks/
