From 3081f6b3a18d3a063df5e1b6c1e4586072c2d558 Mon Sep 17 00:00:00 2001 From: jialipen Date: Mon, 12 Apr 2021 23:00:39 +0800 Subject: [PATCH 01/54] step1 --- ngraph/test/frontend/paddlepaddle/op.cpp | 60 ++++++++++++++++ ngraph/test/frontend/shared/include/op.hpp | 45 ++++++++++++ ngraph/test/frontend/shared/src/op.cpp | 81 ++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 ngraph/test/frontend/paddlepaddle/op.cpp create mode 100644 ngraph/test/frontend/shared/include/op.hpp create mode 100644 ngraph/test/frontend/shared/src/op.cpp diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp new file mode 100644 index 00000000000000..9c0a4fc059cd08 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using PDPDFrontendOpTest = FrontendOpTest; + +#if 0 +static const std::vector models { + std::string("conv2d"), + std::string("conv2d_s/conv2d.pdmodel"), + std::string("conv2d_relu/conv2d_relu.pdmodel"), + std::string("2in_2out/2in_2out.pdmodel"), +}; + +INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, + ::testing::Combine( + ::testing::Values(PDPD), + ::testing::Values(PATH_TO_MODELS), + ::testing::ValuesIn(models)), + PDPDFrontendOpTest::getTestCaseName); + +#endif + +static FrontendOpTestParam getTestData_2in_2out() { + FrontendOpTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "2in_2out/2in_2out.pdmodel"; + return res; +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, + ::testing::Values( + getTestData_2in_2out(), + FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_s/conv2d.pdmodel" }, + FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_relu/conv2d_relu.pdmodel" } + ), + FrontendOpTest::getTestCaseName); + +#if 0 +static std::vector getTestData_2in_2out() { + std::vector res; + + res.emplace_back(FrontendOpTestParam{PDPD, PATH_TO_MODELS, "2in_2out/2in_2out.pdmodel"}); + + return res; +} + +INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, + ::testing::ValuesIn(getTestData_2in_2out()), + FrontendOpTest::getTestCaseName); +#endif \ No newline at end of file diff --git a/ngraph/test/frontend/shared/include/op.hpp b/ngraph/test/frontend/shared/include/op.hpp new file mode 100644 index 00000000000000..b04f8bd48aee82 --- /dev/null +++ b/ngraph/test/frontend/shared/include/op.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +#include +#include "util/all_close.hpp" +#include "util/all_close_f.hpp" +#include "util/engine/test_engines.hpp" +#include "util/ndarray.hpp" +#include "util/test_case.hpp" +#include "util/test_control.hpp" +#include "util/test_tools.hpp" + +using Inputs = std::vector>; +using Outputs = std::vector>; + +struct FrontendOpTestParam { + std::string m_frontEndName; + std::string m_modelsPath; + std::string m_modelName; + + Inputs inputs; + Outputs expected_outputs; +}; + +class FrontendOpTest : public ::testing::TestWithParam { +public: + FrontendOpTestParam m_param; + + ngraph::frontend::FrontEndManager m_fem; + ngraph::frontend::FrontEnd::Ptr m_frontEnd; + ngraph::frontend::InputModel::Ptr m_inputModel; + + static std::string getTestCaseName(const testing::TestParamInfo &obj); + + void SetUp() override; + +protected: + void initParamTest(); + void doLoadFromFile(); +}; \ No newline at end of file diff --git a/ngraph/test/frontend/shared/src/op.cpp b/ngraph/test/frontend/shared/src/op.cpp new file mode 100644 index 00000000000000..b0f9705e086808 --- /dev/null +++ b/ngraph/test/frontend/shared/src/op.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include "../include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +std::string FrontendOpTest::getTestCaseName(const testing::TestParamInfo &obj) { + std::string res = obj.param.m_frontEndName + "_" + obj.param.m_modelName; + //res += "I" + joinStrings(obj.param.m_oldInputs) + joinStrings(obj.param.m_newInputs); + //res += "O" + joinStrings(obj.param.m_oldOutputs) + joinStrings(obj.param.m_newOutputs); + // need to replace special characters to create valid test case name + res = std::regex_replace(res, std::regex("[/\\.]"), "_"); + return res; +} + +void FrontendOpTest::SetUp() { + initParamTest(); +} + +void FrontendOpTest::initParamTest() { + m_param = GetParam(); + m_param.m_modelName = std::string(TEST_FILES) + m_param.m_modelsPath + m_param.m_modelName; + std::cout << "Model: " << m_param.m_modelName << std::endl; +} + +void FrontendOpTest::doLoadFromFile() { + std::vector frontends; + FrontEnd::Ptr fe; + ASSERT_NO_THROW(frontends = m_fem.availableFrontEnds()); + ASSERT_NO_THROW(m_frontEnd = m_fem.loadByFramework(m_param.m_frontEndName)); + ASSERT_NE(m_frontEnd, nullptr); + ASSERT_NO_THROW(m_inputModel = m_frontEnd->loadFromFile(m_param.m_modelName)); + ASSERT_NE(m_inputModel, nullptr); +} + +/*---------------------------------------------------------------------------------------------------------------------*/ + +using TestEngine = test::IE_CPU_Engine; + +TEST_P(FrontendOpTest, test_model_runtime) { + ASSERT_NO_THROW(doLoadFromFile()); + std::shared_ptr function; + ASSERT_NO_THROW(function = m_frontEnd->convert(m_inputModel)); + ASSERT_NE(function, nullptr); +// std::cout << "Ordered ops names\n"; +// for (const auto &n : function->get_ordered_ops()) { +// std::cout << "----" << n->get_friendly_name() << "---\n"; +// } + + Inputs inputs; + // data (1, 1, 7, 5) input tensor + inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + // filters (1, 1, 3, 3) aka convolution weights + inputs.emplace_back( + test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} + .get_vector()); + + // (1, 1, 4, 3) + auto expected_output = test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector(); + + auto test_case = test::TestCase(function); + test_case.add_multiple_inputs(inputs); + test_case.add_expected_output(expected_output); + test_case.run(); +} From 588a7c7a08d3b648bceade6f14bb3f7d61cf6e22 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 00:03:17 +0800 Subject: [PATCH 02/54] step2 --- ngraph/test/frontend/paddlepaddle/op.cpp | 87 +++++++++++++--------- ngraph/test/frontend/shared/include/op.hpp | 4 +- ngraph/test/frontend/shared/src/op.cpp | 60 ++++++--------- 3 files changed, 76 insertions(+), 75 deletions(-) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 9c0a4fc059cd08..361d601062961b 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -12,49 +12,68 @@ static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; using PDPDFrontendOpTest = FrontendOpTest; -#if 0 -static const std::vector models { - std::string("conv2d"), - std::string("conv2d_s/conv2d.pdmodel"), - std::string("conv2d_relu/conv2d_relu.pdmodel"), - std::string("2in_2out/2in_2out.pdmodel"), -}; - -INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, - ::testing::Combine( - ::testing::Values(PDPD), - ::testing::Values(PATH_TO_MODELS), - ::testing::ValuesIn(models)), - PDPDFrontendOpTest::getTestCaseName); - -#endif - -static FrontendOpTestParam getTestData_2in_2out() { +static FrontendOpTestParam conv2d() { FrontendOpTestParam res; res.m_frontEndName = PDPD; res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "2in_2out/2in_2out.pdmodel"; + res.m_modelName = "conv2d/"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 3, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + // (1, 5, 6, 6) + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector()); + return res; } -INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, - ::testing::Values( - getTestData_2in_2out(), - FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_s/conv2d.pdmodel" }, - FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_relu/conv2d_relu.pdmodel" } - ), - FrontendOpTest::getTestCaseName); +static FrontendOpTestParam relu() { + FrontendOpTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "relu/"; + + //Inputs inputs; + // data (1, 1, 7, 5) input tensor + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); -#if 0 -static std::vector getTestData_2in_2out() { - std::vector res; + // filters (1, 1, 3, 3) aka convolution weights + res.inputs.emplace_back( + test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} + .get_vector()); - res.emplace_back(FrontendOpTestParam{PDPD, PATH_TO_MODELS, "2in_2out/2in_2out.pdmodel"}); + // (1, 1, 4, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector()); return res; } -INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, - ::testing::ValuesIn(getTestData_2in_2out()), - FrontendOpTest::getTestCaseName); -#endif \ No newline at end of file +INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, + ::testing::Values( + conv2d(), + relu() + ), + FrontendOpTest::getTestCaseName); diff --git a/ngraph/test/frontend/shared/include/op.hpp b/ngraph/test/frontend/shared/include/op.hpp index b04f8bd48aee82..84c081c2f09dc5 100644 --- a/ngraph/test/frontend/shared/include/op.hpp +++ b/ngraph/test/frontend/shared/include/op.hpp @@ -16,7 +16,7 @@ #include "util/test_tools.hpp" using Inputs = std::vector>; -using Outputs = std::vector>; +using Outputs = std::vector>; struct FrontendOpTestParam { std::string m_frontEndName; @@ -41,5 +41,5 @@ class FrontendOpTest : public ::testing::TestWithParam { protected: void initParamTest(); - void doLoadFromFile(); + void validateOp(); }; \ No newline at end of file diff --git a/ngraph/test/frontend/shared/src/op.cpp b/ngraph/test/frontend/shared/src/op.cpp index b0f9705e086808..af17504ad9ad13 100644 --- a/ngraph/test/frontend/shared/src/op.cpp +++ b/ngraph/test/frontend/shared/src/op.cpp @@ -8,6 +8,8 @@ using namespace ngraph; using namespace ngraph::frontend; +using TestEngine = test::IE_CPU_Engine; + std::string FrontendOpTest::getTestCaseName(const testing::TestParamInfo &obj) { std::string res = obj.param.m_frontEndName + "_" + obj.param.m_modelName; //res += "I" + joinStrings(obj.param.m_oldInputs) + joinStrings(obj.param.m_newInputs); @@ -27,55 +29,35 @@ void FrontendOpTest::initParamTest() { std::cout << "Model: " << m_param.m_modelName << std::endl; } -void FrontendOpTest::doLoadFromFile() { - std::vector frontends; - FrontEnd::Ptr fe; - ASSERT_NO_THROW(frontends = m_fem.availableFrontEnds()); +void FrontendOpTest::validateOp() { + // load + ASSERT_NO_THROW(m_fem.availableFrontEnds()); ASSERT_NO_THROW(m_frontEnd = m_fem.loadByFramework(m_param.m_frontEndName)); ASSERT_NE(m_frontEnd, nullptr); ASSERT_NO_THROW(m_inputModel = m_frontEnd->loadFromFile(m_param.m_modelName)); ASSERT_NE(m_inputModel, nullptr); -} - -/*---------------------------------------------------------------------------------------------------------------------*/ - -using TestEngine = test::IE_CPU_Engine; -TEST_P(FrontendOpTest, test_model_runtime) { - ASSERT_NO_THROW(doLoadFromFile()); + // convert std::shared_ptr function; ASSERT_NO_THROW(function = m_frontEnd->convert(m_inputModel)); ASSERT_NE(function, nullptr); -// std::cout << "Ordered ops names\n"; -// for (const auto &n : function->get_ordered_ops()) { -// std::cout << "----" << n->get_friendly_name() << "---\n"; -// } - Inputs inputs; - // data (1, 1, 7, 5) input tensor - inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, - {5.f, 6.f, 7.f, 8.f, 9.f}, - {10.f, 11.f, 12.f, 13.f, 14.f}, - {15.f, 16.f, 17.f, 18.f, 19.f}, - {20.f, 21.f, 22.f, 23.f, 24.f}, - {25.f, 26.f, 27.f, 28.f, 29.f}, - {30.f, 31.f, 32.f, 33.f, 34.f}}}}} - .get_vector()); + // run + auto test_case = test::TestCase(function); - // filters (1, 1, 3, 3) aka convolution weights - inputs.emplace_back( - test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} - .get_vector()); + for (auto it = m_param.inputs.begin(); it != m_param.inputs.end(); it++ ) { + test_case.add_input(*it); + } + for (auto it = m_param.expected_outputs.begin(); it != m_param.expected_outputs.end(); it++) + { + test_case.add_expected_output(*it); + } + + test_case.run(); +} - // (1, 1, 4, 3) - auto expected_output = test::NDArray({{{{12.f, 27.f, 24.f}, - {63.f, 108.f, 81.f}, - {123.f, 198.f, 141.f}, - {112.f, 177.f, 124.f}}}}) - .get_vector(); +/*---------------------------------------------------------------------------------------------------------------------*/ - auto test_case = test::TestCase(function); - test_case.add_multiple_inputs(inputs); - test_case.add_expected_output(expected_output); - test_case.run(); +TEST_P(FrontendOpTest, test_model_runtime) { + ASSERT_NO_THROW(validateOp()); } From ca6e45e5864fbd7ef0c8b0234ae69cc4e9068c22 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 18:42:32 +0800 Subject: [PATCH 03/54] generate model helper and pool2d. --- .../gen_scripts/generate_pool2d.py | 81 +++++++++++++++++++ .../paddlepaddle/gen_scripts/save_model.py | 23 ++++++ 2 files changed, 104 insertions(+) create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/save_model.py diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py new file mode 100644 index 00000000000000..68095df6aef0ae --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -0,0 +1,81 @@ +# +# pool2d paddle model generator +# +import numpy as np +from save_model import saveModel + +def pool2d(name : str, x, attrs : dict): + import paddle as pdpd + pdpd.enable_static() + + exclusive = False + if 'exclusive' in attrs: + exclusive = attrs['exclusive'] + + node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') + out = pdpd.fluid.layers.pool2d(node_x, pool_size=attrs['kernel_size'], + pool_type=attrs['type'], + pool_stride=attrs['stride'], + pool_padding=attrs['pool_padding'], + global_pooling=False, + exclusive=exclusive) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + + +def main(): + data = np.array([[[ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16], + ]]]).astype(np.float32) + + # maxPool + pdpd_max_attrs = { + 'kernel_size': [3, 3], + 'type': 'max', + 'stride': 1, + 'pool_padding': 0 + } + pool2d("maxPool", data, pdpd_max_attrs) + + # maxGlobalPool + spatial_shape = np.ndim(data) - 2 + pdpd_max_global_attrs = { + 'kernel_size': [spatial_shape, spatial_shape], + 'type': 'max', + 'stride': 1, + 'pool_padding': 0, + 'global_pool': True} + + pool2d("maxGlobalPool", data, pdpd_max_global_attrs) + + # avgPool + pdpd_avg_attrs = {'kernel_size': [3, 3], + 'type': 'avg', + 'stride': 1, + 'pool_padding': 1, + 'exclusive': True} + ng_avg_attrs = { + 'kernel_size': [3, 3], + 'type': 'avg', + 'stride': [1, 1], + 'padding': [1, 1], + 'exclude_pad': True + } + pool2d("avgPool", data, pdpd_avg_attrs) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py new file mode 100644 index 00000000000000..ce22942671f935 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -0,0 +1,23 @@ + +import numpy as np +import paddle as pdpd + +def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list, **kwargv): + for key, value in kwargv.items(): + print ("%s == %s" %(key, value)) + + np.set_printoptions(precision=2) + np.set_printoptions(suppress=True) + + print("\n\n------------- %s -----------\n" % (name)) + for i, input in enumerate(inputs): + print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) + print(input) + print("\n") + for i, output in enumerate(outputs): + print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) + print(output) + + # composited model + scattered model + pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe) + pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") \ No newline at end of file From ccb74c288546729f8c4cad7ba6d41aa152e7341a Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 23:09:48 +0800 Subject: [PATCH 04/54] helper: save paddle model, dump inputs, outputs as C structures to facilite developer. --- .../paddlepaddle/gen_scripts/save_model.py | 69 +++++++++++++++++-- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index ce22942671f935..23e72f50c44a9f 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -2,22 +2,77 @@ import numpy as np import paddle as pdpd + +#print numpy array like C structure +def print_alike(arr): + shape = arr.shape + rank = len(shape) + print("shape: ", shape, "rank: %d" %(rank)) + + #for idx, value in np.ndenumerate(arr): + # print(idx, value) + print(arr) + + def print_array(arr, end=' '): + shape = arr.shape + rank = len(arr.shape) + if rank > 1: + #print("{") + line = "{" + for i in range(arr.shape[0]): + line += print_array(arr[i,:], end="},\n" if i < arr.shape[0]-1 else "}") + line += end + return line + else: + line = "{" + for i in range(arr.shape[0]): + line += str(arr[i]) + line += ", " if i < shape[0]-1 else ' ' + line += end + #print(line) + return line + + + print(print_array(arr, "}")) + + def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list, **kwargv): for key, value in kwargv.items(): - print ("%s == %s" %(key, value)) - - np.set_printoptions(precision=2) - np.set_printoptions(suppress=True) + print ("%s == %s" %(key, value)) print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) - print(input) + print_alike(input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) - print(output) + print_alike(output) # composited model + scattered model pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe) - pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") \ No newline at end of file + pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") + + +if __name__ == "__main__": + np.set_printoptions(precision=2) + np.set_printoptions(suppress=True) + + #x = np.random.randn(2,3).astype(np.float32) + x = np.array([[[ + [1, 2, 3], + [4, 5, 6] + ], + [ + [1, 2, 3], + [4, 5, 6] + ]], + [[ + [1, 2, 3], + [4, 5, 6] + ], + [ + [1, 2, 3], + [4, 5, 6] + ]]]).astype(np.float32) + print_alike(x) \ No newline at end of file From 40be6b03cb195b176d4043d91f930179012c3b66 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 23:10:23 +0800 Subject: [PATCH 05/54] test op pool2d and matmul --- .../test/frontend/paddlepaddle/op/matmul.cpp | 51 +++++++++++++++++++ .../test/frontend/paddlepaddle/op/pool2d.cpp | 46 +++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 ngraph/test/frontend/paddlepaddle/op/matmul.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/pool2d.cpp diff --git a/ngraph/test/frontend/paddlepaddle/op/matmul.cpp b/ngraph/test/frontend/paddlepaddle/op/matmul.cpp new file mode 100644 index 00000000000000..35b37580d11d70 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/matmul.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using matmulTestParam = FrontendOpTestParam; +using matmulTest = FrontendOpTest; + +static matmulTestParam matmul() { + matmulTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "matmul"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 7, 5) input tensor + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + // (1, 1, 4, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector()); + + return res; +} + +TEST_P(matmulTest, test_matmul) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, matmulTest, + ::testing::Values( + matmul() + ), + matmulTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp new file mode 100644 index 00000000000000..37885e73be006d --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using pool2dTestParam = FrontendOpTestParam; +using pool2dTest = FrontendOpTest; + +static pool2dTestParam maxPool() { + pool2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, + {5.0, 6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0, 12.0 }, + {13.0, 14.0, 15.0, 16.0 }}}}} + .get_vector()); + + // (1, 1, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{11.0, 12.0 }, + {15.0, 16.0 }}}}}) + .get_vector()); + + return res; +} + +TEST_P(pool2dTest, test_pool2d) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, pool2dTest, + ::testing::Values( + maxPool() + ), + pool2dTest::getTestCaseName); From a6b90b0183952f5a04d321dea0ff01f6266a68bb Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 23:11:35 +0800 Subject: [PATCH 06/54] git ignore ngraph/test/files/paddlepaddle/models --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8cd490e3269fc6..23fe8c3d55ce89 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ ngraph/src/ngraphConfigVersion.cmake ngraph/src/protobuf/ ngraph/src/src/ ngraph/src/test/ +ngraph/test/files/paddlepaddle/models/* From e8c90d6733db29eeb695d71180d8bd00474bc50f Mon Sep 17 00:00:00 2001 From: jialipen Date: Wed, 14 Apr 2021 17:58:16 +0800 Subject: [PATCH 07/54] pool2d global_pool fix --- .../gen_scripts/generate_pool2d.py | 7 ++- .../test/frontend/paddlepaddle/op/pool2d.cpp | 51 ++++++++++++++++++- ngraph/test/frontend/shared/src/op.cpp | 2 +- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 68095df6aef0ae..0de80c0c80e75e 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -11,13 +11,16 @@ def pool2d(name : str, x, attrs : dict): exclusive = False if 'exclusive' in attrs: exclusive = attrs['exclusive'] + global_pool=False + if 'global_pool' in attrs: + global_pool = attrs['global_pool'] node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') out = pdpd.fluid.layers.pool2d(node_x, pool_size=attrs['kernel_size'], pool_type=attrs['type'], pool_stride=attrs['stride'], pool_padding=attrs['pool_padding'], - global_pooling=False, + global_pooling=global_pool, exclusive=exclusive) cpu = pdpd.static.cpu_places(1) @@ -52,7 +55,7 @@ def main(): pool2d("maxPool", data, pdpd_max_attrs) # maxGlobalPool - spatial_shape = np.ndim(data) - 2 + spatial_shape = np.ndim(data) pdpd_max_global_attrs = { 'kernel_size': [spatial_shape, spatial_shape], 'type': 'max', diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 37885e73be006d..669b078daea9c8 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -35,12 +35,59 @@ static pool2dTestParam maxPool() { return res; } +static pool2dTestParam avgPool() { + pool2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, + {5.0, 6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0, 12.0 }, + {13.0, 14.0, 15.0, 16.0 }}}}} + .get_vector()); + + // (1, 1, 4, 4) + res.expected_outputs.emplace_back(test::NDArray({{{{{3.5, 4.0, 5.0, 5.5 }, + {5.5, 6.0, 7.0, 7.5 }, + {9.5, 10.0, 11.0, 11.5 }, + {11.5, 12.0, 13.0, 13.5 }}}}}) + .get_vector()); + + return res; +} + +static pool2dTestParam maxGlobalPool() { + pool2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxGlobalPool"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, + {5.0, 6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0, 12.0 }, + {13.0, 14.0, 15.0, 16.0 }}}}} + .get_vector()); + + // (1, 1, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{16.0 }}}}}) + .get_vector()); + + return res; +} + TEST_P(pool2dTest, test_pool2d) { - ASSERT_NO_THROW(validateOp()); + validateOp(); } INSTANTIATE_TEST_CASE_P(FrontendOpTest, pool2dTest, ::testing::Values( - maxPool() + avgPool(), + maxPool(), + maxGlobalPool() ), pool2dTest::getTestCaseName); diff --git a/ngraph/test/frontend/shared/src/op.cpp b/ngraph/test/frontend/shared/src/op.cpp index af17504ad9ad13..0024c60bca83e7 100644 --- a/ngraph/test/frontend/shared/src/op.cpp +++ b/ngraph/test/frontend/shared/src/op.cpp @@ -39,7 +39,7 @@ void FrontendOpTest::validateOp() { // convert std::shared_ptr function; - ASSERT_NO_THROW(function = m_frontEnd->convert(m_inputModel)); + function = m_frontEnd->convert(m_inputModel); ASSERT_NE(function, nullptr); // run From 16bd0435c51bd5c9c8890682fef5be745af4e850 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 15 Apr 2021 21:25:14 +0800 Subject: [PATCH 08/54] pool2d basic tests --- .../frontend/paddlepaddle/src/op/pool2d.cpp | 198 +++++++++++++++--- .../gen_scripts/generate_pool2d.py | 2 +- .../test/frontend/paddlepaddle/op/pool2d.cpp | 6 +- 3 files changed, 178 insertions(+), 28 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp index ca2c82d895ef9c..412c84d3146610 100644 --- a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp @@ -22,38 +22,186 @@ namespace frontend { namespace pdpd { namespace op { +// helper func - get pad_begin and pad_end +static void get_paddings(const NodeContext& node, ngraph::Shape& pad_begin, ngraph::Shape& pad_end, ngraph::op::PadType &auto_pad) { + // + auto pad_algo = node.get_attribute("padding_algorithm"); + if (pad_algo == "SAME") { + auto_pad = ngraph::op::PadType::SAME_UPPER; + } else if (pad_algo == "VALID") { + auto_pad = ngraph::op::PadType::VALID; + } else if (pad_algo == "EXPLICIT") { + auto_pad = ngraph::op::PadType::EXPLICIT; + }else { + // FIXME + throw std::runtime_error("Unsupported pooling padding_algorithm " + pad_algo); + } + + /*如果它是一个元组或列表,它可以有3种格式: + (1)包含2个整数值:[pad_height, pad_width]; + (2)包含4个整数值:[pad_height_top, pad_height_bottom, pad_width_left, pad_width_right]; + (3)包含4个二元组: + 当 data_format 为"NCHW"时为 [[0,0], [0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right]], + 当 data_format 为"NHWC"时为[[0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right], [0,0]]。 + 若为一个整数,则表示H和W维度上均为该值。默认值:0。*/ + auto paddings = node.get_attribute>("paddings"); + auto data_format = node.get_attribute("data_format"); + + switch (paddings.size()) + { + case 1: + pad_begin = Shape(2, paddings[0]); + pad_end = pad_begin; + break; + case 2: + pad_begin = Shape{static_cast(paddings[0]), static_cast(paddings[1])}; + pad_end = pad_begin; + break; + case 4: + pad_begin = Shape{static_cast(paddings[0]), static_cast(paddings[2])}; + pad_end = Shape(static_cast(paddings[1]), static_cast(paddings[3])); + break; + case 8: + if (data_format == "NCHW") { + pad_begin = Shape{static_cast(paddings[4]), static_cast(paddings[6])}; + pad_end = Shape(static_cast(paddings[5]), static_cast(paddings[7])); + } else if (data_format == "NHWC") { + pad_begin = Shape{static_cast(paddings[2]), static_cast(paddings[4])}; + pad_end = Shape(static_cast(paddings[3]), static_cast(paddings[5])); + } else { + throw std::runtime_error("Unsupported pooling data_format " + data_format); + } + break; + default: + throw std::runtime_error("Unsupported pooling paddings " + paddings.size()); + break; + } +} + + OutputVector pool2d (const NodeContext& node) { // TODO : resolve padding according to spec - auto data = node.get_ng_input("X"); + auto data = node.get_ng_input("X"); + auto pooling_type = node.get_attribute("pooling_type"); auto global_pooling = node.get_attribute("global_pooling"); auto adaptive = node.get_attribute("adaptive"); - auto kernel_shape = node.get_attribute>("ksize"); - if (pooling_type == "max" && !global_pooling) { + auto kernel_shape = node.get_attribute>("ksize"); // FIXME: int/list? + + auto rounding_type = node.get_attribute("ceil_mode") + ? ngraph::op::RoundingType::CEIL + : ngraph::op::RoundingType::FLOOR; + + MY_ASSERT((pooling_type == "max") || (pooling_type == "avg"), + "pool2d: not supported pooling type !"); + MY_ASSERT(kernel_shape.size()==1 || kernel_shape.size()==2, + "pool2d: ksize must be 1 or 2!"); + + PartialShape input_shape = data.get_partial_shape(); + MY_ASSERT(input_shape.rank().is_static(), "pool2d: X rank must be static!"); + int32_t input_rank = input_shape.rank().get_length(); + uint64_t input_h = input_shape[input_rank-2].get_length(); + uint64_t input_w = input_shape[input_rank-1].get_length(); + std::cout << input_rank << "," << input_h << "," << input_w << std::endl; + + auto auto_pad = ngraph::op::PadType::EXPLICIT; + ngraph::Shape pad_begin, pad_end; + get_paddings(node, pad_begin, pad_end, auto_pad); + + if (global_pooling || (adaptive && + std::any_of(kernel_shape.begin(), + kernel_shape.end(), + [](int32_t i){return i==1;}))) { + if (pooling_type == "max") { + return {std::make_shared( + data, + ngraph::Strides({1,1}), + ngraph::Shape{0,0}, //FIXME pads_begin + ngraph::Shape{0,0}, //pads_end + ngraph::Shape{input_h,input_w})}; + } else { + // TODO : resolve axes according to rank + auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {2, 3}); + return {std::make_shared(data, axes, true)}; + } + } else if (adaptive) { + uint64_t pool_size_Height, pool_size_Width; + if (kernel_shape.size()==1) { + pool_size_Height = pool_size_Width = kernel_shape[0]; + } else { + pool_size_Height = kernel_shape[0]; + pool_size_Width = kernel_shape[1]; + } + + uint64_t stride_h = int64_t(input_h / pool_size_Height); + uint64_t stride_w = int64_t(input_h / pool_size_Width); + uint64_t kernel_h = input_h - (pool_size_Height - 1) * stride_h; + uint64_t kernel_w = input_w - (pool_size_Width - 1) * stride_w; + + if ( stride_h < 1 || stride_w < 1) { // upsampling? + throw std::runtime_error("Unsupported pooling adaptive type!"); + } + + if (pooling_type == "max") { + return {std::make_shared( + data, + ngraph::Strides{stride_h, stride_w}, + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + rounding_type, + auto_pad)}; + } else { + bool exclude_pad = node.get_attribute("exclusive") ? true : false; + return {std::make_shared( + data, + ngraph::Strides{stride_h, stride_w}, + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + exclude_pad, + rounding_type, + auto_pad)}; + } + } else { auto strides = node.get_attribute>("strides"); auto paddings = node.get_attribute>("paddings"); - auto rounding_type = node.get_attribute("ceil_mode") - ? ngraph::op::RoundingType::CEIL - : ngraph::op::RoundingType::FLOOR; - return {std::make_shared( - data, - ngraph::Strides(strides.begin(), strides.end()), - ngraph::Shape(paddings.begin(), paddings.end()), - ngraph::Shape(paddings.begin(), paddings.end()), - ngraph::Shape(kernel_shape.begin(), kernel_shape.end()), - rounding_type)}; - } - else if (pooling_type == "avg" && - (global_pooling || adaptive && all_of(kernel_shape.begin(), - kernel_shape.end(), - [](int32_t s) { return s == 1; }))) - { - // TODO : resolve axes according to rank - auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {2, 3}); - return {std::make_shared(data, axes, true)}; - } else { - throw std::runtime_error("Unsupported pooling type"); - } + + uint64_t kernel_h, kernel_w; + if (kernel_shape.size() == 1) { + kernel_h = kernel_w = kernel_shape[0]; + } else { + kernel_h = kernel_shape[0]; + kernel_w = kernel_shape[1]; + } + + if ((input_h > 0) && + (input_h+paddings[0] < kernel_h)) { + kernel_h = input_h+paddings[0]; + } + if ((input_w > 0) && + (input_w+paddings[1] < kernel_w)) { + kernel_w = input_w+paddings[1]; + } + + if (pooling_type == "max") { + return {std::make_shared( + data, + ngraph::Strides(strides.begin(), strides.end()), + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + rounding_type, + auto_pad)}; + } else { + bool exclude_pad = node.get_attribute("exclusive") ? true : false; + return {std::make_shared( + data, + ngraph::Strides(strides.begin(), strides.end()), + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + exclude_pad, + rounding_type, + auto_pad)}; + } + } } }}}} \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 0de80c0c80e75e..746b02e14d1197 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -50,7 +50,7 @@ def main(): 'kernel_size': [3, 3], 'type': 'max', 'stride': 1, - 'pool_padding': 0 + 'pool_padding': 1 } pool2d("maxPool", data, pdpd_max_attrs) diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 669b078daea9c8..0d072ba5724c06 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -28,8 +28,10 @@ static pool2dTestParam maxPool() { .get_vector()); // (1, 1, 2, 2) - res.expected_outputs.emplace_back(test::NDArray({{{{{11.0, 12.0 }, - {15.0, 16.0 }}}}}) + res.expected_outputs.emplace_back(test::NDArray({{{{{6.0, 7.0, 8.0, 8.0 }, + {10.0, 11.0, 12.0, 12.0 }, + {14.0, 15.0, 16.0, 16.0 }, + {14.0, 15.0, 16.0, 16.0 }}}}}) .get_vector()); return res; From 96163397d054406c2dfa8431d2824cb2ee256828 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 15 Apr 2021 23:04:17 +0800 Subject: [PATCH 09/54] pool2d with various attributes. --- .../frontend/paddlepaddle/src/op/pool2d.cpp | 12 +- .../gen_scripts/generate_pool2d.py | 198 +++++--- .../paddlepaddle/gen_scripts/save_model.py | 8 +- .../test/frontend/paddlepaddle/op/pool2d.cpp | 445 +++++++++++++++--- 4 files changed, 507 insertions(+), 156 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp index 412c84d3146610..adf417e781fde8 100644 --- a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp @@ -37,13 +37,11 @@ static void get_paddings(const NodeContext& node, ngraph::Shape& pad_begin, ngra throw std::runtime_error("Unsupported pooling padding_algorithm " + pad_algo); } - /*如果它是一个元组或列表,它可以有3种格式: - (1)包含2个整数值:[pad_height, pad_width]; - (2)包含4个整数值:[pad_height_top, pad_height_bottom, pad_width_left, pad_width_right]; - (3)包含4个二元组: - 当 data_format 为"NCHW"时为 [[0,0], [0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right]], - 当 data_format 为"NHWC"时为[[0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right], [0,0]]。 - 若为一个整数,则表示H和W维度上均为该值。默认值:0。*/ + /*If pool padding size is a tuple or list, it could be in three forms: + [pad_height, pad_width] or [pad_height_top, pad_height_bottom, pad_width_left, pad_width_right], + and when data_format is “NCHW”, pool_padding can be in the form [[0,0], [0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right]]. + when data_format is “NHWC”, pool_padding can be in the form [[0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right], [0,0]]. + Otherwise, the pool padding size will be a square of an int.*/ auto paddings = node.get_attribute>("paddings"); auto data_format = node.get_attribute("data_format"); diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 746b02e14d1197..680c58078c8338 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -4,81 +4,147 @@ import numpy as np from save_model import saveModel +data_type = 'float32' + def pool2d(name : str, x, attrs : dict): import paddle as pdpd pdpd.enable_static() - exclusive = False - if 'exclusive' in attrs: - exclusive = attrs['exclusive'] - global_pool=False - if 'global_pool' in attrs: - global_pool = attrs['global_pool'] - - node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') - out = pdpd.fluid.layers.pool2d(node_x, pool_size=attrs['kernel_size'], - pool_type=attrs['type'], - pool_stride=attrs['stride'], - pool_padding=attrs['pool_padding'], - global_pooling=global_pool, - exclusive=exclusive) - - 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={'x': x}, - fetch_list=[out]) - - saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=data_type) + out = pdpd.fluid.layers.pool2d(node_x, + pool_size=attrs['pool_size'], + pool_type=attrs['pool_type'], + pool_stride=attrs['pool_stride'], + pool_padding=attrs['pool_padding'], + global_pooling=attrs['global_pooling'], + ceil_mode=attrs['ceil_mode'], + exclusive=attrs['exclusive'], + data_format=attrs['data_format']) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) return outs[0] def main(): - data = np.array([[[ - [1, 2, 3, 4], - [5, 6, 7, 8], - [9, 10, 11, 12], - [13, 14, 15, 16], - ]]]).astype(np.float32) - - # maxPool - pdpd_max_attrs = { - 'kernel_size': [3, 3], - 'type': 'max', - 'stride': 1, - 'pool_padding': 1 - } - pool2d("maxPool", data, pdpd_max_attrs) - - # maxGlobalPool - spatial_shape = np.ndim(data) - pdpd_max_global_attrs = { - 'kernel_size': [spatial_shape, spatial_shape], - 'type': 'max', - 'stride': 1, - 'pool_padding': 0, - 'global_pool': True} - - pool2d("maxGlobalPool", data, pdpd_max_global_attrs) - - # avgPool - pdpd_avg_attrs = {'kernel_size': [3, 3], - 'type': 'avg', - 'stride': 1, - 'pool_padding': 1, - 'exclusive': True} - ng_avg_attrs = { - 'kernel_size': [3, 3], - 'type': 'avg', - 'stride': [1, 1], - 'padding': [1, 1], - 'exclude_pad': True - } - pool2d("avgPool", data, pdpd_avg_attrs) + N, C, H, W = 2, 3, 4, 4 + data = np.arange(N*C*H*W).astype(data_type) + data_NCHW = data.reshape(N, C, H, W) + data_NHWC = data.reshape(N, H, W, C) + #print(data_NCHW, data_NCHW.shape) + + pooling_types = ['max', 'avg'] + + for i, pooling_type in enumerate(pooling_types): + # example 1: + # ceil_mode = False + pdpd_attrs = { + # input=data_NCHW, # shape: [2, 3, 8, 8] + 'pool_size' : [3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding' : [2,1], # it is same as pool_padding = [2,2,1,1] + 'global_pooling' : False, + 'ceil_mode' : False, + 'exclusive' : True, + 'data_format' : "NCHW" + } + # shape of out_1: [2, 3, 4, 3] + pool2d(pooling_type+'Pool_test1', data_NCHW, pdpd_attrs) + + # Cecilia: there is a bug of PaddlePaddle in this case. + # example 2: + # ceil_mode = True (different from example 1) + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':[[0,0], [0,0], [2,2], [1,1]], # it is same as pool_padding = [2,2,1,1] + 'global_pooling':False, + 'ceil_mode':True, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_2: [2, 3, 4, 4] which is different from out_1 + pool2d(pooling_type+'Pool_test2', data_NCHW, pdpd_attrs) + + # example 3: + # pool_padding = "SAME" (different from example 1) + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':"SAME", + 'global_pooling':False, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_3: [2, 3, 3, 3] which is different from out_1 + pool2d(pooling_type+'Pool_test3', data_NCHW, pdpd_attrs) + + # example 4: + # pool_padding = "VALID" (different from example 1) + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':"VALID", + 'global_pooling':False, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_4: [2, 3, 2, 2] which is different from out_1 + pool2d(pooling_type+'Pool_test4', data_NCHW, pdpd_attrs) + + # example 5: + # global_pooling = True (different from example 1) + # It will be set pool_size = [8,8] and pool_padding = [0,0] actually. + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':[2,1], + 'global_pooling':True, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_5: [2, 3, 1, 1] which is different from out_1 + pool2d(pooling_type+'Pool_test5', data_NCHW, pdpd_attrs) + + # example 6: + # data_format = "NHWC" (different from example 1) + pdpd_attrs = { + #input=data_NHWC, # shape: [2, 8, 8, 3] + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':[2,1], + 'global_pooling':False, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NHWC" + } + # shape of out_6: [2, 4, 3, 3] which is different from out_1 + pool2d(pooling_type+'Pool_test6', data_NHWC, pdpd_attrs) + # + if __name__ == "__main__": main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index 23e72f50c44a9f..e01a1eb93e2cc1 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -7,17 +7,15 @@ def print_alike(arr): shape = arr.shape rank = len(shape) - print("shape: ", shape, "rank: %d" %(rank)) + #print("shape: ", shape, "rank: %d" %(rank)) #for idx, value in np.ndenumerate(arr): # print(idx, value) - print(arr) def print_array(arr, end=' '): shape = arr.shape rank = len(arr.shape) if rank > 1: - #print("{") line = "{" for i in range(arr.shape[0]): line += print_array(arr[i,:], end="},\n" if i < arr.shape[0]-1 else "}") @@ -26,7 +24,7 @@ def print_array(arr, end=' '): else: line = "{" for i in range(arr.shape[0]): - line += str(arr[i]) + line += "{:.2f}".format(arr[i]) #str(arr[i]) line += ", " if i < shape[0]-1 else ' ' line += end #print(line) @@ -43,7 +41,7 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) - print_alike(input) + #print_alike(input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 0d072ba5724c06..1d4bb8b141d613 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -10,86 +10,375 @@ using namespace ngraph::frontend; static const std::string PDPD = "pdpd"; static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; -using pool2dTestParam = FrontendOpTestParam; -using pool2dTest = FrontendOpTest; - -static pool2dTestParam maxPool() { - pool2dTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "maxPool"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 1, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, - {5.0, 6.0, 7.0, 8.0 }, - {9.0, 10.0, 11.0, 12.0 }, - {13.0, 14.0, 15.0, 16.0 }}}}} - .get_vector()); - - // (1, 1, 2, 2) - res.expected_outputs.emplace_back(test::NDArray({{{{{6.0, 7.0, 8.0, 8.0 }, - {10.0, 11.0, 12.0, 12.0 }, - {14.0, 15.0, 16.0, 16.0 }, - {14.0, 15.0, 16.0, 16.0 }}}}}) - .get_vector()); - - return res; -} +auto shared_input_NCHW = test::NDArray{{{{{0.0, 1.0, 2.0, 3.0 }, + {4.0, 5.0, 6.0, 7.0 }, + {8.0, 9.0, 10.0, 11.0 }, + {12.0, 13.0, 14.0, 15.0 }}, + {{16.0, 17.0, 18.0, 19.0 }, + {20.0, 21.0, 22.0, 23.0 }, + {24.0, 25.0, 26.0, 27.0 }, + {28.0, 29.0, 30.0, 31.0 }}, + {{32.0, 33.0, 34.0, 35.0 }, + {36.0, 37.0, 38.0, 39.0 }, + {40.0, 41.0, 42.0, 43.0 }, + {44.0, 45.0, 46.0, 47.0 }}}, + {{{48.0, 49.0, 50.0, 51.0 }, + {52.0, 53.0, 54.0, 55.0 }, + {56.0, 57.0, 58.0, 59.0 }, + {60.0, 61.0, 62.0, 63.0 }}, + {{64.0, 65.0, 66.0, 67.0 }, + {68.0, 69.0, 70.0, 71.0 }, + {72.0, 73.0, 74.0, 75.0 }, + {76.0, 77.0, 78.0, 79.0 }}, + {{80.0, 81.0, 82.0, 83.0 }, + {84.0, 85.0, 86.0, 87.0 }, + {88.0, 89.0, 90.0, 91.0 }, + {92.0, 93.0, 94.0, 95.0 }}}}} + .get_vector(); -static pool2dTestParam avgPool() { - pool2dTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "avgPool"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 1, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, - {5.0, 6.0, 7.0, 8.0 }, - {9.0, 10.0, 11.0, 12.0 }, - {13.0, 14.0, 15.0, 16.0 }}}}} - .get_vector()); - - // (1, 1, 4, 4) - res.expected_outputs.emplace_back(test::NDArray({{{{{3.5, 4.0, 5.0, 5.5 }, - {5.5, 6.0, 7.0, 7.5 }, - {9.5, 10.0, 11.0, 11.5 }, - {11.5, 12.0, 13.0, 13.5 }}}}}) - .get_vector()); - - return res; -} +auto shared_input_NHWC = test::NDArray{{{{{0.0, 1.0, 2.0 }, + {3.0, 4.0, 5.0 }, + {6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0 }}, + {{12.0, 13.0, 14.0 }, + {15.0, 16.0, 17.0 }, + {18.0, 19.0, 20.0 }, + {21.0, 22.0, 23.0 }}, + {{24.0, 25.0, 26.0 }, + {27.0, 28.0, 29.0 }, + {30.0, 31.0, 32.0 }, + {33.0, 34.0, 35.0 }}, + {{36.0, 37.0, 38.0 }, + {39.0, 40.0, 41.0 }, + {42.0, 43.0, 44.0 }, + {45.0, 46.0, 47.0 }}}, + {{{48.0, 49.0, 50.0 }, + {51.0, 52.0, 53.0 }, + {54.0, 55.0, 56.0 }, + {57.0, 58.0, 59.0 }}, + {{60.0, 61.0, 62.0 }, + {63.0, 64.0, 65.0 }, + {66.0, 67.0, 68.0 }, + {69.0, 70.0, 71.0 }}, + {{72.0, 73.0, 74.0 }, + {75.0, 76.0, 77.0 }, + {78.0, 79.0, 80.0 }, + {81.0, 82.0, 83.0 }}, + {{84.0, 85.0, 86.0 }, + {87.0, 88.0, 89.0 }, + {90.0, 91.0, 92.0 }, + {93.0, 94.0, 95.0 }}}}} + .get_vector(); -static pool2dTestParam maxGlobalPool() { - pool2dTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "maxGlobalPool"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 1, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, - {5.0, 6.0, 7.0, 8.0 }, - {9.0, 10.0, 11.0, 12.0 }, - {13.0, 14.0, 15.0, 16.0 }}}}} - .get_vector()); - - // (1, 1, 1, 1) - res.expected_outputs.emplace_back(test::NDArray({{{{{16.0 }}}}}) - .get_vector()); - - return res; -} +/* maxPool2D */ +namespace maxPool2D { + + using maxPool2DTestParam = FrontendOpTestParam; + using maxPool2DTest = FrontendOpTest; + + static maxPool2DTestParam maxPool_test1() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test1"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{1.0, 3.0 }, + {13.0, 15.0 }}, + {{17.0, 19.0 }, + {29.0, 31.0 }}, + {{33.0, 35.0 }, + {45.0, 47.0 }}}, + {{{49.0, 51.0 }, + {61.0, 63.0 }}, + {{65.0, 67.0 }, + {77.0, 79.0 }}, + {{81.0, 83.0 }, + {93.0, 95.0 }}}}}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test2() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test2"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test3() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test3"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{5.00, 7.00 }, + {13.00, 15.00 }}, + {{21.00, 23.00 }, + {29.00, 31.00 }}, + {{37.00, 39.00 }, + {45.00, 47.00 }}}, + {{{53.00, 55.00 }, + {61.00, 63.00 }}, + {{69.00, 71.00 }, + {77.00, 79.00 }}, + {{85.00, 87.00 }, + {93.00, 95.00 }}}}}) + .get_vector()); -TEST_P(pool2dTest, test_pool2d) { - validateOp(); + return res; + } + static maxPool2DTestParam maxPool_test4() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test4"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{10.00 }}, + {{26.00 }}, + {{42.00 }}}, + {{{58.00 }}, + {{74.00 }}, + {{90.00 }}}}}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test5() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test5"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{15.00 }}, + {{31.00 }}, + {{47.00 }}}, + {{{63.00 }}, + {{79.00 }}, + {{95.00 }}}}}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test6() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test6"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NHWC); + + // (2, 2, 2, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{{3.00, 4.00, 5.00 }, + {9.00, 10.00, 11.00 }}, + {{39.00, 40.00, 41.00 }, + {45.00, 46.00, 47.00 }}}, + {{{51.00, 52.00, 53.00 }, + {57.00, 58.00, 59.00 }}, + {{87.00, 88.00, 89.00 }, + {93.00, 94.00, 95.00 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(maxPool2DTest, test_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, maxPool2DTest, + ::testing::Values( + maxPool_test1(), + //maxPool_test2(), + maxPool_test3(), + maxPool_test4(), + maxPool_test5(), + maxPool_test6() + ), + maxPool2DTest::getTestCaseName); } -INSTANTIATE_TEST_CASE_P(FrontendOpTest, pool2dTest, - ::testing::Values( - avgPool(), - maxPool(), - maxGlobalPool() - ), - pool2dTest::getTestCaseName); +/* avgPool2D */ +namespace avgPool2D { + using avgPool2DTestParam = FrontendOpTestParam; + using avgPool2DTest = FrontendOpTest; + + static avgPool2DTestParam avgPool_test1() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test1"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{0.50, 2.50 }, + {8.50, 10.50 }}, + {{16.50, 18.50 }, + {24.50, 26.50 }}, + {{32.50, 34.50 }, + {40.50, 42.50 }}}, + {{{48.50, 50.50 }, + {56.50, 58.50 }}, + {{64.50, 66.50 }, + {72.50, 74.50 }}, + {{80.50, 82.50 }, + {88.50, 90.50 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test2() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test2"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (1, 1, 4, 4) + res.expected_outputs.emplace_back(test::NDArray({{{{{7.5 }}, + {{23.5 }}, + {{39.5 }}}, + {{{55.5 }}, + {{71.5 }}, + {{87.5 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test3() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test3"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{2.50, 4.50 }, + {10.50, 12.50 }}, + {{18.50, 20.50 }, + {26.50, 28.50 }}, + {{34.50, 36.50 }, + {42.50, 44.50 }}}, + {{{50.50, 52.50 }, + {58.50, 60.50 }}, + {{66.50, 68.50 }, + {74.50, 76.50 }}, + {{82.50, 84.50 }, + {90.50, 92.50 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test4() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test4"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{5.00 }}, + {{21.00 }}, + {{37.00 }}}, + {{{53.00 }}, + {{69.00 }}, + {{85.00 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test5() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test5"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{7.5 }}, + {{23.5 }}, + {{39.5 }}}, + {{{55.5 }}, + {{71.5 }}, + {{87.5 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test6() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test6"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NHWC); + + // (2, 2, 2, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{{1.5, 2.5, 3.5 }, + {7.5, 8.5, 9.5 }}, + {{25.5, 26.5, 27.5 }, + {31.5, 32.5, 33.5 }}}, + {{{49.5, 50.5, 51.5 }, + {55.5, 56.5, 57.5 }}, + {{73.5, 74.5, 75.5 }, + {79.5, 80.5, 81.5 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(avgPool2DTest, test_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, avgPool2DTest, + ::testing::Values( + avgPool_test1(), + //avgPool_test2(), + avgPool_test3(), + avgPool_test4(), + avgPool_test5(), + avgPool_test6() + ), + avgPool2DTest::getTestCaseName); +} \ No newline at end of file From 6ad796d3910f1f526f4b5cd2ef069466ebea21fd Mon Sep 17 00:00:00 2001 From: jialipen Date: Fri, 16 Apr 2021 00:27:08 +0800 Subject: [PATCH 10/54] validate pool2d and adpative_pool2d. all attr pass, except layout NHWC. --- .../frontend/paddlepaddle/src/op/pool2d.cpp | 9 +- ngraph/frontend/paddlepaddle/src/op_table.cpp | 1 + .../paddlepaddle/gen_scripts/save_model.py | 2 +- .../test/frontend/paddlepaddle/op/pool2d.cpp | 100 +++++++++++++++++- 4 files changed, 108 insertions(+), 4 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp index adf417e781fde8..a1a7852c141ef2 100644 --- a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp @@ -30,7 +30,8 @@ static void get_paddings(const NodeContext& node, ngraph::Shape& pad_begin, ngra auto_pad = ngraph::op::PadType::SAME_UPPER; } else if (pad_algo == "VALID") { auto_pad = ngraph::op::PadType::VALID; - } else if (pad_algo == "EXPLICIT") { + } else if ((pad_algo == "EXPLICIT") || + pad_algo.empty()) { //adaptive_maxpool with no such attr. auto_pad = ngraph::op::PadType::EXPLICIT; }else { // FIXME @@ -90,6 +91,10 @@ OutputVector pool2d (const NodeContext& node) { ? ngraph::op::RoundingType::CEIL : ngraph::op::RoundingType::FLOOR; + if (pooling_type.empty()) { // TODO: to check op.type "max_pool2d_with_index" + pooling_type = "max"; + } + MY_ASSERT((pooling_type == "max") || (pooling_type == "avg"), "pool2d: not supported pooling type !"); MY_ASSERT(kernel_shape.size()==1 || kernel_shape.size()==2, @@ -119,7 +124,7 @@ OutputVector pool2d (const NodeContext& node) { ngraph::Shape{input_h,input_w})}; } else { // TODO : resolve axes according to rank - auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {2, 3}); + auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {input_rank-2, input_rank-1}); return {std::make_shared(data, axes, true)}; } } else if (adaptive) { diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index a35743e2eab4d4..fc3ff50dca9115 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -59,6 +59,7 @@ std::map get_supported_ops() { {"nearest_interp_v2", op::nearest_interp_v2}, {"concat", op::concat}, {"cast", op::cast}, + {"max_pool2d_with_index", op::pool2d}, //adaptive_max_pool2d {"softmax", op::softmax} }; }; diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index e01a1eb93e2cc1..0f5f596115f3ab 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -41,7 +41,7 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) - #print_alike(input) + print_alike(input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 1d4bb8b141d613..96cdbfccca2505 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -381,4 +381,102 @@ namespace avgPool2D { avgPool_test6() ), avgPool2DTest::getTestCaseName); -} \ No newline at end of file +} + +/* maxAaptivePool2D */ +namespace maxAaptivePool2D { + using maxAaptivePool2DTestParam = FrontendOpTestParam; + using maxAaptivePool2DTest = FrontendOpTest; + + static maxAaptivePool2DTestParam maxAdaptivePool_test1() { + maxAaptivePool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxAdaptivePool2D_test1"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{5.00, 6.00, 7.00 }, + {9.00, 10.00, 11.00 }, + {13.00, 14.00, 15.00 }}, + {{21.00, 22.00, 23.00 }, + {25.00, 26.00, 27.00 }, + {29.00, 30.00, 31.00 }}, + {{37.00, 38.00, 39.00 }, + {41.00, 42.00, 43.00 }, + {45.00, 46.00, 47.00 }}}, + {{{53.00, 54.00, 55.00 }, + {57.00, 58.00, 59.00 }, + {61.00, 62.00, 63.00 }}, + {{69.00, 70.00, 71.00 }, + {73.00, 74.00, 75.00 }, + {77.00, 78.00, 79.00 }}, + {{85.00, 86.00, 87.00 }, + {89.00, 90.00, 91.00 }, + {93.00, 94.00, 95.00 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(maxAaptivePool2DTest, test_adaptive_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, maxAaptivePool2DTest, + ::testing::Values( + maxAdaptivePool_test1() + ), + maxAaptivePool2DTest::getTestCaseName); +} + +/* avgAaptivePool2D */ +namespace avgAaptivePool2D { + using avgAaptivePool2DTestParam = FrontendOpTestParam; + using avgAaptivePool2DTest = FrontendOpTest; + + static avgAaptivePool2DTestParam avgAdaptivePool_test1() { + avgAaptivePool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgAdaptivePool2D_test1"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{2.50, 3.50, 4.50 }, + {6.50, 7.50, 8.50 }, + {10.50, 11.50, 12.50 }}, + {{18.50, 19.50, 20.50 }, + {22.50, 23.50, 24.50 }, + {26.50, 27.50, 28.50 }}, + {{34.50, 35.50, 36.50 }, + {38.50, 39.50, 40.50 }, + {42.50, 43.50, 44.50 }}}, + {{{50.50, 51.50, 52.50 }, + {54.50, 55.50, 56.50 }, + {58.50, 59.50, 60.50 }}, + {{66.50, 67.50, 68.50 }, + {70.50, 71.50, 72.50 }, + {74.50, 75.50, 76.50 }}, + {{82.50, 83.50, 84.50 }, + {86.50, 87.50, 88.50 }, + {90.50, 91.50, 92.50 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(avgAaptivePool2DTest, test_adaptive_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, avgAaptivePool2DTest, + ::testing::Values( + avgAdaptivePool_test1() + ), + avgAaptivePool2DTest::getTestCaseName); +} From eb8caeb1faf4b7fde0f54e980f9d34a84363c06b Mon Sep 17 00:00:00 2001 From: bai Date: Fri, 16 Apr 2021 16:16:42 +0800 Subject: [PATCH 11/54] add softmax & relu --- .../paddlepaddle/gen_scripts/generate_relu.py | 36 +++++++++++++ .../gen_scripts/generate_softmax.py | 43 +++++++++++++++ .../files/paddlepaddle/models/relu/__model__ | Bin 0 -> 9517 bytes .../paddlepaddle/models/relu/relu.pdmodel | Bin 0 -> 9721 bytes .../paddlepaddle/models/softmax/__model__ | Bin 0 -> 9714 bytes .../models/softmax/softmax.pdmodel | Bin 0 -> 9918 bytes ngraph/test/frontend/paddlepaddle/op/relu.cpp | 41 ++++++++++++++ .../test/frontend/paddlepaddle/op/softmax.cpp | 51 ++++++++++++++++++ .../frontend/paddlepaddle/op/squeeze2.cpp | 48 +++++++++++++++++ 9 files changed, 219 insertions(+) create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_relu.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_softmax.py create mode 100644 ngraph/test/files/paddlepaddle/models/relu/__model__ create mode 100644 ngraph/test/files/paddlepaddle/models/relu/relu.pdmodel create mode 100644 ngraph/test/files/paddlepaddle/models/softmax/__model__ create mode 100644 ngraph/test/files/paddlepaddle/models/softmax/softmax.pdmodel create mode 100644 ngraph/test/frontend/paddlepaddle/op/relu.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/softmax.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_relu.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_relu.py new file mode 100644 index 00000000000000..e269ebe204707a --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_relu.py @@ -0,0 +1,36 @@ +# +# relu paddle model generator +# +import numpy as np +from save_model import saveModel + + +def relu(name: str, x): + import paddle as pdpd + pdpd.enable_static() + + node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') + out = pdpd.nn.functional.relu(node_x) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + + +def main(): + data = np.array([-2, 0, 1]).astype('float32') + + relu("relu", data) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_softmax.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_softmax.py new file mode 100644 index 00000000000000..f127625ba23d17 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_softmax.py @@ -0,0 +1,43 @@ +# +# softmax paddle model generator +# +import numpy as np +from save_model import saveModel + + +def softmax(name: str, x, axis): + import paddle as pdpd + pdpd.enable_static() + + node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') + out = pdpd.nn.functional.softmax(x=node_x, axis=axis) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + + +def main(): + data = np.array( + [[[2.0, 3.0, 4.0, 5.0], + [3.0, 4.0, 5.0, 6.0], + [7.0, 8.0, 8.0, 9.0]], + [[1.0, 2.0, 3.0, 4.0], + [5.0, 6.0, 7.0, 8.0], + [6.0, 7.0, 8.0, 9.0]]] + ).astype(np.float32) + + softmax("softmax", data, axis=1) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/models/relu/__model__ b/ngraph/test/files/paddlepaddle/models/relu/__model__ new file mode 100644 index 0000000000000000000000000000000000000000..f2a22621a4619b6a03b9733b46ee59944c70f45d GIT binary patch literal 9517 zcmeHNZExGg9k(1iwJ%PhI87I5KtO0MEIA%&SIv`G3$S-8_c*pzwAMgJ_^4Fhj ztyTX!{j1b&lFfwcsJFYmMebK>J7go_JjUHN?(UJwXm@Apt=bmZ*xIaKtFGN&^D4Cm zWT)V1Ne_KJ$m!wYjM^c2pxBU8AroHEK^F5gP!UV{i&oVCRwdh{@?_U-zD2HmRO;Qz zsAli$x5;*v)0huM#H;K3YZ$nJfg-~jhpeb>*8g#v>|g|Yq)M}>U)>CU=Xt*nDfj9@ zFB|Zn!vr0d11`J4X;$=w?8c%9vYgAIkXazR10Tah!7Z8+5s(Dk?;- zmAU2x)0`R}`1!bg;H5%xul=I~Pe|{_ptnrnC-)N3=jjh zQ8&N98#B#b1E`~83(9~9pBPX^OMY$CqaoRVA9#F(AESSLK2|4B_eOiq%stdI6-u8x z%}R{{A@fq>@d(!#aW}Y7PY<6xYlhEX6|b#MTWy|``lGg`>70`A6GK=Y=dquprHFlz z`7>kSGUCo48g<_f?8{V8f9S}cQa(qsGcg2ujq?ND0+!Y{4>c~U^h zjq|y{Zf6tckPYG~&zD2}`U;>zX=jeD)qdZ3lVy4w9vi@U!Qn|`YBZQ;xoQ~4L-Qho zTOBx)#sm0jYBXIn!#`a)5v|9Mt#T|v4euEOnAU|lIope}bnin?Ja2|yT>-*n8qsdG zoJ#@w98NkcA02>Nm+-lhfYb{)dq3 zCRRXba@Pe47ow5chCSpig$PS``ShI}p#3zK zvU>evlT0mSR}20Y&&`UcoG$qKF1bl=d}0#1-*Tz4g4{9w_<|SSeb2e(mn4F=T%Vkf(-Uj26`#bxk)6%CpZ1%WBCkTT zRcN*f&AyGLbyrcDMO-sI4%;TMnbak07i?*19o@0lTv`9X^)MEZzNoUkD)qSb+l91f zSr~P-b@h#{KYaPw{#S$`PLY|W{L_-9_z<8%ZjjB{%`VyL799QWg6bZVb^?k@Xql_I zCEq9a&imwO1Lc`wsiMOpJN*H*OA}%~OtEy*?GFJfRV9 zmn{s(VrYkJJ>uv?GOrVLZUxny2TO+mmP#yER)Z< zzC*4f6&p-;Mb!?CAv&c554%kFcwyHn(o+TrBZ@P3S4pKD7Pvnz#)dV?u??8v;NqAg)!Z5fG<6yF5M~sP+6k$v{d#v z_*Z0tvQ%`9RId@l*Mc&qz(O-I&oU#=b>fklc@a2EPlfK$sK|`2OAWmq+gF2` zctf8em&7pGY)2vRBo(>6o=Rt;P!KS_GD#`+H)1yYUMCowTGq_mAjeXQPfN$d2B{~k zk76t=Px2IaU>{RyP}WiB^2f_^F~StpE0ZL3%ki?P9H;re2xKpuH%A`(*dB|FB$w sG!{2rke{K_%GCmz+_jy_LMG8vCV&e2Da44%fg=i%$7c>v>dayNf3y*10{{R3 literal 0 HcmV?d00001 diff --git a/ngraph/test/files/paddlepaddle/models/relu/relu.pdmodel b/ngraph/test/files/paddlepaddle/models/relu/relu.pdmodel new file mode 100644 index 0000000000000000000000000000000000000000..bb10873039531da8df27663e7bed4c64e589a76e GIT binary patch literal 9721 zcmeHNZ*Lp78MhoewHYT-oTdvjAUNDwSaLj_WjRY)%o}zCw!P^(V0#fD2ngzqClNaF zu1B6M)d*G$*q?OU+kLKmhrJ&50S0vYk(4Z1)(~_>oOF|4$VVP|eE#$IJS6$skG9sT z|C;_)YB$Md!gbW!UEd=2E43Z6k#HWPwT;$2QW@>;Y`s(4A{$$q)oazY`)gjM_JHgZ zJT2*AQx9@_xHzJANFFFQ{_le2ZNBq}02W zQO&mf+hjY-Y0QTr;??#2HFVrSN0H%+LsnEb{V#8m9rR$0RB0CVtDE7kJ?|$X<(?n( zvH=e|Owe&T;IbQ>W<_7fZY+u*%efp1nFX?2u)G&&u5^%KnhJ6j$0>KeL6=LaqC(_a znP*-w&8d+=Gavg0UMeK_+TT0yg!H}-e#?~qAS53C2299$BRsouVvZ~^X8G_vLx>@^ z?weoG8#B$`08vNBmMB9+_|y<(tmI>39(BnE{J`TQ{22S|^RYU4wl~^)ZrU)1Ek)cE zS##zMTt?h^MBQ&T1N$`<_zxZbQ`YC0o(RPbq{cGM$P@GP&~N6k?T1ElR{;9FpW|!-_ zZ>dHE`FSRJqY?i84Uv4*I&`vy6-%Mvcn=M|Nmh84L$kFaTtvKs$kVi;Bhu7v_Vva` z{$0EOTf>O3sRJcc0)LxagDwnc@o$oMCWyf{za-?k!5e@#cOBTcfM{wPcB8xmGnTIM zkL?xqxCn&aM(iR(Fsxm@OPI zP%vbMin+k~sO>!268u(AnNo#GuiO8A3YS z`=r$91K)^DFJCKPZkJ8j81R2W?rbYKb_|`0nzWq*Q>h{WO-cdi@tBAzR4M7UC`5n;B6#o$%MY z&{6xFkONLiWJ`0vCk6!|yF2h&%>&O?IsDnc3suCk7k(3o!GP(yK+5vl ztHLrW08*R*nO5ug_(Pj!*$pWCvEjghG21aiV-A!p$6^PQywT=iD_}NPjQ#pv(f&UJ zW=r$aOIhqCuy%_$2vx0ou(tO350NZybOckjxwhuNN2;btS)zgGt!V@FRTgvVmv_i_ z42F9JT-)7osLmZb)ZD+z0P+&m|6G;$k>SmSpZ43BX0PDg3f`?s{0pawUw@#Y#VSisgKwby`?37obG(ox2`u@h& zZ(e@3{{ml`VM2HBi7P%-Kj9B26j)jcNd02H@y{IBMwe4E@mKl8_N zRGul8Dmpx}!yl0QG0vt7(J65yAj$2Cl^cTh>*OA}%~Oth2l`Z?0)|TkcG^OBEQYqb zM&6wtoupY-Oy7Nr+(FVq^KnO@?rUx;P>M+#i%SgHXxS12;rLrv83)KqN0&}q3#0Sw z)Q%=(gT-txeNNe+W1sJk8$DLURP_oW`?d>(J|S^VV~QRUNt^A2TC9-IrM^S1Bb^&e zRz>v?2UK**30`)Y?(xFTg@Te&p-N7>MQMB9CAXqX4k^xuq=M|Z?S-auP@!!Dd_b1{ zGN+n#%(W4xy<21pmLawH%+0~DC__zBfmm(pl6E$R;fjaCq4)W)c{QohagP=45!H0X zE-RH1Oj6JlXO44gasm=!I9{G{lycS|+Z!d*1qZmbB6aCzfdG{yI!{Yw-$Q;yCMZiq z*J$+`0Y*0>ID%nZ5CSHefq9l0eXbLa)Xaw@n0)jxyrIwk6?UVN}e?2y|SZ$kcn>8#$ z5MIo4-Ln)pG1`7unypwkMs9IzTBsXajAiW4+7=z*NkQ{J1 zyV;qg$QUk~06ipV`yzdgK0$$^7wtt~p)b&WGsBZ9x`qQ-u2JfO+L@i%{r=s#b@sj^Ep+MLH2ZDaIZQX1}+x2|A%YiqN-UcOY`D6idK z^GcNy@`hpqPK9jqoc7b0CxMDs!s$_6_cMC5Y+vOLxvtW-?z7>4Tju|{Otwksvpt7p zi(LA+(0ip}#g6^!WIN4h%m*Uk<@JL#OzdDHPx0~r%gdYoU$2v0%m7ZJG>dxW&G4&| z=Y1d&?)gDC?en0;1RWK9E<3?ln)ih4#3B#UjLU(LX&^f}%esN)N(XIhQ$fb!IN|O$ z=x|9@l#5I&bIo(6IUQ40&qn^Cmk7zdljfl(r1vARr%3pZL*n7D&xEYj!e71wJk9$S zk3kT=Ww4APSN-t?fX7U;LyrxGI&IX#FJA`Rj!!JiF{bb{ixkTCGoxiy$@=`z<3s!y zRqgSSI(@J|+<$1s(BwoYefl6RG$w@13XR)CTw}%!aG@R?J$zUTAHOIWSktgZF{cf0 zJ8dxcEG6NmhOjKo;(9wNL|hkXeP&Z!M%>v|)vwnB`!E&wcOCf?%I9ddJgJ5H+t4(C z+6Ref1=&bqJDyiD z9UXcHRX)@?Q{G*VKp-+eTIVSfr0H%TLQx0TmbTR4kb5!=?Qi_vzS6Qh$lQ>4)ymJ02N9*b9jyByT{IU zr)R@VkHZrKILkSlY)p*?(==06ezZCe}8uu^{B{mE;Vf>Y1FIM>eGGa&)AFb`Aa?O(Xn$+Q*8f-{`3c= z-0vmOG-`4Isz=t*UTG&O)6L^W9}AZ&6g7!b`SK^F^T`<@8^*5SkIl`6M6FDS(Pj5K z>^HgG_Efv=11n_5!oU&HXBr-V`+Yh3h>c*}{-0hWSIN$&ChhzMmnzN4P2=tto&4S% z=lq|Mu~s&10_*?n#_A+^g-?Q2_K1qiEb3lmkJD<-DtnaP|91A+eCO%e>FZjP0Ib7)u~L+(f1Q-gkg~Q$nqXDihHeYl_&>|!O%t9yBMjTyb(SO$2at+~G`Vlrw z&@(Ql*#6woqCfg}FS+J_-*s0Okv^^Fzp7BV#^4hTw`C#L#a8?`w!ZrMi-T_nK@1~P zP5I{qOYk*AiR_Tg*X&{&PA)hvD?mU56dmV{dIDST;~bL2L}2~pu~l*2kf?m=~xWxbcNiUUyWK@nosV1 zhulCiL$gs!pv-D2ZIoiu#^NjRRmHMb^o65u;mv3$FI`$ipaZ<@6&cm6Wj+vb(z`~s zpczt&FWeq1i&B&k6~Jm+O0>JN3?FhRw85v#=EbB6M?KzXn^u!Ic37d5V3Gn?oI1*_ z$_a3Yq2WBEDB-L(qB&0-MR;K!pQlJ&xLp{VW<{11%03+Y%TqyFB05H@mk45S!-8Wd z#uH4yMzb(WQzOrH;*rX@>p{rP`uxW+3=bs)MELPg)+2$RVATTfHneJKyj*WI6 znr2%q6rT?{IlvX5$Cz+5BNt7*G?77bQ3kik-g*CFxddq}zIZ`?hDs|}3uruQI+KM= bqKQlZ750;hA(eec6eN!iFrvhn!}@;!kg28F literal 0 HcmV?d00001 diff --git a/ngraph/test/files/paddlepaddle/models/softmax/softmax.pdmodel b/ngraph/test/files/paddlepaddle/models/softmax/softmax.pdmodel new file mode 100644 index 0000000000000000000000000000000000000000..1800a07e06c987508b4a1f3460f21e316a396a73 GIT binary patch literal 9918 zcmeHN?Qa`N8IRMXO(uPDbL~+KoL0+KvD4s<;~Z^I1jL?nd;ty#KAcolqw((89(g^x zw=i+dAe&vTqyFyt7P(icT_+n|&SQ+WG5R{GjCQMA*D$@cwOL)SUa4+W*Y2%( zmD(|RN3l~*h3xX24%3(?fr?nd>0wh3Gum3VuXdl@QfXHY*{EE0xNMpK;x^ePm5+BF zEnDQuM}^+4jB0l5-y+*-Mq_>|B3@nJU&F)>Ch`<7KV^A!)BkIgT*nN^Nt9;Mpt>1; zR`I+KMZ!Hl=%+&-beN#yV#sALI7{<^kiA&sL7H)SDr6eSUe2<9pt;gP7u!^ju{ch+ z`wedE2Lr;YIW>(YUB4eJzh z*6?1*)`XMr&k(NXWpNfayGbG9rbwGJr{Xf=&avu#vl-Z@slb2W_@A&o$8;$ayO0{A zH7ifd&jY`i#daPF&REWdYRLlO?)ZℜK))!gYc~bb@TG`>AX<9|lTj{+$dC$a?Ug zm`5obCC%q#a@1~FU3Uu^21Xh=*F`Qp&wU_UnA4bEdop9?N^GftmfmStI=8 zmom;*(pmbrRY`D$IFRue;bsZ(?^)U@6~io{G_21tFxh7~sP7xH9o3eB@V6I0c^7Kt zCbqpKZfAp2k`2WZnJ*{x4;Mfx?0yzBTkS_j&i|+9%ghzRV?%J3a|G&`8YiG>rs^i5 z(JW69wTCV&;0DeDYOG&1!rxyw6Rn32Efb5RhIb7EOzT{oJll)XWbb`XJa2@bUjT*6 zETY|NxkC!#b3#oscQ!a02WQ4&n?0`UzMVk?`DrS7qY?h@4Uv4*I&`vy6-%Mvcn^$B zyJ_xO4$YB^a1rqiB2UwXj!07r1nQ0V{kJSOu!a%gya$4)1pYR;0$mtv;7HaR{2y}iO6%W%*o!5yV1OmN3zV^shP-ibS-rEHoIsYNPT z(kxfiM<)`ngpNwgWPnp6{L^c74Jm^eAprwLr_4|_7epVo4qXg&XgmC-;bpH-oJK_~ zC4$cM8o}qqYbDnmqzM}%QRwp|4A7OQR;Apn7Zr?X_-_GTlB}jIjv0 zLQ#`!Rj>Z6az4Q$WW)Fs;<358knB|nF}Cbphy5lW+@4yuePE63STb-#44Fp6-~OQ- z|Co*8-2T7bA~(p+&rRz33occflRGBdF9!MD`!4vuBI~Vf+9cTj+wSTlxWp&HDg!lT zof+(2WuU7J)YQZNx7>Nz>3Gz>3>j$qyI-7vJ~99Wx#fY^Y94sD#^TSaHZPSzpFQ`R z?#!tRBuu}#D43-JVAZ*dx^;Z)Du4EH3O_I$m?QaQ&ra+aW^HZE{hQUwp6z{9Xn;i= zl+OWhZPsdkSD10GO8nKmqP@b5!FgnNuF!vzICxd9++SP!)eit8H#&kTJ6v1y-zHTv zq^zrvYFN{@@NXfb|NCw7Z3FRM0p)hDJH+SuBQ^K$JT^UtNB^>FJ}hm9T#_Qd3i_>} z->Ug=z7_h_54p<${T{h;_zcm_vY@bSfKyr4vAxEn%?I=#-*E5YvBTJllzvg~VO1$} z4a%1qe@l~>3++5?Y<>3P)BVp00S=O>ru>tFCHOL66-yL7J+jN+A@^c*&2!NyaCCPw+e>pxaDScLCAWCO@v($H z6DYOeO9;DdVLBG4cDhFH%&$hxFU=?SzD8~%A)?v1BT()&6+cR`X=Cvf_(EjaD~7`H zxA11PwwJChoVXTNXX%+;ZK{ef8&0khHtg8z+hnKD@|dcAF66*Yp++bqI!LA^FHuCa zlTeEl@>J^A$yJmWhvi#=I?+0#6Haim$8?|Pb}tmvEfi|@w3iol<_@_TrSg=bb0rmI z&+RNUoq-B%2jBy;926PVtYbcQaoW2{wqO}ji%;DiEQ?ZVhl zY?>xnQYiay$S+R?Wr^q+tzIF(??wbiFpQUkfQ@EhmZnCZ>%=3qvim~MgznQQPmQfh z4Z9xOM?;u+!hj-I#WcihXQA+JA~JhD(N1YlP%yrjNGRTK)NJIvPB1y~teLw(kA)PU z6i$eB;&<5qT@`qqQmLUi)=9%tW3Y-}2JS@$&d?-GJa(X~0K(905Xo@bndS#-6_M#5% zk=^t0!%7L-SbXt<{tTB^ua=;4)OIclokSCzfK>QTE=E)i9aGReuvnBhcUb=~9VG3s literal 0 HcmV?d00001 diff --git a/ngraph/test/frontend/paddlepaddle/op/relu.cpp b/ngraph/test/frontend/paddlepaddle/op/relu.cpp new file mode 100644 index 00000000000000..f70131cd8f900d --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/relu.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using reluTestParam = FrontendOpTestParam; +using reluTest = FrontendOpTest; + +static reluTestParam relu() { + reluTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "relu"; //TODO: compact model/decomposited + + //Inputs inputs; + res.inputs.emplace_back(test::NDArray{{-2.0, 0.0, 1.0 }} + .get_vector()); + + // + res.expected_outputs.emplace_back(test::NDArray({{0.0, 0.0, 1.0 }}) + .get_vector()); + + return res; +} + +TEST_P(reluTest, test_relu) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, reluTest, + ::testing::Values( + relu() + ), + reluTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/softmax.cpp b/ngraph/test/frontend/paddlepaddle/op/softmax.cpp new file mode 100644 index 00000000000000..6b47c56378667a --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/softmax.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using softmaxTestParam = FrontendOpTestParam; +using softmaxTest = FrontendOpTest; + +static softmaxTestParam softmax() { + softmaxTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "softmax"; //TODO: compact model/decomposited + + //Inputs inputs; + res.inputs.emplace_back(test::NDArray{{{{2.0, 3.0, 4.0, 5.0 }, + {3.0, 4.0, 5.0, 6.0 }, + {7.0, 8.0, 8.0, 9.0 }}, + {{1.0, 2.0, 3.0, 4.0 }, + {5.0, 6.0, 7.0, 8.0 }, + {6.0, 7.0, 8.0, 9.0 }}}} + .get_vector()); + + // + res.expected_outputs.emplace_back(test::NDArray({{{{0.0065732626, 0.0065732626, 0.017147826, 0.017147826 }, + {0.01786798, 0.01786798, 0.04661262, 0.04661262 }, + {0.9755587, 0.9755587, 0.93623954, 0.93623954 }}, + {{0.004901689, 0.004901689, 0.004901689, 0.004901689 }, + {0.26762316, 0.26762316, 0.26762316, 0.26762316 }, + {0.72747517, 0.72747517, 0.72747517, 0.72747517 }}}}) + .get_vector()); + + return res; +} + +TEST_P(softmaxTest, test_softmax) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, softmaxTest, + ::testing::Values( + softmax() + ), + softmaxTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp b/ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp new file mode 100644 index 00000000000000..dce3c4ce011c85 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using squeezeTestParam = FrontendOpTestParam; +using squeezeTest = FrontendOpTest; + +static squeezeTestParam squeeze2() { + squeezeTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "squeeze2"; //TODO: compact model/decomposited + + //Inputs inputs; + res.inputs.emplace_back(test::NDArray{{{{0.9197787, 0.17733535, 0.53042966, 0.86230236, 0.36841938 }}, + {{0.3493094, 0.16514555, 0.8016413, 0.13844138, 0.75991917 }}, + {{0.054560415, 0.8210127, 0.6733729, 0.06564956, 0.9250301 }}}} + .get_vector()); + + res.inputs.emplace_back(test::NDArray{1} + .get_vector()); + + // + res.expected_outputs.emplace_back(test::NDArray({{{0.9197787, 0.17733535, 0.53042966, 0.86230236, 0.36841938 }, + {0.3493094, 0.16514555, 0.8016413, 0.13844138, 0.75991917 }, + {0.054560415, 0.8210127, 0.6733729, 0.06564956, 0.9250301 }}}) + .get_vector()); + + return res; +} + +TEST_P(squeezeTest, test_squeeze) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, squeezeTest, + ::testing::Values( + squeeze2() + ), + squeezeTest::getTestCaseName); From 42b11e9b82104c487cafe640742fb196d2feb0af Mon Sep 17 00:00:00 2001 From: BaiYM0117 Date: Fri, 16 Apr 2021 16:55:09 +0800 Subject: [PATCH 12/54] Delete unnecessary file --- .../frontend/paddlepaddle/op/squeeze2.cpp | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp diff --git a/ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp b/ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp deleted file mode 100644 index dce3c4ce011c85..00000000000000 --- a/ngraph/test/frontend/paddlepaddle/op/squeeze2.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2018-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 -// - -#include "../../shared/include/op.hpp" - -using namespace ngraph; -using namespace ngraph::frontend; - -static const std::string PDPD = "pdpd"; -static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; - -using squeezeTestParam = FrontendOpTestParam; -using squeezeTest = FrontendOpTest; - -static squeezeTestParam squeeze2() { - squeezeTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "squeeze2"; //TODO: compact model/decomposited - - //Inputs inputs; - res.inputs.emplace_back(test::NDArray{{{{0.9197787, 0.17733535, 0.53042966, 0.86230236, 0.36841938 }}, - {{0.3493094, 0.16514555, 0.8016413, 0.13844138, 0.75991917 }}, - {{0.054560415, 0.8210127, 0.6733729, 0.06564956, 0.9250301 }}}} - .get_vector()); - - res.inputs.emplace_back(test::NDArray{1} - .get_vector()); - - // - res.expected_outputs.emplace_back(test::NDArray({{{0.9197787, 0.17733535, 0.53042966, 0.86230236, 0.36841938 }, - {0.3493094, 0.16514555, 0.8016413, 0.13844138, 0.75991917 }, - {0.054560415, 0.8210127, 0.6733729, 0.06564956, 0.9250301 }}}) - .get_vector()); - - return res; -} - -TEST_P(squeezeTest, test_squeeze) { - ASSERT_NO_THROW(validateOp()); -} - -INSTANTIATE_TEST_CASE_P(FrontendOpTest, squeezeTest, - ::testing::Values( - squeeze2() - ), - squeezeTest::getTestCaseName); From da0d20a78478bd88d00288237fd0c59fd8d4fa4d Mon Sep 17 00:00:00 2001 From: jialipen Date: Fri, 16 Apr 2021 18:17:46 +0800 Subject: [PATCH 13/54] add adaptive_pool2d generator --- .../gen_scripts/generate_pool2d.py | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 680c58078c8338..e353f7846f5399 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -35,6 +35,30 @@ def pool2d(name : str, x, attrs : dict): return outs[0] +def adaptive_pool2d(name : str, x, attrs : dict): + import paddle as pdpd + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=data_type) + out = pdpd.fluid.layers.adaptive_pool2d( + input=node_x, + pool_size=attrs['pool_size'], + pool_type=attrs['pool_type'], + require_index=attrs['require_index']) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] def main(): N, C, H, W = 2, 3, 4, 4 @@ -45,6 +69,7 @@ def main(): pooling_types = ['max', 'avg'] + # pool2d for i, pooling_type in enumerate(pooling_types): # example 1: # ceil_mode = False @@ -143,7 +168,16 @@ def main(): } # shape of out_6: [2, 4, 3, 3] which is different from out_1 pool2d(pooling_type+'Pool_test6', data_NHWC, pdpd_attrs) - # + # + + # adaptive_pool2d + for i, pooling_type in enumerate(pooling_types): + pdpd_attrs = { + 'pool_size': [3,3], + 'pool_type': pooling_type, + 'require_index': False + } + adaptive_pool2d(pooling_type+'AdaptivePool2D_test1', data_NCHW, pdpd_attrs) if __name__ == "__main__": From 39235b827fde200bf8de1d66760dbfcbba7321d7 Mon Sep 17 00:00:00 2001 From: jialipen Date: Fri, 16 Apr 2021 22:17:56 +0800 Subject: [PATCH 14/54] fuzzyOpTest: read pdmodel as well as its inputs and outputs to set up an unified test case. --- .../paddlepaddle/gen_scripts/save_model.py | 6 +- ngraph/test/frontend/paddlepaddle/op.cpp | 122 ++--- ngraph/test/frontend/shared/include/npy.hpp | 497 ++++++++++++++++++ 3 files changed, 558 insertions(+), 67 deletions(-) create mode 100644 ngraph/test/frontend/shared/include/npy.hpp diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index 0f5f596115f3ab..aab6a06d31e1a1 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -1,4 +1,4 @@ - +import os import numpy as np import paddle as pdpd @@ -42,10 +42,12 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) print_alike(input) + np.save(os.path.join("../models/"+name, "input{}".format(i)), input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) - print_alike(output) + print_alike(output) + np.save(os.path.join("../models/"+name, "output{}".format(i)), output) # composited model + scattered model pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 361d601062961b..5446d6afb849ae 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -3,6 +3,8 @@ // #include "../shared/include/op.hpp" +// library taken from https://github.com/llohse/libnpy +#include "../shared/include/npy.hpp" using namespace ngraph; using namespace ngraph::frontend; @@ -10,70 +12,60 @@ using namespace ngraph::frontend; static const std::string PDPD = "pdpd"; static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; -using PDPDFrontendOpTest = FrontendOpTest; - -static FrontendOpTestParam conv2d() { - FrontendOpTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "conv2d/"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 3, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, - {5.f, 6.f, 7.f, 8.f, 9.f}, - {10.f, 11.f, 12.f, 13.f, 14.f}, - {15.f, 16.f, 17.f, 18.f, 19.f}, - {20.f, 21.f, 22.f, 23.f, 24.f}, - {25.f, 26.f, 27.f, 28.f, 29.f}, - {30.f, 31.f, 32.f, 33.f, 34.f}}}}} - .get_vector()); - - // (1, 5, 6, 6) - res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, - {63.f, 108.f, 81.f}, - {123.f, 198.f, 141.f}, - {112.f, 177.f, 124.f}}}}) - .get_vector()); - - return res; -} +namespace fuzzyOp { + using PDPDFuzzyOpTest = FrontendOpTest; + using PDPDFuzzyOpTestParam = FrontendOpTestParam; -static FrontendOpTestParam relu() { - FrontendOpTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "relu/"; - - //Inputs inputs; - // data (1, 1, 7, 5) input tensor - res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, - {5.f, 6.f, 7.f, 8.f, 9.f}, - {10.f, 11.f, 12.f, 13.f, 14.f}, - {15.f, 16.f, 17.f, 18.f, 19.f}, - {20.f, 21.f, 22.f, 23.f, 24.f}, - {25.f, 26.f, 27.f, 28.f, 29.f}, - {30.f, 31.f, 32.f, 33.f, 34.f}}}}} - .get_vector()); - - // filters (1, 1, 3, 3) aka convolution weights - res.inputs.emplace_back( - test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} - .get_vector()); - - // (1, 1, 4, 3) - res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, - {63.f, 108.f, 81.f}, - {123.f, 198.f, 141.f}, - {112.f, 177.f, 124.f}}}}) - .get_vector()); - - return res; -} + static PDPDFuzzyOpTestParam fuzzy_op() { + PDPDFuzzyOpTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test1"; // TODO: to read models from config file. + + auto modelpath = std::string(TEST_FILES) + res.m_modelsPath + res.m_modelName; + + auto _load_from_npy = [&](std::string name) { + auto file_path = name + ".npy"; + + std::cout << "************load_from_npy (" << file_path << ")" << std::endl; + + std::ifstream npy_file(file_path); + std::vector npy_shape; + std::vector npy_data; + if (npy_file.good()) + npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); + + return npy_data; + }; + + auto npy_input = _load_from_npy(modelpath+"/input0"); + auto npy_output = _load_from_npy(modelpath+"/output0"); + if (npy_input.empty() || npy_output.empty()) { + throw std::runtime_error("failed to load test case input/output npy file!"); + } + + // TODO: to support more inputs/outputs + std::vector data_input(npy_input.size()); + std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); -INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, - ::testing::Values( - conv2d(), - relu() - ), - FrontendOpTest::getTestCaseName); + std::vector data_output(npy_output.size()); + std::copy_n(npy_output.data(), npy_output.size(), data_output.begin()); + + res.inputs.emplace_back(data_input); + + res.expected_outputs.emplace_back(npy_output); + + return res; + } + + TEST_P(PDPDFuzzyOpTest, test_fuzzy) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, PDPDFuzzyOpTest, + ::testing::Values( + fuzzy_op() + ), + PDPDFuzzyOpTest::getTestCaseName); + +} diff --git a/ngraph/test/frontend/shared/include/npy.hpp b/ngraph/test/frontend/shared/include/npy.hpp new file mode 100644 index 00000000000000..1878215cd0954f --- /dev/null +++ b/ngraph/test/frontend/shared/include/npy.hpp @@ -0,0 +1,497 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef NPY_H +#define NPY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace npy { + +/* Compile-time test for byte order. + If your compiler does not define these per default, you may want to define + one of these constants manually. + Defaults to little endian order. */ +#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ + defined(__BIG_ENDIAN__) || \ + defined(__ARMEB__) || \ + defined(__THUMBEB__) || \ + defined(__AARCH64EB__) || \ + defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) +const bool big_endian = true; +#else +const bool big_endian = false; +#endif + + +const char magic_string[] = "\x93NUMPY"; +const size_t magic_string_length = 6; + +const char little_endian_char = '<'; +const char big_endian_char = '>'; +const char no_endian_char = '|'; + +constexpr char host_endian_char = ( big_endian ? + big_endian_char : + little_endian_char ); + +/* npy array length */ +typedef unsigned long int ndarray_len_t; + +inline void write_magic(std::ostream& ostream, unsigned char v_major=1, unsigned char v_minor=0) { + ostream.write(magic_string, magic_string_length); + ostream.put(v_major); + ostream.put(v_minor); +} + +inline void read_magic(std::istream& istream, unsigned char& v_major, unsigned char& v_minor) { + char buf[magic_string_length+2]; + istream.read(buf, magic_string_length+2); + + if(!istream) { + throw std::runtime_error("io error: failed reading file"); + } + + if (0 != std::memcmp(buf, magic_string, magic_string_length)) + throw std::runtime_error("this file does not have a valid npy format."); + + v_major = buf[magic_string_length]; + v_minor = buf[magic_string_length+1]; +} + +// typestring magic +struct Typestring { + private: + char c_endian; + char c_type; + int len; + + public: + inline std::string str() { + const size_t max_buflen = 16; + char buf[max_buflen]; + std::sprintf(buf, "%c%c%u", c_endian, c_type, len); + return std::string(buf); + } + + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'f'}, len {sizeof(float)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'f'}, len {sizeof(double)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'f'}, len {sizeof(long double)} {} + + Typestring(const std::vector& v) + :c_endian {no_endian_char}, c_type {'i'}, len {sizeof(char)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(short)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(int)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(long)} {} + Typestring(const std::vector& v) :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(long long)} {} + + Typestring(const std::vector& v) + :c_endian {no_endian_char}, c_type {'u'}, len {sizeof(unsigned char)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned short)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned int)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned long)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned long long)} {} + + Typestring(const std::vector>& v) + :c_endian {host_endian_char}, c_type {'c'}, len {sizeof(std::complex)} {} + Typestring(const std::vector>& v) + :c_endian {host_endian_char}, c_type {'c'}, len {sizeof(std::complex)} {} + Typestring(const std::vector>& v) + :c_endian {host_endian_char}, c_type {'c'}, len {sizeof(std::complex)} {} +}; + +inline void parse_typestring( std::string typestring){ +// std::regex re ("'([<>|])([ifuc])(\\d+)'"); +// std::smatch sm; +// +// std::regex_match(typestring, sm, re ); +// +// if ( sm.size() != 4 ) { +// throw std::runtime_error("invalid typestring"); +// } +} + +namespace pyparse { + +/** + Removes leading and trailing whitespaces + */ +inline std::string trim(const std::string& str) { + const std::string whitespace = " \t"; + auto begin = str.find_first_not_of(whitespace); + + if (begin == std::string::npos) + return ""; + + auto end = str.find_last_not_of(whitespace); + + return str.substr(begin, end-begin+1); +} + + +inline std::string get_value_from_map(const std::string& mapstr) { + size_t sep_pos = mapstr.find_first_of(":"); + if (sep_pos == std::string::npos) + return ""; + + std::string tmp = mapstr.substr(sep_pos+1); + return trim(tmp); +} + +/** + Parses the string representation of a Python dict + + The keys need to be known and may not appear anywhere else in the data. + */ +inline std::unordered_map parse_dict(std::string in, std::vector& keys) { + + std::unordered_map map; + + if (keys.size() == 0) + return map; + + in = trim(in); + + // unwrap dictionary + if ((in.front() == '{') && (in.back() == '}')) + in = in.substr(1, in.length()-2); + else + throw std::runtime_error("Not a Python dictionary."); + + std::vector> positions; + + for (auto const& value : keys) { + size_t pos = in.find( "'" + value + "'" ); + + if (pos == std::string::npos) + throw std::runtime_error("Missing '"+value+"' key."); + + std::pair position_pair { pos, value }; + positions.push_back(position_pair); + } + + // sort by position in dict + std::sort(positions.begin(), positions.end() ); + + for(size_t i = 0; i < positions.size(); ++i) { + std::string raw_value; + size_t begin { positions[i].first }; + size_t end { std::string::npos }; + + std::string key = positions[i].second; + + if ( i+1 < positions.size() ) + end = positions[i+1].first; + + raw_value = in.substr(begin, end-begin); + + raw_value = trim(raw_value); + + if (raw_value.back() == ',') + raw_value.pop_back(); + + map[key] = get_value_from_map(raw_value); + } + + return map; +} + +/** + Parses the string representation of a Python boolean + */ +inline bool parse_bool(const std::string& in) { + if (in == "True") + return true; + if (in == "False") + return false; + + throw std::runtime_error("Invalid python boolan."); +} + +/** + Parses the string representation of a Python str + */ +inline std::string parse_str(const std::string& in) { + if ((in.front() == '\'') && (in.back() == '\'')) + return in.substr(1, in.length()-2); + + throw std::runtime_error("Invalid python string."); +} + +/** + Parses the string represenatation of a Python tuple into a vector of its items + */ +inline std::vector parse_tuple(std::string in) { + std::vector v; + const char seperator = ','; + + in = trim(in); + + if ((in.front() == '(') && (in.back() == ')')) + in = in.substr(1, in.length()-2); + else + throw std::runtime_error("Invalid Python tuple."); + + std::istringstream iss(in); + + for (std::string token; std::getline(iss, token, seperator);) { + v.push_back(token); + } + + return v; +} + +template +inline std::string write_tuple(const std::vector& v) { + if (v.size() == 0) + return ""; + + std::ostringstream ss; + + if (v.size() == 1) { + ss << "(" << v.front() << ",)"; + } else { + const std::string delimiter = ", "; + // v.size() > 1 + ss << "("; + std::copy(v.begin(), v.end()-1, std::ostream_iterator(ss, delimiter.c_str())); + ss << v.back(); + ss << ")"; + } + + return ss.str(); +} + +inline std::string write_boolean(bool b) { + if(b) + return "True"; + else + return "False"; +} + +} // namespace pyparse + + +inline void parse_header(std::string header, std::string& descr, bool& fortran_order, std::vector& shape) { + /* + The first 6 bytes are a magic string: exactly "x93NUMPY". + The next 1 byte is an unsigned byte: the major version number of the file format, e.g. x01. + The next 1 byte is an unsigned byte: the minor version number of the file format, e.g. x00. Note: the version of the file format is not tied to the version of the numpy package. + The next 2 bytes form a little-endian unsigned short int: the length of the header data HEADER_LEN. + The next HEADER_LEN bytes form the header data describing the array's format. It is an ASCII string which contains a Python literal expression of a dictionary. It is terminated by a newline ('n') and padded with spaces ('x20') to make the total length of the magic string + 4 + HEADER_LEN be evenly divisible by 16 for alignment purposes. + The dictionary contains three keys: + + "descr" : dtype.descr + An object that can be passed as an argument to the numpy.dtype() constructor to create the array's dtype. + "fortran_order" : bool + Whether the array data is Fortran-contiguous or not. Since Fortran-contiguous arrays are a common form of non-C-contiguity, we allow them to be written directly to disk for efficiency. + "shape" : tuple of int + The shape of the array. + For repeatability and readability, this dictionary is formatted using pprint.pformat() so the keys are in alphabetic order. + */ + + // remove trailing newline + if (header.back() != '\n') + throw std::runtime_error("invalid header"); + header.pop_back(); + + // parse the dictionary + std::vector keys { "descr", "fortran_order", "shape" }; + auto dict_map = npy::pyparse::parse_dict(header, keys); + + if (dict_map.size() == 0) + throw std::runtime_error("invalid dictionary in header"); + + std::string descr_s = dict_map["descr"]; + std::string fortran_s = dict_map["fortran_order"]; + std::string shape_s = dict_map["shape"]; + + // TODO: extract info from typestring + parse_typestring(descr_s); + // remove + descr = npy::pyparse::parse_str(descr_s); + + // convert literal Python bool to C++ bool + fortran_order = npy::pyparse::parse_bool(fortran_s); + + // parse the shape tuple + auto shape_v = npy::pyparse::parse_tuple(shape_s); + if (shape_v.size() == 0) + throw std::runtime_error("invalid shape tuple in header"); + + for ( auto item : shape_v ) { + ndarray_len_t dim = static_cast(std::stoul(item)); + shape.push_back(dim); + } +} + + +inline std::string write_header_dict(const std::string& descr, bool fortran_order, const std::vector& shape) { + std::string s_fortran_order = npy::pyparse::write_boolean(fortran_order); + std::string shape_s = npy::pyparse::write_tuple(shape); + + return "{'descr': '" + descr + "', 'fortran_order': " + s_fortran_order + ", 'shape': " + shape_s + ", }"; +} + +inline void write_header(std::ostream& out, const std::string& descr, bool fortran_order, const std::vector& shape_v) +{ + std::string header_dict = write_header_dict(descr, fortran_order, shape_v); + + size_t length = magic_string_length + 2 + 2 + header_dict.length() + 1; + + unsigned char version[2] = {1, 0}; + if (length >= 255*255) { + length = magic_string_length + 2 + 4 + header_dict.length() + 1; + version[0] = 2; + version[1] = 0; + } + size_t padding_len = 16 - length % 16; + std::string padding (padding_len, ' '); + + // write magic + write_magic(out, version[0], version[1]); + + // write header length + if (version[0] == 1 && version[1] == 0) { + char header_len_le16[2]; + uint16_t header_len = header_dict.length() + padding.length() + 1; + + header_len_le16[0] = (header_len >> 0) & 0xff; + header_len_le16[1] = (header_len >> 8) & 0xff; + out.write(reinterpret_cast(header_len_le16), 2); + }else{ + char header_len_le32[4]; + uint32_t header_len = header_dict.length() + padding.length() + 1; + + header_len_le32[0] = (header_len >> 0) & 0xff; + header_len_le32[1] = (header_len >> 8) & 0xff; + header_len_le32[2] = (header_len >> 16) & 0xff; + header_len_le32[3] = (header_len >> 24) & 0xff; + out.write(reinterpret_cast(header_len_le32), 4); + } + + out << header_dict << padding << '\n'; +} + +inline std::string read_header(std::istream& istream) { + // check magic bytes an version number + unsigned char v_major, v_minor; + read_magic(istream, v_major, v_minor); + + uint32_t header_length; + if(v_major == 1 && v_minor == 0){ + + char header_len_le16[2]; + istream.read(header_len_le16, 2); + header_length = (header_len_le16[0] << 0) | (header_len_le16[1] << 8); + + if((magic_string_length + 2 + 2 + header_length) % 16 != 0) { + // TODO: display warning + } + }else if(v_major == 2 && v_minor == 0) { + char header_len_le32[4]; + istream.read(header_len_le32, 4); + + header_length = (header_len_le32[0] << 0) | (header_len_le32[1] << 8) + | (header_len_le32[2] << 16) | (header_len_le32[3] << 24); + + if((magic_string_length + 2 + 4 + header_length) % 16 != 0) { + // TODO: display warning + } + }else{ + throw std::runtime_error("unsupported file format version"); + } + + auto buf_v = std::vector(); + buf_v.reserve(header_length); + istream.read(buf_v.data(), header_length); + std::string header(buf_v.data(), header_length); + + return header; +} + +inline ndarray_len_t comp_size(const std::vector& shape) { + ndarray_len_t size = 1; + for (ndarray_len_t i : shape ) + size *= i; + + return size; +} + +template +inline void SaveArrayAsNumpy( const std::string& filename, bool fortran_order, unsigned int n_dims, const unsigned long shape[], const std::vector& data) +{ + Typestring typestring_o(data); + std::string typestring = typestring_o.str(); + + std::ofstream stream( filename, std::ofstream::binary); + if(!stream) { + throw std::runtime_error("io error: failed to open a file."); + } + + std::vector shape_v(shape, shape+n_dims); + write_header(stream, typestring, fortran_order, shape_v); + + auto size = static_cast(comp_size(shape_v)); + + stream.write(reinterpret_cast(data.data()), sizeof(Scalar) * size); +} + + +template +inline void LoadArrayFromNumpy(const std::string& filename, std::vector& shape, std::vector& data) +{ + std::ifstream stream(filename, std::ifstream::binary); + if(!stream) { + throw std::runtime_error("io error: failed to open a file."); + } + + std::string header = read_header(stream); + + // parse header + bool fortran_order; + std::string typestr; + + parse_header(header, typestr, fortran_order, shape); + + // check if the typestring matches the given one + Typestring typestring_o {data}; + std::string expect_typestr = typestring_o.str(); + if (typestr != expect_typestr) { + throw std::runtime_error("formatting error: typestrings not matching"); + } + + + // compute the data size based on the shape + auto size = static_cast(comp_size(shape)); + data.resize(size); + + // read the data + stream.read(reinterpret_cast(data.data()), sizeof(Scalar)*size); +} + +} // namespace npy + +#endif // NPY_H From d361e42baa24aeef48a82621c3dfce1d14f108ea Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 17 Apr 2021 00:55:13 +0800 Subject: [PATCH 15/54] fuzzy_test: support both decomposed model and composed model. --- ngraph/test/frontend/paddlepaddle/op.cpp | 91 ++++++++++++++++-------- 1 file changed, 63 insertions(+), 28 deletions(-) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 5446d6afb849ae..8d45cdf357e825 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -2,33 +2,46 @@ // SPDX-License-Identifier: Apache-2.0 // -#include "../shared/include/op.hpp" +#include + +#include "util/all_close.hpp" +#include "util/all_close_f.hpp" +#include "util/engine/test_engines.hpp" +#include "util/ndarray.hpp" +#include "util/test_case.hpp" +#include "util/test_control.hpp" +#include "util/test_tools.hpp" + +#include "../shared/include/basic_api.hpp" + // library taken from https://github.com/llohse/libnpy #include "../shared/include/npy.hpp" using namespace ngraph; using namespace ngraph::frontend; +using TestEngine = test::IE_CPU_Engine; static const std::string PDPD = "pdpd"; static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; namespace fuzzyOp { - using PDPDFuzzyOpTest = FrontendOpTest; - using PDPDFuzzyOpTestParam = FrontendOpTestParam; - - static PDPDFuzzyOpTestParam fuzzy_op() { - PDPDFuzzyOpTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "avgPool_test1"; // TODO: to read models from config file. - - auto modelpath = std::string(TEST_FILES) + res.m_modelsPath + res.m_modelName; - - auto _load_from_npy = [&](std::string name) { - auto file_path = name + ".npy"; - - std::cout << "************load_from_npy (" << file_path << ")" << std::endl; - + using PDPDFuzzyOpTest = FrontEndBasicTest; + using PDPDFuzzyOpTestParam = std::tuple; // modelname + + /* + // There are 2 versions of PDPD model. + // * decomposed model, which is a folder. + // * composed model, which is a file with extension .pdmodel. + */ + static const std::vector models { + std::string("maxPool_test1/"), + std::string("avgPool_test1/avgPool_test1.pdmodel"), + }; + + void run_fuzzy(std::shared_ptr function, std::string& modelfile) { + auto _load_from_npy = [&](std::string& file_path) { std::ifstream npy_file(file_path); std::vector npy_shape; std::vector npy_data; @@ -36,10 +49,20 @@ namespace fuzzyOp { npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); return npy_data; - }; + }; - auto npy_input = _load_from_npy(modelpath+"/input0"); - auto npy_output = _load_from_npy(modelpath+"/output0"); + auto _get_modelfolder = [&](std::string& modelfile) { + size_t found = modelfile.find_last_of("/\\"); + + return modelfile.substr(0,found); + }; + + auto modelfolder = _get_modelfolder(modelfile); + + std::string input_path = modelfolder+"/input0.npy"; + std::string output_path = modelfolder+"/output0.npy"; + auto npy_input = _load_from_npy(input_path); + auto npy_output = _load_from_npy(output_path); if (npy_input.empty() || npy_output.empty()) { throw std::runtime_error("failed to load test case input/output npy file!"); } @@ -51,21 +74,33 @@ namespace fuzzyOp { std::vector data_output(npy_output.size()); std::copy_n(npy_output.data(), npy_output.size(), data_output.begin()); - res.inputs.emplace_back(data_input); + // run test + auto test_case = test::TestCase(function); - res.expected_outputs.emplace_back(npy_output); - - return res; + test_case.add_input(data_input); + test_case.add_expected_output(npy_output); + + test_case.run(); } TEST_P(PDPDFuzzyOpTest, test_fuzzy) { - validateOp(); + // load + ASSERT_NO_THROW(doLoadFromFile()); + + // convert + std::shared_ptr function; + function = m_frontEnd->convert(m_inputModel); + ASSERT_NE(function, nullptr); + + // run + run_fuzzy(function, m_modelFile); } INSTANTIATE_TEST_CASE_P(FrontendOpTest, PDPDFuzzyOpTest, - ::testing::Values( - fuzzy_op() - ), + ::testing::Combine( + ::testing::Values(PDPD), + ::testing::Values(PATH_TO_MODELS), + ::testing::ValuesIn(models)), PDPDFuzzyOpTest::getTestCaseName); } From a461bbd250dd5682c976eeaafe1c8ef28765db7d Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 17 Apr 2021 02:13:46 +0800 Subject: [PATCH 16/54] remove the leading whitespace of getline from csv. --- ngraph/test/frontend/paddlepaddle/op.cpp | 45 +++++++++++++++---- ngraph/test/frontend/shared/src/basic_api.cpp | 1 + 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 8d45cdf357e825..8225d64844f402 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -3,6 +3,7 @@ // #include +#include #include "util/all_close.hpp" #include "util/all_close_f.hpp" @@ -35,11 +36,35 @@ namespace fuzzyOp { // * decomposed model, which is a folder. // * composed model, which is a file with extension .pdmodel. */ - static const std::vector models { - std::string("maxPool_test1/"), - std::string("avgPool_test1/avgPool_test1.pdmodel"), - }; - + bool ends_with(std::string const & value, std::string const & ending) { + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); + } + + const std::string& trim_leadingspace(std::string& str) + { + auto it = str.begin(); + for (; it != str.end() && isspace(*it); it++); + auto d = std::distance(str.begin(), it); + std::cout << d << std::endl; + return str.erase(0,d); + } + + std::vector get_models(void) { + std::string models_csv = std::string(TEST_FILES) + PATH_TO_MODELS + "models.csv"; + std::ifstream f(models_csv); + std::vector models; + std::string line; + while (getline(f, line, ',')) { + auto line_trim = trim_leadingspace(line); + std::cout<< "line in csv: " << line_trim< function, std::string& modelfile) { auto _load_from_npy = [&](std::string& file_path) { std::ifstream npy_file(file_path); @@ -51,7 +76,9 @@ namespace fuzzyOp { return npy_data; }; - auto _get_modelfolder = [&](std::string& modelfile) { + auto _get_modelfolder = [&](std::string& modelfile) { + if (!ends_with(modelfile, ".pdmodel")) return modelfile; + size_t found = modelfile.find_last_of("/\\"); return modelfile.substr(0,found); @@ -64,7 +91,7 @@ namespace fuzzyOp { auto npy_input = _load_from_npy(input_path); auto npy_output = _load_from_npy(output_path); if (npy_input.empty() || npy_output.empty()) { - throw std::runtime_error("failed to load test case input/output npy file!"); + throw std::runtime_error("failed to load input/output npy for test case. Tried " + input_path); } // TODO: to support more inputs/outputs @@ -100,7 +127,9 @@ namespace fuzzyOp { ::testing::Combine( ::testing::Values(PDPD), ::testing::Values(PATH_TO_MODELS), - ::testing::ValuesIn(models)), + //::testing::ValuesIn({std::string("maxPool_test1"), + // std::string("avgPool_test1/avgPool_test1.pdmodel")})), + ::testing::ValuesIn(get_models())), PDPDFuzzyOpTest::getTestCaseName); } diff --git a/ngraph/test/frontend/shared/src/basic_api.cpp b/ngraph/test/frontend/shared/src/basic_api.cpp index ee203f7cd435e4..e0df4a390a1a3a 100644 --- a/ngraph/test/frontend/shared/src/basic_api.cpp +++ b/ngraph/test/frontend/shared/src/basic_api.cpp @@ -11,6 +11,7 @@ using namespace ngraph::frontend; std::string FrontEndBasicTest::getTestCaseName(const testing::TestParamInfo &obj) { std::string fe, path, fileName; std::tie(fe, path, fileName) = obj.param; + std::cout <<" *** " << fe << " *** " << path << " *** " << fileName << " *** " << std::endl; // need to replace special characters to create valid test case name fileName = std::regex_replace(fileName, std::regex("[/\\.]"), "_"); return fe + "_" + fileName; From a05583c059a364daa113161c9fa175b3c8987ea6 Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 17 Apr 2021 02:15:11 +0800 Subject: [PATCH 17/54] TODOs --- ngraph/test/frontend/paddlepaddle/op.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 8225d64844f402..97f7d84ae3ccb2 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -95,6 +95,7 @@ namespace fuzzyOp { } // TODO: to support more inputs/outputs + // TODO: to support different data type. std::vector data_input(npy_input.size()); std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); From ba20df8881b5938c95f9461b4c382fb32958f0aa Mon Sep 17 00:00:00 2001 From: bai Date: Mon, 19 Apr 2021 11:11:58 +0800 Subject: [PATCH 18/54] delete binary files --- .../files/paddlepaddle/models/relu/__model__ | Bin 9517 -> 0 bytes .../files/paddlepaddle/models/relu/relu.pdmodel | Bin 9721 -> 0 bytes .../files/paddlepaddle/models/softmax/__model__ | Bin 9714 -> 0 bytes .../paddlepaddle/models/softmax/softmax.pdmodel | Bin 9918 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 ngraph/test/files/paddlepaddle/models/relu/__model__ delete mode 100644 ngraph/test/files/paddlepaddle/models/relu/relu.pdmodel delete mode 100644 ngraph/test/files/paddlepaddle/models/softmax/__model__ delete mode 100644 ngraph/test/files/paddlepaddle/models/softmax/softmax.pdmodel diff --git a/ngraph/test/files/paddlepaddle/models/relu/__model__ b/ngraph/test/files/paddlepaddle/models/relu/__model__ deleted file mode 100644 index f2a22621a4619b6a03b9733b46ee59944c70f45d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9517 zcmeHNZExGg9k(1iwJ%PhI87I5KtO0MEIA%&SIv`G3$S-8_c*pzwAMgJ_^4Fhj ztyTX!{j1b&lFfwcsJFYmMebK>J7go_JjUHN?(UJwXm@Apt=bmZ*xIaKtFGN&^D4Cm zWT)V1Ne_KJ$m!wYjM^c2pxBU8AroHEK^F5gP!UV{i&oVCRwdh{@?_U-zD2HmRO;Qz zsAli$x5;*v)0huM#H;K3YZ$nJfg-~jhpeb>*8g#v>|g|Yq)M}>U)>CU=Xt*nDfj9@ zFB|Zn!vr0d11`J4X;$=w?8c%9vYgAIkXazR10Tah!7Z8+5s(Dk?;- zmAU2x)0`R}`1!bg;H5%xul=I~Pe|{_ptnrnC-)N3=jjh zQ8&N98#B#b1E`~83(9~9pBPX^OMY$CqaoRVA9#F(AESSLK2|4B_eOiq%stdI6-u8x z%}R{{A@fq>@d(!#aW}Y7PY<6xYlhEX6|b#MTWy|``lGg`>70`A6GK=Y=dquprHFlz z`7>kSGUCo48g<_f?8{V8f9S}cQa(qsGcg2ujq?ND0+!Y{4>c~U^h zjq|y{Zf6tckPYG~&zD2}`U;>zX=jeD)qdZ3lVy4w9vi@U!Qn|`YBZQ;xoQ~4L-Qho zTOBx)#sm0jYBXIn!#`a)5v|9Mt#T|v4euEOnAU|lIope}bnin?Ja2|yT>-*n8qsdG zoJ#@w98NkcA02>Nm+-lhfYb{)dq3 zCRRXba@Pe47ow5chCSpig$PS``ShI}p#3zK zvU>evlT0mSR}20Y&&`UcoG$qKF1bl=d}0#1-*Tz4g4{9w_<|SSeb2e(mn4F=T%Vkf(-Uj26`#bxk)6%CpZ1%WBCkTT zRcN*f&AyGLbyrcDMO-sI4%;TMnbak07i?*19o@0lTv`9X^)MEZzNoUkD)qSb+l91f zSr~P-b@h#{KYaPw{#S$`PLY|W{L_-9_z<8%ZjjB{%`VyL799QWg6bZVb^?k@Xql_I zCEq9a&imwO1Lc`wsiMOpJN*H*OA}%~OtEy*?GFJfRV9 zmn{s(VrYkJJ>uv?GOrVLZUxny2TO+mmP#yER)Z< zzC*4f6&p-;Mb!?CAv&c554%kFcwyHn(o+TrBZ@P3S4pKD7Pvnz#)dV?u??8v;NqAg)!Z5fG<6yF5M~sP+6k$v{d#v z_*Z0tvQ%`9RId@l*Mc&qz(O-I&oU#=b>fklc@a2EPlfK$sK|`2OAWmq+gF2` zctf8em&7pGY)2vRBo(>6o=Rt;P!KS_GD#`+H)1yYUMCowTGq_mAjeXQPfN$d2B{~k zk76t=Px2IaU>{RyP}WiB^2f_^F~StpE0ZL3%ki?P9H;re2xKpuH%A`(*dB|FB$w sG!{2rke{K_%GCmz+_jy_LMG8vCV&e2Da44%fg=i%$7c>v>dayNf3y*10{{R3 diff --git a/ngraph/test/files/paddlepaddle/models/relu/relu.pdmodel b/ngraph/test/files/paddlepaddle/models/relu/relu.pdmodel deleted file mode 100644 index bb10873039531da8df27663e7bed4c64e589a76e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9721 zcmeHNZ*Lp78MhoewHYT-oTdvjAUNDwSaLj_WjRY)%o}zCw!P^(V0#fD2ngzqClNaF zu1B6M)d*G$*q?OU+kLKmhrJ&50S0vYk(4Z1)(~_>oOF|4$VVP|eE#$IJS6$skG9sT z|C;_)YB$Md!gbW!UEd=2E43Z6k#HWPwT;$2QW@>;Y`s(4A{$$q)oazY`)gjM_JHgZ zJT2*AQx9@_xHzJANFFFQ{_le2ZNBq}02W zQO&mf+hjY-Y0QTr;??#2HFVrSN0H%+LsnEb{V#8m9rR$0RB0CVtDE7kJ?|$X<(?n( zvH=e|Owe&T;IbQ>W<_7fZY+u*%efp1nFX?2u)G&&u5^%KnhJ6j$0>KeL6=LaqC(_a znP*-w&8d+=Gavg0UMeK_+TT0yg!H}-e#?~qAS53C2299$BRsouVvZ~^X8G_vLx>@^ z?weoG8#B$`08vNBmMB9+_|y<(tmI>39(BnE{J`TQ{22S|^RYU4wl~^)ZrU)1Ek)cE zS##zMTt?h^MBQ&T1N$`<_zxZbQ`YC0o(RPbq{cGM$P@GP&~N6k?T1ElR{;9FpW|!-_ zZ>dHE`FSRJqY?i84Uv4*I&`vy6-%Mvcn=M|Nmh84L$kFaTtvKs$kVi;Bhu7v_Vva` z{$0EOTf>O3sRJcc0)LxagDwnc@o$oMCWyf{za-?k!5e@#cOBTcfM{wPcB8xmGnTIM zkL?xqxCn&aM(iR(Fsxm@OPI zP%vbMin+k~sO>!268u(AnNo#GuiO8A3YS z`=r$91K)^DFJCKPZkJ8j81R2W?rbYKb_|`0nzWq*Q>h{WO-cdi@tBAzR4M7UC`5n;B6#o$%MY z&{6xFkONLiWJ`0vCk6!|yF2h&%>&O?IsDnc3suCk7k(3o!GP(yK+5vl ztHLrW08*R*nO5ug_(Pj!*$pWCvEjghG21aiV-A!p$6^PQywT=iD_}NPjQ#pv(f&UJ zW=r$aOIhqCuy%_$2vx0ou(tO350NZybOckjxwhuNN2;btS)zgGt!V@FRTgvVmv_i_ z42F9JT-)7osLmZb)ZD+z0P+&m|6G;$k>SmSpZ43BX0PDg3f`?s{0pawUw@#Y#VSisgKwby`?37obG(ox2`u@h& zZ(e@3{{ml`VM2HBi7P%-Kj9B26j)jcNd02H@y{IBMwe4E@mKl8_N zRGul8Dmpx}!yl0QG0vt7(J65yAj$2Cl^cTh>*OA}%~Oth2l`Z?0)|TkcG^OBEQYqb zM&6wtoupY-Oy7Nr+(FVq^KnO@?rUx;P>M+#i%SgHXxS12;rLrv83)KqN0&}q3#0Sw z)Q%=(gT-txeNNe+W1sJk8$DLURP_oW`?d>(J|S^VV~QRUNt^A2TC9-IrM^S1Bb^&e zRz>v?2UK**30`)Y?(xFTg@Te&p-N7>MQMB9CAXqX4k^xuq=M|Z?S-auP@!!Dd_b1{ zGN+n#%(W4xy<21pmLawH%+0~DC__zBfmm(pl6E$R;fjaCq4)W)c{QohagP=45!H0X zE-RH1Oj6JlXO44gasm=!I9{G{lycS|+Z!d*1qZmbB6aCzfdG{yI!{Yw-$Q;yCMZiq z*J$+`0Y*0>ID%nZ5CSHefq9l0eXbLa)Xaw@n0)jxyrIwk6?UVN}e?2y|SZ$kcn>8#$ z5MIo4-Ln)pG1`7unypwkMs9IzTBsXajAiW4+7=z*NkQ{J1 zyV;qg$QUk~06ipV`yzdgK0$$^7wtt~p)b&WGsBZ9x`qQ-u2JfO+L@i%{r=s#b@sj^Ep+MLH2ZDaIZQX1}+x2|A%YiqN-UcOY`D6idK z^GcNy@`hpqPK9jqoc7b0CxMDs!s$_6_cMC5Y+vOLxvtW-?z7>4Tju|{Otwksvpt7p zi(LA+(0ip}#g6^!WIN4h%m*Uk<@JL#OzdDHPx0~r%gdYoU$2v0%m7ZJG>dxW&G4&| z=Y1d&?)gDC?en0;1RWK9E<3?ln)ih4#3B#UjLU(LX&^f}%esN)N(XIhQ$fb!IN|O$ z=x|9@l#5I&bIo(6IUQ40&qn^Cmk7zdljfl(r1vARr%3pZL*n7D&xEYj!e71wJk9$S zk3kT=Ww4APSN-t?fX7U;LyrxGI&IX#FJA`Rj!!JiF{bb{ixkTCGoxiy$@=`z<3s!y zRqgSSI(@J|+<$1s(BwoYefl6RG$w@13XR)CTw}%!aG@R?J$zUTAHOIWSktgZF{cf0 zJ8dxcEG6NmhOjKo;(9wNL|hkXeP&Z!M%>v|)vwnB`!E&wcOCf?%I9ddJgJ5H+t4(C z+6Ref1=&bqJDyiD z9UXcHRX)@?Q{G*VKp-+eTIVSfr0H%TLQx0TmbTR4kb5!=?Qi_vzS6Qh$lQ>4)ymJ02N9*b9jyByT{IU zr)R@VkHZrKILkSlY)p*?(==06ezZCe}8uu^{B{mE;Vf>Y1FIM>eGGa&)AFb`Aa?O(Xn$+Q*8f-{`3c= z-0vmOG-`4Isz=t*UTG&O)6L^W9}AZ&6g7!b`SK^F^T`<@8^*5SkIl`6M6FDS(Pj5K z>^HgG_Efv=11n_5!oU&HXBr-V`+Yh3h>c*}{-0hWSIN$&ChhzMmnzN4P2=tto&4S% z=lq|Mu~s&10_*?n#_A+^g-?Q2_K1qiEb3lmkJD<-DtnaP|91A+eCO%e>FZjP0Ib7)u~L+(f1Q-gkg~Q$nqXDihHeYl_&>|!O%t9yBMjTyb(SO$2at+~G`Vlrw z&@(Ql*#6woqCfg}FS+J_-*s0Okv^^Fzp7BV#^4hTw`C#L#a8?`w!ZrMi-T_nK@1~P zP5I{qOYk*AiR_Tg*X&{&PA)hvD?mU56dmV{dIDST;~bL2L}2~pu~l*2kf?m=~xWxbcNiUUyWK@nosV1 zhulCiL$gs!pv-D2ZIoiu#^NjRRmHMb^o65u;mv3$FI`$ipaZ<@6&cm6Wj+vb(z`~s zpczt&FWeq1i&B&k6~Jm+O0>JN3?FhRw85v#=EbB6M?KzXn^u!Ic37d5V3Gn?oI1*_ z$_a3Yq2WBEDB-L(qB&0-MR;K!pQlJ&xLp{VW<{11%03+Y%TqyFB05H@mk45S!-8Wd z#uH4yMzb(WQzOrH;*rX@>p{rP`uxW+3=bs)MELPg)+2$RVATTfHneJKyj*WI6 znr2%q6rT?{IlvX5$Cz+5BNt7*G?77bQ3kik-g*CFxddq}zIZ`?hDs|}3uruQI+KM= bqKQlZ750;hA(eec6eN!iFrvhn!}@;!kg28F diff --git a/ngraph/test/files/paddlepaddle/models/softmax/softmax.pdmodel b/ngraph/test/files/paddlepaddle/models/softmax/softmax.pdmodel deleted file mode 100644 index 1800a07e06c987508b4a1f3460f21e316a396a73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9918 zcmeHN?Qa`N8IRMXO(uPDbL~+KoL0+KvD4s<;~Z^I1jL?nd;ty#KAcolqw((89(g^x zw=i+dAe&vTqyFyt7P(icT_+n|&SQ+WG5R{GjCQMA*D$@cwOL)SUa4+W*Y2%( zmD(|RN3l~*h3xX24%3(?fr?nd>0wh3Gum3VuXdl@QfXHY*{EE0xNMpK;x^ePm5+BF zEnDQuM}^+4jB0l5-y+*-Mq_>|B3@nJU&F)>Ch`<7KV^A!)BkIgT*nN^Nt9;Mpt>1; zR`I+KMZ!Hl=%+&-beN#yV#sALI7{<^kiA&sL7H)SDr6eSUe2<9pt;gP7u!^ju{ch+ z`wedE2Lr;YIW>(YUB4eJzh z*6?1*)`XMr&k(NXWpNfayGbG9rbwGJr{Xf=&avu#vl-Z@slb2W_@A&o$8;$ayO0{A zH7ifd&jY`i#daPF&REWdYRLlO?)ZℜK))!gYc~bb@TG`>AX<9|lTj{+$dC$a?Ug zm`5obCC%q#a@1~FU3Uu^21Xh=*F`Qp&wU_UnA4bEdop9?N^GftmfmStI=8 zmom;*(pmbrRY`D$IFRue;bsZ(?^)U@6~io{G_21tFxh7~sP7xH9o3eB@V6I0c^7Kt zCbqpKZfAp2k`2WZnJ*{x4;Mfx?0yzBTkS_j&i|+9%ghzRV?%J3a|G&`8YiG>rs^i5 z(JW69wTCV&;0DeDYOG&1!rxyw6Rn32Efb5RhIb7EOzT{oJll)XWbb`XJa2@bUjT*6 zETY|NxkC!#b3#oscQ!a02WQ4&n?0`UzMVk?`DrS7qY?h@4Uv4*I&`vy6-%Mvcn^$B zyJ_xO4$YB^a1rqiB2UwXj!07r1nQ0V{kJSOu!a%gya$4)1pYR;0$mtv;7HaR{2y}iO6%W%*o!5yV1OmN3zV^shP-ibS-rEHoIsYNPT z(kxfiM<)`ngpNwgWPnp6{L^c74Jm^eAprwLr_4|_7epVo4qXg&XgmC-;bpH-oJK_~ zC4$cM8o}qqYbDnmqzM}%QRwp|4A7OQR;Apn7Zr?X_-_GTlB}jIjv0 zLQ#`!Rj>Z6az4Q$WW)Fs;<358knB|nF}Cbphy5lW+@4yuePE63STb-#44Fp6-~OQ- z|Co*8-2T7bA~(p+&rRz33occflRGBdF9!MD`!4vuBI~Vf+9cTj+wSTlxWp&HDg!lT zof+(2WuU7J)YQZNx7>Nz>3Gz>3>j$qyI-7vJ~99Wx#fY^Y94sD#^TSaHZPSzpFQ`R z?#!tRBuu}#D43-JVAZ*dx^;Z)Du4EH3O_I$m?QaQ&ra+aW^HZE{hQUwp6z{9Xn;i= zl+OWhZPsdkSD10GO8nKmqP@b5!FgnNuF!vzICxd9++SP!)eit8H#&kTJ6v1y-zHTv zq^zrvYFN{@@NXfb|NCw7Z3FRM0p)hDJH+SuBQ^K$JT^UtNB^>FJ}hm9T#_Qd3i_>} z->Ug=z7_h_54p<${T{h;_zcm_vY@bSfKyr4vAxEn%?I=#-*E5YvBTJllzvg~VO1$} z4a%1qe@l~>3++5?Y<>3P)BVp00S=O>ru>tFCHOL66-yL7J+jN+A@^c*&2!NyaCCPw+e>pxaDScLCAWCO@v($H z6DYOeO9;DdVLBG4cDhFH%&$hxFU=?SzD8~%A)?v1BT()&6+cR`X=Cvf_(EjaD~7`H zxA11PwwJChoVXTNXX%+;ZK{ef8&0khHtg8z+hnKD@|dcAF66*Yp++bqI!LA^FHuCa zlTeEl@>J^A$yJmWhvi#=I?+0#6Haim$8?|Pb}tmvEfi|@w3iol<_@_TrSg=bb0rmI z&+RNUoq-B%2jBy;926PVtYbcQaoW2{wqO}ji%;DiEQ?ZVhl zY?>xnQYiay$S+R?Wr^q+tzIF(??wbiFpQUkfQ@EhmZnCZ>%=3qvim~MgznQQPmQfh z4Z9xOM?;u+!hj-I#WcihXQA+JA~JhD(N1YlP%yrjNGRTK)NJIvPB1y~teLw(kA)PU z6i$eB;&<5qT@`qqQmLUi)=9%tW3Y-}2JS@$&d?-GJa(X~0K(905Xo@bndS#-6_M#5% zk=^t0!%7L-SbXt<{tTB^ua=;4)OIclokSCzfK>QTE=E)i9aGReuvnBhcUb=~9VG3s From f239b166f7d7abd070f1f4bac1c84252a573c4ad Mon Sep 17 00:00:00 2001 From: Zhang Yi3 Date: Mon, 12 Apr 2021 10:02:44 +0800 Subject: [PATCH 19/54] enable rnn lstm convert --- ngraph/frontend/paddlepaddle/CMakeLists.txt | 2 +- ngraph/frontend/paddlepaddle/src/decoder.cpp | 20 ++ ngraph/frontend/paddlepaddle/src/decoder.hpp | 1 + .../paddlepaddle/src/node_context.hpp | 5 + .../paddlepaddle/src/op/fill_constant.cpp | 33 +++ .../paddlepaddle/src/op/fill_constant.hpp | 31 +++ ngraph/frontend/paddlepaddle/src/op/lstm.cpp | 210 ++++++++++++++++++ ngraph/frontend/paddlepaddle/src/op/lstm.hpp | 31 +++ ngraph/frontend/paddlepaddle/src/op/rnn.cpp | 36 +++ ngraph/frontend/paddlepaddle/src/op/rnn.hpp | 31 +++ ngraph/frontend/paddlepaddle/src/op_table.cpp | 6 + 11 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 ngraph/frontend/paddlepaddle/src/op/fill_constant.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/fill_constant.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/lstm.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/lstm.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/rnn.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/rnn.hpp diff --git a/ngraph/frontend/paddlepaddle/CMakeLists.txt b/ngraph/frontend/paddlepaddle/CMakeLists.txt index f41ccf36babffa..8f9f34022399bb 100644 --- a/ngraph/frontend/paddlepaddle/CMakeLists.txt +++ b/ngraph/frontend/paddlepaddle/CMakeLists.txt @@ -51,7 +51,7 @@ if(COMMAND ie_add_vs_version_file) FILEDESCRIPTION "FrontEnd to load and convert PaddlePaddle file format") endif() -target_link_libraries(paddlepaddle_frontend PRIVATE ${Protobuf_LIBRARIES} PUBLIC ngraph) +target_link_libraries(paddlepaddle_frontend PRIVATE ${Protobuf_LIBRARIES} PUBLIC ngraph PRIVATE ngraph::builder) # TODO: Consider to remove the following block (inherited from onnx_import just in case). if (CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") diff --git a/ngraph/frontend/paddlepaddle/src/decoder.cpp b/ngraph/frontend/paddlepaddle/src/decoder.cpp index 7c7343434f6b4f..9c0087b651e759 100644 --- a/ngraph/frontend/paddlepaddle/src/decoder.cpp +++ b/ngraph/frontend/paddlepaddle/src/decoder.cpp @@ -147,5 +147,25 @@ bool DecoderPDPDProto::get_bool(const std::string& name, bool def) const } } +std::vector DecoderPDPDProto::get_longs(const std::string& name, const std::vector& def) const +{ + std::cout << "Running get_longs" << std::endl; + std::vector attrs; + for (const auto &attr : op.attrs()) { + if (attr.name() == name) + attrs.push_back(attr); + } + if (attrs.empty()) { + return def; + } else if (attrs.size() > 1) { + // TODO: raise exception here + return def; + } else { + std::vector res; + std::copy(attrs[0].longs().begin(), attrs[0].longs().end(), std::back_inserter(res)); + return res; + } +} + } } \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/decoder.hpp b/ngraph/frontend/paddlepaddle/src/decoder.hpp index 55e5bc660b53e8..5d8354aeb413da 100644 --- a/ngraph/frontend/paddlepaddle/src/decoder.hpp +++ b/ngraph/frontend/paddlepaddle/src/decoder.hpp @@ -59,6 +59,7 @@ class DecoderPDPDProto float get_float(const std::string& name, float def = 0.) const; std::string get_str(const std::string& name, const std::string& def = "") const; bool get_bool (const std::string& name, bool def = false) const; + std::vector get_longs(const std::string& name, const std::vector& def = {}) const; // TODO: Further populate get_XXX methods on demand ngraph::element::Type get_dtype(const std::string& name, ngraph::element::Type def) const; diff --git a/ngraph/frontend/paddlepaddle/src/node_context.hpp b/ngraph/frontend/paddlepaddle/src/node_context.hpp index 33a815b340234b..fce01f77e2b779 100644 --- a/ngraph/frontend/paddlepaddle/src/node_context.hpp +++ b/ngraph/frontend/paddlepaddle/src/node_context.hpp @@ -100,6 +100,11 @@ template <> inline ngraph::element::Type NodeContext::get_attribute (const std::string& name, const ngraph::element::Type& def) const { return node.get_dtype(name, def); } +template <> +inline std::vector NodeContext::get_attribute (const std::string& name, const std::vector& def) const +{ return node.get_longs(name, def); } + + } } } diff --git a/ngraph/frontend/paddlepaddle/src/op/fill_constant.cpp b/ngraph/frontend/paddlepaddle/src/op/fill_constant.cpp new file mode 100644 index 00000000000000..16c7841b590d7f --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/fill_constant.cpp @@ -0,0 +1,33 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "relu.hpp" +#include "fill_constant.hpp" + + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector fill_constant (const NodeContext& node) { + auto value = node.get_attribute("value"); + auto shape = node.get_attribute>("shape"); + return {std::make_shared(ngraph::element::f32, Shape(shape.begin(), shape.end()), value)}; + } + + }}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/fill_constant.hpp b/ngraph/frontend/paddlepaddle/src/op/fill_constant.hpp new file mode 100644 index 00000000000000..23db0487a64ede --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/fill_constant.hpp @@ -0,0 +1,31 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once + +#include "node_context.hpp" + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector fill_constant(const NodeContext &node); + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op/lstm.cpp b/ngraph/frontend/paddlepaddle/src/op/lstm.cpp new file mode 100644 index 00000000000000..24266f3584efde --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/lstm.cpp @@ -0,0 +1,210 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "lstm.hpp" +#include "utility.hpp" +#include "ngraph/builder/reshape.hpp" +#include "ngraph/builder/split.hpp" + +namespace ngraph { + namespace frontend + { + namespace pdpd + { + namespace op + { + namespace { + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INPUT NODES PARSING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + enum class LSTMInput { + LSTM_INPUT_X, + LSTM_INPUT_W, + LSTM_INPUT_R, + LSTM_INPUT_B, + LSTM_INPUT_SEQ_LENGTHS, + LSTM_INPUT_INIT_H, + LSTM_INPUT_INIT_C, + LSTM_INPUT_P + }; + + struct LSTMNgInputMap { + explicit LSTMNgInputMap(const NodeContext &node, Output& prev_output, int layer) { + auto input_x = builder::opset1::reorder_axes(prev_output, {1, 0, 2}); + //[begin. end) + auto weight_list = node.get_ng_inputs("WeightList"); + auto weight_begin = weight_list.begin(); + auto weight_end = std::next(weight_begin, weight_list.size() / 2 ); + auto bias_begin = weight_end; + auto bias_end = weight_list.end(); + int bidirect_len = node.get_attribute("is_bidirec") ? 4 : 2; + int layer_weight_start = layer * bidirect_len; + int layer_weight_end = bidirect_len + layer * bidirect_len; + int layer_bias_start = layer * bidirect_len; + int layer_bias_end = layer * bidirect_len + bidirect_len; + OutputVector layer_input_weight; + OutputVector layer_hidden_weight; + OutputVector layer_weight_bias; + OutputVector layer_hidden_bias; + + m_input_map[LSTMInput::LSTM_INPUT_X] = input_x; + //Parsing W R B + auto axis_const = std::make_shared(element::i64, Shape{}, 0); + for(int i = layer_weight_start; i < layer_weight_end ; i++) + { + auto weight_node = std::next(weight_begin, i); + if(i & 0x1) + layer_hidden_weight.push_back(std::make_shared(*weight_node, axis_const)); + else + layer_input_weight.push_back(std::make_shared(*weight_node, axis_const)); + + } + + for(int i = layer_bias_start; i < layer_bias_end ; i++) + { + auto weight_node = std::next(bias_begin, i); + + if(i & 0x1) + layer_hidden_bias.push_back(std::make_shared(*weight_node, axis_const)); + else + layer_weight_bias.push_back(std::make_shared(*weight_node, axis_const)); + } + + auto input_weight = std::make_shared(layer_input_weight, 0); + auto hidden_weight = std::make_shared(layer_hidden_weight, 0); + auto weight_bias = std::make_shared(layer_weight_bias, 0); + auto hidden_bias = std::make_shared(layer_hidden_bias, 0); + auto bias = std::make_shared(weight_bias, hidden_bias); + m_input_map[LSTMInput::LSTM_INPUT_W] = + ngraph::op::util::convert_lstm_node_format( + input_weight, + ngraph::op::util::LSTMWeightsFormat::IFCO, + ngraph::op::util::LSTMWeightsFormat::FICO, + 1); + m_input_map[LSTMInput::LSTM_INPUT_R] = + ngraph::op::util::convert_lstm_node_format( + hidden_weight, + ngraph::op::util::LSTMWeightsFormat::IFCO, + ngraph::op::util::LSTMWeightsFormat::FICO, + 1); + m_input_map[LSTMInput::LSTM_INPUT_B] = + ngraph::op::util::convert_lstm_node_format( + bias, + ngraph::op::util::LSTMWeightsFormat::IFCO, + ngraph::op::util::LSTMWeightsFormat::FICO, + 1); + + // Get dimensions needed for default inputs creation + // Parsing init hidden state + auto shape_of_x = std::make_shared(input_x); + + auto axes = + opset6::Constant::create(element::Type_t::i32, Shape{1}, {0}); + + auto batch_size_node = std::make_shared( + shape_of_x, + opset6::Constant::create(element::Type_t::i32, Shape{1}, {0}), + axes); + + auto seq_length_node = std::make_shared( + shape_of_x, + opset6::Constant::create(element::Type_t::i32, Shape{1}, {1}), + axes); + + auto shape_of_r = std::make_shared( + m_input_map[LSTMInput::LSTM_INPUT_R]); + auto num_directions_node = std::make_shared( + shape_of_r, + opset6::Constant::create(element::Type_t::i32, Shape{1}, {0}), + axes); + auto hidden_size_node = std::make_shared( + shape_of_r, + opset6::Constant::create(element::Type_t::i32, Shape{1}, {2}), + axes); + + m_input_map[LSTMInput::LSTM_INPUT_SEQ_LENGTHS] = + std::make_shared(seq_length_node, + batch_size_node); + + auto init_states = node.get_ng_inputs("PreState"); + // 0 for init_h, 1 for init_cell, update bidirect_len for init states + bidirect_len = node.get_attribute("is_bidirec") ? 2 : 1; + + auto h_begin = opset6::Constant::create(element::Type_t::i64, {1}, {layer * bidirect_len}); + auto h_end = opset6::Constant::create(element::Type_t::i32, Shape{1}, {layer * bidirect_len + bidirect_len}); + auto c_begin = opset6::Constant::create(element::Type_t::i64, {1}, {layer * bidirect_len}); + auto c_end = opset6::Constant::create(element::Type_t::i64, {1}, {layer * bidirect_len + bidirect_len}); + + m_input_map[LSTMInput::LSTM_INPUT_INIT_H] = builder::opset1::reorder_axes(std::make_shared(init_states[0], h_begin, h_end, std::vector{0}, std::vector{0}), {1, 0, 2}); + m_input_map[LSTMInput::LSTM_INPUT_INIT_C] = builder::opset1::reorder_axes(std::make_shared(init_states[1], c_begin, c_end,std::vector{0}, std::vector{0}), {1, 0, 2}); + + } + + Output &at(const LSTMInput &key) { return m_input_map.at(key); } + + std::map> m_input_map; + }; + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ATTRIBUTES PARSING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + struct LSTMAttributes + { + explicit LSTMAttributes(const NodeContext &node) + : m_hidden_size(node.get_attribute("hidden_size")), + m_layers(node.get_attribute("num_layers")), + m_direction(node.get_attribute("is_bidirec") ? ngraph::op::RecurrentSequenceDirection::BIDIRECTIONAL : ngraph::op::RecurrentSequenceDirection::FORWARD) + {}; + + ngraph::op::RecurrentSequenceDirection m_direction; + std::int32_t m_hidden_size; + std::int32_t m_layers; + + }; + } + OutputVector lstm (const NodeContext& node) { + auto mode = node.get_attribute("mode"); + MY_ASSERT(mode == "LSTM", "RNN only support LSTM now"); + auto prev_inputs = node.get_ng_inputs("Input"); + Output prev_output = prev_inputs[0]; + LSTMAttributes attrs(node); + Output Y_h, Y_c; + for(int i = 0; i < attrs.m_layers; i++) + { + LSTMNgInputMap input_map(node, prev_output, i); + auto lstm_sequence = std::make_shared( + input_map.at(LSTMInput::LSTM_INPUT_X), + input_map.at(LSTMInput::LSTM_INPUT_INIT_H), + input_map.at(LSTMInput::LSTM_INPUT_INIT_C), + input_map.at(LSTMInput::LSTM_INPUT_SEQ_LENGTHS), + input_map.at(LSTMInput::LSTM_INPUT_W), + input_map.at(LSTMInput::LSTM_INPUT_R), + input_map.at(LSTMInput::LSTM_INPUT_B), + attrs.m_hidden_size, + attrs.m_direction); + prev_output = builder::opset1::reorder_axes(lstm_sequence->output(0), {2, 0, 1, 3}); + auto out_shape = opset6::Constant::create(element::Type_t::i64, Shape{3}, {0, 0, -1}); + prev_output = std::make_shared(prev_output, out_shape, true); + Y_h = lstm_sequence->output(1); + Y_c = lstm_sequence->output(2); + } + + return {prev_output}; + + } + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op/lstm.hpp b/ngraph/frontend/paddlepaddle/src/op/lstm.hpp new file mode 100644 index 00000000000000..fb7a4b58c02946 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/lstm.hpp @@ -0,0 +1,31 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once + +#include "node_context.hpp" + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector lstm(const NodeContext &node); + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op/rnn.cpp b/ngraph/frontend/paddlepaddle/src/op/rnn.cpp new file mode 100644 index 00000000000000..08e56cba1da4d0 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/rnn.cpp @@ -0,0 +1,36 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "rnn.hpp" +#include "lstm.hpp" +#include "utility.hpp" + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector rnn (const NodeContext& node) { + auto mode = node.get_attribute("mode"); + MY_ASSERT(mode == "LSTM", "RNN only support LSTM now"); + return lstm(node); + } + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op/rnn.hpp b/ngraph/frontend/paddlepaddle/src/op/rnn.hpp new file mode 100644 index 00000000000000..3de9d1ef33ed38 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/rnn.hpp @@ -0,0 +1,31 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once + +#include "node_context.hpp" + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector rnn(const NodeContext &node); + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index a6d25f0c82a3cd..f44b63f7f6b454 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -34,6 +34,9 @@ #include "op/transpose2.hpp" #include "op/yolo_box.hpp" #include "op/multiclass_nms.hpp" +#include "op/rnn.hpp" +#include "op/fill_constant.hpp" +#include "op/transpose2.hpp" #include "op_table.hpp" @@ -69,6 +72,9 @@ std::map get_supported_ops() { {"transpose2", op::transpose2}, {"yolo_box", op::yolo_box}, {"multiclass_nms3", op::multiclass_nms} + {"softmax", op::softmax}, + {"rnn", op::rnn}, + {"fill_constant", op::fill_constant} }; }; From abf71d2eca02f95592638f288f747644d6352e3d Mon Sep 17 00:00:00 2001 From: Zhang Yi3 Date: Mon, 19 Apr 2021 14:11:43 +0800 Subject: [PATCH 20/54] refine interp, assign_value and conv2d --- ngraph/frontend/paddlepaddle/src/decoder.cpp | 18 +++ ngraph/frontend/paddlepaddle/src/decoder.hpp | 1 + .../paddlepaddle/src/node_context.hpp | 4 + .../paddlepaddle/src/op/assign_value.cpp | 33 ++++++ .../paddlepaddle/src/op/assign_value.hpp | 31 +++++ .../frontend/paddlepaddle/src/op/conv2d.cpp | 80 ++++++++++++- .../frontend/paddlepaddle/src/op/interp.cpp | 111 ++++++++++++++++-- .../frontend/paddlepaddle/src/op/interp.hpp | 1 + ngraph/frontend/paddlepaddle/src/op/lstm.cpp | 1 - ngraph/frontend/paddlepaddle/src/op/rnn.cpp | 1 - .../paddlepaddle/src/op/uniform_random.cpp | 32 +++++ .../paddlepaddle/src/op/uniform_random.hpp | 31 +++++ ngraph/frontend/paddlepaddle/src/op_table.cpp | 15 ++- 13 files changed, 341 insertions(+), 18 deletions(-) create mode 100644 ngraph/frontend/paddlepaddle/src/op/assign_value.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/assign_value.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/uniform_random.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/uniform_random.hpp diff --git a/ngraph/frontend/paddlepaddle/src/decoder.cpp b/ngraph/frontend/paddlepaddle/src/decoder.cpp index 9c0087b651e759..5e0ab160c996e0 100644 --- a/ngraph/frontend/paddlepaddle/src/decoder.cpp +++ b/ngraph/frontend/paddlepaddle/src/decoder.cpp @@ -167,5 +167,23 @@ std::vector DecoderPDPDProto::get_longs(const std::string& name, const } } +int64_t DecoderPDPDProto::get_long(const std::string& name, const int64_t& def) const + { + std::cout << "Running get_longs" << std::endl; + std::vector attrs; + for (const auto &attr : op.attrs()) { + if (attr.name() == name) + attrs.push_back(attr); + } + if (attrs.empty()) { + return def; + } else if (attrs.size() > 1) { + // TODO: raise exception here + return def; + } else { + return attrs[0].l(); + } + } + } } \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/decoder.hpp b/ngraph/frontend/paddlepaddle/src/decoder.hpp index 5d8354aeb413da..8da52a24408e72 100644 --- a/ngraph/frontend/paddlepaddle/src/decoder.hpp +++ b/ngraph/frontend/paddlepaddle/src/decoder.hpp @@ -60,6 +60,7 @@ class DecoderPDPDProto std::string get_str(const std::string& name, const std::string& def = "") const; bool get_bool (const std::string& name, bool def = false) const; std::vector get_longs(const std::string& name, const std::vector& def = {}) const; + int64_t get_long(const std::string& name, const int64_t& def = {}) const; // TODO: Further populate get_XXX methods on demand ngraph::element::Type get_dtype(const std::string& name, ngraph::element::Type def) const; diff --git a/ngraph/frontend/paddlepaddle/src/node_context.hpp b/ngraph/frontend/paddlepaddle/src/node_context.hpp index fce01f77e2b779..ca9ac2daa7f0f6 100644 --- a/ngraph/frontend/paddlepaddle/src/node_context.hpp +++ b/ngraph/frontend/paddlepaddle/src/node_context.hpp @@ -104,6 +104,10 @@ template <> inline std::vector NodeContext::get_attribute (const std::string& name, const std::vector& def) const { return node.get_longs(name, def); } +template <> +inline int64_t NodeContext::get_attribute (const std::string& name, const int64_t& def) const +{ return node.get_long(name, def); } + } } diff --git a/ngraph/frontend/paddlepaddle/src/op/assign_value.cpp b/ngraph/frontend/paddlepaddle/src/op/assign_value.cpp new file mode 100644 index 00000000000000..62628f0d35efa0 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/assign_value.cpp @@ -0,0 +1,33 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "assign_value.hpp" +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector assign_value (const NodeContext& node) { + std::vector values = node.get_attribute>("fp32_values"); + std::vector shape = node.get_attribute>("shape"); + return {opset6::Constant::create(element::f32, Shape{shape.begin(), shape.end()}, values)}; + } + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op/assign_value.hpp b/ngraph/frontend/paddlepaddle/src/op/assign_value.hpp new file mode 100644 index 00000000000000..650ab1d5add8b0 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/assign_value.hpp @@ -0,0 +1,31 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once + +#include "node_context.hpp" + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector assign_value (const NodeContext &node); + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp b/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp index d3dd4bd898a6a9..6930edb1ce3b6f 100644 --- a/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp @@ -22,20 +22,92 @@ namespace frontend { namespace pdpd { namespace op { +ngraph::op::PadType get_auto_pad(const NodeContext& node) +{ + // Default value means use explicitly provided padding values. + ngraph::op::PadType pad_type{ngraph::op::PadType::NOTSET}; + auto padding_algorithm = node.get_attribute("padding_algorithm"); + static std::unordered_multimap + auto_pad_values{ + {"VALID", ngraph::op::PadType::VALID}, + {"SAME", ngraph::op::PadType::SAME_UPPER}, + {"NOTSET", ngraph::op::PadType::NOTSET}, + }; + + const auto pad_val_it = auto_pad_values.find(padding_algorithm); + + if(pad_val_it == auto_pad_values.end()) { + pad_type = ngraph::op::PadType::NOTSET; + } else { + pad_type = pad_val_it->second; + } + + + + return pad_type; +} + +std::pair get_pads(const NodeContext& node, + const size_t kernel_rank) +{ + CoordinateDiff pads(kernel_rank, 0); + + auto pads_int32 = node.get_attribute>("paddings"); + pads = CoordinateDiff{std::begin(pads_int32), std::end(pads_int32)}; + CoordinateDiff pads_begin; + CoordinateDiff pads_end; + + + if (pads.size() == kernel_rank * 2) + { + for(int i = 0; i < pads.size(); i++) + { + if(i & 0x01) + { + pads_end.push_back(pads[i]); + } else { + pads_begin.push_back(pads[i]); + } + } + return {pads_begin, pads_end}; + } + else + { + // No paddings provided or only one side values provided, which means same + // padding at both begin and end of axis. + return {pads, pads}; + } +} + +std::pair get_pads(const NodeContext& node) +{ + const auto data_rank = node.get_ng_input("Input").get_partial_shape().rank(); + + const auto data_spatial_dims = data_rank.get_length() - 2; + + return get_pads(node, data_spatial_dims); +} + OutputVector conv2d (const NodeContext& node) { auto data = node.get_ng_input("Input"); auto filter = node.get_ng_input("Filter"); // TODO: resolve padding according to spec auto strides = node.get_attribute>("strides"); - auto paddings = node.get_attribute>("paddings"); auto dilations = node.get_attribute>("dilations"); + auto auto_pad_type = get_auto_pad(node); + auto paddings = get_pads(node); + auto pads_begin = paddings.first; + auto pads_end = paddings.second; + + return {std::make_shared( data, filter, ngraph::Strides(strides.begin(), strides.end()), - ngraph::CoordinateDiff(paddings.begin(), paddings.end()), - ngraph::CoordinateDiff(paddings.begin(), paddings.end()), - ngraph::Strides(dilations.begin(), dilations.end()))}; + pads_begin, + pads_end, + ngraph::Strides(dilations.begin(), dilations.end()), + auto_pad_type)}; } }}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/interp.cpp b/ngraph/frontend/paddlepaddle/src/op/interp.cpp index 036a11a4a16de9..5a257df65a0b1f 100644 --- a/ngraph/frontend/paddlepaddle/src/op/interp.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/interp.cpp @@ -22,6 +22,37 @@ namespace frontend { namespace pdpd { namespace op { +std::shared_ptr +calculate_output_shape_based_on_scales(const Output& data, + const Output& scales) +{ + const auto shape_of_data = std::make_shared( + std::make_shared(data), scales.get_element_type()); + const auto multiply = + std::make_shared(shape_of_data, scales); + const auto output_shape = + std::make_shared(multiply, ngraph::element::i64); + + return output_shape; +} + +std::shared_ptr +calculate_scales_based_on_sizes(const Output& data, + const Output& sizes) +{ + const float epsilon = 1.0e-5; + const auto shape_of_data = std::make_shared( + std::make_shared(data), ngraph::element::f32); + const auto converted_sizes = + std::make_shared(sizes, ngraph::element::f32); + const auto divide = + std::make_shared(converted_sizes, shape_of_data); + const auto eps_node = std::make_shared( + ngraph::element::f32, Shape{}, epsilon); + const auto scales = std::make_shared(divide, eps_node); + + return scales; +} OutputVector nearest_interp_v2 (const NodeContext& node) { auto x = node.get_ng_input("X"); @@ -33,7 +64,7 @@ OutputVector nearest_interp_v2 (const NodeContext& node) { InterpolateAttrs attrs; - attrs.mode = InterpolateMode::nearest; //HARDCODE + attrs.mode = InterpolateMode::nearest; auto out_w = node.get_attribute("out_w"); auto out_h = node.get_attribute("out_h"); @@ -45,18 +76,80 @@ OutputVector nearest_interp_v2 (const NodeContext& node) { attrs.shape_calculation_mode = ShapeCalcMode::sizes; } - auto target_spatial_shape = - ngraph::opset6::Constant::create(element::i64, Shape{2}, {out_h, out_w}); - auto scales = ngraph::opset6::Constant::create(element::f32, Shape{2}, std::vector(scale.begin(), scale.end())); - auto axes = ngraph::opset6::Constant::create(element::i64, Shape{2}, {2, 3}); + Output scales; + Output target_spatial_shape; + if (out_w <= 0 || out_h <= 0) { + attrs.shape_calculation_mode = ShapeCalcMode::scales; + scales = opset6::Constant::create(element::f32, Shape{2}, std::vector(scale.begin(), scale.end())); + target_spatial_shape = calculate_output_shape_based_on_scales(x, scales); + } + else { + attrs.shape_calculation_mode = ShapeCalcMode::sizes; + target_spatial_shape = opset6::Constant::create(element::i64, Shape{4}, {1, 1, out_h, out_w}); + scales = calculate_scales_based_on_sizes(x, target_spatial_shape); + } - attrs.coordinate_transformation_mode = CoordinateTransformMode::asymmetric; //HARDCODE - attrs.nearest_mode = Nearest_mode::round_prefer_floor; //HARDCODE - attrs.antialias = false; //HARDCODE + attrs.coordinate_transformation_mode = CoordinateTransformMode::asymmetric; + attrs.nearest_mode = Nearest_mode::round_prefer_floor; + attrs.antialias = false; attrs.pads_begin = {0, 0, 0, 0}; attrs.pads_end = {0, 0, 0, 0}; - return {std::make_shared(x, target_spatial_shape, scales, axes, attrs)}; + return {std::make_shared(x, target_spatial_shape, scales, attrs)}; } + OutputVector bilinear_interp_v2 (const NodeContext& node) { + auto x = node.get_ng_input("X"); + + using InterpolateMode = ngraph::opset6::Interpolate::InterpolateMode; + using CoordinateTransformMode = ngraph::opset6::Interpolate::CoordinateTransformMode; + using Nearest_mode = ngraph::opset6::Interpolate::NearestMode; + using InterpolateAttrs = ngraph::opset6::Interpolate::InterpolateAttrs; + using ShapeCalcMode = ngraph::opset6::Interpolate::ShapeCalcMode; + + InterpolateAttrs attrs; + + attrs.mode = InterpolateMode::linear_onnx; + + auto out_w = node.get_attribute("out_w"); + auto out_h = node.get_attribute("out_h"); + auto scale = node.get_attribute>("scale"); + Output scales; + Output target_spatial_shape; + if (out_w <= 0 || out_h <= 0) { + attrs.shape_calculation_mode = ShapeCalcMode::scales; + scales = opset6::Constant::create(element::f32, Shape{2}, std::vector(scale.begin(), scale.end())); + target_spatial_shape = calculate_output_shape_based_on_scales(x, scales); + } + else { + attrs.shape_calculation_mode = ShapeCalcMode::sizes; + target_spatial_shape = opset6::Constant::create(element::i64, Shape{4}, {1, 1, out_h, out_w}); + scales = calculate_scales_based_on_sizes(x, target_spatial_shape); + } + + bool align_corners = node.get_attribute("align_corners"); + int32_t align_mode = node.get_attribute("align_mode"); + + if(!align_corners && align_mode == 1) + { + attrs.coordinate_transformation_mode = CoordinateTransformMode::asymmetric; + } + else if(!align_corners && align_mode == 0) + { + attrs.coordinate_transformation_mode = CoordinateTransformMode::half_pixel; + } + else if(align_corners) + { + attrs.coordinate_transformation_mode = CoordinateTransformMode::align_corners; + } + + auto axes = ngraph::opset6::Constant::create(element::i64, Shape{2}, {2, 3}); + + attrs.nearest_mode = Nearest_mode::round_prefer_floor; + attrs.antialias = false; + attrs.pads_begin = {0, 0, 0, 0}; + attrs.pads_end = {0, 0, 0, 0}; + + return {std::make_shared(x, target_spatial_shape, scales, attrs)}; + } }}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/interp.hpp b/ngraph/frontend/paddlepaddle/src/op/interp.hpp index a46066e56a6ff6..547ee0707f55b2 100644 --- a/ngraph/frontend/paddlepaddle/src/op/interp.hpp +++ b/ngraph/frontend/paddlepaddle/src/op/interp.hpp @@ -23,5 +23,6 @@ namespace pdpd { namespace op { OutputVector nearest_interp_v2 (const NodeContext& node_context); +OutputVector bilinear_interp_v2 (const NodeContext& node_context); }}}} diff --git a/ngraph/frontend/paddlepaddle/src/op/lstm.cpp b/ngraph/frontend/paddlepaddle/src/op/lstm.cpp index 24266f3584efde..5cc4f700feeecb 100644 --- a/ngraph/frontend/paddlepaddle/src/op/lstm.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/lstm.cpp @@ -16,7 +16,6 @@ #include #include "lstm.hpp" -#include "utility.hpp" #include "ngraph/builder/reshape.hpp" #include "ngraph/builder/split.hpp" diff --git a/ngraph/frontend/paddlepaddle/src/op/rnn.cpp b/ngraph/frontend/paddlepaddle/src/op/rnn.cpp index 08e56cba1da4d0..b8044d395f32ab 100644 --- a/ngraph/frontend/paddlepaddle/src/op/rnn.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/rnn.cpp @@ -17,7 +17,6 @@ #include #include "rnn.hpp" #include "lstm.hpp" -#include "utility.hpp" namespace ngraph { namespace frontend { diff --git a/ngraph/frontend/paddlepaddle/src/op/uniform_random.cpp b/ngraph/frontend/paddlepaddle/src/op/uniform_random.cpp new file mode 100644 index 00000000000000..c0b82bc9151b80 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/uniform_random.cpp @@ -0,0 +1,32 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "uniform_random.hpp" + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector uniform_random (const NodeContext& node) { + return {std::make_shared(element::f32, PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()})}; + } + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op/uniform_random.hpp b/ngraph/frontend/paddlepaddle/src/op/uniform_random.hpp new file mode 100644 index 00000000000000..abbe5c22f7dbd5 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/uniform_random.hpp @@ -0,0 +1,31 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once + +#include "node_context.hpp" + +namespace ngraph { + namespace frontend { + namespace pdpd { + namespace op { + + OutputVector uniform_random (const NodeContext &node); + + } + } + } +} diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index f44b63f7f6b454..60f9262cb0bd49 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -36,7 +36,8 @@ #include "op/multiclass_nms.hpp" #include "op/rnn.hpp" #include "op/fill_constant.hpp" -#include "op/transpose2.hpp" +#include "op/uniform_random.hpp" +#include "op/assign_value.hpp" #include "op_table.hpp" @@ -64,6 +65,9 @@ std::map get_supported_ops() { {"scale", op::scale}, {"leaky_relu", op::leaky_relu}, {"nearest_interp_v2", op::nearest_interp_v2}, + {"bilinear_interp_v2", op::bilinear_interp_v2}, + {"nearest_interp", op::nearest_interp_v2}, + {"bilinear_interp", op::bilinear_interp_v2}, {"concat", op::concat}, {"cast", op::cast}, {"split", op::split}, @@ -71,10 +75,15 @@ std::map get_supported_ops() { {"softmax", op::softmax}, {"transpose2", op::transpose2}, {"yolo_box", op::yolo_box}, - {"multiclass_nms3", op::multiclass_nms} + {"multiclass_nms3", op::multiclass_nms}, {"softmax", op::softmax}, {"rnn", op::rnn}, - {"fill_constant", op::fill_constant} + {"fill_constant", op::fill_constant}, + {"transpose2", op::transpose2}, + {"bmm", op::matmul}, + {"depthwise_conv2d", op::conv2d}, + {"uniform_random", op::uniform_random}, + {"assign_value", op::assign_value} }; }; From be71219c2767cbcdee61fd86212f711bda91bc0e Mon Sep 17 00:00:00 2001 From: jialipen Date: Mon, 12 Apr 2021 23:00:39 +0800 Subject: [PATCH 21/54] step1 --- ngraph/test/frontend/paddlepaddle/op.cpp | 60 ++++++++++++++++ ngraph/test/frontend/shared/include/op.hpp | 45 ++++++++++++ ngraph/test/frontend/shared/src/op.cpp | 81 ++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 ngraph/test/frontend/paddlepaddle/op.cpp create mode 100644 ngraph/test/frontend/shared/include/op.hpp create mode 100644 ngraph/test/frontend/shared/src/op.cpp diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp new file mode 100644 index 00000000000000..9c0a4fc059cd08 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using PDPDFrontendOpTest = FrontendOpTest; + +#if 0 +static const std::vector models { + std::string("conv2d"), + std::string("conv2d_s/conv2d.pdmodel"), + std::string("conv2d_relu/conv2d_relu.pdmodel"), + std::string("2in_2out/2in_2out.pdmodel"), +}; + +INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, + ::testing::Combine( + ::testing::Values(PDPD), + ::testing::Values(PATH_TO_MODELS), + ::testing::ValuesIn(models)), + PDPDFrontendOpTest::getTestCaseName); + +#endif + +static FrontendOpTestParam getTestData_2in_2out() { + FrontendOpTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "2in_2out/2in_2out.pdmodel"; + return res; +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, + ::testing::Values( + getTestData_2in_2out(), + FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_s/conv2d.pdmodel" }, + FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_relu/conv2d_relu.pdmodel" } + ), + FrontendOpTest::getTestCaseName); + +#if 0 +static std::vector getTestData_2in_2out() { + std::vector res; + + res.emplace_back(FrontendOpTestParam{PDPD, PATH_TO_MODELS, "2in_2out/2in_2out.pdmodel"}); + + return res; +} + +INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, + ::testing::ValuesIn(getTestData_2in_2out()), + FrontendOpTest::getTestCaseName); +#endif \ No newline at end of file diff --git a/ngraph/test/frontend/shared/include/op.hpp b/ngraph/test/frontend/shared/include/op.hpp new file mode 100644 index 00000000000000..b04f8bd48aee82 --- /dev/null +++ b/ngraph/test/frontend/shared/include/op.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +#include +#include "util/all_close.hpp" +#include "util/all_close_f.hpp" +#include "util/engine/test_engines.hpp" +#include "util/ndarray.hpp" +#include "util/test_case.hpp" +#include "util/test_control.hpp" +#include "util/test_tools.hpp" + +using Inputs = std::vector>; +using Outputs = std::vector>; + +struct FrontendOpTestParam { + std::string m_frontEndName; + std::string m_modelsPath; + std::string m_modelName; + + Inputs inputs; + Outputs expected_outputs; +}; + +class FrontendOpTest : public ::testing::TestWithParam { +public: + FrontendOpTestParam m_param; + + ngraph::frontend::FrontEndManager m_fem; + ngraph::frontend::FrontEnd::Ptr m_frontEnd; + ngraph::frontend::InputModel::Ptr m_inputModel; + + static std::string getTestCaseName(const testing::TestParamInfo &obj); + + void SetUp() override; + +protected: + void initParamTest(); + void doLoadFromFile(); +}; \ No newline at end of file diff --git a/ngraph/test/frontend/shared/src/op.cpp b/ngraph/test/frontend/shared/src/op.cpp new file mode 100644 index 00000000000000..b0f9705e086808 --- /dev/null +++ b/ngraph/test/frontend/shared/src/op.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include "../include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +std::string FrontendOpTest::getTestCaseName(const testing::TestParamInfo &obj) { + std::string res = obj.param.m_frontEndName + "_" + obj.param.m_modelName; + //res += "I" + joinStrings(obj.param.m_oldInputs) + joinStrings(obj.param.m_newInputs); + //res += "O" + joinStrings(obj.param.m_oldOutputs) + joinStrings(obj.param.m_newOutputs); + // need to replace special characters to create valid test case name + res = std::regex_replace(res, std::regex("[/\\.]"), "_"); + return res; +} + +void FrontendOpTest::SetUp() { + initParamTest(); +} + +void FrontendOpTest::initParamTest() { + m_param = GetParam(); + m_param.m_modelName = std::string(TEST_FILES) + m_param.m_modelsPath + m_param.m_modelName; + std::cout << "Model: " << m_param.m_modelName << std::endl; +} + +void FrontendOpTest::doLoadFromFile() { + std::vector frontends; + FrontEnd::Ptr fe; + ASSERT_NO_THROW(frontends = m_fem.availableFrontEnds()); + ASSERT_NO_THROW(m_frontEnd = m_fem.loadByFramework(m_param.m_frontEndName)); + ASSERT_NE(m_frontEnd, nullptr); + ASSERT_NO_THROW(m_inputModel = m_frontEnd->loadFromFile(m_param.m_modelName)); + ASSERT_NE(m_inputModel, nullptr); +} + +/*---------------------------------------------------------------------------------------------------------------------*/ + +using TestEngine = test::IE_CPU_Engine; + +TEST_P(FrontendOpTest, test_model_runtime) { + ASSERT_NO_THROW(doLoadFromFile()); + std::shared_ptr function; + ASSERT_NO_THROW(function = m_frontEnd->convert(m_inputModel)); + ASSERT_NE(function, nullptr); +// std::cout << "Ordered ops names\n"; +// for (const auto &n : function->get_ordered_ops()) { +// std::cout << "----" << n->get_friendly_name() << "---\n"; +// } + + Inputs inputs; + // data (1, 1, 7, 5) input tensor + inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + // filters (1, 1, 3, 3) aka convolution weights + inputs.emplace_back( + test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} + .get_vector()); + + // (1, 1, 4, 3) + auto expected_output = test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector(); + + auto test_case = test::TestCase(function); + test_case.add_multiple_inputs(inputs); + test_case.add_expected_output(expected_output); + test_case.run(); +} From 47e8717ac07322c5249132204b318dd960a11ce1 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 00:03:17 +0800 Subject: [PATCH 22/54] step2 --- ngraph/test/frontend/paddlepaddle/op.cpp | 87 +++++++++++++--------- ngraph/test/frontend/shared/include/op.hpp | 4 +- ngraph/test/frontend/shared/src/op.cpp | 60 ++++++--------- 3 files changed, 76 insertions(+), 75 deletions(-) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 9c0a4fc059cd08..361d601062961b 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -12,49 +12,68 @@ static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; using PDPDFrontendOpTest = FrontendOpTest; -#if 0 -static const std::vector models { - std::string("conv2d"), - std::string("conv2d_s/conv2d.pdmodel"), - std::string("conv2d_relu/conv2d_relu.pdmodel"), - std::string("2in_2out/2in_2out.pdmodel"), -}; - -INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, - ::testing::Combine( - ::testing::Values(PDPD), - ::testing::Values(PATH_TO_MODELS), - ::testing::ValuesIn(models)), - PDPDFrontendOpTest::getTestCaseName); - -#endif - -static FrontendOpTestParam getTestData_2in_2out() { +static FrontendOpTestParam conv2d() { FrontendOpTestParam res; res.m_frontEndName = PDPD; res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "2in_2out/2in_2out.pdmodel"; + res.m_modelName = "conv2d/"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 3, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + // (1, 5, 6, 6) + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector()); + return res; } -INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, - ::testing::Values( - getTestData_2in_2out(), - FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_s/conv2d.pdmodel" }, - FrontendOpTestParam{ PDPD, PATH_TO_MODELS, "conv2d_relu/conv2d_relu.pdmodel" } - ), - FrontendOpTest::getTestCaseName); +static FrontendOpTestParam relu() { + FrontendOpTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "relu/"; + + //Inputs inputs; + // data (1, 1, 7, 5) input tensor + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); -#if 0 -static std::vector getTestData_2in_2out() { - std::vector res; + // filters (1, 1, 3, 3) aka convolution weights + res.inputs.emplace_back( + test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} + .get_vector()); - res.emplace_back(FrontendOpTestParam{PDPD, PATH_TO_MODELS, "2in_2out/2in_2out.pdmodel"}); + // (1, 1, 4, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector()); return res; } -INSTANTIATE_TEST_CASE_P(PDPDFrontendOpTest, PDPDFrontendOpTest, - ::testing::ValuesIn(getTestData_2in_2out()), - FrontendOpTest::getTestCaseName); -#endif \ No newline at end of file +INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, + ::testing::Values( + conv2d(), + relu() + ), + FrontendOpTest::getTestCaseName); diff --git a/ngraph/test/frontend/shared/include/op.hpp b/ngraph/test/frontend/shared/include/op.hpp index b04f8bd48aee82..84c081c2f09dc5 100644 --- a/ngraph/test/frontend/shared/include/op.hpp +++ b/ngraph/test/frontend/shared/include/op.hpp @@ -16,7 +16,7 @@ #include "util/test_tools.hpp" using Inputs = std::vector>; -using Outputs = std::vector>; +using Outputs = std::vector>; struct FrontendOpTestParam { std::string m_frontEndName; @@ -41,5 +41,5 @@ class FrontendOpTest : public ::testing::TestWithParam { protected: void initParamTest(); - void doLoadFromFile(); + void validateOp(); }; \ No newline at end of file diff --git a/ngraph/test/frontend/shared/src/op.cpp b/ngraph/test/frontend/shared/src/op.cpp index b0f9705e086808..af17504ad9ad13 100644 --- a/ngraph/test/frontend/shared/src/op.cpp +++ b/ngraph/test/frontend/shared/src/op.cpp @@ -8,6 +8,8 @@ using namespace ngraph; using namespace ngraph::frontend; +using TestEngine = test::IE_CPU_Engine; + std::string FrontendOpTest::getTestCaseName(const testing::TestParamInfo &obj) { std::string res = obj.param.m_frontEndName + "_" + obj.param.m_modelName; //res += "I" + joinStrings(obj.param.m_oldInputs) + joinStrings(obj.param.m_newInputs); @@ -27,55 +29,35 @@ void FrontendOpTest::initParamTest() { std::cout << "Model: " << m_param.m_modelName << std::endl; } -void FrontendOpTest::doLoadFromFile() { - std::vector frontends; - FrontEnd::Ptr fe; - ASSERT_NO_THROW(frontends = m_fem.availableFrontEnds()); +void FrontendOpTest::validateOp() { + // load + ASSERT_NO_THROW(m_fem.availableFrontEnds()); ASSERT_NO_THROW(m_frontEnd = m_fem.loadByFramework(m_param.m_frontEndName)); ASSERT_NE(m_frontEnd, nullptr); ASSERT_NO_THROW(m_inputModel = m_frontEnd->loadFromFile(m_param.m_modelName)); ASSERT_NE(m_inputModel, nullptr); -} - -/*---------------------------------------------------------------------------------------------------------------------*/ - -using TestEngine = test::IE_CPU_Engine; -TEST_P(FrontendOpTest, test_model_runtime) { - ASSERT_NO_THROW(doLoadFromFile()); + // convert std::shared_ptr function; ASSERT_NO_THROW(function = m_frontEnd->convert(m_inputModel)); ASSERT_NE(function, nullptr); -// std::cout << "Ordered ops names\n"; -// for (const auto &n : function->get_ordered_ops()) { -// std::cout << "----" << n->get_friendly_name() << "---\n"; -// } - Inputs inputs; - // data (1, 1, 7, 5) input tensor - inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, - {5.f, 6.f, 7.f, 8.f, 9.f}, - {10.f, 11.f, 12.f, 13.f, 14.f}, - {15.f, 16.f, 17.f, 18.f, 19.f}, - {20.f, 21.f, 22.f, 23.f, 24.f}, - {25.f, 26.f, 27.f, 28.f, 29.f}, - {30.f, 31.f, 32.f, 33.f, 34.f}}}}} - .get_vector()); + // run + auto test_case = test::TestCase(function); - // filters (1, 1, 3, 3) aka convolution weights - inputs.emplace_back( - test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} - .get_vector()); + for (auto it = m_param.inputs.begin(); it != m_param.inputs.end(); it++ ) { + test_case.add_input(*it); + } + for (auto it = m_param.expected_outputs.begin(); it != m_param.expected_outputs.end(); it++) + { + test_case.add_expected_output(*it); + } + + test_case.run(); +} - // (1, 1, 4, 3) - auto expected_output = test::NDArray({{{{12.f, 27.f, 24.f}, - {63.f, 108.f, 81.f}, - {123.f, 198.f, 141.f}, - {112.f, 177.f, 124.f}}}}) - .get_vector(); +/*---------------------------------------------------------------------------------------------------------------------*/ - auto test_case = test::TestCase(function); - test_case.add_multiple_inputs(inputs); - test_case.add_expected_output(expected_output); - test_case.run(); +TEST_P(FrontendOpTest, test_model_runtime) { + ASSERT_NO_THROW(validateOp()); } From 7b590af109f31e56c03d5deb5cf51c8e372721e4 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 18:42:32 +0800 Subject: [PATCH 23/54] generate model helper and pool2d. --- .../gen_scripts/generate_pool2d.py | 81 +++++++++++++++++++ .../paddlepaddle/gen_scripts/save_model.py | 23 ++++++ 2 files changed, 104 insertions(+) create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/save_model.py diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py new file mode 100644 index 00000000000000..68095df6aef0ae --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -0,0 +1,81 @@ +# +# pool2d paddle model generator +# +import numpy as np +from save_model import saveModel + +def pool2d(name : str, x, attrs : dict): + import paddle as pdpd + pdpd.enable_static() + + exclusive = False + if 'exclusive' in attrs: + exclusive = attrs['exclusive'] + + node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') + out = pdpd.fluid.layers.pool2d(node_x, pool_size=attrs['kernel_size'], + pool_type=attrs['type'], + pool_stride=attrs['stride'], + pool_padding=attrs['pool_padding'], + global_pooling=False, + exclusive=exclusive) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + + +def main(): + data = np.array([[[ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16], + ]]]).astype(np.float32) + + # maxPool + pdpd_max_attrs = { + 'kernel_size': [3, 3], + 'type': 'max', + 'stride': 1, + 'pool_padding': 0 + } + pool2d("maxPool", data, pdpd_max_attrs) + + # maxGlobalPool + spatial_shape = np.ndim(data) - 2 + pdpd_max_global_attrs = { + 'kernel_size': [spatial_shape, spatial_shape], + 'type': 'max', + 'stride': 1, + 'pool_padding': 0, + 'global_pool': True} + + pool2d("maxGlobalPool", data, pdpd_max_global_attrs) + + # avgPool + pdpd_avg_attrs = {'kernel_size': [3, 3], + 'type': 'avg', + 'stride': 1, + 'pool_padding': 1, + 'exclusive': True} + ng_avg_attrs = { + 'kernel_size': [3, 3], + 'type': 'avg', + 'stride': [1, 1], + 'padding': [1, 1], + 'exclude_pad': True + } + pool2d("avgPool", data, pdpd_avg_attrs) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py new file mode 100644 index 00000000000000..ce22942671f935 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -0,0 +1,23 @@ + +import numpy as np +import paddle as pdpd + +def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list, **kwargv): + for key, value in kwargv.items(): + print ("%s == %s" %(key, value)) + + np.set_printoptions(precision=2) + np.set_printoptions(suppress=True) + + print("\n\n------------- %s -----------\n" % (name)) + for i, input in enumerate(inputs): + print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) + print(input) + print("\n") + for i, output in enumerate(outputs): + print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) + print(output) + + # composited model + scattered model + pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe) + pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") \ No newline at end of file From 832188afb2cf26049aba4035d30f74f2777f16b2 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 23:09:48 +0800 Subject: [PATCH 24/54] helper: save paddle model, dump inputs, outputs as C structures to facilite developer. --- .../paddlepaddle/gen_scripts/save_model.py | 69 +++++++++++++++++-- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index ce22942671f935..23e72f50c44a9f 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -2,22 +2,77 @@ import numpy as np import paddle as pdpd + +#print numpy array like C structure +def print_alike(arr): + shape = arr.shape + rank = len(shape) + print("shape: ", shape, "rank: %d" %(rank)) + + #for idx, value in np.ndenumerate(arr): + # print(idx, value) + print(arr) + + def print_array(arr, end=' '): + shape = arr.shape + rank = len(arr.shape) + if rank > 1: + #print("{") + line = "{" + for i in range(arr.shape[0]): + line += print_array(arr[i,:], end="},\n" if i < arr.shape[0]-1 else "}") + line += end + return line + else: + line = "{" + for i in range(arr.shape[0]): + line += str(arr[i]) + line += ", " if i < shape[0]-1 else ' ' + line += end + #print(line) + return line + + + print(print_array(arr, "}")) + + def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list, **kwargv): for key, value in kwargv.items(): - print ("%s == %s" %(key, value)) - - np.set_printoptions(precision=2) - np.set_printoptions(suppress=True) + print ("%s == %s" %(key, value)) print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) - print(input) + print_alike(input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) - print(output) + print_alike(output) # composited model + scattered model pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe) - pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") \ No newline at end of file + pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") + + +if __name__ == "__main__": + np.set_printoptions(precision=2) + np.set_printoptions(suppress=True) + + #x = np.random.randn(2,3).astype(np.float32) + x = np.array([[[ + [1, 2, 3], + [4, 5, 6] + ], + [ + [1, 2, 3], + [4, 5, 6] + ]], + [[ + [1, 2, 3], + [4, 5, 6] + ], + [ + [1, 2, 3], + [4, 5, 6] + ]]]).astype(np.float32) + print_alike(x) \ No newline at end of file From 88e639dd6e3dfc08cbd8f1a3b00be1f2abcb8a87 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 23:10:23 +0800 Subject: [PATCH 25/54] test op pool2d and matmul --- .../test/frontend/paddlepaddle/op/matmul.cpp | 51 +++++++++++++++++++ .../test/frontend/paddlepaddle/op/pool2d.cpp | 46 +++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 ngraph/test/frontend/paddlepaddle/op/matmul.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/pool2d.cpp diff --git a/ngraph/test/frontend/paddlepaddle/op/matmul.cpp b/ngraph/test/frontend/paddlepaddle/op/matmul.cpp new file mode 100644 index 00000000000000..35b37580d11d70 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/matmul.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using matmulTestParam = FrontendOpTestParam; +using matmulTest = FrontendOpTest; + +static matmulTestParam matmul() { + matmulTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "matmul"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 7, 5) input tensor + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + // (1, 1, 4, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}) + .get_vector()); + + return res; +} + +TEST_P(matmulTest, test_matmul) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, matmulTest, + ::testing::Values( + matmul() + ), + matmulTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp new file mode 100644 index 00000000000000..37885e73be006d --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using pool2dTestParam = FrontendOpTestParam; +using pool2dTest = FrontendOpTest; + +static pool2dTestParam maxPool() { + pool2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, + {5.0, 6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0, 12.0 }, + {13.0, 14.0, 15.0, 16.0 }}}}} + .get_vector()); + + // (1, 1, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{11.0, 12.0 }, + {15.0, 16.0 }}}}}) + .get_vector()); + + return res; +} + +TEST_P(pool2dTest, test_pool2d) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, pool2dTest, + ::testing::Values( + maxPool() + ), + pool2dTest::getTestCaseName); From cc4a6429d153bc277014838a70f7b9fc113238e8 Mon Sep 17 00:00:00 2001 From: jialipen Date: Tue, 13 Apr 2021 23:11:35 +0800 Subject: [PATCH 26/54] git ignore ngraph/test/files/paddlepaddle/models --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8cd490e3269fc6..23fe8c3d55ce89 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ ngraph/src/ngraphConfigVersion.cmake ngraph/src/protobuf/ ngraph/src/src/ ngraph/src/test/ +ngraph/test/files/paddlepaddle/models/* From 08cf44ffcd375eedca31eb9de42d1ea69f43fd06 Mon Sep 17 00:00:00 2001 From: jialipen Date: Wed, 14 Apr 2021 17:58:16 +0800 Subject: [PATCH 27/54] pool2d global_pool fix --- .../gen_scripts/generate_pool2d.py | 7 ++- .../test/frontend/paddlepaddle/op/pool2d.cpp | 51 ++++++++++++++++++- ngraph/test/frontend/shared/src/op.cpp | 2 +- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 68095df6aef0ae..0de80c0c80e75e 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -11,13 +11,16 @@ def pool2d(name : str, x, attrs : dict): exclusive = False if 'exclusive' in attrs: exclusive = attrs['exclusive'] + global_pool=False + if 'global_pool' in attrs: + global_pool = attrs['global_pool'] node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') out = pdpd.fluid.layers.pool2d(node_x, pool_size=attrs['kernel_size'], pool_type=attrs['type'], pool_stride=attrs['stride'], pool_padding=attrs['pool_padding'], - global_pooling=False, + global_pooling=global_pool, exclusive=exclusive) cpu = pdpd.static.cpu_places(1) @@ -52,7 +55,7 @@ def main(): pool2d("maxPool", data, pdpd_max_attrs) # maxGlobalPool - spatial_shape = np.ndim(data) - 2 + spatial_shape = np.ndim(data) pdpd_max_global_attrs = { 'kernel_size': [spatial_shape, spatial_shape], 'type': 'max', diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 37885e73be006d..669b078daea9c8 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -35,12 +35,59 @@ static pool2dTestParam maxPool() { return res; } +static pool2dTestParam avgPool() { + pool2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, + {5.0, 6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0, 12.0 }, + {13.0, 14.0, 15.0, 16.0 }}}}} + .get_vector()); + + // (1, 1, 4, 4) + res.expected_outputs.emplace_back(test::NDArray({{{{{3.5, 4.0, 5.0, 5.5 }, + {5.5, 6.0, 7.0, 7.5 }, + {9.5, 10.0, 11.0, 11.5 }, + {11.5, 12.0, 13.0, 13.5 }}}}}) + .get_vector()); + + return res; +} + +static pool2dTestParam maxGlobalPool() { + pool2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxGlobalPool"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, + {5.0, 6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0, 12.0 }, + {13.0, 14.0, 15.0, 16.0 }}}}} + .get_vector()); + + // (1, 1, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{16.0 }}}}}) + .get_vector()); + + return res; +} + TEST_P(pool2dTest, test_pool2d) { - ASSERT_NO_THROW(validateOp()); + validateOp(); } INSTANTIATE_TEST_CASE_P(FrontendOpTest, pool2dTest, ::testing::Values( - maxPool() + avgPool(), + maxPool(), + maxGlobalPool() ), pool2dTest::getTestCaseName); diff --git a/ngraph/test/frontend/shared/src/op.cpp b/ngraph/test/frontend/shared/src/op.cpp index af17504ad9ad13..0024c60bca83e7 100644 --- a/ngraph/test/frontend/shared/src/op.cpp +++ b/ngraph/test/frontend/shared/src/op.cpp @@ -39,7 +39,7 @@ void FrontendOpTest::validateOp() { // convert std::shared_ptr function; - ASSERT_NO_THROW(function = m_frontEnd->convert(m_inputModel)); + function = m_frontEnd->convert(m_inputModel); ASSERT_NE(function, nullptr); // run From 516ee1a0904be54b612bfad584b83ce63c322f7d Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 15 Apr 2021 21:25:14 +0800 Subject: [PATCH 28/54] pool2d basic tests --- .../frontend/paddlepaddle/src/op/pool2d.cpp | 198 +++++++++++++++--- .../gen_scripts/generate_pool2d.py | 2 +- .../test/frontend/paddlepaddle/op/pool2d.cpp | 6 +- 3 files changed, 178 insertions(+), 28 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp index ca2c82d895ef9c..412c84d3146610 100644 --- a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp @@ -22,38 +22,186 @@ namespace frontend { namespace pdpd { namespace op { +// helper func - get pad_begin and pad_end +static void get_paddings(const NodeContext& node, ngraph::Shape& pad_begin, ngraph::Shape& pad_end, ngraph::op::PadType &auto_pad) { + // + auto pad_algo = node.get_attribute("padding_algorithm"); + if (pad_algo == "SAME") { + auto_pad = ngraph::op::PadType::SAME_UPPER; + } else if (pad_algo == "VALID") { + auto_pad = ngraph::op::PadType::VALID; + } else if (pad_algo == "EXPLICIT") { + auto_pad = ngraph::op::PadType::EXPLICIT; + }else { + // FIXME + throw std::runtime_error("Unsupported pooling padding_algorithm " + pad_algo); + } + + /*如果它是一个元组或列表,它可以有3种格式: + (1)包含2个整数值:[pad_height, pad_width]; + (2)包含4个整数值:[pad_height_top, pad_height_bottom, pad_width_left, pad_width_right]; + (3)包含4个二元组: + 当 data_format 为"NCHW"时为 [[0,0], [0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right]], + 当 data_format 为"NHWC"时为[[0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right], [0,0]]。 + 若为一个整数,则表示H和W维度上均为该值。默认值:0。*/ + auto paddings = node.get_attribute>("paddings"); + auto data_format = node.get_attribute("data_format"); + + switch (paddings.size()) + { + case 1: + pad_begin = Shape(2, paddings[0]); + pad_end = pad_begin; + break; + case 2: + pad_begin = Shape{static_cast(paddings[0]), static_cast(paddings[1])}; + pad_end = pad_begin; + break; + case 4: + pad_begin = Shape{static_cast(paddings[0]), static_cast(paddings[2])}; + pad_end = Shape(static_cast(paddings[1]), static_cast(paddings[3])); + break; + case 8: + if (data_format == "NCHW") { + pad_begin = Shape{static_cast(paddings[4]), static_cast(paddings[6])}; + pad_end = Shape(static_cast(paddings[5]), static_cast(paddings[7])); + } else if (data_format == "NHWC") { + pad_begin = Shape{static_cast(paddings[2]), static_cast(paddings[4])}; + pad_end = Shape(static_cast(paddings[3]), static_cast(paddings[5])); + } else { + throw std::runtime_error("Unsupported pooling data_format " + data_format); + } + break; + default: + throw std::runtime_error("Unsupported pooling paddings " + paddings.size()); + break; + } +} + + OutputVector pool2d (const NodeContext& node) { // TODO : resolve padding according to spec - auto data = node.get_ng_input("X"); + auto data = node.get_ng_input("X"); + auto pooling_type = node.get_attribute("pooling_type"); auto global_pooling = node.get_attribute("global_pooling"); auto adaptive = node.get_attribute("adaptive"); - auto kernel_shape = node.get_attribute>("ksize"); - if (pooling_type == "max" && !global_pooling) { + auto kernel_shape = node.get_attribute>("ksize"); // FIXME: int/list? + + auto rounding_type = node.get_attribute("ceil_mode") + ? ngraph::op::RoundingType::CEIL + : ngraph::op::RoundingType::FLOOR; + + MY_ASSERT((pooling_type == "max") || (pooling_type == "avg"), + "pool2d: not supported pooling type !"); + MY_ASSERT(kernel_shape.size()==1 || kernel_shape.size()==2, + "pool2d: ksize must be 1 or 2!"); + + PartialShape input_shape = data.get_partial_shape(); + MY_ASSERT(input_shape.rank().is_static(), "pool2d: X rank must be static!"); + int32_t input_rank = input_shape.rank().get_length(); + uint64_t input_h = input_shape[input_rank-2].get_length(); + uint64_t input_w = input_shape[input_rank-1].get_length(); + std::cout << input_rank << "," << input_h << "," << input_w << std::endl; + + auto auto_pad = ngraph::op::PadType::EXPLICIT; + ngraph::Shape pad_begin, pad_end; + get_paddings(node, pad_begin, pad_end, auto_pad); + + if (global_pooling || (adaptive && + std::any_of(kernel_shape.begin(), + kernel_shape.end(), + [](int32_t i){return i==1;}))) { + if (pooling_type == "max") { + return {std::make_shared( + data, + ngraph::Strides({1,1}), + ngraph::Shape{0,0}, //FIXME pads_begin + ngraph::Shape{0,0}, //pads_end + ngraph::Shape{input_h,input_w})}; + } else { + // TODO : resolve axes according to rank + auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {2, 3}); + return {std::make_shared(data, axes, true)}; + } + } else if (adaptive) { + uint64_t pool_size_Height, pool_size_Width; + if (kernel_shape.size()==1) { + pool_size_Height = pool_size_Width = kernel_shape[0]; + } else { + pool_size_Height = kernel_shape[0]; + pool_size_Width = kernel_shape[1]; + } + + uint64_t stride_h = int64_t(input_h / pool_size_Height); + uint64_t stride_w = int64_t(input_h / pool_size_Width); + uint64_t kernel_h = input_h - (pool_size_Height - 1) * stride_h; + uint64_t kernel_w = input_w - (pool_size_Width - 1) * stride_w; + + if ( stride_h < 1 || stride_w < 1) { // upsampling? + throw std::runtime_error("Unsupported pooling adaptive type!"); + } + + if (pooling_type == "max") { + return {std::make_shared( + data, + ngraph::Strides{stride_h, stride_w}, + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + rounding_type, + auto_pad)}; + } else { + bool exclude_pad = node.get_attribute("exclusive") ? true : false; + return {std::make_shared( + data, + ngraph::Strides{stride_h, stride_w}, + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + exclude_pad, + rounding_type, + auto_pad)}; + } + } else { auto strides = node.get_attribute>("strides"); auto paddings = node.get_attribute>("paddings"); - auto rounding_type = node.get_attribute("ceil_mode") - ? ngraph::op::RoundingType::CEIL - : ngraph::op::RoundingType::FLOOR; - return {std::make_shared( - data, - ngraph::Strides(strides.begin(), strides.end()), - ngraph::Shape(paddings.begin(), paddings.end()), - ngraph::Shape(paddings.begin(), paddings.end()), - ngraph::Shape(kernel_shape.begin(), kernel_shape.end()), - rounding_type)}; - } - else if (pooling_type == "avg" && - (global_pooling || adaptive && all_of(kernel_shape.begin(), - kernel_shape.end(), - [](int32_t s) { return s == 1; }))) - { - // TODO : resolve axes according to rank - auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {2, 3}); - return {std::make_shared(data, axes, true)}; - } else { - throw std::runtime_error("Unsupported pooling type"); - } + + uint64_t kernel_h, kernel_w; + if (kernel_shape.size() == 1) { + kernel_h = kernel_w = kernel_shape[0]; + } else { + kernel_h = kernel_shape[0]; + kernel_w = kernel_shape[1]; + } + + if ((input_h > 0) && + (input_h+paddings[0] < kernel_h)) { + kernel_h = input_h+paddings[0]; + } + if ((input_w > 0) && + (input_w+paddings[1] < kernel_w)) { + kernel_w = input_w+paddings[1]; + } + + if (pooling_type == "max") { + return {std::make_shared( + data, + ngraph::Strides(strides.begin(), strides.end()), + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + rounding_type, + auto_pad)}; + } else { + bool exclude_pad = node.get_attribute("exclusive") ? true : false; + return {std::make_shared( + data, + ngraph::Strides(strides.begin(), strides.end()), + pad_begin, pad_end, + ngraph::Shape{kernel_h, kernel_w}, + exclude_pad, + rounding_type, + auto_pad)}; + } + } } }}}} \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 0de80c0c80e75e..746b02e14d1197 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -50,7 +50,7 @@ def main(): 'kernel_size': [3, 3], 'type': 'max', 'stride': 1, - 'pool_padding': 0 + 'pool_padding': 1 } pool2d("maxPool", data, pdpd_max_attrs) diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 669b078daea9c8..0d072ba5724c06 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -28,8 +28,10 @@ static pool2dTestParam maxPool() { .get_vector()); // (1, 1, 2, 2) - res.expected_outputs.emplace_back(test::NDArray({{{{{11.0, 12.0 }, - {15.0, 16.0 }}}}}) + res.expected_outputs.emplace_back(test::NDArray({{{{{6.0, 7.0, 8.0, 8.0 }, + {10.0, 11.0, 12.0, 12.0 }, + {14.0, 15.0, 16.0, 16.0 }, + {14.0, 15.0, 16.0, 16.0 }}}}}) .get_vector()); return res; From 7fe0b9cf87c8a3683b05e204986829dec6d298f9 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 15 Apr 2021 23:04:17 +0800 Subject: [PATCH 29/54] pool2d with various attributes. --- .../frontend/paddlepaddle/src/op/pool2d.cpp | 12 +- .../gen_scripts/generate_pool2d.py | 198 +++++--- .../paddlepaddle/gen_scripts/save_model.py | 8 +- .../test/frontend/paddlepaddle/op/pool2d.cpp | 445 +++++++++++++++--- 4 files changed, 507 insertions(+), 156 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp index 412c84d3146610..adf417e781fde8 100644 --- a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp @@ -37,13 +37,11 @@ static void get_paddings(const NodeContext& node, ngraph::Shape& pad_begin, ngra throw std::runtime_error("Unsupported pooling padding_algorithm " + pad_algo); } - /*如果它是一个元组或列表,它可以有3种格式: - (1)包含2个整数值:[pad_height, pad_width]; - (2)包含4个整数值:[pad_height_top, pad_height_bottom, pad_width_left, pad_width_right]; - (3)包含4个二元组: - 当 data_format 为"NCHW"时为 [[0,0], [0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right]], - 当 data_format 为"NHWC"时为[[0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right], [0,0]]。 - 若为一个整数,则表示H和W维度上均为该值。默认值:0。*/ + /*If pool padding size is a tuple or list, it could be in three forms: + [pad_height, pad_width] or [pad_height_top, pad_height_bottom, pad_width_left, pad_width_right], + and when data_format is “NCHW”, pool_padding can be in the form [[0,0], [0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right]]. + when data_format is “NHWC”, pool_padding can be in the form [[0,0], [pad_height_top, pad_height_bottom], [pad_width_left, pad_width_right], [0,0]]. + Otherwise, the pool padding size will be a square of an int.*/ auto paddings = node.get_attribute>("paddings"); auto data_format = node.get_attribute("data_format"); diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 746b02e14d1197..680c58078c8338 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -4,81 +4,147 @@ import numpy as np from save_model import saveModel +data_type = 'float32' + def pool2d(name : str, x, attrs : dict): import paddle as pdpd pdpd.enable_static() - exclusive = False - if 'exclusive' in attrs: - exclusive = attrs['exclusive'] - global_pool=False - if 'global_pool' in attrs: - global_pool = attrs['global_pool'] - - node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') - out = pdpd.fluid.layers.pool2d(node_x, pool_size=attrs['kernel_size'], - pool_type=attrs['type'], - pool_stride=attrs['stride'], - pool_padding=attrs['pool_padding'], - global_pooling=global_pool, - exclusive=exclusive) - - 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={'x': x}, - fetch_list=[out]) - - saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=data_type) + out = pdpd.fluid.layers.pool2d(node_x, + pool_size=attrs['pool_size'], + pool_type=attrs['pool_type'], + pool_stride=attrs['pool_stride'], + pool_padding=attrs['pool_padding'], + global_pooling=attrs['global_pooling'], + ceil_mode=attrs['ceil_mode'], + exclusive=attrs['exclusive'], + data_format=attrs['data_format']) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) return outs[0] def main(): - data = np.array([[[ - [1, 2, 3, 4], - [5, 6, 7, 8], - [9, 10, 11, 12], - [13, 14, 15, 16], - ]]]).astype(np.float32) - - # maxPool - pdpd_max_attrs = { - 'kernel_size': [3, 3], - 'type': 'max', - 'stride': 1, - 'pool_padding': 1 - } - pool2d("maxPool", data, pdpd_max_attrs) - - # maxGlobalPool - spatial_shape = np.ndim(data) - pdpd_max_global_attrs = { - 'kernel_size': [spatial_shape, spatial_shape], - 'type': 'max', - 'stride': 1, - 'pool_padding': 0, - 'global_pool': True} - - pool2d("maxGlobalPool", data, pdpd_max_global_attrs) - - # avgPool - pdpd_avg_attrs = {'kernel_size': [3, 3], - 'type': 'avg', - 'stride': 1, - 'pool_padding': 1, - 'exclusive': True} - ng_avg_attrs = { - 'kernel_size': [3, 3], - 'type': 'avg', - 'stride': [1, 1], - 'padding': [1, 1], - 'exclude_pad': True - } - pool2d("avgPool", data, pdpd_avg_attrs) + N, C, H, W = 2, 3, 4, 4 + data = np.arange(N*C*H*W).astype(data_type) + data_NCHW = data.reshape(N, C, H, W) + data_NHWC = data.reshape(N, H, W, C) + #print(data_NCHW, data_NCHW.shape) + + pooling_types = ['max', 'avg'] + + for i, pooling_type in enumerate(pooling_types): + # example 1: + # ceil_mode = False + pdpd_attrs = { + # input=data_NCHW, # shape: [2, 3, 8, 8] + 'pool_size' : [3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding' : [2,1], # it is same as pool_padding = [2,2,1,1] + 'global_pooling' : False, + 'ceil_mode' : False, + 'exclusive' : True, + 'data_format' : "NCHW" + } + # shape of out_1: [2, 3, 4, 3] + pool2d(pooling_type+'Pool_test1', data_NCHW, pdpd_attrs) + + # Cecilia: there is a bug of PaddlePaddle in this case. + # example 2: + # ceil_mode = True (different from example 1) + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':[[0,0], [0,0], [2,2], [1,1]], # it is same as pool_padding = [2,2,1,1] + 'global_pooling':False, + 'ceil_mode':True, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_2: [2, 3, 4, 4] which is different from out_1 + pool2d(pooling_type+'Pool_test2', data_NCHW, pdpd_attrs) + + # example 3: + # pool_padding = "SAME" (different from example 1) + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':"SAME", + 'global_pooling':False, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_3: [2, 3, 3, 3] which is different from out_1 + pool2d(pooling_type+'Pool_test3', data_NCHW, pdpd_attrs) + + # example 4: + # pool_padding = "VALID" (different from example 1) + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':"VALID", + 'global_pooling':False, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_4: [2, 3, 2, 2] which is different from out_1 + pool2d(pooling_type+'Pool_test4', data_NCHW, pdpd_attrs) + + # example 5: + # global_pooling = True (different from example 1) + # It will be set pool_size = [8,8] and pool_padding = [0,0] actually. + pdpd_attrs = { + #input=data_NCHW, + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':[2,1], + 'global_pooling':True, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NCHW" + } + # shape of out_5: [2, 3, 1, 1] which is different from out_1 + pool2d(pooling_type+'Pool_test5', data_NCHW, pdpd_attrs) + + # example 6: + # data_format = "NHWC" (different from example 1) + pdpd_attrs = { + #input=data_NHWC, # shape: [2, 8, 8, 3] + 'pool_size':[3,3], + 'pool_type' : pooling_type, + 'pool_stride' : [3,3], + 'pool_padding':[2,1], + 'global_pooling':False, + 'ceil_mode':False, + 'exclusive':True, + 'data_format':"NHWC" + } + # shape of out_6: [2, 4, 3, 3] which is different from out_1 + pool2d(pooling_type+'Pool_test6', data_NHWC, pdpd_attrs) + # + if __name__ == "__main__": main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index 23e72f50c44a9f..e01a1eb93e2cc1 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -7,17 +7,15 @@ def print_alike(arr): shape = arr.shape rank = len(shape) - print("shape: ", shape, "rank: %d" %(rank)) + #print("shape: ", shape, "rank: %d" %(rank)) #for idx, value in np.ndenumerate(arr): # print(idx, value) - print(arr) def print_array(arr, end=' '): shape = arr.shape rank = len(arr.shape) if rank > 1: - #print("{") line = "{" for i in range(arr.shape[0]): line += print_array(arr[i,:], end="},\n" if i < arr.shape[0]-1 else "}") @@ -26,7 +24,7 @@ def print_array(arr, end=' '): else: line = "{" for i in range(arr.shape[0]): - line += str(arr[i]) + line += "{:.2f}".format(arr[i]) #str(arr[i]) line += ", " if i < shape[0]-1 else ' ' line += end #print(line) @@ -43,7 +41,7 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) - print_alike(input) + #print_alike(input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 0d072ba5724c06..1d4bb8b141d613 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -10,86 +10,375 @@ using namespace ngraph::frontend; static const std::string PDPD = "pdpd"; static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; -using pool2dTestParam = FrontendOpTestParam; -using pool2dTest = FrontendOpTest; - -static pool2dTestParam maxPool() { - pool2dTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "maxPool"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 1, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, - {5.0, 6.0, 7.0, 8.0 }, - {9.0, 10.0, 11.0, 12.0 }, - {13.0, 14.0, 15.0, 16.0 }}}}} - .get_vector()); - - // (1, 1, 2, 2) - res.expected_outputs.emplace_back(test::NDArray({{{{{6.0, 7.0, 8.0, 8.0 }, - {10.0, 11.0, 12.0, 12.0 }, - {14.0, 15.0, 16.0, 16.0 }, - {14.0, 15.0, 16.0, 16.0 }}}}}) - .get_vector()); - - return res; -} +auto shared_input_NCHW = test::NDArray{{{{{0.0, 1.0, 2.0, 3.0 }, + {4.0, 5.0, 6.0, 7.0 }, + {8.0, 9.0, 10.0, 11.0 }, + {12.0, 13.0, 14.0, 15.0 }}, + {{16.0, 17.0, 18.0, 19.0 }, + {20.0, 21.0, 22.0, 23.0 }, + {24.0, 25.0, 26.0, 27.0 }, + {28.0, 29.0, 30.0, 31.0 }}, + {{32.0, 33.0, 34.0, 35.0 }, + {36.0, 37.0, 38.0, 39.0 }, + {40.0, 41.0, 42.0, 43.0 }, + {44.0, 45.0, 46.0, 47.0 }}}, + {{{48.0, 49.0, 50.0, 51.0 }, + {52.0, 53.0, 54.0, 55.0 }, + {56.0, 57.0, 58.0, 59.0 }, + {60.0, 61.0, 62.0, 63.0 }}, + {{64.0, 65.0, 66.0, 67.0 }, + {68.0, 69.0, 70.0, 71.0 }, + {72.0, 73.0, 74.0, 75.0 }, + {76.0, 77.0, 78.0, 79.0 }}, + {{80.0, 81.0, 82.0, 83.0 }, + {84.0, 85.0, 86.0, 87.0 }, + {88.0, 89.0, 90.0, 91.0 }, + {92.0, 93.0, 94.0, 95.0 }}}}} + .get_vector(); -static pool2dTestParam avgPool() { - pool2dTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "avgPool"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 1, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, - {5.0, 6.0, 7.0, 8.0 }, - {9.0, 10.0, 11.0, 12.0 }, - {13.0, 14.0, 15.0, 16.0 }}}}} - .get_vector()); - - // (1, 1, 4, 4) - res.expected_outputs.emplace_back(test::NDArray({{{{{3.5, 4.0, 5.0, 5.5 }, - {5.5, 6.0, 7.0, 7.5 }, - {9.5, 10.0, 11.0, 11.5 }, - {11.5, 12.0, 13.0, 13.5 }}}}}) - .get_vector()); - - return res; -} +auto shared_input_NHWC = test::NDArray{{{{{0.0, 1.0, 2.0 }, + {3.0, 4.0, 5.0 }, + {6.0, 7.0, 8.0 }, + {9.0, 10.0, 11.0 }}, + {{12.0, 13.0, 14.0 }, + {15.0, 16.0, 17.0 }, + {18.0, 19.0, 20.0 }, + {21.0, 22.0, 23.0 }}, + {{24.0, 25.0, 26.0 }, + {27.0, 28.0, 29.0 }, + {30.0, 31.0, 32.0 }, + {33.0, 34.0, 35.0 }}, + {{36.0, 37.0, 38.0 }, + {39.0, 40.0, 41.0 }, + {42.0, 43.0, 44.0 }, + {45.0, 46.0, 47.0 }}}, + {{{48.0, 49.0, 50.0 }, + {51.0, 52.0, 53.0 }, + {54.0, 55.0, 56.0 }, + {57.0, 58.0, 59.0 }}, + {{60.0, 61.0, 62.0 }, + {63.0, 64.0, 65.0 }, + {66.0, 67.0, 68.0 }, + {69.0, 70.0, 71.0 }}, + {{72.0, 73.0, 74.0 }, + {75.0, 76.0, 77.0 }, + {78.0, 79.0, 80.0 }, + {81.0, 82.0, 83.0 }}, + {{84.0, 85.0, 86.0 }, + {87.0, 88.0, 89.0 }, + {90.0, 91.0, 92.0 }, + {93.0, 94.0, 95.0 }}}}} + .get_vector(); -static pool2dTestParam maxGlobalPool() { - pool2dTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "maxGlobalPool"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 1, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{1.0, 2.0, 3.0, 4.0 }, - {5.0, 6.0, 7.0, 8.0 }, - {9.0, 10.0, 11.0, 12.0 }, - {13.0, 14.0, 15.0, 16.0 }}}}} - .get_vector()); - - // (1, 1, 1, 1) - res.expected_outputs.emplace_back(test::NDArray({{{{{16.0 }}}}}) - .get_vector()); - - return res; -} +/* maxPool2D */ +namespace maxPool2D { + + using maxPool2DTestParam = FrontendOpTestParam; + using maxPool2DTest = FrontendOpTest; + + static maxPool2DTestParam maxPool_test1() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test1"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{1.0, 3.0 }, + {13.0, 15.0 }}, + {{17.0, 19.0 }, + {29.0, 31.0 }}, + {{33.0, 35.0 }, + {45.0, 47.0 }}}, + {{{49.0, 51.0 }, + {61.0, 63.0 }}, + {{65.0, 67.0 }, + {77.0, 79.0 }}, + {{81.0, 83.0 }, + {93.0, 95.0 }}}}}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test2() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test2"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test3() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test3"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{5.00, 7.00 }, + {13.00, 15.00 }}, + {{21.00, 23.00 }, + {29.00, 31.00 }}, + {{37.00, 39.00 }, + {45.00, 47.00 }}}, + {{{53.00, 55.00 }, + {61.00, 63.00 }}, + {{69.00, 71.00 }, + {77.00, 79.00 }}, + {{85.00, 87.00 }, + {93.00, 95.00 }}}}}) + .get_vector()); -TEST_P(pool2dTest, test_pool2d) { - validateOp(); + return res; + } + static maxPool2DTestParam maxPool_test4() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test4"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{10.00 }}, + {{26.00 }}, + {{42.00 }}}, + {{{58.00 }}, + {{74.00 }}, + {{90.00 }}}}}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test5() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test5"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{15.00 }}, + {{31.00 }}, + {{47.00 }}}, + {{{63.00 }}, + {{79.00 }}, + {{95.00 }}}}}) + .get_vector()); + + return res; + } + static maxPool2DTestParam maxPool_test6() { + maxPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxPool_test6"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NHWC); + + // (2, 2, 2, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{{3.00, 4.00, 5.00 }, + {9.00, 10.00, 11.00 }}, + {{39.00, 40.00, 41.00 }, + {45.00, 46.00, 47.00 }}}, + {{{51.00, 52.00, 53.00 }, + {57.00, 58.00, 59.00 }}, + {{87.00, 88.00, 89.00 }, + {93.00, 94.00, 95.00 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(maxPool2DTest, test_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, maxPool2DTest, + ::testing::Values( + maxPool_test1(), + //maxPool_test2(), + maxPool_test3(), + maxPool_test4(), + maxPool_test5(), + maxPool_test6() + ), + maxPool2DTest::getTestCaseName); } -INSTANTIATE_TEST_CASE_P(FrontendOpTest, pool2dTest, - ::testing::Values( - avgPool(), - maxPool(), - maxGlobalPool() - ), - pool2dTest::getTestCaseName); +/* avgPool2D */ +namespace avgPool2D { + using avgPool2DTestParam = FrontendOpTestParam; + using avgPool2DTest = FrontendOpTest; + + static avgPool2DTestParam avgPool_test1() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test1"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{0.50, 2.50 }, + {8.50, 10.50 }}, + {{16.50, 18.50 }, + {24.50, 26.50 }}, + {{32.50, 34.50 }, + {40.50, 42.50 }}}, + {{{48.50, 50.50 }, + {56.50, 58.50 }}, + {{64.50, 66.50 }, + {72.50, 74.50 }}, + {{80.50, 82.50 }, + {88.50, 90.50 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test2() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test2"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (1, 1, 4, 4) + res.expected_outputs.emplace_back(test::NDArray({{{{{7.5 }}, + {{23.5 }}, + {{39.5 }}}, + {{{55.5 }}, + {{71.5 }}, + {{87.5 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test3() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test3"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{2.50, 4.50 }, + {10.50, 12.50 }}, + {{18.50, 20.50 }, + {26.50, 28.50 }}, + {{34.50, 36.50 }, + {42.50, 44.50 }}}, + {{{50.50, 52.50 }, + {58.50, 60.50 }}, + {{66.50, 68.50 }, + {74.50, 76.50 }}, + {{82.50, 84.50 }, + {90.50, 92.50 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test4() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test4"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{5.00 }}, + {{21.00 }}, + {{37.00 }}}, + {{{53.00 }}, + {{69.00 }}, + {{85.00 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test5() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test5"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 1, 1) + res.expected_outputs.emplace_back(test::NDArray({{{{{7.5 }}, + {{23.5 }}, + {{39.5 }}}, + {{{55.5 }}, + {{71.5 }}, + {{87.5 }}}}}) + .get_vector()); + + return res; + } + + static avgPool2DTestParam avgPool_test6() { + avgPool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test6"; //TODO: compact model/decomposited + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NHWC); + + // (2, 2, 2, 3) + res.expected_outputs.emplace_back(test::NDArray({{{{{1.5, 2.5, 3.5 }, + {7.5, 8.5, 9.5 }}, + {{25.5, 26.5, 27.5 }, + {31.5, 32.5, 33.5 }}}, + {{{49.5, 50.5, 51.5 }, + {55.5, 56.5, 57.5 }}, + {{73.5, 74.5, 75.5 }, + {79.5, 80.5, 81.5 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(avgPool2DTest, test_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, avgPool2DTest, + ::testing::Values( + avgPool_test1(), + //avgPool_test2(), + avgPool_test3(), + avgPool_test4(), + avgPool_test5(), + avgPool_test6() + ), + avgPool2DTest::getTestCaseName); +} \ No newline at end of file From 345c97fd15c62c62323bff21375db274ee1c95a1 Mon Sep 17 00:00:00 2001 From: jialipen Date: Fri, 16 Apr 2021 00:27:08 +0800 Subject: [PATCH 30/54] validate pool2d and adpative_pool2d. all attr pass, except layout NHWC. --- .../frontend/paddlepaddle/src/op/pool2d.cpp | 9 +- ngraph/frontend/paddlepaddle/src/op_table.cpp | 5 +- .../paddlepaddle/gen_scripts/save_model.py | 2 +- .../test/frontend/paddlepaddle/op/pool2d.cpp | 100 +++++++++++++++++- 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp index adf417e781fde8..a1a7852c141ef2 100644 --- a/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/pool2d.cpp @@ -30,7 +30,8 @@ static void get_paddings(const NodeContext& node, ngraph::Shape& pad_begin, ngra auto_pad = ngraph::op::PadType::SAME_UPPER; } else if (pad_algo == "VALID") { auto_pad = ngraph::op::PadType::VALID; - } else if (pad_algo == "EXPLICIT") { + } else if ((pad_algo == "EXPLICIT") || + pad_algo.empty()) { //adaptive_maxpool with no such attr. auto_pad = ngraph::op::PadType::EXPLICIT; }else { // FIXME @@ -90,6 +91,10 @@ OutputVector pool2d (const NodeContext& node) { ? ngraph::op::RoundingType::CEIL : ngraph::op::RoundingType::FLOOR; + if (pooling_type.empty()) { // TODO: to check op.type "max_pool2d_with_index" + pooling_type = "max"; + } + MY_ASSERT((pooling_type == "max") || (pooling_type == "avg"), "pool2d: not supported pooling type !"); MY_ASSERT(kernel_shape.size()==1 || kernel_shape.size()==2, @@ -119,7 +124,7 @@ OutputVector pool2d (const NodeContext& node) { ngraph::Shape{input_h,input_w})}; } else { // TODO : resolve axes according to rank - auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {2, 3}); + auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {input_rank-2, input_rank-1}); return {std::make_shared(data, axes, true)}; } } else if (adaptive) { diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index 603fee3105963f..94410240574adf 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -60,8 +60,9 @@ std::map get_supported_ops() { {"nearest_interp_v2", op::nearest_interp_v2}, {"concat", op::concat}, {"cast", op::cast}, - {"softmax", op::softmax}, - {"split", op::split} + {"split", op::split}, + {"max_pool2d_with_index", op::pool2d}, //adaptive_max_pool2d + {"softmax", op::softmax} }; }; diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index e01a1eb93e2cc1..0f5f596115f3ab 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -41,7 +41,7 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) - #print_alike(input) + print_alike(input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) diff --git a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp index 1d4bb8b141d613..96cdbfccca2505 100644 --- a/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp +++ b/ngraph/test/frontend/paddlepaddle/op/pool2d.cpp @@ -381,4 +381,102 @@ namespace avgPool2D { avgPool_test6() ), avgPool2DTest::getTestCaseName); -} \ No newline at end of file +} + +/* maxAaptivePool2D */ +namespace maxAaptivePool2D { + using maxAaptivePool2DTestParam = FrontendOpTestParam; + using maxAaptivePool2DTest = FrontendOpTest; + + static maxAaptivePool2DTestParam maxAdaptivePool_test1() { + maxAaptivePool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "maxAdaptivePool2D_test1"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{5.00, 6.00, 7.00 }, + {9.00, 10.00, 11.00 }, + {13.00, 14.00, 15.00 }}, + {{21.00, 22.00, 23.00 }, + {25.00, 26.00, 27.00 }, + {29.00, 30.00, 31.00 }}, + {{37.00, 38.00, 39.00 }, + {41.00, 42.00, 43.00 }, + {45.00, 46.00, 47.00 }}}, + {{{53.00, 54.00, 55.00 }, + {57.00, 58.00, 59.00 }, + {61.00, 62.00, 63.00 }}, + {{69.00, 70.00, 71.00 }, + {73.00, 74.00, 75.00 }, + {77.00, 78.00, 79.00 }}, + {{85.00, 86.00, 87.00 }, + {89.00, 90.00, 91.00 }, + {93.00, 94.00, 95.00 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(maxAaptivePool2DTest, test_adaptive_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, maxAaptivePool2DTest, + ::testing::Values( + maxAdaptivePool_test1() + ), + maxAaptivePool2DTest::getTestCaseName); +} + +/* avgAaptivePool2D */ +namespace avgAaptivePool2D { + using avgAaptivePool2DTestParam = FrontendOpTestParam; + using avgAaptivePool2DTest = FrontendOpTest; + + static avgAaptivePool2DTestParam avgAdaptivePool_test1() { + avgAaptivePool2DTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgAdaptivePool2D_test1"; + + // data (2, 3, 4, 4) input tensor + res.inputs.emplace_back(shared_input_NCHW); + + // (2, 3, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{2.50, 3.50, 4.50 }, + {6.50, 7.50, 8.50 }, + {10.50, 11.50, 12.50 }}, + {{18.50, 19.50, 20.50 }, + {22.50, 23.50, 24.50 }, + {26.50, 27.50, 28.50 }}, + {{34.50, 35.50, 36.50 }, + {38.50, 39.50, 40.50 }, + {42.50, 43.50, 44.50 }}}, + {{{50.50, 51.50, 52.50 }, + {54.50, 55.50, 56.50 }, + {58.50, 59.50, 60.50 }}, + {{66.50, 67.50, 68.50 }, + {70.50, 71.50, 72.50 }, + {74.50, 75.50, 76.50 }}, + {{82.50, 83.50, 84.50 }, + {86.50, 87.50, 88.50 }, + {90.50, 91.50, 92.50 }}}}}) + .get_vector()); + + return res; + } + + TEST_P(avgAaptivePool2DTest, test_adaptive_pool2d) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, avgAaptivePool2DTest, + ::testing::Values( + avgAdaptivePool_test1() + ), + avgAaptivePool2DTest::getTestCaseName); +} From 24b2ad440f5123c7a2cd1e749586fb507bf0d15e Mon Sep 17 00:00:00 2001 From: jialipen Date: Fri, 16 Apr 2021 18:17:46 +0800 Subject: [PATCH 31/54] add adaptive_pool2d generator --- .../gen_scripts/generate_pool2d.py | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py index 680c58078c8338..e353f7846f5399 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pool2d.py @@ -35,6 +35,30 @@ def pool2d(name : str, x, attrs : dict): return outs[0] +def adaptive_pool2d(name : str, x, attrs : dict): + import paddle as pdpd + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=data_type) + out = pdpd.fluid.layers.adaptive_pool2d( + input=node_x, + pool_size=attrs['pool_size'], + pool_type=attrs['pool_type'], + require_index=attrs['require_index']) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] def main(): N, C, H, W = 2, 3, 4, 4 @@ -45,6 +69,7 @@ def main(): pooling_types = ['max', 'avg'] + # pool2d for i, pooling_type in enumerate(pooling_types): # example 1: # ceil_mode = False @@ -143,7 +168,16 @@ def main(): } # shape of out_6: [2, 4, 3, 3] which is different from out_1 pool2d(pooling_type+'Pool_test6', data_NHWC, pdpd_attrs) - # + # + + # adaptive_pool2d + for i, pooling_type in enumerate(pooling_types): + pdpd_attrs = { + 'pool_size': [3,3], + 'pool_type': pooling_type, + 'require_index': False + } + adaptive_pool2d(pooling_type+'AdaptivePool2D_test1', data_NCHW, pdpd_attrs) if __name__ == "__main__": From ff4e8917b900e1b82cc5a3277bb63d756219a8ef Mon Sep 17 00:00:00 2001 From: jialipen Date: Fri, 16 Apr 2021 22:17:56 +0800 Subject: [PATCH 32/54] fuzzyOpTest: read pdmodel as well as its inputs and outputs to set up an unified test case. --- .../paddlepaddle/gen_scripts/save_model.py | 6 +- ngraph/test/frontend/paddlepaddle/op.cpp | 122 ++--- ngraph/test/frontend/shared/include/npy.hpp | 497 ++++++++++++++++++ 3 files changed, 558 insertions(+), 67 deletions(-) create mode 100644 ngraph/test/frontend/shared/include/npy.hpp diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index 0f5f596115f3ab..aab6a06d31e1a1 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -1,4 +1,4 @@ - +import os import numpy as np import paddle as pdpd @@ -42,10 +42,12 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) print_alike(input) + np.save(os.path.join("../models/"+name, "input{}".format(i)), input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) - print_alike(output) + print_alike(output) + np.save(os.path.join("../models/"+name, "output{}".format(i)), output) # composited model + scattered model pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 361d601062961b..5446d6afb849ae 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -3,6 +3,8 @@ // #include "../shared/include/op.hpp" +// library taken from https://github.com/llohse/libnpy +#include "../shared/include/npy.hpp" using namespace ngraph; using namespace ngraph::frontend; @@ -10,70 +12,60 @@ using namespace ngraph::frontend; static const std::string PDPD = "pdpd"; static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; -using PDPDFrontendOpTest = FrontendOpTest; - -static FrontendOpTestParam conv2d() { - FrontendOpTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "conv2d/"; //TODO: compact model/decomposited - - //Inputs inputs; - // data (1, 3, 4, 4) input tensor - res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, - {5.f, 6.f, 7.f, 8.f, 9.f}, - {10.f, 11.f, 12.f, 13.f, 14.f}, - {15.f, 16.f, 17.f, 18.f, 19.f}, - {20.f, 21.f, 22.f, 23.f, 24.f}, - {25.f, 26.f, 27.f, 28.f, 29.f}, - {30.f, 31.f, 32.f, 33.f, 34.f}}}}} - .get_vector()); - - // (1, 5, 6, 6) - res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, - {63.f, 108.f, 81.f}, - {123.f, 198.f, 141.f}, - {112.f, 177.f, 124.f}}}}) - .get_vector()); - - return res; -} +namespace fuzzyOp { + using PDPDFuzzyOpTest = FrontendOpTest; + using PDPDFuzzyOpTestParam = FrontendOpTestParam; -static FrontendOpTestParam relu() { - FrontendOpTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "relu/"; - - //Inputs inputs; - // data (1, 1, 7, 5) input tensor - res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, - {5.f, 6.f, 7.f, 8.f, 9.f}, - {10.f, 11.f, 12.f, 13.f, 14.f}, - {15.f, 16.f, 17.f, 18.f, 19.f}, - {20.f, 21.f, 22.f, 23.f, 24.f}, - {25.f, 26.f, 27.f, 28.f, 29.f}, - {30.f, 31.f, 32.f, 33.f, 34.f}}}}} - .get_vector()); - - // filters (1, 1, 3, 3) aka convolution weights - res.inputs.emplace_back( - test::NDArray{{{{{1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f, 1.f}}}}} - .get_vector()); - - // (1, 1, 4, 3) - res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, - {63.f, 108.f, 81.f}, - {123.f, 198.f, 141.f}, - {112.f, 177.f, 124.f}}}}) - .get_vector()); - - return res; -} + static PDPDFuzzyOpTestParam fuzzy_op() { + PDPDFuzzyOpTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "avgPool_test1"; // TODO: to read models from config file. + + auto modelpath = std::string(TEST_FILES) + res.m_modelsPath + res.m_modelName; + + auto _load_from_npy = [&](std::string name) { + auto file_path = name + ".npy"; + + std::cout << "************load_from_npy (" << file_path << ")" << std::endl; + + std::ifstream npy_file(file_path); + std::vector npy_shape; + std::vector npy_data; + if (npy_file.good()) + npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); + + return npy_data; + }; + + auto npy_input = _load_from_npy(modelpath+"/input0"); + auto npy_output = _load_from_npy(modelpath+"/output0"); + if (npy_input.empty() || npy_output.empty()) { + throw std::runtime_error("failed to load test case input/output npy file!"); + } + + // TODO: to support more inputs/outputs + std::vector data_input(npy_input.size()); + std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); -INSTANTIATE_TEST_CASE_P(FrontendOpTest, FrontendOpTest, - ::testing::Values( - conv2d(), - relu() - ), - FrontendOpTest::getTestCaseName); + std::vector data_output(npy_output.size()); + std::copy_n(npy_output.data(), npy_output.size(), data_output.begin()); + + res.inputs.emplace_back(data_input); + + res.expected_outputs.emplace_back(npy_output); + + return res; + } + + TEST_P(PDPDFuzzyOpTest, test_fuzzy) { + validateOp(); + } + + INSTANTIATE_TEST_CASE_P(FrontendOpTest, PDPDFuzzyOpTest, + ::testing::Values( + fuzzy_op() + ), + PDPDFuzzyOpTest::getTestCaseName); + +} diff --git a/ngraph/test/frontend/shared/include/npy.hpp b/ngraph/test/frontend/shared/include/npy.hpp new file mode 100644 index 00000000000000..1878215cd0954f --- /dev/null +++ b/ngraph/test/frontend/shared/include/npy.hpp @@ -0,0 +1,497 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef NPY_H +#define NPY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace npy { + +/* Compile-time test for byte order. + If your compiler does not define these per default, you may want to define + one of these constants manually. + Defaults to little endian order. */ +#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ + defined(__BIG_ENDIAN__) || \ + defined(__ARMEB__) || \ + defined(__THUMBEB__) || \ + defined(__AARCH64EB__) || \ + defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) +const bool big_endian = true; +#else +const bool big_endian = false; +#endif + + +const char magic_string[] = "\x93NUMPY"; +const size_t magic_string_length = 6; + +const char little_endian_char = '<'; +const char big_endian_char = '>'; +const char no_endian_char = '|'; + +constexpr char host_endian_char = ( big_endian ? + big_endian_char : + little_endian_char ); + +/* npy array length */ +typedef unsigned long int ndarray_len_t; + +inline void write_magic(std::ostream& ostream, unsigned char v_major=1, unsigned char v_minor=0) { + ostream.write(magic_string, magic_string_length); + ostream.put(v_major); + ostream.put(v_minor); +} + +inline void read_magic(std::istream& istream, unsigned char& v_major, unsigned char& v_minor) { + char buf[magic_string_length+2]; + istream.read(buf, magic_string_length+2); + + if(!istream) { + throw std::runtime_error("io error: failed reading file"); + } + + if (0 != std::memcmp(buf, magic_string, magic_string_length)) + throw std::runtime_error("this file does not have a valid npy format."); + + v_major = buf[magic_string_length]; + v_minor = buf[magic_string_length+1]; +} + +// typestring magic +struct Typestring { + private: + char c_endian; + char c_type; + int len; + + public: + inline std::string str() { + const size_t max_buflen = 16; + char buf[max_buflen]; + std::sprintf(buf, "%c%c%u", c_endian, c_type, len); + return std::string(buf); + } + + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'f'}, len {sizeof(float)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'f'}, len {sizeof(double)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'f'}, len {sizeof(long double)} {} + + Typestring(const std::vector& v) + :c_endian {no_endian_char}, c_type {'i'}, len {sizeof(char)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(short)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(int)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(long)} {} + Typestring(const std::vector& v) :c_endian {host_endian_char}, c_type {'i'}, len {sizeof(long long)} {} + + Typestring(const std::vector& v) + :c_endian {no_endian_char}, c_type {'u'}, len {sizeof(unsigned char)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned short)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned int)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned long)} {} + Typestring(const std::vector& v) + :c_endian {host_endian_char}, c_type {'u'}, len {sizeof(unsigned long long)} {} + + Typestring(const std::vector>& v) + :c_endian {host_endian_char}, c_type {'c'}, len {sizeof(std::complex)} {} + Typestring(const std::vector>& v) + :c_endian {host_endian_char}, c_type {'c'}, len {sizeof(std::complex)} {} + Typestring(const std::vector>& v) + :c_endian {host_endian_char}, c_type {'c'}, len {sizeof(std::complex)} {} +}; + +inline void parse_typestring( std::string typestring){ +// std::regex re ("'([<>|])([ifuc])(\\d+)'"); +// std::smatch sm; +// +// std::regex_match(typestring, sm, re ); +// +// if ( sm.size() != 4 ) { +// throw std::runtime_error("invalid typestring"); +// } +} + +namespace pyparse { + +/** + Removes leading and trailing whitespaces + */ +inline std::string trim(const std::string& str) { + const std::string whitespace = " \t"; + auto begin = str.find_first_not_of(whitespace); + + if (begin == std::string::npos) + return ""; + + auto end = str.find_last_not_of(whitespace); + + return str.substr(begin, end-begin+1); +} + + +inline std::string get_value_from_map(const std::string& mapstr) { + size_t sep_pos = mapstr.find_first_of(":"); + if (sep_pos == std::string::npos) + return ""; + + std::string tmp = mapstr.substr(sep_pos+1); + return trim(tmp); +} + +/** + Parses the string representation of a Python dict + + The keys need to be known and may not appear anywhere else in the data. + */ +inline std::unordered_map parse_dict(std::string in, std::vector& keys) { + + std::unordered_map map; + + if (keys.size() == 0) + return map; + + in = trim(in); + + // unwrap dictionary + if ((in.front() == '{') && (in.back() == '}')) + in = in.substr(1, in.length()-2); + else + throw std::runtime_error("Not a Python dictionary."); + + std::vector> positions; + + for (auto const& value : keys) { + size_t pos = in.find( "'" + value + "'" ); + + if (pos == std::string::npos) + throw std::runtime_error("Missing '"+value+"' key."); + + std::pair position_pair { pos, value }; + positions.push_back(position_pair); + } + + // sort by position in dict + std::sort(positions.begin(), positions.end() ); + + for(size_t i = 0; i < positions.size(); ++i) { + std::string raw_value; + size_t begin { positions[i].first }; + size_t end { std::string::npos }; + + std::string key = positions[i].second; + + if ( i+1 < positions.size() ) + end = positions[i+1].first; + + raw_value = in.substr(begin, end-begin); + + raw_value = trim(raw_value); + + if (raw_value.back() == ',') + raw_value.pop_back(); + + map[key] = get_value_from_map(raw_value); + } + + return map; +} + +/** + Parses the string representation of a Python boolean + */ +inline bool parse_bool(const std::string& in) { + if (in == "True") + return true; + if (in == "False") + return false; + + throw std::runtime_error("Invalid python boolan."); +} + +/** + Parses the string representation of a Python str + */ +inline std::string parse_str(const std::string& in) { + if ((in.front() == '\'') && (in.back() == '\'')) + return in.substr(1, in.length()-2); + + throw std::runtime_error("Invalid python string."); +} + +/** + Parses the string represenatation of a Python tuple into a vector of its items + */ +inline std::vector parse_tuple(std::string in) { + std::vector v; + const char seperator = ','; + + in = trim(in); + + if ((in.front() == '(') && (in.back() == ')')) + in = in.substr(1, in.length()-2); + else + throw std::runtime_error("Invalid Python tuple."); + + std::istringstream iss(in); + + for (std::string token; std::getline(iss, token, seperator);) { + v.push_back(token); + } + + return v; +} + +template +inline std::string write_tuple(const std::vector& v) { + if (v.size() == 0) + return ""; + + std::ostringstream ss; + + if (v.size() == 1) { + ss << "(" << v.front() << ",)"; + } else { + const std::string delimiter = ", "; + // v.size() > 1 + ss << "("; + std::copy(v.begin(), v.end()-1, std::ostream_iterator(ss, delimiter.c_str())); + ss << v.back(); + ss << ")"; + } + + return ss.str(); +} + +inline std::string write_boolean(bool b) { + if(b) + return "True"; + else + return "False"; +} + +} // namespace pyparse + + +inline void parse_header(std::string header, std::string& descr, bool& fortran_order, std::vector& shape) { + /* + The first 6 bytes are a magic string: exactly "x93NUMPY". + The next 1 byte is an unsigned byte: the major version number of the file format, e.g. x01. + The next 1 byte is an unsigned byte: the minor version number of the file format, e.g. x00. Note: the version of the file format is not tied to the version of the numpy package. + The next 2 bytes form a little-endian unsigned short int: the length of the header data HEADER_LEN. + The next HEADER_LEN bytes form the header data describing the array's format. It is an ASCII string which contains a Python literal expression of a dictionary. It is terminated by a newline ('n') and padded with spaces ('x20') to make the total length of the magic string + 4 + HEADER_LEN be evenly divisible by 16 for alignment purposes. + The dictionary contains three keys: + + "descr" : dtype.descr + An object that can be passed as an argument to the numpy.dtype() constructor to create the array's dtype. + "fortran_order" : bool + Whether the array data is Fortran-contiguous or not. Since Fortran-contiguous arrays are a common form of non-C-contiguity, we allow them to be written directly to disk for efficiency. + "shape" : tuple of int + The shape of the array. + For repeatability and readability, this dictionary is formatted using pprint.pformat() so the keys are in alphabetic order. + */ + + // remove trailing newline + if (header.back() != '\n') + throw std::runtime_error("invalid header"); + header.pop_back(); + + // parse the dictionary + std::vector keys { "descr", "fortran_order", "shape" }; + auto dict_map = npy::pyparse::parse_dict(header, keys); + + if (dict_map.size() == 0) + throw std::runtime_error("invalid dictionary in header"); + + std::string descr_s = dict_map["descr"]; + std::string fortran_s = dict_map["fortran_order"]; + std::string shape_s = dict_map["shape"]; + + // TODO: extract info from typestring + parse_typestring(descr_s); + // remove + descr = npy::pyparse::parse_str(descr_s); + + // convert literal Python bool to C++ bool + fortran_order = npy::pyparse::parse_bool(fortran_s); + + // parse the shape tuple + auto shape_v = npy::pyparse::parse_tuple(shape_s); + if (shape_v.size() == 0) + throw std::runtime_error("invalid shape tuple in header"); + + for ( auto item : shape_v ) { + ndarray_len_t dim = static_cast(std::stoul(item)); + shape.push_back(dim); + } +} + + +inline std::string write_header_dict(const std::string& descr, bool fortran_order, const std::vector& shape) { + std::string s_fortran_order = npy::pyparse::write_boolean(fortran_order); + std::string shape_s = npy::pyparse::write_tuple(shape); + + return "{'descr': '" + descr + "', 'fortran_order': " + s_fortran_order + ", 'shape': " + shape_s + ", }"; +} + +inline void write_header(std::ostream& out, const std::string& descr, bool fortran_order, const std::vector& shape_v) +{ + std::string header_dict = write_header_dict(descr, fortran_order, shape_v); + + size_t length = magic_string_length + 2 + 2 + header_dict.length() + 1; + + unsigned char version[2] = {1, 0}; + if (length >= 255*255) { + length = magic_string_length + 2 + 4 + header_dict.length() + 1; + version[0] = 2; + version[1] = 0; + } + size_t padding_len = 16 - length % 16; + std::string padding (padding_len, ' '); + + // write magic + write_magic(out, version[0], version[1]); + + // write header length + if (version[0] == 1 && version[1] == 0) { + char header_len_le16[2]; + uint16_t header_len = header_dict.length() + padding.length() + 1; + + header_len_le16[0] = (header_len >> 0) & 0xff; + header_len_le16[1] = (header_len >> 8) & 0xff; + out.write(reinterpret_cast(header_len_le16), 2); + }else{ + char header_len_le32[4]; + uint32_t header_len = header_dict.length() + padding.length() + 1; + + header_len_le32[0] = (header_len >> 0) & 0xff; + header_len_le32[1] = (header_len >> 8) & 0xff; + header_len_le32[2] = (header_len >> 16) & 0xff; + header_len_le32[3] = (header_len >> 24) & 0xff; + out.write(reinterpret_cast(header_len_le32), 4); + } + + out << header_dict << padding << '\n'; +} + +inline std::string read_header(std::istream& istream) { + // check magic bytes an version number + unsigned char v_major, v_minor; + read_magic(istream, v_major, v_minor); + + uint32_t header_length; + if(v_major == 1 && v_minor == 0){ + + char header_len_le16[2]; + istream.read(header_len_le16, 2); + header_length = (header_len_le16[0] << 0) | (header_len_le16[1] << 8); + + if((magic_string_length + 2 + 2 + header_length) % 16 != 0) { + // TODO: display warning + } + }else if(v_major == 2 && v_minor == 0) { + char header_len_le32[4]; + istream.read(header_len_le32, 4); + + header_length = (header_len_le32[0] << 0) | (header_len_le32[1] << 8) + | (header_len_le32[2] << 16) | (header_len_le32[3] << 24); + + if((magic_string_length + 2 + 4 + header_length) % 16 != 0) { + // TODO: display warning + } + }else{ + throw std::runtime_error("unsupported file format version"); + } + + auto buf_v = std::vector(); + buf_v.reserve(header_length); + istream.read(buf_v.data(), header_length); + std::string header(buf_v.data(), header_length); + + return header; +} + +inline ndarray_len_t comp_size(const std::vector& shape) { + ndarray_len_t size = 1; + for (ndarray_len_t i : shape ) + size *= i; + + return size; +} + +template +inline void SaveArrayAsNumpy( const std::string& filename, bool fortran_order, unsigned int n_dims, const unsigned long shape[], const std::vector& data) +{ + Typestring typestring_o(data); + std::string typestring = typestring_o.str(); + + std::ofstream stream( filename, std::ofstream::binary); + if(!stream) { + throw std::runtime_error("io error: failed to open a file."); + } + + std::vector shape_v(shape, shape+n_dims); + write_header(stream, typestring, fortran_order, shape_v); + + auto size = static_cast(comp_size(shape_v)); + + stream.write(reinterpret_cast(data.data()), sizeof(Scalar) * size); +} + + +template +inline void LoadArrayFromNumpy(const std::string& filename, std::vector& shape, std::vector& data) +{ + std::ifstream stream(filename, std::ifstream::binary); + if(!stream) { + throw std::runtime_error("io error: failed to open a file."); + } + + std::string header = read_header(stream); + + // parse header + bool fortran_order; + std::string typestr; + + parse_header(header, typestr, fortran_order, shape); + + // check if the typestring matches the given one + Typestring typestring_o {data}; + std::string expect_typestr = typestring_o.str(); + if (typestr != expect_typestr) { + throw std::runtime_error("formatting error: typestrings not matching"); + } + + + // compute the data size based on the shape + auto size = static_cast(comp_size(shape)); + data.resize(size); + + // read the data + stream.read(reinterpret_cast(data.data()), sizeof(Scalar)*size); +} + +} // namespace npy + +#endif // NPY_H From 09f51495cfa7a64f28de40aeaa4eebe5d71c9fff Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 17 Apr 2021 00:55:13 +0800 Subject: [PATCH 33/54] fuzzy_test: support both decomposed model and composed model. --- ngraph/test/frontend/paddlepaddle/op.cpp | 91 ++++++++++++++++-------- 1 file changed, 63 insertions(+), 28 deletions(-) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 5446d6afb849ae..8d45cdf357e825 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -2,33 +2,46 @@ // SPDX-License-Identifier: Apache-2.0 // -#include "../shared/include/op.hpp" +#include + +#include "util/all_close.hpp" +#include "util/all_close_f.hpp" +#include "util/engine/test_engines.hpp" +#include "util/ndarray.hpp" +#include "util/test_case.hpp" +#include "util/test_control.hpp" +#include "util/test_tools.hpp" + +#include "../shared/include/basic_api.hpp" + // library taken from https://github.com/llohse/libnpy #include "../shared/include/npy.hpp" using namespace ngraph; using namespace ngraph::frontend; +using TestEngine = test::IE_CPU_Engine; static const std::string PDPD = "pdpd"; static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; namespace fuzzyOp { - using PDPDFuzzyOpTest = FrontendOpTest; - using PDPDFuzzyOpTestParam = FrontendOpTestParam; - - static PDPDFuzzyOpTestParam fuzzy_op() { - PDPDFuzzyOpTestParam res; - res.m_frontEndName = PDPD; - res.m_modelsPath = PATH_TO_MODELS; - res.m_modelName = "avgPool_test1"; // TODO: to read models from config file. - - auto modelpath = std::string(TEST_FILES) + res.m_modelsPath + res.m_modelName; - - auto _load_from_npy = [&](std::string name) { - auto file_path = name + ".npy"; - - std::cout << "************load_from_npy (" << file_path << ")" << std::endl; - + using PDPDFuzzyOpTest = FrontEndBasicTest; + using PDPDFuzzyOpTestParam = std::tuple; // modelname + + /* + // There are 2 versions of PDPD model. + // * decomposed model, which is a folder. + // * composed model, which is a file with extension .pdmodel. + */ + static const std::vector models { + std::string("maxPool_test1/"), + std::string("avgPool_test1/avgPool_test1.pdmodel"), + }; + + void run_fuzzy(std::shared_ptr function, std::string& modelfile) { + auto _load_from_npy = [&](std::string& file_path) { std::ifstream npy_file(file_path); std::vector npy_shape; std::vector npy_data; @@ -36,10 +49,20 @@ namespace fuzzyOp { npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); return npy_data; - }; + }; - auto npy_input = _load_from_npy(modelpath+"/input0"); - auto npy_output = _load_from_npy(modelpath+"/output0"); + auto _get_modelfolder = [&](std::string& modelfile) { + size_t found = modelfile.find_last_of("/\\"); + + return modelfile.substr(0,found); + }; + + auto modelfolder = _get_modelfolder(modelfile); + + std::string input_path = modelfolder+"/input0.npy"; + std::string output_path = modelfolder+"/output0.npy"; + auto npy_input = _load_from_npy(input_path); + auto npy_output = _load_from_npy(output_path); if (npy_input.empty() || npy_output.empty()) { throw std::runtime_error("failed to load test case input/output npy file!"); } @@ -51,21 +74,33 @@ namespace fuzzyOp { std::vector data_output(npy_output.size()); std::copy_n(npy_output.data(), npy_output.size(), data_output.begin()); - res.inputs.emplace_back(data_input); + // run test + auto test_case = test::TestCase(function); - res.expected_outputs.emplace_back(npy_output); - - return res; + test_case.add_input(data_input); + test_case.add_expected_output(npy_output); + + test_case.run(); } TEST_P(PDPDFuzzyOpTest, test_fuzzy) { - validateOp(); + // load + ASSERT_NO_THROW(doLoadFromFile()); + + // convert + std::shared_ptr function; + function = m_frontEnd->convert(m_inputModel); + ASSERT_NE(function, nullptr); + + // run + run_fuzzy(function, m_modelFile); } INSTANTIATE_TEST_CASE_P(FrontendOpTest, PDPDFuzzyOpTest, - ::testing::Values( - fuzzy_op() - ), + ::testing::Combine( + ::testing::Values(PDPD), + ::testing::Values(PATH_TO_MODELS), + ::testing::ValuesIn(models)), PDPDFuzzyOpTest::getTestCaseName); } From c402bb58771b088c6612a121ff08a92e660dd487 Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 17 Apr 2021 02:13:46 +0800 Subject: [PATCH 34/54] remove the leading whitespace of getline from csv. --- ngraph/test/frontend/paddlepaddle/op.cpp | 45 +++++++++++++++---- ngraph/test/frontend/shared/src/basic_api.cpp | 1 + 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 8d45cdf357e825..8225d64844f402 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -3,6 +3,7 @@ // #include +#include #include "util/all_close.hpp" #include "util/all_close_f.hpp" @@ -35,11 +36,35 @@ namespace fuzzyOp { // * decomposed model, which is a folder. // * composed model, which is a file with extension .pdmodel. */ - static const std::vector models { - std::string("maxPool_test1/"), - std::string("avgPool_test1/avgPool_test1.pdmodel"), - }; - + bool ends_with(std::string const & value, std::string const & ending) { + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); + } + + const std::string& trim_leadingspace(std::string& str) + { + auto it = str.begin(); + for (; it != str.end() && isspace(*it); it++); + auto d = std::distance(str.begin(), it); + std::cout << d << std::endl; + return str.erase(0,d); + } + + std::vector get_models(void) { + std::string models_csv = std::string(TEST_FILES) + PATH_TO_MODELS + "models.csv"; + std::ifstream f(models_csv); + std::vector models; + std::string line; + while (getline(f, line, ',')) { + auto line_trim = trim_leadingspace(line); + std::cout<< "line in csv: " << line_trim< function, std::string& modelfile) { auto _load_from_npy = [&](std::string& file_path) { std::ifstream npy_file(file_path); @@ -51,7 +76,9 @@ namespace fuzzyOp { return npy_data; }; - auto _get_modelfolder = [&](std::string& modelfile) { + auto _get_modelfolder = [&](std::string& modelfile) { + if (!ends_with(modelfile, ".pdmodel")) return modelfile; + size_t found = modelfile.find_last_of("/\\"); return modelfile.substr(0,found); @@ -64,7 +91,7 @@ namespace fuzzyOp { auto npy_input = _load_from_npy(input_path); auto npy_output = _load_from_npy(output_path); if (npy_input.empty() || npy_output.empty()) { - throw std::runtime_error("failed to load test case input/output npy file!"); + throw std::runtime_error("failed to load input/output npy for test case. Tried " + input_path); } // TODO: to support more inputs/outputs @@ -100,7 +127,9 @@ namespace fuzzyOp { ::testing::Combine( ::testing::Values(PDPD), ::testing::Values(PATH_TO_MODELS), - ::testing::ValuesIn(models)), + //::testing::ValuesIn({std::string("maxPool_test1"), + // std::string("avgPool_test1/avgPool_test1.pdmodel")})), + ::testing::ValuesIn(get_models())), PDPDFuzzyOpTest::getTestCaseName); } diff --git a/ngraph/test/frontend/shared/src/basic_api.cpp b/ngraph/test/frontend/shared/src/basic_api.cpp index c38071163ca629..b79780db473359 100644 --- a/ngraph/test/frontend/shared/src/basic_api.cpp +++ b/ngraph/test/frontend/shared/src/basic_api.cpp @@ -11,6 +11,7 @@ using namespace ngraph::frontend; std::string FrontEndBasicTest::getTestCaseName(const testing::TestParamInfo &obj) { std::string fe, path, fileName; std::tie(fe, path, fileName) = obj.param; + std::cout <<" *** " << fe << " *** " << path << " *** " << fileName << " *** " << std::endl; // need to replace special characters to create valid test case name fileName = std::regex_replace(fileName, std::regex("[/\\.]"), "_"); return fe + "_" + fileName; From 64795a1238c94f1c1a8ca45d4606fb31e6c985df Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 17 Apr 2021 02:15:11 +0800 Subject: [PATCH 35/54] TODOs --- ngraph/test/frontend/paddlepaddle/op.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 8225d64844f402..97f7d84ae3ccb2 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -95,6 +95,7 @@ namespace fuzzyOp { } // TODO: to support more inputs/outputs + // TODO: to support different data type. std::vector data_input(npy_input.size()); std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); From be935416e17ad79389a992ce1a28b5095029bc57 Mon Sep 17 00:00:00 2001 From: mangguo Date: Thu, 15 Apr 2021 04:04:50 -0400 Subject: [PATCH 36/54] Add transpose and batch_norm unit test --- .../gen_scripts/generate_batch_norm.py | 50 +++++++++++++++++ .../gen_scripts/generate_transpose.py | 34 ++++++++++++ .../frontend/paddlepaddle/op/batch_norm.cpp | 44 +++++++++++++++ .../frontend/paddlepaddle/op/transpose2.cpp | 53 +++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_batch_norm.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_transpose.py create mode 100644 ngraph/test/frontend/paddlepaddle/op/batch_norm.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/transpose2.cpp diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_batch_norm.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_batch_norm.py new file mode 100644 index 00000000000000..d732b282600914 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_batch_norm.py @@ -0,0 +1,50 @@ +# +# pool2d paddle model generator +# +import numpy as np +from save_model import saveModel + +def batch_norm(name : str, x, scale, bias, mean, var): + import paddle as pdpd + pdpd.enable_static() + + node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') + scale_attr = pdpd.ParamAttr(name="scale", initializer=pdpd.nn.initializer.Assign(scale)) + bias_attr = pdpd.ParamAttr(name="bias", initializer=pdpd.nn.initializer.Assign(bias)) + + out = pdpd.static.nn.batch_norm(node_x, epsilon=1e-5, + param_attr=scale_attr, + bias_attr=bias_attr, + moving_mean_name="bn_mean", + moving_variance_name="bn_variance", + use_global_stats=True) + + 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()) + pdpd.static.global_scope().var("bn_mean").get_tensor().set(mean, pdpd.CPUPlace()) + pdpd.static.global_scope().var("bn_variance").get_tensor().set(var, pdpd.CPUPlace()) + + outs = exe.run( + feed={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + + +def main(): + import paddle as pdpd + data = np.array([[[[-1, 0, 1]], [[2, 3, 4]]]]).astype(np.float32) + + scale = np.array([1.0, 1.5]).astype(np.float32) + bias = np.array([0, 1]).astype(np.float32) + mean = np.array([0, 3]).astype(np.float32) + var = np.array([1, 1.5]).astype(np.float32) + + batch_norm("batch_norm", data, scale, bias, mean, var) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_transpose.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_transpose.py new file mode 100644 index 00000000000000..7371c4656b8efd --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_transpose.py @@ -0,0 +1,34 @@ +# +# pool2d paddle model generator +# +import numpy as np +from save_model import saveModel + +def transpose2(name : str, x, perm): + import paddle as pdpd + pdpd.enable_static() + + node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') + out = pdpd.transpose(node_x, perm=perm) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + + +def main(): + shape = (2, 3, 4) + data = np.random.random_sample(shape).astype(np.float32) + transpose2("transpose2", data, perm=[1,0,2]) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/frontend/paddlepaddle/op/batch_norm.cpp b/ngraph/test/frontend/paddlepaddle/op/batch_norm.cpp new file mode 100644 index 00000000000000..c737cc943a94e5 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/batch_norm.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using batchNormTestParam = FrontendOpTestParam; +using batchNormTest = FrontendOpTest; + +static batchNormTestParam batchNorm() { + batchNormTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "batch_norm"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{{-1.0, 0.0, 1.0 }}, + {{2.0, 3.0, 4.0 }}}}} + .get_vector()); + + // (1, 1, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{{-0.999995, 0.0, 0.999995 }}, + {{-0.22474074, 1.0, 2.2247407 }}}}}) + .get_vector()); + + return res; +} + +TEST_P(batchNormTest, test_batchNorm) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, batchNormTest, + ::testing::Values( + batchNorm() + ), + batchNormTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/transpose2.cpp b/ngraph/test/frontend/paddlepaddle/op/transpose2.cpp new file mode 100644 index 00000000000000..61e51688a1161d --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/transpose2.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using transpose2TestParam = FrontendOpTestParam; +using transpose2Test = FrontendOpTest; + +static transpose2TestParam transpose2() { + transpose2TestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "transpose2"; //TODO: compact model/decomposited + + //Inputs inputs; + // data (1, 1, 4, 4) input tensor + res.inputs.emplace_back(test::NDArray{{{{0.41149938, 0.8413846, 0.10664962, 0.39433905 }, + {0.25102508, 0.04060893, 0.94616824, 0.51882 }, + {0.12143327, 0.2064155, 0.6016887, 0.6604398 }}, + {{0.03658712, 0.59241855, 0.6489582, 0.7365383 }, + {0.6795765, 0.8855304, 0.6346199, 0.5214592 }, + {0.056553815, 0.6466467, 0.3580794, 0.53899676 }}} + } + .get_vector()); + + // (1, 1, 2, 2) + res.expected_outputs.emplace_back(test::NDArray({{{{0.41149938, 0.8413846, 0.10664962, 0.39433905 }, + {0.03658712, 0.59241855, 0.6489582, 0.7365383 }}, + {{0.25102508, 0.04060893, 0.94616824, 0.51882 }, + {0.6795765, 0.8855304, 0.6346199, 0.5214592 }}, + {{0.12143327, 0.2064155, 0.6016887, 0.6604398 }, + {0.056553815, 0.6466467, 0.3580794, 0.53899676 }}}}) + .get_vector()); + + return res; +} + +TEST_P(transpose2Test, test_transpose2) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, transpose2Test, + ::testing::Values( + transpose2() + ), + transpose2Test::getTestCaseName); From f4f41844e51da7f99d0bfab94a7359226f159e3b Mon Sep 17 00:00:00 2001 From: mangguo Date: Thu, 15 Apr 2021 04:13:47 -0400 Subject: [PATCH 37/54] Add transpose2 to op_table --- ngraph/frontend/paddlepaddle/src/op_table.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index 94410240574adf..31c2e9d3437592 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -30,7 +30,11 @@ #include "op/concat.hpp" #include "op/cast.hpp" #include "op/softmax.hpp" +<<<<<<< HEAD #include "op/split.h" +======= +#include "op/transpose2.hpp" +>>>>>>> 46419e77a... Add transpose2 to op_table #include "op_table.hpp" @@ -62,7 +66,8 @@ std::map get_supported_ops() { {"cast", op::cast}, {"split", op::split}, {"max_pool2d_with_index", op::pool2d}, //adaptive_max_pool2d - {"softmax", op::softmax} + {"softmax", op::softmax}, + {"transpose2", op::transpose2} }; }; From 7a1294ee27ef1a92be7f17b1c148c696c27aa594 Mon Sep 17 00:00:00 2001 From: jialipen Date: Mon, 19 Apr 2021 17:21:45 +0800 Subject: [PATCH 38/54] merge --- ngraph/frontend/paddlepaddle/src/op_table.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index 31c2e9d3437592..da50315599eddb 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -30,11 +30,8 @@ #include "op/concat.hpp" #include "op/cast.hpp" #include "op/softmax.hpp" -<<<<<<< HEAD #include "op/split.h" -======= #include "op/transpose2.hpp" ->>>>>>> 46419e77a... Add transpose2 to op_table #include "op_table.hpp" From 7b60a8f609bc3048f1d0e67a485a5be05a1a6437 Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 10 Apr 2021 00:32:45 +0800 Subject: [PATCH 39/54] feature/yolo-box implemented. validation WIP --- .../frontend/paddlepaddle/src/op/yolo_box.cpp | 283 ++++++++++++++++++ .../frontend/paddlepaddle/src/op/yolo_box.hpp | 27 ++ 2 files changed, 310 insertions(+) create mode 100644 ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/yolo_box.hpp diff --git a/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp new file mode 100644 index 00000000000000..c51163351bfc57 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp @@ -0,0 +1,283 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** +#include // std::numeric_limits + +#include +#include "yolo_box.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + using namespace opset6; + using namespace element; + +OutputVector yolo_box (const NodeContext& node_context) { + //model_name = node.output('Boxes', 0) + + auto data = node_context.get_ng_input("X"); + auto image_size = node_context.get_ng_input("ImgSize"); + + auto input_shape = data.get_partial_shape(); + int32_t input_height = input_shape[2].get_length(); + int32_t input_width = input_shape[3].get_length(); + + int32_t class_num = node_context.get_attribute("class_num"); + //PDPD anchors attribute is of type int32. Convert to float for computing convinient. + auto _anchors = node_context.get_attribute>("anchors"); + std::vector anchors; + anchors.resize(_anchors.size()); + std::transform(_anchors.begin(), _anchors.end(), anchors.begin(), [](int i) {return static_cast(i); }); + + int32_t num_anchors = anchors.size()/2; + + auto default_scale = 1.0f; + auto scale_x_y = node_context.get_attribute("scale_x_y", default_scale); + auto downsample_ratio = node_context.get_attribute("downsample_ratio"); + auto input_size = input_height * downsample_ratio; + + auto conf_thresh = node_context.get_attribute("conf_thresh"); + std::vector conf_thresh_mat((float)num_anchors * input_height * input_width, conf_thresh); + + std::vector score_shape {1, input_height * input_width * num_anchors, class_num}; + + std::cout << "input_height: " << input_height << " input_width: " << input_width << " input_size: " << input_size<< std::endl; + std::cout << "num_anchors: " << num_anchors << " scale_x_y: " << scale_x_y << std::endl; + std::cout << "downsample_ratio: " << downsample_ratio << " conf_thresh: " << conf_thresh << std::endl; + std::cout << "class_num: " << class_num << " image_size: " << image_size << std::endl; + + // main X + auto node_x_shape = Constant::create(i64, {5}, + {1, num_anchors, 5 + class_num, input_height, input_width}); + + auto node_x_reshape = std::make_shared(data, node_x_shape, false); + + auto node_input_order = Constant::create(i64, {5}, {0, 1, 3, 4, 2}); + auto node_x_transpose = std::make_shared(node_x_reshape, node_input_order); + + // range x/y + std::vector range_x, range_y; + for (size_t i = 0; i < input_width; i++) + { + range_x.push_back(i); + } + for (size_t j = 0; j < input_height; j++) + { + range_y.push_back(j); + } + auto node_range_x = Constant::create(f32, {range_x.size()}, range_x); + auto node_range_y = Constant::create(f32, {range_y.size()}, range_y); + + auto node_range_x_new_shape = Constant::create(i64, {2}, {1, input_width}); + auto node_range_y_new_shape = Constant::create(i64, {2}, {input_height, 1}); + + auto node_range_x_reshape = std::make_shared(node_range_x, node_range_x_new_shape, false); + auto node_range_y_reshape = std::make_shared(node_range_y, node_range_y_new_shape, false); + + auto node_grid_x = std::make_shared(node_range_x_reshape, node_range_y_new_shape); + auto node_grid_y = std::make_shared(node_range_y_reshape, node_range_x_new_shape); + + // main X (part2) + auto node_split_axis = Constant::create(i64, {1}, {-1}); + auto node_split_lengths = Constant::create(i64, {6}, {1, 1, 1, 1, 1, class_num}); + auto node_split_input = std::make_shared(node_x_transpose, node_split_axis, node_split_lengths); + + auto node_box_x = node_split_input->output(0); + auto node_box_y = node_split_input->output(1); + auto node_box_w = node_split_input->output(2); + auto node_box_h = node_split_input->output(3); + auto node_conf = node_split_input->output(4); + auto node_prob = node_split_input->output(5); + + // x/y + std::shared_ptr node_box_x_sigmoid = std::make_shared(node_box_x); + std::shared_ptr node_box_y_sigmoid = std::make_shared(node_box_y); + + if (scale_x_y != default_scale) { //FIXME: float compare + // TODO + float bias_x_y = -0.5 * (scale_x_y - 1.0); + + auto scale_x_y_node = Constant::create(f32, {1}, {scale_x_y}); + auto bias_x_y_node = Constant::create(f32, {1}, {bias_x_y}); + + node_box_x_sigmoid = std::make_shared(node_box_x_sigmoid, scale_x_y_node); + node_box_x_sigmoid = std::make_shared(node_box_x_sigmoid, bias_x_y_node); + + node_box_y_sigmoid = std::make_shared(node_box_y_sigmoid, scale_x_y_node); + node_box_y_sigmoid = std::make_shared(node_box_y_sigmoid, bias_x_y_node); + } + + auto squeeze_box_x = Constant::create(i64, {1}, {4}); + auto node_box_x_squeeze = std::make_shared(node_box_x_sigmoid, squeeze_box_x); + + auto squeeze_box_y = Constant::create(i64, {1}, {4}); + auto node_box_y_squeeze = std::make_shared(node_box_y_sigmoid, squeeze_box_y); + + auto node_box_x_add_grid = std::make_shared(node_grid_x, node_box_x_squeeze); + auto node_box_y_add_grid = std::make_shared(node_grid_y, node_box_y_squeeze); + + auto node_input_h = Constant::create(f32, {1}, {(float)input_height}); + auto node_input_w = Constant::create(f32, {1}, {(float)input_width}); + + auto node_box_x_encode = std::make_shared(node_box_x_add_grid, node_input_w); + auto node_box_y_encode = std::make_shared(node_box_y_add_grid, node_input_h); + + // w/h + auto node_anchor_tensor = Constant::create(f32, {anchors.size()}, anchors); //FIXME:Paddle2ONNX use float! + + auto node_anchor_shape = Constant::create(i64, {2}, {num_anchors, 2}); + auto node_anchor_tensor_reshape = std::make_shared(node_anchor_tensor, node_anchor_shape, false); + + auto node_input_size = Constant::create(f32, {1}, {(float)input_size}); + auto node_anchors_div_input_size = std::make_shared(node_anchor_tensor_reshape, node_input_size); + + auto split_axis = Constant::create(i32, {}, {1}); + auto node_anchor_split = std::make_shared(node_anchors_div_input_size, split_axis, 2); + + auto node_anchor_w = node_anchor_split->output(0); + auto node_anchor_h = node_anchor_split->output(1); + + auto node_new_anchor_shape = Constant::create(i64, {4}, {1, num_anchors, 1, 1}); + auto node_anchor_w_reshape = std::make_shared(node_anchor_w, node_new_anchor_shape, false); + auto node_anchor_h_reshape = std::make_shared(node_anchor_h, node_new_anchor_shape, false); + + auto squeeze_box_wh = Constant::create(i64, {1}, {4}); + auto node_box_w_squeeze = std::make_shared(node_box_w, squeeze_box_wh); + auto node_box_h_squeeze = std::make_shared(node_box_h, squeeze_box_wh); + + auto node_box_w_exp = std::make_shared(node_box_w_squeeze); + auto node_box_h_exp = std::make_shared(node_box_h_squeeze); + + auto node_box_w_encode = std::make_shared(node_box_w_exp, node_anchor_w_reshape); + auto node_box_h_encode = std::make_shared(node_box_h_exp, node_anchor_h_reshape); + + // confidence + auto node_conf_sigmoid = std::make_shared(node_conf); + + auto node_conf_thresh = Constant::create(f32, {conf_thresh_mat.size()}, conf_thresh_mat); + auto node_conf_shape = Constant::create(i64, {5}, {1, num_anchors, input_height, input_width, 1}); + auto node_conf_thresh_reshape = std::make_shared(node_conf_thresh, node_conf_shape, false); + + auto node_conf_sub = std::make_shared(node_conf_sigmoid, node_conf_thresh_reshape); + + auto node_conf_clip = std::make_shared(node_conf_sub, 0.0f, std::numeric_limits::max()); //FIXME: PDPD not specify min/max + + auto node_zeros = Constant::create(f32, {1}, {0}); + auto node_conf_clip_bool = std::make_shared(node_conf_clip, node_zeros); + + auto node_conf_clip_cast = std::make_shared(node_conf_clip_bool, f32); //FIMXE: to=1 + + auto node_conf_set_zero = std::make_shared(node_conf_sigmoid, node_conf_clip_cast); + + /* probability */ + auto node_prob_sigmoid = std::make_shared(node_prob); + + auto node_new_shape = Constant::create(i64, {5}, {1, int(num_anchors), input_height, input_width, 1}); + auto node_conf_new_shape = std::make_shared(node_conf_set_zero, node_new_shape, false); + + // broadcast confidence * probability of each category + auto node_score = std::make_shared(node_prob_sigmoid, node_conf_new_shape); + + // for bbox which has object (greater than threshold) + auto node_conf_bool = std::make_shared(node_conf_new_shape, node_zeros); + + auto node_box_x_new_shape = std::make_shared(node_box_x_encode, node_new_shape, false); + auto node_box_y_new_shape = std::make_shared(node_box_y_encode, node_new_shape, false); + auto node_box_w_new_shape = std::make_shared(node_box_w_encode, node_new_shape, false); + auto node_box_h_new_shape = std::make_shared(node_box_h_encode, node_new_shape, false); + auto node_pred_box = std::make_shared(OutputVector{node_box_x_new_shape, node_box_y_new_shape, + node_box_w_new_shape, node_box_h_new_shape}, 4); + + auto node_conf_cast = std::make_shared(node_conf_bool, f32); //FIMXE: to=1 + + auto node_pred_box_mul_conf = std::make_shared(node_pred_box, node_conf_cast); //(1,3,19,19,4) (1,3,19,19,1) + + auto node_box_shape = Constant::create(i64, {3}, {1, int(num_anchors) * input_height * input_width, 4}); + auto node_pred_box_new_shape = std::make_shared(node_pred_box_mul_conf, node_box_shape, false); //(1,3*19*19,4) + + auto pred_box_split_axis = Constant::create(i32, {}, {2}); + auto node_pred_box_split = std::make_shared(node_pred_box_new_shape, pred_box_split_axis, 4); + + auto node_pred_box_x = node_pred_box_split->output(0); + auto node_pred_box_y = node_pred_box_split->output(1); + auto node_pred_box_w = node_pred_box_split->output(2); + auto node_pred_box_h = node_pred_box_split->output(3); + + /* x,y,w,h -> x1,y1,x2,y2 */ + auto node_number_two = Constant::create(f32, {1}, {2.0f}); + auto node_half_w = std::make_shared(node_pred_box_w, node_number_two); + auto node_half_h = std::make_shared(node_pred_box_h, node_number_two); + + auto node_pred_box_x1 = std::make_shared(node_pred_box_x, node_half_w); + auto node_pred_box_y1 = std::make_shared(node_pred_box_y, node_half_h); + + auto node_pred_box_x2 = std::make_shared(node_pred_box_x, node_half_w); + auto node_pred_box_y2 = std::make_shared(node_pred_box_y, node_half_h); + + /* map normalized coords to original image */ + auto squeeze_image_size_axes = Constant::create(i64, {1}, {0}); + auto node_sqeeze_image_size = std::make_shared(image_size, squeeze_image_size_axes); // input ImgSize + + auto image_size_split_axis = Constant::create(i32, {}, {-1}); + auto node_image_size_split = std::make_shared(node_sqeeze_image_size, image_size_split_axis, 2); + auto node_img_height = node_image_size_split->output(0); + auto node_img_width = node_image_size_split->output(1); + + auto node_img_width_cast = std::make_shared(node_img_width, f32); //FIMXE: to=1 + auto node_img_height_cast = std::make_shared(node_img_height, f32); + + auto node_pred_box_x1_decode = std::make_shared(node_pred_box_x1, node_img_width_cast); + auto node_pred_box_y1_decode = std::make_shared(node_pred_box_y1, node_img_height_cast); + auto node_pred_box_x2_decode = std::make_shared(node_pred_box_x2, node_img_width_cast); + auto node_pred_box_y2_decode = std::make_shared(node_pred_box_y2, node_img_height_cast); + + auto node_number_one = Constant::create(f32, {1}, {1.0}); + auto node_new_img_height = std::make_shared(node_img_height_cast, node_number_one); + auto node_new_img_width = std::make_shared(node_img_height_cast, node_number_one); + auto node_pred_box_x2_sub_w = std::make_shared(node_pred_box_x2_decode, node_number_one); //x2 - (w-1) + auto node_pred_box_y2_sub_h = std::make_shared(node_pred_box_y2_decode, node_number_one); //y2 - (h-1) + + /* opset_11 */ + auto max_const = std::numeric_limits::max(); + auto node_pred_box_x1_clip = std::make_shared(node_pred_box_x1_decode, 0.0f, max_const); + auto node_pred_box_y1_clip = std::make_shared(node_pred_box_y1_decode, 0.0f, max_const); + auto node_pred_box_x2_clip = std::make_shared(node_pred_box_x2_sub_w, 0.0f, max_const); + auto node_pred_box_y2_clip = std::make_shared(node_pred_box_y2_sub_h, 0.0f, max_const); + + auto node_pred_box_x2_res = std::make_shared(node_pred_box_x2_decode, node_pred_box_x2_clip); + auto node_pred_box_y2_res = std::make_shared(node_pred_box_y2_decode, node_pred_box_y2_clip); + + auto node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_clip, node_pred_box_y1_clip, + node_pred_box_x2_res, node_pred_box_y2_res}, -1); //outputs=node.output('Boxes') + + auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); + auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') + +#if 1 + return OutputVector{node_pred_box_result, node_score_new_shape}; +#else + //FIXME: combine the two output nodes into 1, to satisfy frontend/pdpd. + auto node_result_concat = std::make_shared(OutputVector{node_pred_box_result, node_score_new_shape}, 2); + + auto result_split_axis = Constant::create(i64, {1}, {2}); //(1,xx,6) -> bboxes(1,xx,4) and scores(1,xx,class_num) + auto result_split_axes_lengths = Constant::create(i64, {2}, {4, class_num}); + auto node_result = std::make_shared(node_result_concat, result_split_axis, result_split_axes_lengths); + //return OutputVector{node_result}; + return node_result->outputs(); +#endif +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/yolo_box.hpp b/ngraph/frontend/paddlepaddle/src/op/yolo_box.hpp new file mode 100644 index 00000000000000..062677bbe8c422 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/yolo_box.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector yolo_box (const NodeContext& node); + +}}}} \ No newline at end of file From 66c9b53d16db89a27cd38cf1fa7b86761b5c249b Mon Sep 17 00:00:00 2001 From: jialipen Date: Sat, 10 Apr 2021 00:33:14 +0800 Subject: [PATCH 40/54] op_table:yolo-box --- ngraph/frontend/paddlepaddle/src/op_table.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index da50315599eddb..aa8f343242f516 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -32,6 +32,8 @@ #include "op/softmax.hpp" #include "op/split.h" #include "op/transpose2.hpp" +#include "op/yolo_box.hpp" +#include "op/multiclass_nms.hpp" #include "op_table.hpp" @@ -65,6 +67,8 @@ std::map get_supported_ops() { {"max_pool2d_with_index", op::pool2d}, //adaptive_max_pool2d {"softmax", op::softmax}, {"transpose2", op::transpose2} + {"yolo_box", op::yolo_box}, + {"multiclass_nms3", op::multiclass_nms} }; }; From 476d56c961ea03f4b43730c1325bfcef693ecd99 Mon Sep 17 00:00:00 2001 From: jialipen Date: Mon, 19 Apr 2021 18:18:36 +0800 Subject: [PATCH 41/54] fix compiling error --- ngraph/frontend/paddlepaddle/src/op_table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index aa8f343242f516..a6d25f0c82a3cd 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -66,7 +66,7 @@ std::map get_supported_ops() { {"split", op::split}, {"max_pool2d_with_index", op::pool2d}, //adaptive_max_pool2d {"softmax", op::softmax}, - {"transpose2", op::transpose2} + {"transpose2", op::transpose2}, {"yolo_box", op::yolo_box}, {"multiclass_nms3", op::multiclass_nms} }; From 2c9c954b3f7ba89dd7b338171a4409fc57d87384 Mon Sep 17 00:00:00 2001 From: jialipen Date: Mon, 19 Apr 2021 21:08:12 +0800 Subject: [PATCH 42/54] yolo_box generator --- .../gen_scripts/generate_yolo_box.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py new file mode 100644 index 00000000000000..c66a0490954c9c --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py @@ -0,0 +1,62 @@ +# +# pool2d paddle model generator +# +import numpy as np +from save_model import saveModel + +data_type = 'float32' + +def yolo_box(name : str, x, img_size, attrs : dict): + import paddle as pdpd + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=data_type) + node_img_size = pdpd.static.data(name='img_size', shape=img_size.shape, dtype='int32') + boxes, scores = pdpd.vision.ops.yolo_box(node_x, + node_img_size, + anchors=attrs['anchors'], + class_num=attrs['class_num'], + conf_thresh=attrs['conf_thresh'], + downsample_ratio=attrs['downsample_ratio'], + clip_bbox=attrs['clip_bbox'], + name=None, + scale_x_y=attrs['scale_x_y']) + + 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={'x': x, 'img_size': img_size}, + fetch_list=[boxes, scores]) + + saveModel(name, exe, feedkeys=['x', 'img_size'], fetchlist=[boxes, scores], inputs=[x, img_size], outputs=outs) + + return + +def main(): + # yolo_box + pdpd_attrs = { + 'anchors': [116, 90, 156, 198, 373, 326], + 'class_num': 2, + 'conf_thresh': 0.80, + 'downsample_ratio': 32, + 'clip_bbox': True, + 'scale_x_y': 1.0 + } + + num_anchors = int(len(pdpd_attrs['anchors'])/2) + N, C, H, W = 1, (num_anchors * (5+pdpd_attrs['class_num'])), 3, 3 + + data = np.arange(N*C*H*W).astype(data_type) + data_NCHW = data.reshape(N, C, H, W) + data_ImSize = np.arange(N*2).astype('int32').reshape(N, 2) + print(data_NCHW.shape) + + yolo_box('yolo_box_test1', data_NCHW, data_ImSize, pdpd_attrs) + + +if __name__ == "__main__": + main() \ No newline at end of file From c84b53718588e6a100b0dd823ce25beceb75856b Mon Sep 17 00:00:00 2001 From: jialipen Date: Mon, 19 Apr 2021 21:08:37 +0800 Subject: [PATCH 43/54] fix issue: if model dir not exist, create one. --- .../files/paddlepaddle/gen_scripts/save_model.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index aab6a06d31e1a1..eb1c2398779f8d 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -36,22 +36,26 @@ def print_array(arr, end=' '): def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list, **kwargv): for key, value in kwargv.items(): - print ("%s == %s" %(key, value)) + print ("%s == %s" %(key, value)) + + model_dir = "../models/"+name + if not os.path.exists(model_dir): + os.makedirs(model_dir) print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) print_alike(input) - np.save(os.path.join("../models/"+name, "input{}".format(i)), input) + np.save(os.path.join(model_dir, "input{}".format(i)), input) print("\n") for i, output in enumerate(outputs): print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) print_alike(output) - np.save(os.path.join("../models/"+name, "output{}".format(i)), output) + np.save(os.path.join(model_dir, "output{}".format(i)), output) # composited model + scattered model - pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe) - pdpd.fluid.io.save_inference_model("../models/"+name, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") + pdpd.fluid.io.save_inference_model(model_dir, feedkeys, fetchlist, exe) + pdpd.fluid.io.save_inference_model(model_dir, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") if __name__ == "__main__": From 52bf5f911649dc2ef840707123bdd9ceda03972d Mon Sep 17 00:00:00 2001 From: Zhang Yi3 Date: Tue, 20 Apr 2021 10:13:54 +0800 Subject: [PATCH 44/54] add test for assign_value, bmm, conv2d fix bug in matmul support group conv --- .../frontend/paddlepaddle/src/op/conv2d.cpp | 54 +++-- .../frontend/paddlepaddle/src/op/matmul.cpp | 1 + .../gen_scripts/generate_assign_value.py | 32 +++ .../paddlepaddle/gen_scripts/generate_bmm.py | 36 ++++ .../generate_conv2d_combinations.py | 146 +++++++++++++ .../gen_scripts/generate_interpolate.py | 111 ++++++++++ .../frontend/paddlepaddle/op/assign_value.cpp | 45 ++++ ngraph/test/frontend/paddlepaddle/op/bmm.cpp | 56 +++++ .../test/frontend/paddlepaddle/op/conv2d.cpp | 201 ++++++++++++++++++ .../frontend/paddlepaddle/op/interpolate.cpp | 190 +++++++++++++++++ 10 files changed, 855 insertions(+), 17 deletions(-) create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_assign_value.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_bmm.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_conv2d_combinations.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_interpolate.py create mode 100644 ngraph/test/frontend/paddlepaddle/op/assign_value.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/bmm.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/conv2d.cpp create mode 100644 ngraph/test/frontend/paddlepaddle/op/interpolate.cpp diff --git a/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp b/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp index 6930edb1ce3b6f..351a81488d3e9a 100644 --- a/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/conv2d.cpp @@ -15,6 +15,7 @@ //***************************************************************************** #include +#include #include "conv2d.hpp" namespace ngraph { @@ -90,24 +91,43 @@ std::pair get_pads(const NodeContext& node) OutputVector conv2d (const NodeContext& node) { auto data = node.get_ng_input("Input"); - auto filter = node.get_ng_input("Filter"); + auto filters = node.get_ng_input("Filter"); // TODO: resolve padding according to spec - auto strides = node.get_attribute>("strides"); - auto dilations = node.get_attribute>("dilations"); - auto auto_pad_type = get_auto_pad(node); - auto paddings = get_pads(node); - auto pads_begin = paddings.first; - auto pads_end = paddings.second; - - - return {std::make_shared( - data, - filter, - ngraph::Strides(strides.begin(), strides.end()), - pads_begin, - pads_end, - ngraph::Strides(dilations.begin(), dilations.end()), - auto_pad_type)}; + const auto strides = node.get_attribute>("strides"); + const auto dilations = node.get_attribute>("dilations"); + const auto auto_pad_type = get_auto_pad(node); + const auto paddings = get_pads(node); + const auto pads_begin = paddings.first; + const auto pads_end = paddings.second; + const auto groups = node.get_attribute("groups"); + + if (groups > 1) { + auto filters_shape = filters.get_shape(); + filters_shape.at(0) = filters_shape.at(0) / groups; + filters_shape.insert(filters_shape.begin(), groups); + + const auto reshaped_filters = + ngraph::builder::opset1::reshape(filters, filters_shape); + return {std::make_shared( + data, + reshaped_filters, + ngraph::Strides(strides.begin(), strides.end()), + pads_begin, + pads_end, + ngraph::Strides(dilations.begin(), dilations.end()), + auto_pad_type)}; + } + else + { + return {std::make_shared( + data, + filters, + ngraph::Strides(strides.begin(), strides.end()), + pads_begin, + pads_end, + ngraph::Strides(dilations.begin(), dilations.end()), + auto_pad_type)}; + } } }}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/matmul.cpp b/ngraph/frontend/paddlepaddle/src/op/matmul.cpp index d7ac841f29f6ba..79ec09ee9b6b1b 100644 --- a/ngraph/frontend/paddlepaddle/src/op/matmul.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/matmul.cpp @@ -30,6 +30,7 @@ namespace op { auto transpose_a = node.get_attribute("transpose_a"); auto transpose_b = node.get_attribute("transpose_b"); auto mm = std::make_shared(x, y, transpose_a, transpose_b); + alpha = alpha ? alpha : 1; auto alpha_node = ngraph::opset6::Constant::create(ngraph::element::f32, {1}, {alpha}); return {std::make_shared(mm, alpha_node)}; } diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_assign_value.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_assign_value.py new file mode 100644 index 00000000000000..f9371b1270e26d --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_assign_value.py @@ -0,0 +1,32 @@ +import numpy as np +from save_model import saveModel + +def pdpd_assign_value(test_x): + import paddle as pdpd + pdpd.enable_static() + node_x = pdpd.static.data(name='x', shape=test_x.shape, dtype='float32') + const_value = pdpd.assign(test_x, output=None) + add_node = pdpd.add(node_x, const_value); + result = pdpd.static.nn.batch_norm(add_node, use_global_stats=True, epsilon=0) + 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={'x': test_x}, + fetch_list=[result] + ) + pdpd.static.save_inference_model("../models/paddle_assign_value", + [node_x], [result], exe) + saveModel("paddle_assign_value", exe, feedkeys=['x'], fetchlist=[result], inputs=[test_x], outputs=[outs[0]]) + + print(outs[0]) + + +def compare(): + x = np.ones([1, 1, 4, 4]).astype(np.float32) + pdpd_result = pdpd_assign_value(x) + + +if __name__ == "__main__": + compare() diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_bmm.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_bmm.py new file mode 100644 index 00000000000000..8016ee6cd956f5 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_bmm.py @@ -0,0 +1,36 @@ +import numpy as np +from save_model import saveModel + +def pdpd_bmm(x1, x2): + import paddle as pdpd + + pdpd.enable_static() + node_x1 = pdpd.static.data(name='x1', shape=x1.shape, dtype=x1.dtype) + node_x2 = pdpd.static.data(name='x2', shape=x2.shape, dtype=x2.dtype) + bmm_node = pdpd.bmm(node_x1, node_x2) + result = pdpd.static.nn.batch_norm(bmm_node, use_global_stats=True, epsilon=0) + + 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={'x1': x1, 'x2': x2}, + fetch_list=[result]) + saveModel("paddle_bmm", exe, feedkeys=['x1', 'x2'], fetchlist=[result], inputs=[x1, x2], outputs=[outs[0]]) + + return outs[0] + +if __name__ == "__main__": + input1 = np.array([[[0., 1., 2., 3., 4.], # (1, 1, 7, 5) input tensor + [5., 6., 7., 8., 9.], + [10., 11., 12., 13., 14.], + [15., 16., 17., 18., 19.], + [20., 21., 22., 23., 24.], + [25., 26., 27., 28., 29.], + [30., 31., 32., 33., 34.,]]]).astype(np.float32) + + input2 = np.ones([1, 5, 7]).astype('float32') + pdpd_result = pdpd_bmm(input1, input2) + print(pdpd_result) \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_conv2d_combinations.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_conv2d_combinations.py new file mode 100644 index 00000000000000..db2809ca29c8cd --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_conv2d_combinations.py @@ -0,0 +1,146 @@ +import numpy as np +import paddle as pdpd +pdpd.enable_static() +from save_model import saveModel + +def run_and_save_model(input_x, name, feed, fetch_list, main_prog, start_prog): + cpu = pdpd.static.cpu_places(1) + exe = pdpd.static.Executor(cpu[0]) + exe.run(start_prog) + outs = exe.run( + feed={'x': input_x}, + fetch_list=fetch_list, + program=main_prog) + + print(outs) + pdpd.static.save_inference_model("../models/" + name, + [feed], [fetch_list], exe, program=main_prog) + with pdpd.static.program_guard(main_prog, start_prog): + saveModel(name, exe, feedkeys=['x'], fetchlist=fetch_list, inputs=[input_x], outputs=[outs[0]]) + + + +def pdpd_conv2d(input_x, name, input_shape, kernel, dilation, padding, stride, groups=1, use_cudnn=True): + main_program = pdpd.static.Program() + startup_program = pdpd.static.Program() + with pdpd.static.program_guard(main_program, startup_program): + data = pdpd.static.data(name='x', shape=input_shape, dtype='float32') + weight_attr = pdpd.ParamAttr(name="conv2d_weight", initializer=pdpd.nn.initializer.Assign(kernel)) + conv2d = pdpd.static.nn.conv2d(input=data, num_filters=kernel.shape[0], filter_size=kernel.shape[2:4], + padding=padding, param_attr=weight_attr, dilation=dilation, stride=stride, groups=groups, use_cudnn=use_cudnn) + run_and_save_model(input_x, name, data, conv2d, main_program, startup_program) + + +if __name__ == "__main__": + + test_cases =[ + { + "input_x": np.array([[[[0., 1., 2., 3., 4.], # (1, 1, 7, 5) input tensor + [5., 6., 7., 8., 9.], + [10., 11., 12., 13., 14.], + [15., 16., 17., 18., 19.], + [20., 21., 22., 23., 24.], + [25., 26., 27., 28., 29.], + [30., 31., 32., 33., 34.,]]]]).astype(np.float32), + "name": "paddle_conv2d_SAME_padding", + "input_shape": [1, 1, 7, 5], + "kernel": np.array([[[[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]]]]).astype(np.float32), + "dilation": 1, + "padding": "SAME", + "stride" : 2, + }, + { + "input_x": np.array([[[[0., 1., 2., 3., 4.], # (1, 1, 7, 5) input tensor + [5., 6., 7., 8., 9.], + [10., 11., 12., 13., 14.], + [15., 16., 17., 18., 19.], + [20., 21., 22., 23., 24.], + [25., 26., 27., 28., 29.], + [30., 31., 32., 33., 34.,]]]]).astype(np.float32), + "name": "paddle_conv2d_VALID_padding", + "input_shape": [1, 1, 7, 5], + "kernel": np.array([[[[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]]]]).astype(np.float32), + "dilation": 1, + "padding": "VALID", + "stride" : 2, + }, + { + "input_x": np.array([[[[0., 1., 2., 3., 4.], # (1, 1, 7, 5) input tensor + [5., 6., 7., 8., 9.], + [10., 11., 12., 13., 14.], + [15., 16., 17., 18., 19.], + [20., 21., 22., 23., 24.], + [25., 26., 27., 28., 29.], + [30., 31., 32., 33., 34.,]]]]).astype(np.float32), + "name": "paddle_conv2d_strides_padding", + "input_shape": [1, 1, 7, 5], + "kernel": np.array([[[[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]]]]).astype(np.float32), + "dilation": 1, + "padding": 1, + "stride" : 2, + }, + { "input_x": np.array([[[[0., 1., 2., 3., 4.], # (1, 1, 7, 5) input tensor + [5., 6., 7., 8., 9.], + [10., 11., 12., 13., 14.], + [15., 16., 17., 18., 19.], + [20., 21., 22., 23., 24.], + [25., 26., 27., 28., 29.], + [30., 31., 32., 33., 34.,]]]]).astype(np.float32), + "name": "paddle_conv2d_strides_no_padding", + "input_shape": [1, 1, 7, 5], + "kernel": np.array([[[[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]]]]).astype(np.float32), + "dilation": 1, + "padding": 0, + "stride" : 2, + }, + { "input_x": np.array([[[[0., 1., 2., 3., 4.], # (1, 1, 7, 5) input tensor + [5., 6., 7., 8., 9.], + [10., 11., 12., 13., 14.], + [15., 16., 17., 18., 19.], + [20., 21., 22., 23., 24.], + [25., 26., 27., 28., 29.], + [30., 31., 32., 33., 34.,]]]]).astype(np.float32), + "name": "paddle_conv2d_strides_assymetric_padding", + "input_shape": [1, 1, 7, 5], + "kernel": np.array([[[[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]]]]).astype(np.float32), + "dilation": 1, + "padding": [1,1,0,1], + "stride" : 2, + }, + { + "input_x": np.array([[[[0., 1., 2., 3., 4.], # (1, 1, 7, 5) input tensor + [5., 6., 7., 8., 9.], + [10., 11., 12., 13., 14.], + [15., 16., 17., 18., 19.], + [20., 21., 22., 23., 24.], + [25., 26., 27., 28., 29.], + [30., 31., 32., 33., 34.,]]]]).astype(np.float32), + "name": "paddle_conv2d_dilation_assymetric_pads_strides", + "input_shape": [1, 1, 7, 5], + "kernel": np.array([[[[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]]]]).astype(np.float32), + "dilation": 1, + "padding": [1, 1, 1, 2], + "stride" : [3, 1], + }, + { + "input_x": np.arange(27).astype(np.float32).reshape([1, 3, 3, 3]), + "name": "paddle_depthwise_conv2d_convolotuin", + "input_shape": [1, 3, 3, 3], + "kernel": np.ones([3, 1, 3, 3]).astype(np.float32), + "dilation": 1, + "padding": 1, + "stride": 1, + "groups": 3, + "use_cudnn": True + } + ] + for test in test_cases: + + pdpd_conv2d(test['input_x'], test['name'], test["input_shape"], + test['kernel'], test['dilation'], + test['padding'], + test['stride'], + 1 if "groups" not in test else test['groups'], + True if "use_cudnn" not in test else test['use_cudnn']) + + diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_interpolate.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_interpolate.py new file mode 100644 index 00000000000000..b7aae866104eac --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_interpolate.py @@ -0,0 +1,111 @@ +import numpy as np +import paddle as pdpd +from paddle.nn.functional import interpolate +from save_model import saveModel + +def run_and_save_model(input_x, name, feed, fetch_list, main_prog, start_prog): + cpu = pdpd.static.cpu_places(1) + exe = pdpd.static.Executor(cpu[0]) + exe.run(start_prog) + outs = exe.run( + feed={'x': input_x}, + fetch_list=fetch_list, + program=main_prog) + + with pdpd.static.program_guard(main_prog, start_prog): + saveModel(name, exe, feedkeys=['x'], fetchlist=fetch_list, inputs=[input_x], outputs=[outs[0]]) + + return outs + +def pdpd_interpolate(x, sizes=None, scale_factor=None, mode='nearest', align_corners=True, + align_mode=0, data_format='NCHW', name=None): + pdpd.enable_static() + main_program = pdpd.static.Program() + startup_program = pdpd.static.Program() + with pdpd.static.program_guard(main_program, startup_program): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype='float32') + interp = interpolate(node_x, size=sizes, scale_factor=scale_factor, + mode=mode, align_corners=align_corners, align_mode=align_mode, + data_format=data_format, name=name) + out = pdpd.static.nn.batch_norm(interp, use_global_stats=True, epsilon=0) + outs = run_and_save_model(x, name, node_x, out, main_program, startup_program) + return outs[0] + + +def resize_upsample_bilinear(): + data = np.array([[[ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16] + ]]], dtype=np.float32) + + test_case = [{'name': 'paddle_bilinear_upsample_false_1', 'align_corners': False, 'align_mode': 1}, + {'name': 'paddle_bilinear_upsample_false_0', 'align_corners': False, 'align_mode': 0}, + {'name': 'paddle_bilinear_upsample_true_0', 'align_corners': True, 'align_mode': 0}] + + for test in test_case: + pdpd_result = pdpd_interpolate(data, [8, 8], None, mode='bilinear', align_corners=test['align_corners'], + align_mode=test['align_mode'], data_format='NCHW', name=test['name']) + print(test['name']) + print(pdpd_result) + + +def resize_downsample_bilinear(): + data = np.array([[[ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16] + ]]], dtype=np.float32) + data_28 = data.reshape([1, 1, 2, 8]) + test_case = [{'name': 'paddle_bilinear_downsample_false_1', 'align_corners': False, 'align_mode': 1}, + {'name': 'paddle_bilinear_downsample_false_0', 'align_corners': False, 'align_mode': 0}, + {'name': 'paddle_bilinear_downsample_true_0', 'align_corners': True, 'align_mode': 0}] + + for test in test_case: + pdpd_result = pdpd_interpolate(data_28, [2, 4], None, mode='bilinear', align_corners=test['align_corners'], + align_mode=test['align_mode'], data_format='NCHW', name=test['name']) + print(test['name']) + print(pdpd_result) + + +def resize_upsample_nearest(): + data = np.array([[[ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16] + ]]], dtype=np.float32) + + test_case = [{'name': 'paddle_nearest_upsample_false_0', 'align_corners': False, 'align_mode': 0}] + + for test in test_case: + pdpd_result = pdpd_interpolate(data, [8, 8], None, mode='nearest', align_corners=test['align_corners'], + align_mode=test['align_mode'], data_format='NCHW', name=test['name']) + print(test['name']) + print(pdpd_result) + + +def resize_downsample_nearest(): + data = np.array([[[ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16] + ]]], dtype=np.float32) + data_28 = data.reshape([1, 1, 2, 8]) + test_case = [{'name': 'paddle_nearest_downsample_false_0', 'align_corners': False, 'align_mode': 1}] + + for test in test_case: + pdpd_result = pdpd_interpolate(data_28, [2, 4], None, mode='nearest', align_corners=test['align_corners'], + align_mode=test['align_mode'], data_format='NCHW', name=test['name']) + print(test['name']) + print(pdpd_result) + + +if __name__ == "__main__": + resize_downsample_bilinear() + resize_upsample_bilinear() + resize_downsample_nearest() + resize_upsample_nearest() diff --git a/ngraph/test/frontend/paddlepaddle/op/assign_value.cpp b/ngraph/test/frontend/paddlepaddle/op/assign_value.cpp new file mode 100644 index 00000000000000..22d094bd4bfb9e --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/assign_value.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using assignvalueTestParam = FrontendOpTestParam; +using assignvalueTest = FrontendOpTest; + +static assignvalueTestParam assign_value() { + assignvalueTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_assign_value/"; + res.m_modelName = "paddle_assign_value.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.0, 1.0, 1.0, 1.0}, + {1.0, 1.0, 1.0, 1.0}, + {1.0, 1.0, 1.0, 1.0}, + {1.0, 1.0, 1.0, 1.0}}}}}.get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray{{{{{2.0, 2.0, 2.0, 2.0}, + {2.0, 2.0, 2.0, 2.0}, + {2.0, 2.0, 2.0, 2.0}, + {2.0, 2.0, 2.0, 2.0}}}}}.get_vector()); + + return res; +} + +TEST_P(assignvalueTest, test_assignvalue) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, assignvalueTest, + ::testing::Values( + assign_value() + ), + assignvalueTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/bmm.cpp b/ngraph/test/frontend/paddlepaddle/op/bmm.cpp new file mode 100644 index 00000000000000..d8183a3bf00bf2 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/bmm.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using bmmTestParam = FrontendOpTestParam; +using bmmTest = FrontendOpTest; + +static bmmTestParam bmm() { + bmmTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS; + res.m_modelName = "paddle_bmm/paddle_bmm.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}}}}.get_vector()); + + res.inputs.emplace_back(test::NDArray{{{{0., 1., 2., 3., 4.}, + {5., 6., 7., 8., 9.}, + {10., 11., 12., 13., 14.}, + {15., 16., 17., 18., 19.}, + {20., 21., 22., 23., 24.}, + {25., 26., 27., 28., 29.}, + {30., 31., 32., 33., 34.}}}}.get_vector()); + + + + res.expected_outputs.emplace_back(test::NDArray{{{{ 10., 10., 10., 10., 10., 10., 10.}, + { 35., 35., 35., 35., 35., 35., 35.}, + { 60., 60., 60., 60., 60., 60., 60.}, + { 85., 85., 85., 85., 85., 85., 85.}, + {110., 110., 110., 110., 110., 110., 110.}, + {135., 135., 135., 135., 135., 135., 135.}, + {160., 160., 160., 160., 160., 160., 160.}}}}.get_vector()); + return res; +} + +TEST_P(bmmTest, test_bmm) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, bmmTest, + ::testing::Values( + bmm() + ), + bmmTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/conv2d.cpp b/ngraph/test/frontend/paddlepaddle/op/conv2d.cpp new file mode 100644 index 00000000000000..19aaa4c5ea41e2 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/conv2d.cpp @@ -0,0 +1,201 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using conv2dTestParam = FrontendOpTestParam; +using conv2dTest = FrontendOpTest; + +static conv2dTestParam paddle_conv2d_SAME_padding() { + conv2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_conv2d_SAME_padding/"; + res.m_modelName = "paddle_conv2d_SAME_padding.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}).get_vector()); + + return res; +} + +static conv2dTestParam paddle_conv2d_VALID_padding() { + conv2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_conv2d_VALID_padding/"; + res.m_modelName = "paddle_conv2d_VALID_padding.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray({{{{54.f, 72.f}, + {144.f, 162.f}, + {234.f, 252.f}}}}).get_vector()); + + return res; +} + +static conv2dTestParam paddle_conv2d_strides_padding() { + conv2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_conv2d_strides_padding/"; + res.m_modelName = "paddle_conv2d_strides_padding.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 27.f, 24.f}, + {63.f, 108.f, 81.f}, + {123.f, 198.f, 141.f}, + {112.f, 177.f, 124.f}}}}).get_vector()); + + return res; +} + +static conv2dTestParam paddle_conv2d_strides_no_padding() { + conv2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_conv2d_strides_no_padding/"; + res.m_modelName = "paddle_conv2d_strides_no_padding.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray({{{{54.f, 72.f}, + {144.f, 162.f}, + {234.f, 252.f}}}}).get_vector()); + + return res; +} + +static conv2dTestParam paddle_conv2d_strides_assymetric_padding() { + conv2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_conv2d_strides_assymetric_padding/"; + res.m_modelName = "paddle_conv2d_strides_assymetric_padding.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray({{{{21.f, 33.f}, + {99.f, 117.f}, + {189.f, 207.f}, + {171.f, 183.f}}}}).get_vector()); + + return res; +} + +static conv2dTestParam paddle_conv2d_dilation_assymetric_pads_strides() { + conv2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_conv2d_dilation_assymetric_pads_strides/"; + res.m_modelName = "paddle_conv2d_dilation_assymetric_pads_strides.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f, 9.f}, + {10.f, 11.f, 12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f, 18.f, 19.f}, + {20.f, 21.f, 22.f, 23.f, 24.f}, + {25.f, 26.f, 27.f, 28.f, 29.f}, + {30.f, 31.f, 32.f, 33.f, 34.f}}}}} + .get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray({{{{12.f, 21.f, 27.f, 33.f, 24.f, 13.f}, + {93.f, 144.f, 153.f, 162.f, 111.f, 57.f}, + {112.f, 171.f, 177.f, 183.f, 124.f, 63.f}}}}).get_vector()); + + return res; +} + +static conv2dTestParam paddle_depthwise_conv2d_convolotuin() { + conv2dTestParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_depthwise_conv2d_convolotuin/"; + res.m_modelName = "paddle_depthwise_conv2d_convolotuin.pdmodel"; + + res.inputs.emplace_back(test::NDArray{{{{{0.f, 1.f, 2.f}, + {3.f, 4.f, 5.f}, + {6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f}, + {12.f, 13.f, 14.f}, + {15.f, 16.f, 17.f}, + {18.f, 19.f, 20.f}, + {21.f, 22.f, 23.f}, + {24.f, 25.f, 26.f}}}}}.get_vector()); + + + res.expected_outputs.emplace_back(test::NDArray({{{{8.f, 15.f, 12.f}, + {21.f, 36.f, 27.f}, + {20.f, 33.f, 24.f}, + {44.f, 69.f, 48.f}, + {75.f, 117.f, 81.f}, + {56.f, 87.f, 60.f}, + {80.f, 123.f, 84.f}, + {129.f, 198.f, 135.f}, + {92.f, 141.f, 96.f}}}}).get_vector()); + + return res; +} + +TEST_P(conv2dTest, test_conv2d) { +ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, conv2dTest, + ::testing::Values( + paddle_conv2d_SAME_padding(), + paddle_conv2d_VALID_padding(), + paddle_conv2d_strides_padding(), + paddle_conv2d_strides_no_padding(), + paddle_conv2d_strides_assymetric_padding(), + paddle_conv2d_dilation_assymetric_pads_strides(), + paddle_depthwise_conv2d_convolotuin() + ), + conv2dTest::getTestCaseName); diff --git a/ngraph/test/frontend/paddlepaddle/op/interpolate.cpp b/ngraph/test/frontend/paddlepaddle/op/interpolate.cpp new file mode 100644 index 00000000000000..f5f50e5427f7c5 --- /dev/null +++ b/ngraph/test/frontend/paddlepaddle/op/interpolate.cpp @@ -0,0 +1,190 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "../../shared/include/op.hpp" + +using namespace ngraph; +using namespace ngraph::frontend; + +static const std::string PDPD = "pdpd"; +static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; + +using interpolateParam = FrontendOpTestParam; +using interpolateTest = FrontendOpTest; + +static interpolateParam paddle_bilinear_downsample_false_1() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_bilinear_downsample_false_1/"; + res.m_modelName = "paddle_bilinear_downsample_false_1.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.f, 3.f, 5.f, 7.f}, + {9.f, 11.f, 13.f, 15.f}}}}).get_vector()); + return res; +} + +static interpolateParam paddle_bilinear_downsample_false_0() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_bilinear_downsample_false_0/"; + res.m_modelName = "paddle_bilinear_downsample_false_0.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.5f, 3.5f, 5.5f, 7.5f}, + {9.5f, 11.5f, 13.5f, 15.5f}}}}).get_vector()); + return res; +} + +static interpolateParam paddle_bilinear_downsample_true_0() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_bilinear_downsample_true_0/"; + res.m_modelName = "paddle_bilinear_downsample_true_0.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.0f, 3.333333f, 5.6666665f, 8.0f}, + {9.0f, 11.33333f, 13.666666f, 16.0f}}}}).get_vector()); + return res; +} + +static interpolateParam paddle_bilinear_upsample_false_1() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_bilinear_upsample_false_1/"; + res.m_modelName = "paddle_bilinear_upsample_false_1.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.0f, 1.5f, 2.f, 2.5f, 3.f, 3.5f, 4.f, 4.f}, + {3.f, 3.5f, 4.f, 4.5f, 5.f, 5.5f, 6.f, 6.f}, + {5.f, 5.5f, 6.f, 6.5f, 7.f, 7.5f, 8.f, 8.f}, + {7.f, 7.5f, 8.f, 8.5f, 9.f, 9.5f, 10.f, 10.f}, + {9.f, 9.5f, 10.f, 10.5f, 11.f, 11.5f, 12.f, 12.f}, + {11.f, 11.5f, 12.f, 12.5f, 13.f, 13.5f, 14.f, 14.f}, + {13, 13.5f, 14.f, 14.5f, 15.f, 15.5f, 16.f, 16.f}, + {13., 13.5f, 14.f, 14.5f, 15.f, 15.5f, 16.f, 16.f}}}}).get_vector()); + return res; +} + +static interpolateParam paddle_bilinear_upsample_false_0() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_bilinear_upsample_false_0/"; + res.m_modelName = "paddle_bilinear_upsample_false_0.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.0f, 1.25f, 1.75f, 2.25f, 2.75f, 3.25f, 3.75f, 4.f}, + {2.f, 2.25f, 2.75f, 3.25f, 3.75f, 4.25f, 4.75f, 5.f}, + {4.f, 4.25f, 4.75f, 5.25f, 5.75f, 6.25f, 6.75f, 7.f}, + {6.f, 6.25f, 6.75f, 7.25f, 7.75f, 8.25f, 8.75f, 9.f}, + {8.f, 8.25f, 8.75f, 9.25f, 9.75f, 10.25f, 10.75f, 11.f}, + {10.f, 10.25f, 10.75f, 11.25f, 11.75f, 12.25f, 12.75f, 13.f}, + {12, 12.25f, 12.75f, 13.25f, 13.75f, 14.25f, 14.75f, 15.f}, + {13., 13.25f, 13.75f, 14.25f, 14.75f, 15.25f, 15.75f, 16.f}}}}).get_vector()); + return res; +} + +static interpolateParam paddle_bilinear_upsample_true_0() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_bilinear_upsample_true_0/"; + res.m_modelName = "paddle_bilinear_upsample_true_0.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.f, 1.4285715f, 1.8571429f, 2.2857141f, 2.7142856f, 3.142857f, 3.5714285f, 4.f}, + {2.7142856f, 3.1428568f, 3.5714283f, 4.f, 4.428571f, 4.8571424f, 5.285714f, 5.714286f}, + {4.428571f, 4.8571424f, 5.285714f, 5.714286f, 6.1428566f, 6.57142837f, 7.f, 7.4285717f}, + {6.142857f, 6.5714283f, 6.9999995f, 7.428571f, 7.8571424f, 8.285714f, 8.714286f, 9.142857f}, + {7.857143f, 8.285714f, 8.714286f, 9.142857f, 9.571428f, 10.f, 10.428572f, 10.857142f}, + {9.571428f, 10.f, 10.428572f, 10.857142f, 11.285713f, 11.714285f, 12.142857f, 12.571428f}, + {11.285714f, 11.714285f, 12.142857f, 12.571428f, 13.f, 13.428572, 13.857143f, 14.285714f}, + {13.f, 13.428571f, 13.857142f, 14.285714f, 14.714286f, 15.142857f, 15.571428f, 16.f}}}}).get_vector()); + return res; +} + +static interpolateParam paddle_nearest_downsample_false_0() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_nearest_downsample_false_0/"; + res.m_modelName = "paddle_nearest_downsample_false_0.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.f, 3.f, 5.f, 7.f}, + {9.f, 11.f, 13.f, 15.f}}}}).get_vector()); + return res; +} + +static interpolateParam paddle_nearest_upsample_false_0() { + interpolateParam res; + res.m_frontEndName = PDPD; + res.m_modelsPath = PATH_TO_MODELS + "paddle_nearest_upsample_false_0/"; + res.m_modelName = "paddle_nearest_upsample_false_0.pdmodel"; + + + res.inputs.emplace_back(test::NDArray{{{{{1.f, 2.f, 3.f, 4.f}, + {5.f, 6.f, 7.f, 8.f}, + {9.f, 10.f, 11.f, 12.f}, + {13.f, 14.f, 15.f, 16.f}}}}}.get_vector()); + + res.expected_outputs.emplace_back(test::NDArray({{{{1.f, 1.f, 2.f, 2.f, 3.f, 3.f, 4.f, 4.f}, + {1.f, 1.f, 2.f, 2.f, 3.f, 3.f, 4.f, 4.f}, + {5.f, 5.f, 6.f, 6.f, 7.f, 7.f, 8.f, 8.f}, + {5.f, 5.f, 6.f, 6.f, 7.f, 7.f, 8.f, 8.f}, + {9.f, 9.f, 10.f, 10.f, 11.f, 11.f, 12.f, 12.f}, + {9.f, 9.f, 10.f, 10.f, 11.f, 11.f, 12.f, 12.f}, + {13, 13.f, 14.f, 14.f, 15.f, 15.f, 16.f, 16.f}, + {13, 13.f, 14.f, 14.f, 15.f, 15.f, 16.f, 16.f}}}}).get_vector()); + return res; +} + +TEST_P(interpolateTest, test_interpolate) { + ASSERT_NO_THROW(validateOp()); +} + +INSTANTIATE_TEST_CASE_P(FrontendOpTest, interpolateTest, + ::testing::Values( + paddle_bilinear_downsample_false_1(), + paddle_bilinear_downsample_false_0(), + paddle_bilinear_downsample_true_0(), + paddle_bilinear_upsample_false_1(), + paddle_bilinear_upsample_false_0(), + paddle_bilinear_upsample_true_0(), + paddle_nearest_downsample_false_0() + ), + interpolateTest::getTestCaseName); From 79aaa5f6e19ba2a22ab630b8705bf5319d725cfa Mon Sep 17 00:00:00 2001 From: jialipen Date: Wed, 21 Apr 2021 20:34:38 +0800 Subject: [PATCH 45/54] fix bug of yolo_box. --- ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp index c51163351bfc57..976ed5f9f6c309 100644 --- a/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp @@ -26,8 +26,6 @@ namespace op { using namespace element; OutputVector yolo_box (const NodeContext& node_context) { - //model_name = node.output('Boxes', 0) - auto data = node_context.get_ng_input("X"); auto image_size = node_context.get_ng_input("ImgSize"); @@ -36,7 +34,7 @@ OutputVector yolo_box (const NodeContext& node_context) { int32_t input_width = input_shape[3].get_length(); int32_t class_num = node_context.get_attribute("class_num"); - //PDPD anchors attribute is of type int32. Convert to float for computing convinient. + // PDPD anchors attribute is of type int32. Convert to float for computing convinient. auto _anchors = node_context.get_attribute>("anchors"); std::vector anchors; anchors.resize(_anchors.size()); @@ -59,6 +57,8 @@ OutputVector yolo_box (const NodeContext& node_context) { std::cout << "downsample_ratio: " << downsample_ratio << " conf_thresh: " << conf_thresh << std::endl; std::cout << "class_num: " << class_num << " image_size: " << image_size << std::endl; + //auto clip_bbox = node_context.get_attribute("clip_bbox"); // clip_bbox is not used by Paddle2ONNX. + // main X auto node_x_shape = Constant::create(i64, {5}, {1, num_anchors, 5 + class_num, input_height, input_width}); @@ -246,9 +246,9 @@ OutputVector yolo_box (const NodeContext& node_context) { auto node_number_one = Constant::create(f32, {1}, {1.0}); auto node_new_img_height = std::make_shared(node_img_height_cast, node_number_one); - auto node_new_img_width = std::make_shared(node_img_height_cast, node_number_one); - auto node_pred_box_x2_sub_w = std::make_shared(node_pred_box_x2_decode, node_number_one); //x2 - (w-1) - auto node_pred_box_y2_sub_h = std::make_shared(node_pred_box_y2_decode, node_number_one); //y2 - (h-1) + auto node_new_img_width = std::make_shared(node_img_width_cast, node_number_one); + auto node_pred_box_x2_sub_w = std::make_shared(node_pred_box_x2_decode, node_new_img_width); //x2 - (w-1) + auto node_pred_box_y2_sub_h = std::make_shared(node_pred_box_y2_decode, node_new_img_height); //y2 - (h-1) /* opset_11 */ auto max_const = std::numeric_limits::max(); @@ -261,12 +261,12 @@ OutputVector yolo_box (const NodeContext& node_context) { auto node_pred_box_y2_res = std::make_shared(node_pred_box_y2_decode, node_pred_box_y2_clip); auto node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_clip, node_pred_box_y1_clip, - node_pred_box_x2_res, node_pred_box_y2_res}, -1); //outputs=node.output('Boxes') + node_pred_box_x2_res, node_pred_box_y2_res}, -1); //outputs=node.output('Boxes') auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') -#if 1 +#if 0 return OutputVector{node_pred_box_result, node_score_new_shape}; #else //FIXME: combine the two output nodes into 1, to satisfy frontend/pdpd. From dd65f6dfbe792409f3642bc2ee54c02e5edabc61 Mon Sep 17 00:00:00 2001 From: jialipen Date: Wed, 21 Apr 2021 21:14:53 +0800 Subject: [PATCH 46/54] yolo_box and its generator --- .../frontend/paddlepaddle/src/op/yolo_box.cpp | 82 ++++++---- .../gen_scripts/generate_yolo_box.py | 141 +++++++++++++++--- 2 files changed, 177 insertions(+), 46 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp index 976ed5f9f6c309..3892c4a1554a74 100644 --- a/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp @@ -57,7 +57,7 @@ OutputVector yolo_box (const NodeContext& node_context) { std::cout << "downsample_ratio: " << downsample_ratio << " conf_thresh: " << conf_thresh << std::endl; std::cout << "class_num: " << class_num << " image_size: " << image_size << std::endl; - //auto clip_bbox = node_context.get_attribute("clip_bbox"); // clip_bbox is not used by Paddle2ONNX. + auto clip_bbox = node_context.get_attribute("clip_bbox"); // main X auto node_x_shape = Constant::create(i64, {5}, @@ -244,40 +244,66 @@ OutputVector yolo_box (const NodeContext& node_context) { auto node_pred_box_x2_decode = std::make_shared(node_pred_box_x2, node_img_width_cast); auto node_pred_box_y2_decode = std::make_shared(node_pred_box_y2, node_img_height_cast); - auto node_number_one = Constant::create(f32, {1}, {1.0}); - auto node_new_img_height = std::make_shared(node_img_height_cast, node_number_one); - auto node_new_img_width = std::make_shared(node_img_width_cast, node_number_one); - auto node_pred_box_x2_sub_w = std::make_shared(node_pred_box_x2_decode, node_new_img_width); //x2 - (w-1) - auto node_pred_box_y2_sub_h = std::make_shared(node_pred_box_y2_decode, node_new_img_height); //y2 - (h-1) + // reference + // Paddle/python/paddle/fluid/tests/unittests/test_yolo_box_op.py + // Paddle/paddle/fluid/operators/detection/yolo_box_op.h + // Paddle2ONNX/paddle2onnx/op_mapper/detection/yolo_box.py - clip_bbox is not used by Paddle2ONNX. + if (clip_bbox) { + auto node_number_one = Constant::create(f32, {1}, {1.0}); + auto node_new_img_height = std::make_shared(node_img_height_cast, node_number_one); + auto node_new_img_width = std::make_shared(node_img_width_cast, node_number_one); + auto node_pred_box_x2_sub_w = std::make_shared(node_pred_box_x2_decode, node_new_img_width); //x2 - (w-1) + auto node_pred_box_y2_sub_h = std::make_shared(node_pred_box_y2_decode, node_new_img_height); //y2 - (h-1) - /* opset_11 */ - auto max_const = std::numeric_limits::max(); - auto node_pred_box_x1_clip = std::make_shared(node_pred_box_x1_decode, 0.0f, max_const); - auto node_pred_box_y1_clip = std::make_shared(node_pred_box_y1_decode, 0.0f, max_const); - auto node_pred_box_x2_clip = std::make_shared(node_pred_box_x2_sub_w, 0.0f, max_const); - auto node_pred_box_y2_clip = std::make_shared(node_pred_box_y2_sub_h, 0.0f, max_const); + auto max_const = std::numeric_limits::max(); + auto node_pred_box_x1_clip = std::make_shared(node_pred_box_x1_decode, 0.0f, max_const); + auto node_pred_box_y1_clip = std::make_shared(node_pred_box_y1_decode, 0.0f, max_const); + auto node_pred_box_x2_clip = std::make_shared(node_pred_box_x2_sub_w, 0.0f, max_const); + auto node_pred_box_y2_clip = std::make_shared(node_pred_box_y2_sub_h, 0.0f, max_const); - auto node_pred_box_x2_res = std::make_shared(node_pred_box_x2_decode, node_pred_box_x2_clip); - auto node_pred_box_y2_res = std::make_shared(node_pred_box_y2_decode, node_pred_box_y2_clip); + auto node_pred_box_x2_res = std::make_shared(node_pred_box_x2_decode, node_pred_box_x2_clip); + auto node_pred_box_y2_res = std::make_shared(node_pred_box_y2_decode, node_pred_box_y2_clip); - auto node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_clip, node_pred_box_y1_clip, - node_pred_box_x2_res, node_pred_box_y2_res}, -1); //outputs=node.output('Boxes') + auto node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_clip, node_pred_box_y1_clip, + node_pred_box_x2_res, node_pred_box_y2_res}, -1); //outputs=node.output('Boxes') - auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); - auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') + auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); + auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') #if 0 - return OutputVector{node_pred_box_result, node_score_new_shape}; + return OutputVector{node_pred_box_result, node_score_new_shape}; #else - //FIXME: combine the two output nodes into 1, to satisfy frontend/pdpd. - auto node_result_concat = std::make_shared(OutputVector{node_pred_box_result, node_score_new_shape}, 2); - - auto result_split_axis = Constant::create(i64, {1}, {2}); //(1,xx,6) -> bboxes(1,xx,4) and scores(1,xx,class_num) - auto result_split_axes_lengths = Constant::create(i64, {2}, {4, class_num}); - auto node_result = std::make_shared(node_result_concat, result_split_axis, result_split_axes_lengths); - //return OutputVector{node_result}; - return node_result->outputs(); -#endif + //FIXME: combine the two output nodes into 1, to satisfy frontend/pdpd. + auto node_result_concat = std::make_shared(OutputVector{node_pred_box_result, node_score_new_shape}, 2); + + auto result_split_axis = Constant::create(i64, {1}, {2}); //(1,xx,6) -> bboxes(1,xx,4) and scores(1,xx,class_num) + auto result_split_axes_lengths = Constant::create(i64, {2}, {4, class_num}); + auto node_result = std::make_shared(node_result_concat, result_split_axis, result_split_axes_lengths); + //return OutputVector{node_result}; + return node_result->outputs(); +#endif + } + else { + auto node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_decode, node_pred_box_y1_decode, + node_pred_box_x2_decode, node_pred_box_y2_decode}, -1); //outputs=node.output('Boxes') + + auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); + auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') + +#if 0 + return OutputVector{node_pred_box_result, node_score_new_shape}; +#else + //FIXME: combine the two output nodes into 1, to satisfy frontend/pdpd. + auto node_result_concat = std::make_shared(OutputVector{node_pred_box_result, node_score_new_shape}, 2); + + auto result_split_axis = Constant::create(i64, {1}, {2}); //(1,xx,6) -> bboxes(1,xx,4) and scores(1,xx,class_num) + auto result_split_axes_lengths = Constant::create(i64, {2}, {4, class_num}); + auto node_result = std::make_shared(node_result_concat, result_split_axis, result_split_axes_lengths); + //return OutputVector{node_result}; + return node_result->outputs(); +#endif + } + } }}}} \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py index c66a0490954c9c..56e098ee0c1e82 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py @@ -4,15 +4,13 @@ import numpy as np from save_model import saveModel -data_type = 'float32' - def yolo_box(name : str, x, img_size, attrs : dict): import paddle as pdpd pdpd.enable_static() with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): - node_x = pdpd.static.data(name='x', shape=x.shape, dtype=data_type) - node_img_size = pdpd.static.data(name='img_size', shape=img_size.shape, dtype='int32') + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=x.dtype) + node_img_size = pdpd.static.data(name='img_size', shape=img_size.shape, dtype=img_size.dtype) boxes, scores = pdpd.vision.ops.yolo_box(node_x, node_img_size, anchors=attrs['anchors'], @@ -28,34 +26,141 @@ def yolo_box(name : str, x, img_size, attrs : dict): # startup program will call initializer to initialize the parameters. exe.run(pdpd.static.default_startup_program()) + input_dict = {'x': x, 'img_size': img_size} + input_dict = dict(sorted(input_dict.items())) + outs = exe.run( - feed={'x': x, 'img_size': img_size}, - fetch_list=[boxes, scores]) + feed=input_dict, + fetch_list=[boxes, scores]) + + #save inputs in alphabeta order, as it is in pdpd frontend. + saveModel(name, exe, feedkeys=list(input_dict.keys()), fetchlist=[boxes, scores], inputs=list(input_dict.values()), outputs=outs) + + return outs + +def onnx_run(x, img_size, onnx_model="../models/yolo_box_test1/yolo_box_test1.onnx"): + import onnxruntime as rt + + sess = rt.InferenceSession(onnx_model) + for input in sess.get_inputs(): + print(input.name) + for output in sess.get_outputs(): + print(output.name) + pred_onx = sess.run(None, {"img_size": img_size, "x": x}) + print(pred_onx) + return pred_onx + +def IE_run(x, img_size, path_to_ie_model="../models/yolo_box_test1/yolo_box"): + from openvino.inference_engine import IECore + + #IE inference + ie = IECore() + net = ie.read_network(model=path_to_ie_model + ".xml", weights=path_to_ie_model + ".bin") + exec_net = ie.load_network(net, "CPU") + pred_ie = exec_net.infer({"img_size": img_size, "x": x}) + print(type(pred_ie)) + return pred_ie + +def checker(outs, dump=False): + if type(outs) is list: + for i in range(len(outs)): + print("output{} shape {}, type {} ".format(i, outs[i].shape, outs[i].dtype)) + if(dump): + print(outs[i]) + if type(outs) is dict: + for i in outs: + print("output{} shape {}, type {} ".format(i, outs[i].shape, outs[i].dtype)) + if(dump): + print(outs[i]) + +def print_2Dlike(data, filename): + with open(filename+".txt", 'w') as f: + print(data.shape, file=f) + _data = data.copy() + _data = np.squeeze(_data) + _data.reshape(-1, data.shape[len(data.shape)-1]) + print(_data.shape, file=f) + print("\n[", file=f) + for j in range(_data.shape[0]): + line="" + for i in range(_data.shape[1]): + line+="{:.2f}".format(_data[j, i]) + " " + print(line, file=f) + print("]\n", file=f) + f.close() - saveModel(name, exe, feedkeys=['x', 'img_size'], fetchlist=[boxes, scores], inputs=[x, img_size], outputs=outs) +def validate(pred_pdpd: list, pred_onx: list, pred_ie: dict, rtol=1e-05, atol=1e-08): + checker(pred_pdpd) + checker(pred_onx) + checker(pred_ie) + + # compare results: IE vs PDPD vs ONNX + idx = 0 + for key in pred_ie: + comp1 = np.all(np.isclose(pred_pdpd[idx], pred_onx[idx], rtol=rtol, atol=atol, equal_nan=True)) + #comp1 = np.all(np.isclose([1,2.1], [1,2], rtol=1e-05, atol=1e-08, equal_nan=True)) + #np.all(np.isclose(res_pdpd[0], list(res_ie.values())[0], rtol=1e-4, atol=1e-5)) + if not comp1: + print('\033[91m' + "PDPD and ONNX results are different at {} ".format(idx) + '\033[0m') + + comp2 = np.all(np.isclose(pred_pdpd[idx], pred_ie[key], rtol=rtol, atol=atol, equal_nan=True)) + #np.all(np.isclose(res_pdpd[0], list(res_ie.values())[0], rtol=1e-4, atol=1e-5)) + if not comp2: + print('\033[91m' + "PDPD and IE results are different at {} ".format(idx) + '\033[0m') + + comp3 = np.all(np.isclose(pred_ie[key], pred_onx[idx], rtol=rtol, atol=atol, equal_nan=True)) + #np.all(np.isclose(res_pdpd[0], list(res_ie.values())[0], rtol=1e-4, atol=1e-5)) + if not comp3: + print('\033[91m' + "ONNX and IE results are different at {} ".format(idx) + '\033[0m') + + print_2Dlike(pred_pdpd[idx], "pdpd{}".format(idx)) + print_2Dlike(pred_onx[idx], "onnx{}".format(idx)) + print_2Dlike(pred_ie[key], "ie{}".format(idx)) + + if comp1 and comp2 and comp3: + print('\033[92m' + "PDPD, ONNX and IE results are identical at {} ".format(idx) + '\033[0m') + + idx += 1 - return def main(): # yolo_box pdpd_attrs = { - 'anchors': [116, 90, 156, 198, 373, 326], + 'anchors': [10, 13, 16, 30, 33, 23], 'class_num': 2, - 'conf_thresh': 0.80, + 'conf_thresh': 0.5, 'downsample_ratio': 32, - 'clip_bbox': True, + 'clip_bbox': True, #There is bug in Paddle2ONN where clip_bbox is always ignored. 'scale_x_y': 1.0 } - num_anchors = int(len(pdpd_attrs['anchors'])/2) - N, C, H, W = 1, (num_anchors * (5+pdpd_attrs['class_num'])), 3, 3 + N = 1 + num_anchors = int(len(pdpd_attrs['anchors'])//2) + x_shape = (N, num_anchors * (5 + pdpd_attrs['class_num']), 13, 13) + imgsize_shape = (N, 2) + + data = np.random.random(x_shape).astype('float32') + data_ImSize = np.random.randint(10, 20, imgsize_shape).astype('int32') + + # For any change to pdpd_attrs, do - + # step 1. generate paddle model + pred_pdpd = yolo_box('yolo_box_test1', data, data_ImSize, pdpd_attrs) + + # step 2. generate onnx model + # !paddle2onnx --model_dir=../models/yolo_box_test1/ --save_file=../models/yolo_box_test1/yolo_box_test1.onnx --opset_version=10 + import subprocess + subprocess.run(["paddle2onnx", "--model_dir=../models/yolo_box_test1/", "--save_file=../models/yolo_box_test1/yolo_box_test1.onnx", "--opset_version=12"]) + pred_onx = onnx_run(data, data_ImSize) - data = np.arange(N*C*H*W).astype(data_type) - data_NCHW = data.reshape(N, C, H, W) - data_ImSize = np.arange(N*2).astype('int32').reshape(N, 2) - print(data_NCHW.shape) + # step 3. generate OV IR + # MO or ngraph/frontend/paddlepaddle Fuzzy unit test helper. + subprocess.run(["unit-test", "--gtest_filter=*Fuzzy*"]) + pred_ie = IE_run(data, data_ImSize) - yolo_box('yolo_box_test1', data_NCHW, data_ImSize, pdpd_attrs) + # step 4. compare + # Try different tolerence + validate(pred_pdpd, pred_onx, pred_ie) + validate(pred_pdpd, pred_onx, pred_ie, rtol=1e-4, atol=1e-5) if __name__ == "__main__": From fac29ddcbc5b405c4ccc1fd4ebc1c5d902f93cde Mon Sep 17 00:00:00 2001 From: Luo Cheng Date: Thu, 22 Apr 2021 08:30:07 +0800 Subject: [PATCH 47/54] add new ops --- .../paddlepaddle/src/op/elementwise_ops.cpp | 2 +- .../paddlepaddle/src/op/hard_sigmoid.cpp | 35 ++++++++++++ .../paddlepaddle/src/op/hard_sigmoid.hpp | 27 +++++++++ .../paddlepaddle/src/op/hard_swish.cpp | 43 +++++++++++++++ .../paddlepaddle/src/op/hard_swish.hpp | 27 +++++++++ ngraph/frontend/paddlepaddle/src/op/pow.cpp | 34 ++++++++++++ ngraph/frontend/paddlepaddle/src/op/pow.hpp | 27 +++++++++ ngraph/frontend/paddlepaddle/src/op/relu6.cpp | 33 +++++++++++ ngraph/frontend/paddlepaddle/src/op/relu6.hpp | 27 +++++++++ .../frontend/paddlepaddle/src/op/sigmoid.cpp | 30 ++++++++++ .../frontend/paddlepaddle/src/op/sigmoid.hpp | 27 +++++++++ ngraph/frontend/paddlepaddle/src/op/slice.cpp | 55 +++++++++++++++++++ ngraph/frontend/paddlepaddle/src/op/slice.hpp | 27 +++++++++ .../frontend/paddlepaddle/src/op/squeeze.cpp | 45 +++++++++++++++ .../frontend/paddlepaddle/src/op/squeeze.hpp | 27 +++++++++ .../paddlepaddle/src/op/unsqueeze.cpp | 33 +++++++++++ .../paddlepaddle/src/op/unsqueeze.hpp | 27 +++++++++ ngraph/frontend/paddlepaddle/src/op_table.cpp | 20 ++++++- .../gen_scripts/generate_hard_sigmoid.py | 36 ++++++++++++ .../gen_scripts/generate_hard_swish.py | 36 ++++++++++++ .../gen_scripts/generate_leaky_relu.py | 36 ++++++++++++ .../paddlepaddle/gen_scripts/generate_pow.py | 36 ++++++++++++ .../gen_scripts/generate_relu6.py | 36 ++++++++++++ .../gen_scripts/generate_sigmoid.py | 36 ++++++++++++ .../gen_scripts/generate_slice.py | 38 +++++++++++++ .../gen_scripts/generate_squeeze.py | 37 +++++++++++++ .../gen_scripts/generate_unsqueeze.py | 36 ++++++++++++ 27 files changed, 870 insertions(+), 3 deletions(-) create mode 100644 ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/hard_swish.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/hard_swish.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/pow.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/pow.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/relu6.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/relu6.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/sigmoid.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/sigmoid.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/slice.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/slice.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/squeeze.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/squeeze.hpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/unsqueeze.cpp create mode 100644 ngraph/frontend/paddlepaddle/src/op/unsqueeze.hpp create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_sigmoid.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_swish.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_leaky_relu.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_pow.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_relu6.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_sigmoid.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_slice.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_squeeze.py create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_unsqueeze.py diff --git a/ngraph/frontend/paddlepaddle/src/op/elementwise_ops.cpp b/ngraph/frontend/paddlepaddle/src/op/elementwise_ops.cpp index 8804c37ef55f69..922709165a5d84 100644 --- a/ngraph/frontend/paddlepaddle/src/op/elementwise_ops.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/elementwise_ops.cpp @@ -31,7 +31,7 @@ OutputVector elementwise_ops (const NodeContext& node) { auto axis = node.get_attribute("axis"); MY_ASSERT(x.get_partial_shape().rank().is_static(), "elementwise_ops: X rank must be static!"); - MY_ASSERT(y.get_partial_shape().rank().is_static()), "elementwise_ops: Y rank must be static!"; + MY_ASSERT(y.get_partial_shape().rank().is_static(), "elementwise_ops: Y rank must be static!"); int64_t x_rank = x.get_partial_shape().rank().get_length(); int64_t y_rank = y.get_partial_shape().rank().get_length(); diff --git a/ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.cpp b/ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.cpp new file mode 100644 index 00000000000000..c007aab90e599d --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.cpp @@ -0,0 +1,35 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "hard_sigmoid.hpp" +#include + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector hard_sigmoid (const NodeContext& node) { + auto data = node.get_ng_input("X"); + auto slope = node.get_attribute("slope"); + MY_ASSERT(slope >= 0, "hard_sigmoid: slope must greater than 0!"); + auto alpha = ngraph::opset6::Constant::create(ngraph::element::f32, {}, {slope}); + auto beta = ngraph::opset6::Constant::create(ngraph::element::f32, {}, {node.get_attribute("offset")}); + return {std::make_shared(data, alpha, beta)}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.hpp b/ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.hpp new file mode 100644 index 00000000000000..96c8634d47f407 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/hard_sigmoid.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector hard_sigmoid (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/hard_swish.cpp b/ngraph/frontend/paddlepaddle/src/op/hard_swish.cpp new file mode 100644 index 00000000000000..974c2320bfa89c --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/hard_swish.cpp @@ -0,0 +1,43 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "hard_swish.hpp" +#include + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector hard_swish (const NodeContext& node) { + auto data = node.get_ng_input("X"); + if (node.has_attribute("threshold")) { + auto threshold = node.get_attribute("threshold"); + MY_ASSERT(std::abs(threshold - 6.0) < 0.001, "hard_swish: threshold must = 6.0."); + } + if (node.has_attribute("scale")) { + auto scale = node.get_attribute("scale"); + MY_ASSERT(std::abs(scale - 6.0) < 0.001, "hard_swish: scale must = 6.0."); + } + if (node.has_attribute("offset")) { + auto offset = node.get_attribute("offset"); + MY_ASSERT(std::abs(offset - 3.0) < 0.001, "hard_swish: offset must = 3.0."); + } + return {std::make_shared(data)}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/hard_swish.hpp b/ngraph/frontend/paddlepaddle/src/op/hard_swish.hpp new file mode 100644 index 00000000000000..766f5ab5ce3d5b --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/hard_swish.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector hard_swish (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/pow.cpp b/ngraph/frontend/paddlepaddle/src/op/pow.cpp new file mode 100644 index 00000000000000..c731f6be554b79 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/pow.cpp @@ -0,0 +1,34 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "pow.hpp" +#include + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector pow (const NodeContext& node) { + auto x = node.get_ng_input("X"); + Output factorNode; + auto factor = node.get_attribute("factor"); + factorNode = ngraph::opset6::Constant::create(ngraph::element::f32, {}, {factor}); + return {std::make_shared(x, factorNode)}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/pow.hpp b/ngraph/frontend/paddlepaddle/src/op/pow.hpp new file mode 100644 index 00000000000000..ae25325fc7e528 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/pow.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector pow (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/relu6.cpp b/ngraph/frontend/paddlepaddle/src/op/relu6.cpp new file mode 100644 index 00000000000000..812f33954edef2 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/relu6.cpp @@ -0,0 +1,33 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "relu6.hpp" +#include + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector relu6 (const NodeContext& node) { + auto data = node.get_ng_input("X"); + auto threshold = node.get_attribute("threshold"); + MY_ASSERT(threshold >= 0, "relu6: threshold must greater than 0!"); + return {std::make_shared(data, 0.0, threshold)}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/relu6.hpp b/ngraph/frontend/paddlepaddle/src/op/relu6.hpp new file mode 100644 index 00000000000000..d11e89dda1c116 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/relu6.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector relu6 (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/sigmoid.cpp b/ngraph/frontend/paddlepaddle/src/op/sigmoid.cpp new file mode 100644 index 00000000000000..fb8b2570118be1 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/sigmoid.cpp @@ -0,0 +1,30 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "sigmoid.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector sigmoid (const NodeContext& node) { + auto data = node.get_ng_input("X"); + return {std::make_shared(data)}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/sigmoid.hpp b/ngraph/frontend/paddlepaddle/src/op/sigmoid.hpp new file mode 100644 index 00000000000000..e7592e5cee7cdb --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/sigmoid.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector sigmoid (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/slice.cpp b/ngraph/frontend/paddlepaddle/src/op/slice.cpp new file mode 100644 index 00000000000000..217efc7df3c9a8 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/slice.cpp @@ -0,0 +1,55 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "slice.hpp" +#include + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector slice (const NodeContext& node) { + auto data = node.get_ng_input("Input"); + auto axes = node.get_attribute>("axes"); + auto starts = node.get_attribute>("starts"); + auto ends = node.get_attribute>("ends"); + auto parialShape = data.get_partial_shape(); + MY_ASSERT(parialShape.is_static(), "slice: must use static shape."); + auto shape = parialShape.to_shape(); + std::vector fixedStarts(shape.size(), 0); + std::vector fixedEnds(shape.size(), INT_MAX); + int n = 0; + for (auto &&i : axes) { + MY_ASSERT(i < shape.size(), "slice: axes must be less than the X rank."); + fixedStarts[i] = starts[n]; + fixedEnds[i] = ends[n]; + n++; + } + + auto startsNode = ngraph::opset6::Constant::create(ngraph::element::i32, { shape.size() }, fixedStarts); + auto endsNode = ngraph::opset6::Constant::create(ngraph::element::i32, { shape.size() }, fixedEnds); + auto stridesNode = ngraph::opset6::Constant::create(ngraph::element::i32, { shape.size() }, std::vector(shape.size(), 1)); + return {std::make_shared(data, + startsNode, + endsNode, + stridesNode, + std::vector(shape.size(), 0), + std::vector(shape.size(), 0))}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/slice.hpp b/ngraph/frontend/paddlepaddle/src/op/slice.hpp new file mode 100644 index 00000000000000..9eda21349515fa --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/slice.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector slice (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/squeeze.cpp b/ngraph/frontend/paddlepaddle/src/op/squeeze.cpp new file mode 100644 index 00000000000000..e22e9ee98acec3 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/squeeze.cpp @@ -0,0 +1,45 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "squeeze.hpp" +#include + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector squeeze (const NodeContext& node) { + auto data = node.get_ng_input("X"); + auto axes = node.get_attribute>("axes"); + MY_ASSERT(data.get_partial_shape().rank().is_static(), "squeeze: X rank must be static!"); + + auto shape = data.get_partial_shape().to_shape(); + for (auto &&i : axes) { + auto idx = i; + if (idx < 0) { + idx = i + shape.size(); + } + MY_ASSERT(idx < shape.size(), "squeeze: axes value must be < max_rank."); + MY_ASSERT(shape[idx] == 1, "squeeze: the specified dimension is not equal to one."); + } + + auto axesNode = ngraph::opset6::Constant::create(ngraph::element::i32, {axes.size()}, axes); + return {std::make_shared(data, axesNode)}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/squeeze.hpp b/ngraph/frontend/paddlepaddle/src/op/squeeze.hpp new file mode 100644 index 00000000000000..b478cc95d3e096 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/squeeze.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector squeeze (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/unsqueeze.cpp b/ngraph/frontend/paddlepaddle/src/op/unsqueeze.cpp new file mode 100644 index 00000000000000..5d7430e9e14967 --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/unsqueeze.cpp @@ -0,0 +1,33 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#include +#include "unsqueeze.hpp" +#include + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector unsqueeze (const NodeContext& node) { + auto data = node.get_ng_input("X"); + auto axes = node.get_attribute>("axes"); + auto axesNode = ngraph::opset6::Constant::create(ngraph::element::i32, {axes.size()}, axes); + return {std::make_shared(data, axesNode)}; +} + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op/unsqueeze.hpp b/ngraph/frontend/paddlepaddle/src/op/unsqueeze.hpp new file mode 100644 index 00000000000000..801f1c9d1de0dc --- /dev/null +++ b/ngraph/frontend/paddlepaddle/src/op/unsqueeze.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// 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. +//***************************************************************************** + +#pragma once +#include "node_context.hpp" + +namespace ngraph { +namespace frontend { +namespace pdpd { +namespace op { + +OutputVector unsqueeze (const NodeContext& node); + +}}}} \ No newline at end of file diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index a6d25f0c82a3cd..97c7808f40d246 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -34,6 +34,14 @@ #include "op/transpose2.hpp" #include "op/yolo_box.hpp" #include "op/multiclass_nms.hpp" +#include "op/sigmoid.hpp" +#include "op/hard_sigmoid.hpp" +#include "op/relu6.hpp" +#include "op/pow.hpp" +#include "op/squeeze.hpp" +#include "op/unsqueeze.hpp" +#include "op/slice.hpp" +#include "op/hard_swish.hpp" #include "op_table.hpp" @@ -68,8 +76,16 @@ std::map get_supported_ops() { {"softmax", op::softmax}, {"transpose2", op::transpose2}, {"yolo_box", op::yolo_box}, - {"multiclass_nms3", op::multiclass_nms} - }; + {"multiclass_nms3", op::multiclass_nms}, + {"sigmoid", op::sigmoid}, + {"hard_sigmoid", op::hard_sigmoid}, + {"relu6", op::relu6}, + {"pow", op::pow}, + {"squeeze2", op::squeeze}, + {"unsqueeze2", op::unsqueeze}, + {"slice", op::slice}, + {"hard_swish", op::hard_swish}, + }; }; }}} diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_sigmoid.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_sigmoid.py new file mode 100644 index 00000000000000..be249536ecb926 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_sigmoid.py @@ -0,0 +1,36 @@ +# +# hard_sigmoid paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def hard_sigmoid(name : str, x, slope : float = 0.2, offset : float = 0.5): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.hard_sigmoid(node_x, slope=slope, offset=offset, name='hard_sigmoid') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + data = np.array([0, 1, 2, 3, 4, 5, 6, -10]).astype(data_type) + + hard_sigmoid("hard_sigmoid", data, 0.1, 0.6) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_swish.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_swish.py new file mode 100644 index 00000000000000..2d27b5200655d6 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_hard_swish.py @@ -0,0 +1,36 @@ +# +# sigmoid paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def hard_swish(name : str, x, threshold=6.0, scale=6.0, offset=3.0): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=data_type) + out = pdpd.fluid.layers.hard_swish(node_x, threshold=threshold, scale=scale, offset=offset, name='hard_swish') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + data = np.array([-6, 1, 6]).astype(data_type) + + hard_swish("hard_swish", data) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_leaky_relu.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_leaky_relu.py new file mode 100644 index 00000000000000..f75063f5a29357 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_leaky_relu.py @@ -0,0 +1,36 @@ +# +# leaky_relu paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def leaky_relu(name : str, x, alpha : float = 0.02): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.leaky_relu(node_x, alpha=alpha, name='leaky_relu') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + data = np.array([-1, 2, 3]).astype(data_type) + + leaky_relu("leaky_relu", data, 0.03) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_pow.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pow.py new file mode 100644 index 00000000000000..c3f31048fbe0d9 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_pow.py @@ -0,0 +1,36 @@ +# +# pow paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def pow(name : str, x, y): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.pow(node_x, y, name = 'pow') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + x = np.array([0, 1, 2, -10]).astype(data_type) + + pow("pow", x, 2.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_relu6.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_relu6.py new file mode 100644 index 00000000000000..1cc995ea71d4f1 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_relu6.py @@ -0,0 +1,36 @@ +# +# relu6 paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def relu6(name : str, x, threshold : float = 6.0): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.relu6(node_x, threshold=threshold, name='relu6') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + data = np.array([-1, 1, 5]).astype(data_type) + + relu6("relu6", data, 4) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_sigmoid.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_sigmoid.py new file mode 100644 index 00000000000000..13375aa659120b --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_sigmoid.py @@ -0,0 +1,36 @@ +# +# sigmoid paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def sigmoid(name : str, x): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.sigmoid(node_x, name='sigmoid') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + data = np.array([0, 1, -1]).astype(data_type) + + sigmoid("sigmoid", data) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_slice.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_slice.py new file mode 100644 index 00000000000000..f3db16e80db1f9 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_slice.py @@ -0,0 +1,38 @@ +# +# slice paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def slice(name : str, x, axes : list, start : list, end : list): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.slice(node_x, axes = axes, starts = start, ends = end) + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + x = np.linspace(1, 60, num = 60, dtype=np.int32).reshape(4, 3, 5).astype(data_type) + slice("slice", x, axes=[1, 2], start=(0, 1), end=(-1, 3)) + + x = np.linspace(1, 60, num = 60, dtype=np.int32).reshape(2, 30).astype(data_type) + slice("slice_1d", x, axes=[0], start=[0], end=[1]) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_squeeze.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_squeeze.py new file mode 100644 index 00000000000000..f6a66dc8f0d72b --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_squeeze.py @@ -0,0 +1,37 @@ +# +# squeeze paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def squeeze(name : str, x, axes : list): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.squeeze(node_x, axes=axes, name='squeeze') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + data = np.random.rand(1, 3, 1, 4).astype(data_type) + + squeeze("squeeze", data, [0, -2]) + squeeze("squeeze_null_axes", data, []) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_unsqueeze.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_unsqueeze.py new file mode 100644 index 00000000000000..a6a6389ffe99b3 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_unsqueeze.py @@ -0,0 +1,36 @@ +# +# unsqueeze paddle model generator +# +import numpy as np +from save_model import saveModel +import paddle as pdpd + +data_type = 'float32' + +def unsqueeze(name : str, x, axes : list): + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype = data_type) + out = pdpd.fluid.layers.unsqueeze(node_x, axes = axes, name = 'unsqueeze') + + 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={'x': x}, + fetch_list=[out]) + + saveModel(name, exe, feedkeys=['x'], fetchlist=[out], inputs=[x], outputs=[outs[0]]) + + return outs[0] + +def main(): + data = np.random.rand(5, 10).astype(data_type) + + unsqueeze("unsqueeze", data, [1]) + +if __name__ == "__main__": + main() \ No newline at end of file From 7ad16a0b0e43ac8a62fc0ad26c03b979be17ec1c Mon Sep 17 00:00:00 2001 From: Luo Cheng Date: Thu, 22 Apr 2021 08:44:08 +0800 Subject: [PATCH 48/54] support exec in non-py directory --- ngraph/test/files/paddlepaddle/gen_scripts/save_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index eb1c2398779f8d..a7ec6ba888f875 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -38,7 +38,7 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis for key, value in kwargv.items(): print ("%s == %s" %(key, value)) - model_dir = "../models/"+name + model_dir = os.path.dirname(os.path.abspath(__file__)) + '/../models/%s' %(name) if not os.path.exists(model_dir): os.makedirs(model_dir) From 2cc9dd36e44be565797ec8646ed3e4b32ed8a78d Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 22 Apr 2021 21:24:59 +0800 Subject: [PATCH 49/54] yolo_box Fuzzy test okay. --- .../frontend/paddlepaddle/src/op/yolo_box.cpp | 54 ++--- .../gen_scripts/generate_yolo_box.py | 59 ++++- .../paddlepaddle/gen_scripts/save_model.py | 11 +- ngraph/test/frontend/paddlepaddle/op.cpp | 223 +++++++++++++----- ngraph/test/frontend/shared/src/basic_api.cpp | 2 +- 5 files changed, 237 insertions(+), 112 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp index 3892c4a1554a74..9d654c2007bb9f 100644 --- a/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/yolo_box.cpp @@ -248,6 +248,7 @@ OutputVector yolo_box (const NodeContext& node_context) { // Paddle/python/paddle/fluid/tests/unittests/test_yolo_box_op.py // Paddle/paddle/fluid/operators/detection/yolo_box_op.h // Paddle2ONNX/paddle2onnx/op_mapper/detection/yolo_box.py - clip_bbox is not used by Paddle2ONNX. + std::shared_ptr node_pred_box_result; if (clip_bbox) { auto node_number_one = Constant::create(f32, {1}, {1.0}); auto node_new_img_height = std::make_shared(node_img_height_cast, node_number_one); @@ -264,46 +265,29 @@ OutputVector yolo_box (const NodeContext& node_context) { auto node_pred_box_x2_res = std::make_shared(node_pred_box_x2_decode, node_pred_box_x2_clip); auto node_pred_box_y2_res = std::make_shared(node_pred_box_y2_decode, node_pred_box_y2_clip); - auto node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_clip, node_pred_box_y1_clip, - node_pred_box_x2_res, node_pred_box_y2_res}, -1); //outputs=node.output('Boxes') - - auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); - auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') - -#if 0 - return OutputVector{node_pred_box_result, node_score_new_shape}; -#else - //FIXME: combine the two output nodes into 1, to satisfy frontend/pdpd. - auto node_result_concat = std::make_shared(OutputVector{node_pred_box_result, node_score_new_shape}, 2); - - auto result_split_axis = Constant::create(i64, {1}, {2}); //(1,xx,6) -> bboxes(1,xx,4) and scores(1,xx,class_num) - auto result_split_axes_lengths = Constant::create(i64, {2}, {4, class_num}); - auto node_result = std::make_shared(node_result_concat, result_split_axis, result_split_axes_lengths); - //return OutputVector{node_result}; - return node_result->outputs(); -#endif + node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_clip, node_pred_box_y1_clip, + node_pred_box_x2_res, node_pred_box_y2_res}, -1); //outputs=node.output('Boxes') } else { - auto node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_decode, node_pred_box_y1_decode, - node_pred_box_x2_decode, node_pred_box_y2_decode}, -1); //outputs=node.output('Boxes') + node_pred_box_result = std::make_shared(OutputVector{node_pred_box_x1_decode, node_pred_box_y1_decode, + node_pred_box_x2_decode, node_pred_box_y2_decode}, -1); //outputs=node.output('Boxes') + } - auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); - auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') + // + auto node_score_shape = Constant::create(i64, {score_shape.size()}, score_shape); + auto node_score_new_shape = std::make_shared(node_score, node_score_shape, false); //outputs=node.output('Scores') + //TODO: combine the two output nodes into 1, to satisfy frontend/pdpd. #if 0 - return OutputVector{node_pred_box_result, node_score_new_shape}; -#else - //FIXME: combine the two output nodes into 1, to satisfy frontend/pdpd. - auto node_result_concat = std::make_shared(OutputVector{node_pred_box_result, node_score_new_shape}, 2); - - auto result_split_axis = Constant::create(i64, {1}, {2}); //(1,xx,6) -> bboxes(1,xx,4) and scores(1,xx,class_num) - auto result_split_axes_lengths = Constant::create(i64, {2}, {4, class_num}); - auto node_result = std::make_shared(node_result_concat, result_split_axis, result_split_axes_lengths); - //return OutputVector{node_result}; - return node_result->outputs(); -#endif - } - + return OutputVector{node_pred_box_result, node_score_new_shape}; +#else + auto node_result_concat = std::make_shared(OutputVector{node_pred_box_result, node_score_new_shape}, 2); + + auto result_split_axis = Constant::create(i64, {1}, {2}); //(1,xx,6) -> bboxes(1,xx,4) and scores(1,xx,class_num) + auto result_split_axes_lengths = Constant::create(i64, {2}, {4, class_num}); + auto node_result = std::make_shared(node_result_concat, result_split_axis, result_split_axes_lengths); + return node_result->outputs(); +#endif } }}}} \ No newline at end of file diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py index 56e098ee0c1e82..25dea9437cf36a 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_yolo_box.py @@ -26,15 +26,13 @@ def yolo_box(name : str, x, img_size, attrs : dict): # startup program will call initializer to initialize the parameters. exe.run(pdpd.static.default_startup_program()) - input_dict = {'x': x, 'img_size': img_size} - input_dict = dict(sorted(input_dict.items())) - outs = exe.run( - feed=input_dict, + feed={'x': x, 'img_size': img_size}, fetch_list=[boxes, scores]) - - #save inputs in alphabeta order, as it is in pdpd frontend. - saveModel(name, exe, feedkeys=list(input_dict.keys()), fetchlist=[boxes, scores], inputs=list(input_dict.values()), outputs=outs) + + # 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=['x', 'img_size'], fetchlist=[boxes, scores], inputs=[x, img_size], outputs=outs) return outs @@ -50,7 +48,7 @@ def onnx_run(x, img_size, onnx_model="../models/yolo_box_test1/yolo_box_test1.on print(pred_onx) return pred_onx -def IE_run(x, img_size, path_to_ie_model="../models/yolo_box_test1/yolo_box"): +def OV_IR_run(x, img_size, path_to_ie_model="../models/yolo_box_test1/fuzzy"): from openvino.inference_engine import IECore #IE inference @@ -61,6 +59,40 @@ def IE_run(x, img_size, path_to_ie_model="../models/yolo_box_test1/yolo_box"): print(type(pred_ie)) return pred_ie +def OV_frontend_run(x, img_size, path_to_pdpd_model="../models/yolo_box_test1/", user_shapes=[]): + from ngraph import FrontEndManager # pylint: disable=import-error + from ngraph import function_to_cnn # pylint: disable=import-error + from ngraph import PartialShape # pylint: disable=import-error + + fem = FrontEndManager() + print('fem.availableFrontEnds: ' + str(fem.availableFrontEnds())) + print('Initializing new FE for framework {}'.format("pdpd")) + fe = fem.loadByFramework("pdpd") + print(fe) + inputModel = fe.loadFromFile(path_to_pdpd_model) + try: + place = inputModel.getPlaceByTensorName('x') + print(place) + print(place.isEqual(None)) + except Exception: + print('Failed to call model API with hardcoded input name "x"') + + if len(user_shapes) > 0: + for user_shape in user_shapes: + inputModel.setPartialShape(user_shape['node'], PartialShape(user_shape['shape'])) + nGraphModel = fe.convert(inputModel) + + net = function_to_cnn(nGraphModel) + + from openvino.inference_engine import IECore + + #IE inference + ie = IECore() + exec_net = ie.load_network(net, "CPU") + pred_ie = exec_net.infer({"img_size": img_size, "x": x}) + print(type(pred_ie)) + return pred_ie + def checker(outs, dump=False): if type(outs) is list: for i in range(len(outs)): @@ -130,7 +162,7 @@ def main(): 'class_num': 2, 'conf_thresh': 0.5, 'downsample_ratio': 32, - 'clip_bbox': True, #There is bug in Paddle2ONN where clip_bbox is always ignored. + 'clip_bbox': False, #There is bug in Paddle2ONN where clip_bbox is always ignored. 'scale_x_y': 1.0 } @@ -152,10 +184,13 @@ def main(): subprocess.run(["paddle2onnx", "--model_dir=../models/yolo_box_test1/", "--save_file=../models/yolo_box_test1/yolo_box_test1.onnx", "--opset_version=12"]) pred_onx = onnx_run(data, data_ImSize) - # step 3. generate OV IR + # step 3.a generate OV IR # MO or ngraph/frontend/paddlepaddle Fuzzy unit test helper. - subprocess.run(["unit-test", "--gtest_filter=*Fuzzy*"]) - pred_ie = IE_run(data, data_ImSize) + #subprocess.run(["unit-test", "--gtest_filter=*Fuzzy*"]) + #pred_ie = OV_IR_run(data, data_ImSize) + + # step3.b alternatively, run from frontend API + pred_ie = OV_frontend_run(data, data_ImSize) # step 4. compare # Try different tolerence diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py index eb1c2398779f8d..1d25293ce4099d 100644 --- a/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py +++ b/ngraph/test/files/paddlepaddle/gen_scripts/save_model.py @@ -34,22 +34,21 @@ def print_array(arr, end=' '): print(print_array(arr, "}")) -def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list, **kwargv): - for key, value in kwargv.items(): - print ("%s == %s" %(key, value)) - +def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list): model_dir = "../models/"+name if not os.path.exists(model_dir): os.makedirs(model_dir) print("\n\n------------- %s -----------\n" % (name)) for i, input in enumerate(inputs): - print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype) + print("INPUT %s :" % (feedkeys[i]), input.shape, input.dtype, "\n") print_alike(input) np.save(os.path.join(model_dir, "input{}".format(i)), input) + np.save(os.path.join(model_dir, "input{}.{}.{}".format(i, feedkeys[i], input.dtype)), input) print("\n") + for i, output in enumerate(outputs): - print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype) + print("OUTPUT %s :" % (fetchlist[i]),output.shape, output.dtype, "\n") print_alike(output) np.save(os.path.join(model_dir, "output{}".format(i)), output) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 97f7d84ae3ccb2..34060a7dee10d3 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -13,6 +13,11 @@ #include "util/test_control.hpp" #include "util/test_tools.hpp" +#include "ngraph/ngraph.hpp" + +using namespace ngraph; +using namespace InferenceEngine; + #include "../shared/include/basic_api.hpp" // library taken from https://github.com/llohse/libnpy @@ -25,46 +30,70 @@ using TestEngine = test::IE_CPU_Engine; static const std::string PDPD = "pdpd"; static const std::string PATH_TO_MODELS = "/paddlepaddle/models/"; +/* helper */ +static bool ends_with(std::string const & value, std::string const & ending) { + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +static bool starts_with(std::string const & value, std::string const & starting) { + if (starting.size() > value.size()) return false; + return std::equal(starting.begin(), starting.end(), value.begin()); +} + +static std::string get_modelfolder(std::string& modelfile) { + if (!ends_with(modelfile, ".pdmodel")) return modelfile; + size_t found = modelfile.find_last_of("/\\"); + return modelfile.substr(0,found); +}; + +static const std::string& trim_space(std::string& str) //trim leading and tailing spaces +{ + //leading + auto it = str.begin(); + for (; it != str.end() && isspace(*it); it++); + auto d = std::distance(str.begin(), it); + str.erase(0,d); + + //tailing + auto rit = str.rbegin(); + for (; rit != str.rend() && isspace(*rit); rit++) { + str.pop_back(); + } + + //std::cout << "[" << str << "]" << std::endl; + return str; +} + +static std::vector get_models(void) { + std::string models_csv = std::string(TEST_FILES) + PATH_TO_MODELS + "models.csv"; + std::ifstream f(models_csv); + std::vector models; + std::string line; + while (getline(f, line, ',')) { + auto line_trim = trim_space(line); + if(line_trim.empty() || + starts_with(line_trim, "#")) + continue; + // std::cout<< "line in csv: [" << line_trim<< "]" << std::endl; + models.emplace_back(line_trim); + } + return models; +} + +static void visualizer(std::shared_ptr function, std::string path) { + ngraph::pass::VisualizeTree("function.png").run_on_function(function); + + CNNNetwork network(function); + network.serialize(path+".xml", path+".bin"); +} + namespace fuzzyOp { using PDPDFuzzyOpTest = FrontEndBasicTest; using PDPDFuzzyOpTestParam = std::tuple; // modelname - /* - // There are 2 versions of PDPD model. - // * decomposed model, which is a folder. - // * composed model, which is a file with extension .pdmodel. - */ - bool ends_with(std::string const & value, std::string const & ending) { - if (ending.size() > value.size()) return false; - return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); - } - - const std::string& trim_leadingspace(std::string& str) - { - auto it = str.begin(); - for (; it != str.end() && isspace(*it); it++); - auto d = std::distance(str.begin(), it); - std::cout << d << std::endl; - return str.erase(0,d); - } - - std::vector get_models(void) { - std::string models_csv = std::string(TEST_FILES) + PATH_TO_MODELS + "models.csv"; - std::ifstream f(models_csv); - std::vector models; - std::string line; - while (getline(f, line, ',')) { - auto line_trim = trim_leadingspace(line); - std::cout<< "line in csv: " << line_trim< function, std::string& modelfile) { auto _load_from_npy = [&](std::string& file_path) { std::ifstream npy_file(file_path); @@ -75,40 +104,117 @@ namespace fuzzyOp { return npy_data; }; + auto _load_int32_from_npy = [&](std::string& file_path) { + std::ifstream npy_file(file_path); + std::vector npy_shape; + std::vector npy_data; + if (npy_file.good()) + npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); - auto _get_modelfolder = [&](std::string& modelfile) { - if (!ends_with(modelfile, ".pdmodel")) return modelfile; + return npy_data; + }; - size_t found = modelfile.find_last_of("/\\"); + auto _get_npy_dtype = [&](std::string& filename) { + std::ifstream stream(filename, std::ifstream::binary); + if(!stream) { + throw std::runtime_error("io error: failed to open a file."); + } - return modelfile.substr(0,found); - }; + std::string header = npy::read_header(stream); - auto modelfolder = _get_modelfolder(modelfile); + // parse header + bool fortran_order; + std::string typestr; + std::vectorshape; - std::string input_path = modelfolder+"/input0.npy"; - std::string output_path = modelfolder+"/output0.npy"; - auto npy_input = _load_from_npy(input_path); - auto npy_output = _load_from_npy(output_path); - if (npy_input.empty() || npy_output.empty()) { - throw std::runtime_error("failed to load input/output npy for test case. Tried " + input_path); - } + npy::parse_header(header, typestr, fortran_order, shape); - // TODO: to support more inputs/outputs - // TODO: to support different data type. - std::vector data_input(npy_input.size()); - std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); + std::cout << "$$$$$$$$$" << filename << ": " << typestr << std::endl; + return typestr; + }; - std::vector data_output(npy_output.size()); - std::copy_n(npy_output.data(), npy_output.size(), data_output.begin()); + auto modelfolder = get_modelfolder(modelfile); // run test auto test_case = test::TestCase(function); - test_case.add_input(data_input); - test_case.add_expected_output(npy_output); + const auto parameters = function->get_parameters(); + for (auto i = 0; i < parameters.size(); i++) { + // read input npy file + std::string input_path = modelfolder+"/input"+std::to_string((parameters.size()-1)-i)+".npy"; + + auto dtype = _get_npy_dtype(input_path); + if (dtype == " data_input(npy_input.size()); + std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); + + const auto& input_pshape = parameters.at(i)->get_output_partial_shape(0); + std::cout << "input_pshape###########" << input_pshape << std::endl; + test_case.add_input(data_input); + + } else if (dtype == " data_input(npy_input.size()); + std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); + + const auto& input_pshape = parameters.at(i)->get_output_partial_shape(0); + std::cout << "input_pshape###########" << input_pshape << std::endl; + test_case.add_input(data_input); + } else { + throw std::runtime_error("not supported dtype in" + dtype); + } + } + + const auto results = function->get_results(); + for (auto i = 0; i < results.size(); i++) { + // read input npy file + std::string datafile = modelfolder+"/output"+std::to_string(i)+".npy"; + + auto dtype = _get_npy_dtype(datafile); + if (dtype == " data_input(npy_input.size()); + std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); + + const auto& input_pshape = results.at(i)->get_output_partial_shape(0); + std::cout << "input_pshape###########" << input_pshape << std::endl; + test_case.add_expected_output(data_input); + + } else if (dtype == " data_input(npy_input.size()); + std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); + + const auto& input_pshape = results.at(i)->get_output_partial_shape(0); + std::cout << "output_pshape###########" << input_pshape << std::endl; + test_case.add_expected_output(data_input); + } else { + throw std::runtime_error("not supported dtype out "+ dtype); + } + } - test_case.run(); + test_case.run_with_tolerance_as_fp(1e-4); } TEST_P(PDPDFuzzyOpTest, test_fuzzy) { @@ -120,6 +226,9 @@ namespace fuzzyOp { function = m_frontEnd->convert(m_inputModel); ASSERT_NE(function, nullptr); + // debug + //visualizer(function, get_modelfolder(m_modelFile)+"/fuzzy"); + // run run_fuzzy(function, m_modelFile); } @@ -128,8 +237,6 @@ namespace fuzzyOp { ::testing::Combine( ::testing::Values(PDPD), ::testing::Values(PATH_TO_MODELS), - //::testing::ValuesIn({std::string("maxPool_test1"), - // std::string("avgPool_test1/avgPool_test1.pdmodel")})), ::testing::ValuesIn(get_models())), PDPDFuzzyOpTest::getTestCaseName); diff --git a/ngraph/test/frontend/shared/src/basic_api.cpp b/ngraph/test/frontend/shared/src/basic_api.cpp index b79780db473359..2eb8df217615f3 100644 --- a/ngraph/test/frontend/shared/src/basic_api.cpp +++ b/ngraph/test/frontend/shared/src/basic_api.cpp @@ -11,7 +11,7 @@ using namespace ngraph::frontend; std::string FrontEndBasicTest::getTestCaseName(const testing::TestParamInfo &obj) { std::string fe, path, fileName; std::tie(fe, path, fileName) = obj.param; - std::cout <<" *** " << fe << " *** " << path << " *** " << fileName << " *** " << std::endl; + //std::cout <<" *** " << fe << " *** " << path << " *** " << fileName << " *** " << std::endl; // need to replace special characters to create valid test case name fileName = std::regex_replace(fileName, std::regex("[/\\.]"), "_"); return fe + "_" + fileName; From dce044e7f9efd521da8ddb7c84109fbf15addcb4 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 22 Apr 2021 22:29:28 +0800 Subject: [PATCH 50/54] refactor Fuzzy test, to support multiple inputs and outputs. --- ngraph/test/frontend/paddlepaddle/op.cpp | 136 ++++++++--------------- 1 file changed, 48 insertions(+), 88 deletions(-) diff --git a/ngraph/test/frontend/paddlepaddle/op.cpp b/ngraph/test/frontend/paddlepaddle/op.cpp index 34060a7dee10d3..30f29d45a26b18 100644 --- a/ngraph/test/frontend/paddlepaddle/op.cpp +++ b/ngraph/test/frontend/paddlepaddle/op.cpp @@ -88,6 +88,35 @@ static void visualizer(std::shared_ptr function, std::string p network.serialize(path+".xml", path+".bin"); } +std::string get_npy_dtype(std::string& filename) { + std::ifstream stream(filename, std::ifstream::binary); + if(!stream) { + throw std::runtime_error("io error: failed to open a file."); + } + + std::string header = npy::read_header(stream); + + // parse header + bool fortran_order; + std::string typestr; + std::vectorshape; + + npy::parse_header(header, typestr, fortran_order, shape); + return typestr; +} + +template +void load_from_npy(std::string& file_path, std::vector &npy_data) { + std::ifstream npy_file(file_path); + std::vector npy_shape; + if (npy_file.good()) + npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); + + if (npy_data.empty()) { + throw std::runtime_error("failed to load npy for test case "+file_path); + } +} + namespace fuzzyOp { using PDPDFuzzyOpTest = FrontEndBasicTest; using PDPDFuzzyOpTestParam = std::tuple; // modelname void run_fuzzy(std::shared_ptr function, std::string& modelfile) { - auto _load_from_npy = [&](std::string& file_path) { - std::ifstream npy_file(file_path); - std::vector npy_shape; - std::vector npy_data; - if (npy_file.good()) - npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); - - return npy_data; - }; - auto _load_int32_from_npy = [&](std::string& file_path) { - std::ifstream npy_file(file_path); - std::vector npy_shape; - std::vector npy_data; - if (npy_file.good()) - npy::LoadArrayFromNumpy(file_path, npy_shape, npy_data); - - return npy_data; - }; - - auto _get_npy_dtype = [&](std::string& filename) { - std::ifstream stream(filename, std::ifstream::binary); - if(!stream) { - throw std::runtime_error("io error: failed to open a file."); - } - - std::string header = npy::read_header(stream); - - // parse header - bool fortran_order; - std::string typestr; - std::vectorshape; - - npy::parse_header(header, typestr, fortran_order, shape); - - std::cout << "$$$$$$$$$" << filename << ": " << typestr << std::endl; - return typestr; - }; + auto modelfolder = get_modelfolder(modelfile); @@ -141,80 +134,47 @@ namespace fuzzyOp { const auto parameters = function->get_parameters(); for (auto i = 0; i < parameters.size(); i++) { // read input npy file - std::string input_path = modelfolder+"/input"+std::to_string((parameters.size()-1)-i)+".npy"; + std::string datafile = modelfolder+"/input"+std::to_string((parameters.size()-1)-i)+".npy"; - auto dtype = _get_npy_dtype(input_path); + auto dtype = get_npy_dtype(datafile); if (dtype == " data_input(npy_input.size()); - std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); - - const auto& input_pshape = parameters.at(i)->get_output_partial_shape(0); - std::cout << "input_pshape###########" << input_pshape << std::endl; - test_case.add_input(data_input); - + std::vector data_in; + load_from_npy(datafile, data_in); + test_case.add_input(data_in); } else if (dtype == " data_input(npy_input.size()); - std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); - - const auto& input_pshape = parameters.at(i)->get_output_partial_shape(0); - std::cout << "input_pshape###########" << input_pshape << std::endl; - test_case.add_input(data_input); + std::vector data_in; + load_from_npy(datafile, data_in); + test_case.add_input(data_in); } else { throw std::runtime_error("not supported dtype in" + dtype); - } + } } const auto results = function->get_results(); for (auto i = 0; i < results.size(); i++) { - // read input npy file + // read expected output npy file std::string datafile = modelfolder+"/output"+std::to_string(i)+".npy"; - auto dtype = _get_npy_dtype(datafile); + auto dtype = get_npy_dtype(datafile); if (dtype == " data_input(npy_input.size()); - std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); - - const auto& input_pshape = results.at(i)->get_output_partial_shape(0); - std::cout << "input_pshape###########" << input_pshape << std::endl; - test_case.add_expected_output(data_input); - + std::vector data_in; + load_from_npy(datafile, data_in); + test_case.add_expected_output(data_in); } else if (dtype == " data_input(npy_input.size()); - std::copy_n(npy_input.data(), npy_input.size(), data_input.begin()); - - const auto& input_pshape = results.at(i)->get_output_partial_shape(0); - std::cout << "output_pshape###########" << input_pshape << std::endl; - test_case.add_expected_output(data_input); + std::vector data_in; + load_from_npy(datafile, data_in); + test_case.add_expected_output(data_in); } else { throw std::runtime_error("not supported dtype out "+ dtype); } } test_case.run_with_tolerance_as_fp(1e-4); + // test_case.run(); } TEST_P(PDPDFuzzyOpTest, test_fuzzy) { From 3fb4129ca7c75285a69b9f879fb5f21e51ca6045 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 22 Apr 2021 22:38:42 +0800 Subject: [PATCH 51/54] models.csv for Fuzzy Op test. --- ngraph/test/files/paddlepaddle/models/models.csv | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 ngraph/test/files/paddlepaddle/models/models.csv diff --git a/ngraph/test/files/paddlepaddle/models/models.csv b/ngraph/test/files/paddlepaddle/models/models.csv new file mode 100644 index 00000000000000..1e62e961054789 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/models/models.csv @@ -0,0 +1,15 @@ +#yolo_box_test1, +avgPool_test1, +avgPool_test2, +avgPool_test3, +avgPool_test4, +avgPool_test5, +#avgPool_test6, +maxPool_test1, +maxPool_test2, +maxPool_test3, +maxPool_test4, +maxPool_test5, +#maxPool_test6, +avgAdaptivePool2D_test1, +#maxAdaptivePool2D_test1, From 0f9aa0f229c15508acc2cda0ef686d7e63c054f3 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 22 Apr 2021 22:39:10 +0800 Subject: [PATCH 52/54] gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 23fe8c3d55ce89..8cd490e3269fc6 100644 --- a/.gitignore +++ b/.gitignore @@ -71,4 +71,3 @@ ngraph/src/ngraphConfigVersion.cmake ngraph/src/protobuf/ ngraph/src/src/ ngraph/src/test/ -ngraph/test/files/paddlepaddle/models/* From 97ff2cb9e0354f793e85e0dd3991d82d07b705f3 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 22 Apr 2021 22:42:06 +0800 Subject: [PATCH 53/54] generator for split --- .../gen_scripts/generate_split.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 ngraph/test/files/paddlepaddle/gen_scripts/generate_split.py diff --git a/ngraph/test/files/paddlepaddle/gen_scripts/generate_split.py b/ngraph/test/files/paddlepaddle/gen_scripts/generate_split.py new file mode 100644 index 00000000000000..2de7f431113913 --- /dev/null +++ b/ngraph/test/files/paddlepaddle/gen_scripts/generate_split.py @@ -0,0 +1,51 @@ +# +# pool2d paddle model generator +# +import numpy as np +from save_model import saveModel + +def split(name : str, x, attrs : dict): + import paddle as pdpd + pdpd.enable_static() + + with pdpd.static.program_guard(pdpd.static.Program(), pdpd.static.Program()): + node_x = pdpd.static.data(name='x', shape=x.shape, dtype=x.dtype) + out = pdpd.fluid.layers.split(node_x, num_or_sections=attrs['num_or_sections'], dim=attrs['axis']) + + 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={'x': x}, + fetch_list=[out]) + print("outputs: ", type(outs),len(outs)) + print("out: ", type(out), len(out)) + + saveModel(name, exe, feedkeys=['x'], fetchlist=out, inputs=[x], outputs=outs) + + return outs[0] + +def main(): + # split + data_types = ['float32'] #TODOD: ['bool', 'float16', 'float32', 'float64', 'int32', 'int64'] + num_or_sections = [3, [2, 3, 4], [2, 3, -1]] + axes = [1, -2] + + idx = 1 + for t in data_types: + for s in num_or_sections: + for i in axes: + pdpd_attrs = { + 'num_or_sections': s, + 'axis': i + } + print(idx, t, s, i) + data_NCHW = np.random.rand(3,9,5).astype(t) + split("split_test{}".format(idx), data_NCHW, pdpd_attrs) + idx+=1 + + +if __name__ == "__main__": + main() \ No newline at end of file From f078fb8df059e458d8a6a6fd07aa4e5aaa2a5303 Mon Sep 17 00:00:00 2001 From: jialipen Date: Thu, 22 Apr 2021 23:33:47 +0800 Subject: [PATCH 54/54] fix conflict --- ngraph/frontend/paddlepaddle/src/op_table.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ngraph/frontend/paddlepaddle/src/op_table.cpp b/ngraph/frontend/paddlepaddle/src/op_table.cpp index 2ff8685493e034..594efed5e43b5e 100644 --- a/ngraph/frontend/paddlepaddle/src/op_table.cpp +++ b/ngraph/frontend/paddlepaddle/src/op_table.cpp @@ -89,7 +89,7 @@ std::map get_supported_ops() { {"bmm", op::matmul}, {"depthwise_conv2d", op::conv2d}, {"uniform_random", op::uniform_random}, - {"assign_value", op::assign_value} + {"assign_value", op::assign_value}, {"sigmoid", op::sigmoid}, {"hard_sigmoid", op::hard_sigmoid}, {"relu6", op::relu6}, @@ -97,7 +97,7 @@ std::map get_supported_ops() { {"squeeze2", op::squeeze}, {"unsqueeze2", op::unsqueeze}, {"slice", op::slice}, - {"hard_swish", op::hard_swish}, + {"hard_swish", op::hard_swish} }; };