2020-10-25 19:40:01 -06:00
|
|
|
import torch
|
2022-10-26 19:02:36 -06:00
|
|
|
import time
|
2020-10-25 19:40:01 -06:00
|
|
|
import numpy as np
|
|
|
|
import unittest
|
2021-11-27 09:12:23 -07:00
|
|
|
from tinygrad.tensor import Tensor, Device
|
2023-01-31 16:09:09 -07:00
|
|
|
from tinygrad.helpers import getenv
|
2020-10-25 19:40:01 -06:00
|
|
|
|
2023-01-31 16:09:09 -07:00
|
|
|
FORWARD_ONLY = getenv("FORWARD_ONLY", 0)
|
2023-01-18 19:02:02 -07:00
|
|
|
def helper_test_op(shps, torch_fxn, tinygrad_fxn=None, atol=1e-6, rtol=1e-3, grad_atol=1e-4, grad_rtol=1e-3, forward_only=False, vals=None, a=-0.5, b=3):
|
|
|
|
if tinygrad_fxn is None: tinygrad_fxn = torch_fxn
|
2020-11-12 14:33:35 -07:00
|
|
|
torch.manual_seed(0)
|
2022-09-19 18:01:47 -06:00
|
|
|
np.random.seed(0)
|
2020-12-30 16:52:50 -07:00
|
|
|
if shps is None:
|
|
|
|
ts = [torch.tensor(x, requires_grad=True) for x in vals]
|
|
|
|
else:
|
2021-01-03 10:43:34 -07:00
|
|
|
ts = [torch.tensor((np.random.random(size=x).astype(np.float32)+a)*b, requires_grad=True) for x in shps]
|
2020-10-25 19:40:01 -06:00
|
|
|
|
2023-01-09 13:40:01 -07:00
|
|
|
tst = [Tensor(x.detach().numpy(), requires_grad=not FORWARD_ONLY) for x in ts]
|
2022-10-26 19:02:36 -06:00
|
|
|
|
|
|
|
st = time.monotonic()
|
2020-10-25 20:01:02 -06:00
|
|
|
out = torch_fxn(*ts)
|
2022-10-26 19:02:36 -06:00
|
|
|
torch_fp = time.monotonic() - st
|
|
|
|
|
|
|
|
st = time.monotonic()
|
|
|
|
ret = tinygrad_fxn(*tst).realize()
|
|
|
|
tinygrad_fp = time.monotonic() - st
|
2020-10-25 20:01:02 -06:00
|
|
|
|
2022-09-13 09:18:52 -06:00
|
|
|
def compare(s, x,y,atol,rtol):
|
2022-09-13 09:31:04 -06:00
|
|
|
if y.shape != tuple(): assert x.shape == y.shape, f"shape mismatch {x.shape} != {y.shape}"
|
2022-09-13 09:18:52 -06:00
|
|
|
try:
|
|
|
|
np.testing.assert_allclose(x,y, atol=atol, rtol=rtol)
|
|
|
|
except Exception:
|
|
|
|
raise Exception(f"{s} failed shape {x.shape}")
|
|
|
|
|
2022-10-30 14:23:58 -06:00
|
|
|
compare("forward pass", ret.numpy(), out.detach().numpy(), atol=atol, rtol=rtol)
|
2020-10-25 19:40:01 -06:00
|
|
|
|
2022-10-26 19:02:36 -06:00
|
|
|
torch_fbp, tinygrad_fbp = np.nan, np.nan
|
|
|
|
if not forward_only and not FORWARD_ONLY:
|
|
|
|
st = time.monotonic()
|
2022-10-30 17:43:24 -06:00
|
|
|
out.square().mean().backward()
|
2022-10-26 19:02:36 -06:00
|
|
|
torch_fbp = time.monotonic() - st
|
|
|
|
|
|
|
|
st = time.monotonic()
|
2022-10-30 17:43:24 -06:00
|
|
|
ret.square().mean().backward()
|
2022-10-26 19:02:36 -06:00
|
|
|
for tt in tst: tt.grad.realize()
|
|
|
|
tinygrad_fbp = time.monotonic() - st
|
2020-10-25 19:40:01 -06:00
|
|
|
|
2022-09-13 09:18:52 -06:00
|
|
|
for i, (t, tt) in enumerate(zip(ts, tst)):
|
2022-10-30 14:23:58 -06:00
|
|
|
compare(f"backward pass tensor {i}", tt.grad.numpy(), t.grad.detach().numpy(), atol=grad_atol, rtol=grad_rtol)
|
2020-10-25 20:01:02 -06:00
|
|
|
|
2022-10-26 19:02:36 -06:00
|
|
|
print("\ntesting %40r torch/tinygrad fp: %.2f / %.2f ms bp: %.2f / %.2f ms " % (shps, torch_fp*1000, tinygrad_fp*1000, torch_fbp*1000, tinygrad_fbp*1000), end="")
|
2020-10-25 20:01:02 -06:00
|
|
|
|
2020-10-25 19:40:01 -06:00
|
|
|
class TestOps(unittest.TestCase):
|
2020-12-16 00:44:08 -07:00
|
|
|
|
2020-10-29 08:57:16 -06:00
|
|
|
def test_add(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65), (45,65)], lambda x,y: x+y, Tensor.add)
|
2023-01-27 17:26:24 -07:00
|
|
|
def test_add_simple(self):
|
|
|
|
helper_test_op([(256), (256)], lambda x,y: x+y, Tensor.add, forward_only=True)
|
2022-06-12 11:19:58 -06:00
|
|
|
def test_broadcasted_add(self):
|
|
|
|
helper_test_op([(45,65), (45,1)], lambda x,y: x+y, lambda x,y: x+y)
|
2022-09-06 17:36:13 -06:00
|
|
|
def test_broadcasted_add_2(self):
|
|
|
|
helper_test_op([(45,65), (65,)], lambda x,y: x+y, lambda x,y: x+y)
|
2020-10-29 08:57:16 -06:00
|
|
|
def test_sub(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65), (45,65)], lambda x,y: x-y, Tensor.sub)
|
2020-10-29 08:57:16 -06:00
|
|
|
def test_mul(self):
|
2022-10-29 13:47:52 -06:00
|
|
|
helper_test_op([(64,64), (64,64)], lambda x,y: x*y, Tensor.mul)
|
2020-10-29 08:57:16 -06:00
|
|
|
def test_div(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65), (45,65)], lambda x,y: x/y, Tensor.div)
|
2022-09-03 17:23:39 -06:00
|
|
|
def test_div_const(self):
|
|
|
|
helper_test_op([(45,65)], lambda x: x/255, lambda x: x/255)
|
2020-10-29 08:57:16 -06:00
|
|
|
def test_pow(self):
|
2023-02-01 12:53:57 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: x**2, lambda x: Tensor.pow(x,2), a=0)
|
|
|
|
helper_test_op([(45,65)], lambda x: x**3, lambda x: Tensor.pow(x,3), a=0)
|
|
|
|
helper_test_op([(45,65)], lambda x: x**-2, lambda x: Tensor.pow(x,-2), a=0)
|
2021-01-03 10:43:34 -07:00
|
|
|
helper_test_op([(45,65), (45,65)], lambda x,y: x**y, Tensor.pow, a=0)
|
2020-10-29 08:57:16 -06:00
|
|
|
def test_sqrt(self):
|
2021-01-03 10:43:34 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: x.sqrt(), Tensor.sqrt, a=0)
|
2020-11-02 09:25:32 -07:00
|
|
|
def test_relu(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: x.relu(), Tensor.relu)
|
2020-12-09 03:58:35 -07:00
|
|
|
def test_leakyrelu(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.functional.leaky_relu(x,0.01), Tensor.leakyrelu)
|
2020-12-09 13:20:34 -07:00
|
|
|
def test_abs(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.abs(x), Tensor.abs)
|
2020-12-28 08:00:30 -07:00
|
|
|
def test_log(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.log(x), Tensor.log)
|
2020-12-28 08:00:30 -07:00
|
|
|
def test_exp(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.exp(x), Tensor.exp)
|
2021-01-03 09:29:57 -07:00
|
|
|
def test_sign(self):
|
2022-10-13 10:58:53 -06:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.sign(x), Tensor.sign)
|
2020-11-05 22:57:50 -07:00
|
|
|
def test_sigmoid(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: x.sigmoid(), Tensor.sigmoid)
|
2021-01-03 09:08:41 -07:00
|
|
|
def test_softplus(self):
|
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.functional.softplus(x), Tensor.softplus, atol=1e-6, grad_atol=1e-6)
|
2021-11-29 13:00:50 -07:00
|
|
|
def test_gelu(self):
|
2023-02-03 21:01:39 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.functional.gelu(x, approximate="tanh"), Tensor.gelu)
|
|
|
|
def test_quick_gelu(self):
|
|
|
|
helper_test_op([(45,65)], lambda x: x * torch.sigmoid(1.702 * x), Tensor.quick_gelu)
|
2022-06-11 11:47:23 -06:00
|
|
|
def test_elu(self):
|
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.functional.elu(x), Tensor.elu)
|
2022-07-16 08:26:19 -06:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.functional.elu(x, alpha=0.1), lambda x: Tensor.elu(x, alpha=0.1))
|
2021-01-03 09:29:57 -07:00
|
|
|
def test_relu6(self):
|
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.functional.relu6(x), Tensor.relu6)
|
|
|
|
def test_hardswish(self):
|
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.functional.hardswish(x), Tensor.hardswish, atol=1e-6, grad_atol=1e-6)
|
2021-01-03 09:08:41 -07:00
|
|
|
def test_mish(self):
|
|
|
|
def _mish_pytorch(x):
|
|
|
|
return x*torch.tanh(torch.nn.functional.softplus(x))
|
2021-01-05 08:45:47 -07:00
|
|
|
helper_test_op([(45,65)], _mish_pytorch, Tensor.mish, atol=1e-4)
|
2020-11-01 08:51:35 -07:00
|
|
|
def test_dot(self):
|
2021-01-05 08:45:47 -07:00
|
|
|
helper_test_op([(45,65), (65,100)], lambda x,y: x.matmul(y), Tensor.dot, atol=1e-4)
|
2022-09-13 09:18:52 -06:00
|
|
|
def test_matmul_simple(self):
|
|
|
|
helper_test_op([(2), (2,2)], lambda x,y: x.matmul(y), Tensor.dot, atol=1e-4)
|
2022-09-13 08:51:33 -06:00
|
|
|
def test_matmul(self):
|
2022-09-13 08:59:15 -06:00
|
|
|
helper_test_op([(65), (65,99)], lambda x,y: x.matmul(y), Tensor.dot, atol=1e-4)
|
2022-10-30 14:23:58 -06:00
|
|
|
def test_gemm(self):
|
2023-01-12 18:36:30 -07:00
|
|
|
helper_test_op([(64,64), (64,64)], lambda x,y: x.matmul(y), Tensor.dot, atol=1e-3)
|
2021-11-29 16:54:57 -07:00
|
|
|
def test_broadcastdot(self):
|
|
|
|
helper_test_op([(10,45,65), (65,45)], lambda x,y: x @ y, Tensor.dot, atol=1e-4)
|
2020-12-27 15:25:37 -07:00
|
|
|
def test_multidot(self):
|
2021-01-03 10:30:33 -07:00
|
|
|
helper_test_op([(10,45,65), (10,65,45)], lambda x,y: x @ y, Tensor.dot, atol=1e-4)
|
|
|
|
helper_test_op([(3,3,45,65), (3,3,65,45)], lambda x,y: x @ y, Tensor.dot, atol=1e-4)
|
2022-10-26 19:02:36 -06:00
|
|
|
def test_sum_simple(self):
|
|
|
|
helper_test_op(None, lambda x: x.sum(), Tensor.sum, vals=[[1.,1.]])
|
2022-10-29 12:59:48 -06:00
|
|
|
def test_sum_full(self):
|
|
|
|
helper_test_op([(10000)], lambda x: x.sum(), lambda x: x.sum())
|
2022-10-28 09:27:03 -06:00
|
|
|
def test_sum_relu(self):
|
|
|
|
helper_test_op([(3,4,5)], lambda x: x.relu().sum().relu(), lambda x: x.relu().sum().relu())
|
2020-11-05 22:59:16 -07:00
|
|
|
def test_sum(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,3)], lambda x: x.sum(), Tensor.sum)
|
2021-06-17 17:38:34 -06:00
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.sum(axis=3), lambda x: Tensor.sum(x, axis=3))
|
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.sum(axis=(1,3)), lambda x: Tensor.sum(x, axis=(1,3)))
|
2021-06-17 17:19:35 -06:00
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.sum(axis=(0,2)), lambda x: Tensor.sum(x, axis=(0,2)))
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.sum(axis=(1,2)), lambda x: Tensor.sum(x, axis=(1,2)))
|
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.sum(axis=1), lambda x: Tensor.sum(x, axis=1))
|
2022-09-18 18:39:41 -06:00
|
|
|
def test_min(self):
|
|
|
|
helper_test_op([(3,3)], lambda x: x.min(), Tensor.min)
|
|
|
|
helper_test_op([(45,3)], lambda x: x.min(), Tensor.min)
|
|
|
|
helper_test_op([(45,3)], lambda x: x.min().mul(0.5), lambda x: Tensor.min(x).mul(0.5))
|
2020-12-28 21:54:52 -07:00
|
|
|
def test_max(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,3)], lambda x: x.max(), Tensor.max)
|
|
|
|
helper_test_op([(45,3)], lambda x: x.max().mul(0.5), lambda x: Tensor.max(x).mul(0.5))
|
2022-10-13 10:58:53 -06:00
|
|
|
helper_test_op(None, lambda x: x.max().mul(0.5), lambda x: Tensor.max(x).mul(0.5),
|
|
|
|
vals=[
|
|
|
|
[[1.0,1.0,0.0,1.0]],
|
|
|
|
])
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.max(axis=1)[0], lambda x: Tensor.max(x, axis=1))
|
2020-12-07 23:58:34 -07:00
|
|
|
def test_mean_axis(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.mean(axis=(1,2)), lambda x: Tensor.mean(x, axis=(1,2)))
|
2020-11-07 08:26:53 -07:00
|
|
|
def test_logsoftmax(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: torch.nn.LogSoftmax(dim=1)(x), Tensor.logsoftmax, atol=1e-7, grad_atol=1e-7)
|
2020-11-12 14:32:50 -07:00
|
|
|
def test_tanh(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: x.tanh(), Tensor.tanh, atol=1e-6, grad_atol=1e-6)
|
2020-11-15 21:25:29 -07:00
|
|
|
def test_topo_sort(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: (x+x)*x, lambda x: x.add(x).mul(x), atol=1e-6, grad_atol=1e-6)
|
2020-12-08 10:52:07 -07:00
|
|
|
|
|
|
|
def test_scalar_mul(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: x*2, lambda x: x*2)
|
2020-12-08 10:52:07 -07:00
|
|
|
def test_scalar_rmul(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: 2*x, lambda x: 2*x)
|
2020-10-29 08:57:16 -06:00
|
|
|
|
2020-12-08 11:05:21 -07:00
|
|
|
def test_scalar_sub(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: x-2, lambda x: x-2)
|
2020-12-08 11:05:21 -07:00
|
|
|
def test_scalar_rsub(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(45,65)], lambda x: 2-x, lambda x: 2-x)
|
2020-12-08 11:05:21 -07:00
|
|
|
|
2020-11-12 14:33:35 -07:00
|
|
|
def test_broadcast_full(self):
|
2020-11-12 08:08:28 -07:00
|
|
|
for torch_op, tinygrad_op in [(torch.add, Tensor.add), (torch.sub, Tensor.sub), (torch.mul, Tensor.mul),
|
|
|
|
(torch.div, Tensor.div), (torch.pow, Tensor.pow)]:
|
2020-11-12 14:33:35 -07:00
|
|
|
for shapes in [((5,13,24,16), (5,1,24,1)), ((1,3,1,7,1), (2,1,5,1,8))]:
|
|
|
|
with self.subTest(op=torch_op.__name__, shapes=shapes):
|
2021-01-03 10:43:34 -07:00
|
|
|
helper_test_op(shapes, torch_op, tinygrad_op, a=-0.5 if tinygrad_op != Tensor.pow else 0.0)
|
2020-11-12 14:33:35 -07:00
|
|
|
|
2022-07-19 10:24:02 -06:00
|
|
|
def test_broadcast_simple(self):
|
|
|
|
helper_test_op([(45,65), (45,1)], lambda x,y: x/y, lambda x,y: x/y)
|
2020-11-12 14:33:35 -07:00
|
|
|
|
|
|
|
def test_broadcast_partial(self):
|
|
|
|
for torch_op, tinygrad_op in [(torch.add, Tensor.add), (torch.sub, Tensor.sub), (torch.mul, Tensor.mul),
|
|
|
|
(torch.div, Tensor.div), (torch.pow, Tensor.pow)]:
|
|
|
|
for shapes in [((1,32,32,32), (1,32,1,1)), ((5,13,24,16,2), (1,13,24,1,1)),
|
|
|
|
((4,1), (4,5)), ((1,4), (5,4))]:
|
2020-11-12 08:08:28 -07:00
|
|
|
with self.subTest(op=torch_op.__name__, shapes=shapes):
|
2020-12-16 00:44:08 -07:00
|
|
|
# NOTE: ANE backwards?
|
2021-01-03 10:43:34 -07:00
|
|
|
helper_test_op(shapes, torch_op, tinygrad_op, a=-0.5 if tinygrad_op != Tensor.pow else 0.0)
|
2020-11-12 08:08:28 -07:00
|
|
|
|
2022-10-26 19:02:36 -06:00
|
|
|
def test_slice_simple(self):
|
|
|
|
helper_test_op([(3,3)], lambda x: x[1:2, 1:2], lambda x: x[1:2, 1:2])
|
|
|
|
|
2020-12-30 08:32:53 -07:00
|
|
|
def test_slice(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(3,3,3,3)], lambda x: x[1:2], lambda x: x[1:2])
|
|
|
|
helper_test_op([(3,3,3,3)], lambda x: x[1:2, 1:2], lambda x: x[1:2, 1:2])
|
|
|
|
helper_test_op([(3,3,3,3)], lambda x: x[1:2, 1:2, 0:-1], lambda x: x[1:2, 1:2, 0:-1])
|
2020-12-30 08:32:53 -07:00
|
|
|
|
2022-07-03 13:14:20 -06:00
|
|
|
def test_slice_one(self):
|
|
|
|
helper_test_op([(3)], lambda x: x[1], lambda x: x[1])
|
|
|
|
|
2022-09-06 20:51:33 -06:00
|
|
|
def test_slice_one_multi(self):
|
|
|
|
helper_test_op([(10,10)], lambda x: x[1], lambda x: x[1])
|
|
|
|
|
2020-11-07 11:46:36 -07:00
|
|
|
def test_pad2d(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(3,3,3,3)], lambda x: torch.nn.functional.pad(x, (1,2,3,4)), lambda x: x.pad2d(padding=(1,2,3,4)))
|
2020-11-07 11:46:36 -07:00
|
|
|
|
2020-12-27 14:59:12 -07:00
|
|
|
def test_transpose(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(3,3,3)], lambda x: x.transpose(1,2), lambda x: x.transpose(order=(0,2,1)))
|
2022-06-06 09:14:52 -06:00
|
|
|
helper_test_op([(3,3,3)], lambda x: x.transpose(0,2), lambda x: x.transpose(order=(2,1,0)))
|
|
|
|
helper_test_op([(1,2,3,4)], lambda x: x.movedim((3,0,2,1),(0,1,2,3)), lambda x: x.transpose(order=(3,0,2,1)))
|
|
|
|
helper_test_op([(3,4,5,6)], lambda x: x.movedim((3,2,1,0),(0,1,2,3)), lambda x: x.transpose(order=(3,2,1,0)))
|
2020-12-27 14:59:12 -07:00
|
|
|
|
2020-11-13 14:20:43 -07:00
|
|
|
def test_reshape(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(4,3,6,6)], lambda x: torch.reshape(x, (-1,3,6,6)), lambda x: x.reshape(shape=(-1,3,6,6)))
|
|
|
|
helper_test_op([(4,3,6,6)], lambda x: torch.reshape(x, (-1,1,6,6)), lambda x: x.reshape(shape=(-1,1,6,6)))
|
2020-11-13 14:20:43 -07:00
|
|
|
|
2022-06-14 18:28:43 -06:00
|
|
|
def test_flip(self):
|
|
|
|
helper_test_op([(4,3,6,6)], lambda x: torch.flip(x, (0,)), lambda x: x.flip(axis=(0,)))
|
|
|
|
helper_test_op([(4,3,6,6)], lambda x: torch.flip(x, (0,1)), lambda x: x.flip(axis=(0,1)))
|
|
|
|
helper_test_op([(4,3,6,6)], lambda x: torch.flip(x, (0,1,3)), lambda x: x.flip(axis=(0,1,3)))
|
|
|
|
helper_test_op([(4,3,6,6)], lambda x: torch.flip(x, (3,)), lambda x: x.flip(axis=(3,)))
|
|
|
|
|
2022-06-11 12:15:16 -06:00
|
|
|
def test_flatten(self):
|
|
|
|
for axis in range(3):
|
|
|
|
helper_test_op([(4,3,6,6)], lambda x: torch.flatten(x, start_dim=axis), lambda x: x.flatten(axis))
|
|
|
|
|
2020-11-19 20:03:42 -07:00
|
|
|
def test_detach(self):
|
2021-01-01 07:19:03 -07:00
|
|
|
helper_test_op([(4,3,6,6)], lambda x: x.detach(), lambda x: x.detach(), forward_only=True)
|
2020-11-19 20:03:42 -07:00
|
|
|
|
2022-06-12 13:31:48 -06:00
|
|
|
def test_expand(self):
|
|
|
|
arg = (4,3,2,6)
|
|
|
|
helper_test_op([(4,3,1,6)], lambda x: x.expand(arg), lambda x: x.expand(shape=arg))
|
|
|
|
|
2022-10-26 19:02:36 -06:00
|
|
|
@unittest.skip("very slow")
|
2022-09-03 13:32:43 -06:00
|
|
|
def test_sd_big_conv(self):
|
|
|
|
# internal shape (1, 1, 512, 62, 62, 512, 3, 3) overflows a int
|
2022-10-01 11:26:05 -06:00
|
|
|
helper_test_op([(1,256,64,64), (512,256,3,3)],
|
2022-09-03 13:32:43 -06:00
|
|
|
lambda x,w: torch.nn.functional.conv2d(x, w),
|
2022-10-01 11:26:05 -06:00
|
|
|
lambda x,w: x.conv2d(w), atol=1e-2)
|
2022-09-19 18:01:47 -06:00
|
|
|
|
2023-01-12 18:36:30 -07:00
|
|
|
@unittest.skip("not supported with IMAGE=1")
|
2022-09-19 18:01:47 -06:00
|
|
|
def test_large_bs_conv(self):
|
|
|
|
# large batch size can cause OpenCL image to exceed max image height on macOS
|
|
|
|
# (or cause the conv kernel to overflow short sampling coords)
|
|
|
|
helper_test_op([(4096,3,3,3), (1,3,3,3)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x, w),
|
|
|
|
lambda x,w: x.conv2d(w), atol=1e-4, rtol=1e-2)
|
|
|
|
|
2023-01-12 18:36:30 -07:00
|
|
|
@unittest.skip("not supported with IMAGE=1")
|
2022-09-19 18:01:47 -06:00
|
|
|
def test_large_ic_conv(self):
|
|
|
|
# large input channel count can cause OpenCL image to exceed max image width on macOS
|
|
|
|
helper_test_op([(1,2048,3,3), (1,2048,3,3)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x, w),
|
2022-09-03 13:32:43 -06:00
|
|
|
lambda x,w: x.conv2d(w), atol=1e-4)
|
|
|
|
|
2022-06-19 17:57:14 -06:00
|
|
|
def test_biased_conv2d(self):
|
|
|
|
C = 8
|
|
|
|
helper_test_op([(1,C,5,5), (C,C,1,1), (C,)],
|
|
|
|
lambda x,w,b: torch.nn.functional.conv2d(torch.nn.functional.conv2d(x,w,b).relu(),w,b),
|
2022-10-30 17:43:24 -06:00
|
|
|
lambda x,w,b: Tensor.conv2d(x,w,b).relu().conv2d(w,b), atol=1e-4)
|
2022-06-19 17:57:14 -06:00
|
|
|
|
2022-06-10 16:04:39 -06:00
|
|
|
def test_simple_conv2d(self):
|
2023-01-09 13:40:01 -07:00
|
|
|
helper_test_op([(1,4,9,9), (4,4,3,3)],
|
2022-06-10 16:04:39 -06:00
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w).relu(), atol=1e-4, grad_rtol=1e-5)
|
|
|
|
|
2023-01-09 13:40:01 -07:00
|
|
|
def test_nested_conv2d(self):
|
|
|
|
helper_test_op([(1,32,9,9), (32,32,3,3), (32,32,3,3)],
|
|
|
|
lambda x,w1,w2: torch.nn.functional.conv2d(torch.nn.functional.conv2d(x,w1).relu(), w2).relu(),
|
|
|
|
lambda x,w1,w2: x.conv2d(w1).relu().conv2d(w2).relu(), atol=1e-4, grad_rtol=1e-5)
|
|
|
|
|
2022-10-26 19:02:36 -06:00
|
|
|
# expect reduce nodes == 3
|
|
|
|
def test_simple_conv2d_nhwc(self):
|
|
|
|
# weights (from tf): filter_height x filter_width x in_channels x out_channels
|
|
|
|
helper_test_op([(2,9,9,10), (3,3,10,20)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x.permute(0,3,1,2),w.permute(3,2,0,1)).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x.permute(0,3,1,2),w.permute(3,2,0,1)).relu(), atol=1e-4, grad_rtol=1e-5)
|
|
|
|
|
2022-06-16 16:40:52 -06:00
|
|
|
def test_simple_conv2d_batched(self):
|
|
|
|
helper_test_op([(2,4,9,9), (4,4,3,3)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w).relu(),
|
2022-06-26 18:20:25 -06:00
|
|
|
lambda x,w: Tensor.conv2d(x,w).relu(), atol=1e-4, grad_rtol=1e-5)
|
2022-06-16 16:40:52 -06:00
|
|
|
|
2020-10-25 19:40:01 -06:00
|
|
|
def test_conv2d(self):
|
2020-10-26 09:38:53 -06:00
|
|
|
for bs in [1,8]:
|
2020-10-25 20:01:02 -06:00
|
|
|
for cin in [1,3]:
|
2020-10-30 10:19:20 -06:00
|
|
|
for groups in [1,3] if cin == 3 else [1]:
|
2020-11-07 11:15:52 -07:00
|
|
|
for H in [1,2,5]:
|
|
|
|
for W in [1,2,3,5]:
|
2020-11-09 07:25:06 -07:00
|
|
|
with self.subTest(batch_size=bs, channels=cin, groups=groups, height=H, width=W):
|
|
|
|
helper_test_op([(bs,cin,11,28), (6,cin//groups,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,groups=groups).relu(),
|
2021-01-03 10:30:33 -07:00
|
|
|
lambda x,w: Tensor.conv2d(x,w,groups=groups).relu(), atol=1e-4, grad_rtol=1e-5)
|
2022-09-06 17:36:13 -06:00
|
|
|
|
2021-10-30 17:12:19 -06:00
|
|
|
def test_large_input_conv2d(self):
|
|
|
|
bs = 4
|
|
|
|
cin = 16
|
|
|
|
groups = 1
|
|
|
|
H = 5
|
|
|
|
W = 2
|
|
|
|
helper_test_op([(bs,cin,64,64), (6,cin//groups,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,groups=groups).relu(),
|
2022-06-14 18:28:43 -06:00
|
|
|
# needed to relax tolerance on NVIDIA
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,groups=groups).relu(), atol=1e-3, grad_rtol=1e-5)
|
2020-10-25 19:40:01 -06:00
|
|
|
|
2022-06-10 16:04:39 -06:00
|
|
|
def test_simple_grouped_conv2d(self):
|
|
|
|
bs = 1
|
|
|
|
groups = 2
|
|
|
|
rcout = 1
|
|
|
|
cin = 2
|
|
|
|
helper_test_op([(bs,groups*cin,1,1), (groups*rcout,cin,1,1)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,groups=groups).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,groups=groups).relu(), atol=1e-4, grad_rtol=1e-5)
|
|
|
|
|
|
|
|
def test_medium_grouped_conv2d(self):
|
|
|
|
bs = 1
|
|
|
|
groups = 2
|
|
|
|
rcout = 2
|
|
|
|
cin = 2
|
|
|
|
helper_test_op([(bs,groups*cin,1,1), (groups*rcout,cin,1,1)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,groups=groups).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,groups=groups).relu(), atol=1e-4, grad_rtol=1e-5)
|
|
|
|
|
2023-01-09 13:40:01 -07:00
|
|
|
def test_depthwise_conv2d(self):
|
|
|
|
bs = 1
|
|
|
|
groups = 32
|
|
|
|
rcout = 1
|
|
|
|
cin = 1
|
|
|
|
helper_test_op([(bs,groups*cin,32,32), (groups*rcout,cin,1,1)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,groups=groups).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,groups=groups).relu(), atol=1e-4, grad_rtol=1e-5)
|
|
|
|
|
2021-06-07 18:45:09 -06:00
|
|
|
def test_grouped_conv2d(self):
|
2022-06-10 13:20:42 -06:00
|
|
|
bs = 4
|
|
|
|
groups = 5
|
|
|
|
rcout = 7
|
|
|
|
cin = 3
|
|
|
|
helper_test_op([(bs,groups*cin,5,5), (groups*rcout,cin,3,3)],
|
2021-06-07 18:45:09 -06:00
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,groups=groups).relu(),
|
2022-06-10 13:20:42 -06:00
|
|
|
lambda x,w: Tensor.conv2d(x,w,groups=groups).relu(), atol=1e-4, grad_rtol=1e-5)
|
2021-06-07 18:45:09 -06:00
|
|
|
|
|
|
|
def test_fancy_conv2d(self):
|
|
|
|
bs = 2
|
|
|
|
cin = 3
|
|
|
|
cout = 1
|
|
|
|
groups = 3
|
|
|
|
H,W = 3,3
|
|
|
|
helper_test_op([(bs,cin,11,28), (groups*cout,cin//groups,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,groups=groups).relu(),
|
2021-10-30 17:12:19 -06:00
|
|
|
lambda x,w: Tensor.conv2d(x,w,groups=groups).relu(), atol=1e-4, grad_rtol=1e-5)
|
2021-06-07 18:45:09 -06:00
|
|
|
|
2022-07-17 13:49:58 -06:00
|
|
|
def test_strided_conv2d_simple(self):
|
|
|
|
bs,H,W = 2,3,1
|
|
|
|
helper_test_op([(bs,1,5,1), (1,1,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,stride=2).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,stride=2).relu(), atol=1e-4)
|
|
|
|
|
2020-10-26 09:47:11 -06:00
|
|
|
def test_strided_conv2d(self):
|
|
|
|
bs = 4
|
|
|
|
cin = 3
|
|
|
|
H,W = 3,3
|
2020-11-09 07:25:06 -07:00
|
|
|
with self.subTest(stride := 2):
|
|
|
|
helper_test_op([(bs,cin,11,28), (4,cin,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,stride=2).relu(),
|
2021-01-03 10:30:33 -07:00
|
|
|
lambda x,w: Tensor.conv2d(x,w,stride=stride).relu(), atol=1e-4)
|
2020-11-09 07:25:06 -07:00
|
|
|
with self.subTest(stride := (2,1)):
|
|
|
|
helper_test_op([(bs,cin,11,28), (4,cin,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,stride=stride).relu(),
|
2021-01-03 10:30:33 -07:00
|
|
|
lambda x,w: Tensor.conv2d(x,w,stride=(2,1)).relu(), atol=1e-4)
|
2020-10-26 09:47:11 -06:00
|
|
|
|
2022-06-26 18:59:25 -06:00
|
|
|
def test_negative_padding_conv2d(self):
|
|
|
|
n,k = 10, 3
|
|
|
|
helper_test_op([(1,1,n,n), (1,1,k,k)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x[:, :, 1:-1, 1:-1],w).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,padding=-1).relu(), atol=1e-4)
|
|
|
|
helper_test_op([(1,1,n,n), (1,1,k,k)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x[:, :, 1:, 1:],w).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,padding=(-1,0,-1,0)).relu(), atol=1e-4)
|
|
|
|
|
2023-01-12 18:36:30 -07:00
|
|
|
def test_simple_padding_conv2d(self):
|
|
|
|
p = (1,1,1,1)
|
|
|
|
helper_test_op(None,
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(torch.nn.functional.pad(x, p),w).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,padding=p).relu(), atol=1e-4, vals=[[[[[2.,3.]]]], [[[[1.]]]]])
|
|
|
|
|
2022-06-26 18:59:25 -06:00
|
|
|
def test_asymmetric_padding_conv2d(self):
|
|
|
|
for p in [(0,1,0,1), (2,1,2,1), (2,0,2,1)]:
|
|
|
|
with self.subTest(padding := p):
|
|
|
|
for n in [3,4]:
|
|
|
|
for k in [2]:
|
|
|
|
helper_test_op([(1,1,n,n), (1,1,k,k)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(torch.nn.functional.pad(x, p),w).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,padding=p).relu(), atol=1e-4)
|
|
|
|
helper_test_op([(1,1,n,n), (1,1,k,k)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(torch.nn.functional.pad(x, p),w).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,padding=p).relu(), atol=1e-4)
|
|
|
|
|
2022-06-14 18:41:22 -06:00
|
|
|
def test_padded_conv2d(self):
|
|
|
|
bs = 4
|
|
|
|
cin = 3
|
|
|
|
H,W = 3,3
|
2022-06-26 18:20:25 -06:00
|
|
|
for p in [2, (2,1), (2,2)]:
|
2022-06-15 15:46:44 -06:00
|
|
|
with self.subTest(padding := p):
|
|
|
|
helper_test_op([(bs,cin,11,28), (4,cin,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,padding=padding).relu(),
|
2022-06-26 18:20:25 -06:00
|
|
|
lambda x,w: Tensor.conv2d(x,w,padding=padding).relu(), atol=1e-4)
|
2022-06-15 12:38:23 -06:00
|
|
|
|
2023-01-12 18:36:30 -07:00
|
|
|
def test_padded_conv2d_bs1(self):
|
|
|
|
bs = 1
|
|
|
|
cin = 3
|
|
|
|
H,W = 3,3
|
|
|
|
padding = 1
|
|
|
|
helper_test_op([(bs,cin,11,28), (4,cin,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,padding=padding).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,padding=padding).relu(), atol=1e-4)
|
|
|
|
|
2022-06-14 19:03:35 -06:00
|
|
|
def test_dilated_conv2d(self):
|
|
|
|
bs = 4
|
|
|
|
cin = 3
|
|
|
|
H,W = 3,3
|
2022-06-15 12:38:23 -06:00
|
|
|
for d in [2, (2,1)]:
|
|
|
|
with self.subTest(dilation := d):
|
|
|
|
helper_test_op([(bs,cin,11,28), (4,cin,H,W)],
|
|
|
|
lambda x,w: torch.nn.functional.conv2d(x,w,dilation=dilation).relu(),
|
|
|
|
lambda x,w: Tensor.conv2d(x,w,dilation=dilation).relu(), atol=1e-4)
|
2022-06-14 19:03:35 -06:00
|
|
|
|
2022-06-26 18:07:03 -06:00
|
|
|
def test_maxpool2d_simple(self):
|
|
|
|
ksz = (2,2)
|
|
|
|
helper_test_op([(1,1,2,3)],
|
|
|
|
lambda x: torch.nn.functional.max_pool2d(x, kernel_size=ksz),
|
2022-10-13 10:58:53 -06:00
|
|
|
lambda x: Tensor.max_pool2d(x, kernel_size=ksz))
|
2022-06-26 18:07:03 -06:00
|
|
|
|
2020-11-08 12:45:55 -07:00
|
|
|
def test_maxpool2d(self):
|
2023-01-30 12:07:23 -07:00
|
|
|
for ksz in [(2,2), (3,3), 2, 3, (3,2), (5,5), (5,1)]:
|
2020-11-09 07:25:06 -07:00
|
|
|
with self.subTest(kernel_size=ksz):
|
|
|
|
helper_test_op([(32,2,110,28)],
|
|
|
|
lambda x: torch.nn.functional.max_pool2d(x, kernel_size=ksz),
|
2022-10-13 10:58:53 -06:00
|
|
|
lambda x: Tensor.max_pool2d(x, kernel_size=ksz))
|
2020-11-08 18:25:01 -07:00
|
|
|
|
2020-11-08 12:45:55 -07:00
|
|
|
def test_avgpool2d(self):
|
2020-11-09 18:31:22 -07:00
|
|
|
shape = (32,2,111,28)
|
|
|
|
for ksz in [(2,2), (3,3), (3,2), (5,5), (5,1), shape[2:]]:
|
2020-11-09 07:25:06 -07:00
|
|
|
with self.subTest(kernel_size=ksz):
|
2020-11-09 18:31:22 -07:00
|
|
|
helper_test_op([shape],
|
2020-11-09 07:25:06 -07:00
|
|
|
lambda x: torch.nn.functional.avg_pool2d(x, kernel_size=ksz),
|
2021-01-01 07:19:03 -07:00
|
|
|
lambda x: Tensor.avg_pool2d(x, kernel_size=ksz), rtol=1e-5)
|
2020-10-25 19:40:01 -06:00
|
|
|
|
2021-11-28 21:21:49 -07:00
|
|
|
def test_cat(self):
|
|
|
|
for dim in range(-1, 2):
|
2022-06-11 12:50:47 -06:00
|
|
|
helper_test_op([(45,65), (45,65)], lambda x,y: torch.cat((x,y), dim), lambda x,y: x.cat(y, dim=dim))
|
|
|
|
|
|
|
|
def test_multicat(self):
|
|
|
|
for dim in range(-1, 2):
|
|
|
|
helper_test_op([(45,65), (45,65), (45,65)], lambda x,y,z: torch.cat((x,y,z), dim), lambda x,y,z: x.cat(y, z, dim=dim))
|
2021-11-28 21:21:49 -07:00
|
|
|
|
2022-06-11 14:17:15 -06:00
|
|
|
def test_clip(self):
|
|
|
|
helper_test_op([(45,65)], lambda x: x.clip(-2.3, 1.2), lambda x: x.clip(-2.3, 1.2))
|
|
|
|
|
2023-01-18 19:02:02 -07:00
|
|
|
def test_matvec(self):
|
|
|
|
helper_test_op([(1,128), (128,128), (128,128)], lambda x,y,z: (x@y).relu()@z, atol=1e-4)
|
|
|
|
|
2020-10-25 19:40:01 -06:00
|
|
|
if __name__ == '__main__':
|
2021-06-07 18:45:09 -06:00
|
|
|
np.random.seed(1337)
|
2020-10-25 20:01:02 -06:00
|
|
|
unittest.main(verbosity=2)
|