Add tests for all unary aten ops supported in eager mode (#12087)

* Add tests for all uniary aten ops supported in eager mode

* fixing the PR draft

* fixing the merge

* changing eval to be at compile time

* adding requirements for eager

* 1.adding function to {ops}_out
2.cleaning the code
  and adding comments

* editing the code according to code review

Co-authored-by: root <root@AHA-LIRONKESE-1>
This commit is contained in:
LironKesem 2022-07-12 08:53:19 -04:00 committed by GitHub
parent 73310b2a0f
commit 9647a3be40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 127 additions and 30 deletions

View file

@ -8,6 +8,57 @@ import unittest
import numpy as np
import onnxruntime_pybind11_state as torch_ort
import torch
from parameterized import parameterized
# OPS - is a list of list of [test_operator, the tested_tensor].
# The default value for tested_tensor is torch.rand (6)- size of 6 uniform distribution on the interval [0, 1).
# for floor and erf the ort- produce a roundoff error for floor(NaN), compare to cpu- stay NaN. thus, nan_to_num change nan to zero.
ops = [
["abs", torch.tensor([-1, -2, 3, -6, -7])],
["acos"],
["acosh"],
["asinh"],
["atanh"],
["asin"],
["atan"],
["ceil"],
["cos"],
["cosh"],
["erf", torch.nan_to_num(torch.rand(5))],
["exp"],
["floor", torch.nan_to_num(torch.rand(5))],
["log"],
["reciprocal"],
["neg"],
["round"],
["relu"],
["sigmoid"],
["sin"],
["sinh"],
["sqrt"],
["tan"],
["tanh"],
]
# the following unary ops not been tested:
# ["isnan", torch.tensor([1, float('nan'), 2])]]
# ["selu", torch.randn(10)]]
# ["nonzero", torch.tensor([0, 2, 1, 3])]]
# ["sign", ]]
# ["hardsigmoid", ],
# ["isinf", ],
# ["det" ]]
def rename_func_to_op(testcase_func, param_num, param):
return f"test_{parameterized.to_safe_name(str(param.args[0]))}"
def rename_func_to_inplace(testcase_func, param_num, param):
return f"test_{parameterized.to_safe_name(str(param.args[0]))}_"
def rename_func_to_out(testcase_func, param_num, param):
return f"test_{parameterized.to_safe_name(str(param.args[0]))}_out"
class OrtOpTests(unittest.TestCase):
@ -200,6 +251,50 @@ class OrtOpTests(unittest.TestCase):
assert torch.allclose(cpu_result, ort_result.cpu())
assert cpu_result.dim() == ort_result.dim()
# @parameterized.expand generate test methods for ops and using name_func we renaming the test to be test_{ops}
@parameterized.expand(ops, name_func=rename_func_to_op)
def test_op(self, test_name, tensor_test=torch.rand(6)):
# compile eval- creates a code object that evaluates the operator (for example torch.abs(tensor_test)) and returns its result.
cpu_result = eval(compile("torch." + test_name + "(tensor_test)", "<string>", "eval"))
ort_result = eval(compile("torch." + test_name + "(tensor_test.to(self.get_device()))", "<string>", "eval"))
assert torch.allclose(cpu_result, ort_result.cpu(), equal_nan=True)
@parameterized.expand(ops, name_func=rename_func_to_inplace)
def test_op_inplace(self, test_name, tensor_test=torch.rand(6)):
device = self.get_device()
cpu_tensor = tensor_test
ort_tensor = cpu_tensor.to(device)
eval(compile("torch." + test_name + "_(cpu_tensor)", "<string>", "eval"))
eval(compile("torch." + test_name + "_(ort_tensor)", "<string>", "eval"))
assert torch.allclose(cpu_tensor, ort_tensor.cpu(), equal_nan=True)
@parameterized.expand(ops, name_func=rename_func_to_out)
def test_op_out(self, test_name, tensor_test=torch.rand(6)):
##relu -don't have output
if test_name == "relu":
self.skipTest(f"no {test_name}_output")
### troubleshoot later: the following tests are Failing.
if test_name == "asin" or test_name == "log" or test_name == "atanh":
self.skipTest(f" {test_name}_output Fails - skipping for now")
device = self.get_device()
cpu_tensor = tensor_test
ort_tensor = cpu_tensor.to(device)
cpu_out_tensor = torch.tensor([], dtype=tensor_test.dtype)
ort_out_tensor = cpu_out_tensor.to(device)
st_cpu = f"torch.{test_name}(cpu_tensor, out=cpu_out_tensor)"
st_ort = f"torch.{test_name}(ort_tensor, out=ort_out_tensor)"
cpu_result = eval(compile(st_cpu, "<string>", "eval"))
ort_result = eval(compile(st_ort, "<string>", "eval"))
assert torch.allclose(cpu_result, ort_result.cpu(), equal_nan=True)
assert torch.allclose(cpu_out_tensor, ort_out_tensor.cpu(), equal_nan=True)
assert torch.allclose(ort_result.cpu(), ort_out_tensor.cpu(), equal_nan=True)
def test_resize(self):
device = self.get_device()
@ -258,26 +353,6 @@ class OrtOpTests(unittest.TestCase):
self.assertEqual(cpu_tensor.size(), ort_tensor.size())
self.assertTrue(torch.allclose(cpu_tensor, ort_tensor.cpu()))
def test_abs(self):
device = self.get_device()
cpu_tensor = torch.tensor([-1, -2, 3, -6, -7])
ort_tensor = cpu_tensor.to(device)
cpu_result = torch.abs(cpu_tensor)
ort_result = torch.abs(ort_tensor)
assert torch.equal(cpu_result, ort_result.cpu())
def test_abs_(self):
device = self.get_device()
cpu_tensor = torch.tensor([-1, -2, 3, -6, -7])
ort_tensor = cpu_tensor.to(device)
torch.abs_(cpu_tensor)
torch.abs_(ort_tensor)
assert torch.equal(cpu_tensor, ort_tensor.cpu())
def test_abs_out(self):
device = self.get_device()
cpu_tensor = torch.tensor([-1, -2, 3, -6, -7])
@ -305,8 +380,12 @@ class OrtOpTests(unittest.TestCase):
print(f"Testing {func} with type {tensor_type}")
cpu_out_tensor = torch.tensor([], dtype=tensor_type)
ort_out_tensor = cpu_out_tensor.to(device)
cpu_a_b_eq_result = eval("torch." + func + "(cpu_a, cpu_b, out=cpu_out_tensor)")
ort_a_b_eq_result = eval("torch." + func + "(ort_a, ort_b, out=ort_out_tensor)")
cpu_a_b_eq_result = eval(
compile("torch." + func + "(cpu_a, cpu_b, out=cpu_out_tensor)", "<string>", "eval")
)
ort_a_b_eq_result = eval(
compile("torch." + func + "(ort_a, ort_b, out=ort_out_tensor)", "<string>", "eval")
)
assert torch.equal(cpu_a_b_eq_result.to(device), ort_a_b_eq_result)
assert torch.equal(cpu_out_tensor, ort_out_tensor.to("cpu"))
assert ort_out_tensor.dtype == tensor_type
@ -332,15 +411,31 @@ class OrtOpTests(unittest.TestCase):
ort_out_tensor = cpu_out_tensor.to(device)
for func in {"eq", "ne"}:
cpu_int_int_result = eval("torch." + func + "(cpu_tensor_int, cpu_scalar_int, out=cpu_out_tensor)")
cpu_int_int_not_result = eval("torch." + func + "(cpu_tensor_int, cpu_scalar_int_not)")
cpu_float_float_result = eval("torch." + func + "(cpu_tensor_float, cpu_scalar_float)")
cpu_float_float_not_result = eval("torch." + func + "(cpu_tensor_float, cpu_scalar_float_not)")
cpu_int_int_result = eval(
compile("torch." + func + "(cpu_tensor_int, cpu_scalar_int, out=cpu_out_tensor)", "<string>", "eval")
)
cpu_int_int_not_result = eval(
compile("torch." + func + "(cpu_tensor_int, cpu_scalar_int_not)", "<string>", "eval")
)
cpu_float_float_result = eval(
compile("torch." + func + "(cpu_tensor_float, cpu_scalar_float)", "<string>", "eval")
)
cpu_float_float_not_result = eval(
compile("torch." + func + "(cpu_tensor_float, cpu_scalar_float_not)", "<string>", "eval")
)
ort_int_int_result = eval("torch." + func + "(ort_tensor_int, ort_scalar_int, out=ort_out_tensor)")
ort_int_int_not_result = eval("torch." + func + "(ort_tensor_int, ort_scalar_int_not)")
ort_float_float_result = eval("torch." + func + "(ort_tensor_float, ort_scalar_float)")
ort_float_float_not_result = eval("torch." + func + "(ort_tensor_float, ort_scalar_float_not)")
ort_int_int_result = eval(
compile("torch." + func + "(ort_tensor_int, ort_scalar_int, out=ort_out_tensor)", "<string>", "eval")
)
ort_int_int_not_result = eval(
compile("torch." + func + "(ort_tensor_int, ort_scalar_int_not)", "<string>", "eval")
)
ort_float_float_result = eval(
compile("torch." + func + "(ort_tensor_float, ort_scalar_float)", "<string>", "eval")
)
ort_float_float_not_result = eval(
compile("torch." + func + "(ort_tensor_float, ort_scalar_float_not)", "<string>", "eval")
)
assert torch.equal(cpu_out_tensor, ort_out_tensor.to("cpu"))
assert torch.equal(cpu_int_int_result, ort_int_int_result.to("cpu"))

View file

@ -7,3 +7,4 @@ h5py
sklearn
numpy
pandas
parameterized

View file

@ -3,3 +3,4 @@ wheel
numpy
typing_extensions
torch==1.11.0
parameterized