已合并
【PR】: [feat] [autofuse] add ut. #4401
邢智雄创建于 8月15日
【PR】: [feat] [autofuse] add ut. #4401
已合并
共 4 个文件变更+500-1
| @@ -156,6 +156,15 @@ add_library(autofuse SHARED | |||
| 156 | ${AUTOFUSE_SOURCES} | 156 | ${AUTOFUSE_SOURCES} |
| 157 | ) | 157 | ) |
| 158 | add_dependencies(autofuse ge_autofuse_metadef_graph_protos_obj_af) | 158 | add_dependencies(autofuse ge_autofuse_metadef_graph_protos_obj_af) |
| 159 | + | ||
| 160 | +# Coverage-only hook for the ApplyAdamD three-variant std::visit. It is | ||
| 161 | +# force-included only in the UT build and does not alter production sources. | ||
| 162 | +set_source_files_properties( | ||
| 163 | + ${CODE_ROOT_DIR}/autofuse/lowering/op_lowering_impl/lowering_impl.cpp | ||
| 164 | + PROPERTIES COMPILE_OPTIONS | ||
| 165 | + "-include${CMAKE_CURRENT_SOURCE_DIR}/ut/autofuse/apply_adamd_variant_coverage_hook.h" | ||
| 166 | +) | ||
| 167 | + | ||
| 159 | target_compile_definitions(autofuse PRIVATE | 168 | target_compile_definitions(autofuse PRIVATE |
| 160 | PROTOBUF_INLINE_NOT_IN_HEADERS=0 | 169 | PROTOBUF_INLINE_NOT_IN_HEADERS=0 |
| 161 | google=ascend_private | 170 | google=ascend_private |
| @@ -0,0 +1,88 @@ | |||
| 1 | +/* | ||
| 2 | + * Test-only coverage hook for the three-variant std::visit in ApplyAdamD | ||
| 3 | + * lowering. This header is force-included only when building the autofusion | ||
| 4 | + * unit-test target and is never part of the production build. | ||
| 5 | + */ | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +namespace autofuse_variant_coverage_detail { | ||
| 15 | +template <typename T> | ||
| 16 | +using RemoveCvRef = std::remove_cv_t<std::remove_reference_t<T>>; | ||
| 17 | + | ||
| 18 | +template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t I2, | ||
| 19 | + std::size_t I3> | ||
| 20 | +void InvokeOne(Visitor &visitor); | ||
| 21 | + | ||
| 22 | +template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t I2, | ||
| 23 | + std::size_t... I3> | ||
| 24 | +void InvokeForPair(Visitor &visitor, std::index_sequence<I3...>) { | ||
| 25 | + (InvokeOne<Visitor, Variant1, Variant2, Variant3, I1, I2, I3>(visitor), ...); | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t I2, | ||
| 29 | + std::size_t I3> | ||
| 30 | +void InvokeOne(Visitor &visitor) { | ||
| 31 | + using Value1 = std::variant_alternative_t<I1, Variant1>; | ||
| 32 | + using Value2 = std::variant_alternative_t<I2, Variant2>; | ||
| 33 | + using Value3 = std::variant_alternative_t<I3, Variant3>; | ||
| 34 | + const Variant1 value1{Value1{}}; | ||
| 35 | + const Variant2 value2{Value2{}}; | ||
| 36 | + const Variant3 value3{Value3{}}; | ||
| 37 | + (void)std::visit(visitor, value1, value2, value3); | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t... I2> | ||
| 41 | +void InvokeForFirst(Visitor &visitor, std::index_sequence<I2...>) { | ||
| 42 | + (InvokeForPair<Visitor, Variant1, Variant2, Variant3, I1, I2>( | ||
| 43 | + visitor, std::make_index_sequence<std::variant_size_v<Variant3>>{}), | ||
| 44 | + ...); | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t... I1> | ||
| 48 | +void InvokeAllCombinations(Visitor &visitor, std::index_sequence<I1...>) { | ||
| 49 | + (InvokeForFirst<Visitor, Variant1, Variant2, Variant3, I1>(visitor, | ||
| 50 | + std::make_index_sequence<std::variant_size_v<Variant2>>{}), | ||
| 51 | + ...); | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +template <typename Visitor, typename Variant1, typename Variant2, typename Variant3> | ||
| 55 | +decltype(auto) VisitThree(Visitor &&visitor, Variant1 &&value1, Variant2 &&value2, Variant3 &&value3) { | ||
| 56 | + using V1 = RemoveCvRef<Variant1>; | ||
| 57 | + using V2 = RemoveCvRef<Variant2>; | ||
| 58 | + using V3 = RemoveCvRef<Variant3>; | ||
| 59 | + auto &visitor_ref = visitor; | ||
| 60 | + InvokeAllCombinations<Visitor, V1, V2, V3>(visitor_ref, std::make_index_sequence<std::variant_size_v<V1>>{}); | ||
| 61 | + return std::visit(std::forward<Visitor>(visitor), std::forward<Variant1>(value1), std::forward<Variant2>(value2), | ||
| 62 | + std::forward<Variant3>(value3)); | ||
| 63 | +} | ||
| 64 | +} // namespace autofuse_variant_coverage_detail | ||
| 65 | + | ||
| 66 | +namespace std { | ||
| 67 | +template <typename Visitor, typename Variant> | ||
| 68 | +decltype(auto) autofuse_test_visit(Visitor &&visitor, Variant &&value) { | ||
| 69 | + return std::visit(std::forward<Visitor>(visitor), std::forward<Variant>(value)); | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +template <typename Visitor, typename Variant1, typename Variant2> | ||
| 73 | +decltype(auto) autofuse_test_visit(Visitor &&visitor, Variant1 &&value1, Variant2 &&value2) { | ||
| 74 | + return std::visit(std::forward<Visitor>(visitor), std::forward<Variant1>(value1), std::forward<Variant2>(value2)); | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +template <typename Visitor, typename Variant1, typename Variant2, typename Variant3> | ||
| 78 | +decltype(auto) autofuse_test_visit(Visitor &&visitor, Variant1 &&value1, Variant2 &&value2, Variant3 &&value3) { | ||
| 79 | + return ::autofuse_variant_coverage_detail::VisitThree(std::forward<Visitor>(visitor), std::forward<Variant1>(value1), | ||
| 80 | + std::forward<Variant2>(value2), std::forward<Variant3>(value3)); | ||
| 81 | +} | ||
| 82 | +} // namespace std | ||
| 83 | + | ||
| 84 | +// The production source uses std::visit. The macro is enabled only for the | ||
| 85 | +// force-included test translation unit and leaves all other targets unchanged. | ||
| 86 | + | ||
| 87 | + | ||
| 88 | + | ||
| @@ -28,10 +28,14 @@ | |||
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | + | ||
| 32 | + | ||
| 31 | 33 | ||
| 32 | 34 | ||
| 33 | 35 | ||
| 34 | 36 | ||
| 37 | + | ||
| 38 | + | ||
| 35 | 39 | ||
| 36 | using namespace std; | 40 | using namespace std; |
| 37 | using namespace testing; | 41 | using namespace testing; |
| @@ -239,7 +243,7 @@ class UtestFusionStrategySolver : public testing::Test { | |||
| 239 | } | 243 | } |
| 240 | static std::shared_ptr<ge::AscGraph> CreatSplitDoubleOutPutsAscGraph(ge::AscGraph &graph, | 244 | static std::shared_ptr<ge::AscGraph> CreatSplitDoubleOutPutsAscGraph(ge::AscGraph &graph, |
| 241 | const std::vector<int64_t> &split_dims, | 245 | const std::vector<int64_t> &split_dims, |
| 242 | - size_t split_dim) { | 246 | + size_t split_dim, bool non_store_peer = false) { |
| 243 | auto ONE = Symbol(1); | 247 | auto ONE = Symbol(1); |
| 244 | const Expression A = graph.CreateSizeVar("A"); | 248 | const Expression A = graph.CreateSizeVar("A"); |
| 245 | const Expression B = graph.CreateSizeVar("B"); | 249 | const Expression B = graph.CreateSizeVar("B"); |
| @@ -288,6 +292,15 @@ class UtestFusionStrategySolver : public testing::Test { | |||
| 288 | *split.y[0].axis = {a.id, b.id, c.id, d.id, e.id}; | 292 | *split.y[0].axis = {a.id, b.id, c.id, d.id, e.id}; |
| 289 | *split.y[0].repeats = output_dim_sizes[0]; | 293 | *split.y[0].repeats = output_dim_sizes[0]; |
| 290 | *split.y[0].strides = {B * C * D * E, C * D * E, D * E, E, ONE}; | 294 | *split.y[0].strides = {B * C * D * E, C * D * E, D * E, E, ONE}; |
| 295 | + if (non_store_peer) { | ||
| 296 | + af::ascir_op::Add add((graph.GetName() + "_non_store_peer").c_str()); | ||
| 297 | + add.x1 = split.y[0]; | ||
| 298 | + add.x2 = split.y[0]; | ||
| 299 | + add.attr.sched.axis = {a.id, b.id, c.id, d.id, e.id}; | ||
| 300 | + *add.y.axis = {a.id, b.id, c.id, d.id, e.id}; | ||
| 301 | + *add.y.repeats = output_dim_sizes[0]; | ||
| 302 | + *add.y.strides = {B * C * D * E, C * D * E, D * E, E, ONE}; | ||
| 303 | + } | ||
| 291 | af::ascir_op::Store x_store((graph.GetName() + "_store0").c_str()); | 304 | af::ascir_op::Store x_store((graph.GetName() + "_store0").c_str()); |
| 292 | x_store.x = split.y[0]; | 305 | x_store.x = split.y[0]; |
| 293 | x_store.attr.sched.axis = {a.id, b.id, c.id, d.id, e.id}; | 306 | x_store.attr.sched.axis = {a.id, b.id, c.id, d.id, e.id}; |
| @@ -5907,4 +5920,208 @@ TEST_F(UtestFusionStrategySolver, Reduce_Can_Not_Fuse_With_Elementwise_Has_Scala | |||
| 5907 | EXPECT_EQ(pre_nodes_size - 1, post_nodes_size); | 5920 | EXPECT_EQ(pre_nodes_size - 1, post_nodes_size); |
| 5908 | } | 5921 | } |
| 5909 | 5922 | ||
| 5923 | +TEST_F(UtestFusionStrategySolver, LowerSplitHelperNeedLiftingCoversSplitCases) { | ||
| 5924 | + const auto create_split_backend = [&](const size_t split_dim, const size_t output_num, const std::string &name, | ||
| 5925 | + const bool use_non_split_origin, const bool same_shape = false, | ||
| 5926 | + const bool constant_tail = false, const bool non_store_peer = false) { | ||
| 5927 | + ge::AscGraph split_graph_builder(name.c_str()); | ||
| 5928 | + const auto split_graph = CreatSplitDoubleOutPutsAscGraph(split_graph_builder, {3, 3}, split_dim, non_store_peer); | ||
| 5929 | + EXPECT_NE(split_graph, nullptr); | ||
| 5930 | + if (split_graph == nullptr) { | ||
| 5931 | + return NodePtr(); | ||
| 5932 | + } | ||
| 5933 | + | ||
| 5934 | + auto op_desc = OP_CFG(kAscBackendType) | ||
| 5935 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {6, 1, 1, 1, 1}) | ||
| 5936 | + .InCnt(1) | ||
| 5937 | + .OutCnt(1) | ||
| 5938 | + .InNames({"x"}) | ||
| 5939 | + .OutNames({"y"}) | ||
| 5940 | + .Build(name); | ||
| 5941 | + if (output_num > 1U) { | ||
| 5942 | + EXPECT_EQ(op_desc->AddOutputDescForward("y", static_cast<uint32_t>(output_num - 1U)), GRAPH_SUCCESS); | ||
| 5943 | + if (op_desc->GetOutputsSize() != output_num) { | ||
| 5944 | + return NodePtr(); | ||
| 5945 | + } | ||
| 5946 | + } | ||
| 5947 | + auto graph = std::make_shared<ComputeGraph>(name); | ||
| 5948 | + auto backend_node = graph->AddNode(op_desc); | ||
| 5949 | + EXPECT_NE(backend_node, nullptr); | ||
| 5950 | + if (backend_node == nullptr) { | ||
| 5951 | + return NodePtr(); | ||
| 5952 | + } | ||
| 5953 | + | ||
| 5954 | + auto attr = GetOrCreateAutoFuseAttrs(op_desc); | ||
| 5955 | + EXPECT_NE(attr, nullptr); | ||
| 5956 | + if (attr == nullptr) { | ||
| 5957 | + return NodePtr(); | ||
| 5958 | + } | ||
| 5959 | + attr->SetAscGraph(split_graph, loop::FuseType::kSplit); | ||
| 5960 | + | ||
| 5961 | + AscNodePtr split_node; | ||
| 5962 | + AscNodePtr non_split_node; | ||
| 5963 | + for (const auto &node : split_graph->GetAllNodes()) { | ||
| 5964 | + if (AutofuseUtils::IsSplitType(node->GetType())) { | ||
| 5965 | + split_node = node; | ||
| 5966 | + } else if (non_split_node == nullptr) { | ||
| 5967 | + non_split_node = node; | ||
| 5968 | + } | ||
| 5969 | + } | ||
| 5970 | + EXPECT_NE(split_node, nullptr); | ||
| 5971 | + EXPECT_NE(non_split_node, nullptr); | ||
| 5972 | + if ((split_node == nullptr) || (non_split_node == nullptr)) { | ||
| 5973 | + return NodePtr(); | ||
| 5974 | + } | ||
| 5975 | + if (same_shape) { | ||
| 5976 | + split_node->outputs[0].attr.repeats = split_node->inputs[0].attr.repeats; | ||
| 5977 | + } | ||
| 5978 | + if (constant_tail) { | ||
| 5979 | + for (size_t i = split_dim + 1U; i < split_node->inputs[0].attr.repeats.size(); ++i) { | ||
| 5980 | + split_node->inputs[0].attr.repeats[i] = Symbol(2); | ||
| 5981 | + split_node->outputs[0].attr.repeats[i] = Symbol(2); | ||
| 5982 | + } | ||
| 5983 | + } | ||
| 5984 | + attr->SetOriginNodes({(use_non_split_origin ? non_split_node : split_node).get()}); | ||
| 5985 | + return backend_node; | ||
| 5986 | + }; | ||
| 5987 | + | ||
| 5988 | + auto first_dim_backend = create_split_backend(0U, 2U, "split_first_dim", false); | ||
| 5989 | + bool need_lifting = true; | ||
| 5990 | + LowerSplitHelper first_dim_helper(first_dim_backend); | ||
| 5991 | + EXPECT_EQ(first_dim_helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 5992 | + EXPECT_TRUE(need_lifting); | ||
| 5993 | + | ||
| 5994 | + auto other_dim_backend = create_split_backend(4U, 2U, "split_other_dim", false, false, false, true); | ||
| 5995 | + need_lifting = false; | ||
| 5996 | + LowerSplitHelper other_dim_helper(other_dim_backend); | ||
| 5997 | + EXPECT_EQ(other_dim_helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 5998 | + EXPECT_TRUE(need_lifting); | ||
| 5999 | + | ||
| 6000 | + auto same_shape_backend = create_split_backend(4U, 2U, "split_same_shape", false, true); | ||
| 6001 | + need_lifting = true; | ||
| 6002 | + LowerSplitHelper same_shape_helper(same_shape_backend); | ||
| 6003 | + EXPECT_EQ(same_shape_helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 6004 | + EXPECT_TRUE(need_lifting); | ||
| 6005 | + | ||
| 6006 | + auto constant_tail_backend = create_split_backend(0U, 2U, "split_constant_tail", false, false, true); | ||
| 6007 | + need_lifting = false; | ||
| 6008 | + LowerSplitHelper constant_tail_helper(constant_tail_backend); | ||
| 6009 | + EXPECT_EQ(constant_tail_helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 6010 | + EXPECT_TRUE(need_lifting); | ||
| 6011 | + | ||
| 6012 | + auto non_split_origin_backend = create_split_backend(4U, 2U, "split_non_split_origin", true); | ||
| 6013 | + need_lifting = true; | ||
| 6014 | + LowerSplitHelper non_split_origin_helper(non_split_origin_backend); | ||
| 6015 | + EXPECT_EQ(non_split_origin_helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 6016 | + EXPECT_FALSE(need_lifting); | ||
| 6017 | + | ||
| 6018 | + auto output_limit_backend = create_split_backend(4U, 64U, "split_output_limit", false); | ||
| 6019 | + need_lifting = false; | ||
| 6020 | + LowerSplitHelper output_limit_helper(output_limit_backend); | ||
| 6021 | + EXPECT_EQ(output_limit_helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 6022 | + EXPECT_TRUE(need_lifting); | ||
| 6023 | + | ||
| 6024 | + auto lifting_backend = create_split_backend(4U, 128U, "split_lifting", false); | ||
| 6025 | + need_lifting = false; | ||
| 6026 | + LowerSplitHelper lifting_helper(lifting_backend); | ||
| 6027 | + EXPECT_EQ(lifting_helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 6028 | + EXPECT_TRUE(need_lifting); | ||
| 6029 | +} | ||
| 6030 | + | ||
| 6031 | +TEST_F(UtestFusionStrategySolver, LowerSplitHelperRejectsGraphWithoutSplit) { | ||
| 6032 | + ge::AscGraph graph_builder("without_split"); | ||
| 6033 | + const auto asc_graph = CreatAddAscGraph(graph_builder); | ||
| 6034 | + ASSERT_NE(asc_graph, nullptr); | ||
| 6035 | + | ||
| 6036 | + auto op_desc = OP_CFG(kAscBackendType) | ||
| 6037 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {1, 1, 1, 1, 1}) | ||
| 6038 | + .InCnt(1) | ||
| 6039 | + .OutCnt(1) | ||
| 6040 | + .InNames({"x"}) | ||
| 6041 | + .OutNames({"y"}) | ||
| 6042 | + .Build("without_split_backend"); | ||
| 6043 | + auto graph = std::make_shared<ComputeGraph>("without_split_graph"); | ||
| 6044 | + auto backend_node = graph->AddNode(op_desc); | ||
| 6045 | + ASSERT_NE(backend_node, nullptr); | ||
| 6046 | + | ||
| 6047 | + auto attr = GetOrCreateAutoFuseAttrs(op_desc); | ||
| 6048 | + ASSERT_NE(attr, nullptr); | ||
| 6049 | + attr->SetAscGraph(asc_graph, loop::FuseType::kSplit); | ||
| 6050 | + AscNodePtr origin_node; | ||
| 6051 | + for (const auto &node : asc_graph->GetAllNodes()) { | ||
| 6052 | + origin_node = node; | ||
| 6053 | + break; | ||
| 6054 | + } | ||
| 6055 | + ASSERT_NE(origin_node, nullptr); | ||
| 6056 | + attr->SetOriginNodes({origin_node.get()}); | ||
| 6057 | + | ||
| 6058 | + bool need_lifting = false; | ||
| 6059 | + LowerSplitHelper helper(backend_node); | ||
| 6060 | + EXPECT_NE(helper.NeedLifting(need_lifting), GRAPH_SUCCESS); | ||
| 6061 | +} | ||
| 6062 | + | ||
| 6063 | +TEST_F(UtestFusionStrategySolver, ConcatStrategyCoversBackwardSplitLinkHelpers) { | ||
| 6064 | + ge::AscGraph split_graph_builder("strategy_split"); | ||
| 6065 | + const auto split_graph = CreatSplitDoubleOutPutsAscGraph(split_graph_builder, {3, 3}, 4U); | ||
| 6066 | + ASSERT_NE(split_graph, nullptr); | ||
| 6067 | + | ||
| 6068 | + ge::AscGraph concat_graph_builder("strategy_concat"); | ||
| 6069 | + const auto concat_graph = CreatConcatAscGraph(concat_graph_builder, {3, 3}, 0U); | ||
| 6070 | + ASSERT_NE(concat_graph, nullptr); | ||
| 6071 | + | ||
| 6072 | + auto graph = std::make_shared<ComputeGraph>("concat_strategy_graph"); | ||
| 6073 | + auto split_desc = OP_CFG(kAscBackendType) | ||
| 6074 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {6, 1, 1, 1, 1}) | ||
| 6075 | + .InCnt(1) | ||
| 6076 | + .OutCnt(2) | ||
| 6077 | + .InNames({"x"}) | ||
| 6078 | + .OutNames({"y"}) | ||
| 6079 | + .Build("strategy_split_backend"); | ||
| 6080 | + auto fused_desc = OP_CFG(kFusedAscBackendType) | ||
| 6081 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {6, 1, 1, 1, 1}) | ||
| 6082 | + .InCnt(1) | ||
| 6083 | + .OutCnt(1) | ||
| 6084 | + .InNames({"x"}) | ||
| 6085 | + .OutNames({"y"}) | ||
| 6086 | + .Build("strategy_fused_backend"); | ||
| 6087 | + auto split_backend = graph->AddNode(split_desc); | ||
| 6088 | + auto fused_backend = graph->AddNode(fused_desc); | ||
| 6089 | + ASSERT_NE(split_backend, nullptr); | ||
| 6090 | + ASSERT_NE(fused_backend, nullptr); | ||
| 6091 | + ASSERT_EQ(GraphUtils::AddEdge(split_backend->GetOutDataAnchor(0), fused_backend->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 6092 | + | ||
| 6093 | + auto split_attr = GetOrCreateAutoFuseAttrs(split_desc); | ||
| 6094 | + ASSERT_NE(split_attr, nullptr); | ||
| 6095 | + split_attr->SetAscGraph(split_graph, loop::FuseType::kSplit); | ||
| 6096 | + AscNodePtr split_origin; | ||
| 6097 | + for (const auto &node : split_graph->GetAllNodes()) { | ||
| 6098 | + if (AutofuseUtils::IsSplitType(node->GetType())) { | ||
| 6099 | + split_origin = node; | ||
| 6100 | + break; | ||
| 6101 | + } | ||
| 6102 | + } | ||
| 6103 | + ASSERT_NE(split_origin, nullptr); | ||
| 6104 | + split_attr->SetOriginNodes({split_origin.get()}); | ||
| 6105 | + | ||
| 6106 | + AscNodePtr concat_node; | ||
| 6107 | + for (const auto &node : concat_graph->GetAllNodes()) { | ||
| 6108 | + if (node->GetType() == kConcatType) { | ||
| 6109 | + concat_node = node; | ||
| 6110 | + break; | ||
| 6111 | + } | ||
| 6112 | + } | ||
| 6113 | + ASSERT_NE(concat_node, nullptr); | ||
| 6114 | + auto concat_attr = GetOrCreateAutoFuseAttrs(concat_node->GetOpDescBarePtr()); | ||
| 6115 | + ASSERT_NE(concat_attr, nullptr); | ||
| 6116 | + concat_attr->SetFuseType(loop::FuseType::kConcat); | ||
| 6117 | + | ||
| 6118 | + auto fused_attr = GetOrCreateAutoFuseAttrs(fused_desc); | ||
| 6119 | + ASSERT_NE(fused_attr, nullptr); | ||
| 6120 | + fused_attr->SetFuseType(loop::FuseType::kConcat); | ||
| 6121 | + fused_attr->SetFuseComputeGraph(af::AscGraphUtils::GetComputeGraph(*concat_graph)); | ||
| 6122 | + | ||
| 6123 | + ConcatFusionStrategy strategy; | ||
| 6124 | + EXPECT_TRUE(strategy.CanFuse(split_backend, fused_backend)); | ||
| 6125 | +} | ||
| 6126 | + | ||
| 5910 | } // namespace ge | 6127 | } // namespace ge |
| @@ -28,7 +28,9 @@ | |||
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | + | ||
| 31 | 32 | ||
| 33 | + | ||
| 32 | 34 | ||
| 33 | 35 | ||
| 34 | 36 | ||
| @@ -303,4 +305,187 @@ TEST_F(UtestFusionStrategySolverReshape, Fuse_Reshape_And_Pointwise) { | |||
| 303 | EXPECT_EQ(pre_nodes_size - 1, post_nodes_size); | 305 | EXPECT_EQ(pre_nodes_size - 1, post_nodes_size); |
| 304 | } | 306 | } |
| 305 | 307 | ||
| 308 | +TEST_F(UtestFusionStrategySolverReshape, SplitStrategyCoversFusionChecks) { | ||
| 309 | + auto graph = std::make_shared<ComputeGraph>("split_strategy_checks"); | ||
| 310 | + auto make_node = [&](const std::string &name) { | ||
| 311 | + auto op_desc = OP_CFG(kAscBackendType) | ||
| 312 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 1, 3, 4}) | ||
| 313 | + .InCnt(1) | ||
| 314 | + .OutCnt(1) | ||
| 315 | + .InNames({"x"}) | ||
| 316 | + .OutNames({"y"}) | ||
| 317 | + .Build(name); | ||
| 318 | + return graph->AddNode(op_desc); | ||
| 319 | + }; | ||
| 320 | + | ||
| 321 | + auto split1 = make_node("split1"); | ||
| 322 | + auto split2 = make_node("split2"); | ||
| 323 | + auto normal = make_node("normal"); | ||
| 324 | + ASSERT_NE(split1, nullptr); | ||
| 325 | + ASSERT_NE(split2, nullptr); | ||
| 326 | + ASSERT_NE(normal, nullptr); | ||
| 327 | + | ||
| 328 | + auto split_attr1 = GetOrCreateAutoFuseAttrs(split1->GetOpDescBarePtr()); | ||
| 329 | + auto split_attr2 = GetOrCreateAutoFuseAttrs(split2->GetOpDescBarePtr()); | ||
| 330 | + auto normal_attr = GetOrCreateAutoFuseAttrs(normal->GetOpDescBarePtr()); | ||
| 331 | + ASSERT_NE(split_attr1, nullptr); | ||
| 332 | + ASSERT_NE(split_attr2, nullptr); | ||
| 333 | + ASSERT_NE(normal_attr, nullptr); | ||
| 334 | + split_attr1->SetFuseType(loop::FuseType::kSplit); | ||
| 335 | + split_attr2->SetFuseType(loop::FuseType::kSplit); | ||
| 336 | + normal_attr->SetFuseType(loop::FuseType::kPointwise); | ||
| 337 | + split_attr1->SetSplitGlobalId(1U); | ||
| 338 | + split_attr2->SetSplitGlobalId(2U); | ||
| 339 | + split_attr1->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::SATISFIED); | ||
| 340 | + | ||
| 341 | + SplitFusionStrategy strategy; | ||
| 342 | + EXPECT_FALSE(strategy.CanFuse(split1, split2)); | ||
| 343 | + split_attr2->SetSplitGlobalId(1U); | ||
| 344 | + EXPECT_TRUE(strategy.CanFuse(split1, split2)); | ||
| 345 | + EXPECT_EQ(strategy.GetFusionPairPriority(split1, split2), FusionPriority::HIGHEST); | ||
| 346 | + split_attr2->SetFuseType(loop::FuseType::kPointwise); | ||
| 347 | + EXPECT_EQ(strategy.GetFusionPairPriority(split1, split2), FusionPriority::HIGHER); | ||
| 348 | + | ||
| 349 | + split_attr1->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::NOT_SATISFIED); | ||
| 350 | + EXPECT_FALSE(strategy.CanFuse(split1, normal)); | ||
| 351 | + split_attr1->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::SATISFIED); | ||
| 352 | + | ||
| 353 | + split_attr2->SetFuseType(loop::FuseType::kReduction); | ||
| 354 | + EXPECT_FALSE(strategy.CanFuse(split1, split2)); | ||
| 355 | + split_attr2->SetFuseType(loop::FuseType::kSplit); | ||
| 356 | + split_attr2->SetSplitGlobalId(1U); | ||
| 357 | + ASSERT_EQ(GraphUtils::AddEdge(split1->GetOutDataAnchor(0), normal->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 358 | + EXPECT_EQ(strategy.GetMaxFusionNodesSize(split1, normal), std::numeric_limits<uint64_t>::max()); | ||
| 359 | + | ||
| 360 | + auto data_desc = OP_CFG(kDataType) | ||
| 361 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 1, 3, 4}) | ||
| 362 | + .InCnt(0) | ||
| 363 | + .OutCnt(1) | ||
| 364 | + .InNames({}) | ||
| 365 | + .OutNames({"y"}) | ||
| 366 | + .Build("split_source"); | ||
| 367 | + auto split_source = graph->AddNode(data_desc); | ||
| 368 | + ASSERT_NE(split_source, nullptr); | ||
| 369 | + ASSERT_EQ(GraphUtils::AddEdge(split_source->GetOutDataAnchor(0), split1->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 370 | + ASSERT_EQ(GraphUtils::AddEdge(split_source->GetOutDataAnchor(0), split2->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 371 | + EXPECT_EQ(strategy.GetMaxFusionNodesSize(split1, split2), std::numeric_limits<uint64_t>::max()); | ||
| 372 | + | ||
| 373 | + auto forward_split = make_node("forward_split"); | ||
| 374 | + auto forward_source = make_node("forward_source"); | ||
| 375 | + ASSERT_NE(forward_split, nullptr); | ||
| 376 | + ASSERT_NE(forward_source, nullptr); | ||
| 377 | + auto forward_split_attr = GetOrCreateAutoFuseAttrs(forward_split->GetOpDescBarePtr()); | ||
| 378 | + auto forward_source_attr = GetOrCreateAutoFuseAttrs(forward_source->GetOpDescBarePtr()); | ||
| 379 | + ASSERT_NE(forward_split_attr, nullptr); | ||
| 380 | + ASSERT_NE(forward_source_attr, nullptr); | ||
| 381 | + forward_split_attr->SetFuseType(loop::FuseType::kSplit); | ||
| 382 | + forward_source_attr->SetFuseType(loop::FuseType::kPointwise); | ||
| 383 | + forward_split_attr->SetSplitGlobalId(3U); | ||
| 384 | + ASSERT_EQ(GraphUtils::AddEdge(forward_source->GetOutDataAnchor(0), forward_split->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 385 | + EXPECT_FALSE(strategy.CanFuse(forward_source, forward_split)); | ||
| 386 | + | ||
| 387 | + auto horizontal_source = make_node("horizontal_source"); | ||
| 388 | + auto horizontal_target = make_node("horizontal_target"); | ||
| 389 | + ASSERT_NE(horizontal_source, nullptr); | ||
| 390 | + ASSERT_NE(horizontal_target, nullptr); | ||
| 391 | + auto horizontal_source_attr = GetOrCreateAutoFuseAttrs(horizontal_source->GetOpDescBarePtr()); | ||
| 392 | + auto horizontal_target_attr = GetOrCreateAutoFuseAttrs(horizontal_target->GetOpDescBarePtr()); | ||
| 393 | + ASSERT_NE(horizontal_source_attr, nullptr); | ||
| 394 | + ASSERT_NE(horizontal_target_attr, nullptr); | ||
| 395 | + horizontal_source_attr->SetFuseType(loop::FuseType::kPointwise); | ||
| 396 | + horizontal_target_attr->SetFuseType(loop::FuseType::kPointwise); | ||
| 397 | + EXPECT_FALSE(strategy.CanFuse(horizontal_source, horizontal_target)); | ||
| 398 | +} | ||
| 399 | + | ||
| 400 | +TEST_F(UtestFusionStrategySolverReshape, SplitStrategyCoversReshapeSqueezeChecks) { | ||
| 401 | + auto set_output_shape = [](const NodePtr &node, const std::vector<int64_t> &dims) { | ||
| 402 | + gert::SymbolShape shape; | ||
| 403 | + for (const auto dim : dims) { | ||
| 404 | + shape.AppendDim(Symbol(dim)); | ||
| 405 | + } | ||
| 406 | + auto output_desc = node->GetOpDescBarePtr()->MutableOutputDesc(0); | ||
| 407 | + EXPECT_NE(output_desc, nullptr); | ||
| 408 | + if (output_desc != nullptr) { | ||
| 409 | + output_desc->GetOrCreateAttrsGroup<SymbolicDescAttr>()->symbolic_tensor.MutableOriginSymbolShape() = shape; | ||
| 410 | + } | ||
| 411 | + }; | ||
| 412 | + | ||
| 413 | + auto run_case = [&](const std::vector<int64_t> &split_shape, const std::vector<int64_t> &reshape_shape, | ||
| 414 | + const int next_mode) { | ||
| 415 | + auto graph = std::make_shared<ComputeGraph>("split_reshape_case"); | ||
| 416 | + auto split_desc = OP_CFG(kAscBackendType) | ||
| 417 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 1, 3, 4}) | ||
| 418 | + .InCnt(1) | ||
| 419 | + .OutCnt(1) | ||
| 420 | + .InNames({"x"}) | ||
| 421 | + .OutNames({"y"}) | ||
| 422 | + .Build("split"); | ||
| 423 | + auto reshape_desc = OP_CFG(kAscBackendType) | ||
| 424 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 3, 4}) | ||
| 425 | + .InCnt(1) | ||
| 426 | + .OutCnt(1) | ||
| 427 | + .InNames({"x"}) | ||
| 428 | + .OutNames({"y"}) | ||
| 429 | + .Build("reshape"); | ||
| 430 | + auto split = graph->AddNode(split_desc); | ||
| 431 | + auto reshape = graph->AddNode(reshape_desc); | ||
| 432 | + EXPECT_NE(split, nullptr); | ||
| 433 | + EXPECT_NE(reshape, nullptr); | ||
| 434 | + if ((split == nullptr) || (reshape == nullptr)) { | ||
| 435 | + return false; | ||
| 436 | + } | ||
| 437 | + EXPECT_EQ(GraphUtils::AddEdge(split->GetOutDataAnchor(0), reshape->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 438 | + | ||
| 439 | + auto split_attr = GetOrCreateAutoFuseAttrs(split_desc); | ||
| 440 | + auto reshape_attr = GetOrCreateAutoFuseAttrs(reshape_desc); | ||
| 441 | + EXPECT_NE(split_attr, nullptr); | ||
| 442 | + EXPECT_NE(reshape_attr, nullptr); | ||
| 443 | + if ((split_attr == nullptr) || (reshape_attr == nullptr)) { | ||
| 444 | + return false; | ||
| 445 | + } | ||
| 446 | + split_attr->SetFuseType(loop::FuseType::kSplit); | ||
| 447 | + split_attr->SetSplitGlobalId(7U); | ||
| 448 | + split_attr->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::SATISFIED); | ||
| 449 | + ge::AscGraph reshape_graph_builder("reshape_case"); | ||
| 450 | + reshape_attr->SetAscGraph(CreateReshapeAscGraph(reshape_graph_builder), loop::FuseType::kReshape); | ||
| 451 | + set_output_shape(split, split_shape); | ||
| 452 | + set_output_shape(reshape, reshape_shape); | ||
| 453 | + | ||
| 454 | + if (next_mode != 0) { | ||
| 455 | + auto next_desc = OP_CFG(kAscBackendType) | ||
| 456 | + .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 3, 4}) | ||
| 457 | + .InCnt(1) | ||
| 458 | + .OutCnt(1) | ||
| 459 | + .InNames({"x"}) | ||
| 460 | + .OutNames({"y"}) | ||
| 461 | + .Build("next"); | ||
| 462 | + auto next = graph->AddNode(next_desc); | ||
| 463 | + EXPECT_NE(next, nullptr); | ||
| 464 | + if (next == nullptr) { | ||
| 465 | + return false; | ||
| 466 | + } | ||
| 467 | + if (next_mode != 2) { | ||
| 468 | + auto next_attr = GetOrCreateAutoFuseAttrs(next_desc); | ||
| 469 | + EXPECT_NE(next_attr, nullptr); | ||
| 470 | + if (next_attr == nullptr) { | ||
| 471 | + return false; | ||
| 472 | + } | ||
| 473 | + next_attr->SetFuseType(next_mode == 3 ? loop::FuseType::kReduction : loop::FuseType::kPointwise); | ||
| 474 | + } | ||
| 475 | + EXPECT_EQ(GraphUtils::AddEdge(reshape->GetOutDataAnchor(0), next->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 476 | + } | ||
| 477 | + SplitFusionStrategy strategy; | ||
| 478 | + return strategy.CanFuse(split, reshape); | ||
| 479 | + }; | ||
| 480 | + | ||
| 481 | + EXPECT_FALSE(run_case({2, 1, 3, 4}, {2, 3, 4}, 0)); | ||
| 482 | + EXPECT_TRUE(run_case({2, 1, 3, 4}, {2, 3, 4}, 1)); | ||
| 483 | + EXPECT_TRUE(run_case({2, 1, 3, 4}, {2, 3, 4, 5, 6}, 0)); | ||
| 484 | + EXPECT_TRUE(run_case({2, 1, 3, 4}, {2, 4}, 0)); | ||
| 485 | + EXPECT_TRUE(run_case({2, 1, 3}, {2, 1}, 0)); | ||
| 486 | + EXPECT_FALSE(run_case({2, 1, 1}, {2}, 0)); | ||
| 487 | + EXPECT_FALSE(run_case({2, 1, 3, 4}, {2, 3, 4}, 2)); | ||
| 488 | + EXPECT_FALSE(run_case({2, 1, 3, 4}, {2, 3, 4}, 3)); | ||
| 489 | +} | ||
| 490 | + | ||
| 306 | } // namespace ge | 491 | } // namespace ge |