From b8691c80bcf31739440e5458373210b2d80790b0 Mon Sep 17 00:00:00 2001 From: Vladislav Golubev Date: Mon, 20 Nov 2023 12:07:21 +0100 Subject: [PATCH] Review comments applied --- src/plugins/intel_cpu/src/graph_optimizer.cpp | 46 +++--- .../graph/merge_transpose_reorder_test.cpp | 134 ++++++++++++------ 2 files changed, 110 insertions(+), 70 deletions(-) diff --git a/src/plugins/intel_cpu/src/graph_optimizer.cpp b/src/plugins/intel_cpu/src/graph_optimizer.cpp index 417728fdda1d9a..edc5f8c74f560a 100644 --- a/src/plugins/intel_cpu/src/graph_optimizer.cpp +++ b/src/plugins/intel_cpu/src/graph_optimizer.cpp @@ -2523,32 +2523,28 @@ void GraphOptimizer::mergeTransposeReshapeReorder(Graph& graph, } OPENVINO_ASSERT(edge, "Parent node '", parentNode->getName(), "' has invalid edges."); - // transposeNode support blocked input & non-blocked output, in the case, the Reorder after Transpose cannot be optimized std::vector srcPerm; - if (!reverseOrder) { - // case 1. transposeNode support blocked input & non-blocked output, in the case, the reorder - // cannot be optimized - // case 2. Transpose and Reorder do opposite permutation to each other as expected, but isOptimized is already - // set false due to some preliminarily checks. We need to reinterpret layout Transpose input without physical - // change of the memory. - auto* castedTranspose = dynamic_cast(transposeNode.get()); - OPENVINO_ASSERT(castedTranspose, - "[CPU] parent node of type:", - transposeNode->getTypeStr(), - " with name: ", - transposeNode->getName(), - " is not a transpose node"); - - auto inOrder = transposeNode->getSelectedPrimitiveDescriptor()->getConfig().inConfs[0].getMemDesc()->as()->getOrder(); - auto outOrder = reorderOutDesc->as()->getOrder(); - if (!isOptimized || inOrder.size() > outOrder.size()) { - isOptimized = false; - // inDesc should be permuted before calling reorder - auto& ord = castedTranspose->getOrder(); - srcPerm = std::vector(ord.size()); - for (size_t i = 0; i < ord.size(); i++) { - srcPerm[ord[i]] = i; - } + auto* castedTranspose = dynamic_cast(transposeNode.get()); + OPENVINO_ASSERT(castedTranspose, + "[CPU] parent node of type:", + transposeNode->getTypeStr(), + " with name: ", + transposeNode->getName(), + " is not a transpose node"); + + auto inOrder = transposeNode->getSelectedPrimitiveDescriptor()->getConfig().inConfs[0].getMemDesc()->as()->getOrder(); + auto outOrder = reorderOutDesc->as()->getOrder(); + // Permutation must be set and reorder mustn't be optimized in 2 cases: + // 1. Transpose has blocked input & non-blocked output + // 2. Transpose and Reorder do opposite permutation to each other as expected, + // but isOptimized is already set to false due to some preliminarily checks. + if (!isOptimized || inOrder.size() > outOrder.size()) { + isOptimized = false; + // inDesc should be permuted before calling reorder + auto& ord = castedTranspose->getOrder(); + srcPerm = std::vector(ord.size()); + for (size_t i = 0; i < ord.size(); i++) { + srcPerm[ord[i]] = i; } } diff --git a/src/plugins/intel_cpu/tests/unit/graph/merge_transpose_reorder_test.cpp b/src/plugins/intel_cpu/tests/unit/graph/merge_transpose_reorder_test.cpp index 62f2a4d3271004..7225df64d9f564 100644 --- a/src/plugins/intel_cpu/tests/unit/graph/merge_transpose_reorder_test.cpp +++ b/src/plugins/intel_cpu/tests/unit/graph/merge_transpose_reorder_test.cpp @@ -3,25 +3,29 @@ // #include +#include +#include + +#include "edge.h" +#include "graph.h" +#include "ie_ngraph_utils.hpp" #include "node.h" -#include "nodes/reorder.h" #include "nodes/input.h" +#include "nodes/reorder.h" #include "nodes/transpose.h" -#include "graph.h" -#include "edge.h" - #include "ov_models/builders.hpp" -#include -#include "ie_ngraph_utils.hpp" +#include "utils/rt_info/memory_formats_attribute.hpp" + +#include "openvino/pass/visualize_tree.hpp" using namespace ov::intel_cpu; namespace MergeTransposeReorderCPUTest { class DummyNode : public Node { public: - DummyNode(const std::shared_ptr& op, const GraphContext::CPtr context) : - Node(op, context, PassThroughShapeInferFactory()) { - OPENVINO_THROW("Can't create DummyNode from ngraph node"); + DummyNode(const std::shared_ptr& op, const GraphContext::CPtr context) + : Node(op, context, PassThroughShapeInferFactory()) { + OPENVINO_THROW("Can't create DummyNode from OV node"); } DummyNode(const ov::Shape& shape, const ov::element::Type_t& prc, @@ -78,53 +82,86 @@ class DummyNode : public Node { } // namespace MergeTransposeReorderCPUTest using namespace MergeTransposeReorderCPUTest; +using LOOK = Edge::LOOK; +struct MergeTransposeReorderTestParams { + enum Result {IS_OPTIMIZED, NOT_OPTIMIZED}; + MergeTransposeReorderTestParams(const ov::Shape& testShape, + ov::element::Type_t testPrec, + LayoutType firstNodeLayout, + LOOK firstNodeInplaceDirection, + LayoutType secondNodeLayout, + LOOK secondNodeInplaceDirection, + Result test_result) + : testShape(testShape), + testPrec(testPrec), + firstNodeLayout(firstNodeLayout), + firstNodeInplaceDirection(firstNodeInplaceDirection), + secondNodeLayout(secondNodeLayout), + secondNodeInplaceDirection(secondNodeInplaceDirection), + test_result(test_result) {} + + ov::Shape testShape; + ov::element::Type_t testPrec; + LayoutType firstNodeLayout; + LOOK firstNodeInplaceDirection; + LayoutType secondNodeLayout; + LOOK secondNodeInplaceDirection; + Result test_result; +}; +using Result = MergeTransposeReorderTestParams::Result; /* * MergeTransposeReorderIsOptimizedCPUTest to test the CPU plugin-in MergeTransposeReorder graph optimizer * under the circumstance that the upstream node or downstream node is inPlaced thereby the inserted Reorder * cannot be optimized. */ -class MergeTransposeReorderIsOptimizedCPUTest : public ::testing::Test { +class MergeTransposeReorderIsOptimizedCPUTest : public testing::WithParamInterface, + public ov::test::TestsCommon { public: void Validate() const { CheckTransposeCount(0); - CheckReorderOptimized(std::string("_fake"), false); // the fused node is of name "reshape_abcd_acdb_fake" + const bool is_optimized = GetParam().test_result == MergeTransposeReorderTestParams::Result::IS_OPTIMIZED; + CheckReorderOptimized(std::string("_fake"), is_optimized); // the fused reorder has always postfix "fake" } +protected: void SetUp() override { - CreateGraph(); + MergeTransposeReorderTestParams params = GetParam(); + CreateGraph(params.testShape, + params.testPrec, + params.firstNodeLayout, + params.firstNodeInplaceDirection, + params.secondNodeLayout, + params.secondNodeInplaceDirection); } -protected: /* graph typology --------- |Input | --------- | ---------- - | Dummy | <*NOTE: fake node with laytout NCSP, and inplace from upstream*> + | Dummy | <*NOTE: fake node with firstNodeLayout, and firstNodeInplaceDirection*> ---------- | - |---------------| - | ---------- | - | |Transpose| | - | --------- | - | | | - | --------- | - | |Reorder | | <*NOTE: Reorder is inheristically inserted since Multiply is asking NSPC input.*> - | --------- | - |---------------| + ---------- + |Transpose| <*NOTE: Reorder is inserted before/after Transpose depending on first/second node layouts.*> + ---------- | ----------- - | Dummy | <*NOTE: fake node with laytout NSPC, and inplace from downstream*> + | Dummy | <*NOTE: fake node with secondNodeLayout, and secondNodeInplaceDirection*> ----------- | --------- |Output | --------- */ - void CreateGraph() { - // + void CreateGraph(const ov::Shape& testShape, + const ov::element::Type_t& testPrec, + LayoutType firstNodeLayout, + LOOK firstNodeInplaceDirection, + LayoutType secondNodeLayout, + LOOK secondNodeInplaceDirection) { Config conf; conf.rtCacheCapacity = 100; auto context = std::make_shared(conf, nullptr, nullptr, false); @@ -132,12 +169,13 @@ class MergeTransposeReorderIsOptimizedCPUTest : public ::testing::Test { m_graph = std::unique_ptr(new Graph()); + OPENVINO_ASSERT(testShape.size() == 4 || testShape.size() == 3, "Only 4D and 3D shapes are supported"); // ov::Model with only a transpose node - ov::ParameterVector params{std::make_shared(testPrec, ov::Shape(testShape))}; - auto order = std::vector{0, 3, 1, 2}; - auto constOrder = ngraph::builder::makeConstant(ngraph::element::i32, {order.size()}, order); - auto transpose = std::make_shared(params[0], constOrder); - ov::ResultVector results{std::make_shared(transpose)}; + ov::ParameterVector params{std::make_shared(testPrec, testShape)}; + auto order = testShape.size() == 4 ? std::vector{0, 3, 1, 2} : std::vector{0, 2, 1}; + auto constOrder = ngraph::builder::makeConstant(ov::element::i32, {order.size()}, order); + auto transpose = std::make_shared(params[0], constOrder); + ov::ResultVector results{std::make_shared(transpose)}; // Replicate auto replicate = [&](std::vector &nodes, std::vector &edges) -> void { @@ -153,20 +191,18 @@ class MergeTransposeReorderIsOptimizedCPUTest : public ::testing::Test { auto inputNode = std::make_shared(params[0], context); - // dummy ncsp + inPlace LOOK_UP auto dummyNode1 = std::make_shared(testShape, testPrec, "reshape", "DummyNode", context); - dummyNode1->setLayout(LayoutType::ncsp); - dummyNode1->setInplaceDirection(Edge::LOOK::LOOK_UP); + dummyNode1->setLayout(firstNodeLayout); + dummyNode1->setInplaceDirection(firstNodeInplaceDirection); auto orderNode = std::make_shared(constOrder, context); // const order auto transposeNode = std::make_shared(transpose, context); transposeNode->filterSupportedPrimitiveDescriptors(); - // dummy nspc + inPlace LOOK_DOWN - const ov::Shape shape_tranpose{testShape[0], testShape[3], testShape[1], testShape[2]}; // shape after transpose - auto dummyNode2 = std::make_shared(shape_tranpose, testPrec, "multiply", "DummyNode", context); - dummyNode2->setLayout(LayoutType::nspc); - dummyNode2->setInplaceDirection(Edge::LOOK::LOOK_DOWN); + const auto& transpose_shape = transpose->get_output_shape(0); + auto dummyNode2 = std::make_shared(transpose_shape, testPrec, "multiply", "DummyNode", context); + dummyNode2->setLayout(secondNodeLayout); + dummyNode2->setInplaceDirection(secondNodeInplaceDirection); auto outputNode = std::make_shared(results[0], context); @@ -215,12 +251,20 @@ class MergeTransposeReorderIsOptimizedCPUTest : public ::testing::Test { } private: - const ov::element::Type_t testPrec = ov::element::Type_t::f32; - const ov::Shape testShape{1, 3, 8, 16}; - std::unique_ptr m_graph; -}; // class MergeTransposeReorderIsOptimizedCPUTest +}; // class MergeTransposeReorderIsOptimizedCPUTest -TEST_F(MergeTransposeReorderIsOptimizedCPUTest, smoke_Run_MergeTransposeReorder_isOptimized) { +TEST_P(MergeTransposeReorderIsOptimizedCPUTest, smoke_Run_MergeTransposeReorder_isOptimized) { Validate(); -} \ No newline at end of file +} + +const std::vector params = { + {{1, 3, 8, 16}, ov::element::f32, LayoutType::ncsp, LOOK::LOOK_UP, LayoutType::nspc, LOOK::LOOK_DOWN, Result::NOT_OPTIMIZED}, + {{1, 3, 8, 16}, ov::element::f32, LayoutType::ncsp, LOOK::LOOK_DOWN, LayoutType::nspc, LOOK::LOOK_UP, Result::IS_OPTIMIZED}, + {{3, 8, 16}, ov::element::f32, LayoutType::nspc, LOOK::LOOK_UP, LayoutType::ncsp, LOOK::LOOK_DOWN, Result::NOT_OPTIMIZED}, + {{3, 8, 16}, ov::element::f32, LayoutType::nspc, LOOK::LOOK_DOWN, LayoutType::ncsp, LOOK::LOOK_UP, Result::IS_OPTIMIZED}, +}; + +INSTANTIATE_TEST_SUITE_P(smoke_Run_MergeTransposeReorder_isOptimized, + MergeTransposeReorderIsOptimizedCPUTest, + ::testing::ValuesIn(params)); \ No newline at end of file