Simple math problems showing different results for torch and numpy

Hi,
So I was working with a code when I realized this issue:
Suppose,

import torch
import numpy as np

mu1 = torch.Tensor([0.51])
mu2 = torch.Tensor([0.52])
sigma1 = torch.Tensor([0.10])
sigma2 = torch.Tensor([0.11])
output = torch.log(sigma2/sigma1) + (sigma1**2 + (mu1 - mu2)**2)/(2*sigma2**2) - torch.Tensor([0.5])

print(output)

mu1 = torch.Tensor([0.51])
mu2 = torch.Tensor([0.52])
sigma1 = torch.Tensor([0.10])
sigma2 = torch.Tensor([0.11])
output = np.log(sigma2.item()/sigma1.item()) + (sigma1.item()**2 + (mu1.item() - mu2.item())**2)/(2*sigma2.item()**2) - 0.5

print(output)

The results are: tensor([0.0127])
0.012665540341760373, pretty good!
But if,

import torch
import numpy as np

mu1 = torch.Tensor([0.4651])
mu2 = torch.Tensor([0.4652])
sigma1 = torch.Tensor([0.7910])
sigma2 = torch.Tensor([0.7911])
output = torch.log(sigma2/sigma1) + (sigma1**2 + (mu1 - mu2)**2)/(2*sigma2**2) - torch.Tensor([0.5])

print(output)

mu1 = torch.Tensor([0.4651])
mu2 = torch.Tensor([0.4652])
sigma1 = torch.Tensor([0.7910])
sigma2 = torch.Tensor([0.7911])
output = np.log(sigma2.item()/sigma1.item()) + (sigma1.item()**2 + (mu1.item() - mu2.item())**2)/(2*sigma2.item()**2) - 0.5

print(output)

gives results: tensor([5.9605e-08])
2.3976444829543198e-08
What is going on? Why such weird behaviour?

I believe that this is because numpy will do operations in float64 by default while in torch they are in float32. For example:

import torch
import numpy as np

mu1 = torch.Tensor([0.4651]).to(torch.double)
mu2 = torch.Tensor([0.4652]).to(torch.double)
sigma1 = torch.Tensor([0.7910]).to(torch.double)
sigma2 = torch.Tensor([0.7911]).to(torch.double)
output = torch.log(sigma2/sigma1) + (sigma1**2 + (mu1 - mu2)**2)/(2*sigma2**2) - torch.Tensor([0.5]).to(torch.double)

print(output)

mu1 = torch.Tensor([0.4651])
mu2 = torch.Tensor([0.4652])
sigma1 = torch.Tensor([0.7910])
sigma2 = torch.Tensor([0.7911])
output = np.log(sigma2.item()/sigma1.item()) + (sigma1.item()**2 + (mu1.item() - mu2.item())**2)/(2*sigma2.item()**2) - 0.5

print(output)
print(output.dtype)

yields the following output

tensor([2.3976e-08], dtype=torch.float64)
2.3976444829543198e-08
float64

on my machine.

1 Like
output = np.log(sigma2.item()/sigma1.item()) + (sigma1.item()**2 + (mu1.item() - mu2.item())**2)/(2*sigma2.item()**2) - 0.5

calling item() returns python’s standard float, which is double precision, thus np.log will keep processing floats as double precision
If you want to keep precision intact you can replace item() with numpy(), this will convert all tensor.float32 to np.float32

output = np.log(sigma2.numpy()/sigma1.numpy()) + (sigma1.numpy()**2 + (mu1.numpy() - mu2.numpy())**2)/(2*sigma2.numpy()**2) - 0.5
>>> output
array([5.9604645e-08], dtype=float32)
1 Like