已合并
DepthwiseDX算子融合pass相关代码开源到ops-nn仓 #8172
cheng_gao创建于 8月3日
DepthwiseDX算子融合pass相关代码开源到ops-nn仓 #8172
已合并
共 7 个文件变更+1065-36
| @@ -20,7 +20,10 @@ void ConvBackpropFusionBasePass::InitMember() | |||
| 20 | npuArch = NpuArch::DAV_RESV; | 20 | npuArch = NpuArch::DAV_RESV; |
| 21 | input0Desc = TensorDesc(); | 21 | input0Desc = TensorDesc(); |
| 22 | input1Desc = TensorDesc(); | 22 | input1Desc = TensorDesc(); |
| 23 | - input2Desc = TensorDesc(); | 23 | + if (isDynamic) { |
| 24 | + input2Desc = TensorDesc(); | ||
| 25 | + } | ||
| 26 | + | ||
| 24 | outputDesc = TensorDesc(); | 27 | outputDesc = TensorDesc(); |
| 25 | convBpAttr.Reset(); | 28 | convBpAttr.Reset(); |
| 26 | } | 29 | } |
| @@ -43,15 +46,19 @@ bool ConvBackpropFusionBasePass::MeetRequirements(const GNode& convBpInputNode) | |||
| 43 | bool ConvBackpropFusionBasePass::GetNodeDesc(const GNode& node) | 46 | bool ConvBackpropFusionBasePass::GetNodeDesc(const GNode& node) |
| 44 | { | 47 | { |
| 45 | InitMember(); | 48 | InitMember(); |
| 46 | - // 获取输入索引 | ||
| 47 | int32_t inputIdx0 = 0; | 49 | int32_t inputIdx0 = 0; |
| 48 | int32_t inputIdx1 = 1; | 50 | int32_t inputIdx1 = 1; |
| 49 | - int32_t outBackpropIdx = 2; | ||
| 50 | OP_CHECK_IF(node.GetInputDesc(inputIdx0, input0Desc) != GRAPH_SUCCESS || | 51 | OP_CHECK_IF(node.GetInputDesc(inputIdx0, input0Desc) != GRAPH_SUCCESS || |
| 51 | node.GetInputDesc(inputIdx1, input1Desc) != GRAPH_SUCCESS || | 52 | node.GetInputDesc(inputIdx1, input1Desc) != GRAPH_SUCCESS || |
| 52 | - node.GetInputDesc(outBackpropIdx, input2Desc) != GRAPH_SUCCESS || | ||
| 53 | node.GetOutputDesc(OUTPUT_INDEX, outputDesc) != GRAPH_SUCCESS, | 53 | node.GetOutputDesc(OUTPUT_INDEX, outputDesc) != GRAPH_SUCCESS, |
| 54 | OP_LOGE(GetNodeType().GetString(), "Get input/output desc failed"), return false); | 54 | OP_LOGE(GetNodeType().GetString(), "Get input/output desc failed"), return false); |
| 55 | + | ||
| 56 | + // 动态算子多了input_size或filter_size字段,需要获取第3个输入 | ||
H | |||
| 57 | + if (isDynamic) { | ||
| 58 | + int32_t inputIdx2 = 2; | ||
| 59 | + OP_CHECK_IF(node.GetInputDesc(inputIdx2, input2Desc) != GRAPH_SUCCESS, | ||
| 60 | + OP_LOGE(GetNodeType().GetString(), "Get input2 desc failed"), return false); | ||
| 61 | + } | ||
| 55 | return true; | 62 | return true; |
| 56 | } | 63 | } |
| 57 | 64 | ||
| @@ -80,8 +87,14 @@ bool ConvBackpropFusionBasePass::GetNodeAttrs(const GNode& node) | |||
| 80 | 87 | ||
| 81 | convBpAttr.dataFormat = std::string(format.GetString()); | 88 | convBpAttr.dataFormat = std::string(format.GetString()); |
| 82 | 89 | ||
| 83 | - convBpAttr.hf32 = input2Desc.GetDataType() == DataType::DT_FLOAT && | 90 | + // 判断out_backprop的dtype,动态算子时为第3个输入,静态算子时为第2个输入 |
| 84 | - convBpAttr.opImplModeEnum == HF32_PRECISION_MODE_INT; | 91 | + if (isDynamic) { |
| 92 | + convBpAttr.hf32 = input2Desc.GetDataType() == DataType::DT_FLOAT && | ||
| 93 | + convBpAttr.opImplModeEnum == HF32_PRECISION_MODE_INT; | ||
| 94 | + } else { | ||
| 95 | + convBpAttr.hf32 = input1Desc.GetDataType() == DataType::DT_FLOAT && | ||
| 96 | + convBpAttr.opImplModeEnum == HF32_PRECISION_MODE_INT; | ||
| 97 | + } | ||
| 85 | 98 | ||
| 86 | convBpAttr.opImplModeEnum = convBpAttr.hf32 ? convBpAttr.opImplModeEnum : 0x1; | 99 | convBpAttr.opImplModeEnum = convBpAttr.hf32 ? convBpAttr.opImplModeEnum : 0x1; |
| 87 | 100 | ||
| @@ -30,6 +30,7 @@ struct ConvBackpropAttrs { | |||
| 30 | std::vector<int64_t> strides; | 30 | std::vector<int64_t> strides; |
| 31 | std::vector<int64_t> pads; | 31 | std::vector<int64_t> pads; |
| 32 | std::vector<int64_t> dilations; | 32 | std::vector<int64_t> dilations; |
| 33 | + std::vector<int64_t> input_size; | ||
| 33 | int64_t groups = 0; | 34 | int64_t groups = 0; |
| 34 | std::string dataFormat; | 35 | std::string dataFormat; |
| 35 | int64_t opImplModeEnum = 0; | 36 | int64_t opImplModeEnum = 0; |
| @@ -41,6 +42,7 @@ struct ConvBackpropAttrs { | |||
| 41 | strides.clear(); | 42 | strides.clear(); |
| 42 | pads.clear(); | 43 | pads.clear(); |
| 43 | dilations.clear(); | 44 | dilations.clear(); |
| 45 | + input_size.clear(); | ||
| 44 | groups = 0; | 46 | groups = 0; |
| 45 | dataFormat = ""; | 47 | dataFormat = ""; |
| 46 | opImplModeEnum = 0; | 48 | opImplModeEnum = 0; |
| @@ -70,7 +72,7 @@ protected: | |||
| 70 | 72 | ||
| 71 | virtual bool UpdateNodeInputDescInfo(ge::GNode* node); | 73 | virtual bool UpdateNodeInputDescInfo(ge::GNode* node); |
| 72 | 74 | ||
| 73 | - void SetNodeAttrs(ge::GNode& outNode); | 75 | + virtual void SetNodeAttrs(ge::GNode& outNode); |
| 74 | 76 | ||
| 75 | virtual ge::AscendString GetNodeType() const = 0; | 77 | virtual ge::AscendString GetNodeType() const = 0; |
| 76 | 78 | ||
| @@ -87,6 +89,11 @@ protected: | |||
| 87 | ge::TensorDesc outputDesc; | 89 | ge::TensorDesc outputDesc; |
| 88 | 90 | ||
| 89 | ConvBackpropAttrs convBpAttr; | 91 | ConvBackpropAttrs convBpAttr; |
| 92 | + | ||
| 93 | + // 是否是动态算子调用,带D算子为false,950中动静归一全部为true | ||
| 94 | + bool isDynamic = true; | ||
| 95 | + | ||
| 96 | + bool isArch35 = true; | ||
| 90 | }; | 97 | }; |
| 91 | 98 | ||
| 92 | } // namespace ops | 99 | } // namespace ops |
| @@ -60,6 +60,17 @@ bool ConvBackpropFusionUtilsPass::CheckSocAndIntrinsic(const std::map<std::strin | |||
| 60 | return true; | 60 | return true; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | +bool ConvBackpropFusionUtilsPass::IsArch35() | ||
| 64 | +{ | ||
| 65 | + fe::PlatformInfo platformInfo; | ||
| 66 | + fe::OptionalInfo optionalInfo; | ||
| 67 | + if (fe::PlatformInfoManager::Instance().GetPlatformInfoWithOutSocVersion(platformInfo, optionalInfo) != SUCCESS) { | ||
| 68 | + return false; | ||
| 69 | + } | ||
| 70 | + const std::string soc = platformInfo.str_info.short_soc_version; | ||
| 71 | + return SUPPORT_SOC_LIST.find(soc) != SUPPORT_SOC_LIST.end() && SUPPORT_SOC_LIST.at(soc) == NpuArch::DAV_3510; | ||
| 72 | +} | ||
| 73 | + | ||
| 63 | bool ConvBackpropFusionUtilsPass::GetNodeName(const GNode& node, std::string& nodeName) | 74 | bool ConvBackpropFusionUtilsPass::GetNodeName(const GNode& node, std::string& nodeName) |
| 64 | { | 75 | { |
| 65 | AscendString rawNodeName; | 76 | AscendString rawNodeName; |
| @@ -82,53 +93,96 @@ int64_t ConvBackpropFusionUtilsPass::GetAiCoreCount() | |||
| 82 | return platformInfo.soc_info.ai_core_cnt; | 93 | return platformInfo.soc_info.ai_core_cnt; |
| 83 | } | 94 | } |
| 84 | 95 | ||
| 85 | -bool ConvBackpropFusionUtilsPass::CreateTransposeNode(EsGraphBuilder& builder, const TransposeNodeConfig& config, | 96 | +bool ConvBackpropFusionUtilsPass::CreateTransposeNodeImpl(EsGraphBuilder& builder, const TransposeNodeConfig& config, |
| 86 | - EsTensorHolder& output, TensorDesc& outDesc, | 97 | + EsTensorHolder& output, TensorDesc& outDesc, |
| 87 | - const AscendString& opType) | 98 | + const TensorDesc* inDescOverride, bool isTransposeD, |
| 99 | + const AscendString& opType) | ||
| 88 | { | 100 | { |
| 89 | auto* graph = builder.GetCGraphBuilder()->GetGraph(); | 101 | auto* graph = builder.GetCGraphBuilder()->GetGraph(); |
| 90 | - OP_CHECK_IF(graph == nullptr, OP_LOGE(opType.GetString(), "create transpose node failed"), return false); | 102 | + OP_CHECK_IF(graph == nullptr, OP_LOGE(opType.GetString(), "get graph failed"), return false); |
| 91 | 103 | ||
| 92 | auto* producer = config.input.GetProducer(); | 104 | auto* producer = config.input.GetProducer(); |
| 93 | - OP_CHECK_IF(producer == nullptr, OP_LOGE(opType.GetString(), "input producer is nullptr in CreateTransposeNode"), | 105 | + OP_CHECK_IF(producer == nullptr, OP_LOGE(opType.GetString(), "input producer is nullptr"), return false); |
| 94 | - return false); | ||
| 95 | 106 | ||
| 96 | TensorDesc inDesc; | 107 | TensorDesc inDesc; |
| 97 | - producer->GetOutputDesc(config.input.GetProducerOutIndex(), inDesc); | 108 | + if (inDescOverride != nullptr) { |
| 98 | - auto transposeNode = ge::es::CompliantNodeBuilder(graph) | 109 | + inDesc = *inDescOverride; |
| 99 | - .OpType("Transpose") | 110 | + } else { |
| 100 | - .Name(config.name.c_str()) | 111 | + OP_CHECK_IF(producer->GetOutputDesc(config.input.GetProducerOutIndex(), inDesc) != GRAPH_SUCCESS, |
| 101 | - .IrDefInputs({{"x", ge::es::CompliantNodeBuilder::kEsIrInputRequired, ""}, | 112 | + OP_LOGE(opType.GetString(), "Get output desc failed"), return false); |
| 102 | - {"perm", ge::es::CompliantNodeBuilder::kEsIrInputRequired, ""}}) | 113 | + } |
| 103 | - .IrDefOutputs({{"y", ge::es::CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | 114 | + |
| 104 | - .Build(); | 115 | + GNode transposeNode; |
| 105 | - OP_CHECK_IF(ge::es::AddEdgeAndUpdatePeerDesc(*graph, *producer, TENSOR_DEFAULT_OUTPUT_INDEX, transposeNode, | 116 | + if (isTransposeD) { |
| 106 | - TRANSPOSE_INPUT_X_INDEX) != GRAPH_SUCCESS, | 117 | + transposeNode = ge::es::CompliantNodeBuilder(graph) |
| 107 | - OP_LOGE(opType.GetString(), "Add edge for transpose input failed"), return false); | 118 | + .OpType("TransposeD") |
| 108 | - transposeNode.UpdateInputDesc(TRANSPOSE_INPUT_X_INDEX, inDesc); | 119 | + .Name(config.name.c_str()) |
| 109 | - auto permTensorHolder = builder.CreateVector(config.perm); | 120 | + .IrDefInputs({{"x", ge::es::CompliantNodeBuilder::kEsIrInputRequired, ""}}) |
| 110 | - auto* permTensorProducer = permTensorHolder.GetProducer(); | 121 | + .IrDefOutputs({{"y", ge::es::CompliantNodeBuilder::kEsIrOutputRequired, ""}}) |
| 111 | - OP_CHECK_IF(permTensorProducer == nullptr, OP_LOGE(opType.GetString(), "perm producer is nullptr"), return false); | 122 | + .Build(); |
| 112 | - OP_CHECK_IF(ge::es::AddEdgeAndUpdatePeerDesc(*graph, *permTensorProducer, TENSOR_DEFAULT_OUTPUT_INDEX, | 123 | + } else { |
| 113 | - transposeNode, TRANSPOSE_INPUT_PERM_INDEX) != GRAPH_SUCCESS, | 124 | + transposeNode = ge::es::CompliantNodeBuilder(graph) |
| 114 | - OP_LOGE(opType.GetString(), "Add edge for transpose perm failed"), return false); | 125 | + .OpType("Transpose") |
| 126 | + .Name(config.name.c_str()) | ||
| 127 | + .IrDefInputs({{"x", ge::es::CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 128 | + {"perm", ge::es::CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 129 | + .IrDefOutputs({{"y", ge::es::CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 130 | + .Build(); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + OP_CHECK_IF(ge::es::AddEdgeAndUpdatePeerDesc(*graph, *producer, config.input.GetProducerOutIndex(), transposeNode, | ||
| 134 | + TRANSPOSE_INPUT_X_INDEX) != GRAPH_SUCCESS, | ||
| 135 | + OP_LOGE(opType.GetString(), "Add edge for transpose x input failed"), return false); | ||
| 136 | + OP_CHECK_IF(transposeNode.UpdateInputDesc(TRANSPOSE_INPUT_X_INDEX, inDesc) != GRAPH_SUCCESS, | ||
| 137 | + OP_LOGE(opType.GetString(), "Update transpose input desc failed"), return false); | ||
| 138 | + | ||
| 139 | + if (isTransposeD) { | ||
| 140 | + std::vector<int32_t> perm(config.perm.begin(), config.perm.end()); | ||
| 141 | + OP_CHECK_IF(transposeNode.SetAttr("perm", perm) != GRAPH_SUCCESS, | ||
| 142 | + OP_LOGE(opType.GetString(), "Set perm attr failed"), return false); | ||
| 143 | + } else { | ||
| 144 | + auto permTensorHolder = builder.CreateVector(config.perm); | ||
| 145 | + auto* permTensorProducer = permTensorHolder.GetProducer(); | ||
| 146 | + OP_CHECK_IF(permTensorProducer == nullptr, OP_LOGE(opType.GetString(), "perm producer is nullptr"), | ||
| 147 | + return false); | ||
| 148 | + OP_CHECK_IF(ge::es::AddEdgeAndUpdatePeerDesc(*graph, *permTensorProducer, TENSOR_DEFAULT_OUTPUT_INDEX, | ||
| 149 | + transposeNode, TRANSPOSE_INPUT_PERM_INDEX) != GRAPH_SUCCESS, | ||
| 150 | + OP_LOGE(opType.GetString(), "Add edge for transpose perm failed"), return false); | ||
| 151 | + TensorDesc permTensorDesc; | ||
| 152 | + OP_CHECK_IF(permTensorProducer->GetOutputDesc(TENSOR_DEFAULT_OUTPUT_INDEX, permTensorDesc) != GRAPH_SUCCESS, | ||
| 153 | + OP_LOGE(opType.GetString(), "Get perm tensor desc failed"), return false); | ||
| 154 | + OP_CHECK_IF(transposeNode.UpdateInputDesc(TRANSPOSE_INPUT_PERM_INDEX, permTensorDesc) != GRAPH_SUCCESS, | ||
| 155 | + OP_LOGE(opType.GetString(), "Update perm input desc failed"), return false); | ||
| 156 | + } | ||
| 115 | 157 | ||
| 116 | - TensorDesc permTensorDesc; | ||
| 117 | - permTensorProducer->GetOutputDesc(TENSOR_DEFAULT_OUTPUT_INDEX, permTensorDesc); | ||
| 118 | - transposeNode.UpdateInputDesc(TRANSPOSE_INPUT_PERM_INDEX, permTensorDesc); | ||
| 119 | outDesc.SetDataType(inDesc.GetDataType()); | 158 | outDesc.SetDataType(inDesc.GetDataType()); |
| 120 | auto outShape = CalcTransposeShape(inDesc.GetShape().GetDims(), config.perm); | 159 | auto outShape = CalcTransposeShape(inDesc.GetShape().GetDims(), config.perm); |
| 121 | outDesc.SetShape(Shape(outShape)); | 160 | outDesc.SetShape(Shape(outShape)); |
| 122 | outDesc.SetOriginShape(Shape(outShape)); | 161 | outDesc.SetOriginShape(Shape(outShape)); |
| 123 | outDesc.SetFormat(config.format); | 162 | outDesc.SetFormat(config.format); |
| 124 | outDesc.SetOriginFormat(config.format); | 163 | outDesc.SetOriginFormat(config.format); |
| 125 | - transposeNode.UpdateOutputDesc(TRANSPOSE_OUTPUT_Y_INDEX, outDesc); | 164 | + OP_CHECK_IF(transposeNode.UpdateOutputDesc(TRANSPOSE_OUTPUT_Y_INDEX, outDesc) != GRAPH_SUCCESS, |
| 165 | + OP_LOGE(opType.GetString(), "Update transpose output desc failed"), return false); | ||
| 166 | + | ||
| 126 | output = EsTensorHolder( | 167 | output = EsTensorHolder( |
| 127 | builder.GetCGraphBuilder()->GetTensorHolderFromNode(transposeNode, TRANSPOSE_OUTPUT_Y_INDEX)); | 168 | builder.GetCGraphBuilder()->GetTensorHolderFromNode(transposeNode, TRANSPOSE_OUTPUT_Y_INDEX)); |
| 128 | - | ||
| 129 | return true; | 169 | return true; |
| 130 | } | 170 | } |
| 131 | 171 | ||
| 172 | +bool ConvBackpropFusionUtilsPass::CreateTransposeNode(EsGraphBuilder& builder, const TransposeNodeConfig& config, | ||
| 173 | + EsTensorHolder& output, TensorDesc& outDesc, | ||
| 174 | + const AscendString& opType) | ||
| 175 | +{ | ||
| 176 | + return CreateTransposeNodeImpl(builder, config, output, outDesc, nullptr, false, opType); | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | +bool ConvBackpropFusionUtilsPass::CreateTransposeDNode(EsGraphBuilder& builder, const TransposeNodeConfig& config, | ||
| 180 | + EsTensorHolder& output, TensorDesc& outDesc, | ||
| 181 | + const TensorDesc& inputDesc, const AscendString& opType) | ||
| 182 | +{ | ||
| 183 | + return CreateTransposeNodeImpl(builder, config, output, outDesc, &inputDesc, true, opType); | ||
| 184 | +} | ||
| 185 | + | ||
| 132 | int32_t ConvBackpropFusionUtilsPass::GetExpandAxis(ge::Format format2D) | 186 | int32_t ConvBackpropFusionUtilsPass::GetExpandAxis(ge::Format format2D) |
| 133 | { | 187 | { |
| 134 | if (format2D == ge::FORMAT_NCHW) { | 188 | if (format2D == ge::FORMAT_NCHW) { |
| @@ -121,6 +121,8 @@ public: | |||
| 121 | 121 | ||
| 122 | static bool CheckSocAndIntrinsic(const std::map<std::string, NpuArch>& supportSocList, NpuArch& npuArch); | 122 | static bool CheckSocAndIntrinsic(const std::map<std::string, NpuArch>& supportSocList, NpuArch& npuArch); |
| 123 | 123 | ||
| 124 | + static bool IsArch35(); | ||
| 125 | + | ||
| 124 | static bool GetNodeName(const ge::GNode& node, std::string& nodeName); | 126 | static bool GetNodeName(const ge::GNode& node, std::string& nodeName); |
| 125 | 127 | ||
| 126 | static int64_t GetAiCoreCount(); | 128 | static int64_t GetAiCoreCount(); |
| @@ -131,6 +133,10 @@ public: | |||
| 131 | ge::es::EsTensorHolder& output, ge::TensorDesc& outDesc, | 133 | ge::es::EsTensorHolder& output, ge::TensorDesc& outDesc, |
| 132 | const ge::AscendString& opType); | 134 | const ge::AscendString& opType); |
| 133 | 135 | ||
| 136 | + static bool CreateTransposeDNode(ge::es::EsGraphBuilder& builder, const TransposeNodeConfig& config, | ||
| 137 | + ge::es::EsTensorHolder& output, ge::TensorDesc& outDesc, | ||
| 138 | + const ge::TensorDesc& inputDesc, const ge::AscendString& opType); | ||
| 139 | + | ||
| 134 | static int32_t GetExpandAxis(ge::Format format2D); | 140 | static int32_t GetExpandAxis(ge::Format format2D); |
| 135 | static ge::Format Get3DFormat(ge::Format format2D); | 141 | static ge::Format Get3DFormat(ge::Format format2D); |
| 136 | static std::string Get3DDataFormatStr(const std::string& format2D); | 142 | static std::string Get3DDataFormatStr(const std::string& format2D); |
| @@ -146,6 +152,12 @@ public: | |||
| 146 | std::string& dataFormat, std::vector<int64_t>* outputPadding = nullptr); | 152 | std::string& dataFormat, std::vector<int64_t>* outputPadding = nullptr); |
| 147 | 153 | ||
| 148 | static void ExpandOutputDesc(const ge::TensorDesc& output2DDesc, ge::TensorDesc& output3DDesc); | 154 | static void ExpandOutputDesc(const ge::TensorDesc& output2DDesc, ge::TensorDesc& output3DDesc); |
| 155 | + | ||
| 156 | +private: | ||
| 157 | + static bool CreateTransposeNodeImpl(ge::es::EsGraphBuilder& builder, const TransposeNodeConfig& config, | ||
| 158 | + ge::es::EsTensorHolder& output, ge::TensorDesc& outDesc, | ||
| 159 | + const ge::TensorDesc* inDescOverride, bool isTransposeD, | ||
| 160 | + const ge::AscendString& opType); | ||
| 149 | }; | 161 | }; |
| 150 | 162 | ||
| 151 | } // namespace ConvBackpropFusionUtils | 163 | } // namespace ConvBackpropFusionUtils |
| @@ -0,0 +1,365 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +namespace ops { | ||
| 19 | +using namespace ge; | ||
| 20 | +using namespace ge::es; | ||
| 21 | +using namespace ge::fusion; | ||
| 22 | +using namespace ConvBackpropFusionUtils; | ||
| 23 | +namespace { | ||
| 24 | + | ||
| 25 | +const AscendString PASS_NAME = "DepthwiseDfFusionPass"; | ||
| 26 | +const AscendString DEPTHWISE_D = "DepthwiseConv2DBackpropInputD"; | ||
| 27 | +const AscendString DEPTHWISE_DYN = "DepthwiseConv2DBackpropInput"; | ||
| 28 | + | ||
| 29 | +constexpr uint32_t FILTER_INDEX_D = 0U; | ||
| 30 | +constexpr uint32_t FILTER_INDEX_DYN = 1U; | ||
| 31 | +constexpr uint32_t GRAD_OUTPUT_INDEX_D = 1U; | ||
| 32 | +constexpr uint32_t GRAD_OUTPUT_INDEX_DYN = 2U; | ||
| 33 | +constexpr int32_t GRAD_OUTPUT_DIM = 4; | ||
| 34 | +constexpr int64_t GROUP_MAX_RANGE = 65535; | ||
| 35 | +constexpr size_t FILTER_DIM_EXPECT = 4; | ||
| 36 | +constexpr int32_t INPUT_SIZE_INDEX = 0; | ||
| 37 | + | ||
| 38 | +const std::vector<int32_t> TRANSPOSE_PERM = {1, 0, 2, 3}; | ||
| 39 | + | ||
| 40 | +const std::map<ge::Format, std::vector<int32_t>> FORMAT_TO_NCHW_DIM_MAP = {{ge::FORMAT_NCHW, {0, 1, 2, 3}}, | ||
| 41 | + {ge::FORMAT_HWCN, {3, 2, 0, 1}}}; | ||
| 42 | + | ||
| 43 | +constexpr const char* DEPTHWISE_PREFIX = "Depthwise"; | ||
| 44 | + | ||
| 45 | +} // anonymous namespace | ||
| 46 | + | ||
| 47 | +AscendString DepthwiseDfFusionPass::GetNodeType() const { return PASS_NAME; } | ||
| 48 | + | ||
| 49 | +bool DepthwiseDfFusionPass::GetResizeDepthwiseFilterShape(std::vector<int64_t>& resizeShape) | ||
| 50 | +{ | ||
| 51 | + const TensorDesc& filterDesc = isDynamic ? input1Desc : input0Desc; | ||
| 52 | + const auto& oriShape = filterDesc.GetShape().GetDims(); | ||
| 53 | + ge::Format format = filterDesc.GetOriginFormat(); | ||
| 54 | + if (oriShape.size() != FILTER_DIM_EXPECT) { | ||
| 55 | + OP_LOGE(GetNodeType().GetString(), "filter dim only supports 4 dims, got %zu.", oriShape.size()); | ||
| 56 | + return false; | ||
| 57 | + } | ||
| 58 | + const auto& dimVec = FORMAT_TO_NCHW_DIM_MAP.at(format); | ||
| 59 | + if (format == ge::FORMAT_NCHW) { | ||
| 60 | + resizeShape = {oriShape[dimVec[0]] * oriShape[dimVec[1]], 1, oriShape[dimVec[2]], oriShape[dimVec[3]]}; | ||
| 61 | + } else { | ||
| 62 | + resizeShape = {oriShape[dimVec[2]], oriShape[dimVec[3]], 1, oriShape[dimVec[0]] * oriShape[dimVec[1]]}; | ||
| 63 | + } | ||
| 64 | + return true; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +bool DepthwiseDfFusionPass::ValidateArch35Descs() | ||
| 68 | +{ | ||
| 69 | + const TensorDesc& filterDesc = isDynamic ? input1Desc : input0Desc; | ||
| 70 | + const TensorDesc& dedyDesc = isDynamic ? input2Desc : input1Desc; | ||
| 71 | + auto filterOriShapeDims = filterDesc.GetOriginShape().GetDims(); | ||
| 72 | + for (auto filterDim : filterOriShapeDims) { | ||
| 73 | + OP_CHECK_IF(filterDim <= 0, | ||
| 74 | + OP_LOGE(GetNodeType().GetString(), "%ld in filter shape should be positive.", filterDim), | ||
| 75 | + return false); | ||
| 76 | + } | ||
| 77 | + auto dedyOriShape = dedyDesc.GetOriginShape(); | ||
| 78 | + size_t dedyDims = dedyOriShape.GetDims().size(); | ||
| 79 | + OP_CHECK_IF(dedyDims != static_cast<size_t>(GRAD_OUTPUT_DIM) && | ||
| 80 | + (dedyDims != UNKNOWN_RANK_DIM || dedyOriShape.GetDim(0) != UNKNOWN_RANK_DIM_VALUE), | ||
| 81 | + OP_LOGE(GetNodeType().GetString(), "out_backprop dims should be 4 or shape is [-2], but got dims=%zu", | ||
| 82 | + dedyDims), | ||
| 83 | + return false); | ||
| 84 | + ge::Format gradOutputFormat = dedyDesc.GetOriginFormat(); | ||
| 85 | + ge::Format outputFormat = outputDesc.GetOriginFormat(); | ||
| 86 | + if (outputFormat != gradOutputFormat) { | ||
| 87 | + OP_LOGE(GetNodeType().GetString(), "output origin format and out_backprop origin format are not consistent."); | ||
| 88 | + return false; | ||
| 89 | + } | ||
| 90 | + return true; | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +bool DepthwiseDfFusionPass::ValidateFilterDesc(const GNode& matchedNode) | ||
| 94 | +{ | ||
| 95 | + if (isArch35) { | ||
| 96 | + OP_CHECK_IF(!ValidateArch35Descs(), OP_LOGE(GetNodeType().GetString(), "ValidateArch35Descs failed"), | ||
| 97 | + return false); | ||
| 98 | + } | ||
| 99 | + int64_t groups = 0; | ||
| 100 | + OP_CHECK_IF(matchedNode.GetAttr("groups", groups) != GRAPH_SUCCESS, | ||
| 101 | + OP_LOGE(GetNodeType().GetString(), "Failed to get groups attr"), return false); | ||
| 102 | + OP_CHECK_IF(groups <= 0 || groups > GROUP_MAX_RANGE, | ||
| 103 | + OP_LOGE(GetNodeType().GetString(), "groups=%ld should be in range [1, 65535].", groups), return false); | ||
| 104 | + return true; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +bool DepthwiseDfFusionPass::MeetRequirements(const GNode& matchedNode) | ||
| 108 | +{ | ||
| 109 | + AscendString matchedTypeAsc; | ||
| 110 | + OP_CHECK_IF(matchedNode.GetType(matchedTypeAsc) != GRAPH_SUCCESS, | ||
| 111 | + OP_LOGD(GetNodeType().GetString(), "GetType failed"), return false); | ||
| 112 | + isDynamic = (matchedTypeAsc.GetString() == std::string(DEPTHWISE_DYN.GetString())); | ||
| 113 | + isArch35 = ConvBackpropFusionUtilsPass::IsArch35(); | ||
| 114 | + OP_CHECK_IF(!GetNodeDesc(matchedNode), OP_LOGE(GetNodeType().GetString(), "GetNodeDesc failed"), return false); | ||
| 115 | + OP_CHECK_IF(!ValidateFilterDesc(matchedNode), OP_LOGD(GetNodeType().GetString(), "ValidateFilterDesc failed"), | ||
| 116 | + return false); | ||
| 117 | + const TensorDesc& filterDesc = isDynamic ? input1Desc : input0Desc; | ||
| 118 | + ge::Format originFormat = filterDesc.GetOriginFormat(); | ||
| 119 | + OP_CHECK_IF(FORMAT_TO_NCHW_DIM_MAP.find(originFormat) == FORMAT_TO_NCHW_DIM_MAP.end(), | ||
| 120 | + OP_LOGE(GetNodeType().GetString(), "filter origin format only supports NCHW or HWCN, got %d", | ||
| 121 | + static_cast<int>(originFormat)), | ||
| 122 | + return false); | ||
| 123 | + OP_LOGD(GetNodeType().GetString(), "MeetRequirements passed"); | ||
| 124 | + return true; | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +bool DepthwiseDfFusionPass::GetNodeAttrs(const GNode& node) | ||
| 128 | +{ | ||
| 129 | + OP_CHECK_IF(!ConvBackpropFusionBasePass::GetNodeAttrs(node), | ||
| 130 | + OP_LOGE(GetNodeType().GetString(), "Base GetNodeAttrs failed"), return false); | ||
| 131 | + if (!isDynamic) { | ||
| 132 | + OP_CHECK_IF(node.GetAttr("input_size", convBpAttr.input_size) != GRAPH_SUCCESS, | ||
| 133 | + OP_LOGE(GetNodeType().GetString(), "Failed to get input_size attr"), return false); | ||
| 134 | + } | ||
| 135 | + return true; | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +void DepthwiseDfFusionPass::SetNodeAttrs(GNode& outNode) | ||
| 139 | +{ | ||
| 140 | + ConvBackpropFusionBasePass::SetNodeAttrs(outNode); | ||
| 141 | + if (!isDynamic) { | ||
| 142 | + if (outNode.SetAttr("input_size", convBpAttr.input_size) != GRAPH_SUCCESS) { | ||
| 143 | + OP_LOGD(GetNodeType().GetString(), "Set input_size attr failed"); | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +void DepthwiseDfFusionPass::CreateBoundaryInputs(EsGraphBuilder& builder, EsTensorHolder& iFilterHolder, | ||
| 149 | + EsTensorHolder& iGradOutputHolder, EsTensorHolder& iInputSizeHolder) | ||
| 150 | +{ | ||
| 151 | + uint32_t filterIndex = isDynamic ? FILTER_INDEX_DYN : FILTER_INDEX_D; | ||
| 152 | + uint32_t gradOutputIndex = isDynamic ? GRAD_OUTPUT_INDEX_DYN : GRAD_OUTPUT_INDEX_D; | ||
| 153 | + const TensorDesc& filterDesc = isDynamic ? input1Desc : input0Desc; | ||
| 154 | + const TensorDesc& gradOutputDesc = isDynamic ? input2Desc : input1Desc; | ||
| 155 | + if (isDynamic) { | ||
| 156 | + iInputSizeHolder = builder.CreateInput(INPUT_SIZE_INDEX); | ||
| 157 | + ConvBackpropFusionUtilsPass::SetPlaceholderDesc(iInputSizeHolder, TENSOR_DEFAULT_OUTPUT_INDEX, input0Desc); | ||
| 158 | + } | ||
| 159 | + iFilterHolder = builder.CreateInput(static_cast<int64_t>(filterIndex)); | ||
| 160 | + ConvBackpropFusionUtilsPass::SetPlaceholderDesc(iFilterHolder, TENSOR_DEFAULT_OUTPUT_INDEX, filterDesc); | ||
| 161 | + iGradOutputHolder = builder.CreateInput(static_cast<int64_t>(gradOutputIndex)); | ||
| 162 | + ConvBackpropFusionUtilsPass::SetPlaceholderDesc(iGradOutputHolder, TENSOR_DEFAULT_OUTPUT_INDEX, gradOutputDesc); | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +bool DepthwiseDfFusionPass::BuildOptionalTranspose(EsGraphBuilder& builder, const std::string& nodeNamePrefix, | ||
| 166 | + const EsTensorHolder& iFilterHolder, | ||
| 167 | + EsTensorHolder& reshapeInputHolder, TensorDesc& reshapeInputDesc) | ||
| 168 | +{ | ||
| 169 | + const TensorDesc& filterDesc = isDynamic ? input1Desc : input0Desc; | ||
| 170 | + ge::Format originFormat = filterDesc.GetOriginFormat(); | ||
| 171 | + reshapeInputHolder = iFilterHolder; | ||
| 172 | + reshapeInputDesc = filterDesc; | ||
| 173 | + if (originFormat != ge::FORMAT_NCHW) { | ||
| 174 | + return true; | ||
| 175 | + } | ||
| 176 | + TensorDesc transposeOutDesc; | ||
| 177 | + EsTensorHolder transposeOut; | ||
| 178 | + if (isArch35) { | ||
| 179 | + TransposeNodeConfig config = TransposeNodeConfig::Create(iFilterHolder, TRANSPOSE_PERM, | ||
| 180 | + nodeNamePrefix + "/Transpose", originFormat); | ||
| 181 | + OP_CHECK_IF(!ConvBackpropFusionUtilsPass::CreateTransposeNode(builder, config, transposeOut, transposeOutDesc, | ||
| 182 | + GetNodeType()), | ||
| 183 | + OP_LOGE(GetNodeType().GetString(), "Create Transpose failed"), return false); | ||
| 184 | + } else { | ||
| 185 | + TransposeNodeConfig config = TransposeNodeConfig::Create(iFilterHolder, TRANSPOSE_PERM, | ||
| 186 | + nodeNamePrefix + "/TransposeD", originFormat); | ||
| 187 | + OP_CHECK_IF(!ConvBackpropFusionUtilsPass::CreateTransposeDNode(builder, config, transposeOut, transposeOutDesc, | ||
| 188 | + filterDesc, GetNodeType()), | ||
| 189 | + OP_LOGE(GetNodeType().GetString(), "Create TransposeD failed"), return false); | ||
| 190 | + } | ||
| 191 | + reshapeInputHolder = transposeOut; | ||
| 192 | + reshapeInputDesc = transposeOutDesc; | ||
| 193 | + OP_LOGD(GetNodeType().GetString(), "Insert Transpose before filter."); | ||
| 194 | + return true; | ||
| 195 | +} | ||
| 196 | + | ||
| 197 | +bool DepthwiseDfFusionPass::BuildReshapeNode(EsGraphBuilder& builder, const std::vector<int64_t>& filterResetShape, | ||
| 198 | + const std::string& nodeNamePrefix, | ||
| 199 | + const EsTensorHolder& reshapeInputHolder, | ||
| 200 | + const TensorDesc& reshapeInputDesc, EsTensorHolder& reshapeOutput, | ||
| 201 | + TensorDesc& targetFilterDesc) | ||
| 202 | +{ | ||
| 203 | + const TensorDesc& filterDesc = isDynamic ? input1Desc : input0Desc; | ||
| 204 | + auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 205 | + auto* reshapeInProducer = reshapeInputHolder.GetProducer(); | ||
| 206 | + OP_CHECK_IF(reshapeInProducer == nullptr, OP_LOGE(GetNodeType().GetString(), "Reshape input producer nullptr"), | ||
| 207 | + return false); | ||
| 208 | + TensorDesc reshapeOutDesc(reshapeInputDesc); | ||
| 209 | + reshapeOutDesc.SetShape(ge::Shape(filterResetShape)); | ||
| 210 | + reshapeOutDesc.SetOriginShape(ge::Shape(filterResetShape)); | ||
| 211 | + std::string reshapeName = nodeNamePrefix + "/Reshape"; | ||
| 212 | + GNode reshapeNode = CompliantNodeBuilder(graph) | ||
| 213 | + .OpType("Reshape") | ||
| 214 | + .Name(reshapeName.c_str()) | ||
| 215 | + .IrDefInputs({{"x", CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 216 | + .IrDefOutputs({{"y", CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 217 | + .Build(); | ||
| 218 | + OP_CHECK_IF(AddEdgeAndUpdatePeerDesc(*graph, *reshapeInProducer, reshapeInputHolder.GetProducerOutIndex(), | ||
| 219 | + reshapeNode, 0) != GRAPH_SUCCESS, | ||
| 220 | + OP_LOGE(GetNodeType().GetString(), "Add edge to reshape x failed"), return false); | ||
| 221 | + OP_CHECK_IF(reshapeNode.UpdateInputDesc(0, reshapeInputDesc) != GRAPH_SUCCESS || | ||
| 222 | + reshapeNode.UpdateOutputDesc(0, reshapeOutDesc) != GRAPH_SUCCESS, | ||
| 223 | + OP_LOGE(GetNodeType().GetString(), "Update reshape node desc failed"), return false); | ||
| 224 | + std::vector<int64_t> shapeAttr = filterResetShape; | ||
| 225 | + OP_CHECK_IF(reshapeNode.SetAttr("shape", shapeAttr) != GRAPH_SUCCESS, | ||
| 226 | + OP_LOGE(GetNodeType().GetString(), "Set shape attr failed"), return false); | ||
| 227 | + reshapeOutput = EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(reshapeNode, OUTPUT_INDEX)); | ||
| 228 | + targetFilterDesc = filterDesc; | ||
| 229 | + targetFilterDesc.SetShape(ge::Shape(filterResetShape)); | ||
| 230 | + targetFilterDesc.SetOriginShape(ge::Shape(filterResetShape)); | ||
| 231 | + return true; | ||
| 232 | +} | ||
| 233 | + | ||
| 234 | +GraphUniqPtr DepthwiseDfFusionPass::BuildDynamicTargetNode(EsGraphBuilder& builder, const std::string& targetOpType, | ||
| 235 | + const std::string& targetNodeName, | ||
| 236 | + const EsTensorHolder& iInputSizeHolder, | ||
| 237 | + const EsTensorHolder& iGradOutputHolder, | ||
| 238 | + const EsTensorHolder& reshapeOutput, | ||
| 239 | + const TensorDesc& targetFilterDesc) | ||
| 240 | +{ | ||
| 241 | + auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 242 | + const std::string outputName = isArch35 ? "y" : "input_grad"; | ||
| 243 | + GNode targetNode = CompliantNodeBuilder(graph) | ||
| 244 | + .OpType(targetOpType.c_str()) | ||
| 245 | + .Name(targetNodeName.c_str()) | ||
| 246 | + .IrDefInputs({{"input_size", CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 247 | + {"filter", CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 248 | + {"out_backprop", CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 249 | + .IrDefOutputs({{outputName, CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 250 | + .Build(); | ||
| 251 | + auto* inputSizeProducer = iInputSizeHolder.GetProducer(); | ||
| 252 | + OP_CHECK_IF(inputSizeProducer == nullptr, OP_LOGE(GetNodeType().GetString(), "input_size producer nullptr"), | ||
| 253 | + return nullptr); | ||
| 254 | + OP_CHECK_IF(AddEdgeAndUpdatePeerDesc(*graph, *inputSizeProducer, iInputSizeHolder.GetProducerOutIndex(), targetNode, | ||
| 255 | + INPUT_SIZE_INDEX) != GRAPH_SUCCESS, | ||
| 256 | + OP_LOGE(GetNodeType().GetString(), "Add edge input_size failed"), return nullptr); | ||
| 257 | + auto* reshapeProducer = reshapeOutput.GetProducer(); | ||
| 258 | + OP_CHECK_IF(reshapeProducer == nullptr, OP_LOGE(GetNodeType().GetString(), "reshape output producer nullptr"), | ||
| 259 | + return nullptr); | ||
| 260 | + OP_CHECK_IF(AddEdgeAndUpdatePeerDesc(*graph, *reshapeProducer, reshapeOutput.GetProducerOutIndex(), targetNode, | ||
| 261 | + static_cast<int32_t>(FILTER_INDEX_DYN)) != GRAPH_SUCCESS, | ||
| 262 | + OP_LOGE(GetNodeType().GetString(), "Add edge filter to target failed"), return nullptr); | ||
| 263 | + auto* gradOutProducer = iGradOutputHolder.GetProducer(); | ||
| 264 | + OP_CHECK_IF(gradOutProducer == nullptr, OP_LOGE(GetNodeType().GetString(), "grad out producer nullptr"), | ||
| 265 | + return nullptr); | ||
| 266 | + OP_CHECK_IF(AddEdgeAndUpdatePeerDesc(*graph, *gradOutProducer, iGradOutputHolder.GetProducerOutIndex(), targetNode, | ||
| 267 | + static_cast<int32_t>(GRAD_OUTPUT_INDEX_DYN)) != GRAPH_SUCCESS, | ||
| 268 | + OP_LOGE(GetNodeType().GetString(), "Add edge grad output to target failed"), return nullptr); | ||
| 269 | + SetNodeAttrs(targetNode); | ||
| 270 | + OP_CHECK_IF(targetNode.SetAttr("from_depthwise", convBpAttr.from_depthwise) != GRAPH_SUCCESS, | ||
| 271 | + OP_LOGE(GetNodeType().GetString(), "Set from_depthwise attr failed"), return nullptr); | ||
| 272 | + OP_CHECK_IF(targetNode.UpdateInputDesc(INPUT_SIZE_INDEX, input0Desc) != GRAPH_SUCCESS || | ||
| 273 | + targetNode.UpdateInputDesc(FILTER_INDEX_DYN, targetFilterDesc) != GRAPH_SUCCESS || | ||
| 274 | + targetNode.UpdateInputDesc(GRAD_OUTPUT_INDEX_DYN, input2Desc) != GRAPH_SUCCESS || | ||
| 275 | + targetNode.UpdateOutputDesc(OUTPUT_INDEX, outputDesc) != GRAPH_SUCCESS, | ||
| 276 | + OP_LOGE(GetNodeType().GetString(), "Update target node desc failed"), return nullptr); | ||
| 277 | + auto targetOutput = EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(targetNode, OUTPUT_INDEX)); | ||
| 278 | + OP_LOGD(GetNodeType().GetString(), "DepthwiseDF Replacement success (type=%s)", targetOpType.c_str()); | ||
| 279 | + return builder.BuildAndReset(std::vector<EsTensorHolder>{targetOutput}); | ||
| 280 | +} | ||
| 281 | + | ||
| 282 | +GraphUniqPtr DepthwiseDfFusionPass::BuildStaticTargetNode(EsGraphBuilder& builder, const std::string& targetOpType, | ||
| 283 | + const std::string& targetNodeName, | ||
| 284 | + const EsTensorHolder& iGradOutputHolder, | ||
| 285 | + const EsTensorHolder& reshapeOutput, | ||
| 286 | + const TensorDesc& targetFilterDesc) | ||
| 287 | +{ | ||
| 288 | + auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 289 | + GNode targetNode = CompliantNodeBuilder(graph) | ||
| 290 | + .OpType(targetOpType.c_str()) | ||
| 291 | + .Name(targetNodeName.c_str()) | ||
| 292 | + .IrDefInputs({{"filter", CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 293 | + {"out_backprop", CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 294 | + .IrDefOutputs({{"input_grad", CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 295 | + .Build(); | ||
| 296 | + auto* reshapeProducer = reshapeOutput.GetProducer(); | ||
| 297 | + OP_CHECK_IF(reshapeProducer == nullptr, OP_LOGE(GetNodeType().GetString(), "reshape output producer nullptr"), | ||
| 298 | + return nullptr); | ||
| 299 | + OP_CHECK_IF(AddEdgeAndUpdatePeerDesc(*graph, *reshapeProducer, reshapeOutput.GetProducerOutIndex(), targetNode, | ||
| 300 | + static_cast<int32_t>(FILTER_INDEX_D)) != GRAPH_SUCCESS, | ||
| 301 | + OP_LOGE(GetNodeType().GetString(), "Add edge filter to target failed"), return nullptr); | ||
| 302 | + auto* gradOutProducer = iGradOutputHolder.GetProducer(); | ||
| 303 | + OP_CHECK_IF(gradOutProducer == nullptr, OP_LOGE(GetNodeType().GetString(), "grad out producer nullptr"), | ||
| 304 | + return nullptr); | ||
| 305 | + OP_CHECK_IF(AddEdgeAndUpdatePeerDesc(*graph, *gradOutProducer, iGradOutputHolder.GetProducerOutIndex(), targetNode, | ||
| 306 | + static_cast<int32_t>(GRAD_OUTPUT_INDEX_D)) != GRAPH_SUCCESS, | ||
| 307 | + OP_LOGE(GetNodeType().GetString(), "Add edge grad output to target failed"), return nullptr); | ||
| 308 | + SetNodeAttrs(targetNode); | ||
| 309 | + OP_CHECK_IF(targetNode.SetAttr("from_depthwise", convBpAttr.from_depthwise) != GRAPH_SUCCESS, | ||
| 310 | + OP_LOGE(GetNodeType().GetString(), "Set from_depthwise attr failed"), return nullptr); | ||
| 311 | + OP_CHECK_IF(targetNode.UpdateInputDesc(FILTER_INDEX_D, targetFilterDesc) != GRAPH_SUCCESS || | ||
| 312 | + targetNode.UpdateInputDesc(GRAD_OUTPUT_INDEX_D, input1Desc) != GRAPH_SUCCESS || | ||
| 313 | + targetNode.UpdateOutputDesc(OUTPUT_INDEX, outputDesc) != GRAPH_SUCCESS, | ||
| 314 | + OP_LOGE(GetNodeType().GetString(), "Update target node desc failed"), return nullptr); | ||
| 315 | + auto targetOutput = EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(targetNode, OUTPUT_INDEX)); | ||
| 316 | + OP_LOGD(GetNodeType().GetString(), "DepthwiseDF Replacement success (D, type=%s)", targetOpType.c_str()); | ||
| 317 | + return builder.BuildAndReset(std::vector<EsTensorHolder>{targetOutput}); | ||
| 318 | +} | ||
| 319 | + | ||
| 320 | +GraphUniqPtr DepthwiseDfFusionPass::Replacement(const GNode& matchedNode) | ||
| 321 | +{ | ||
| 322 | + OP_LOGD(GetNodeType().GetString(), "Replacement start"); | ||
| 323 | + AscendString matchedTypeAsc; | ||
| 324 | + OP_CHECK_IF(matchedNode.GetType(matchedTypeAsc) != GRAPH_SUCCESS, | ||
| 325 | + OP_LOGE(GetNodeType().GetString(), "GetType failed"), return nullptr); | ||
| 326 | + std::string matchedType(matchedTypeAsc.GetString()); | ||
| 327 | + OP_CHECK_IF(!GetNodeAttrs(matchedNode), OP_LOGE(GetNodeType().GetString(), "GetNodeAttrs failed"), return nullptr); | ||
| 328 | + std::string nodeNamePrefix; | ||
| 329 | + OP_CHECK_IF(!ConvBackpropFusionUtilsPass::GetNodeName(matchedNode, nodeNamePrefix), | ||
| 330 | + OP_LOGE(GetNodeType().GetString(), "GetNodeName failed"), return nullptr); | ||
| 331 | + std::vector<int64_t> filterResetShape; | ||
| 332 | + OP_CHECK_IF(!GetResizeDepthwiseFilterShape(filterResetShape), | ||
| 333 | + OP_LOGE(GetNodeType().GetString(), "Compute filter resize shape failed"), return nullptr); | ||
| 334 | + auto builder = EsGraphBuilder("replacement"); | ||
| 335 | + OP_CHECK_IF(builder.GetCGraphBuilder()->GetGraph() == nullptr, | ||
| 336 | + OP_LOGE(GetNodeType().GetString(), "Get graph failed"), return nullptr); | ||
| 337 | + EsTensorHolder iFilterHolder, iGradOutputHolder, iInputSizeHolder; | ||
| 338 | + CreateBoundaryInputs(builder, iFilterHolder, iGradOutputHolder, iInputSizeHolder); | ||
| 339 | + EsTensorHolder reshapeInputHolder; | ||
| 340 | + TensorDesc reshapeInputDesc; | ||
| 341 | + OP_CHECK_IF(!BuildOptionalTranspose(builder, nodeNamePrefix, iFilterHolder, reshapeInputHolder, reshapeInputDesc), | ||
| 342 | + OP_LOGE(GetNodeType().GetString(), "BuildOptionalTranspose failed"), return nullptr); | ||
| 343 | + EsTensorHolder reshapeOutput; | ||
| 344 | + TensorDesc targetFilterDesc; | ||
| 345 | + OP_CHECK_IF(!BuildReshapeNode(builder, filterResetShape, nodeNamePrefix, reshapeInputHolder, reshapeInputDesc, | ||
| 346 | + reshapeOutput, targetFilterDesc), | ||
| 347 | + OP_LOGE(GetNodeType().GetString(), "BuildReshapeNode failed"), return nullptr); | ||
| 348 | + std::string targetOpType = matchedType; | ||
| 349 | + if (isArch35) { | ||
| 350 | + targetOpType.erase(0, strlen(DEPTHWISE_PREFIX)); | ||
| 351 | + } | ||
| 352 | + std::string targetNodeName = nodeNamePrefix + "/dx"; | ||
| 353 | + if (isDynamic) { | ||
| 354 | + return BuildDynamicTargetNode(builder, targetOpType, targetNodeName, iInputSizeHolder, iGradOutputHolder, | ||
| 355 | + reshapeOutput, targetFilterDesc); | ||
| 356 | + } | ||
| 357 | + return BuildStaticTargetNode(builder, targetOpType, targetNodeName, iGradOutputHolder, reshapeOutput, | ||
| 358 | + targetFilterDesc); | ||
| 359 | +} | ||
| 360 | + | ||
| 361 | +const std::vector<AscendString> kMatchOpTypes = {DEPTHWISE_D, DEPTHWISE_DYN}; | ||
| 362 | + | ||
| 363 | +REG_DECOMPOSE_PASS(DepthwiseDfFusionPass, kMatchOpTypes).Stage(CustomPassStage::kCompatibleInherited); | ||
| 364 | + | ||
| 365 | +} // namespace ops | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace ops { | ||
| 17 | + | ||
| 18 | +class __attribute__((visibility("default"))) DepthwiseDfFusionPass : public ConvBackpropFusionBasePass { | ||
| 19 | +public: | ||
| 20 | + explicit DepthwiseDfFusionPass(const std::vector<ge::AscendString>& opTypes) : ConvBackpropFusionBasePass(opTypes) | ||
| 21 | + {} | ||
| 22 | + | ||
| 23 | +protected: | ||
| 24 | + ge::AscendString GetNodeType() const override; | ||
| 25 | + bool MeetRequirements(const ge::GNode& matchedNode) override; | ||
| 26 | + ge::fusion::GraphUniqPtr Replacement(const ge::GNode& matchedNode) override; | ||
| 27 | + bool GetNodeAttrs(const ge::GNode& node) override; | ||
| 28 | + void SetNodeAttrs(ge::GNode& outNode) override; | ||
| 29 | + | ||
| 30 | + bool ValidateFilterDesc(const ge::GNode& matchedNode); | ||
| 31 | + bool GetResizeDepthwiseFilterShape(std::vector<int64_t>& resizeShape); | ||
| 32 | + | ||
| 33 | +private: | ||
| 34 | + bool ValidateArch35Descs(); | ||
| 35 | + void CreateBoundaryInputs(ge::es::EsGraphBuilder& builder, ge::es::EsTensorHolder& iFilterHolder, | ||
| 36 | + ge::es::EsTensorHolder& iGradOutputHolder, ge::es::EsTensorHolder& iInputSizeHolder); | ||
| 37 | + bool BuildOptionalTranspose(ge::es::EsGraphBuilder& builder, const std::string& nodeNamePrefix, | ||
| 38 | + const ge::es::EsTensorHolder& iFilterHolder, ge::es::EsTensorHolder& reshapeInputHolder, | ||
| 39 | + ge::TensorDesc& reshapeInputDesc); | ||
| 40 | + bool BuildReshapeNode(ge::es::EsGraphBuilder& builder, const std::vector<int64_t>& filterResetShape, | ||
| 41 | + const std::string& nodeNamePrefix, const ge::es::EsTensorHolder& reshapeInputHolder, | ||
| 42 | + const ge::TensorDesc& reshapeInputDesc, ge::es::EsTensorHolder& reshapeOutput, | ||
| 43 | + ge::TensorDesc& targetFilterDesc); | ||
| 44 | + ge::fusion::GraphUniqPtr BuildDynamicTargetNode(ge::es::EsGraphBuilder& builder, const std::string& targetOpType, | ||
| 45 | + const std::string& targetNodeName, | ||
| 46 | + const ge::es::EsTensorHolder& iInputSizeHolder, | ||
| 47 | + const ge::es::EsTensorHolder& iGradOutputHolder, | ||
| 48 | + const ge::es::EsTensorHolder& reshapeOutput, | ||
| 49 | + const ge::TensorDesc& targetFilterDesc); | ||
| 50 | + ge::fusion::GraphUniqPtr BuildStaticTargetNode(ge::es::EsGraphBuilder& builder, const std::string& targetOpType, | ||
| 51 | + const std::string& targetNodeName, | ||
| 52 | + const ge::es::EsTensorHolder& iGradOutputHolder, | ||
| 53 | + const ge::es::EsTensorHolder& reshapeOutput, | ||
| 54 | + const ge::TensorDesc& targetFilterDesc); | ||
| 55 | +}; | ||
| 56 | + | ||
| 57 | +} // namespace ops | ||
| 58 | + | ||
| 59 | + | ||
| @@ -0,0 +1,519 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +using namespace ge; | ||
| 23 | +using namespace ge::es; | ||
| 24 | +using namespace fe; | ||
| 25 | +using namespace fusion; | ||
| 26 | +using namespace ops::ConvBackpropFusionUtils; | ||
| 27 | + | ||
| 28 | +namespace { | ||
| 29 | + | ||
| 30 | +constexpr int64_t AI_CORE_CNT = 64; | ||
| 31 | +constexpr int64_t INPUT_SIZE_DIM = 4; | ||
| 32 | +int64_t DEFAULT_IMPL_MODE = 0x1; | ||
| 33 | + | ||
| 34 | +void SetPlatform(const std::string& soc) | ||
| 35 | +{ | ||
| 36 | + PlatformInfo platformInfo; | ||
| 37 | + OptionalInfo optionalInfo; | ||
| 38 | + platformInfo.soc_info.ai_core_cnt = AI_CORE_CNT; | ||
| 39 | + platformInfo.str_info.short_soc_version = soc; | ||
| 40 | + optionalInfo.soc_version = soc; | ||
| 41 | + if (soc == "Ascend950") { | ||
| 42 | + platformInfo.ai_core_intrinsic_dtype_map["Intrinsic_data_move_out2l1_dn2nz"] = {"float16", "float", "bfloat16"}; | ||
| 43 | + } | ||
| 44 | + PlatformInfoManager::Instance().platform_info_map_[soc] = platformInfo; | ||
| 45 | + PlatformInfoManager::Instance().SetOptionalCompilationInfo(optionalInfo); | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +EsTensorHolder CreateDepthwiseConv2DBpInputDNode(EsGraphBuilder& builder, const char* opType, | ||
| 49 | + const EsTensorHolder& filter, const EsTensorHolder& outBackprop, | ||
| 50 | + std::vector<int64_t> strides, std::vector<int64_t> pads, | ||
| 51 | + std::vector<int64_t> dilations, int64_t groups, | ||
| 52 | + const std::string& dataFormat, DataType outDtype, | ||
| 53 | + const std::vector<int64_t>& outShape, Format outFormat, | ||
| 54 | + bool fromDepthwise = false) | ||
| 55 | +{ | ||
| 56 | + auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 57 | + auto node = CompliantNodeBuilder(graph) | ||
| 58 | + .OpType(opType) | ||
| 59 | + .Name(opType) | ||
| 60 | + .IrDefInputs({{"filter", CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 61 | + {"out_backprop", CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 62 | + .IrDefOutputs({{"y", CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 63 | + .InstanceOutputDataType("y", outDtype) | ||
| 64 | + .InstanceOutputShape("y", outShape) | ||
| 65 | + .InstanceOutputFormat("y", outFormat) | ||
| 66 | + .Build(); | ||
| 67 | + | ||
| 68 | + AddEdgeAndUpdatePeerDesc(*graph, *filter.GetProducer(), filter.GetProducerOutIndex(), node, 0); | ||
| 69 | + AddEdgeAndUpdatePeerDesc(*graph, *outBackprop.GetProducer(), outBackprop.GetProducerOutIndex(), node, 1); | ||
| 70 | + | ||
| 71 | + TensorDesc filterDesc, outBackpropDesc; | ||
| 72 | + filter.GetProducer()->GetOutputDesc(filter.GetProducerOutIndex(), filterDesc); | ||
| 73 | + outBackprop.GetProducer()->GetOutputDesc(outBackprop.GetProducerOutIndex(), outBackpropDesc); | ||
| 74 | + node.UpdateInputDesc(0, filterDesc); | ||
| 75 | + node.UpdateInputDesc(1, outBackpropDesc); | ||
| 76 | + | ||
| 77 | + node.SetAttr("strides", strides); | ||
| 78 | + node.SetAttr("pads", pads); | ||
| 79 | + node.SetAttr("dilations", dilations); | ||
| 80 | + node.SetAttr("groups", groups); | ||
| 81 | + AscendString fmt = dataFormat.c_str(); | ||
| 82 | + node.SetAttr("data_format", fmt); | ||
| 83 | + node.SetAttr("_op_impl_mode_enum", DEFAULT_IMPL_MODE); | ||
| 84 | + node.SetAttr("from_depthwise", fromDepthwise); | ||
| 85 | + std::vector<int64_t> inputSizeAttr = outShape; | ||
| 86 | + node.SetAttr("input_size", inputSizeAttr); | ||
| 87 | + | ||
| 88 | + return EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(node, 0)); | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +EsTensorHolder CreateDepthwiseConv2DBpInputNode(EsGraphBuilder& builder, const char* opType, | ||
| 92 | + const EsTensorHolder& inputSize, const EsTensorHolder& filter, | ||
| 93 | + const EsTensorHolder& outBackprop, std::vector<int64_t> strides, | ||
| 94 | + std::vector<int64_t> pads, std::vector<int64_t> dilations, | ||
| 95 | + int64_t groups, const std::string& dataFormat, DataType outDtype, | ||
| 96 | + const std::vector<int64_t>& outShape, Format outFormat, | ||
| 97 | + bool fromDepthwise = false) | ||
| 98 | +{ | ||
| 99 | + auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 100 | + auto node = CompliantNodeBuilder(graph) | ||
| 101 | + .OpType(opType) | ||
| 102 | + .Name(opType) | ||
| 103 | + .IrDefInputs({{"input_size", CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 104 | + {"filter", CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 105 | + {"out_backprop", CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 106 | + .IrDefOutputs({{"y", CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 107 | + .InstanceOutputDataType("y", outDtype) | ||
| 108 | + .InstanceOutputShape("y", outShape) | ||
| 109 | + .InstanceOutputFormat("y", outFormat) | ||
| 110 | + .Build(); | ||
| 111 | + | ||
| 112 | + AddEdgeAndUpdatePeerDesc(*graph, *inputSize.GetProducer(), inputSize.GetProducerOutIndex(), node, 0); | ||
| 113 | + AddEdgeAndUpdatePeerDesc(*graph, *filter.GetProducer(), filter.GetProducerOutIndex(), node, 1); | ||
| 114 | + AddEdgeAndUpdatePeerDesc(*graph, *outBackprop.GetProducer(), outBackprop.GetProducerOutIndex(), node, 2); | ||
| 115 | + | ||
| 116 | + TensorDesc inputSizeDesc, filterDesc, outBackpropDesc; | ||
| 117 | + inputSize.GetProducer()->GetOutputDesc(inputSize.GetProducerOutIndex(), inputSizeDesc); | ||
| 118 | + filter.GetProducer()->GetOutputDesc(filter.GetProducerOutIndex(), filterDesc); | ||
| 119 | + outBackprop.GetProducer()->GetOutputDesc(outBackprop.GetProducerOutIndex(), outBackpropDesc); | ||
| 120 | + node.UpdateInputDesc(0, inputSizeDesc); | ||
| 121 | + node.UpdateInputDesc(1, filterDesc); | ||
| 122 | + node.UpdateInputDesc(2, outBackpropDesc); | ||
| 123 | + | ||
| 124 | + node.SetAttr("strides", strides); | ||
| 125 | + node.SetAttr("pads", pads); | ||
| 126 | + node.SetAttr("dilations", dilations); | ||
| 127 | + node.SetAttr("groups", groups); | ||
| 128 | + AscendString fmt = dataFormat.c_str(); | ||
| 129 | + node.SetAttr("data_format", fmt); | ||
| 130 | + node.SetAttr("_op_impl_mode_enum", DEFAULT_IMPL_MODE); | ||
| 131 | + node.SetAttr("from_depthwise", fromDepthwise); | ||
| 132 | + | ||
| 133 | + return EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(node, 0)); | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +bool CheckNodeExists(GraphPtr& graph, const std::string& type) | ||
| 137 | +{ | ||
| 138 | + for (auto node : graph->GetAllNodes()) { | ||
| 139 | + AscendString nodeType; | ||
| 140 | + node.GetType(nodeType); | ||
| 141 | + if (nodeType.GetString() == type) { | ||
| 142 | + return true; | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + return false; | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +bool GetNodeBoolAttr(GraphPtr& graph, const std::string& type, const std::string& attrName, bool& attrValue) | ||
| 149 | +{ | ||
| 150 | + for (auto node : graph->GetAllNodes()) { | ||
| 151 | + AscendString nodeType; | ||
| 152 | + node.GetType(nodeType); | ||
| 153 | + if (nodeType.GetString() == type) { | ||
| 154 | + return node.GetAttr(attrName.c_str(), attrValue) == GRAPH_SUCCESS; | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | + return false; | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +} // namespace | ||
| 161 | + | ||
| 162 | +class DepthwiseDfFusionPassTest : public testing::Test { | ||
| 163 | +protected: | ||
| 164 | + void SetUp() override { SetPlatform("Ascend950"); } | ||
| 165 | +}; | ||
| 166 | + | ||
| 167 | +TEST_F(DepthwiseDfFusionPassTest, staticDNchwFp16Success) | ||
| 168 | +{ | ||
| 169 | + auto builder = EsGraphBuilder("staticDNchwFp16Success"); | ||
| 170 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 171 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 172 | + | ||
| 173 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 174 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 175 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 176 | + | ||
| 177 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 178 | + CustomPassContext ctx; | ||
| 179 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 180 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 181 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 182 | + EXPECT_TRUE(CheckNodeExists(graph, "Reshape")); | ||
| 183 | + EXPECT_TRUE(CheckNodeExists(graph, "Transpose")); | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +TEST_F(DepthwiseDfFusionPassTest, dynamicNchwFp16Success) | ||
| 187 | +{ | ||
| 188 | + auto builder = EsGraphBuilder("dynamicNchwFp16Success"); | ||
| 189 | + auto inputSize = builder.CreateInput(0, "input_size", DT_INT32, FORMAT_ND, {INPUT_SIZE_DIM}); | ||
| 190 | + auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 191 | + auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 192 | + | ||
| 193 | + auto y = CreateDepthwiseConv2DBpInputNode(builder, "DepthwiseConv2DBackpropInput", inputSize, filter, outBackprop, | ||
| 194 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 195 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 196 | + | ||
| 197 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 198 | + CustomPassContext ctx; | ||
| 199 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInput")}); | ||
| 200 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 201 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInput")); | ||
| 202 | + EXPECT_TRUE(CheckNodeExists(graph, "Reshape")); | ||
| 203 | + EXPECT_TRUE(CheckNodeExists(graph, "Transpose")); | ||
| 204 | +} | ||
| 205 | + | ||
| 206 | +TEST_F(DepthwiseDfFusionPassTest, staticDHwcnFp16Success) | ||
| 207 | +{ | ||
| 208 | + auto builder = EsGraphBuilder("staticDHwcnFp16Success"); | ||
| 209 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 210 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 211 | + | ||
| 212 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 213 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 214 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 215 | + | ||
| 216 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 217 | + CustomPassContext ctx; | ||
| 218 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 219 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 220 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 221 | + EXPECT_TRUE(CheckNodeExists(graph, "Reshape")); | ||
| 222 | + EXPECT_FALSE(CheckNodeExists(graph, "Transpose")); | ||
| 223 | +} | ||
| 224 | + | ||
| 225 | +TEST_F(DepthwiseDfFusionPassTest, dynamicHwcnFp16Success) | ||
| 226 | +{ | ||
| 227 | + auto builder = EsGraphBuilder("dynamicHwcnFp16Success"); | ||
| 228 | + auto inputSize = builder.CreateInput(0, "input_size", DT_INT32, FORMAT_ND, {INPUT_SIZE_DIM}); | ||
| 229 | + auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 230 | + auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 231 | + | ||
| 232 | + auto y = CreateDepthwiseConv2DBpInputNode(builder, "DepthwiseConv2DBackpropInput", inputSize, filter, outBackprop, | ||
| 233 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 234 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 235 | + | ||
| 236 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 237 | + CustomPassContext ctx; | ||
| 238 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInput")}); | ||
| 239 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 240 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInput")); | ||
| 241 | + EXPECT_TRUE(CheckNodeExists(graph, "Reshape")); | ||
| 242 | + EXPECT_FALSE(CheckNodeExists(graph, "Transpose")); | ||
| 243 | +} | ||
| 244 | + | ||
| 245 | +TEST_F(DepthwiseDfFusionPassTest, staticDNchwBf16Success) | ||
| 246 | +{ | ||
| 247 | + auto builder = EsGraphBuilder("staticDNchwBf16Success"); | ||
| 248 | + auto filter = builder.CreateInput(0, "filter", DT_BF16, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 249 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_BF16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 250 | + | ||
| 251 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 252 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_BF16, | ||
| 253 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 254 | + | ||
| 255 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 256 | + CustomPassContext ctx; | ||
| 257 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 258 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 259 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 260 | +} | ||
| 261 | + | ||
| 262 | +TEST_F(DepthwiseDfFusionPassTest, staticDNchwFp32Success) | ||
| 263 | +{ | ||
| 264 | + auto builder = EsGraphBuilder("staticDNchwFp32Success"); | ||
| 265 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 266 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 267 | + | ||
| 268 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 269 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT, | ||
| 270 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 271 | + | ||
| 272 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 273 | + CustomPassContext ctx; | ||
| 274 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 275 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 276 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +TEST_F(DepthwiseDfFusionPassTest, dynamicHwcnBf16Success) | ||
| 280 | +{ | ||
| 281 | + auto builder = EsGraphBuilder("dynamicHwcnBf16Success"); | ||
| 282 | + auto inputSize = builder.CreateInput(0, "input_size", DT_INT32, FORMAT_ND, {INPUT_SIZE_DIM}); | ||
| 283 | + auto filter = builder.CreateInput(1, "filter", DT_BF16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 284 | + auto outBackprop = builder.CreateInput(2, "out_backprop", DT_BF16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 285 | + | ||
| 286 | + auto y = CreateDepthwiseConv2DBpInputNode(builder, "DepthwiseConv2DBackpropInput", inputSize, filter, outBackprop, | ||
| 287 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_BF16, | ||
| 288 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 289 | + | ||
| 290 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 291 | + CustomPassContext ctx; | ||
| 292 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInput")}); | ||
| 293 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 294 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInput")); | ||
| 295 | +} | ||
| 296 | + | ||
| 297 | +TEST_F(DepthwiseDfFusionPassTest, nonArch35NchwTransposeDSuccess) | ||
| 298 | +{ | ||
| 299 | + SetPlatform("Ascend910_93"); | ||
| 300 | + auto builder = EsGraphBuilder("nonArch35NchwTransposeDSuccess"); | ||
| 301 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 302 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 303 | + | ||
| 304 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 305 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 306 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 307 | + | ||
| 308 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 309 | + CustomPassContext ctx; | ||
| 310 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 311 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 312 | + EXPECT_TRUE(CheckNodeExists(graph, "DepthwiseConv2DBackpropInputD")); | ||
| 313 | + EXPECT_TRUE(CheckNodeExists(graph, "TransposeD")); | ||
| 314 | + EXPECT_FALSE(CheckNodeExists(graph, "Transpose")); | ||
| 315 | +} | ||
| 316 | + | ||
| 317 | +TEST_F(DepthwiseDfFusionPassTest, groupsZeroFail) | ||
| 318 | +{ | ||
| 319 | + auto builder = EsGraphBuilder("groupsZeroFail"); | ||
| 320 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 321 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 322 | + | ||
| 323 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 324 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 0, "NCHW", DT_FLOAT16, | ||
| 325 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 326 | + | ||
| 327 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 328 | + CustomPassContext ctx; | ||
| 329 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 330 | + EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 331 | + EXPECT_FALSE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 332 | +} | ||
| 333 | + | ||
| 334 | +TEST_F(DepthwiseDfFusionPassTest, groupsTooLargeFail) | ||
| 335 | +{ | ||
| 336 | + auto builder = EsGraphBuilder("groupsTooLargeFail"); | ||
| 337 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 338 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 339 | + | ||
| 340 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 341 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 65536, "NCHW", DT_FLOAT16, | ||
| 342 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 343 | + | ||
| 344 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 345 | + CustomPassContext ctx; | ||
| 346 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 347 | + EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 348 | + EXPECT_FALSE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 349 | +} | ||
| 350 | + | ||
| 351 | +TEST_F(DepthwiseDfFusionPassTest, groupsMaxBoundarySuccess) | ||
| 352 | +{ | ||
| 353 | + auto builder = EsGraphBuilder("groupsMaxBoundarySuccess"); | ||
| 354 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 355 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 356 | + | ||
| 357 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 358 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 65535, "NCHW", DT_FLOAT16, | ||
| 359 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 360 | + | ||
| 361 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 362 | + CustomPassContext ctx; | ||
| 363 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 364 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 365 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 366 | +} | ||
| 367 | + | ||
| 368 | +TEST_F(DepthwiseDfFusionPassTest, groupsMinBoundarySuccess) | ||
| 369 | +{ | ||
| 370 | + auto builder = EsGraphBuilder("groupsMinBoundarySuccess"); | ||
| 371 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 372 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 373 | + | ||
| 374 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 375 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 1, "NCHW", DT_FLOAT16, | ||
| 376 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 377 | + | ||
| 378 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 379 | + CustomPassContext ctx; | ||
| 380 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 381 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 382 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 383 | +} | ||
| 384 | + | ||
| 385 | +TEST_F(DepthwiseDfFusionPassTest, invalidFilterDimFail) | ||
| 386 | +{ | ||
| 387 | + auto builder = EsGraphBuilder("invalidFilterDimFail"); | ||
| 388 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_NCHW, {32, 1, 3}); | ||
| 389 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 390 | + | ||
| 391 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 392 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 393 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 394 | + | ||
| 395 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 396 | + CustomPassContext ctx; | ||
| 397 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 398 | + EXPECT_NE(pass.Run(graph, ctx), SUCCESS); | ||
| 399 | + EXPECT_FALSE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 400 | +} | ||
| 401 | + | ||
| 402 | +TEST_F(DepthwiseDfFusionPassTest, invalidFilterFormatFail) | ||
| 403 | +{ | ||
| 404 | + auto builder = EsGraphBuilder("invalidFilterFormatFail"); | ||
| 405 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_ND, {32, 1, 3, 3}); | ||
| 406 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 407 | + | ||
| 408 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 409 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 410 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 411 | + | ||
| 412 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 413 | + CustomPassContext ctx; | ||
| 414 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 415 | + EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 416 | + EXPECT_FALSE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 417 | +} | ||
| 418 | + | ||
| 419 | +TEST_F(DepthwiseDfFusionPassTest, formatMismatchFail) | ||
| 420 | +{ | ||
| 421 | + auto builder = EsGraphBuilder("formatMismatchFail"); | ||
| 422 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_NCHW, {32, 1, 3, 3}); | ||
| 423 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 424 | + | ||
| 425 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 426 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 427 | + {2, 32, 32, 32}, FORMAT_NHWC); | ||
| 428 | + | ||
| 429 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 430 | + CustomPassContext ctx; | ||
| 431 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 432 | + EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 433 | + EXPECT_FALSE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 434 | +} | ||
| 435 | + | ||
| 436 | +TEST_F(DepthwiseDfFusionPassTest, unknownRankDedySuccess) | ||
| 437 | +{ | ||
| 438 | + auto builder = EsGraphBuilder("unknownRankDedySuccess"); | ||
| 439 | + auto inputSize = builder.CreateInput(0, "input_size", DT_INT32, FORMAT_ND, {INPUT_SIZE_DIM}); | ||
| 440 | + auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 441 | + auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {-2}); | ||
| 442 | + | ||
| 443 | + auto y = CreateDepthwiseConv2DBpInputNode(builder, "DepthwiseConv2DBackpropInput", inputSize, filter, outBackprop, | ||
| 444 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, {-2}, | ||
| 445 | + FORMAT_NCHW); | ||
| 446 | + | ||
| 447 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 448 | + CustomPassContext ctx; | ||
| 449 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInput")}); | ||
| 450 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 451 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInput")); | ||
| 452 | +} | ||
| 453 | + | ||
| 454 | +TEST_F(DepthwiseDfFusionPassTest, fromDepthwisePropagatedSuccess) | ||
| 455 | +{ | ||
| 456 | + auto builder = EsGraphBuilder("fromDepthwisePropagatedSuccess"); | ||
| 457 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 458 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 459 | + | ||
| 460 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 461 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 462 | + {2, 32, 32, 32}, FORMAT_NCHW, true); | ||
| 463 | + | ||
| 464 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 465 | + CustomPassContext ctx; | ||
| 466 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 467 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 468 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 469 | + bool fromDepthwise = false; | ||
| 470 | + EXPECT_TRUE(GetNodeBoolAttr(graph, "Conv2DBackpropInputD", "from_depthwise", fromDepthwise)); | ||
| 471 | + EXPECT_TRUE(fromDepthwise); | ||
| 472 | +} | ||
| 473 | + | ||
| 474 | +TEST_F(DepthwiseDfFusionPassTest, fromDepthwiseDefaultFalse) | ||
| 475 | +{ | ||
| 476 | + auto builder = EsGraphBuilder("fromDepthwiseDefaultFalse"); | ||
| 477 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 478 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 479 | + | ||
| 480 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 481 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 482 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 483 | + | ||
| 484 | + std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 485 | + CustomPassContext ctx; | ||
| 486 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 487 | + EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 488 | + EXPECT_TRUE(CheckNodeExists(graph, "Conv2DBackpropInputD")); | ||
| 489 | + bool fromDepthwise = true; | ||
| 490 | + EXPECT_TRUE(GetNodeBoolAttr(graph, "Conv2DBackpropInputD", "from_depthwise", fromDepthwise)); | ||
| 491 | + EXPECT_FALSE(fromDepthwise); | ||
| 492 | +} | ||
| 493 | + | ||
| 494 | +TEST_F(DepthwiseDfFusionPassTest, staticDInputSizeAttrPropagated) | ||
| 495 | +{ | ||
| 496 | + auto builder = EsGraphBuilder("staticDInputSizeAttrPropagated"); | ||
| 497 | + auto filter = builder.CreateInput(0, "filter", DT_FLOAT16, FORMAT_HWCN, {3, 3, 1, 32}); | ||
| 498 | + auto outBackprop = builder.CreateInput(1, "out_backprop", DT_FLOAT16, FORMAT_NCHW, {2, 32, 16, 16}); | ||
| 499 | + | ||
| 500 | + auto y = CreateDepthwiseConv2DBpInputDNode(builder, "DepthwiseConv2DBackpropInputD", filter, outBackprop, | ||
| 501 | + {1, 1, 2, 2}, {0, 0, 1, 1}, {1, 1, 1, 1}, 32, "NCHW", DT_FLOAT16, | ||
| 502 | + {2, 32, 32, 32}, FORMAT_NCHW); | ||
| 503 | + auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 504 | + for (auto node : graph->GetAllNodes()) { | ||
| 505 | + AscendString nodeType; | ||
| 506 | + node.GetType(nodeType); | ||
| 507 | + if (std::string(nodeType.GetString()) == "DepthwiseConv2DBackpropInputD") { | ||
| 508 | + std::vector<int64_t> inputSizeAttr = {2, 32, 32, 32}; | ||
| 509 | + node.SetAttr("input_size", inputSizeAttr); | ||
| 510 | + break; | ||
| 511 | + } | ||
| 512 | + } | ||
| 513 | + | ||
| 514 | + std::shared_ptr<Graph> graphBuilt = builder.BuildAndReset({y}); | ||
| 515 | + CustomPassContext ctx; | ||
| 516 | + ops::DepthwiseDfFusionPass pass({AscendString("DepthwiseConv2DBackpropInputD")}); | ||
| 517 | + EXPECT_EQ(pass.Run(graphBuilt, ctx), SUCCESS); | ||
| 518 | + EXPECT_TRUE(CheckNodeExists(graphBuilt, "Conv2DBackpropInputD")); | ||
| 519 | +} | ||


950的图有静态算子吗?