From 96806173336897180fd968f449ee8e3086aee2a7 Mon Sep 17 00:00:00 2001 From: Xiuchuan Zhai Date: Mon, 21 Nov 2022 11:05:16 +0800 Subject: [PATCH] [CPU][Paddle] support paddle reverse op mapping and unittest (#12822) * support paddle reverse op mapping and unittest * Update reverse.cpp --- src/frontends/paddle/src/op/reverse.cpp | 35 +++++++++++ src/frontends/paddle/src/op_table.cpp | 2 + src/frontends/paddle/tests/op_fuzzy.cpp | 8 +++ .../gen_scripts/generate_reverse.py | 61 +++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/frontends/paddle/src/op/reverse.cpp create mode 100644 src/frontends/paddle/tests/test_models/gen_scripts/generate_reverse.py diff --git a/src/frontends/paddle/src/op/reverse.cpp b/src/frontends/paddle/src/op/reverse.cpp new file mode 100644 index 00000000000..5714ad694b6 --- /dev/null +++ b/src/frontends/paddle/src/op/reverse.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "default_opset.hpp" +#include "openvino/frontend/paddle/node_context.hpp" +#include "openvino/opsets/opset1.hpp" + +namespace ov { +namespace frontend { +namespace paddle { +namespace op { + +using namespace default_opset; + +NamedOutputs reverse(const NodeContext& node) { + auto x = node.get_input("X"); + // axis is a vector + auto axis = node.get_attribute>("axis"); + // try to keep the axis positive since reverse IR doesn't support negative axis. + const auto dims = static_cast(x.get_partial_shape().rank().get_length()); + std::for_each(axis.begin(), axis.end(), [&dims](int32_t& value) { + if (value < 0) { + value += dims; + } + }); + + auto axis_node = std::make_shared(ngraph::element::i32, Shape{axis.size()}, axis); + auto reverse_op = std::make_shared(x, axis_node, ov::opset1::Reverse::Mode::INDEX); + return node.default_single_output_mapping({reverse_op}, {"Out"}); +} +} // namespace op +} // namespace paddle +} // namespace frontend +} // namespace ov diff --git a/src/frontends/paddle/src/op_table.cpp b/src/frontends/paddle/src/op_table.cpp index 7d27df30dbc..50fa5b55e6d 100644 --- a/src/frontends/paddle/src/op_table.cpp +++ b/src/frontends/paddle/src/op_table.cpp @@ -81,6 +81,7 @@ OP_CONVERTER(reduce_sum); OP_CONVERTER(relu); OP_CONVERTER(relu6); OP_CONVERTER(reshape2); +OP_CONVERTER(reverse); OP_CONVERTER(rnn); OP_CONVERTER(roi_align); OP_CONVERTER(scale); @@ -193,6 +194,7 @@ std::map get_supported_ops() { {"relu", op::relu}, {"relu6", op::relu6}, {"reshape2", op::reshape2}, + {"reverse", op::reverse}, {"rnn", op::rnn}, {"roi_align", op::roi_align}, {"scale", op::scale}, diff --git a/src/frontends/paddle/tests/op_fuzzy.cpp b/src/frontends/paddle/tests/op_fuzzy.cpp index ea7aadc3e18..e6cfa74d63c 100644 --- a/src/frontends/paddle/tests/op_fuzzy.cpp +++ b/src/frontends/paddle/tests/op_fuzzy.cpp @@ -418,6 +418,14 @@ static const std::vector models{ std::string("reshape"), std::string("reshape_tensor"), std::string("reshape_tensor_list"), + std::string("reverse_static_1"), + std::string("reverse_static_2"), + std::string("reverse_static_3"), + std::string("reverse_static_4"), + std::string("reverse_dynamic_1"), + std::string("reverse_dynamic_2"), + std::string("reverse_dynamic_3"), + std::string("reverse_dynamic_4"), std::string("rnn_lstm_layer_1_bidirectional"), std::string("rnn_lstm_layer_1_forward"), std::string("rnn_lstm_layer_2_bidirectional"), diff --git a/src/frontends/paddle/tests/test_models/gen_scripts/generate_reverse.py b/src/frontends/paddle/tests/test_models/gen_scripts/generate_reverse.py new file mode 100644 index 00000000000..2c72dbc3ff4 --- /dev/null +++ b/src/frontends/paddle/tests/test_models/gen_scripts/generate_reverse.py @@ -0,0 +1,61 @@ +# Copyright (C) 2018-2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# +# reverse paddle model generator +# +import numpy as np +from save_model import saveModel +import sys +import paddle + +def reverse(name: str, x, axis, use_static=True, dtype="float32"): + paddle.enable_static() + + with paddle.static.program_guard(paddle.static.Program(), paddle.static.Program()): + if use_static: + node_x = paddle.static.data(name='x', shape=x.shape, dtype=dtype) + else: + node_x = paddle.fluid.data(name='x', shape=[1, 1, -1, -1], dtype=dtype) + out = paddle.fluid.layers.reverse(node_x, axis) + + cpu = paddle.static.cpu_places(1) + exe = paddle.static.Executor(cpu[0]) + # startup program will call initializer to initialize the parameters. + exe.run(paddle.static.default_startup_program()) + + outs = exe.run( + feed={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]], target_dir=sys.argv[1]) + + return outs[0] + +def main(): + data1 = np.array([0,2], dtype='int64') + reverse("reverse_static_1", data1, 0, True, 'int64') + + data2 = np.array([[0,1,2], [3,4,5], [6,7,8]], dtype='float32') + reverse("reverse_static_2", data2, 1, True, 'float32') + + data3 = np.array([[0,1,2], [3,4,5], [6,7,8]], dtype='float32') + reverse("reverse_static_3", data3, [0, 1], True, 'float32') + + data4 = np.array([[0,1,2], [3,4,5], [6,7,8]], dtype='int32') + reverse("reverse_static_4", data4, -1, True, 'int32') + + data5 = np.random.randn(1, 1, 32, 32).astype('int32') + reverse("reverse_dynamic_1", data5, [2], False, dtype='int32') + + data6 = np.random.randn(1, 1, 64, 64).astype('float32') + reverse("reverse_dynamic_2", data6, [3], False, dtype='float32') + + data7 = np.random.randn(1, 1, 112, 112).astype('float32') + reverse("reverse_dynamic_3", data7, [2,3], False, dtype='float32') + + data8 = np.random.randn(1, 1, 224, 224).astype('int32') + reverse("reverse_dynamic_4", data8, [-2, -1], False, dtype='int32') + +if __name__ == "__main__": + main()