已合并
FusionPass:Con3dBpInput/Con3dBpFilter to Con3dBpInputV2/Con3dBpFilterV2 FusionPass #6004
FusionPass:Con3dBpInput/Con3dBpFilter to Con3dBpInputV2/Con3dBpFilterV2 FusionPass #6004
已合并
xxxzh创建于 6月12日
14 个文件变更+1483-0
Aconv/common/op_graph/fusion_pass/conv_backprop_fusion_base_pass.cpp+97-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#include "conv_backprop_fusion_base_pass.h"
12#include "log/log.h"
13 
14namespace ops {
15using namespace ge;
16using namespace ConvBackpropFusionUtils;
17 
18void 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 
28bool ConvBackpropFusionBasePass::CheckSocAndIntrinsic()
29{
30 return ConvBackpropFusionUtilsPass::CheckSocAndIntrinsic(SUPPORT_SOC_LIST, npuArch);
31}
32 
33 
34bool 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 
44bool 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 
59bool 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 
87bool 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
Aconv/common/op_graph/fusion_pass/conv_backprop_fusion_base_pass.h+82-0
@@ -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#ifndef CONV_BACKPROP_FUSION_BASE_PASS_H
12#define CONV_BACKPROP_FUSION_BASE_PASS_H
13 
14#include "conv_backprop_fusion_utils_pass.h"
15#include "ge/fusion/pass/decompose_pass.h"
16 
17namespace ops {
18 
19// ConvBackprop属性结构体
20struct 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 */
45class __attribute__((visibility("default"))) ConvBackpropFusionBasePass : public ge::fusion::DecomposePass {
46public:
47 explicit ConvBackpropFusionBasePass(const std::vector<ge::AscendString>& opTypes) : DecomposePass(opTypes) {}
48 
49protected:
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 
69protected:
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#endif // CONV_BACKPROP_FUSION_BASE_PASS_H
Aconv/common/op_graph/fusion_pass/conv_backprop_fusion_utils_pass.cpp+111-0
@@ -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#include "conv_backprop_fusion_utils_pass.h"
12#include "log/log.h"
13 
14namespace ops {
15using namespace ge;
16using namespace ge::es;
17using namespace ConvBackpropFusionUtils;
18 
19std::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 
31void 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 
41bool 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 
47bool 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 
63bool 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 
Aconv/common/op_graph/fusion_pass/conv_backprop_fusion_utils_pass.h+138-0
@@ -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#ifndef CONV_BACKPROP_FUSION_UTILS_PASS_H
12#define CONV_BACKPROP_FUSION_UTILS_PASS_H
13 
14#include <algorithm>
15#include <map>
16#include <set>
17#include <vector>
18#include <string>
19 
20#include "ge/es_graph_builder.h"
21#include "ge/es_tensor_holder.h"
22#include "ge/ge_utils.h"
23#include "ge/compliant_node_builder.h"
24#include "platform/platform_info.h"
25#include "platform/soc_spec.h"
26 
27namespace ops {
28namespace ConvBackpropFusionUtils {
29 
30// Conv Backprop 公共常量定义
31constexpr int32_t CONV_DIM_LENGTH = 5;
32constexpr int32_t OUTPUT_INDEX = 0;
33constexpr int32_t OUT_BACKPROP_INDEX = 2;
34constexpr int64_t HF32_PRECISION_MODE_INT = 0x40;
35 
36// Transpose 算子的输入输出索引常量
37constexpr int32_t TRANSPOSE_INPUT_X_INDEX = 0; // Transpose 第一个输入(x)的索引
38constexpr int32_t TRANSPOSE_INPUT_PERM_INDEX = 1; // Transpose 第二个输入(perm)的索引
39constexpr int32_t TRANSPOSE_OUTPUT_Y_INDEX = 0; // Transpose 第一个输出(y)的索引
40 
41// Tensor 的默认输出索引常量
42constexpr int32_t TENSOR_DEFAULT_OUTPUT_INDEX = 0; // Tensor 的默认输出索引(大多数算子只有一个输出)
43 
44// ConvBackpropV2 算子的输入输出索引常量
45constexpr int32_t CONV_BP_V2_INPUT_INDEX = 0; // input_size 输入索引
46constexpr int32_t CONV_BP_V2_FILTER_INDEX = 1; // filter 输入索引
47constexpr int32_t CONV_BP_V2_OUT_BACKPROP_INDEX = 2; // out_backprop 输入索引
48constexpr int32_t CONV_BP_V2_OUTPUT_INDEX = 0; // output 输出索引
49 
50// NDHWC格式的维度索引
51constexpr int64_t N_DIM_NDHWC_INDEX = 0;
52constexpr int64_t D_DIM_NDHWC_INDEX = 1;
53constexpr int64_t H_DIM_NDHWC_INDEX = 2;
54constexpr int64_t W_DIM_NDHWC_INDEX = 3;
55constexpr int64_t C_DIM_NDHWC_INDEX = 4;
56 
57// NCDHW格式的维度索引
58constexpr int64_t N_DIM_NCDHW_INDEX = 0;
59constexpr int64_t C_DIM_NCDHW_INDEX = 1;
60constexpr int64_t D_DIM_NCDHW_INDEX = 2;
61constexpr int64_t H_DIM_NCDHW_INDEX = 3;
62constexpr int64_t W_DIM_NCDHW_INDEX = 4;
63 
64// DHWCN格式的维度索引
65constexpr int64_t D_DIM_DHWCN_INDEX = 0;
66constexpr int64_t H_DIM_DHWCN_INDEX = 1;
67constexpr int64_t W_DIM_DHWCN_INDEX = 2;
68constexpr int64_t C_DIM_DHWCN_INDEX = 3;
69constexpr int64_t N_DIM_DHWCN_INDEX = 4;
70 
71// 支持的SOC列表
72const std::map<std::string, NpuArch> SUPPORT_SOC_LIST = {
73 {"Ascend950", NpuArch::DAV_3510}
74};
75 
76// Transpose排列常量
77const std::vector<int32_t> FILTER_TRANSPOSE_PERM = {4, 3, 0, 1, 2}; // DHWCN -> NCDHW
78const std::vector<int32_t> DEDY_TRANSPOSE_PERM = {0, 4, 1, 2, 3}; // NDHWC -> NCDHW
79const std::vector<int32_t> OUTPUT_TRANSPOSE_PERM = {0, 2, 3, 4, 1}; // NCDHW -> NDHWC
80 
81 
82// Transpose 节点配置结构体
83struct 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 
103class ConvBackpropFusionUtilsPass {
104public:
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#endif // CONV_BACKPROP_FUSION_UTILS_PASS_H
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#include "conv3d_backprop_filter_to_v2_fusion_pass.h"
12 
13#include "es_nn_ops.h"
14#include "log/log.h"
15#include "register/register_custom_pass.h"
16 
17namespace ops {
18using namespace ge;
19using namespace ge::es;
20using namespace fusion;
21using namespace ConvBackpropFusionUtils;
22 
23// FilterV2特有的常量
24constexpr int64_t CONDICTION_DIVIDE_K = 16 * 32 * 32;
25const std::vector<int32_t> TRANSPOSE_PERM_NDHWC = {0, 2, 3, 4, 1}; // NCDHW -> NDHWC
26const std::vector<int32_t> TRANSPOSE_PERM_DHWCN = {2, 3, 4, 1, 0}; // NCDHW -> DHWCN
27 
28AscendString Conv3DBackpropFilterToV2FusionPass::GetNodeType() const
29{
30 return CONV_BACKPROP_FILTER_V2_PASS;
31}
32 
33bool 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 
82bool 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 
127GraphUniqPtr 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 
163REG_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#ifndef CONV3D_BACKPROP_FILTER_TO_V2_FUSION_PASS_H
12#define CONV3D_BACKPROP_FILTER_TO_V2_FUSION_PASS_H
13 
14#include "../../conv/common/op_graph/fusion_pass/conv_backprop_fusion_base_pass.h"
15 
16namespace ops {
17 
18const ge::AscendString CONV_BACKPROP_FILTER = "Conv3DBackpropFilter";
19const ge::AscendString CONV_BACKPROP_FILTER_V2_PASS = "Conv3DBackpropFilterToV2FusionPass";
20 
21class __attribute__((visibility("default"))) Conv3DBackpropFilterToV2FusionPass : public ConvBackpropFusionBasePass {
22public:
23 explicit Conv3DBackpropFilterToV2FusionPass(const std::vector<ge::AscendString>& opTypes)
24 : ConvBackpropFusionBasePass(opTypes) {}
25 
26protected:
27 ge::AscendString GetNodeType() const override;
28 bool CheckTransposeNeeded() override;
29 ge::fusion::GraphUniqPtr Replacement(const ge::GNode& convBpFilterNode) override;
30 
31private:
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#endif // CONV3D_BACKPROP_FILTER_TO_V2_FUSION_PASS_H
Aconv/conv3d_backprop_filter_v2/tests/ut/op_graph/CMakeLists.txt+14-0
@@ -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 
11file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
12if(UT_TEST_ALL OR OP_GRAPH_UT)
13 add_modules_ut_sources(HOSTNAME ${OP_GRAPH_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR})
14endif()
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#include <gtest/gtest.h>
12 
13#include <string>
14#include <vector>
15 
16#include "platform/platform_info.h"
17#include "register/register_custom_pass.h"
18#include "ge/compliant_node_builder.h"
19#include "ge/es_graph_builder.h"
20#include "../../../op_graph/fusion_pass/conv3d_backprop_filter_to_v2_fusion_pass.h"
21 
22using namespace ge;
23using namespace fe;
24using namespace fusion;
25using namespace ops::ConvBackpropFusionUtils;
26 
27namespace {
28 
29void 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 
43es::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 
87bool 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 
100class Conv3dBpFilterToV2FusionPassTest : public testing::Test {
101protected:
102 void SetUp() override { SetPlatform("Ascend950"); }
103};
104 
105// Test 1: patternTest - FP16 basic fusion success (需要 Transpose)
106TEST_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 不支持
125TEST_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 融合成功
145TEST_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 融合成功
164TEST_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 平台不支持
183TEST_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)
203TEST_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 但仍融合成功
222TEST_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
241TEST_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 但仍融合成功
260TEST_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#include "conv3d_backprop_input_to_v2_fusion_pass.h"
12 
13#include "es_nn_ops.h"
14#include "log/log.h"
15#include "register/register_custom_pass.h"
16 
17namespace ops {
18using namespace ge;
19using namespace ge::es;
20using namespace fusion;
21using namespace ConvBackpropFusionUtils;
22 
23AscendString Conv3DBackpropInputToV2FusionPass::GetNodeType() const { return CONV_BACKPROP_INPUT_V2_PASS; }
24 
25bool 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 
74bool 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 
98bool 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 
145GraphUniqPtr 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 
186REG_DECOMPOSE_PASS(Conv3DBackpropInputToV2FusionPass, {CONV_BACKPROP_INPUT})
187 .Stage(CustomPassStage::kCompatibleInherited);
188 
189} // namespace ops
Aconv/conv3d_backprop_input_v2/op_graph/fusion_pass/conv3d_backprop_input_to_v2_fusion_pass.h+60-0
@@ -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#ifndef CONV3D_BACKPROP_INPUT_TO_V2_FUSION_PASS_H
12#define CONV3D_BACKPROP_INPUT_TO_V2_FUSION_PASS_H
13 
14#include "../../conv/common/op_graph/fusion_pass/conv_backprop_fusion_base_pass.h"
15 
16namespace ops {
17 
18const ge::AscendString CONV_BACKPROP_INPUT = "Conv3DBackpropInput";
19const ge::AscendString CONV_BACKPROP_INPUT_V2_PASS = "Conv3DBackpropInputToV2FusionPass";
20 
21class __attribute__((visibility("default"))) Conv3DBackpropInputToV2FusionPass : public ConvBackpropFusionBasePass {
22public:
23 explicit Conv3DBackpropInputToV2FusionPass(const std::vector<ge::AscendString>& opTypes)
24 : ConvBackpropFusionBasePass(opTypes)
25 {}
26 
27protected:
28 ge::AscendString GetNodeType() const override;
29 bool CheckTransposeNeeded() override;
30 ge::fusion::GraphUniqPtr Replacement(const ge::GNode& convBpInputNode) override;
31 
32private:
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#endif // CONV3D_BACKPROP_INPUT_TO_V2_FUSION_PASS_H
Aconv/conv3d_backprop_input_v2/tests/ut/op_graph/CMakeLists.txt+14-0
@@ -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 
11file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
12if(UT_TEST_ALL OR OP_GRAPH_UT)
13 add_modules_ut_sources(HOSTNAME ${OP_GRAPH_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR})
14endif()
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#include <gtest/gtest.h>
12 
13#include <string>
14#include <vector>
15 
16#include "platform/platform_info.h"
17#include "register/register_custom_pass.h"
18#include "ge/compliant_node_builder.h"
19#include "ge/es_graph_builder.h"
20#include "../../../op_graph/fusion_pass/conv3d_backprop_input_to_v2_fusion_pass.h"
21 
22using namespace ge;
23using namespace fe;
24using namespace fusion;
25using namespace ops::ConvBackpropFusionUtils;
26 
27namespace {
28 
29void 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 
43es::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 
87bool 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 
100class Conv3dBpInputToV2FusionPassTest : public testing::Test {
101protected:
102 void SetUp() override { SetPlatform("Ascend950"); }
103};
104 
105// Test 1: patternTest - FP16 basic fusion success (需要 Transpose)
106TEST_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 不支持
125TEST_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 融合成功
145TEST_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 融合成功
164TEST_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 平台不支持
183TEST_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)
203TEST_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 但仍融合成功
222TEST_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 但仍融合成功
241TEST_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 但仍融合成功
260TEST_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 但仍融合成功
279TEST_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}