Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logical and compare ops #855

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/inference_model_convertor/op_list.md
Expand Up @@ -76,7 +76,7 @@
| 81 | Add | 82 | Concat | 83 | Max | 84 | Min |
| 85 | GreaterOrEqual | 86 | GatherND | 87 | And | 88 | cos |
| 89 | Neg | 90 | SpaceToDepth | 91 | GatherElement | 92 | Sin |
| 93 | CumSum | | | | | | |
| 93 | CumSum | 94 | Or | 95 | Xor | 96 | Mod |

## PyTorch

Expand Down
7 changes: 5 additions & 2 deletions tests/onnx/auto_scan_test.py
Expand Up @@ -48,7 +48,7 @@
derandomize=True,
report_multiple_bugs=False)
if float(os.getenv('TEST_NUM_PERCENT_CASES', default='1.0')) < 1 or \
os.getenv('HYPOTHESIS_TEST_PROFILE', 'dev') == 'ci':
os.getenv('HYPOTHESIS_TEST_PROFILE', 'dev') == 'ci':
settings.load_profile("ci")
else:
settings.load_profile("dev")
Expand Down Expand Up @@ -155,6 +155,7 @@ def run_test(self, configs):
# max_opset_version is a fixed value
max_opset_version = 15
enable_onnx_checker = True
run_dynamic = False

self.num_ran_tests += 1
# add ignore testcases
Expand Down Expand Up @@ -189,12 +190,14 @@ def run_test(self, configs):
max_opset_version = config["max_opset_version"]
if "enable_onnx_checker" in config.keys():
enable_onnx_checker = config["enable_onnx_checker"]
if "run_dynamic" in config.keys():
run_dynamic = config["run_dynamic"]

for i in range(len(op_names)):
obj = ONNXConverter(op_names[i], min_opset_version[i],
max_opset_version, op_names[i], inputs_name,
outputs_name, inputs_shape, delta, rtol, attrs,
enable_onnx_checker)
enable_onnx_checker, run_dynamic)
for input_type in input_type_list:
input_data = list()
for j, shape in enumerate(test_data_shapes):
Expand Down
40 changes: 28 additions & 12 deletions tests/onnx/onnxbase.py
Expand Up @@ -60,7 +60,7 @@ def compare(result, expect, delta=1e-10, rtol=1e-10):
result.shape, expect.shape)
assert result.dtype == expect.dtype, "result.dtype: {} != expect.dtype: {}".format(
result.dtype, expect.dtype)
elif isinstance(result, (list, tuple)) and len(result) > 1:
elif isinstance(result, (list, tuple)):
for i in range(len(result)):
if isinstance(result[i], (np.generic, np.ndarray)):
compare(result[i], expect[i], delta, rtol)
Expand All @@ -69,6 +69,8 @@ def compare(result, expect, delta=1e-10, rtol=1e-10):
# deal with scalar tensor
elif len(expect) == 1:
compare(result, expect[0], delta, rtol)
else:
raise Exception("Compare diff wrong!!!!!!")


def randtool(dtype, low, high, shape):
Expand Down Expand Up @@ -101,7 +103,8 @@ def __init__(self,
delta=1e-5,
rtol=1e-5,
attrs=[],
enable_onnx_checker=True):
enable_onnx_checker=True,
run_dynamic=False):
self.op_type = op_type
assert isinstance(self.op_type,
str), "The dtype of op_type must be string!"
Expand All @@ -124,6 +127,7 @@ def __init__(self,
self.inputs_shape = inputs_shape
self.attrs = attrs
self.enable_onnx_checker = enable_onnx_checker
self.run_dynamic = run_dynamic

def set_input_data(self, group_name, *args):
"""
Expand Down Expand Up @@ -182,17 +186,29 @@ def _mk_paddle_res(self, ver):
"""
make paddle res
"""
paddle_path = os.path.join(
self.pwd, self.name,
self.name + '_' + str(ver) + '_paddle/inference_model/model')
paddle.disable_static()
# run
model = paddle.jit.load(paddle_path)
paddle_feed = list()

# input data
paddle_numpy_feed = list()
paddle_tensor_feed = list()
for i in range(len(self.input_feed)):
paddle_feed.append(self.input_feed[self.inputs_name[i]])
result = model(*paddle_feed)
paddle_numpy_feed.append(self.input_feed[self.inputs_name[i]])
paddle_tensor_feed.append(
paddle.to_tensor(self.input_feed[self.inputs_name[i]]))

if self.run_dynamic:
paddle_path = os.path.join(self.pwd, self.name,
self.name + '_' + str(ver) + '_paddle/')
import sys
sys.path.append(paddle_path)
from x2paddle_code import main
result = main(*paddle_tensor_feed)
else:
paddle_path = os.path.join(
self.pwd, self.name,
self.name + '_' + str(ver) + '_paddle/inference_model/model')
paddle.disable_static()
# run
model = paddle.jit.load(paddle_path)
result = model(*paddle_numpy_feed)
# get paddle outputs
if isinstance(result, (tuple, list)):
result = tuple(out.numpy() for out in result)
Expand Down
78 changes: 78 additions & 0 deletions tests/onnx/test_auto_scan_compare_ops.py
@@ -0,0 +1,78 @@
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from auto_scan_test import OPConvertAutoScanTest
from hypothesis import reproduce_failure
from onnxbase import randtool
import hypothesis.strategies as st
import numpy as np
import unittest

min_opset_version_map = {
"Greater": 7,
"Less": 7,
"GreaterOrEqual": 12,
"LessOrEqual": 12,
}


class TestCompareopsConvert(OPConvertAutoScanTest):
"""
ONNX op: Compare ops
OPset version: 7~15
"""

def sample_convert_config(self, draw):
input1_shape = draw(
st.lists(
st.integers(
min_value=10, max_value=20), min_size=2, max_size=4))

if draw(st.booleans()):
input2_shape = [input1_shape[-1]]
else:
input2_shape = input1_shape

if draw(st.booleans()):
input2_shape = [1]

input_dtype = draw(st.sampled_from(["float32", "float64"]))

config = {
"op_names": ["Greater", "Less", "GreaterOrEqual", "LessOrEqual"],
"test_data_shapes": [input1_shape, input2_shape],
"test_data_types": [[input_dtype], [input_dtype]],
"inputs_shape": [],
"min_opset_version": 7,
"inputs_name": ["x", "y"],
"outputs_name": ["z"],
"delta": 1e-4,
"rtol": 1e-4,
"run_dynamic": True,
}
min_opset_versions = list()
for op_name in config["op_names"]:
min_opset_versions.append(min_opset_version_map[op_name])
config["min_opset_version"] = min_opset_versions

attrs = {}

return (config, attrs)

def test(self):
self.run_and_statis(max_examples=30)


if __name__ == "__main__":
unittest.main()
67 changes: 67 additions & 0 deletions tests/onnx/test_auto_scan_equal.py
@@ -0,0 +1,67 @@
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from auto_scan_test import OPConvertAutoScanTest
from hypothesis import reproduce_failure
from onnxbase import randtool
import hypothesis.strategies as st
import numpy as np
import unittest


class TestEqualConvert(OPConvertAutoScanTest):
"""
ONNX op: Equal
OPset version: 7~15
"""

def sample_convert_config(self, draw):
input1_shape = draw(
st.lists(
st.integers(
min_value=10, max_value=20), min_size=2, max_size=4))

if draw(st.booleans()):
input2_shape = [input1_shape[-1]]
else:
input2_shape = input1_shape

if draw(st.booleans()):
input2_shape = [1]

input_dtype = draw(st.sampled_from(["int32", "int64", "bool"]))

config = {
"op_names": ["Equal"],
"test_data_shapes": [input1_shape, input2_shape],
"test_data_types": [[input_dtype], [input_dtype]],
"inputs_shape": [],
"min_opset_version": 7,
"inputs_name": ["x", "y"],
"outputs_name": ["z"],
"delta": 1e-4,
"rtol": 1e-4,
"run_dynamic": True,
}

attrs = {}

return (config, attrs)

def test(self):
self.run_and_statis(max_examples=30)


if __name__ == "__main__":
unittest.main()
77 changes: 77 additions & 0 deletions tests/onnx/test_auto_scan_logical_ops.py
@@ -0,0 +1,77 @@
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from auto_scan_test import OPConvertAutoScanTest
from hypothesis import reproduce_failure
from onnxbase import randtool
import hypothesis.strategies as st
import numpy as np
import unittest

min_opset_version_map = {
"And": 7,
"Or": 7,
"Xor": 7,
}


class TestLogicalopsConvert(OPConvertAutoScanTest):
"""
ONNX op: Logical ops
OPset version: 7~15
"""

def sample_convert_config(self, draw):
input1_shape = draw(
st.lists(
st.integers(
min_value=10, max_value=20), min_size=2, max_size=4))

if draw(st.booleans()):
input2_shape = [input1_shape[-1]]
else:
input2_shape = input1_shape

if draw(st.booleans()):
input2_shape = [1]

input_dtype = draw(st.sampled_from(["bool"]))

config = {
"op_names": ["And", "Or", "Xor"],
"test_data_shapes": [input1_shape, input2_shape],
"test_data_types": [[input_dtype], [input_dtype]],
"inputs_shape": [],
"min_opset_version": 7,
"inputs_name": ["x", "y"],
"outputs_name": ["z"],
"delta": 1e-4,
"rtol": 1e-4,
"run_dynamic": True,
}
min_opset_versions = list()
for op_name in config["op_names"]:
min_opset_versions.append(min_opset_version_map[op_name])
config["min_opset_version"] = min_opset_versions

attrs = {}

return (config, attrs)

def test(self):
self.run_and_statis(max_examples=30)


if __name__ == "__main__":
unittest.main()
20 changes: 20 additions & 0 deletions x2paddle/op_mapper/onnx2paddle/opset7.py
Expand Up @@ -33,6 +33,26 @@ class OpSet7(OpSet):
def __init__(self, decoder, paddle_graph):
super(OpSet7, self).__init__(decoder, paddle_graph)

@print_mapping_info
def Or(self, node):
val_x = self.graph.get_input_node(node, idx=0, copy=True)
val_y = self.graph.get_input_node(node, idx=1, copy=True)
self.paddle_graph.add_layer(
"paddle.logical_or",
inputs={"x": val_x.name,
"y": val_y.name},
outputs=[node.name])

@print_mapping_info
def Xor(self, node):
val_x = self.graph.get_input_node(node, idx=0, copy=True)
val_y = self.graph.get_input_node(node, idx=1, copy=True)
self.paddle_graph.add_layer(
"paddle.logical_xor",
inputs={"x": val_x.name,
"y": val_y.name},
outputs=[node.name])

@print_mapping_info
def Unsqueeze(self, node):
val_x = self.graph.get_input_node(node, idx=0, copy=True)
Expand Down