# Why conv2d computation results are all different even if their data types are all integer?

I’ve tried and compared three different methods for convolution computation with a custom kernel in Pytorch. Their results are different but I don’t understand why that is.

Setup code:

``````import torch
import torch.nn.functional as F

inp = torch.arange(3*500*700).reshape(1,3,500,700).to(dtype=torch.float32)
wgt = torch.ones((1,3,3,3)).to(dtype=torch.float32)
stride = 1
h = inp.shape - wgt.shape + 1
w = inp.shape - wgt.shape + 1
``````

Method 1

``````out1 = torch.zeros((1,h,w)).to(dtype=torch.float32)
for o in range(1):
for i in range(3):
for j in range(h):
for k in range(w):
out1[o,j,k] = out1[o,j,k] + (inp[0, i, j*stride:j*stride+3, k*stride:k*stride+3] * wgt[0,i]).sum()
out1 = out1.to(dtype=torch.int)
``````

Method 2

``````inp_unf = F.unfold(inp, (3,3))
out_unf = inp_unf.transpose(1,2).matmul(wgt.view(1,-1).t()).transpose(1,2)
out2 = F.fold(out_unf, (h,w), (1,1))
out2 = out2.to(dtype=torch.int)
``````

Method 3

``````out3 = F.conv2d(inp, wgt, bias=None, stride=1, padding=0)
out3 = out3.to(dtype=torch.int)
``````

And here are the results comparison:

``````>>> h*w
347604

>>> (out1==out2).sum().item()
327338
>>> (out2 == out3).sum().item()
344026
>>> (out1 == out3).sum().item()
330797

>>> out1.shape
(1, 498, 698)
>>> out2.shape
(1, 1, 498, 698)
>>> out3.shape
(1, 1, 498, 698)
``````

Their data types are all `int` so floating point won’t the result. When I use a squared input format such as `h=500` and `w=500` , all three results are all matching. But not for non-squared inputs, such as the one above with `h=500` and `w=700` . Any insight?

It’s not completely true that you are using `int32` `dtypes` as the actual convolutions are performed in `float32`.
If you check the errors you would see that you start to diverge at the higher range and in particular you are running into the expected rounding in `float32`.
This Wikipedia article on Single-precision floats explains when `float32` starts to round on integer values.

Interesting for you would be the range in:

Integers between `2**24=16777216` and `2**25=33554432` round to a multiple of 2 (even number)

If you check the max. values you would see that the output fits into this range:

``````print(out1[-1, -1, -1] > 2**24)
# tensor(True)

print(out1[-1, -1, -1].float())
# tensor(18881046.)
print(out1[-1, -1, -1].float() + 1)
# tensor(18881048.)
``````

If you use `float64` your results would match as you wouldn’t round the integer values in the output range.

1 Like

Thank you very much for your answer, ptrblck. This question has been bugging me for awhile haha. My suffering and pain’s gone now. Thank you again.

1 Like