已合并
FusionPass:Con3dBpInput/Con3dBpFilter to Con3dBpInputV2/Con3dBpFilterV2 FusionPass #6004
xxxzh创建于 6月12日
FusionPass:Con3dBpInput/Con3dBpFilter to Con3dBpInputV2/Con3dBpFilterV2 FusionPass #6004
已合并
共 14 个文件变更+1483-0
| @@ -0,0 +1,97 @@ | |||
| 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 | namespace ops { | ||
| 15 | using namespace ge; | ||
| 16 | using namespace ConvBackpropFusionUtils; | ||
| 17 | |||
| 18 | void ConvBackpropFusionBasePass::InitMember() | ||
| 19 | { | ||
| 20 | npuArch = NpuArch::DAV_RESV; | ||
| 21 | input0Desc = TensorDesc(); | ||
| 22 | input1Desc = TensorDesc(); | ||
| 23 | input2Desc = TensorDesc(); | ||
| 24 | outputDesc = TensorDesc(); | ||
| 25 | convBpAttr.Reset(); | ||
| 26 | } | ||
| 27 | |||
| 28 | bool ConvBackpropFusionBasePass::CheckSocAndIntrinsic() | ||
| 29 | { | ||
| 30 | return ConvBackpropFusionUtilsPass::CheckSocAndIntrinsic(SUPPORT_SOC_LIST, npuArch); | ||
| 31 | } | ||
| 32 | |||
| 33 | |||
| 34 | bool ConvBackpropFusionBasePass::MeetRequirements(const GNode& convBpInputNode) | ||
| 35 | { | ||
| 36 | if (!CheckSocAndIntrinsic()) { | ||
| 37 | OP_LOGD(GetNodeType().GetString(), "SOC check failed"); | ||
| 38 | return false; | ||
| 39 | } | ||
| 40 | OP_LOGD(GetNodeType().GetString(), "SOC check passed"); | ||
| 41 | return true; | ||
| 42 | } | ||
| 43 | |||
| 44 | bool ConvBackpropFusionBasePass::GetNodeDesc(const GNode& node) | ||
| 45 | { | ||
| 46 | InitMember(); | ||
| 47 | // 获取输入索引 | ||
| 48 | int32_t inputIdx0 = 0; | ||
| 49 | int32_t inputIdx1 = 1; | ||
| 50 | int32_t outBackpropIdx = 2; | ||
| 51 | OP_CHECK_IF(node.GetInputDesc(inputIdx0, input0Desc) != GRAPH_SUCCESS || | ||
| 52 | node.GetInputDesc(inputIdx1, input1Desc) != GRAPH_SUCCESS || | ||
| 53 | node.GetInputDesc(outBackpropIdx, input2Desc) != GRAPH_SUCCESS || | ||
| 54 | node.GetOutputDesc(OUTPUT_INDEX, outputDesc) != GRAPH_SUCCESS, | ||
| 55 | OP_LOGE(GetNodeType().GetString(), "Get input/output desc failed"), return false); | ||
| 56 | return true; | ||
| 57 | } | ||
| 58 | |||
| 59 | bool ConvBackpropFusionBasePass::GetNodeAttrs(const GNode& node) | ||
| 60 | { | ||
| 61 | AscendString name; | ||
| 62 | node.GetName(name); | ||
| 63 | |||
| 64 | AscendString format; | ||
| 65 | OP_CHECK_IF(node.GetAttr("strides", convBpAttr.strides) != GRAPH_SUCCESS || | ||
| 66 | node.GetAttr("pads", convBpAttr.pads) != GRAPH_SUCCESS || | ||
| 67 | node.GetAttr("dilations", convBpAttr.dilations) != GRAPH_SUCCESS || | ||
| 68 | node.GetAttr("groups", convBpAttr.groups) != GRAPH_SUCCESS || | ||
| 69 | node.GetAttr("data_format", format) != GRAPH_SUCCESS, | ||
| 70 | OP_LOGE(GetNodeType().GetString(), "Get attrs from %s failed", name.GetString()), return false); | ||
| 71 | |||
| 72 | if(node.GetAttr("_op_impl_mode_enum", convBpAttr.opImplModeEnum) != GRAPH_SUCCESS){ | ||
| 73 | OP_LOGD(GetNodeType().GetString(), "Get _op_impl_mode_enum attrs from %s failed, set default value", name.GetString()); | ||
| 74 | } | ||
| 75 | |||
| 76 | convBpAttr.dataFormat = std::string(format.GetString()); | ||
| 77 | |||
| 78 | convBpAttr.hf32 = | ||
| 79 | input2Desc.GetDataType() == DataType::DT_FLOAT && | ||
| 80 | convBpAttr.opImplModeEnum == HF32_PRECISION_MODE_INT; | ||
| 81 | |||
| 82 | convBpAttr.opImplModeEnum = convBpAttr.hf32 ? convBpAttr.opImplModeEnum : 0x1; | ||
| 83 | |||
| 84 | return true; | ||
| 85 | } | ||
| 86 | |||
| 87 | bool ConvBackpropFusionBasePass::UpdateNodeInputDescInfo(ge::GNode *node) | ||
| 88 | { | ||
| 89 | OP_CHECK_IF(node->UpdateInputDesc(CONV_BP_V2_INPUT_INDEX, input0Desc) != GRAPH_SUCCESS || | ||
| 90 | node->UpdateInputDesc(CONV_BP_V2_FILTER_INDEX, input1Desc) != GRAPH_SUCCESS || | ||
| 91 | node->UpdateInputDesc(CONV_BP_V2_OUT_BACKPROP_INDEX, input2Desc) != GRAPH_SUCCESS || | ||
| 92 | node->UpdateOutputDesc(CONV_BP_V2_OUTPUT_INDEX, outputDesc) != GRAPH_SUCCESS, | ||
| 93 | OP_LOGE(GetNodeType().GetString(), "Update NodeInputDescInfo failed"), return false); | ||
| 94 | return true; | ||
| 95 | } | ||
| 96 | |||
| 97 | } // namespace ops | ||
| @@ -0,0 +1,82 @@ | |||
| 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 | namespace ops { | ||
| 18 | |||
| 19 | // ConvBackprop属性结构体 | ||
| 20 | struct ConvBackpropAttrs { | ||
| 21 | std::vector<int64_t> strides; | ||
| 22 | std::vector<int64_t> pads; | ||
| 23 | std::vector<int64_t> dilations; | ||
| 24 | int64_t groups = 0; | ||
| 25 | std::string dataFormat; | ||
| 26 | int64_t opImplModeEnum = 0; | ||
| 27 | bool hf32 = false; | ||
| 28 | |||
| 29 | void Reset() | ||
| 30 | { | ||
| 31 | strides.clear(); | ||
| 32 | pads.clear(); | ||
| 33 | dilations.clear(); | ||
| 34 | groups = 0; | ||
| 35 | dataFormat = ""; | ||
| 36 | opImplModeEnum = 0; | ||
| 37 | hf32 = false; | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * ConvBackprop融合规则基类 | ||
| 43 | * 用于适配InputV2和FilterV2的公共成员和方法 | ||
| 44 | */ | ||
| 45 | class __attribute__((visibility("default"))) ConvBackpropFusionBasePass : public ge::fusion::DecomposePass { | ||
| 46 | public: | ||
| 47 | explicit ConvBackpropFusionBasePass(const std::vector<ge::AscendString>& opTypes) : DecomposePass(opTypes) {} | ||
| 48 | |||
| 49 | protected: | ||
| 50 | |||
| 51 | virtual void InitMember(); | ||
| 52 | |||
| 53 | virtual bool CheckSocAndIntrinsic(); | ||
| 54 | |||
| 55 | bool MeetRequirements(const ge::GNode& convBpInputNode) override; | ||
| 56 | |||
| 57 | virtual bool GetNodeDesc(const ge::GNode& node); | ||
| 58 | |||
| 59 | virtual bool GetNodeAttrs(const ge::GNode& node); | ||
| 60 | |||
| 61 | virtual bool UpdateNodeInputDescInfo(ge::GNode *node); | ||
| 62 | |||
| 63 | virtual ge::AscendString GetNodeType() const = 0; | ||
| 64 | |||
| 65 | virtual bool CheckTransposeNeeded() = 0; | ||
| 66 | |||
| 67 | virtual ge::fusion::GraphUniqPtr Replacement(const ge::GNode& convBpInputNode) = 0; | ||
| 68 | |||
| 69 | protected: | ||
| 70 | NpuArch npuArch = NpuArch::DAV_RESV; | ||
| 71 | |||
| 72 | ge::TensorDesc input0Desc; | ||
| 73 | ge::TensorDesc input1Desc; | ||
| 74 | ge::TensorDesc input2Desc; | ||
| 75 | ge::TensorDesc outputDesc; | ||
| 76 | |||
| 77 | ConvBackpropAttrs convBpAttr; | ||
| 78 | }; | ||
| 79 | |||
| 80 | } // namespace ops | ||
| 81 | |||
| 82 | |||
| @@ -0,0 +1,111 @@ | |||
| 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 | namespace ops { | ||
| 15 | using namespace ge; | ||
| 16 | using namespace ge::es; | ||
| 17 | using namespace ConvBackpropFusionUtils; | ||
| 18 | |||
| 19 | std::vector<int64_t> ConvBackpropFusionUtilsPass::CalcTransposeShape( | ||
| 20 | const std::vector<int64_t>& inputShape, const std::vector<int32_t>& perm) | ||
| 21 | { | ||
| 22 | std::vector<int64_t> retShape; | ||
| 23 | for (size_t i = 0; i < perm.size() && i < inputShape.size(); ++i) { | ||
| 24 | if (perm[i] >= 0 && static_cast<size_t>(perm[i]) < inputShape.size()) { | ||
| 25 | retShape.push_back(inputShape[perm[i]]); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | return retShape; | ||
| 29 | } | ||
| 30 | |||
| 31 | void ConvBackpropFusionUtilsPass::SetPlaceholderDesc( | ||
| 32 | EsTensorHolder& tensorHolder, int64_t idx, const TensorDesc& desc) | ||
| 33 | { | ||
| 34 | auto* producer = tensorHolder.GetProducer(); | ||
| 35 | if (producer == nullptr) { | ||
| 36 | return; | ||
| 37 | } | ||
| 38 | producer->UpdateOutputDesc(static_cast<uint32_t>(idx), desc); | ||
| 39 | } | ||
| 40 | |||
| 41 | bool ConvBackpropFusionUtilsPass::InWhitelist( | ||
| 42 | const std::vector<int64_t>& shape, const std::vector<std::vector<int64_t>>& whitelist) | ||
| 43 | { | ||
| 44 | return std::find(whitelist.begin(), whitelist.end(), shape) != whitelist.end(); | ||
| 45 | } | ||
| 46 | |||
| 47 | bool ConvBackpropFusionUtilsPass::CheckSocAndIntrinsic( | ||
| 48 | const std::map<std::string, NpuArch>& supportSocList, NpuArch& npuArch) | ||
| 49 | { | ||
| 50 | fe::PlatformInfo platformInfo; | ||
| 51 | fe::OptionalInfo optionalInfo; | ||
| 52 | if (fe::PlatformInfoManager::Instance().GetPlatformInfoWithOutSocVersion(platformInfo, optionalInfo) != SUCCESS) { | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | const std::string soc = platformInfo.str_info.short_soc_version; | ||
| 56 | if (supportSocList.find(soc) == supportSocList.end()) { | ||
| 57 | return false; | ||
| 58 | } | ||
| 59 | npuArch = supportSocList.at(soc); | ||
| 60 | return true; | ||
| 61 | } | ||
| 62 | |||
| 63 | bool ConvBackpropFusionUtilsPass::CreateTransposeNode( | ||
| 64 | EsGraphBuilder& builder, const TransposeNodeConfig& config, | ||
| 65 | EsTensorHolder& output, TensorDesc& outDesc, const AscendString& opType) | ||
| 66 | { | ||
| 67 | auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 68 | OP_CHECK_IF(graph == nullptr, OP_LOGE(opType.GetString(), "create transpose node failed"), return false); | ||
| 69 | |||
| 70 | auto* producer = config.input.GetProducer(); | ||
| 71 | OP_CHECK_IF(producer == nullptr, OP_LOGE(opType.GetString(), "input producer is nullptr in CreateTransposeNode"), | ||
| 72 | return false); | ||
| 73 | |||
| 74 | TensorDesc inDesc; | ||
| 75 | producer->GetOutputDesc(config.input.GetProducerOutIndex(), inDesc); | ||
| 76 | auto transposeNode = ge::es::CompliantNodeBuilder(graph) | ||
| 77 | .OpType("Transpose") | ||
| 78 | .Name(config.name.c_str()) | ||
| 79 | .IrDefInputs( | ||
| 80 | {{"x", ge::es::CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 81 | {"perm", ge::es::CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 82 | .IrDefOutputs({{"y", ge::es::CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 83 | .Build(); | ||
| 84 | OP_CHECK_IF(ge::es::AddEdgeAndUpdatePeerDesc(*graph, *producer, TENSOR_DEFAULT_OUTPUT_INDEX, | ||
| 85 | transposeNode, TRANSPOSE_INPUT_X_INDEX) != GRAPH_SUCCESS, | ||
| 86 | OP_LOGE(opType.GetString(), "Add edge for transpose input failed"), return false); | ||
| 87 | transposeNode.UpdateInputDesc(TRANSPOSE_INPUT_X_INDEX, inDesc); | ||
| 88 | auto permTensorHolder = builder.CreateVector(config.perm); | ||
| 89 | auto* permTensorProducer = permTensorHolder.GetProducer(); | ||
| 90 | OP_CHECK_IF(permTensorProducer == nullptr, OP_LOGE(opType.GetString(), "perm producer is nullptr"), return false); | ||
| 91 | OP_CHECK_IF(ge::es::AddEdgeAndUpdatePeerDesc(*graph, *permTensorProducer, TENSOR_DEFAULT_OUTPUT_INDEX, | ||
| 92 | transposeNode, TRANSPOSE_INPUT_PERM_INDEX) != GRAPH_SUCCESS, | ||
| 93 | OP_LOGE(opType.GetString(), "Add edge for transpose perm failed"), return false); | ||
| 94 | |||
| 95 | TensorDesc permTensorDesc; | ||
| 96 | permTensorProducer->GetOutputDesc(TENSOR_DEFAULT_OUTPUT_INDEX, permTensorDesc); | ||
| 97 | transposeNode.UpdateInputDesc(TRANSPOSE_INPUT_PERM_INDEX, permTensorDesc); | ||
| 98 | outDesc.SetDataType(inDesc.GetDataType()); | ||
| 99 | auto outShape = CalcTransposeShape(inDesc.GetShape().GetDims(), config.perm); | ||
| 100 | outDesc.SetShape(Shape(outShape)); | ||
| 101 | outDesc.SetOriginShape(Shape(outShape)); | ||
| 102 | outDesc.SetFormat(config.format); | ||
| 103 | outDesc.SetOriginFormat(config.format); | ||
| 104 | transposeNode.UpdateOutputDesc(TRANSPOSE_OUTPUT_Y_INDEX, outDesc); | ||
| 105 | output = EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(transposeNode, TRANSPOSE_OUTPUT_Y_INDEX)); | ||
| 106 | |||
| 107 | return true; | ||
| 108 | } | ||
| 109 | |||
| 110 | } // namespace ops | ||
| 111 | |||
| @@ -0,0 +1,138 @@ | |||
| 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 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | namespace ops { | ||
| 28 | namespace ConvBackpropFusionUtils { | ||
| 29 | |||
| 30 | // Conv Backprop 公共常量定义 | ||
| 31 | constexpr int32_t CONV_DIM_LENGTH = 5; | ||
| 32 | constexpr int32_t OUTPUT_INDEX = 0; | ||
| 33 | constexpr int32_t OUT_BACKPROP_INDEX = 2; | ||
| 34 | constexpr int64_t HF32_PRECISION_MODE_INT = 0x40; | ||
| 35 | |||
| 36 | // Transpose 算子的输入输出索引常量 | ||
| 37 | constexpr int32_t TRANSPOSE_INPUT_X_INDEX = 0; // Transpose 第一个输入(x)的索引 | ||
| 38 | constexpr int32_t TRANSPOSE_INPUT_PERM_INDEX = 1; // Transpose 第二个输入(perm)的索引 | ||
| 39 | constexpr int32_t TRANSPOSE_OUTPUT_Y_INDEX = 0; // Transpose 第一个输出(y)的索引 | ||
| 40 | |||
| 41 | // Tensor 的默认输出索引常量 | ||
| 42 | constexpr int32_t TENSOR_DEFAULT_OUTPUT_INDEX = 0; // Tensor 的默认输出索引(大多数算子只有一个输出) | ||
| 43 | |||
| 44 | // ConvBackpropV2 算子的输入输出索引常量 | ||
| 45 | constexpr int32_t CONV_BP_V2_INPUT_INDEX = 0; // input_size 输入索引 | ||
| 46 | constexpr int32_t CONV_BP_V2_FILTER_INDEX = 1; // filter 输入索引 | ||
| 47 | constexpr int32_t CONV_BP_V2_OUT_BACKPROP_INDEX = 2; // out_backprop 输入索引 | ||
| 48 | constexpr int32_t CONV_BP_V2_OUTPUT_INDEX = 0; // output 输出索引 | ||
| 49 | |||
| 50 | // NDHWC格式的维度索引 | ||
| 51 | constexpr int64_t N_DIM_NDHWC_INDEX = 0; | ||
| 52 | constexpr int64_t D_DIM_NDHWC_INDEX = 1; | ||
| 53 | constexpr int64_t H_DIM_NDHWC_INDEX = 2; | ||
| 54 | constexpr int64_t W_DIM_NDHWC_INDEX = 3; | ||
| 55 | constexpr int64_t C_DIM_NDHWC_INDEX = 4; | ||
| 56 | |||
| 57 | // NCDHW格式的维度索引 | ||
| 58 | constexpr int64_t N_DIM_NCDHW_INDEX = 0; | ||
| 59 | constexpr int64_t C_DIM_NCDHW_INDEX = 1; | ||
| 60 | constexpr int64_t D_DIM_NCDHW_INDEX = 2; | ||
| 61 | constexpr int64_t H_DIM_NCDHW_INDEX = 3; | ||
| 62 | constexpr int64_t W_DIM_NCDHW_INDEX = 4; | ||
| 63 | |||
| 64 | // DHWCN格式的维度索引 | ||
| 65 | constexpr int64_t D_DIM_DHWCN_INDEX = 0; | ||
| 66 | constexpr int64_t H_DIM_DHWCN_INDEX = 1; | ||
| 67 | constexpr int64_t W_DIM_DHWCN_INDEX = 2; | ||
| 68 | constexpr int64_t C_DIM_DHWCN_INDEX = 3; | ||
| 69 | constexpr int64_t N_DIM_DHWCN_INDEX = 4; | ||
| 70 | |||
| 71 | // 支持的SOC列表 | ||
| 72 | const std::map<std::string, NpuArch> SUPPORT_SOC_LIST = { | ||
| 73 | {"Ascend950", NpuArch::DAV_3510} | ||
| 74 | }; | ||
| 75 | |||
| 76 | // Transpose排列常量 | ||
| 77 | const std::vector<int32_t> FILTER_TRANSPOSE_PERM = {4, 3, 0, 1, 2}; // DHWCN -> NCDHW | ||
| 78 | const std::vector<int32_t> DEDY_TRANSPOSE_PERM = {0, 4, 1, 2, 3}; // NDHWC -> NCDHW | ||
| 79 | const std::vector<int32_t> OUTPUT_TRANSPOSE_PERM = {0, 2, 3, 4, 1}; // NCDHW -> NDHWC | ||
| 80 | |||
| 81 | |||
| 82 | // Transpose 节点配置结构体 | ||
| 83 | struct TransposeNodeConfig { | ||
| 84 | ge::es::EsTensorHolder input; // 输入张量 | ||
| 85 | std::vector<int32_t> perm; // 转置排列 | ||
| 86 | std::string name; // 节点名称 | ||
| 87 | ge::Format format; // 输出格式 | ||
| 88 | |||
| 89 | static TransposeNodeConfig Create( | ||
| 90 | const ge::es::EsTensorHolder& inputTensor, | ||
| 91 | const std::vector<int32_t>& permutation, | ||
| 92 | const std::string& nodeName, | ||
| 93 | ge::Format outputFormat) { | ||
| 94 | TransposeNodeConfig config; | ||
| 95 | config.input = inputTensor; | ||
| 96 | config.perm = permutation; | ||
| 97 | config.name = nodeName; | ||
| 98 | config.format = outputFormat; | ||
| 99 | return config; | ||
| 100 | } | ||
| 101 | }; | ||
| 102 | |||
| 103 | class ConvBackpropFusionUtilsPass { | ||
| 104 | public: | ||
| 105 | |||
| 106 | static std::vector<int64_t> CalcTransposeShape( | ||
| 107 | const std::vector<int64_t>& inputShape, | ||
| 108 | const std::vector<int32_t>& perm); | ||
| 109 | |||
| 110 | static void SetPlaceholderDesc( | ||
| 111 | ge::es::EsTensorHolder& tensorHolder, | ||
| 112 | int64_t idx, | ||
| 113 | const ge::TensorDesc& desc); | ||
| 114 | |||
| 115 | static bool InWhitelist( | ||
| 116 | const std::vector<int64_t>& shape, | ||
| 117 | const std::vector<std::vector<int64_t>>& whitelist); | ||
| 118 | |||
| 119 | static bool CheckSocAndIntrinsic( | ||
| 120 | const std::map<std::string, NpuArch>& supportSocList, | ||
| 121 | NpuArch& npuArch); | ||
| 122 | |||
| 123 | static bool IsSupportedDtype( | ||
| 124 | ge::DataType dtype, | ||
| 125 | const std::set<ge::DataType>& supportedDtypes); | ||
| 126 | |||
| 127 | static bool CreateTransposeNode( | ||
| 128 | ge::es::EsGraphBuilder& builder, | ||
| 129 | const TransposeNodeConfig& config, | ||
| 130 | ge::es::EsTensorHolder& output, | ||
| 131 | ge::TensorDesc& outDesc, | ||
| 132 | const ge::AscendString& opType); | ||
| 133 | }; | ||
| 134 | |||
| 135 | } // namespace ConvBackpropFusionUtils | ||
| 136 | } // namespace ops | ||
| 137 | |||
| 138 | |||
Dconv/conv3d_backprop_filter_v2/op_graph/fusion_pass/.gitkeep+0-0
The file is empty
Aconv/conv3d_backprop_filter_v2/op_graph/fusion_pass/conv3d_backprop_filter_to_v2_fusion_pass.cpp+166-0
| @@ -0,0 +1,166 @@ | |||
| 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 | namespace ops { | ||
| 18 | using namespace ge; | ||
| 19 | using namespace ge::es; | ||
| 20 | using namespace fusion; | ||
| 21 | using namespace ConvBackpropFusionUtils; | ||
| 22 | |||
| 23 | // FilterV2特有的常量 | ||
| 24 | constexpr int64_t CONDICTION_DIVIDE_K = 16 * 32 * 32; | ||
| 25 | const std::vector<int32_t> TRANSPOSE_PERM_NDHWC = {0, 2, 3, 4, 1}; // NCDHW -> NDHWC | ||
| 26 | const std::vector<int32_t> TRANSPOSE_PERM_DHWCN = {2, 3, 4, 1, 0}; // NCDHW -> DHWCN | ||
| 27 | |||
| 28 | AscendString Conv3DBackpropFilterToV2FusionPass::GetNodeType() const | ||
| 29 | { | ||
| 30 | return CONV_BACKPROP_FILTER_V2_PASS; | ||
| 31 | } | ||
| 32 | |||
| 33 | bool Conv3DBackpropFilterToV2FusionPass::CheckTransposeNeeded() | ||
| 34 | { | ||
| 35 | auto outputOriginFormat = outputDesc.GetOriginFormat(); | ||
| 36 | if (outputOriginFormat == Format::FORMAT_NCDHW) { | ||
| 37 | OP_LOGD(GetNodeType().GetString(), "y format is NCDHW, need not insert transpose node."); | ||
| 38 | return false; | ||
| 39 | } | ||
| 40 | |||
| 41 | bool isDynamic = input0Desc.GetShape().GetShapeSize() == -1 || | ||
| 42 | input2Desc.GetShape().GetShapeSize() == -1 || | ||
| 43 | outputDesc.GetShape().GetShapeSize() == -1; | ||
| 44 | if (isDynamic) { | ||
| 45 | OP_LOGD(GetNodeType().GetString(), "all shape must be specify."); | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | auto yShapeVec = outputDesc.GetShape().GetDims(); | ||
| 50 | OP_CHECK_IF(yShapeVec.size() != CONV_DIM_LENGTH, | ||
| 51 | OP_LOGE(GetNodeType().GetString(), "y shape size %zu != %d", yShapeVec.size(), CONV_DIM_LENGTH), | ||
| 52 | return false); | ||
| 53 | |||
| 54 | int64_t cin = 0, cout = 0, di = 0; | ||
| 55 | if (outputOriginFormat == Format::FORMAT_NDHWC) { | ||
| 56 | cin = yShapeVec[C_DIM_NDHWC_INDEX]; | ||
| 57 | cout = yShapeVec[N_DIM_NDHWC_INDEX]; | ||
| 58 | auto xShapeVec = input0Desc.GetShape().GetDims(); | ||
| 59 | OP_CHECK_IF(xShapeVec.size() != CONV_DIM_LENGTH, | ||
| 60 | OP_LOGE(GetNodeType().GetString(), "x shape size %zu != %d for NDHWC format", | ||
| 61 | xShapeVec.size(), CONV_DIM_LENGTH), return false); | ||
| 62 | di = xShapeVec[D_DIM_NDHWC_INDEX]; | ||
| 63 | } else { | ||
| 64 | cin = yShapeVec[C_DIM_DHWCN_INDEX]; | ||
| 65 | cout = yShapeVec[N_DIM_DHWCN_INDEX]; | ||
| 66 | auto xShapeVec = input0Desc.GetShape().GetDims(); | ||
| 67 | OP_CHECK_IF(xShapeVec.size() != CONV_DIM_LENGTH, | ||
| 68 | OP_LOGE(GetNodeType().GetString(), "x shape size %zu != %d for DHWCN format", | ||
| 69 | xShapeVec.size(), CONV_DIM_LENGTH), return false); | ||
| 70 | di = xShapeVec[D_DIM_NCDHW_INDEX]; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (di * cin * cout >= CONDICTION_DIVIDE_K) { | ||
| 74 | OP_LOGD(GetNodeType().GetString(), "need satisfy divide K condition."); | ||
| 75 | return false; | ||
| 76 | } | ||
| 77 | |||
| 78 | OP_LOGD(GetNodeType().GetString(), "Transpose needed"); | ||
| 79 | return true; | ||
| 80 | } | ||
| 81 | |||
| 82 | bool Conv3DBackpropFilterToV2FusionPass::CreateOutputWithTranspose( | ||
| 83 | EsGraphBuilder& builder, | ||
| 84 | const EsTensorHolder& conv3dBackpropFilterV2, | ||
| 85 | GNode* conv3dBackpropFilterV2Node, | ||
| 86 | EsTensorHolder& transOutput) | ||
| 87 | { | ||
| 88 | TensorDesc ncdhwDesc; | ||
| 89 | ncdhwDesc.SetDataType(outputDesc.GetDataType()); | ||
| 90 | auto yShapeVec = outputDesc.GetShape().GetDims(); | ||
| 91 | std::vector<int64_t> yShapeNcdhw; | ||
| 92 | auto outputOriginFormat = outputDesc.GetOriginFormat(); | ||
| 93 | if (outputOriginFormat == Format::FORMAT_NDHWC) { | ||
| 94 | yShapeNcdhw = { | ||
| 95 | yShapeVec[N_DIM_NDHWC_INDEX], yShapeVec[C_DIM_NDHWC_INDEX], | ||
| 96 | yShapeVec[D_DIM_NDHWC_INDEX], yShapeVec[H_DIM_NDHWC_INDEX], yShapeVec[W_DIM_NDHWC_INDEX] | ||
| 97 | }; | ||
| 98 | } else { | ||
| 99 | yShapeNcdhw = { | ||
| 100 | yShapeVec[N_DIM_DHWCN_INDEX], yShapeVec[C_DIM_DHWCN_INDEX], | ||
| 101 | yShapeVec[D_DIM_DHWCN_INDEX], yShapeVec[H_DIM_DHWCN_INDEX], yShapeVec[W_DIM_DHWCN_INDEX] | ||
| 102 | }; | ||
| 103 | } | ||
| 104 | |||
| 105 | ncdhwDesc.SetShape(Shape(yShapeNcdhw)); | ||
| 106 | ncdhwDesc.SetOriginShape(Shape(yShapeNcdhw)); | ||
| 107 | ncdhwDesc.SetFormat(Format::FORMAT_NCDHW); | ||
| 108 | ncdhwDesc.SetOriginFormat(Format::FORMAT_NCDHW); | ||
| 109 | conv3dBackpropFilterV2Node->UpdateOutputDesc(OUTPUT_INDEX, ncdhwDesc); | ||
| 110 | |||
| 111 | std::vector<int32_t> transposePerm = TRANSPOSE_PERM_DHWCN; | ||
| 112 | if (outputOriginFormat == Format::FORMAT_NDHWC) { | ||
| 113 | transposePerm = TRANSPOSE_PERM_NDHWC; | ||
| 114 | } | ||
| 115 | |||
| 116 | auto config = TransposeNodeConfig::Create( | ||
| 117 | conv3dBackpropFilterV2, transposePerm, "y_transpose", outputOriginFormat); | ||
| 118 | |||
| 119 | TensorDesc transOutDesc; | ||
| 120 | OP_CHECK_IF(!ConvBackpropFusionUtilsPass::CreateTransposeNode( | ||
| 121 | builder, config, transOutput, transOutDesc, GetNodeType()), | ||
| 122 | OP_LOGE(GetNodeType().GetString(), "Create y transpose node failed"), return false); | ||
| 123 | |||
| 124 | return true; | ||
| 125 | } | ||
| 126 | |||
| 127 | GraphUniqPtr Conv3DBackpropFilterToV2FusionPass::Replacement(const GNode& convBpFilterNode) | ||
| 128 | { | ||
| 129 | OP_LOGD(GetNodeType().GetString(), "Replacement start"); | ||
| 130 | |||
| 131 | OP_CHECK_IF(!GetNodeDesc(convBpFilterNode), | ||
| 132 | OP_LOGE(GetNodeType().GetString(), "GetNodeDesc failed"), return nullptr); | ||
| 133 | OP_CHECK_IF(!GetNodeAttrs(convBpFilterNode), | ||
| 134 | OP_LOGE(GetNodeType().GetString(), "GetNodeAttrs failed"), return nullptr); | ||
| 135 | |||
| 136 | auto builder = EsGraphBuilder("replacement"); | ||
| 137 | auto [x, filterSize, outBackprop] = builder.CreateInputs<3>(); | ||
| 138 | |||
| 139 | auto conv3dBackpropFilterV2 = Conv3DBackpropFilterV2( | ||
| 140 | x, filterSize, outBackprop, convBpAttr.strides, convBpAttr.pads, | ||
| 141 | convBpAttr.dilations, convBpAttr.groups, | ||
| 142 | convBpAttr.dataFormat.c_str(), convBpAttr.hf32); | ||
| 143 | |||
| 144 | auto* conv3dBackpropFilterV2Node = conv3dBackpropFilterV2.GetProducer(); | ||
| 145 | OP_CHECK_IF(conv3dBackpropFilterV2Node == nullptr, | ||
| 146 | OP_LOGE(GetNodeType().GetString(), "Create Conv3DBackpropFilterV2 node failed"), return nullptr); | ||
| 147 | |||
| 148 | conv3dBackpropFilterV2Node->SetAttr("_op_impl_mode_enum", convBpAttr.opImplModeEnum); | ||
| 149 | OP_CHECK_IF(!UpdateNodeInputDescInfo(conv3dBackpropFilterV2Node), | ||
| 150 | OP_LOGE(GetNodeType().GetString(), "Update conv3dBackpropFilterV2Node DescInfo failed"), | ||
| 151 | return nullptr); | ||
| 152 | |||
| 153 | EsTensorHolder finalY = conv3dBackpropFilterV2; | ||
| 154 | bool needTranspose = CheckTransposeNeeded(); | ||
| 155 | if (needTranspose) { | ||
| 156 | OP_CHECK_IF(!CreateOutputWithTranspose(builder, conv3dBackpropFilterV2, conv3dBackpropFilterV2Node, finalY), | ||
| 157 | OP_LOGE(GetNodeType().GetString(), "Create y with transpose failed"), return nullptr); | ||
| 158 | } | ||
| 159 | |||
| 160 | return builder.BuildAndReset(std::vector<EsTensorHolder>{finalY}); | ||
| 161 | } | ||
| 162 | |||
| 163 | REG_DECOMPOSE_PASS(Conv3DBackpropFilterToV2FusionPass, {CONV_BACKPROP_FILTER}) | ||
| 164 | .Stage(CustomPassStage::kCompatibleInherited); | ||
| 165 | |||
| 166 | } // namespace ops | ||
Aconv/conv3d_backprop_filter_v2/op_graph/fusion_pass/conv3d_backprop_filter_to_v2_fusion_pass.h+41-0
| @@ -0,0 +1,41 @@ | |||
| 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 | const ge::AscendString CONV_BACKPROP_FILTER = "Conv3DBackpropFilter"; | ||
| 19 | const ge::AscendString CONV_BACKPROP_FILTER_V2_PASS = "Conv3DBackpropFilterToV2FusionPass"; | ||
| 20 | |||
| 21 | class __attribute__((visibility("default"))) Conv3DBackpropFilterToV2FusionPass : public ConvBackpropFusionBasePass { | ||
| 22 | public: | ||
| 23 | explicit Conv3DBackpropFilterToV2FusionPass(const std::vector<ge::AscendString>& opTypes) | ||
| 24 | : ConvBackpropFusionBasePass(opTypes) {} | ||
| 25 | |||
| 26 | protected: | ||
| 27 | ge::AscendString GetNodeType() const override; | ||
| 28 | bool CheckTransposeNeeded() override; | ||
| 29 | ge::fusion::GraphUniqPtr Replacement(const ge::GNode& convBpFilterNode) override; | ||
| 30 | |||
| 31 | private: | ||
| 32 | bool CreateOutputWithTranspose( | ||
| 33 | ge::es::EsGraphBuilder& builder, | ||
| 34 | const ge::es::EsTensorHolder& conv3dBackpropFilterV2, | ||
| 35 | ge::GNode* conv3dBackpropFilterV2Node, | ||
| 36 | ge::es::EsTensorHolder& transOutput); | ||
| 37 | }; | ||
| 38 | |||
| 39 | } // namespace ops | ||
| 40 | |||
| 41 | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # ---------------------------------------------------------------------------- | ||
| 2 | # Copyright (c) 2025 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 OR 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 | file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | if(UT_TEST_ALL OR OP_GRAPH_UT) | ||
| 13 | add_modules_ut_sources(HOSTNAME ${OP_GRAPH_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | endif() | ||
Aconv/conv3d_backprop_filter_v2/tests/ut/op_graph/test_conv3d_backprop_filter_to_v2_fusion_pass.cpp+276-0
| @@ -0,0 +1,276 @@ | |||
| 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 fe; | ||
| 24 | using namespace fusion; | ||
| 25 | using namespace ops::ConvBackpropFusionUtils; | ||
| 26 | |||
| 27 | namespace { | ||
| 28 | |||
| 29 | void SetPlatform(const std::string& soc) | ||
| 30 | { | ||
| 31 | PlatformInfo platformInfo; | ||
| 32 | OptionalInfo optionalInfo; | ||
| 33 | platformInfo.soc_info.ai_core_cnt = 64; | ||
| 34 | platformInfo.str_info.short_soc_version = soc; | ||
| 35 | optionalInfo.soc_version = soc; | ||
| 36 | if (soc == "Ascend950" || soc == "MC62CM12A") { | ||
| 37 | platformInfo.ai_core_intrinsic_dtype_map["Intrinsic_data_move_out2l1_dn2nz"] = {"float16", "float", "bfloat16"}; | ||
| 38 | } | ||
| 39 | PlatformInfoManager::Instance().platform_info_map_[soc] = platformInfo; | ||
| 40 | PlatformInfoManager::Instance().SetOptionalCompilationInfo(optionalInfo); | ||
| 41 | } | ||
| 42 | |||
| 43 | es::EsTensorHolder CreateConv3dBpFilterNode( | ||
| 44 | es::EsGraphBuilder& builder, const char* opType, const es::EsTensorHolder& x, const es::EsTensorHolder& filterSize, | ||
| 45 | const es::EsTensorHolder& outBackprop, std::vector<int64_t> strides, std::vector<int64_t> pads, | ||
| 46 | std::vector<int64_t> dilations, int64_t groups, const std::string& dataFormat, DataType outDtype, | ||
| 47 | const std::vector<int64_t>& outShape, Format outFormat) | ||
| 48 | { | ||
| 49 | auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 50 | auto node = es::CompliantNodeBuilder(graph) | ||
| 51 | .OpType(opType) | ||
| 52 | .Name(opType) | ||
| 53 | .IrDefInputs( | ||
| 54 | {{"x", es::CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 55 | {"filter_size", es::CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 56 | {"out_backprop", es::CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 57 | .IrDefOutputs({{"y", es::CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 58 | .InstanceOutputDataType("y", outDtype) | ||
| 59 | .InstanceOutputShape("y", outShape) | ||
| 60 | .InstanceOutputFormat("y", outFormat) | ||
| 61 | .Build(); | ||
| 62 | |||
| 63 | es::AddEdgeAndUpdatePeerDesc(*graph, *x.GetProducer(), x.GetProducerOutIndex(), node, 0); | ||
| 64 | es::AddEdgeAndUpdatePeerDesc(*graph, *filterSize.GetProducer(), filterSize.GetProducerOutIndex(), node, 1); | ||
| 65 | es::AddEdgeAndUpdatePeerDesc(*graph, *outBackprop.GetProducer(), outBackprop.GetProducerOutIndex(), node, 2); | ||
| 66 | |||
| 67 | TensorDesc xDesc, filterSizeDesc, outBackpropDesc; | ||
| 68 | x.GetProducer()->GetOutputDesc(x.GetProducerOutIndex(), xDesc); | ||
| 69 | filterSize.GetProducer()->GetOutputDesc(filterSize.GetProducerOutIndex(), filterSizeDesc); | ||
| 70 | outBackprop.GetProducer()->GetOutputDesc(outBackprop.GetProducerOutIndex(), outBackpropDesc); | ||
| 71 | node.UpdateInputDesc(0, xDesc); | ||
| 72 | node.UpdateInputDesc(1, filterSizeDesc); | ||
| 73 | node.UpdateInputDesc(2, outBackpropDesc); | ||
| 74 | |||
| 75 | node.SetAttr("strides", strides); | ||
| 76 | node.SetAttr("pads", pads); | ||
| 77 | node.SetAttr("dilations", dilations); | ||
| 78 | node.SetAttr("groups", groups); | ||
| 79 | AscendString fmt = dataFormat.c_str(); | ||
| 80 | node.SetAttr("data_format", fmt); | ||
| 81 | int64_t implMode = 0x1; | ||
| 82 | node.SetAttr("_op_impl_mode_enum", implMode); | ||
| 83 | |||
| 84 | return es::EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(node, 0)); | ||
| 85 | } | ||
| 86 | |||
| 87 | bool CheckNodeExists(GraphPtr& graph, const std::string& type) | ||
| 88 | { | ||
| 89 | for (auto node : graph->GetAllNodes()) { | ||
| 90 | AscendString nodeType; | ||
| 91 | node.GetType(nodeType); | ||
| 92 | if (nodeType.GetString() == type) | ||
| 93 | return true; | ||
| 94 | } | ||
| 95 | return false; | ||
| 96 | } | ||
| 97 | |||
| 98 | } // namespace | ||
| 99 | |||
| 100 | class Conv3dBpFilterToV2FusionPassTest : public testing::Test { | ||
| 101 | protected: | ||
| 102 | void SetUp() override { SetPlatform("Ascend950"); } | ||
| 103 | }; | ||
| 104 | |||
| 105 | // Test 1: patternTest - FP16 basic fusion success (需要 Transpose) | ||
| 106 | TEST_F(Conv3dBpFilterToV2FusionPassTest, patternTest) | ||
| 107 | { | ||
| 108 | auto builder = es::EsGraphBuilder("patternTest"); | ||
| 109 | auto x = builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCDHW, {2, 32, 16, 16, 16}); | ||
| 110 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 111 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {2, 1, 8, 8, 64}); | ||
| 112 | |||
| 113 | auto y = CreateConv3dBpFilterNode( | ||
| 114 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 115 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT16, {2, 1, 4, 4, 32}, FORMAT_NDHWC); | ||
| 116 | |||
| 117 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 118 | CustomPassContext ctx; | ||
| 119 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 120 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 121 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 122 | } | ||
| 123 | |||
| 124 | // Test 2: unsupportedPlatformFail - Ascend910_93 不支持 | ||
| 125 | TEST_F(Conv3dBpFilterToV2FusionPassTest, unsupportedPlatformFail) | ||
| 126 | { | ||
| 127 | SetPlatform("Ascend910_93"); | ||
| 128 | auto builder = es::EsGraphBuilder("unsupportedPlatformFail"); | ||
| 129 | auto x = builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCDHW, {2, 32, 16, 16, 16}); | ||
| 130 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 131 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {2, 1, 8, 8, 64}); | ||
| 132 | |||
| 133 | auto y = CreateConv3dBpFilterNode( | ||
| 134 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 135 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT16, {2, 1, 4, 4, 32}, FORMAT_NDHWC); | ||
| 136 | |||
| 137 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 138 | CustomPassContext ctx; | ||
| 139 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 140 | EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 141 | EXPECT_FALSE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 142 | } | ||
| 143 | |||
| 144 | // Test 4: bf16FusionSuccess - BF16 融合成功 | ||
| 145 | TEST_F(Conv3dBpFilterToV2FusionPassTest, bf16FusionSuccess) | ||
| 146 | { | ||
| 147 | auto builder = es::EsGraphBuilder("bf16FusionSuccess"); | ||
| 148 | auto x = builder.CreateInput(0, "x", DT_BF16, FORMAT_NCDHW, {2, 32, 16, 16, 16}); | ||
| 149 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 150 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_BF16, FORMAT_NDHWC, {2, 1, 8, 8, 64}); | ||
| 151 | |||
| 152 | auto y = CreateConv3dBpFilterNode( | ||
| 153 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 154 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_BF16, {2, 1, 4, 4, 32}, FORMAT_NDHWC); | ||
| 155 | |||
| 156 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 157 | CustomPassContext ctx; | ||
| 158 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 159 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 160 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 161 | } | ||
| 162 | |||
| 163 | // Test 5: fp32FusionSuccess - FP32 融合成功 | ||
| 164 | TEST_F(Conv3dBpFilterToV2FusionPassTest, fp32FusionSuccess) | ||
| 165 | { | ||
| 166 | auto builder = es::EsGraphBuilder("fp32FusionSuccess"); | ||
| 167 | auto x = builder.CreateInput(0, "x", DT_FLOAT, FORMAT_NCDHW, {2, 32, 16, 16, 16}); | ||
| 168 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 169 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT, FORMAT_NDHWC, {2, 1, 8, 8, 64}); | ||
| 170 | |||
| 171 | auto y = CreateConv3dBpFilterNode( | ||
| 172 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 173 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT, {2, 1, 4, 4, 32}, FORMAT_NDHWC); | ||
| 174 | |||
| 175 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 176 | CustomPassContext ctx; | ||
| 177 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 178 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 179 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 180 | } | ||
| 181 | |||
| 182 | // Test 6: mc62cm12APlatformFail - MC62CM12A 平台不支持 | ||
| 183 | TEST_F(Conv3dBpFilterToV2FusionPassTest, mc62cm12APlatformFail) | ||
| 184 | { | ||
| 185 | SetPlatform("MC62CM12A"); | ||
| 186 | auto builder = es::EsGraphBuilder("mc62cm12APlatformFail"); | ||
| 187 | auto x = builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCDHW, {2, 32, 16, 16, 16}); | ||
| 188 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 189 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {2, 1, 8, 8, 64}); | ||
| 190 | |||
| 191 | auto y = CreateConv3dBpFilterNode( | ||
| 192 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 193 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT16, {2, 1, 4, 4, 32}, FORMAT_NDHWC); | ||
| 194 | |||
| 195 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 196 | CustomPassContext ctx; | ||
| 197 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 198 | EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 199 | EXPECT_FALSE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 200 | } | ||
| 201 | |||
| 202 | // Test 7: differentShapeSmallBatch - 不同 shape(小 batch) | ||
| 203 | TEST_F(Conv3dBpFilterToV2FusionPassTest, differentShapeSmallBatch) | ||
| 204 | { | ||
| 205 | auto builder = es::EsGraphBuilder("differentShapeSmallBatch"); | ||
| 206 | auto x = builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCDHW, {1, 16, 8, 8, 8}); | ||
| 207 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 208 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {1, 1, 4, 4, 32}); | ||
| 209 | |||
| 210 | auto y = CreateConv3dBpFilterNode( | ||
| 211 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 212 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT16, {1, 1, 2, 2, 16}, FORMAT_NDHWC); | ||
| 213 | |||
| 214 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 215 | CustomPassContext ctx; | ||
| 216 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 217 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 218 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 219 | } | ||
| 220 | |||
| 221 | // Test 8: noTransposeCase - output 格式是 NCDHW,不需要 Transpose 但仍融合成功 | ||
| 222 | TEST_F(Conv3dBpFilterToV2FusionPassTest, noTransposeCase) | ||
| 223 | { | ||
| 224 | auto builder = es::EsGraphBuilder("noTransposeCase"); | ||
| 225 | auto x = builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCDHW, {2, 32, 16, 16, 16}); | ||
| 226 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 227 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {2, 1, 8, 8, 64}); | ||
| 228 | |||
| 229 | auto y = CreateConv3dBpFilterNode( | ||
| 230 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 231 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT16, {2, 32, 1, 4, 4}, FORMAT_NCDHW); | ||
| 232 | |||
| 233 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 234 | CustomPassContext ctx; | ||
| 235 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 236 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 237 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 238 | } | ||
| 239 | |||
| 240 | // Test 9: dhwcFormatCase - DHWCN 格式输出,需要 Transpose | ||
| 241 | TEST_F(Conv3dBpFilterToV2FusionPassTest, dhwcFormatCase) | ||
| 242 | { | ||
| 243 | auto builder = es::EsGraphBuilder("dhwcFormatCase"); | ||
| 244 | auto x = builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCDHW, {2, 32, 16, 16, 16}); | ||
| 245 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 246 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {2, 1, 8, 8, 64}); | ||
| 247 | |||
| 248 | auto y = CreateConv3dBpFilterNode( | ||
| 249 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 250 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT16, {1, 4, 4, 32, 2}, FORMAT_DHWCN); | ||
| 251 | |||
| 252 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 253 | CustomPassContext ctx; | ||
| 254 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 255 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 256 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 257 | } | ||
| 258 | |||
| 259 | // Test 10: largeDivideKCase - 大 divide K,不需要 Transpose 但仍融合成功 | ||
| 260 | TEST_F(Conv3dBpFilterToV2FusionPassTest, largeDivideKCase) | ||
| 261 | { | ||
| 262 | auto builder = es::EsGraphBuilder("largeDivideKCase"); | ||
| 263 | auto x = builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCDHW, {2, 256, 32, 32, 32}); | ||
| 264 | auto filterSize = builder.CreateInput(1, "filter_size", DT_INT64, FORMAT_ND, {5}); | ||
| 265 | auto outBackprop = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {2, 1, 16, 16, 512}); | ||
| 266 | |||
| 267 | auto y = CreateConv3dBpFilterNode( | ||
| 268 | builder, "Conv3DBackpropFilter", x, filterSize, outBackprop, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, | ||
| 269 | {1, 1, 1, 1, 1}, 1, "NCDHW", DT_FLOAT16, {2, 1, 8, 8, 256}, FORMAT_NDHWC); | ||
| 270 | |||
| 271 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 272 | CustomPassContext ctx; | ||
| 273 | ops::Conv3DBackpropFilterToV2FusionPass pass({AscendString("Conv3DBackpropFilter")}); | ||
| 274 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 275 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropFilterV2")); | ||
| 276 | } | ||
Dconv/conv3d_backprop_input_v2/op_graph/fusion_pass/.gitkeep+0-0
The file is empty
Aconv/conv3d_backprop_input_v2/op_graph/fusion_pass/conv3d_backprop_input_to_v2_fusion_pass.cpp+189-0
| @@ -0,0 +1,189 @@ | |||
| 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 | namespace ops { | ||
| 18 | using namespace ge; | ||
| 19 | using namespace ge::es; | ||
| 20 | using namespace fusion; | ||
| 21 | using namespace ConvBackpropFusionUtils; | ||
| 22 | |||
| 23 | AscendString Conv3DBackpropInputToV2FusionPass::GetNodeType() const { return CONV_BACKPROP_INPUT_V2_PASS; } | ||
| 24 | |||
| 25 | bool Conv3DBackpropInputToV2FusionPass::CheckTransposeNeeded() | ||
| 26 | { | ||
| 27 | if (input1Desc.GetOriginFormat() != FORMAT_DHWCN) { | ||
| 28 | OP_LOGD(GetNodeType().GetString(), "Transpose not needed: filter format is not DHWCN"); | ||
| 29 | return false; | ||
| 30 | } | ||
| 31 | |||
| 32 | if (input2Desc.GetOriginFormat() != FORMAT_NDHWC) { | ||
| 33 | OP_LOGD(GetNodeType().GetString(), "Transpose not needed: out_backprop format is not NDHWC"); | ||
| 34 | return false; | ||
| 35 | } | ||
| 36 | |||
| 37 | bool isDynamic = input1Desc.GetShape().GetShapeSize() == -1 || input2Desc.GetShape().GetShapeSize() == -1 || | ||
| 38 | outputDesc.GetShape().GetShapeSize() == -1; | ||
| 39 | if (isDynamic) { | ||
| 40 | OP_LOGD(GetNodeType().GetString(), "Transpose not needed: dynamic shape detected"); | ||
| 41 | return false; | ||
| 42 | } | ||
| 43 | |||
| 44 | auto outShape = outputDesc.GetShape().GetDims(); | ||
| 45 | auto fltShape = input1Desc.GetShape().GetDims(); | ||
| 46 | if (outShape.size() != CONV_DIM_LENGTH || fltShape.size() != CONV_DIM_LENGTH) { | ||
| 47 | OP_LOGD(GetNodeType().GetString(), "Transpose not needed: filter or y shape dim != 5"); | ||
| 48 | return false; | ||
| 49 | } | ||
| 50 | |||
| 51 | if (!ConvBackpropFusionUtilsPass::InWhitelist(outShape, outputShapeWhitelist) || | ||
| 52 | !ConvBackpropFusionUtilsPass::InWhitelist(fltShape, filterShapeWhitelist) || | ||
| 53 | !ConvBackpropFusionUtilsPass::InWhitelist(input2Desc.GetShape().GetDims(), dedyShapeWhitelist)) { | ||
| 54 | OP_LOGD(GetNodeType().GetString(), "Transpose not needed: shape not in whitelist"); | ||
| 55 | return false; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (convBpAttr.strides.size() != CONV_DIM_LENGTH || | ||
| 59 | convBpAttr.dilations.size() != CONV_DIM_LENGTH || convBpAttr.groups != 1) { | ||
| 60 | OP_LOGD(GetNodeType().GetString(), "Transpose not needed: attr check failed or groups != 1"); | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | |||
| 64 | if (convBpAttr.strides[H_DIM_NDHWC_INDEX] != 2 || convBpAttr.strides[W_DIM_NDHWC_INDEX] != 2 || | ||
| 65 | convBpAttr.dilations[H_DIM_NDHWC_INDEX] != 1 || convBpAttr.dilations[W_DIM_NDHWC_INDEX] != 1) { | ||
| 66 | OP_LOGD(GetNodeType().GetString(), "Transpose not needed: strides or dilations constraint not met"); | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | |||
| 70 | OP_LOGD(GetNodeType().GetString(), "Transpose needed"); | ||
| 71 | return true; | ||
| 72 | } | ||
| 73 | |||
| 74 | bool Conv3DBackpropInputToV2FusionPass::CreateOutputWithTranspose( | ||
| 75 | EsGraphBuilder& builder, const EsTensorHolder& conv3dBpInputV2, GNode* conv3dBpInputV2Node, | ||
| 76 | EsTensorHolder& transOutput) | ||
| 77 | { | ||
| 78 | TensorDesc outNcdhwDesc; | ||
| 79 | outNcdhwDesc.SetDataType(outputDesc.GetDataType()); | ||
| 80 | auto ndhwc = outputDesc.GetShape().GetDims(); | ||
| 81 | auto ncdhw ={ndhwc[N_DIM_NDHWC_INDEX], ndhwc[C_DIM_NDHWC_INDEX],ndhwc[D_DIM_NDHWC_INDEX], ndhwc[H_DIM_NDHWC_INDEX], ndhwc[W_DIM_NDHWC_INDEX]}; | ||
| 82 | outNcdhwDesc.SetShape(Shape(ncdhw)); | ||
| 83 | outNcdhwDesc.SetOriginShape(Shape(ncdhw)); | ||
| 84 | outNcdhwDesc.SetFormat(Format::FORMAT_NCDHW); | ||
| 85 | outNcdhwDesc.SetOriginFormat(Format::FORMAT_NCDHW); | ||
| 86 | conv3dBpInputV2Node->UpdateOutputDesc(OUTPUT_INDEX, outNcdhwDesc); | ||
| 87 | |||
| 88 | auto config = TransposeNodeConfig::Create( | ||
| 89 | conv3dBpInputV2, OUTPUT_TRANSPOSE_PERM, "y_transpose", outputDesc.GetFormat()); | ||
| 90 | |||
| 91 | TensorDesc transOutDesc; | ||
| 92 | OP_CHECK_IF(!ConvBackpropFusionUtilsPass::CreateTransposeNode( | ||
| 93 | builder, config, transOutput, transOutDesc, GetNodeType()), | ||
| 94 | OP_LOGE(GetNodeType().GetString(), "Create y transpose node failed"), return false); | ||
| 95 | return true; | ||
| 96 | } | ||
| 97 | |||
| 98 | bool Conv3DBackpropInputToV2FusionPass::Createconv3dBpInputTransposeGraph( | ||
| 99 | EsGraphBuilder& builder, EsTensorHolder& conv3dBpInputTrans, EsTensorHolder& inputSize, EsTensorHolder& filter, | ||
| 100 | EsTensorHolder& dedy) | ||
| 101 | { | ||
| 102 | EsTensorHolder transFlt; | ||
| 103 | TensorDesc transFltDesc; | ||
| 104 | auto fltConfig = TransposeNodeConfig::Create( | ||
| 105 | filter, FILTER_TRANSPOSE_PERM, "filter_transpose", Format::FORMAT_NCDHW); | ||
| 106 | OP_CHECK_IF(!ConvBackpropFusionUtilsPass::CreateTransposeNode( | ||
| 107 | builder, fltConfig, transFlt, transFltDesc, GetNodeType()), | ||
| 108 | OP_LOGE(GetNodeType().GetString(), "Create filter transpose node failed"), return false); | ||
| 109 | |||
| 110 | auto dedyConfig = TransposeNodeConfig::Create( | ||
| 111 | dedy, DEDY_TRANSPOSE_PERM, "dedy_transpose", Format::FORMAT_NCDHW); | ||
| 112 | |||
| 113 | EsTensorHolder transDedy; | ||
| 114 | TensorDesc transDedyDesc; | ||
| 115 | OP_CHECK_IF(!ConvBackpropFusionUtilsPass::CreateTransposeNode( | ||
| 116 | builder, dedyConfig, transDedy, transDedyDesc, GetNodeType()), | ||
| 117 | OP_LOGE(GetNodeType().GetString(), "Create out_backprop transpose node failed"), return false); | ||
| 118 | |||
| 119 | std::vector<int64_t> transStrides = convBpAttr.strides; | ||
| 120 | std::vector<int64_t> transDils = convBpAttr.dilations; | ||
| 121 | std::rotate(transStrides.begin() + 1, transStrides.begin() + 4, transStrides.end()); | ||
| 122 | std::rotate(transDils.begin() + 1, transDils.begin() + 4, transDils.end()); | ||
| 123 | std::string finalFmt = "NCDHW"; | ||
| 124 | |||
| 125 | auto conv3dBpInputV2 = Conv3DBackpropInputV2( | ||
| 126 | inputSize, transFlt, transDedy, transStrides, convBpAttr.pads, transDils, convBpAttr.groups, | ||
| 127 | finalFmt.c_str(), convBpAttr.hf32); | ||
| 128 | |||
| 129 | auto* conv3dBpInputV2Node = conv3dBpInputV2.GetProducer(); | ||
| 130 | OP_CHECK_IF(conv3dBpInputV2Node == nullptr, | ||
| 131 | OP_LOGE(GetNodeType().GetString(), "Create Conv3DBackpropInputV2 node failed"), return false); | ||
| 132 | |||
| 133 | conv3dBpInputV2Node->SetAttr("_op_impl_mode_enum", convBpAttr.opImplModeEnum); | ||
| 134 | conv3dBpInputV2Node->UpdateInputDesc(CONV_BP_V2_INPUT_INDEX, input0Desc); | ||
| 135 | conv3dBpInputV2Node->UpdateInputDesc(CONV_BP_V2_FILTER_INDEX, transFltDesc); | ||
| 136 | conv3dBpInputV2Node->UpdateInputDesc(CONV_BP_V2_OUT_BACKPROP_INDEX, transDedyDesc); | ||
| 137 | conv3dBpInputV2Node->UpdateOutputDesc(CONV_BP_V2_OUTPUT_INDEX, outputDesc); | ||
| 138 | |||
| 139 | OP_CHECK_IF(!CreateOutputWithTranspose(builder, conv3dBpInputV2, conv3dBpInputV2Node, conv3dBpInputTrans), | ||
| 140 | OP_LOGE(GetNodeType().GetString(), "Create y with transpose failed"), return false); | ||
| 141 | |||
| 142 | return true; | ||
| 143 | } | ||
| 144 | |||
| 145 | GraphUniqPtr Conv3DBackpropInputToV2FusionPass::Replacement(const GNode& convBpInputNode) | ||
| 146 | { | ||
| 147 | OP_LOGD(GetNodeType().GetString(), "Replacement start"); | ||
| 148 | |||
| 149 | OP_CHECK_IF(!GetNodeDesc(convBpInputNode), | ||
| 150 | OP_LOGE(GetNodeType().GetString(), "GetNodeDesc failed"), return nullptr); | ||
| 151 | |||
| 152 | OP_CHECK_IF(!GetNodeAttrs(convBpInputNode), | ||
| 153 | OP_LOGE(GetNodeType().GetString(), "GetNodeAttrs failed"), return nullptr); | ||
| 154 | |||
| 155 | auto builder = EsGraphBuilder("replacement"); | ||
| 156 | auto [inputSize, filter, dedy] = builder.CreateInputs<3>(); | ||
| 157 | |||
| 158 | ConvBackpropFusionUtilsPass::SetPlaceholderDesc(inputSize, 0, input0Desc); | ||
| 159 | ConvBackpropFusionUtilsPass::SetPlaceholderDesc(filter, 0, input1Desc); | ||
| 160 | ConvBackpropFusionUtilsPass::SetPlaceholderDesc(dedy, 0, input2Desc); | ||
| 161 | |||
| 162 | bool needTranspose = CheckTransposeNeeded(); | ||
| 163 | if (needTranspose) { | ||
| 164 | EsTensorHolder conv3dBpInputTrans; | ||
| 165 | if (!Createconv3dBpInputTransposeGraph(builder, conv3dBpInputTrans, inputSize, filter, dedy)) { | ||
| 166 | return nullptr; | ||
| 167 | } | ||
| 168 | return builder.BuildAndReset(std::vector<EsTensorHolder>{conv3dBpInputTrans}); | ||
| 169 | } | ||
| 170 | |||
| 171 | auto conv3dBpInputV2 = Conv3DBackpropInputV2( | ||
| 172 | inputSize, filter, dedy, convBpAttr.strides, convBpAttr.pads, convBpAttr.dilations, | ||
| 173 | convBpAttr.groups, convBpAttr.dataFormat.c_str(), convBpAttr.hf32); | ||
| 174 | |||
| 175 | auto* conv3dBpInputV2Node = conv3dBpInputV2.GetProducer(); | ||
| 176 | OP_CHECK_IF(conv3dBpInputV2Node == nullptr, | ||
| 177 | OP_LOGE(GetNodeType().GetString(), "Create Conv3DBackpropInputV2 node failed"), return nullptr); | ||
| 178 | |||
| 179 | conv3dBpInputV2Node->SetAttr("_op_impl_mode_enum", convBpAttr.opImplModeEnum); | ||
| 180 | OP_CHECK_IF(!UpdateNodeInputDescInfo(conv3dBpInputV2Node), | ||
| 181 | OP_LOGE(GetNodeType().GetString(), "Update conv3dBpInputV2Node DescInfo failed"), return nullptr); | ||
| 182 | |||
| 183 | return builder.BuildAndReset(std::vector<EsTensorHolder>{conv3dBpInputV2}); | ||
| 184 | } | ||
| 185 | |||
| 186 | REG_DECOMPOSE_PASS(Conv3DBackpropInputToV2FusionPass, {CONV_BACKPROP_INPUT}) | ||
| 187 | .Stage(CustomPassStage::kCompatibleInherited); | ||
| 188 | |||
| 189 | } // namespace ops | ||
| @@ -0,0 +1,60 @@ | |||
| 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 | const ge::AscendString CONV_BACKPROP_INPUT = "Conv3DBackpropInput"; | ||
| 19 | const ge::AscendString CONV_BACKPROP_INPUT_V2_PASS = "Conv3DBackpropInputToV2FusionPass"; | ||
| 20 | |||
| 21 | class __attribute__((visibility("default"))) Conv3DBackpropInputToV2FusionPass : public ConvBackpropFusionBasePass { | ||
| 22 | public: | ||
| 23 | explicit Conv3DBackpropInputToV2FusionPass(const std::vector<ge::AscendString>& opTypes) | ||
| 24 | : ConvBackpropFusionBasePass(opTypes) | ||
| 25 | {} | ||
| 26 | |||
| 27 | protected: | ||
| 28 | ge::AscendString GetNodeType() const override; | ||
| 29 | bool CheckTransposeNeeded() override; | ||
| 30 | ge::fusion::GraphUniqPtr Replacement(const ge::GNode& convBpInputNode) override; | ||
| 31 | |||
| 32 | private: | ||
| 33 | // InputV2特有的Shape白名单 | ||
| 34 | const std::vector<std::vector<int64_t>> outputShapeWhitelist = { | ||
| 35 | {256, 1, 8, 8, 512}, {256, 1, 32, 32, 128}, {256, 1, 8, 8, 1024}, {256, 1, 16, 16, 256}, | ||
| 36 | {256, 1, 64, 64, 64}, {256, 1, 32, 32, 256}, {256, 1, 64, 64, 128}, {256, 1, 128, 128, 3}, | ||
| 37 | {256, 1, 16, 16, 512}, {64, 1, 32, 32, 128}, {64, 1, 64, 64, 32}}; | ||
| 38 | |||
| 39 | const std::vector<std::vector<int64_t>> filterShapeWhitelist = { | ||
| 40 | {1, 4, 4, 512, 1037}, {1, 4, 4, 128, 269}, {1, 4, 4, 1024, 1037}, {1, 4, 4, 256, 525}, | ||
| 41 | {1, 4, 4, 64, 141}, {1, 4, 4, 256, 781}, {1, 4, 4, 128, 397}, {1, 4, 4, 3, 205}, | ||
| 42 | {1, 4, 4, 512, 1549}, {1, 5, 5, 128, 256}, {1, 5, 5, 32, 128}}; | ||
| 43 | |||
| 44 | const std::vector<std::vector<int64_t>> dedyShapeWhitelist = { | ||
| 45 | {256, 1, 4, 4, 1037}, {256, 1, 16, 16, 269}, {256, 1, 4, 4, 1037}, {256, 1, 8, 8, 525}, | ||
| 46 | {256, 1, 32, 32, 141}, {256, 1, 16, 16, 781}, {256, 1, 32, 32, 397}, {256, 1, 64, 64, 205}, | ||
| 47 | {256, 1, 8, 8, 1549}, {64, 1, 16, 16, 256}, {64, 1, 32, 32, 128}}; | ||
| 48 | |||
| 49 | bool Createconv3dBpInputTransposeGraph( | ||
| 50 | ge::es::EsGraphBuilder& builder, ge::es::EsTensorHolder& conv3dBpInputTrans, ge::es::EsTensorHolder& inputSize, | ||
| 51 | ge::es::EsTensorHolder& filter, ge::es::EsTensorHolder& dedy); | ||
| 52 | |||
| 53 | bool CreateOutputWithTranspose( | ||
| 54 | ge::es::EsGraphBuilder& builder, const ge::es::EsTensorHolder& conv3dBpInputV2, ge::GNode* conv3dBpInputV2Node, | ||
| 55 | ge::es::EsTensorHolder& transOutput); | ||
| 56 | }; | ||
| 57 | |||
| 58 | } // namespace ops | ||
| 59 | |||
| 60 | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # ---------------------------------------------------------------------------- | ||
| 2 | # Copyright (c) 2025 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 | file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | if(UT_TEST_ALL OR OP_GRAPH_UT) | ||
| 13 | add_modules_ut_sources(HOSTNAME ${OP_GRAPH_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | endif() | ||
Aconv/conv3d_backprop_input_v2/tests/ut/op_graph/test_conv3d_backprop_input_to_v2_fusion_pass.cpp+295-0
| @@ -0,0 +1,295 @@ | |||
| 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 fe; | ||
| 24 | using namespace fusion; | ||
| 25 | using namespace ops::ConvBackpropFusionUtils; | ||
| 26 | |||
| 27 | namespace { | ||
| 28 | |||
| 29 | void SetPlatform(const std::string& soc) | ||
| 30 | { | ||
| 31 | PlatformInfo platformInfo; | ||
| 32 | OptionalInfo optionalInfo; | ||
| 33 | platformInfo.soc_info.ai_core_cnt = 64; | ||
| 34 | platformInfo.str_info.short_soc_version = soc; | ||
| 35 | optionalInfo.soc_version = soc; | ||
| 36 | if (soc == "Ascend950" || soc == "MC62CM12A") { | ||
| 37 | platformInfo.ai_core_intrinsic_dtype_map["Intrinsic_data_move_out2l1_dn2nz"] = {"float16", "float", "bfloat16"}; | ||
| 38 | } | ||
| 39 | PlatformInfoManager::Instance().platform_info_map_[soc] = platformInfo; | ||
| 40 | PlatformInfoManager::Instance().SetOptionalCompilationInfo(optionalInfo); | ||
| 41 | } | ||
| 42 | |||
| 43 | es::EsTensorHolder CreateConv3dBpInputNode( | ||
| 44 | es::EsGraphBuilder& builder, const char* opType, const es::EsTensorHolder& inputSize, | ||
| 45 | const es::EsTensorHolder& filter, const es::EsTensorHolder& dedy, std::vector<int64_t> strides, | ||
| 46 | std::vector<int64_t> pads, std::vector<int64_t> dilations, int64_t groups, const std::string& dataFormat, | ||
| 47 | DataType outDtype, const std::vector<int64_t>& outShape, Format outFormat) | ||
| 48 | { | ||
| 49 | auto* graph = builder.GetCGraphBuilder()->GetGraph(); | ||
| 50 | auto node = es::CompliantNodeBuilder(graph) | ||
| 51 | .OpType(opType) | ||
| 52 | .Name(opType) | ||
| 53 | .IrDefInputs( | ||
| 54 | {{"input_size", es::CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 55 | {"filter", es::CompliantNodeBuilder::kEsIrInputRequired, ""}, | ||
| 56 | {"out_backprop", es::CompliantNodeBuilder::kEsIrInputRequired, ""}}) | ||
| 57 | .IrDefOutputs({{"y", es::CompliantNodeBuilder::kEsIrOutputRequired, ""}}) | ||
| 58 | .InstanceOutputDataType("y", outDtype) | ||
| 59 | .InstanceOutputShape("y", outShape) | ||
| 60 | .InstanceOutputFormat("y", outFormat) | ||
| 61 | .Build(); | ||
| 62 | |||
| 63 | es::AddEdgeAndUpdatePeerDesc(*graph, *inputSize.GetProducer(), inputSize.GetProducerOutIndex(), node, 0); | ||
| 64 | es::AddEdgeAndUpdatePeerDesc(*graph, *filter.GetProducer(), filter.GetProducerOutIndex(), node, 1); | ||
| 65 | es::AddEdgeAndUpdatePeerDesc(*graph, *dedy.GetProducer(), dedy.GetProducerOutIndex(), node, 2); | ||
| 66 | |||
| 67 | TensorDesc inputSizeDesc, filterDesc, dedyDesc; | ||
| 68 | inputSize.GetProducer()->GetOutputDesc(inputSize.GetProducerOutIndex(), inputSizeDesc); | ||
| 69 | filter.GetProducer()->GetOutputDesc(filter.GetProducerOutIndex(), filterDesc); | ||
| 70 | dedy.GetProducer()->GetOutputDesc(dedy.GetProducerOutIndex(), dedyDesc); | ||
| 71 | node.UpdateInputDesc(0, inputSizeDesc); | ||
| 72 | node.UpdateInputDesc(1, filterDesc); | ||
| 73 | node.UpdateInputDesc(2, dedyDesc); | ||
| 74 | |||
| 75 | node.SetAttr("strides", strides); | ||
| 76 | node.SetAttr("pads", pads); | ||
| 77 | node.SetAttr("dilations", dilations); | ||
| 78 | node.SetAttr("groups", groups); | ||
| 79 | AscendString fmt = dataFormat.c_str(); | ||
| 80 | node.SetAttr("data_format", fmt); | ||
| 81 | int64_t implMode = 0x1; | ||
| 82 | node.SetAttr("_op_impl_mode_enum", implMode); | ||
| 83 | |||
| 84 | return es::EsTensorHolder(builder.GetCGraphBuilder()->GetTensorHolderFromNode(node, 0)); | ||
| 85 | } | ||
| 86 | |||
| 87 | bool CheckNodeExists(GraphPtr& graph, const std::string& type) | ||
| 88 | { | ||
| 89 | for (auto node : graph->GetAllNodes()) { | ||
| 90 | AscendString nodeType; | ||
| 91 | node.GetType(nodeType); | ||
| 92 | if (nodeType.GetString() == type) | ||
| 93 | return true; | ||
| 94 | } | ||
| 95 | return false; | ||
| 96 | } | ||
| 97 | |||
| 98 | } // namespace | ||
| 99 | |||
| 100 | class Conv3dBpInputToV2FusionPassTest : public testing::Test { | ||
| 101 | protected: | ||
| 102 | void SetUp() override { SetPlatform("Ascend950"); } | ||
| 103 | }; | ||
| 104 | |||
| 105 | // Test 1: patternTest - FP16 basic fusion success (需要 Transpose) | ||
| 106 | TEST_F(Conv3dBpInputToV2FusionPassTest, patternTest) | ||
| 107 | { | ||
| 108 | auto builder = es::EsGraphBuilder("patternTest"); | ||
| 109 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 110 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_DHWCN, {1, 4, 4, 512, 1037}); | ||
| 111 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 112 | |||
| 113 | auto y = CreateConv3dBpInputNode( | ||
| 114 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 115 | 1, "NDHWC", DT_FLOAT16, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 116 | |||
| 117 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 118 | CustomPassContext ctx; | ||
| 119 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 120 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 121 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 122 | } | ||
| 123 | |||
| 124 | // Test 2: unsupportedPlatformFail - Ascend910_93 不支持 | ||
| 125 | TEST_F(Conv3dBpInputToV2FusionPassTest, unsupportedPlatformFail) | ||
| 126 | { | ||
| 127 | SetPlatform("Ascend910_93"); | ||
| 128 | auto builder = es::EsGraphBuilder("unsupportedPlatformFail"); | ||
| 129 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 130 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_DHWCN, {1, 4, 4, 512, 1037}); | ||
| 131 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 132 | |||
| 133 | auto y = CreateConv3dBpInputNode( | ||
| 134 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 135 | 1, "NDHWC", DT_FLOAT16, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 136 | |||
| 137 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 138 | CustomPassContext ctx; | ||
| 139 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 140 | EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 141 | EXPECT_FALSE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 142 | } | ||
| 143 | |||
| 144 | // Test 4: bf16FusionSuccess - BF16 融合成功 | ||
| 145 | TEST_F(Conv3dBpInputToV2FusionPassTest, bf16FusionSuccess) | ||
| 146 | { | ||
| 147 | auto builder = es::EsGraphBuilder("bf16FusionSuccess"); | ||
| 148 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 149 | auto filter = builder.CreateInput(1, "filter", DT_BF16, FORMAT_DHWCN, {1, 4, 4, 512, 1037}); | ||
| 150 | auto dedy = builder.CreateInput(2, "out_backprop", DT_BF16, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 151 | |||
| 152 | auto y = CreateConv3dBpInputNode( | ||
| 153 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 154 | 1, "NDHWC", DT_BF16, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 155 | |||
| 156 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 157 | CustomPassContext ctx; | ||
| 158 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 159 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 160 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 161 | } | ||
| 162 | |||
| 163 | // Test 5: fp32FusionSuccess - FP32 融合成功 | ||
| 164 | TEST_F(Conv3dBpInputToV2FusionPassTest, fp32FusionSuccess) | ||
| 165 | { | ||
| 166 | auto builder = es::EsGraphBuilder("fp32FusionSuccess"); | ||
| 167 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 168 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT, FORMAT_DHWCN, {1, 4, 4, 512, 1037}); | ||
| 169 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 170 | |||
| 171 | auto y = CreateConv3dBpInputNode( | ||
| 172 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 173 | 1, "NDHWC", DT_FLOAT, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 174 | |||
| 175 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 176 | CustomPassContext ctx; | ||
| 177 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 178 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 179 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 180 | } | ||
| 181 | |||
| 182 | // Test 6: mc62cm12APlatformFail - MC62CM12A 平台不支持 | ||
| 183 | TEST_F(Conv3dBpInputToV2FusionPassTest, mc62cm12APlatformFail) | ||
| 184 | { | ||
| 185 | SetPlatform("MC62CM12A"); | ||
| 186 | auto builder = es::EsGraphBuilder("mc62cm12APlatformFail"); | ||
| 187 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 188 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_DHWCN, {1, 4, 4, 512, 1037}); | ||
| 189 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 190 | |||
| 191 | auto y = CreateConv3dBpInputNode( | ||
| 192 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 193 | 1, "NDHWC", DT_FLOAT16, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 194 | |||
| 195 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 196 | CustomPassContext ctx; | ||
| 197 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 198 | EXPECT_EQ(pass.Run(graph, ctx), GRAPH_NOT_CHANGED); | ||
| 199 | EXPECT_FALSE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 200 | } | ||
| 201 | |||
| 202 | // Test 7: differentShapeSmallBatch - 不同 shape(小 batch) | ||
| 203 | TEST_F(Conv3dBpInputToV2FusionPassTest, differentShapeSmallBatch) | ||
| 204 | { | ||
| 205 | auto builder = es::EsGraphBuilder("differentShapeSmallBatch"); | ||
| 206 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 207 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_DHWCN, {1, 5, 5, 128, 256}); | ||
| 208 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {64, 1, 16, 16, 256}); | ||
| 209 | |||
| 210 | auto y = CreateConv3dBpInputNode( | ||
| 211 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 212 | 1, "NDHWC", DT_FLOAT16, {64, 1, 32, 32, 128}, FORMAT_NDHWC); | ||
| 213 | |||
| 214 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 215 | CustomPassContext ctx; | ||
| 216 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 217 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 218 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 219 | } | ||
| 220 | |||
| 221 | // Test 8: noTransposeCase - filter 格式不是 DHWCN,不需要 Transpose 但仍融合成功 | ||
| 222 | TEST_F(Conv3dBpInputToV2FusionPassTest, noTransposeCase) | ||
| 223 | { | ||
| 224 | auto builder = es::EsGraphBuilder("noTransposeCase"); | ||
| 225 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 226 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_NCDHW, {512, 1, 4, 4, 1037}); | ||
| 227 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 228 | |||
| 229 | auto y = CreateConv3dBpInputNode( | ||
| 230 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 231 | 1, "NDHWC", DT_FLOAT16, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 232 | |||
| 233 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 234 | CustomPassContext ctx; | ||
| 235 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 236 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 237 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 238 | } | ||
| 239 | |||
| 240 | // Test 9: strideNotMatchCase - stride 不满足条件,不需要 Transpose 但仍融合成功 | ||
| 241 | TEST_F(Conv3dBpInputToV2FusionPassTest, strideNotMatchCase) | ||
| 242 | { | ||
| 243 | auto builder = es::EsGraphBuilder("strideNotMatchCase"); | ||
| 244 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 245 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_DHWCN, {1, 4, 4, 512, 1037}); | ||
| 246 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 247 | |||
| 248 | auto y = CreateConv3dBpInputNode( | ||
| 249 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 250 | 1, "NDHWC", DT_FLOAT16, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 251 | |||
| 252 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 253 | CustomPassContext ctx; | ||
| 254 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 255 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 256 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 257 | } | ||
| 258 | |||
| 259 | // Test 10: groupsNotMatchCase - groups 不是 1,不需要 Transpose 但仍融合成功 | ||
| 260 | TEST_F(Conv3dBpInputToV2FusionPassTest, groupsNotMatchCase) | ||
| 261 | { | ||
| 262 | auto builder = es::EsGraphBuilder("groupsNotMatchCase"); | ||
| 263 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 264 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_DHWCN, {1, 4, 4, 512, 1037}); | ||
| 265 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {256, 1, 4, 4, 1037}); | ||
| 266 | |||
| 267 | auto y = CreateConv3dBpInputNode( | ||
| 268 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 269 | 2, "NDHWC", DT_FLOAT16, {256, 1, 8, 8, 512}, FORMAT_NDHWC); | ||
| 270 | |||
| 271 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 272 | CustomPassContext ctx; | ||
| 273 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 274 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 275 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 276 | } | ||
| 277 | |||
| 278 | // Test 11: shapeNotInWhitelistCase - shape 不在白名单,不需要 Transpose 但仍融合成功 | ||
| 279 | TEST_F(Conv3dBpInputToV2FusionPassTest, shapeNotInWhitelistCase) | ||
| 280 | { | ||
| 281 | auto builder = es::EsGraphBuilder("shapeNotInWhitelistCase"); | ||
| 282 | auto inputSize = builder.CreateInput(0, "input_size", DT_INT64, FORMAT_ND, {5}); | ||
| 283 | auto filter = builder.CreateInput(1, "filter", DT_FLOAT16, FORMAT_DHWCN, {1, 4, 4, 128, 256}); | ||
| 284 | auto dedy = builder.CreateInput(2, "out_backprop", DT_FLOAT16, FORMAT_NDHWC, {128, 1, 8, 8, 256}); | ||
| 285 | |||
| 286 | auto y = CreateConv3dBpInputNode( | ||
| 287 | builder, "Conv3DBackpropInput", inputSize, filter, dedy, {1, 2, 2, 2, 1}, {0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, | ||
| 288 | 1, "NDHWC", DT_FLOAT16, {128, 1, 16, 16, 128}, FORMAT_NDHWC); | ||
| 289 | |||
| 290 | std::shared_ptr<Graph> graph = builder.BuildAndReset({y}); | ||
| 291 | CustomPassContext ctx; | ||
| 292 | ops::Conv3DBackpropInputToV2FusionPass pass({AscendString("Conv3DBackpropInput")}); | ||
| 293 | EXPECT_EQ(pass.Run(graph, ctx), SUCCESS); | ||
| 294 | EXPECT_TRUE(CheckNodeExists(graph, "Conv3DBackpropInputV2")); | ||
| 295 | } | ||