blob: 31c538e9e02d488f5491e7654832290f06438594 [file] [log] [blame]
import tempfile
import unittest
import torch
import torch.cuda
from common import TestCase, get_gpu_type, to_gpu
def is_floating(t):
return type(t) in [torch.FloatTensor, torch.DoubleTensor,
torch.cuda.FloatTensor, torch.cuda.DoubleTensor]
types = [
torch.FloatTensor,
torch.DoubleTensor,
torch.LongTensor,
torch.IntTensor,
torch.ShortTensor,
torch.CharTensor,
torch.ByteTensor,
]
# TODO: check HalfTensor
S = 10
M = 50
def make_tensor(t, *sizes):
return t(*sizes).copy_(torch.randn(*sizes))
def small_2d(t):
return make_tensor(t, S, S)
def small_3d(t):
return make_tensor(t, S, S, S)
def medium_1d(t):
return make_tensor(t, M)
def medium_2d(t):
return make_tensor(t, M, M)
def small_3d_ones(t):
return t(S, S, S).copy_(torch.ones(S, S, S))
def small_3d_positive(t):
min_val = 1e-3 if is_floating(t) else 2
return make_tensor(t, S, S, S).clamp_(min_val, 120)
def small_3d_unique(t):
return t(S, S, S).copy_(torch.range(1, S*S*S))
def new_t(*sizes):
def tmp(t):
return t(*sizes).copy_(torch.randn(*sizes))
return tmp
tests = [
('add', small_3d, lambda t: [3.14] ),
('add', small_3d, lambda t: [small_3d_positive(t)], 'tensor' ),
('add', small_3d, lambda t: [0.2, small_3d_positive(t)], 'scalar_tensor' ),
('sub', small_3d, lambda t: [3.14], ),
('sub', small_3d, lambda t: [small_3d_positive(t)], 'tensor' ),
('mul', small_3d, lambda t: [3.14], ),
('mul', small_3d, lambda t: [small_3d_positive(t)], 'tensor' ),
('div', small_3d, lambda t: [3.14], ),
('div', small_3d, lambda t: [small_3d_positive(t)], 'tensor' ),
('pow', small_3d, lambda t: [3.14], ),
('pow', small_3d, lambda t: [small_3d(t).abs_()], 'tensor' ),
('addbmm', small_2d, lambda t: [small_3d(t), small_3d(t)], ),
('addbmm', small_2d, lambda t: [0.2, small_3d(t), small_3d(t)], 'scalar' ),
('addbmm', small_2d, lambda t: [0.5, 0.2, small_3d(t), small_3d(t)], 'two_scalars' ),
('baddbmm', small_3d, lambda t: [small_3d(t), small_3d(t)], ),
('baddbmm', small_3d, lambda t: [0.2, small_3d(t), small_3d(t)], 'scalar' ),
('baddbmm', small_3d, lambda t: [0.5, 0.2, small_3d(t), small_3d(t)], 'two_scalars' ),
('addcdiv', small_3d, lambda t: [small_3d(t), small_3d(t)], ),
('addcdiv', small_3d, lambda t: [0.2, small_3d(t), small_3d(t)], 'scalar' ),
('addcmul', small_3d, lambda t: [small_3d(t), small_3d(t)], ),
('addcmul', small_3d, lambda t: [0.2, small_3d(t), small_3d(t)], 'scalar' ),
('addmm', medium_2d, lambda t: [medium_2d(t), medium_2d(t)], ),
('addmm', medium_2d, lambda t: [0.2, medium_2d(t), medium_2d(t)], 'scalar' ),
('addmm', medium_2d, lambda t: [0.5, 0.2, medium_2d(t), medium_2d(t)], 'two_scalars' ),
('addmv', medium_1d, lambda t: [medium_2d(t), medium_1d(t)], ),
('addmv', medium_1d, lambda t: [0.2, medium_2d(t), medium_1d(t)], 'scalar' ),
('addmv', medium_1d, lambda t: [0.5, 0.2, medium_2d(t), medium_1d(t)], 'two_scalars' ),
('addmv', medium_1d, lambda t: [medium_2d(t), medium_1d(t)], ),
('addmv', medium_1d, lambda t: [0.2, medium_2d(t), medium_1d(t)], 'scalar' ),
('addmv', medium_1d, lambda t: [0.5, 0.2, medium_2d(t), medium_1d(t)], 'two_scalars' ),
('addr', medium_2d, lambda t: [medium_1d(t), medium_1d(t)], ),
('addr', medium_2d, lambda t: [0.2, medium_1d(t), medium_1d(t)], 'scalar' ),
('addr', medium_2d, lambda t: [0.5, 0.2, medium_1d(t), medium_1d(t)], 'two_scalars' ),
('addr', medium_2d, lambda t: [0.5, 0.2, medium_1d(t), medium_1d(t)], 'two_scalars' ),
('atan2', medium_2d, lambda t: [medium_2d(t)], ),
('chunk', medium_2d, lambda t: [4], ),
('chunk', medium_2d, lambda t: [4, 1], 'dim' ),
('clamp', medium_2d, lambda t: [-0.1, 0.5], ),
('clone', medium_2d, lambda t: [], ),
('cmax', medium_2d, lambda t: [medium_2d(t)], ),
('cmin', medium_2d, lambda t: [medium_2d(t)], ),
('contiguous', medium_2d, lambda t: [], ),
('cross', new_t(M, 3, M), lambda t: [new_t(M, 3, M)(t)], ),
('cumprod', small_3d, lambda t: [1], ),
('cumsum', small_3d, lambda t: [1], ),
('dim', small_3d, lambda t: [], ),
('dist', small_2d, lambda t: [small_2d(t)], ),
('dist', small_2d, lambda t: [small_2d(t), 3], '3_norm' ),
('dist', small_2d, lambda t: [small_2d(t), 2.5], '2.5_norm' ),
('dot', medium_1d, lambda t: [medium_1d(t)], ),
('elementSize', medium_1d, lambda t: [], ),
('eq', small_3d_ones, lambda t: [small_3d(t)], ),
('eq', small_3d_ones, lambda t: [small_3d_ones(t)], 'equal' ),
('ne', small_3d_ones, lambda t: [small_3d(t)], ),
('ne', small_3d_ones, lambda t: [small_3d_ones(t)], 'equal' ),
('equal', small_3d_ones, lambda t: [small_3d_ones(t)], ),
('equal', small_3d_ones, lambda t: [small_3d(t)], ),
('expand', new_t(M, 1, M), lambda t: [M, 4, M], ),
('expandAs', new_t(M, 1, M), lambda t: [new_t(M, 4, M)(t)], ),
('fill', medium_2d, lambda t: [3.14], ),
('ge', medium_2d, lambda t: [medium_2d(t)], ),
('le', medium_2d, lambda t: [medium_2d(t)], ),
('gt', medium_2d, lambda t: [medium_2d(t)], ),
('lt', medium_2d, lambda t: [medium_2d(t)], ),
('isContiguous', medium_2d, lambda t: [], ),
# TODO: can't check negative case - GPU copy will be contiguous
('isSameSizeAs', medium_2d, lambda t: [small_3d(t)], 'negative' ),
('isSameSizeAs', medium_2d, lambda t: [medium_2d(t)], 'positive' ),
('isSetTo', medium_2d, lambda t: [medium_2d(t)], ),
# TODO: positive case
('isSize', medium_2d, lambda t: [torch.LongStorage((M, M))], ),
('kthvalue', small_3d_unique, lambda t: [3], ),
('kthvalue', small_3d_unique, lambda t: [3, 1], 'dim' ),
('lerp', small_3d, lambda t: [small_3d(t), 0.3], ),
('max', small_3d_unique, lambda t: [], ),
('max', small_3d_unique, lambda t: [1], 'dim' ),
('min', small_3d_unique, lambda t: [], ),
('min', small_3d_unique, lambda t: [1], 'dim' ),
('mean', small_3d, lambda t: [], ),
('mean', small_3d, lambda t: [1], 'dim' ),
('mode', small_3d, lambda t: [], ),
('mode', small_3d, lambda t: [1], 'dim' ),
('std', small_3d, lambda t: [], ),
('std', small_3d, lambda t: [1], 'dim' ),
('var', small_3d, lambda t: [], ),
('var', small_3d, lambda t: [1], 'dim' ),
('nDimension', small_3d, lambda t: [], ),
('nElement', small_3d, lambda t: [], ),
('numel', small_3d, lambda t: [], ),
('narrow', small_3d, lambda t: [1, 3, 2], ),
('nonzero', small_3d, lambda t: [], ),
('norm', small_3d, lambda t: [], ),
('norm', small_3d, lambda t: [3], '3_norm' ),
('norm', small_3d, lambda t: [3, 0], '3_norm_dim' ),
('ones', small_3d, lambda t: [1, 2, 3, 4, 5], ),
('permute', new_t(1, 2, 3, 4), lambda t: [2, 1, 3, 0], ),
('prod', small_3d, lambda t: [], ),
('prod', small_3d, lambda t: [1], 'dim' ),
('sum', small_2d, lambda t: [], ),
('sum', small_3d, lambda t: [1], 'dim' ),
('renorm', small_3d, lambda t: [2, 1, 1], '2_norm' ),
('renorm', small_3d, lambda t: [1.5, 1, 1], '1.5_norm' ),
('repeatTensor', small_2d, lambda t: [2, 2, 2], ),
('size', new_t(1, 2, 3, 4), lambda t: [], ),
('sort', small_3d_unique, lambda t: [], ),
('sort', small_3d_unique, lambda t: [1], 'dim' ),
('sort', small_3d_unique, lambda t: [1, True], 'dim_descending'),
('split', small_3d, lambda t: [2], ),
('split', small_3d, lambda t: [2, 1], 'dim' ),
('squeeze', new_t(1, 2, 1, 4), lambda t: [], ),
('squeeze', new_t(1, 2, 1, 4), lambda t: [2], 'dim' ),
('t', new_t(1, 2), lambda t: [], ),
('transpose', new_t(1, 2, 3, 4), lambda t: [1, 2], ),
('to_list', small_3d, lambda t: [], ),
('topk', small_3d, lambda t: [2, 1, False, True], 'dim_sort' ),
('topk', small_3d, lambda t: [2, 1, True, True], 'dim_desc_sort' ),
('trace', medium_2d, lambda t: [], ),
('tril', medium_2d, lambda t: [], ),
('tril', medium_2d, lambda t: [2], 'positive' ),
('tril', medium_2d, lambda t: [-2], 'negative' ),
('triu', medium_2d, lambda t: [], ),
('triu', medium_2d, lambda t: [2], 'positive' ),
('triu', medium_2d, lambda t: [-2], 'negative' ),
('view', small_3d, lambda t: [100, 10], ),
('viewAs', small_3d, lambda t: [t(100, 10)], ),
('zero', small_3d, lambda t: [], ),
('zeros', small_3d, lambda t: [1, 2, 3, 4], ),
('rsqrt', lambda t: small_3d(t) + 1, lambda t: [], ),
('sinh', lambda t: small_3d(t).clamp(-1, 1), lambda t: [], ),
('tan', lambda t: small_3d(t).clamp(-1, 1), lambda t: [], ),
]
# TODO: random functions, cat, gather, scatter, index*, masked*, resize, resizeAs, storageOffset, storage, stride, unfold
simple_pointwise = [
'abs',
'acos',
'asin',
'atan',
'ceil',
'cinv',
'cos',
'cosh',
'exp',
'floor',
'fmod',
'frac',
'log',
'log1p',
'neg',
'remainder',
'round',
'sigmoid',
'sign',
'sin',
'sqrt',
'tanh',
'trunc',
]
for fn in simple_pointwise:
tests.append((fn, small_3d, lambda t: []))
def compare_cpu_gpu(tensor_constructor, arg_constructor, fn, t):
def tmp(self):
cpu_tensor = tensor_constructor(t)
gpu_tensor = to_gpu(cpu_tensor)
cpu_args = arg_constructor(t)
gpu_args = [to_gpu(arg) for arg in cpu_args]
cpu_result = getattr(cpu_tensor, fn)(*cpu_args)
try:
gpu_result = getattr(gpu_tensor, fn)(*gpu_args)
except RuntimeError as e:
reason = e.args[0]
if 'unimplemented data type' in reason:
raise unittest.SkipTest('unimplemented data type')
raise
# If one changes, another should change as well
self.assertEqual(cpu_tensor, gpu_tensor)
self.assertEqual(cpu_args, gpu_args)
# Compare results
self.assertEqual(cpu_result, gpu_result)
return tmp
class TestCuda(TestCase):
def test_autogpu(self):
if torch.cuda.deviceCount() > 1:
x = torch.randn(5, 5).cuda()
y = torch.randn(5, 5).cuda()
self.assertEqual(x.getDevice(), 0)
self.assertEqual(x.getDevice(), 0)
with torch.cuda.device(1):
z = torch.randn(5, 5).cuda()
self.assertEqual(z.getDevice(), 1)
q = x.add(y)
self.assertEqual(q.getDevice(), 0)
w = torch.randn(5, 5).cuda()
self.assertEqual(w.getDevice(), 1)
z = z.cuda()
self.assertEqual(z.getDevice(), 0)
def test_serialization(self):
x = torch.randn(5, 5).cuda()
y = torch.IntTensor(2, 5).fill_(0).cuda()
q = [x, y, x, y.storage()]
with tempfile.NamedTemporaryFile() as f:
torch.save(q, f)
f.seek(0)
q_copy = torch.load(f)
self.assertEqual(q_copy, q, 0)
q_copy[0].fill_(5)
self.assertEqual(q_copy[0], q_copy[2], 0)
self.assertTrue(isinstance(q_copy[0], torch.cuda.DoubleTensor))
self.assertTrue(isinstance(q_copy[1], torch.cuda.IntTensor))
self.assertTrue(isinstance(q_copy[2], torch.cuda.DoubleTensor))
self.assertTrue(isinstance(q_copy[3], torch.cuda.IntStorage))
q_copy[1].fill_(10)
self.assertTrue(q_copy[3], torch.cuda.IntStorage(10).fill_(10))
for decl in tests:
for t in types:
tensor = t()
gpu_tensor = get_gpu_type(t)()
for inplace in (True, False):
if len(decl) == 3:
name, constr, arg_constr = decl
desc = ''
elif len(decl) == 4:
name, constr, arg_constr, desc = decl
if inplace:
name = name + '_'
if not hasattr(tensor, name):
continue
if not hasattr(gpu_tensor, name):
print("Ignoring {}, because it's not implemented by torch.cuda.{}".format(name, gpu_tensor.__class__.__name__))
continue
test_name = 'test_' + t.__name__ + '_' + name
if desc:
test_name += '_' + desc
assert not hasattr(TestCase, test_name)
setattr(TestCuda, test_name, compare_cpu_gpu(constr, arg_constr, name, t))
if __name__ == '__main__':
unittest.main()