From f83cf4b76586e39fa87d29a89c3d72a6b1c30729 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 6 Oct 2021 17:43:24 +0800 Subject: [PATCH] [FrontEnd]Paddle_Op_Conversion_prior_box (#7639) * Paddle_Op_Conversion_prior_box * use default_opset * apply review comments * const type variables modification --- .../paddlepaddle/src/op/prior_box.cpp | 112 ++++++++++++++++ ngraph/frontend/paddlepaddle/src/op_table.cpp | 2 + .../test/frontend/paddlepaddle/op_fuzzy.cpp | 4 + .../gen_scripts/generate_prior_box.py | 124 ++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 ngraph/frontend/paddlepaddle/src/op/prior_box.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_prior_box.py diff --git a/ngraph/frontend/paddlepaddle/src/op/prior_box.cpp b/ngraph/frontend/paddlepaddle/src/op/prior_box.cpp new file mode 100644 index 00000000000000..fcdae08eaccf48 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/prior_box.cpp @@ -0,0 +1,112 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph/op/prior_box.hpp" + +#include + +#include "default_opset.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { +using namespace default_opset; +using namespace element; +namespace detail { +namespace { +std::shared_ptr make_slice(const std::shared_ptr& node, int64_t start, int64_t end) { + return std::make_shared(node, + Constant::create(i64, Shape{1}, std::vector{start}), + Constant::create(i64, Shape{1}, std::vector{end}), + std::vector{0}, // begin mask + std::vector{0}); // end mask +} +} // namespace +} // namespace detail +NamedOutputs prior_box(const NodeContext& node) { + auto input = node.get_ng_input("Input"); + auto Image = node.get_ng_input("Image"); + const auto input_shape = std::make_shared(input); + const auto Image_shape = std::make_shared(Image); + const auto output_shape_slice = detail::make_slice(input_shape, 2, 4); + const auto image_shape_slice = detail::make_slice(Image_shape, 2, 4); + + ngraph::op::PriorBoxAttrs attrs; + attrs.min_size = node.get_attribute>("min_sizes", {}); + attrs.max_size = node.get_attribute>("max_sizes", {}); + attrs.aspect_ratio = node.get_attribute>("aspect_ratios", {1.0}); + attrs.flip = node.get_attribute("flip", false); + attrs.clip = node.get_attribute("clip", false); + attrs.step = node.get_attribute("step_w", 0); + + attrs.offset = node.get_attribute("offset", 0.5); + attrs.variance = node.get_attribute>("variances", {0.1, 0.1, 0.2, 0.2}); + + bool min_max_aspect_ratios_order = node.get_attribute("min_max_aspect_ratios_order", false); + + const auto ov_prior_box_node = std::make_shared(output_shape_slice, image_shape_slice, attrs); + + const auto split_axis_node = Constant::create(i64, ngraph::Shape{}, {0}); + const auto node_prior_box_split = std::make_shared(ov_prior_box_node, split_axis_node, 2); + + const auto node_boxes_origin = node_prior_box_split->output(0); + const auto node_variances_origin = node_prior_box_split->output(1); + + const auto out_shape = + std::make_shared(NodeVector{output_shape_slice, Constant::create(i64, {2}, {-1, 4})}, 0); + + auto node_boxes_reshape = std::make_shared(node_boxes_origin, out_shape, true); + const auto node_variances_reshape = std::make_shared(node_variances_origin, out_shape, true); + + int64_t total_aspect_ratios = ngraph::op::PriorBox::normalized_aspect_ratio(attrs.aspect_ratio, attrs.flip).size(); + if ((total_aspect_ratios > 1) && !attrs.min_size.empty() && !attrs.max_size.empty() && + !min_max_aspect_ratios_order) { + std::vector mask{1, 1, 1, 0, 1}; + int64_t min_size_len = static_cast(attrs.min_size.size()); + + const auto out_shape_div_numpri = std::make_shared( + NodeVector{output_shape_slice, Constant::create(i64, {3}, {min_size_len, -1, 4})}, + 0); + const auto node_boxes_div_numpri = std::make_shared(node_boxes_reshape, out_shape_div_numpri, true); + + const auto slice_begin_min = Constant::create(i64, Shape{5}, std::vector{0, 0, 0, 0, 0}); + const auto slice_end_min = std::make_shared( + NodeVector{output_shape_slice, Constant::create(i64, {3}, {min_size_len, 1, 4})}, + 0); + const auto slice_min_node = + std::make_shared(node_boxes_div_numpri, slice_begin_min, slice_end_min, mask, mask); + + const auto slice_begin_max = Constant::create(i64, Shape{5}, std::vector{0, 0, 0, 1, 0}); + const auto slice_end_max = std::make_shared( + NodeVector{output_shape_slice, Constant::create(i64, {3}, {min_size_len, 2, 4})}, + 0); + const auto slice_max_node = + std::make_shared(node_boxes_div_numpri, slice_begin_max, slice_end_max, mask, mask); + + const auto slice_begin_aspect_ratios = Constant::create(i64, Shape{5}, std::vector{0, 0, 0, 2, 0}); + const auto slice_end_aspect_ratios = std::make_shared( + NodeVector{output_shape_slice, + Constant::create(i64, {3}, {min_size_len, 2 + (total_aspect_ratios - 1), 4})}, + 0); + const auto slice_aspect_ratios_node = std::make_shared(node_boxes_div_numpri, + slice_begin_aspect_ratios, + slice_end_aspect_ratios, + mask, + mask); + + const auto node_boxes_div_numpri_reorder = + std::make_shared(NodeVector{slice_min_node, slice_aspect_ratios_node, slice_max_node}, 3); + node_boxes_reshape = std::make_shared(node_boxes_div_numpri_reorder, out_shape, true); + } + + NamedOutputs outputs; + outputs["Boxes"] = {node_boxes_reshape}; + outputs["Variances"] = {node_variances_reshape}; + return outputs; +} +} // namespace op +} // namespace pdpd +} // namespace frontend +} // namespace ngraph diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index e6c4106b12b7ed..e4e1943778172e 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -51,6 +51,7 @@ OP_CONVERTER(nearest_interp_v2); OP_CONVERTER(pad3d); OP_CONVERTER(pow); OP_CONVERTER(pool2d); +OP_CONVERTER(prior_box); OP_CONVERTER(range); OP_CONVERTER(relu); OP_CONVERTER(relu6); @@ -126,6 +127,7 @@ std::map get_supported_ops() { {"pad3d", op::pad3d}, {"pow", op::pow}, {"pool2d", op::pool2d}, + {"prior_box", op::prior_box}, {"range", op::range}, {"relu", op::relu}, {"relu6", op::relu6}, diff --git a/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp b/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp index 9e7f91096d9caf..2b24f718b974e6 100644 --- a/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp +++ b/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp @@ -155,6 +155,10 @@ static const std::vector models{std::string("argmax"), std::string("pow_int64"), // pow_int64_out_of_range(out of range of OV int64), std::string("pow_y_tensor"), + std::string("prior_box_attrs_mmar_order_true"), + std::string("prior_box_default"), + std::string("prior_box_flip_clip_false"), + std::string("prior_box_max_sizes_none"), std::string("range0"), std::string("range1"), std::string("range2"), diff --git a/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_prior_box.py b/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_prior_box.py new file mode 100644 index 00000000000000..12e9ddd80fe80c --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_prior_box.py @@ -0,0 +1,124 @@ +# +# prior_box paddle model generator +# +import numpy as np +from save_model import saveModel +import sys + + +def prior_box(name: str, input_data, image_data, attrs: dict): + import paddle as pdpd + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + Input = pdpd.static.data( + name='Input', shape=input_data.shape, dtype=input_data.dtype) + Image = pdpd.static.data( + name='Image', shape=image_data.shape, dtype=image_data.dtype) + + box, var = pdpd.fluid.layers.prior_box(Input, + Image, + min_sizes=attrs['min_sizes'], + max_sizes=attrs['max_sizes'], + aspect_ratios=attrs['aspect_ratios'], + variance=attrs['variance'], + flip=attrs['flip'], + clip=attrs['clip'], + steps=attrs['steps'], + offset=attrs['offset'], + name=None, + min_max_aspect_ratios_order=attrs['min_max_aspect_ratios_order']) + + cpu = pdpd.static.cpu_places(1) + exe = pdpd.static.Executor(cpu[0]) + # startup program will call initializer to initialize the parameters. + exe.run(pdpd.static.default_startup_program()) + + outs = exe.run( + feed={'Input': input_data, 'Image': image_data}, + fetch_list=[box, var]) + + # Save inputs in order of ngraph function, to facilite Fuzzy test, + # which accepts inputs and outputs in this order as well. + saveModel(name, exe, feedkeys=['Input', 'Image'], fetchlist=[box, var], + inputs=[input_data, image_data], outputs=outs, target_dir=sys.argv[1]) + return outs + + +if __name__ == "__main__": + + prior_box_attrs_default = { + 'name': "prior_box_default", + 'min_sizes': np.array([2, 4]).astype('float32').tolist(), + 'max_sizes': np.array([5, 10]).astype('float32').tolist(), + 'aspect_ratios': [2.0, 3.0], + 'flip': True, + 'clip': True, + 'steps': np.array([1.25, 1.25]).astype('float32').tolist(), + 'offset': 0.5, + 'variance': np.array([0.1, 0.1, 0.2, 0.2], dtype=np.float).flatten(), + 'min_max_aspect_ratios_order': False + } + + prior_box_max_sizes_none = { + 'name': "prior_box_max_sizes_none", + 'min_sizes': np.array([2, 4]).astype('float32').tolist(), + 'max_sizes': None, + 'aspect_ratios': [2.0, 3.0], + 'flip': True, + 'clip': True, + 'steps': np.array([1.25, 1.25]).astype('float32').tolist(), + 'offset': 0.5, + 'variance': np.array([0.1, 0.1, 0.2, 0.2], dtype=np.float).flatten(), + 'min_max_aspect_ratios_order': False + } + + prior_box_flip_clip_false = { + 'name': "prior_box_flip_clip_false", + 'min_sizes': np.array([2, 4]).astype('float32').tolist(), + 'max_sizes': np.array([5, 10]).astype('float32').tolist(), + 'aspect_ratios': [2.0, 3.0], + 'flip': False, + 'clip': False, + 'steps': np.array([1.25, 1.25]).astype('float32').tolist(), + 'offset': 0.5, + 'variance': np.array([0.1, 0.1, 0.2, 0.2], dtype=np.float).flatten(), + 'min_max_aspect_ratios_order': False + } + + prior_box_attrs_mmar_order_true = { + 'name': "prior_box_attrs_mmar_order_true", + 'min_sizes': np.array([2, 4]).astype('float32').tolist(), + 'max_sizes': np.array([5, 10]).astype('float32').tolist(), + 'aspect_ratios': [2.0, 3.0], + 'flip': True, + 'clip': True, + 'steps': np.array([1.25, 1.25]).astype('float32').tolist(), + 'offset': 0.5, + 'variance': np.array([0.1, 0.1, 0.2, 0.2], dtype=np.float).flatten(), + 'min_max_aspect_ratios_order': True + } + + prior_box_attrs_list = [prior_box_attrs_default, + prior_box_max_sizes_none, prior_box_flip_clip_false, prior_box_attrs_mmar_order_true] + + layer_w = 32 + layer_h = 32 + + image_w = 40 + image_h = 40 + + input_channels = 2 + image_channels = 3 + batch_size = 10 + + input_data = np.random.random( + (batch_size, input_channels, layer_w, + layer_h)).astype('float32') + + image_data = np.random.random( + (batch_size, image_channels, image_w, + image_h)).astype('float32') + + for item in prior_box_attrs_list: + pred_pdpd = prior_box(item['name'], input_data, image_data, item)