This solution was incredible helpful for my understanding (thank you) but I could not reproduce it with the current implementation. So - if anyone else is wondering in 2023 - the default has changed to align_corners = False
. I find the term align_corners
a bit funny, because it is more straight forward to align the corners of the input and the target grid when set to false, as the outer borders fall onto -1 and 1 and the centroids fall within the range. For align_corners = True
the grid does not refer directly to the centroids in my understanding. The documentation states: āFor example, values x = -1, y = -1
is the left-top pixel of input
, and values x = 1, y = 1
is the right-bottom pixel of input
.ā This confused me because in the default case the centre points of left-top pixel and the right-bottom pixel are not as indicated. Reproducing a given grid with grid_sample() validated this.
I am reproducing the above example with both indexing variants of torch.meshgrid(). I like to keep the notation of xy and ij separate.
input = torch.arange(4*4).view(1, 1, 4, 4).float()
print(input)
> tensor([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]]])
# Create grid to upsample input
d = torch.linspace(-1, 1, 8)
### Using Cartesian xy indexing ###
# both grid axis are the same so order does not matter in this case.
xx, yy = torch.meshgrid((d, d), indexing = "xy")
# x,y order of last two dimensions of grid
grid = torch.stack((xx, yy), 2)
grid = grid.unsqueeze(0) # add batch dim
# 09/2022 default is align_corners = False
output = torch.nn.functional.grid_sample(input, grid, align_corners = True)
print(output)
> tensor([[[[ 0.0000, 0.4286, 0.8571, 1.2857, 1.7143, 2.1429, 2.5714,
3.0000],
[ 1.7143, 2.1429, 2.5714, 3.0000, 3.4286, 3.8571, 4.2857,
4.7143],
[ 3.4286, 3.8571, 4.2857, 4.7143, 5.1429, 5.5714, 6.0000,
6.4286],
[ 5.1429, 5.5714, 6.0000, 6.4286, 6.8571, 7.2857, 7.7143,
8.1429],
[ 6.8571, 7.2857, 7.7143, 8.1429, 8.5714, 9.0000, 9.4286,
9.8571],
[ 8.5714, 9.0000, 9.4286, 9.8571, 10.2857, 10.7143, 11.1429,
11.5714],
[10.2857, 10.7143, 11.1429, 11.5714, 12.0000, 12.4286, 12.8571,
13.2857],
[12.0000, 12.4286, 12.8571, 13.2857, 13.7143, 14.1429, 14.5714,
15.0000]]]])
### Using Matrix ij indexing ###
# This is the default and was used in the referance example I am trying to reporduce
# ii corresponds to rows in matrix indexing, so y-axis in Cartesian indexing
ii, jj = torch.meshgrid((d, d), indexing = "ij")
# Same: ii, jj = torch.meshgrid((d, d))
# Reverse order to match x, y Cartesian ordering: jj == xx, ii == yy in previous example
grid = torch.stack((jj, ii), 2)
grid = grid.unsqueeze(0) # add batch dim
# 09/2023 default is align_corners = False
output = torch.nn.functional.grid_sample(input, grid, align_corners = True)
print(output)
> tensor([[[[ 0.0000, 0.4286, 0.8571, 1.2857, 1.7143, 2.1429, 2.5714,
3.0000],
[ 1.7143, 2.1429, 2.5714, 3.0000, 3.4286, 3.8571, 4.2857,
4.7143],
[ 3.4286, 3.8571, 4.2857, 4.7143, 5.1429, 5.5714, 6.0000,
6.4286],
[ 5.1429, 5.5714, 6.0000, 6.4286, 6.8571, 7.2857, 7.7143,
8.1429],
[ 6.8571, 7.2857, 7.7143, 8.1429, 8.5714, 9.0000, 9.4286,
9.8571],
[ 8.5714, 9.0000, 9.4286, 9.8571, 10.2857, 10.7143, 11.1429,
11.5714],
[10.2857, 10.7143, 11.1429, 11.5714, 12.0000, 12.4286, 12.8571,
13.2857],
[12.0000, 12.4286, 12.8571, 13.2857, 13.7143, 14.1429, 14.5714,
15.0000]]]])