Created
June 10, 2018 21:24
-
-
Save elistevens/6e3bfb20d8d0652b83bd16b3e911285b to your computer and use it in GitHub Desktop.
Tests for volumetric affine grid generation in pytorch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import math | |
| import random | |
| import numpy as np | |
| import scipy.ndimage | |
| import torch | |
| import pytest | |
| from util.logconf import logging | |
| log = logging.getLogger(__name__) | |
| # log.setLevel(logging.WARN) | |
| # log.setLevel(logging.INFO) | |
| log.setLevel(logging.DEBUG) | |
| from .affine import affine_grid_generator | |
| if torch.cuda.is_available(): | |
| @pytest.fixture(params=['cpu', 'cuda']) | |
| # @pytest.fixture(params=['cpu']) | |
| def device(request): | |
| return request.param | |
| else: | |
| @pytest.fixture(params=['cpu']) | |
| def device(request): | |
| return request.param | |
| @pytest.fixture(params=[0.0, 0.5, 0.25, 0.125, 'random']) | |
| # @pytest.fixture(params=[0., 0.25]) | |
| def angle_rad(request): | |
| if request.param == 'random': | |
| return random.random() * math.pi * 2 | |
| return request.param * math.pi * 2 | |
| @pytest.fixture(params=[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), 'random']) | |
| def axis_vector(request): | |
| if request.param == 'random': | |
| t = (random.random(), random.random(), random.random()) | |
| l = sum(x**2 for x in t)**0.5 | |
| return tuple(x/l for x in t) | |
| return request.param | |
| @pytest.fixture(params=[torch.nn.functional.affine_grid, affine_grid_generator]) | |
| # @pytest.fixture(params=[]) | |
| def affine_func2d(request): | |
| return request.param | |
| @pytest.fixture(params=[affine_grid_generator]) | |
| def affine_func3d(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 3, 5], [1, 1, 3, 3], [1, 1, 4, 4], [1, 1, 3, 4]]) | |
| def input_size2d(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 5, 3], [1, 1, 3, 5], [1, 1, 4, 3], [1, 1, 5, 5], [1, 1, 6, 6]]) | |
| def output_size2d(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 2, 2], [1, 1, 3, 3], [1, 1, 4, 4], [1, 1, 6, 6], ]) | |
| def input_size2dsq(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 2, 2], [1, 1, 3, 3], [1, 1, 4, 4], [1, 1, 5, 5], [1, 1, 6, 6], ]) | |
| def output_size2dsq(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 2, 2, 2], [1, 1, 2, 3, 4], [1, 1, 3, 3, 3], [1, 1, 4, 4, 4], [1, 1, 3, 4, 5]]) | |
| def input_size3d(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 2, 2, 2], [1, 1, 3, 3, 3], [1, 1, 4, 4, 4], [1, 1, 6, 6, 6]]) | |
| def input_size3dsq(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 2, 2, 2], [1, 1, 3, 3, 3], [1, 1, 4, 4, 4], [1, 1, 5, 5, 5], [1, 1, 6, 6, 6]]) | |
| def output_size3dsq(request): | |
| return request.param | |
| @pytest.fixture(params=[[1, 1, 2, 2, 2], [1, 1, 3, 3, 3], [1, 1, 3, 4, 5], [1, 1, 4, 3, 2], [1, 1, 5, 5, 5], [1, 1, 6, 6, 6]]) | |
| def output_size3d(request): | |
| return request.param | |
| def _buildEquivalentTransforms2d(device, input_size, output_size, angle_rad): | |
| print("_buildEquivalentTransforms2d", device, input_size, output_size, angle_rad * 180 / math.pi) | |
| input_center = [(x-1)/2 for x in input_size] | |
| output_center = [(x-1)/2 for x in output_size] | |
| s = math.sin(angle_rad) | |
| c = math.cos(angle_rad) | |
| intrans_ary = np.array([ | |
| [1, 0, input_center[2]], | |
| [0, 1, input_center[3]], | |
| [0, 0, 1], | |
| ], dtype=np.float64) | |
| inscale_ary = np.array([ | |
| [input_center[2], 0, 0], | |
| [0, input_center[3], 0], | |
| [0, 0, 1], | |
| ], dtype=np.float64) | |
| rotation_ary = np.array([ | |
| [c, -s, 0], | |
| [s, c, 0], | |
| [0, 0, 1], | |
| ], dtype=np.float64) | |
| outscale_ary = np.array([ | |
| [1/output_center[2], 0, 0], | |
| [0, 1/output_center[3], 0], | |
| [0, 0, 1], | |
| ], dtype=np.float64) | |
| outtrans_ary = np.array([ | |
| [1, 0, -output_center[2]], | |
| [0, 1, -output_center[3]], | |
| [0, 0, 1], | |
| ], dtype=np.float64) | |
| reorder_ary = np.array([ | |
| [0, 1, 0], | |
| [1, 0, 0], | |
| [0, 0, 1], | |
| ], dtype=np.float64) | |
| transform_ary = intrans_ary @ inscale_ary @ rotation_ary.T @ outscale_ary @ outtrans_ary | |
| grid_ary = reorder_ary @ rotation_ary.T @ outscale_ary @ outtrans_ary | |
| transform_tensor = torch.from_numpy((rotation_ary)).to(device, torch.float32) | |
| transform_tensor = transform_tensor[:2].unsqueeze(0) | |
| print('transform_tensor', transform_tensor.size(), transform_tensor.dtype, transform_tensor.device) | |
| print(transform_tensor) | |
| print('outtrans_ary', outtrans_ary.shape, outtrans_ary.dtype) | |
| print(outtrans_ary.round(3)) | |
| print('outscale_ary', outscale_ary.shape, outscale_ary.dtype) | |
| print(outscale_ary.round(3)) | |
| print('rotation_ary', rotation_ary.shape, rotation_ary.dtype) | |
| print(rotation_ary.round(3)) | |
| print('inscale_ary', inscale_ary.shape, inscale_ary.dtype) | |
| print(inscale_ary.round(3)) | |
| print('intrans_ary', intrans_ary.shape, intrans_ary.dtype) | |
| print(intrans_ary.round(3)) | |
| print('transform_ary', transform_ary.shape, transform_ary.dtype) | |
| print(transform_ary.round(3)) | |
| print('grid_ary', grid_ary.shape, grid_ary.dtype) | |
| print(grid_ary.round(3)) | |
| def prtf(pt): | |
| print(pt, 'transformed', (transform_ary @ (pt + [1]))[:2].round(3)) | |
| prtf([0, 0]) | |
| prtf([1, 0]) | |
| prtf([2, 0]) | |
| print('') | |
| prtf([0, 0]) | |
| prtf([0, 1]) | |
| prtf([0, 2]) | |
| prtf(output_center[2:]) | |
| return transform_tensor, transform_ary, grid_ary | |
| def _buildEquivalentTransforms3d(device, input_size, output_size, angle_rad, axis_vector): | |
| print("_buildEquivalentTransforms2d", device, input_size, output_size, angle_rad * 180 / math.pi, axis_vector) | |
| input_center = [(x-1)/2 for x in input_size] | |
| output_center = [(x-1)/2 for x in output_size] | |
| s = math.sin(angle_rad) | |
| c = math.cos(angle_rad) | |
| c1 = 1 - c | |
| intrans_ary = np.array([ | |
| [1, 0, 0, input_center[2]], | |
| [0, 1, 0, input_center[3]], | |
| [0, 0, 1, input_center[4]], | |
| [0, 0, 0, 1], | |
| ], dtype=np.float64) | |
| inscale_ary = np.array([ | |
| [input_center[2], 0, 0, 0], | |
| [0, input_center[3], 0, 0], | |
| [0, 0, input_center[4], 0], | |
| [0, 0, 0, 1], | |
| ], dtype=np.float64) | |
| l, m, n = axis_vector | |
| scipyRotation_ary = np.array([ | |
| [l*l*c1 + c, m*l*c1 - n*s, n*l*c1 + m*s, 0], | |
| [l*m*c1 + n*s, m*m*c1 + c, n*m*c1 - l*s, 0], | |
| [l*n*c1 - m*s, m*n*c1 + l*s, n*n*c1 + c, 0], | |
| [0, 0, 0, 1], | |
| ], dtype=np.float64) | |
| z, y, x = axis_vector | |
| torchRotation_ary = np.array([ | |
| [x*x*c1 + c, y*x*c1 - z*s, z*x*c1 + y*s, 0], | |
| [x*y*c1 + z*s, y*y*c1 + c, z*y*c1 - x*s, 0], | |
| [x*z*c1 - y*s, y*z*c1 + x*s, z*z*c1 + c, 0], | |
| [0, 0, 0, 1], | |
| ], dtype=np.float64) | |
| outscale_ary = np.array([ | |
| [1/output_center[2], 0, 0, 0], | |
| [0, 1/output_center[3], 0, 0], | |
| [0, 0, 1/output_center[4], 0], | |
| [0, 0, 0, 1], | |
| ], dtype=np.float64) | |
| outtrans_ary = np.array([ | |
| [1, 0, 0, -output_center[2]], | |
| [0, 1, 0, -output_center[3]], | |
| [0, 0, 1, -output_center[4]], | |
| [0, 0, 0, 1], | |
| ], dtype=np.float64) | |
| reorder_ary = np.array([ | |
| [0, 0, 1, 0], | |
| [0, 1, 0, 0], | |
| [1, 0, 0, 0], | |
| [0, 0, 0, 1], | |
| ], dtype=np.float64) | |
| transform_ary = intrans_ary @ inscale_ary @ np.linalg.inv(scipyRotation_ary) @ outscale_ary @ outtrans_ary | |
| grid_ary = reorder_ary @ np.linalg.inv(scipyRotation_ary) @ outscale_ary @ outtrans_ary | |
| transform_tensor = torch.from_numpy((torchRotation_ary)).to(device, torch.float32) | |
| transform_tensor = transform_tensor[:3].unsqueeze(0) | |
| print('transform_tensor', transform_tensor.size(), transform_tensor.dtype, transform_tensor.device) | |
| print(transform_tensor) | |
| print('outtrans_ary', outtrans_ary.shape, outtrans_ary.dtype) | |
| print(outtrans_ary.round(3)) | |
| print('outscale_ary', outscale_ary.shape, outscale_ary.dtype) | |
| print(outscale_ary.round(3)) | |
| print('rotation_ary', scipyRotation_ary.shape, scipyRotation_ary.dtype, axis_vector, angle_rad) | |
| print(scipyRotation_ary.round(3)) | |
| print('inscale_ary', inscale_ary.shape, inscale_ary.dtype) | |
| print(inscale_ary.round(3)) | |
| print('intrans_ary', intrans_ary.shape, intrans_ary.dtype) | |
| print(intrans_ary.round(3)) | |
| print('transform_ary', transform_ary.shape, transform_ary.dtype) | |
| print(transform_ary.round(3)) | |
| print('grid_ary', grid_ary.shape, grid_ary.dtype) | |
| print(grid_ary.round(3)) | |
| def prtf(pt): | |
| print(pt, 'transformed', (transform_ary @ (pt + [1]))[:3].round(3)) | |
| prtf([0, 0, 0]) | |
| prtf([1, 0, 0]) | |
| prtf([2, 0, 0]) | |
| print('') | |
| prtf([0, 0, 0]) | |
| prtf([0, 1, 0]) | |
| prtf([0, 2, 0]) | |
| print('') | |
| prtf([0, 0, 0]) | |
| prtf([0, 0, 1]) | |
| prtf([0, 0, 2]) | |
| prtf(output_center[2:]) | |
| return transform_tensor, transform_ary, grid_ary | |
| def test_affine_2d_rotate0(device, affine_func2d): | |
| input_size = [1, 1, 3, 3] | |
| input_ary = np.array(np.random.random(input_size), dtype=np.float32) | |
| output_size = [1, 1, 5, 5] | |
| angle_rad = 0. | |
| transform_tensor, transform_ary, offset = _buildEquivalentTransforms2d(device, input_size, output_size, angle_rad) | |
| # reference | |
| # https://stackoverflow.com/questions/20161175/how-can-i-use-scipy-ndimage-interpolation-affine-transform-to-rotate-an-image-ab | |
| scipy_ary = scipy.ndimage.affine_transform( | |
| input_ary[0,0], | |
| transform_ary, | |
| offset=offset, | |
| output_shape=output_size[2:], | |
| # output=None, | |
| order=1, | |
| mode='nearest', | |
| # cval=0.0, | |
| prefilter=False) | |
| print('input_ary', input_ary.shape, input_ary.dtype) | |
| print(input_ary) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype) | |
| print(scipy_ary) | |
| affine_tensor = affine_func2d( | |
| transform_tensor, | |
| torch.Size(output_size) | |
| ) | |
| print('affine_tensor', affine_tensor.size(), affine_tensor.dtype, affine_tensor.device) | |
| print(affine_tensor) | |
| gridsample_ary = torch.nn.functional.grid_sample( | |
| torch.tensor(input_ary, device=device).to(device), | |
| affine_tensor, | |
| padding_mode='border' | |
| ).to('cpu').numpy() | |
| print('input_ary', input_ary.shape, input_ary.dtype) | |
| print(input_ary) | |
| print('gridsample_ary', gridsample_ary.shape, gridsample_ary.dtype) | |
| print(gridsample_ary) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype) | |
| print(scipy_ary) | |
| assert np.abs(scipy_ary.mean() - gridsample_ary.mean()) < 1e-6 | |
| assert np.abs(scipy_ary - gridsample_ary).max() < 1e-6 | |
| # assert False | |
| def test_affine_2d_rotate90(device, affine_func2d, input_size2dsq, output_size2dsq): | |
| input_size = input_size2dsq | |
| input_ary = np.array(np.random.random(input_size), dtype=np.float32) | |
| output_size = output_size2dsq | |
| angle_rad = 0.25 * math.pi * 2 | |
| transform_tensor, transform_ary, offset = _buildEquivalentTransforms2d(device, input_size, output_size, angle_rad) | |
| # reference | |
| # https://stackoverflow.com/questions/20161175/how-can-i-use-scipy-ndimage-interpolation-affine-transform-to-rotate-an-image-ab | |
| scipy_ary = scipy.ndimage.affine_transform( | |
| input_ary[0,0], | |
| transform_ary, | |
| offset=offset, | |
| output_shape=output_size[2:], | |
| # output=None, | |
| order=1, | |
| mode='nearest', | |
| # cval=0.0, | |
| prefilter=True) | |
| print('input_ary', input_ary.shape, input_ary.dtype, input_ary.mean()) | |
| print(input_ary) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype, scipy_ary.mean()) | |
| print(scipy_ary) | |
| if input_size2dsq == output_size2dsq: | |
| assert np.abs(scipy_ary.mean() - input_ary.mean()) < 1e-6 | |
| assert np.abs(scipy_ary[0,0] - input_ary[0,0,0,-1]).max() < 1e-6 | |
| assert np.abs(scipy_ary[0,-1] - input_ary[0,0,-1,-1]).max() < 1e-6 | |
| assert np.abs(scipy_ary[-1,-1] - input_ary[0,0,-1,0]).max() < 1e-6 | |
| assert np.abs(scipy_ary[-1,0] - input_ary[0,0,0,0]).max() < 1e-6 | |
| affine_tensor = affine_func2d( | |
| transform_tensor, | |
| torch.Size(output_size) | |
| ) | |
| print('affine_tensor', affine_tensor.size(), affine_tensor.dtype, affine_tensor.device) | |
| print(affine_tensor) | |
| gridsample_ary = torch.nn.functional.grid_sample( | |
| torch.tensor(input_ary, device=device).to(device), | |
| affine_tensor, | |
| padding_mode='border' | |
| ).to('cpu').numpy() | |
| print('input_ary', input_ary.shape, input_ary.dtype) | |
| print(input_ary) | |
| print('gridsample_ary', gridsample_ary.shape, gridsample_ary.dtype) | |
| print(gridsample_ary) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype) | |
| print(scipy_ary) | |
| assert np.abs(scipy_ary.mean() - gridsample_ary.mean()) < 1e-6 | |
| assert np.abs(scipy_ary - gridsample_ary).max() < 1e-6 | |
| # assert False | |
| def test_affine_2d_rotate45(device, affine_func2d): | |
| input_size = [1, 1, 3, 3] | |
| # input_ary = np.array(np.random.random(input_size), dtype=np.float32) | |
| input_ary = np.array(np.zeros(input_size), dtype=np.float32) | |
| input_ary[0,0,0,:] = 0.5 | |
| input_ary[0,0,2,2] = 1.0 | |
| output_size = [1, 1, 3, 3] | |
| angle_rad = 0.125 * math.pi * 2 | |
| transform_tensor, transform_ary, offset = _buildEquivalentTransforms2d(device, input_size, output_size, angle_rad) | |
| # reference | |
| # https://stackoverflow.com/questions/20161175/how-can-i-use-scipy-ndimage-interpolation-affine-transform-to-rotate-an-image-ab | |
| scipy_ary = scipy.ndimage.affine_transform( | |
| input_ary[0,0], | |
| transform_ary, | |
| offset=offset, | |
| output_shape=output_size[2:], | |
| # output=None, | |
| order=1, | |
| mode='nearest', | |
| # cval=0.0, | |
| prefilter=False) | |
| print('input_ary', input_ary.shape, input_ary.dtype) | |
| print(input_ary) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype) | |
| print(scipy_ary) | |
| affine_tensor = affine_func2d( | |
| transform_tensor, | |
| torch.Size(output_size) | |
| ) | |
| print('affine_tensor', affine_tensor.size(), affine_tensor.dtype, affine_tensor.device) | |
| print(affine_tensor) | |
| gridsample_ary = torch.nn.functional.grid_sample( | |
| torch.tensor(input_ary, device=device).to(device), | |
| affine_tensor, | |
| padding_mode='border' | |
| ).to('cpu').numpy() | |
| print('input_ary', input_ary.shape, input_ary.dtype) | |
| print(input_ary) | |
| print('gridsample_ary', gridsample_ary.shape, gridsample_ary.dtype) | |
| print(gridsample_ary) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype) | |
| print(scipy_ary) | |
| assert np.abs(scipy_ary - gridsample_ary).max() < 1e-6 | |
| # assert False | |
| def test_affine_2d_rotateRandom(device, affine_func2d, angle_rad, input_size2d, output_size2d): | |
| input_size = input_size2d | |
| input_ary = np.array(np.random.random(input_size), dtype=np.float32).round(3) | |
| output_size = output_size2d | |
| # angle_rad = random.random() * math.pi * 2 | |
| input_ary[0,0,0,0] = 2 | |
| input_ary[0,0,0,-1] = 4 | |
| input_ary[0,0,-1,0] = 6 | |
| input_ary[0,0,-1,-1] = 8 | |
| transform_tensor, transform_ary, grid_ary = _buildEquivalentTransforms2d(device, input_size, output_size, angle_rad) | |
| # reference | |
| # https://stackoverflow.com/questions/20161175/how-can-i-use-scipy-ndimage-interpolation-affine-transform-to-rotate-an-image-ab | |
| scipy_ary = scipy.ndimage.affine_transform( | |
| input_ary[0,0], | |
| transform_ary, | |
| # offset=offset, | |
| output_shape=output_size[2:], | |
| # output=None, | |
| order=1, | |
| mode='nearest', | |
| # cval=0.0, | |
| prefilter=False) | |
| affine_tensor = affine_func2d( | |
| transform_tensor, | |
| torch.Size(output_size) | |
| ) | |
| print('affine_tensor', affine_tensor.size(), affine_tensor.dtype, affine_tensor.device) | |
| print(affine_tensor) | |
| for r in range(affine_tensor.size(1)): | |
| for c in range(affine_tensor.size(2)): | |
| grid_out = grid_ary @ [r, c, 1] | |
| print(r, c, 'affine:', affine_tensor[0,r,c], 'grid:', grid_out[:2]) | |
| gridsample_ary = torch.nn.functional.grid_sample( | |
| torch.tensor(input_ary, device=device).to(device), | |
| affine_tensor, | |
| padding_mode='border' | |
| ).to('cpu').numpy() | |
| print('input_ary', input_ary.shape, input_ary.dtype) | |
| print(input_ary.round(3)) | |
| print('gridsample_ary', gridsample_ary.shape, gridsample_ary.dtype) | |
| print(gridsample_ary.round(3)) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype) | |
| print(scipy_ary.round(3)) | |
| for r in range(affine_tensor.size(1)): | |
| for c in range(affine_tensor.size(2)): | |
| grid_out = grid_ary @ [r, c, 1] | |
| try: | |
| assert np.allclose(affine_tensor[0,r,c], grid_out[:2], atol=1e-5) | |
| except: | |
| print(r, c, 'affine:', affine_tensor[0,r,c], 'grid:', grid_out[:2]) | |
| raise | |
| assert np.abs(scipy_ary - gridsample_ary).max() < 1e-5 | |
| # assert False | |
| def test_affine_3d_rotateRandom(device, affine_func3d, angle_rad, axis_vector, input_size3d, output_size3d): | |
| input_size = input_size3d | |
| input_ary = np.array(np.random.random(input_size), dtype=np.float32) | |
| output_size = output_size3d | |
| # angle_rad = random.random() * math.pi * 2 | |
| input_ary[0,0, 0, 0, 0] = 2 | |
| input_ary[0,0, 0, 0, -1] = 3 | |
| input_ary[0,0, 0, -1, 0] = 4 | |
| input_ary[0,0, 0, -1, -1] = 5 | |
| input_ary[0,0, -1, 0, 0] = 6 | |
| input_ary[0,0, -1, 0, -1] = 7 | |
| input_ary[0,0, -1, -1, 0] = 8 | |
| input_ary[0,0, -1, -1, -1] = 9 | |
| transform_tensor, transform_ary, grid_ary = _buildEquivalentTransforms3d(device, input_size, output_size, angle_rad, axis_vector) | |
| # reference | |
| # https://stackoverflow.com/questions/20161175/how-can-i-use-scipy-ndimage-interpolation-affine-transform-to-rotate-an-image-ab | |
| scipy_ary = scipy.ndimage.affine_transform( | |
| input_ary[0,0], | |
| transform_ary, | |
| # offset=offset, | |
| output_shape=output_size[2:], | |
| # output=None, | |
| order=1, | |
| mode='nearest', | |
| # cval=0.0, | |
| prefilter=False) | |
| affine_tensor = affine_func3d( | |
| transform_tensor, | |
| torch.Size(output_size) | |
| ) | |
| print('affine_tensor', affine_tensor.size(), affine_tensor.dtype, affine_tensor.device) | |
| print(affine_tensor) | |
| for i in range(affine_tensor.size(1)): | |
| for r in range(affine_tensor.size(2)): | |
| for c in range(affine_tensor.size(3)): | |
| grid_out = grid_ary @ [i, r, c, 1] | |
| print(i, r, c, 'affine:', affine_tensor[0,i,r,c], 'grid:', grid_out[:3].round(3)) | |
| print('input_ary', input_ary.shape, input_ary.dtype) | |
| print(input_ary.round(3)) | |
| gridsample_ary = torch.nn.functional.grid_sample( | |
| torch.tensor(input_ary, device=device).to(device), | |
| affine_tensor, | |
| padding_mode='border' | |
| ).to('cpu').numpy() | |
| print('gridsample_ary', gridsample_ary.shape, gridsample_ary.dtype) | |
| print(gridsample_ary.round(3)) | |
| print('scipy_ary', scipy_ary.shape, scipy_ary.dtype) | |
| print(scipy_ary.round(3)) | |
| for i in range(affine_tensor.size(1)): | |
| for r in range(affine_tensor.size(2)): | |
| for c in range(affine_tensor.size(3)): | |
| grid_out = grid_ary @ [i, r, c, 1] | |
| try: | |
| assert np.allclose(affine_tensor[0,i,r,c], grid_out[:3], atol=1e-5) | |
| except: | |
| print(i, r, c, 'affine:', affine_tensor[0,i,r,c], 'grid:', grid_out[:3].round(3)) | |
| raise | |
| assert np.abs(scipy_ary - gridsample_ary).max() < 1e-5 | |
| # assert False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment