From 19fed83d84b72f0199c2b7279c94e59a538f6cc3 Mon Sep 17 00:00:00 2001 From: Yibing Liu Date: Wed, 23 May 2018 03:07:43 -0700 Subject: [PATCH 1/5] Add part of compare operators --- fluid_onnx/ops.py | 14 +++++++++--- tests/test_compare_ops.py | 47 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 tests/test_compare_ops.py diff --git a/fluid_onnx/ops.py b/fluid_onnx/ops.py index 238ee2977..fcd4d4fba 100644 --- a/fluid_onnx/ops.py +++ b/fluid_onnx/ops.py @@ -155,6 +155,14 @@ def clip_op(operator, block): max=attrs['max']) +def compare_ops(op_type, operator, block): + ''' Conversion for compare ops, including 'Less', 'Equal', 'Greater' + ''' + inputs, attrs, outputs = op_io_info(operator) + return make_node( + op_type, inputs=inputs['X'] + inputs['Y'], outputs=outputs['Out']) + + def concat_op(operator, block): inputs, attrs, outputs = op_io_info(operator) return make_node( @@ -696,7 +704,7 @@ def xor_op(): 'elementwise_pow': partial(elementwise_ops, 'Pow'), 'elementwise_sub': partial(elementwise_ops, 'Sub'), '': 'Elu', - '': 'Equal', + 'equal': partial(compare_ops, 'Equal'), 'exp': partial(activation_ops, 'Exp'), '': 'Flatten', 'floor': partial(activation_ops, 'Floor'), @@ -704,14 +712,14 @@ def xor_op(): '': 'Gather', '': 'Gemm', '': 'GlobalLpPool', - '': 'Greater', + 'greater_than': partial(compare_ops, 'Greater'), 'hard_sigmoid': 'HardSigmoid', # Caffe2 error # 'Hardmax', NEEDS ATTENTION. # 'InstanceNormalization', NEEDS ATTENTION. + 'less_than': partial(compare_ops, 'Less'), 'lrn': lrn_op, '': 'LSTM', '': 'LeakyRelu', - '': 'Less', 'log': partial(activation_ops, 'Log'), 'logical_and': partial(binary_logical_ops, 'And'), 'logical_or': partial(binary_logical_ops, 'Or'), diff --git a/tests/test_compare_ops.py b/tests/test_compare_ops.py new file mode 100644 index 000000000..e92873e36 --- /dev/null +++ b/tests/test_compare_ops.py @@ -0,0 +1,47 @@ +# Copyright (c) 2018 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. + +import op_test +import unittest +import numpy + + +def create_test_class(op_type, typename, callback): + class Cls(op_test.OpTest): + def setUp(self): + a = numpy.random.random(size=(10, 7)).astype(typename) + b = numpy.random.random(size=(10, 7)).astype(typename) + c = callback(a, b) + self.inputs = {'X': a, 'Y': b} + self.outputs = {'Out': c} + self.op_type = op_type + + def test_output(self): + self.check_output() + + cls_name = "{0}_{1}".format(op_type, typename) + Cls.__name__ = cls_name + globals()[cls_name] = Cls + + +for _type_name in {'float32', 'float64', 'int32', 'int64'}: + create_test_class('less_than', _type_name, lambda _a, _b: _a < _b) + #create_test_class('less_equal', _type_name, lambda _a, _b: _a <= _b) + create_test_class('greater_than', _type_name, lambda _a, _b: _a > _b) + #create_test_class('greater_equal', _type_name, lambda _a, _b: _a >= _b) + #create_test_class('equal', _type_name, lambda _a, _b: _a == _b) + #create_test_class('not_equal', _type_name, lambda _a, _b: _a != _b) + +if __name__ == '__main__': + unittest.main() From 3c37dd51af6c014c40105af51a092058c7b4f0d6 Mon Sep 17 00:00:00 2001 From: Yibing Liu Date: Wed, 23 May 2018 04:13:02 -0700 Subject: [PATCH 2/5] Add gather_op conversion --- fluid_onnx/ops.py | 12 +++++------- tests/test_gather_op.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 tests/test_gather_op.py diff --git a/fluid_onnx/ops.py b/fluid_onnx/ops.py index fcd4d4fba..ec3386ac9 100644 --- a/fluid_onnx/ops.py +++ b/fluid_onnx/ops.py @@ -294,8 +294,10 @@ def gru_op(): pass -def gather_op(): - pass +def gather_op(operator, block): + inputs, attrs, outputs = op_io_info(operator) + return make_node( + 'Gather', inputs=inputs['X'] + inputs['Index'], outputs=outputs['Out']) def gemm_op(): @@ -306,10 +308,6 @@ def globallppool_op(): pass -def greater_op(): - pass - - def hardsigmoid_op(operator, block): inputs, attrs, outputs = op_io_info(operator) return make_node( @@ -709,7 +707,7 @@ def xor_op(): '': 'Flatten', 'floor': partial(activation_ops, 'Floor'), '': 'GRU', - '': 'Gather', + 'gather': gather_op, '': 'Gemm', '': 'GlobalLpPool', 'greater_than': partial(compare_ops, 'Greater'), diff --git a/tests/test_gather_op.py b/tests/test_gather_op.py new file mode 100644 index 000000000..93a07f7d6 --- /dev/null +++ b/tests/test_gather_op.py @@ -0,0 +1,32 @@ +# Copyright (c) 2018 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. + +import unittest +import numpy as np +from op_test import OpTest + + +class TestGatherOp(OpTest): + def setUp(self): + self.op_type = "gather" + xnp = np.random.random((10, 20)).astype("float32") + self.inputs = {'X': xnp, 'Index': np.array([1, 3, 5]).astype("int32")} + self.outputs = {'Out': self.inputs["X"][self.inputs["Index"]]} + + def test_check_output(self): + self.check_output() + + +if __name__ == "__main__": + unittest.main() From 50742a60c17cd97c8237c2bb62914356730a3ca8 Mon Sep 17 00:00:00 2001 From: Yibing Liu Date: Wed, 23 May 2018 18:13:41 -0700 Subject: [PATCH 3/5] Add elu_op & leaky_relu_op --- fluid_onnx/ops.py | 25 +++++++++++++++---------- tests/test_activation_ops.py | 12 ++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/fluid_onnx/ops.py b/fluid_onnx/ops.py index ec3386ac9..30c710c1a 100644 --- a/fluid_onnx/ops.py +++ b/fluid_onnx/ops.py @@ -278,8 +278,10 @@ def elementwise_ops(op_type, operator, block): broadcast=1) -def elu_op(): - pass +def elu_op(operator, block): + inputs, attrs, outputs = op_io_info(operator) + return make_node( + 'Elu', inputs=inputs['X'], outputs=outputs['Out'], alpha=attrs['alpha']) def equal_op(): @@ -343,12 +345,13 @@ def lstm_op(): pass -def leakyrelu_op(): - pass - - -def less_op(): - pass +def leaky_relu_op(operator, block): + inputs, attrs, outputs = op_io_info(operator) + return make_node( + 'LeakyRelu', + inputs=inputs['X'], + outputs=outputs['Out'], + alpha=attrs['alpha']) def binary_logical_ops(op_type, operator, block): @@ -693,6 +696,7 @@ def xor_op(): 'conv2d': conv2d_op, # Need to continue the mapping below. 'conv2d_transpose': conv2d_transpose_op, + # 'cos': partial(activation_ops, 'Cos'), '': 'DepthToSpace', 'depthwise_conv2d': conv2d_op, 'dropout': dropout_op, @@ -701,7 +705,7 @@ def xor_op(): 'elementwise_mul': partial(elementwise_ops, 'Mul'), 'elementwise_pow': partial(elementwise_ops, 'Pow'), 'elementwise_sub': partial(elementwise_ops, 'Sub'), - '': 'Elu', + 'elu': elu_op, 'equal': partial(compare_ops, 'Equal'), 'exp': partial(activation_ops, 'Exp'), '': 'Flatten', @@ -717,7 +721,7 @@ def xor_op(): 'less_than': partial(compare_ops, 'Less'), 'lrn': lrn_op, '': 'LSTM', - '': 'LeakyRelu', + 'leaky_relu': leaky_relu_op, 'log': partial(activation_ops, 'Log'), 'logical_and': partial(binary_logical_ops, 'And'), 'logical_or': partial(binary_logical_ops, 'Or'), @@ -758,6 +762,7 @@ def xor_op(): # 'Selu', NEEDS ATTENTION. '': 'Shape', 'sigmoid': partial(activation_ops, 'Sigmoid'), + # 'sin': partial(activation_ops, 'Sin'), '': 'Size', # 'Slice', NEEDS ATTENTION. 'softmax': softmax_op, diff --git a/tests/test_activation_ops.py b/tests/test_activation_ops.py index b1310c2bd..014216441 100644 --- a/tests/test_activation_ops.py +++ b/tests/test_activation_ops.py @@ -86,5 +86,17 @@ def init_op_type(self): self.op_type = 'tanh' +class TestEluOp(TestAbsOp): + def init_op_type(self): + self.op_type = 'elu' + self.attrs = {'alpha': 2.0} + + +class TestLeakyReluOp(TestAbsOp): + def init_op_type(self): + self.op_type = 'leaky_relu' + self.attrs = {'alpha': 0.1} + + if __name__ == '__main__': unittest.main() From d842c53c4e8e2b03dd5f03221c0c412cf42049d6 Mon Sep 17 00:00:00 2001 From: Yibing Liu Date: Wed, 23 May 2018 18:32:03 -0700 Subject: [PATCH 4/5] Add the conversion of prelu_op --- fluid_onnx/ops.py | 33 +++++---------------------------- tests/test_prelu_op.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 tests/test_prelu_op.py diff --git a/fluid_onnx/ops.py b/fluid_onnx/ops.py index 30c710c1a..544903794 100644 --- a/fluid_onnx/ops.py +++ b/fluid_onnx/ops.py @@ -486,22 +486,10 @@ def neg_op(): pass -def not_op(): - """ - Need to support broadcast. - """ - pass - - -def or_op(): - """ - Need to support broadcast. - """ - pass - - -def prelu_op(): - pass +def prelu_op(operator, block): + inputs, attrs, outputs = op_io_info(operator) + return make_node( + 'PRelu', inputs=inputs['X'] + inputs['Alpha'], outputs=outputs['Out']) def pad_op(): @@ -639,10 +627,6 @@ def split_op(): pass -def sqrt_op(): - pass - - def squeeze_op(): pass @@ -671,13 +655,6 @@ def unsqueeze_op(): pass -def xor_op(): - """ - Need to support broadcast. - """ - pass - - # Based on the ONNX 1.0 operator list generated on March 26th, 2018. # Reference for paddle operator availability taken from: # /~https://github.com/PaddlePaddle/Paddle/issues/8028 @@ -738,7 +715,7 @@ def xor_op(): '': 'Min', 'mul': mul_op, ',': 'Neg', - '': 'PRelu', + 'prelu': prelu_op, '': 'Pad', 'pool2d': pool2d_op, ',': 'RNN', diff --git a/tests/test_prelu_op.py b/tests/test_prelu_op.py new file mode 100644 index 000000000..908a39efb --- /dev/null +++ b/tests/test_prelu_op.py @@ -0,0 +1,33 @@ +# Copyright (c) 2018 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. + +import unittest +import numpy as np +from op_test import OpTest + + +class PReluTest(OpTest): + def setUp(self): + self.op_type = "prelu" + x = np.random.normal((10, 10)).astype("float32") + alpha = np.array([.1], dtype="float32") + self.inputs = {'X': x, 'Alpha': alpha} + self.outputs = {'Out': np.zeros((1, 1))} + + def test_check_output(self): + self.check_output() + + +if __name__ == "__main__": + unittest.main() From f5087a06d3ef02af6a6d53de26b04b0f1c6f7091 Mon Sep 17 00:00:00 2001 From: Yibing Liu Date: Wed, 23 May 2018 18:47:46 -0700 Subject: [PATCH 5/5] Add thresholded_relu_op --- fluid_onnx/ops.py | 11 ++++++++++- tests/test_activation_ops.py | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fluid_onnx/ops.py b/fluid_onnx/ops.py index 544903794..75291d7c4 100644 --- a/fluid_onnx/ops.py +++ b/fluid_onnx/ops.py @@ -655,6 +655,15 @@ def unsqueeze_op(): pass +def thresholded_relu_op(operator, block): + inputs, attrs, outputs = op_io_info(operator) + return make_node( + 'ThresholdedRelu', + inputs=inputs['X'], + outputs=outputs['Out'], + alpha=attrs['threshold']) + + # Based on the ONNX 1.0 operator list generated on March 26th, 2018. # Reference for paddle operator availability taken from: # /~https://github.com/PaddlePaddle/Paddle/issues/8028 @@ -771,6 +780,6 @@ def unsqueeze_op(): # 'experimental ParametricSoftplus' # 'experimental Scale' # 'experimental ScaledTanh' - # 'experimental ThresholdedRelu' + 'thresholded_relu': thresholded_relu_op, # 'experimental Upsample' } diff --git a/tests/test_activation_ops.py b/tests/test_activation_ops.py index 014216441..605a7a2b1 100644 --- a/tests/test_activation_ops.py +++ b/tests/test_activation_ops.py @@ -98,5 +98,11 @@ def init_op_type(self): self.attrs = {'alpha': 0.1} +class TestThresholdedReluOp(TestAbsOp): + def init_op_type(self): + self.op_type = 'thresholded_relu' + self.attrs = {'alpha': 0.1} + + if __name__ == '__main__': unittest.main()