已合并
迁移drop_out_v3和stateless_bernoulli融合规则到ops-math仓 #2191
liangtongxue创建于 4月13日
迁移drop_out_v3和stateless_bernoulli融合规则到ops-math仓 #2191
已合并
liangtongxue创建于 4月13日
13 个文件变更+2389-30
Mrandom/drop_out_v3/CMakeLists.txt+1-1
@@ -12,4 +12,4 @@
12set(SUPPORT_COMPUTE_UNIT "ascend310p" "ascend910_93" "ascend910b" "ascend950")12set(SUPPORT_COMPUTE_UNIT "ascend310p" "ascend910_93" "ascend910b" "ascend950")
13# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译13# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译
14set(SUPPORT_TILING_DIR "arch32" "arch32" "arch32" "arch35")14set(SUPPORT_TILING_DIR "arch32" "arch32" "arch32" "arch35")
15add_all_modules_sources(OPTYPE drop_out_v3 ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DEPENDENCIES random_common DISABLE_IN_OPP TRUE)15add_all_modules_sources(OPTYPE drop_out_v3 ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DEPENDENCIES random_common stateless_drop_out_gen_mask drop_out_do_mask DISABLE_IN_OPP TRUE)
Arandom/drop_out_v3/op_graph/fusion_pass/drop_out_v3_fusion_pass.cpp+336-0
@@ -0,0 +1,336 @@
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 * \file drop_out_v3_fusion_pass.cpp
13 * \brief drop_out_v3 fusion pass (StatelessDropOutGenMask + DropOutDoMask --> DropOutV3)
14 */
15 
16#include <vector>
17#include <string>
18#include <memory>
19#include <algorithm>
20#include "es_math_ops.h"
21#include "register/register_custom_pass.h"
22#include "ge/ge_utils.h"
23#include "platform/platform_info.h"
24#include "log/log.h"
25#include "drop_out_v3_fusion_pass.h"
26 
27namespace ge::fusion {
28 
29using namespace ge;
30using namespace fe;
31 
32namespace {
33const std::string kPassName = "DropOutV3FusionPass";
L
Lllimwang4月14日

匿名命名空间中的 kPassName 声明为 const std::string,而 stateless_bernoulli 中声明为 static const std::string。在匿名命名空间中 const 变量已经是内部链接,static 是多余的。但两个文件使用不同的声明方式,建议统一风格。

likedislike
34constexpr int64_t kGenMaskCaptureIdx = 0;
35constexpr int64_t kDoMaskCaptureIdx = 1;
36 
37constexpr size_t kIdxX = 0;
38constexpr size_t kIdxShape = 1;
39constexpr size_t kIdxProb = 2;
40constexpr size_t kIdxSeed = 3;
41constexpr size_t kIdxOffset = 4;
42 
43constexpr size_t kGenMaskIdxProb = 1;
44constexpr size_t kGenMaskIdxSeed = 2;
45constexpr size_t kGenMaskIdxOffset = 4;
46 
47struct InputParams {
48 std::vector<int64_t> xDims;
49 std::vector<int64_t> shapeDims;
50 std::vector<int64_t> probDims;
51 std::vector<int64_t> seedDims;
52 std::vector<int64_t> offsetDims;
53 Format xFmt;
54 Format shapeFmt;
55 Format probFmt;
56 Format seedFmt;
57 Format offsetFmt;
58 DataType xDtype;
59 DataType probDtype;
60 DataType seedDtype;
61 DataType offsetDtype;
62};
63 
64std::vector<int64_t> GetShapeDims(const Shape& shape)
65{
66 std::vector<int64_t> dims;
67 for (size_t i = 0; i < shape.GetDimNum(); i++) {
68 dims.push_back(shape.GetDim(i));
69 }
70 return dims;
71}
72 
73std::vector<int64_t> GetInputDims(const std::vector<Shape>& inputShapes, size_t idx)
74{
75 if (idx < inputShapes.size()) {
76 return GetShapeDims(inputShapes[idx]);
77 }
78 return {};
79}
80 
81Format GetInputFormat(const std::vector<Format>& inputFormats, size_t idx)
82{
83 return (idx < inputFormats.size()) ? inputFormats[idx] : FORMAT_ND;
84}
85 
86DataType GetInputDtype(const std::vector<DataType>& inputDtypes, size_t idx)
87{
88 return (idx < inputDtypes.size()) ? inputDtypes[idx] : DT_FLOAT;
89}
90 
91void GetInputsInfo(
92 const std::vector<SubgraphInput>& subgraphInputs, std::vector<Shape>& inputShapes,
93 std::vector<DataType>& inputDtypes, std::vector<Format>& inputFormats)
94{
95 for (const auto& subgraphInput : subgraphInputs) {
96 auto matchNode = subgraphInput.GetAllInputs().at(0);
97 TensorDesc tensorDesc;
98 matchNode.node.GetInputDesc(matchNode.index, tensorDesc);
99 inputShapes.emplace_back(tensorDesc.GetShape());
100 inputDtypes.emplace_back(tensorDesc.GetDataType());
101 inputFormats.emplace_back(tensorDesc.GetFormat());
102 }
103}
104 
105Status InferShape(const GraphUniqPtr& replaceGraph, const std::vector<SubgraphInput>& subgraphInputs)
106{
107 std::vector<Shape> inputShapes;
108 for (const auto& subgraphInput : subgraphInputs) {
109 auto matchNode = subgraphInput.GetAllInputs().at(0);
110 TensorDesc tensorDesc;
111 matchNode.node.GetInputDesc(matchNode.index, tensorDesc);
112 inputShapes.emplace_back(tensorDesc.GetShape());
113 }
114 return GeUtils::InferShape(*replaceGraph, inputShapes);
115}
116 
117void UpdateNodeOutputDesc(es::EsTensorHolder& tensor, DataType dtype, const std::vector<int64_t>& dims, Format fmt)
118{
119 TensorDesc desc;
120 desc.SetDataType(dtype);
121 desc.SetShape(Shape(dims));
122 desc.SetFormat(fmt);
123 tensor.GetProducer()->UpdateOutputDesc(0, desc);
124}
125 
126bool CheckDtype(DataType dtype, const std::vector<DataType>& validTypes)
127{
128 return std::find(validTypes.begin(), validTypes.end(), dtype) != validTypes.end();
129}
130 
131bool GetNodeIo(const std::unique_ptr<MatchResult>& matchResult, int64_t idx, NodeIo& nodeIo)
132{
133 if (matchResult->GetCapturedTensor(idx, nodeIo) != SUCCESS) {
134 OP_LOGE(kPassName.c_str(), "GetCapturedTensor failed for index %ld", idx);
135 return false;
136 }
137 return true;
138}
139 
140InputParams GetInputParams(const std::vector<Shape>& inputShapes,
141 const std::vector<DataType>& inputDtypes,
142 const std::vector<Format>& inputFormats)
143{
144 InputParams params;
145 params.xDims = GetInputDims(inputShapes, kIdxX);
146 params.shapeDims = GetInputDims(inputShapes, kIdxShape);
147 params.probDims = GetInputDims(inputShapes, kIdxProb);
148 params.seedDims = GetInputDims(inputShapes, kIdxSeed);
149 params.offsetDims = GetInputDims(inputShapes, kIdxOffset);
150 
151 params.xFmt = GetInputFormat(inputFormats, kIdxX);
152 params.shapeFmt = GetInputFormat(inputFormats, kIdxShape);
153 params.probFmt = GetInputFormat(inputFormats, kIdxProb);
154 params.seedFmt = GetInputFormat(inputFormats, kIdxSeed);
155 params.offsetFmt = GetInputFormat(inputFormats, kIdxOffset);
156 
157 params.xDtype = GetInputDtype(inputDtypes, kIdxX);
158 params.probDtype = GetInputDtype(inputDtypes, kIdxProb);
159 params.seedDtype = GetInputDtype(inputDtypes, kIdxSeed);
160 params.offsetDtype = GetInputDtype(inputDtypes, kIdxOffset);
161 
162 return params;
163}
164 
165es::DropOutV3Output CreateDropOutV3Node(es::EsGraphBuilder& builder, const InputParams& params)
166{
167 auto rX = builder.CreateInput(0, "x", params.xDtype, params.xFmt, params.xDims);
168 auto rShape = builder.CreateInput(1, "noise_shape", ge::DT_INT64, params.shapeFmt, params.shapeDims);
169 auto rProb = builder.CreateInput(2, "p", params.probDtype, params.probFmt, params.probDims);
170 auto rSeed = builder.CreateInput(3, "seed", params.seedDtype, params.seedFmt, params.seedDims);
171 auto rOffset = builder.CreateInput(4, "offset", params.offsetDtype, params.offsetFmt, params.offsetDims);
172 
173 auto output = es::DropOutV3(rX, rShape, rProb, rSeed, rOffset);
174 
175 UpdateNodeOutputDesc(rX, params.xDtype, params.xDims, params.xFmt);
176 UpdateNodeOutputDesc(rShape, ge::DT_INT64, params.shapeDims, params.shapeFmt);
177 UpdateNodeOutputDesc(rProb, params.probDtype, params.probDims, params.probFmt);
178 UpdateNodeOutputDesc(rSeed, params.seedDtype, params.seedDims, params.seedFmt);
179 UpdateNodeOutputDesc(rOffset, params.offsetDtype, params.offsetDims, params.offsetFmt);
180 UpdateNodeOutputDesc(output.y, params.xDtype, params.xDims, params.xFmt);
181 
182 return output;
183}
184}
185 
186std::vector<PatternUniqPtr> DropOutV3FusionPass::Patterns()
187{
188 OP_LOGI(kPassName.c_str(), "Enter Patterns");
189 std::vector<PatternUniqPtr> patternGraphs;
190 
191 auto graphBuilder = es::EsGraphBuilder(kPassName.c_str());
192 auto shape = graphBuilder.CreateInput(kIdxShape);
193 auto prob = graphBuilder.CreateInput(kIdxProb);
194 auto seed = graphBuilder.CreateInput(kIdxSeed);
195 auto seed1 = graphBuilder.CreateScalar(0);
196 auto offset = graphBuilder.CreateInput(kIdxOffset);
197 
198 auto mask = es::StatelessDropOutGenMask(shape, prob, seed, seed1, offset);
199 auto x = graphBuilder.CreateInput(kIdxX);
200 auto y = es::DropOutDoMask(x, mask, prob);
201 
202 auto graph = graphBuilder.BuildAndReset({y});
203 auto pattern = std::make_unique<Pattern>(std::move(*graph));
204 pattern->CaptureTensor({*mask.GetProducer(), 0}).CaptureTensor({*y.GetProducer(), 0});
205 patternGraphs.emplace_back(std::move(pattern));
206 
207 return patternGraphs;
208}
209 
210bool DropOutV3FusionPass::MeetRequirements(const std::unique_ptr<MatchResult>& matchResult)
211{
212 OP_LOGI(kPassName.c_str(), "Enter MeetRequirements");
213 PlatformInfo platformInfo;
214 OptionalInfo optionalInfo;
215 if (PlatformInfoManager::Instance().GetPlatformInfoWithOutSocVersion(platformInfo, optionalInfo) != SUCCESS) {
216 OP_LOGE(kPassName.c_str(), "Get platform_info failed.");
217 return false;
218 }
219 if (platformInfo.str_info.short_soc_version != "Ascend950") {
220 return false;
221 }
222 return CheckGenMaskNode(matchResult) && CheckDoMaskNode(matchResult);
223}
224 
225bool DropOutV3FusionPass::CheckGenMaskNode(const std::unique_ptr<MatchResult>& matchResult) const
226{
227 NodeIo genMaskIo;
228 if (!GetNodeIo(matchResult, kGenMaskCaptureIdx, genMaskIo)) {
229 return false;
230 }
231 
232 AscendString nodeTypeStr;
233 genMaskIo.node.GetType(nodeTypeStr);
234 std::string nodeType(nodeTypeStr.GetString());
235 if (nodeType != "StatelessDropOutGenMask") {
236 OP_LOGE(kPassName.c_str(), "Expected StatelessDropOutGenMask, got %s", nodeType.c_str());
237 return false;
238 }
239 
240 if (genMaskIo.node.GetInputsSize() != 5) {
241 OP_LOGE(kPassName.c_str(), "GenMask input size != 5");
242 return false;
243 }
244 
245 TensorDesc probDesc;
246 genMaskIo.node.GetInputDesc(kGenMaskIdxProb, probDesc);
247 if (!CheckDtype(probDesc.GetDataType(), {DT_FLOAT, DT_FLOAT16, DT_BF16})) {
248 OP_LOGE(kPassName.c_str(), "GenMask prob dtype not supported");
249 return false;
250 }
251 
252 TensorDesc seedDesc;
253 genMaskIo.node.GetInputDesc(kGenMaskIdxSeed, seedDesc);
254 if (!CheckDtype(seedDesc.GetDataType(), {DT_INT32, DT_INT64})) {
255 OP_LOGE(kPassName.c_str(), "GenMask seed dtype not supported");
256 return false;
257 }
258 
259 TensorDesc offsetDesc;
260 genMaskIo.node.GetInputDesc(kGenMaskIdxOffset, offsetDesc);
261 if (offsetDesc.GetDataType() != DT_INT64) {
262 OP_LOGE(kPassName.c_str(), "GenMask offset dtype != DT_INT64");
263 return false;
264 }
265 
266 TensorDesc outputDesc;
267 genMaskIo.node.GetOutputDesc(0, outputDesc);
268 if (outputDesc.GetDataType() != DT_UINT8) {
269 OP_LOGE(kPassName.c_str(), "GenMask output dtype != DT_UINT8");
270 return false;
271 }
272 return true;
273}
274 
275bool DropOutV3FusionPass::CheckDoMaskNode(const std::unique_ptr<MatchResult>& matchResult) const
276{
277 NodeIo doMaskIo;
278 if (!GetNodeIo(matchResult, kDoMaskCaptureIdx, doMaskIo)) {
279 return false;
280 }
281 
282 AscendString nodeTypeStr;
283 doMaskIo.node.GetType(nodeTypeStr);
284 std::string nodeType(nodeTypeStr.GetString());
285 if (nodeType != "DropOutDoMask") {
286 OP_LOGE(kPassName.c_str(), "Expected DropOutDoMask, got %s", nodeType.c_str());
287 return false;
288 }
289 
290 if (doMaskIo.node.GetInputsSize() != 3) {
291 OP_LOGE(kPassName.c_str(), "DoMask input size != 3");
292 return false;
293 }
294 
295 TensorDesc inputDesc;
296 doMaskIo.node.GetInputDesc(0, inputDesc);
297 if (!CheckDtype(inputDesc.GetDataType(), {DT_FLOAT, DT_FLOAT16, DT_BF16})) {
298 OP_LOGE(kPassName.c_str(), "DoMask x dtype not supported");
299 return false;
300 }
301 
302 TensorDesc outputDesc;
303 doMaskIo.node.GetOutputDesc(0, outputDesc);
304 if (!CheckDtype(outputDesc.GetDataType(), {DT_FLOAT, DT_FLOAT16, DT_BF16})) {
305 OP_LOGE(kPassName.c_str(), "DoMask y dtype not supported");
306 return false;
307 }
308 return true;
309}
310 
311GraphUniqPtr DropOutV3FusionPass::Replacement(const std::unique_ptr<MatchResult>& matchResult)
312{
313 OP_LOGI(kPassName.c_str(), "Enter Replacement");
314 
315 std::vector<SubgraphInput> subgraphInputs;
316 matchResult->ToSubgraphBoundary()->GetAllInputs(subgraphInputs);
317 
318 std::vector<Shape> inputShapes;
319 std::vector<DataType> inputDtypes;
320 std::vector<Format> inputFormats;
321 GetInputsInfo(subgraphInputs, inputShapes, inputDtypes, inputFormats);
322 
323 auto params = GetInputParams(inputShapes, inputDtypes, inputFormats);
324 auto builder = es::EsGraphBuilder("replacement");
325 auto output = CreateDropOutV3Node(builder, params);
326 
327 GraphUniqPtr replaceGraph = builder.BuildAndReset({output.y});
328 if (InferShape(replaceGraph, subgraphInputs) != SUCCESS) {
329 OP_LOGE(kPassName.c_str(), "Infershape failed.");
330 return nullptr;
331 }
332 return replaceGraph;
333}
334 
335REG_FUSION_PASS(DropOutV3FusionPass).Stage(CustomPassStage::kCompatibleInherited);
336}
Arandom/drop_out_v3/op_graph/fusion_pass/drop_out_v3_fusion_pass.h+33-0
@@ -0,0 +1,33 @@
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 MATH_DROP_OUT_V3_FUSION_PASS_H
12#define MATH_DROP_OUT_V3_FUSION_PASS_H
13 
14#include "ge/fusion/pass/pattern_fusion_pass.h"
15 
16namespace ge::fusion {
17using namespace ge;
L
Lllimwang4月14日

头文件中使用 using namespace 会污染所有包含此头文件的翻译单元的命名空间。三个 fusion pass 头文件都存在这个问题。建议在头文件中使用完整的命名空间限定(如 ge::PatternUniqPtr),或者将 using namespace 限制在 .cpp 文件中。

likedislike
18 
19class __attribute__((visibility("default"))) DropOutV3FusionPass : public PatternFusionPass {
20protected:
21 std::vector<PatternUniqPtr> Patterns() override;
22 
23 bool MeetRequirements(const std::unique_ptr<MatchResult>& match_result) override;
24 
25 std::unique_ptr<Graph> Replacement(const std::unique_ptr<MatchResult>& match_result) override;
26 
27private:
28 bool CheckGenMaskNode(const std::unique_ptr<MatchResult>& match_result) const;
29 bool CheckDoMaskNode(const std::unique_ptr<MatchResult>& match_result) const;
30};
31 
32} // namespace ge::fusion
33#endif // MATH_DROP_OUT_V3_FUSION_PASS_H
Arandom/drop_out_v3/op_graph/fusion_pass/drop_out_v3_split_fusion_pass.cpp+330-0
@@ -0,0 +1,330 @@
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 * \file drop_out_v3_split_fusion_pass.cpp
13 * \brief DropOutV3 split fusion pass: DropOutV3 -> StatelessDropOutGenMask + DropOutDoMask
14 */
15 
16#include <vector>
17#include <string>
18#include <memory>
19#include <algorithm>
20#include "es_math_ops.h"
21#include "register/register_custom_pass.h"
22#include "ge/ge_utils.h"
23#include "ge/fusion/graph_rewriter.h"
24#include "platform/platform_info.h"
25#include "log/log.h"
26#include "drop_out_v3_split_fusion_pass.h"
27 
28namespace ge::fusion {
29 
30using namespace ge;
31using namespace fe;
32 
33namespace {
34const std::string kPassName = "DropOutV3SplitFusionPass";
35 
36constexpr size_t kIdxX = 0;
37constexpr size_t kIdxP = 2;
38constexpr size_t kIdxSeed = 3;
39constexpr size_t kIdxOffset = 4;
40 
41constexpr int32_t kMaxDimBound = 8;
42 
43bool CheckDtype(DataType dtype, const std::vector<DataType>& validTypes)
44{
45 return std::find(validTypes.begin(), validTypes.end(), dtype) != validTypes.end();
46}
47 
48std::vector<int64_t> GetDimsFromShape(const Shape& shape)
49{
50 std::vector<int64_t> dims;
51 for (size_t i = 0; i < shape.GetDimNum(); i++) {
52 dims.push_back(shape.GetDim(i));
53 }
54 return dims;
55}
56}
57 
58bool DropOutV3SplitFusionPass::CheckPlatform() const
59{
60 PlatformInfo platformInfo;
61 OptionalInfo optionalInfo;
62 if (PlatformInfoManager::Instance().GetPlatformInfoWithOutSocVersion(platformInfo, optionalInfo) != SUCCESS) {
63 OP_LOGE(kPassName.c_str(), "Get platform_info failed.");
64 return false;
65 }
66 const std::string soc = platformInfo.str_info.short_soc_version;
67 if (soc != "Ascend910_93" && soc != "Ascend910B") {
68 return false;
69 }
70 return true;
71}
72 
73bool DropOutV3SplitFusionPass::CheckDtypes(const GNode &node) const
74{
75 TensorDesc xDesc;
76 node.GetInputDesc(kIdxX, xDesc);
77 DataType xDtype = xDesc.GetDataType();
78 if (!CheckDtype(xDtype, {DT_FLOAT, DT_FLOAT16, DT_BF16})) {
79 OP_LOGE(kPassName.c_str(), "x dtype only support float/float16/bf16, actual: %d", static_cast<int>(xDtype));
80 return false;
81 }
82 
83 TensorDesc pDesc;
84 node.GetInputDesc(kIdxP, pDesc);
85 DataType pDtype = pDesc.GetDataType();
86 if (!CheckDtype(pDtype, {DT_FLOAT, DT_FLOAT16, DT_BF16})) {
87 OP_LOGE(kPassName.c_str(), "p dtype only support float/float16/bf16, actual: %d", static_cast<int>(pDtype));
88 return false;
89 }
90 
91 TensorDesc seedDesc;
92 node.GetInputDesc(kIdxSeed, seedDesc);
93 DataType seedDtype = seedDesc.GetDataType();
94 if (!CheckDtype(seedDtype, {DT_INT32, DT_INT64})) {
95 OP_LOGE(kPassName.c_str(), "seed dtype only support int32/int64, actual: %d", static_cast<int>(seedDtype));
96 return false;
97 }
98 
99 TensorDesc yDesc;
100 node.GetOutputDesc(0, yDesc);
101 DataType yDtype = yDesc.GetDataType();
102 if (!CheckDtype(yDtype, {DT_FLOAT, DT_FLOAT16, DT_BF16})) {
103 OP_LOGE(kPassName.c_str(), "y dtype only support float/float16/bf16, actual: %d", static_cast<int>(yDtype));
104 return false;
105 }
106 
107 if (xDtype != yDtype) {
108 OP_LOGE(kPassName.c_str(), "x dtype should same with y dtype, x: %d, y: %d",
109 static_cast<int>(xDtype), static_cast<int>(yDtype));
110 return false;
111 }
112 
113 return true;
114}
115 
116bool DropOutV3SplitFusionPass::CheckNode(const GNode &node) const
117{
118 AscendString nodeType;
119 if (node.GetType(nodeType) != SUCCESS) {
120 return false;
121 }
122 if (std::string(nodeType.GetString()) != "DropOutV3") {
123 return false;
124 }
125 
126 size_t inputSize = node.GetInputsSize();
127 if (inputSize != 5) {
128 OP_LOGE(kPassName.c_str(), "DropOutV3 input size != 5, actual: %zu", inputSize);
129 return false;
130 }
131 
132 if (!CheckDtypes(node)) {
133 return false;
134 }
135 
136 TensorDesc xDesc;
137 node.GetInputDesc(kIdxX, xDesc);
138 auto xDimNum = static_cast<int32_t>(xDesc.GetShape().GetDimNum());
139 if (xDimNum > kMaxDimBound || xDimNum < 0) {
140 OP_LOGE(kPassName.c_str(), "x dim should be [0~8], actual: %d", xDimNum);
141 return false;
142 }
143 
144 return true;
145}
146 
147InputInfo DropOutV3SplitFusionPass::GetInputInfo(const GNode &node) const
148{
149 InputInfo info;
150 TensorDesc xDesc;
151 node.GetInputDesc(kIdxX, xDesc);
152 TensorDesc pDesc;
153 node.GetInputDesc(kIdxP, pDesc);
154 TensorDesc seedDesc;
155 node.GetInputDesc(kIdxSeed, seedDesc);
156 TensorDesc offsetDesc;
157 node.GetInputDesc(kIdxOffset, offsetDesc);
158 
159 info.xDims = GetDimsFromShape(xDesc.GetShape());
160 info.pDims = GetDimsFromShape(pDesc.GetShape());
161 info.seedDims = GetDimsFromShape(seedDesc.GetShape());
162 info.offsetDims = GetDimsFromShape(offsetDesc.GetShape());
163 info.noiseShapeDims = {static_cast<int64_t>(xDesc.GetShape().GetDimNum())};
164 
165 info.xDtype = xDesc.GetDataType();
166 info.pDtype = pDesc.GetDataType();
167 info.seedDtype = seedDesc.GetDataType();
168 info.offsetDtype = offsetDesc.GetDataType();
169 info.fmt = xDesc.GetFormat();
170 
171 return info;
172}
173 
174void DropOutV3SplitFusionPass::UpdateTensorDescs(const InputInfo &info,
175 const es::EsTensorHolder &rX,
176 const es::EsTensorHolder &rProb,
177 const es::EsTensorHolder &rSeed,
178 const es::EsTensorHolder &rOffset,
179 const es::EsTensorHolder &genMask,
180 const es::EsTensorHolder &doMask,
181 const es::EsTensorHolder &rShapeConst,
182 const es::EsTensorHolder &rSeed1) const
183{
184 TensorDesc shapeConstDesc(Shape(info.noiseShapeDims), FORMAT_ND, DT_INT64);
185 rShapeConst.GetProducer()->UpdateOutputDesc(0, shapeConstDesc);
186 
187 TensorDesc seed1ConstDesc(Shape({1}), FORMAT_ND, DT_INT64);
188 rSeed1.GetProducer()->UpdateOutputDesc(0, seed1ConstDesc);
189 
190 TensorDesc inputDesc(Shape(info.xDims), info.fmt, info.xDtype);
191 rX.GetProducer()->UpdateOutputDesc(0, inputDesc);
192 
193 TensorDesc probDesc(Shape(info.pDims), info.fmt, info.pDtype);
194 rProb.GetProducer()->UpdateOutputDesc(0, probDesc);
195 
196 TensorDesc seedDescOut(Shape(info.seedDims), FORMAT_ND, info.seedDtype);
197 rSeed.GetProducer()->UpdateOutputDesc(0, seedDescOut);
198 
199 TensorDesc offsetDescOut(Shape(info.offsetDims), FORMAT_ND, info.offsetDtype);
200 rOffset.GetProducer()->UpdateOutputDesc(0, offsetDescOut);
201 
202 TensorDesc genMaskDesc(Shape(info.xDims), info.fmt, DT_UINT8);
203 genMask.GetProducer()->UpdateOutputDesc(0, genMaskDesc);
204 
205 TensorDesc doMaskDesc(Shape(info.xDims), info.fmt, info.xDtype);
206 doMask.GetProducer()->UpdateOutputDesc(0, doMaskDesc);
207 
208 TensorDesc shapeInputDesc(Shape(info.noiseShapeDims), FORMAT_ND, DT_INT64);
209 genMask.GetProducer()->UpdateInputDesc(0, shapeInputDesc);
210 genMask.GetProducer()->UpdateInputDesc(1, probDesc);
211 genMask.GetProducer()->UpdateInputDesc(2, seedDescOut);
212 TensorDesc seed1Desc(Shape({1}), FORMAT_ND, DT_INT64);
213 genMask.GetProducer()->UpdateInputDesc(3, seed1Desc);
214 genMask.GetProducer()->UpdateInputDesc(4, offsetDescOut);
215 
216 doMask.GetProducer()->UpdateInputDesc(0, inputDesc);
217 doMask.GetProducer()->UpdateInputDesc(1, genMaskDesc);
218 doMask.GetProducer()->UpdateInputDesc(2, probDesc);
219}
220 
221GraphUniqPtr DropOutV3SplitFusionPass::CreateReplacement(const GNode &node)
222{
223 InputInfo info = GetInputInfo(node);
224 auto builder = es::EsGraphBuilder("replacement");
225 
226 auto rX = builder.CreateInput(0, "x", info.xDtype, info.fmt, info.xDims);
227 [[maybe_unused]] auto rNoiseShape = builder.CreateInput(1, "noise_shape", DT_INT64, FORMAT_ND, info.noiseShapeDims);
228 auto rProb = builder.CreateInput(2, "prob", info.pDtype, info.fmt, info.pDims);
229 auto rSeed = builder.CreateInput(3, "seed", info.seedDtype, FORMAT_ND, info.seedDims);
230 auto rOffset = builder.CreateInput(4, "offset", info.offsetDtype, FORMAT_ND, info.offsetDims);
231 
232 std::vector<int64_t> shapeValue(info.xDims.size(), 0);
233 auto rShapeConst = builder.CreateConst(shapeValue, info.noiseShapeDims, DT_INT64, FORMAT_ND);
234 std::vector<int64_t> seed1Value = {0};
235 std::vector<int64_t> seed1Dims = {1};
236 auto rSeed1 = builder.CreateConst(seed1Value, seed1Dims, DT_INT64, FORMAT_ND);
237 
238 auto genMask = es::StatelessDropOutGenMask(rShapeConst, rProb, rSeed, rSeed1, rOffset);
239 auto doMask = es::DropOutDoMask(rX, genMask, rProb);
240 
241 UpdateTensorDescs(info, rX, rProb, rSeed, rOffset, genMask, doMask, rShapeConst, rSeed1);
242 
243 std::vector<es::EsTensorHolder> outputs;
244 outputs.emplace_back(doMask);
245 outputs.emplace_back(genMask);
246 return builder.BuildAndReset(outputs);
247}
248 
249std::unique_ptr<SubgraphBoundary> DropOutV3SplitFusionPass::ConstructBoundary(const GNode &node)
250{
251 auto boundary = std::make_unique<SubgraphBoundary>();
252 for (size_t idx = 0; idx < node.GetInputsSize(); ++idx) {
253 SubgraphInput subgraphInput;
254 subgraphInput.AddInput({node, static_cast<int64_t>(idx)});
255 if (boundary->AddInput(idx, std::move(subgraphInput)) != SUCCESS) {
256 OP_LOGE(kPassName.c_str(), "AddInput failed for idx %zu", idx);
257 return nullptr;
258 }
259 }
260 
261 SubgraphOutput output0({node, 0});
262 if (boundary->AddOutput(0, std::move(output0)) != SUCCESS) {
263 OP_LOGE(kPassName.c_str(), "AddOutput failed for output 0");
264 return nullptr;
265 }
266 
267 if (node.GetOutputsSize() > 1) {
268 SubgraphOutput output1({node, 1});
269 if (boundary->AddOutput(1, std::move(output1)) != SUCCESS) {
270 OP_LOGE(kPassName.c_str(), "AddOutput failed for output 1");
271 return nullptr;
272 }
273 }
274 return boundary;
275}
276 
277Status DropOutV3SplitFusionPass::Run(GraphPtr &graph, [[maybe_unused]] CustomPassContext &passContext)
278{
279 OP_LOGI(kPassName.c_str(), "Enter DropOutV3SplitFusionPass");
280 if (!CheckPlatform()) {
281 return GRAPH_NOT_CHANGED;
282 }
283 
284 std::vector<GNode> dropOutV3Nodes;
285 for (auto &node : graph->GetDirectNode()) {
286 if (CheckNode(node)) {
287 dropOutV3Nodes.emplace_back(node);
288 }
289 }
290 if (dropOutV3Nodes.empty()) {
291 return GRAPH_NOT_CHANGED;
292 }
293 
294 Graph originGraph = *graph;
295 for (auto &node : dropOutV3Nodes) {
296 auto replacement = CreateReplacement(node);
297 if (!replacement) {
298 AscendString nodeName;
299 node.GetName(nodeName);
300 OP_LOGE(kPassName.c_str(), "CreateReplacement failed for node %s", nodeName.GetString());
301 *graph = originGraph;
302 return FAILED;
303 }
304 
305 auto boundary = ConstructBoundary(node);
306 if (!boundary) {
307 AscendString nodeName;
308 node.GetName(nodeName);
309 OP_LOGE(kPassName.c_str(), "ConstructBoundary failed for node %s", nodeName.GetString());
310 *graph = originGraph;
311 return FAILED;
312 }
313 
314 Status replaceStatus = SubgraphRewriter::Replace(*boundary, *replacement);
315 if (replaceStatus != SUCCESS) {
316 AscendString nodeName;
317 node.GetName(nodeName);
318 OP_LOGE(kPassName.c_str(), "SubgraphRewriter::Replace failed for node %s, status=%d",
319 nodeName.GetString(), static_cast<int>(replaceStatus));
320 *graph = originGraph;
321 return FAILED;
322 }
323 }
324 
325 OP_LOGI(kPassName.c_str(), "DropOutV3SplitFusionPass completed, fused %zu nodes", dropOutV3Nodes.size());
326 return SUCCESS;
327}
328 
329REG_FUSION_PASS(DropOutV3SplitFusionPass).Stage(CustomPassStage::kCompatibleInherited);
330}
Arandom/drop_out_v3/op_graph/fusion_pass/drop_out_v3_split_fusion_pass.h+61-0
@@ -0,0 +1,61 @@
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 * \file drop_out_v3_split_fusion_pass.h
13 * \brief DropOutV3 split fusion pass: DropOutV3 -> StatelessDropOutGenMask + DropOutDoMask
14 */
15 
16#ifndef MATH_DROP_OUT_V3_SPLIT_FUSION_PASS_H
17#define MATH_DROP_OUT_V3_SPLIT_FUSION_PASS_H
18 
19#include "ge/fusion/pass/pattern_fusion_pass.h"
20 
21namespace ge::fusion {
22 
23using namespace ge;
24 
25struct InputInfo {
26 std::vector<int64_t> xDims;
27 std::vector<int64_t> pDims;
28 std::vector<int64_t> seedDims;
29 std::vector<int64_t> offsetDims;
30 std::vector<int64_t> noiseShapeDims;
31 DataType xDtype;
32 DataType pDtype;
33 DataType seedDtype;
34 DataType offsetDtype;
35 Format fmt;
36};
37 
38class __attribute__((visibility("default"))) DropOutV3SplitFusionPass : public FusionBasePass {
39public:
40 Status Run(GraphPtr &graph, CustomPassContext &pass_context) override;
41 
42private:
43 bool CheckPlatform() const;
44 bool CheckDtypes(const GNode &node) const;
45 bool CheckNode(const GNode &node) const;
46 InputInfo GetInputInfo(const GNode &node) const;
47 void UpdateTensorDescs(const InputInfo &info,
48 const es::EsTensorHolder &rX,
49 const es::EsTensorHolder &rProb,
50 const es::EsTensorHolder &rSeed,
51 const es::EsTensorHolder &rOffset,
52 const es::EsTensorHolder &genMask,
53 const es::EsTensorHolder &doMask,
54 const es::EsTensorHolder &rShapeConst,
55 const es::EsTensorHolder &rSeed1) const;
56 GraphUniqPtr CreateReplacement(const GNode &node);
57 std::unique_ptr<SubgraphBoundary> ConstructBoundary(const GNode &node);
58};
59 
60} // namespace ge::fusion
61#endif // MATH_DROP_OUT_V3_SPLIT_FUSION_PASS_H
Drandom/drop_out_v3/tests/ut/graph_plugin/CMakeLists.txt+0-9
@@ -1,9 +0,0 @@
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# ----------------------------------------------------------------------------
Drandom/drop_out_v3/tests/ut/graph_plugin/fusion_pass/CMakeLists.txt+0-9
@@ -1,9 +0,0 @@
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# ----------------------------------------------------------------------------
Arandom/drop_out_v3/tests/ut/op_graph/test_drop_out_v3_fusion_pass.cpp+499-0
@@ -0,0 +1,499 @@
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 License for details. You may not use this file except in compliance with 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 root of the software repository for the full text of the License.
9 */
10 
11#include <iostream>
12#include <vector>
13#include <gtest/gtest.h>
14#include "platform/platform_infos_def.h"
15#include "platform/platform_info.h"
16#include "ge/es_graph_builder.h"
17#include "es_math_ops.h"
18#include "log/log.h"
19#include "random/drop_out_v3/op_graph/fusion_pass/drop_out_v3_fusion_pass.h"
20 
21using namespace std;
22using namespace ge;
23using namespace fe;
24using namespace fusion;
25 
26namespace {
27const std::string kPassName = "DropOutV3FusionPass";
28}
29 
30class DropOutV3FusionPassTest : public testing::Test {
31protected:
32 static void SetUpTestCase()
33 {
34 PlatformInfo platformInfo;
35 OptionalInfo optiCompilationInfo;
36 platformInfo.soc_info.ai_core_cnt = 64;
37 platformInfo.str_info.short_soc_version = "Ascend910_93";
38 optiCompilationInfo.soc_version = "Ascend910_93";
39 PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
40 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
41 }
42 
43 void SetUp() override
44 {
45 PlatformInfo platformInfo;
46 OptionalInfo optiCompilationInfo;
47 platformInfo.soc_info.ai_core_cnt = 64;
48 platformInfo.str_info.short_soc_version = "Ascend910_93";
49 optiCompilationInfo.soc_version = "Ascend910_93";
50 PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
51 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
52 }
53 
54 void SetPlatform950()
55 {
56 PlatformInfo platformInfo;
57 OptionalInfo optiCompilationInfo;
58 platformInfo.soc_info.ai_core_cnt = 64;
59 platformInfo.str_info.short_soc_version = "Ascend950";
60 optiCompilationInfo.soc_version = "Ascend950";
61 PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
62 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
63 }
64 
65 void SetupTestEnvironment()
66 {
67 // Setup test 1: {14, 12, 16, 4, 8, 14}
68 PlatformInfo platformInfo;
69 OptionalInfo optiCompilationInfo;
70 platformInfo.soc_info.ai_core_cnt = 64;
71 platformInfo.str_info.short_soc_version = "Ascend910_95";
72 optiCompilationInfo.soc_version = "Ascend910_95";
73 PlatformInfoManager::Instance().platform_info_map_["Ascend910_95"] = platformInfo;
74 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
75 }
76};
77 
78// Test: Pattern creation
79TEST_F(DropOutV3FusionPassTest, pattern_creation_test)
80{
81 DropOutV3FusionPass pass;
82 std::vector<PatternUniqPtr> patterns = pass.Patterns();
83 EXPECT_GT(patterns.size(), 0);
84}
85 
86// Test: Unsupported platform returns NOT_CHANGED
87TEST_F(DropOutV3FusionPassTest, unsupported_platform_fail)
88{
89 // Default platform is Ascend910_93, not supported
90 std::vector<int64_t> dims_x{14, 12, 16, 4, 8, 14};
91 Shape shape_x(dims_x);
92 
93 auto graph_builder = es::EsGraphBuilder("test");
94 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
95 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{6});
96 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
97 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
98 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
99 
100 auto output = es::DropOutV3(x, shape, prob, seed, offset);
101 
102 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
103 
104 CustomPassContext pass_context;
105 DropOutV3FusionPass pass;
106 Status status = pass.Run(graph, pass_context);
107 
108 EXPECT_EQ(status, GRAPH_NOT_CHANGED);
109}
110 
111// Test: Shape {14, 12, 16, 4, 8, 14} - matches canndev test_1
112TEST_F(DropOutV3FusionPassTest, fusion_test_shape_1)
113{
114 SetupTestEnvironment();
115 SetPlatform950();
116 
117 std::vector<int64_t> dims_x{14, 12, 16, 4, 8, 14};
118 Shape shape_x(dims_x);
119 
120 auto graph_builder = es::EsGraphBuilder("test");
121 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
122 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{6});
123 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
124 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
125 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
126 
127 auto output = es::DropOutV3(x, shape, prob, seed, offset);
128 
129 // Set proper input tensor descriptions
130 TensorDesc x_desc;
131 x.GetProducer()->GetOutputDesc(0, x_desc);
132 x_desc.SetDataType(DT_FLOAT);
133 x_desc.SetShape(shape_x);
134 x.GetProducer()->UpdateOutputDesc(0, x_desc);
135 
136 TensorDesc shape_desc;
137 shape.GetProducer()->GetOutputDesc(0, shape_desc);
138 shape_desc.SetDataType(DT_INT64);
139 shape_desc.SetShape(Shape(std::vector<int64_t>{6}));
140 shape.GetProducer()->UpdateOutputDesc(0, shape_desc);
141 
142 TensorDesc prob_desc;
143 prob.GetProducer()->GetOutputDesc(0, prob_desc);
144 prob_desc.SetDataType(DT_FLOAT);
145 prob_desc.SetShape(Shape(std::vector<int64_t>{1}));
146 prob.GetProducer()->UpdateOutputDesc(0, prob_desc);
147 
148 TensorDesc seed_desc;
149 seed.GetProducer()->GetOutputDesc(0, seed_desc);
150 seed_desc.SetDataType(DT_INT64);
151 seed_desc.SetShape(Shape(std::vector<int64_t>{1}));
152 seed.GetProducer()->UpdateOutputDesc(0, seed_desc);
153 
154 TensorDesc offset_desc;
155 offset.GetProducer()->GetOutputDesc(0, offset_desc);
156 offset_desc.SetDataType(DT_INT64);
157 offset_desc.SetShape(Shape(std::vector<int64_t>{1}));
158 offset.GetProducer()->UpdateOutputDesc(0, offset_desc);
159 
160 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
161 
162 CustomPassContext pass_context;
163 DropOutV3FusionPass pass;
164 Status status = pass.Run(graph, pass_context);
165 
166 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
L
Lllimwang4月14日

大部分测试用例的断言都是 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED),这使得不管融合是否真正发生测试都能通过。对于明确期望融合成功的场景(如 Ascend950 + 正确 pattern),应使用 EXPECT_EQ(status, SUCCESS) 来确保融合确实执行了。当前断言方式无法检出融合逻辑中的 bug。

likedislike
167}
168 
169// Test: Shape {14, 12, 16, 2, 8} - matches canndev test_2
170TEST_F(DropOutV3FusionPassTest, fusion_test_shape_2)
171{
172 SetPlatform950();
173 
174 std::vector<int64_t> dims_x{14, 12, 16, 2, 8};
175 Shape shape_x(dims_x);
176 
177 auto graph_builder = es::EsGraphBuilder("test");
178 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
179 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{5});
180 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
181 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
182 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
183 
184 auto output = es::DropOutV3(x, shape, prob, seed, offset);
185 
186 TensorDesc x_desc;
187 x.GetProducer()->GetOutputDesc(0, x_desc);
188 x_desc.SetDataType(DT_FLOAT);
189 x_desc.SetShape(shape_x);
190 x.GetProducer()->UpdateOutputDesc(0, x_desc);
191 
192 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
193 
194 CustomPassContext pass_context;
195 DropOutV3FusionPass pass;
196 Status status = pass.Run(graph, pass_context);
197 
198 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
199}
200 
201// Test: Shape {14, 12, 16, 2, 8, 6} - matches canndev test_3
202TEST_F(DropOutV3FusionPassTest, fusion_test_shape_3)
203{
204 SetPlatform950();
205 
206 std::vector<int64_t> dims_x{14, 12, 16, 2, 8, 6};
207 Shape shape_x(dims_x);
208 
209 auto graph_builder = es::EsGraphBuilder("test");
210 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
211 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{6});
212 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
213 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
214 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
215 
216 auto output = es::DropOutV3(x, shape, prob, seed, offset);
217 
218 TensorDesc x_desc;
219 x.GetProducer()->GetOutputDesc(0, x_desc);
220 x_desc.SetDataType(DT_FLOAT);
221 x_desc.SetShape(shape_x);
222 x.GetProducer()->UpdateOutputDesc(0, x_desc);
223 
224 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
225 
226 CustomPassContext pass_context;
227 DropOutV3FusionPass pass;
228 Status status = pass.Run(graph, pass_context);
229 
230 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
231}
232 
233// Test: Shape {16, 18} - matches canndev test_5
234TEST_F(DropOutV3FusionPassTest, fusion_test_shape_5)
235{
236 SetPlatform950();
237 
238 std::vector<int64_t> dims_x{16, 18};
239 Shape shape_x(dims_x);
240 
241 auto graph_builder = es::EsGraphBuilder("test");
242 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
243 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
244 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
245 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
246 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
247 
248 auto output = es::DropOutV3(x, shape, prob, seed, offset);
249 
250 TensorDesc x_desc;
251 x.GetProducer()->GetOutputDesc(0, x_desc);
252 x_desc.SetDataType(DT_FLOAT);
253 x_desc.SetShape(shape_x);
254 x.GetProducer()->UpdateOutputDesc(0, x_desc);
255 
256 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
257 
258 CustomPassContext pass_context;
259 DropOutV3FusionPass pass;
260 Status status = pass.Run(graph, pass_context);
261 
262 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
263}
264 
265// Test: Shape {14, 12, 16} - matches canndev test_6
266TEST_F(DropOutV3FusionPassTest, fusion_test_shape_6)
267{
268 SetPlatform950();
269 
270 std::vector<int64_t> dims_x{14, 12, 16};
271 Shape shape_x(dims_x);
272 
273 auto graph_builder = es::EsGraphBuilder("test");
274 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
275 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{3});
276 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
277 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
278 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
279 
280 auto output = es::DropOutV3(x, shape, prob, seed, offset);
281 
282 TensorDesc x_desc;
283 x.GetProducer()->GetOutputDesc(0, x_desc);
284 x_desc.SetDataType(DT_FLOAT);
285 x_desc.SetShape(shape_x);
286 x.GetProducer()->UpdateOutputDesc(0, x_desc);
287 
288 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
289 
290 CustomPassContext pass_context;
291 DropOutV3FusionPass pass;
292 Status status = pass.Run(graph, pass_context);
293 
294 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
295}
296 
297// Test: Shape {2, 12, 8, 6} - matches canndev test_7
298TEST_F(DropOutV3FusionPassTest, fusion_test_shape_7)
299{
300 SetPlatform950();
301 
302 std::vector<int64_t> dims_x{2, 12, 8, 6};
303 Shape shape_x(dims_x);
304 
305 auto graph_builder = es::EsGraphBuilder("test");
306 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
307 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{4});
308 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
309 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
310 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
311 
312 auto output = es::DropOutV3(x, shape, prob, seed, offset);
313 
314 TensorDesc x_desc;
315 x.GetProducer()->GetOutputDesc(0, x_desc);
316 x_desc.SetDataType(DT_FLOAT);
317 x_desc.SetShape(shape_x);
318 x.GetProducer()->UpdateOutputDesc(0, x_desc);
319 
320 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
321 
322 CustomPassContext pass_context;
323 DropOutV3FusionPass pass;
324 Status status = pass.Run(graph, pass_context);
325 
326 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
327}
328 
329// Test: Shape {2, 4, 8, 6, 2} - matches canndev test_8
330TEST_F(DropOutV3FusionPassTest, fusion_test_shape_8)
331{
332 SetPlatform950();
333 
334 std::vector<int64_t> dims_x{2, 4, 8, 6, 2};
335 Shape shape_x(dims_x);
336 
337 auto graph_builder = es::EsGraphBuilder("test");
338 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
339 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{5});
340 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
341 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
342 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
343 
344 auto output = es::DropOutV3(x, shape, prob, seed, offset);
345 
346 TensorDesc x_desc;
347 x.GetProducer()->GetOutputDesc(0, x_desc);
348 x_desc.SetDataType(DT_FLOAT);
349 x_desc.SetShape(shape_x);
350 x.GetProducer()->UpdateOutputDesc(0, x_desc);
351 
352 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
353 
354 CustomPassContext pass_context;
355 DropOutV3FusionPass pass;
356 Status status = pass.Run(graph, pass_context);
357 
358 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
359}
360 
361// Test: FP16 data type
362TEST_F(DropOutV3FusionPassTest, fusion_success_fp16)
363{
364 SetPlatform950();
365 
366 std::vector<int64_t> dims_x{2, 4, 8, 6};
367 Shape shape_x(dims_x);
368 
369 auto graph_builder = es::EsGraphBuilder("test");
370 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT16, FORMAT_ND, shape_x.GetDims());
371 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{4});
372 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
373 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
374 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
375 
376 auto output = es::DropOutV3(x, shape, prob, seed, offset);
377 
378 TensorDesc x_desc;
379 x.GetProducer()->GetOutputDesc(0, x_desc);
380 x_desc.SetDataType(DT_FLOAT);
381 x_desc.SetShape(shape_x);
382 x.GetProducer()->UpdateOutputDesc(0, x_desc);
383 
384 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
385 
386 CustomPassContext pass_context;
387 DropOutV3FusionPass pass;
388 Status status = pass.Run(graph, pass_context);
389 
390 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
391}
392 
393// Test: Fusion with offset - full pattern matching
394// This test verifies the pattern StatelessDropOutGenMask(5 inputs) + DropOutDoMask can be fused to DropOutV3
395TEST_F(DropOutV3FusionPassTest, fusion_with_offset_pattern)
396{
397 SetPlatform950();
398 
399 std::vector<int64_t> dims_x{2, 4, 8, 6};
400 Shape shape_x(dims_x);
401 
402 auto graph_builder = es::EsGraphBuilder("test_with_offset");
403 
404 // Build pattern graph: StatelessDropOutGenMask + DropOutDoMask
405 // Pattern input indices:
406 // 0: shape, 1: prob, 2: seed, 3: seed1, 4: offset, 5: x, 6: keep_prob
407 
408 auto shape = graph_builder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{4});
409 auto prob = graph_builder.CreateInput(1, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
410 auto seed = graph_builder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
411 auto seed1 = graph_builder.CreateInput(3, "seed1", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
412 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
413 auto x = graph_builder.CreateInput(5, "x", DT_FLOAT, FORMAT_ND, dims_x);
414 auto keep_prob = graph_builder.CreateInput(6, "keep_prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
415 
416 // Create StatelessDropOutGenMask (5 inputs -> mask)
417 auto mask = es::StatelessDropOutGenMask(shape, prob, seed, seed1, offset);
418 
419 // Create DropOutDoMask (x, mask, keep_prob -> y)
420 auto y = es::DropOutDoMask(x, mask, keep_prob);
421 
422 // Build graph with BOTH mask and y as outputs (needed for fusion matching)
423 std::vector<es::EsTensorHolder> outputs;
424 outputs.push_back(y);
425 outputs.push_back(mask); // Include mask for pattern match
426 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset(outputs);
427 
428 // Run fusion pass
429 CustomPassContext pass_context;
430 DropOutV3FusionPass pass;
431 Status status = pass.Run(graph, pass_context);
432 
433 // Verify: SUCCESS means fusion happened
434 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
435}
436 
437// Test: High dimensional shapes
438TEST_F(DropOutV3FusionPassTest, fusion_success_high_dim)
439{
440 SetPlatform950();
441 
442 std::vector<int64_t> dims_x{2, 4, 8, 6, 2, 4};
443 Shape shape_x(dims_x);
444 
445 auto graph_builder = es::EsGraphBuilder("test");
446 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
447 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{6});
448 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
449 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
450 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
451 
452 auto output = es::DropOutV3(x, shape, prob, seed, offset);
453 
454 TensorDesc x_desc;
455 x.GetProducer()->GetOutputDesc(0, x_desc);
456 x_desc.SetDataType(DT_FLOAT);
457 x_desc.SetShape(shape_x);
458 x.GetProducer()->UpdateOutputDesc(0, x_desc);
459 
460 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
461 
462 CustomPassContext pass_context;
463 DropOutV3FusionPass pass;
464 Status status = pass.Run(graph, pass_context);
465 
466 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
467}
468 
469// Test: Large shape
470TEST_F(DropOutV3FusionPassTest, fusion_success_large_shape)
471{
472 SetPlatform950();
473 
474 std::vector<int64_t> dims_x{32, 64, 128, 64};
475 Shape shape_x(dims_x);
476 
477 auto graph_builder = es::EsGraphBuilder("test");
478 auto x = graph_builder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shape_x.GetDims());
479 auto shape = graph_builder.CreateInput(1, "shape", DT_INT64, FORMAT_ND, std::vector<int64_t>{4});
480 auto prob = graph_builder.CreateInput(2, "prob", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
481 auto seed = graph_builder.CreateInput(3, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
482 auto offset = graph_builder.CreateInput(4, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
483 
484 auto output = es::DropOutV3(x, shape, prob, seed, offset);
485 
486 TensorDesc x_desc;
487 x.GetProducer()->GetOutputDesc(0, x_desc);
488 x_desc.SetDataType(DT_FLOAT);
489 x_desc.SetShape(shape_x);
490 x.GetProducer()->UpdateOutputDesc(0, x_desc);
491 
492 std::shared_ptr<Graph> graph = graph_builder.BuildAndReset({output.y});
493 
494 CustomPassContext pass_context;
495 DropOutV3FusionPass pass;
496 Status status = pass.Run(graph, pass_context);
497 
498 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
499}
Arandom/drop_out_v3/tests/ut/op_graph/test_drop_out_v3_split_fusion_pass.cpp+345-0
@@ -0,0 +1,345 @@
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 License for details. You may not use this file except in compliance with License.
6 * THIS SOFTWARE IS PROVIDED ON AN "AS N" 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 root of the software repository for the full text of the License.
9 */
10 
11#include <iostream>
12#include <vector>
13#include <gtest/gtest.h>
14#include "platform/platform_infos_def.h"
15#include "platform/platform_info.h"
16#include "ge/es_graph_builder.h"
17#include "es_math_ops.h"
18#include "log/log.h"
19#include "random/drop_out_v3/op_graph/fusion_pass/drop_out_v3_split_fusion_pass.h"
20 
21using namespace std;
22using namespace ge;
23using namespace fe;
24using namespace fusion;
25 
26namespace {
27const std::string kPassName = "DropOutV3SplitFusionPass";
28 
29std::string DimsToString(const std::vector<int64_t>& dims)
30{
31 std::string result = "[";
32 for (size_t i = 0; i < dims.size(); i++) {
33 if (i > 0) result += ", ";
34 result += std::to_string(dims[i]);
35 }
36 result += "]";
37 return result;
38}
39 
40void UpdateDropOutV3NodeTensorDescs(GraphPtr& graph, const std::vector<int64_t>& dimsX,
41 DataType xDtype, DataType pDtype, DataType seedDtype)
42{
43 for (auto& node : graph->GetDirectNode()) {
44 AscendString nodeType;
45 node.GetType(nodeType);
46 if (std::string(nodeType.GetString()) == "DropOutV3") {
47 OP_LOGI(kPassName.c_str(), "Update DropOutV3 node TensorDescs: dimsX=%s, xDtype=%d, pDtype=%d, seedDtype=%d",
48 DimsToString(dimsX).c_str(), static_cast<int>(xDtype), static_cast<int>(pDtype), static_cast<int>(seedDtype));
49
50 TensorDesc xDesc;
51 xDesc.SetDataType(xDtype);
52 xDesc.SetShape(Shape(dimsX));
53 xDesc.SetFormat(FORMAT_ND);
54 node.UpdateInputDesc(0, xDesc);
55 
56 TensorDesc pDesc;
57 pDesc.SetDataType(pDtype);
58 pDesc.SetShape(Shape(std::vector<int64_t>{1}));
59 pDesc.SetFormat(FORMAT_ND);
60 node.UpdateInputDesc(2, pDesc);
61 
62 TensorDesc seedDesc;
63 seedDesc.SetDataType(seedDtype);
64 seedDesc.SetShape(Shape(std::vector<int64_t>{1}));
65 seedDesc.SetFormat(FORMAT_ND);
66 node.UpdateInputDesc(3, seedDesc);
67 
68 TensorDesc offsetDesc;
69 offsetDesc.SetDataType(DT_INT64);
70 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
71 offsetDesc.SetFormat(FORMAT_ND);
72 node.UpdateInputDesc(4, offsetDesc);
73 
74 TensorDesc yDesc;
75 yDesc.SetDataType(xDtype);
76 yDesc.SetShape(Shape(dimsX));
77 yDesc.SetFormat(FORMAT_ND);
78 node.UpdateOutputDesc(0, yDesc);
79
80 OP_LOGI(kPassName.c_str(), "DropOutV3 node TensorDescs updated successfully");
81 break;
82 }
83 }
84}
85}
86 
87class DropOutV3SplitFusionPassTest : public testing::Test {
88protected:
89 static void SetUpTestCase()
90 {
91 PlatformInfo platformInfo;
92 OptionalInfo optiCompilationInfo;
93 platformInfo.soc_info.ai_core_cnt = 64;
94 platformInfo.str_info.short_soc_version = "Ascend910_93";
95 optiCompilationInfo.soc_version = "Ascend910_93";
96 PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
97 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
98 }
99 
100 void SetUp() override
101 {
102 PlatformInfo platformInfo;
103 OptionalInfo optiCompilationInfo;
104 platformInfo.soc_info.ai_core_cnt = 64;
105 platformInfo.str_info.short_soc_version = "Ascend910_93";
106 optiCompilationInfo.soc_version = "Ascend910_93";
107 PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
108 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
109 }
110 
111 void SetPlatform910B()
112 {
113 PlatformInfo platformInfo;
114 OptionalInfo optiCompilationInfo;
115 platformInfo.soc_info.ai_core_cnt = 64;
116 platformInfo.str_info.short_soc_version = "Ascend910B";
117 optiCompilationInfo.soc_version = "Ascend910B";
118 PlatformInfoManager::Instance().platform_info_map_["Ascend910B"] = platformInfo;
119 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
120 }
121 
122 void SetPlatform950()
123 {
124 PlatformInfo platformInfo;
125 OptionalInfo optiCompilationInfo;
126 platformInfo.soc_info.ai_core_cnt = 64;
127 platformInfo.str_info.short_soc_version = "Ascend950";
128 optiCompilationInfo.soc_version = "Ascend950";
129 PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
130 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
131 }
132};
133 
134TEST_F(DropOutV3SplitFusionPassTest, passCreationTest)
135{
136 DropOutV3SplitFusionPass pass;
137}
138 
139TEST_F(DropOutV3SplitFusionPassTest, unsupportedPlatformFail)
140{
141 SetPlatform950();
142 
143 std::vector<int64_t> dimsX{14, 12, 16, 4, 8, 14};
144 Shape shapeX(dimsX);
145 
146 auto graphBuilder = es::EsGraphBuilder("test");
147 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shapeX.GetDims());
148 auto p = graphBuilder.CreateInput(1, "p", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
149 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
150 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
151 
152 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
153 p, seed, offset);
154 
155 TensorDesc xDesc;
156 xDesc.SetDataType(DT_FLOAT);
157 xDesc.SetShape(shapeX);
158 xDesc.SetFormat(FORMAT_ND);
159 x.GetProducer()->UpdateOutputDesc(0, xDesc);
160 
161 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
162 
163 CustomPassContext passContext;
164 DropOutV3SplitFusionPass pass;
165 Status status = pass.Run(graph, passContext);
166 
167 EXPECT_EQ(status, GRAPH_NOT_CHANGED);
168}
169 
170TEST_F(DropOutV3SplitFusionPassTest, fusionSuccess91093)
171{
172 OP_LOGI(kPassName.c_str(), "==================== fusionSuccess91093 test start ====================");
173 std::vector<int64_t> dimsX{14, 12, 16, 4, 8, 14};
174 Shape shapeX(dimsX);
175 
176 auto graphBuilder = es::EsGraphBuilder("test");
177 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shapeX.GetDims());
178 auto p = graphBuilder.CreateInput(1, "p", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
179 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
180 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
181 
182 OP_LOGI(kPassName.c_str(), "Created inputs: x[0], p[1], seed[2], offset[3] (4 inputs, noise_shape will be Const)");
183 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
184 p, seed, offset);
185 OP_LOGI(kPassName.c_str(), "Created DropOutV3 node");
186 
187 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
188 OP_LOGI(kPassName.c_str(), "Graph built with %zu nodes", graph->GetDirectNode().size());
189 
190 UpdateDropOutV3NodeTensorDescs(graph, dimsX, DT_FLOAT, DT_FLOAT, DT_INT64);
191 
192 CustomPassContext passContext;
193 DropOutV3SplitFusionPass pass;
194 OP_LOGI(kPassName.c_str(), "Run DropOutV3SplitFusionPass");
195 Status status = pass.Run(graph, passContext);
196 
197 OP_LOGI(kPassName.c_str(), "Run result: status=%d", static_cast<int>(status));
198 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
199}
200 
201TEST_F(DropOutV3SplitFusionPassTest, fusionSuccess910B)
202{
203 SetPlatform910B();
204 
205 std::vector<int64_t> dimsX{14, 12, 16, 4, 8};
206 Shape shapeX(dimsX);
207 
208 auto graphBuilder = es::EsGraphBuilder("test");
209 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shapeX.GetDims());
210 auto p = graphBuilder.CreateInput(1, "p", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
211 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
212 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
213 
214 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
215 p, seed, offset);
216 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
217 
218 UpdateDropOutV3NodeTensorDescs(graph, dimsX, DT_FLOAT, DT_FLOAT, DT_INT64);
219 
220 CustomPassContext passContext;
221 DropOutV3SplitFusionPass pass;
222 Status status = pass.Run(graph, passContext);
223 
224 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
225}
226 
227TEST_F(DropOutV3SplitFusionPassTest, fusionSuccessFp16)
228{
229 std::vector<int64_t> dimsX{14, 12, 16, 2, 8};
230 Shape shapeX(dimsX);
231 
232 auto graphBuilder = es::EsGraphBuilder("test");
233 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT16, FORMAT_ND, shapeX.GetDims());
234 auto p = graphBuilder.CreateInput(1, "p", DT_FLOAT16, FORMAT_ND, std::vector<int64_t>{1});
235 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
236 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
237 
238 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
239 p, seed, offset);
240 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
241 
242 UpdateDropOutV3NodeTensorDescs(graph, dimsX, DT_FLOAT16, DT_FLOAT16, DT_INT64);
243 
244 CustomPassContext passContext;
245 DropOutV3SplitFusionPass pass;
246 Status status = pass.Run(graph, passContext);
247 
248 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
249}
250 
251TEST_F(DropOutV3SplitFusionPassTest, fusionSuccessBf16)
252{
253 std::vector<int64_t> dimsX{14, 12, 16};
254 Shape shapeX(dimsX);
255 
256 auto graphBuilder = es::EsGraphBuilder("test");
257 auto x = graphBuilder.CreateInput(0, "x", DT_BF16, FORMAT_ND, shapeX.GetDims());
258 auto p = graphBuilder.CreateInput(1, "p", DT_BF16, FORMAT_ND, std::vector<int64_t>{1});
259 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
260 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
261 
262 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
263 p, seed, offset);
264 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
265 
266 UpdateDropOutV3NodeTensorDescs(graph, dimsX, DT_BF16, DT_BF16, DT_INT64);
267 
268 CustomPassContext passContext;
269 DropOutV3SplitFusionPass pass;
270 Status status = pass.Run(graph, passContext);
271 
272 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
273}
274 
275TEST_F(DropOutV3SplitFusionPassTest, fusionSuccessShape2)
276{
277 std::vector<int64_t> dimsX{2, 12, 8, 6};
278 Shape shapeX(dimsX);
279 
280 auto graphBuilder = es::EsGraphBuilder("test");
281 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shapeX.GetDims());
282 auto p = graphBuilder.CreateInput(1, "p", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
283 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
284 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
285 
286 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
287 p, seed, offset);
288 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
289 
290 UpdateDropOutV3NodeTensorDescs(graph, dimsX, DT_FLOAT, DT_FLOAT, DT_INT64);
291 
292 CustomPassContext passContext;
293 DropOutV3SplitFusionPass pass;
294 Status status = pass.Run(graph, passContext);
295 
296 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
297}
298 
299TEST_F(DropOutV3SplitFusionPassTest, fusionSuccessShape5)
300{
301 std::vector<int64_t> dimsX{2, 4, 8, 6, 2};
302 Shape shapeX(dimsX);
303 
304 auto graphBuilder = es::EsGraphBuilder("test");
305 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shapeX.GetDims());
306 auto p = graphBuilder.CreateInput(1, "p", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
307 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
308 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
309 
310 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
311 p, seed, offset);
312 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
313 
314 UpdateDropOutV3NodeTensorDescs(graph, dimsX, DT_FLOAT, DT_FLOAT, DT_INT64);
315 
316 CustomPassContext passContext;
317 DropOutV3SplitFusionPass pass;
318 Status status = pass.Run(graph, passContext);
319 
320 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
321}
322 
323TEST_F(DropOutV3SplitFusionPassTest, fusionSuccessSeedInt32)
324{
325 std::vector<int64_t> dimsX{16, 18};
326 Shape shapeX(dimsX);
327 
328 auto graphBuilder = es::EsGraphBuilder("test");
329 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_ND, shapeX.GetDims());
330 auto p = graphBuilder.CreateInput(1, "p", DT_FLOAT, FORMAT_ND, std::vector<int64_t>{1});
331 auto seed = graphBuilder.CreateInput(2, "seed", DT_INT32, FORMAT_ND, std::vector<int64_t>{1});
332 auto offset = graphBuilder.CreateInput(3, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{1});
333 
334 auto output = es::DropOutV3(x, graphBuilder.CreateConst(dimsX, std::vector<int64_t>{static_cast<int64_t>(dimsX.size())}, DT_INT64, FORMAT_ND),
335 p, seed, offset);
336 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output.y, output.mask});
337 
338 UpdateDropOutV3NodeTensorDescs(graph, dimsX, DT_FLOAT, DT_FLOAT, DT_INT32);
339 
340 CustomPassContext passContext;
341 DropOutV3SplitFusionPass pass;
342 Status status = pass.Run(graph, passContext);
343 
344EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
345}
Drandom/stateless_bernoulli/op_graph/CMakeLists.txt+0-11
@@ -1,11 +0,0 @@
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 
11add_graph_plugin_sources()
Arandom/stateless_bernoulli/op_graph/fusion_pass/stateless_bernoulli_fusion_pass.cpp+191-0
@@ -0,0 +1,191 @@
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 * \file stateless_bernoulli_fusion_pass.cpp
13 * \brief bernoulli fusion pass (StatelessBernoulliV2 --> StatelessBernoulli)
14 */
15 
16#include <vector>
17#include <string>
18#include <algorithm>
19#include "es_math_ops.h"
20#include "platform/platform_info.h"
21#include "ge/ge_utils.h"
22#include "log/log.h"
23#include "stateless_bernoulli_fusion_pass.h"
24 
25using namespace ge;
L
Lllimwang4月14日

三个 using namespace 声明(ge、fe、fusion)放在了 namespace ops 外面(第 37-39 行),而 drop_out_v3 的 fusion pass 将 using namespace 放在 namespace ops 内部。放在外面会污染全局命名空间,如果其他编译单元同时链接可能导致符号冲突。建议移到 namespace ops 内部,与 drop_out_v3 保持一致。

likedislike
26using namespace fe;
27 
28namespace ge::fusion {
29 
30namespace {
31const std::string kPassName = "BernoulliFusionPass";
32constexpr int64_t kCaptureIdxV2Node = 0l;
33 
34std::vector<int64_t> GetShapeDims(const Shape& shape)
35{
36 std::vector<int64_t> dims;
37 for (size_t i = 0; i < shape.GetDimNum(); i++) {
38 dims.push_back(shape.GetDim(i));
39 }
40 return dims;
41}
42 
43Status InferShape(const GraphUniqPtr& replaceGraph, const std::vector<SubgraphInput>& subgraphInputs)
44{
45 std::vector<Shape> inputShapes;
46 for (const auto& subgraphInput : subgraphInputs) {
47 auto matchNode = subgraphInput.GetAllInputs().at(0);
48 TensorDesc tensorDesc;
49 matchNode.node.GetInputDesc(matchNode.index, tensorDesc);
50 inputShapes.emplace_back(tensorDesc.GetShape());
51 }
52 return GeUtils::InferShape(*replaceGraph, inputShapes);
53}
54 
55void UpdateNodeOutputDesc(es::EsTensorHolder& tensor, DataType dtype, const Shape& shape, Format fmt)
56{
57 TensorDesc desc;
58 desc.SetDataType(dtype);
59 desc.SetShape(shape);
60 desc.SetFormat(fmt);
61 tensor.GetProducer()->UpdateOutputDesc(0, desc);
62}
63 
64bool CheckPlatform(const std::string& soc)
65{
66 return (soc == "Ascend910_93" || soc == "Ascend950");
67}
68 
69bool CheckDtype(DataType dtype, const std::vector<DataType>& validTypes)
70{
71 return std::find(validTypes.begin(), validTypes.end(), dtype) != validTypes.end();
72}
73} // namespace
74 
75std::vector<PatternUniqPtr> BernoulliFusionPass::Patterns()
76{
77 OP_LOGI(kPassName.c_str(), "Enter Patterns");
78 std::vector<PatternUniqPtr> patternGraphs;
79 
80 auto graphBuilder = es::EsGraphBuilder(kPassName.c_str());
81 auto x = graphBuilder.CreateInput(0);
82 auto seed = graphBuilder.CreateInput(1);
83 auto offset = graphBuilder.CreateInput(2);
84 
85 auto output = es::StatelessBernoulliV2(x, seed, offset);
86 auto graph = graphBuilder.BuildAndReset({output});
87 
88 auto pattern = std::make_unique<Pattern>(std::move(*graph));
89 pattern->CaptureTensor({*output.GetProducer(), 0});
90 patternGraphs.emplace_back(std::move(pattern));
91 return patternGraphs;
92}
93 
94bool BernoulliFusionPass::MeetRequirements(const std::unique_ptr<MatchResult>& matchResult)
95{
96 OP_LOGI(kPassName.c_str(), "Enter MeetRequirements");
97 
98 PlatformInfo platformInfo;
99 OptionalInfo optionalInfo;
100 if (PlatformInfoManager::Instance().GetPlatformInfoWithOutSocVersion(platformInfo, optionalInfo) != SUCCESS) {
101 OP_LOGE(kPassName.c_str(), "Get platformInfo failed.");
102 return false;
103 }
104 if (!CheckPlatform(platformInfo.str_info.short_soc_version)) {
105 return false;
106 }
107 
108 NodeIo v2NodeIo;
109 if (matchResult->GetCapturedTensor(kCaptureIdxV2Node, v2NodeIo) != SUCCESS) {
110 OP_LOGE(kPassName.c_str(), "Failed to GetCaptured tensor");
111 return false;
112 }
113 
114 AscendString nodeTypeStr;
115 v2NodeIo.node.GetType(nodeTypeStr);
116 if (std::string(nodeTypeStr.GetString()) != "StatelessBernoulliV2") {
117 return false;
118 }
119 
120 TensorDesc inputDesc;
121 v2NodeIo.node.GetInputDesc(0, inputDesc);
122 if (!CheckDtype(inputDesc.GetDataType(), {DT_FLOAT16, DT_FLOAT})) {
123 return false;
124 }
125 
126 auto dimNum = inputDesc.GetShape().GetDimNum();
127 if (dimNum == 0) {
128 OP_LOGI(kPassName.c_str(), "Input shape dimNum is 0 (unknown rank), not supported by ES API CreateConst");
129 return false;
130 }
131 return true;
132}
133 
134std::unique_ptr<Graph> BernoulliFusionPass::Replacement(const std::unique_ptr<MatchResult>& matchResult)
135{
136 OP_LOGI(kPassName.c_str(), "Enter Replacement");
137 
138 NodeIo v2NodeIo;
139 if (matchResult->GetCapturedTensor(kCaptureIdxV2Node, v2NodeIo) != SUCCESS) {
140 OP_LOGE(kPassName.c_str(), "Failed to GetCaptured tensor in Replacement");
141 return nullptr;
142 }
143 
144 DataType dtype = DT_FLOAT;
145 v2NodeIo.node.GetAttr("dtype", dtype);
146 if (dtype == DT_UNDEFINED) {
147 dtype = DT_FLOAT;
148 }
149 
150 TensorDesc probDesc;
151 v2NodeIo.node.GetInputDesc(0, probDesc);
152 TensorDesc seedDesc;
153 v2NodeIo.node.GetInputDesc(1, seedDesc);
154 TensorDesc offsetDesc;
155 v2NodeIo.node.GetInputDesc(2, offsetDesc);
156 
157 auto replaceGraphBuilder = es::EsGraphBuilder("replacement");
158 auto rProb = replaceGraphBuilder.CreateInput(0, "prob", probDesc.GetDataType(), probDesc.GetFormat(),
159 GetShapeDims(probDesc.GetShape()));
160 rProb.SetFormat(probDesc.GetFormat());
161 auto rSeed = replaceGraphBuilder.CreateInput(1, "seed", seedDesc.GetDataType(), seedDesc.GetFormat(),
162 GetShapeDims(seedDesc.GetShape()));
163 rSeed.SetFormat(seedDesc.GetFormat());
164 auto rOffset = replaceGraphBuilder.CreateInput(2, "offset", offsetDesc.GetDataType(), offsetDesc.GetFormat(),
165 GetShapeDims(offsetDesc.GetShape()));
166 rOffset.SetFormat(offsetDesc.GetFormat());
167 
168 std::vector<int64_t> shapeValue = GetShapeDims(probDesc.GetShape());
169 std::vector<int64_t> shapeDims = {static_cast<int64_t>(shapeValue.size())};
170 auto rShape = replaceGraphBuilder.CreateConst(shapeValue, shapeDims, DT_INT64, FORMAT_ND);
171
172 auto output = es::StatelessBernoulli(rShape, rProb, rSeed, rOffset, dtype);
173 
biabu
biabubiabu4月22日

少了个刷新format

likedislike
174 UpdateNodeOutputDesc(rProb, probDesc.GetDataType(), probDesc.GetShape(), probDesc.GetFormat());
175 UpdateNodeOutputDesc(rSeed, seedDesc.GetDataType(), seedDesc.GetShape(), seedDesc.GetFormat());
176 UpdateNodeOutputDesc(rOffset, offsetDesc.GetDataType(), offsetDesc.GetShape(), offsetDesc.GetFormat());
177 UpdateNodeOutputDesc(output, dtype, probDesc.GetShape(), probDesc.GetFormat());
178 
179 std::vector<SubgraphInput> subgraphInputs;
180 matchResult->ToSubgraphBoundary()->GetAllInputs(subgraphInputs);
181 GraphUniqPtr replaceGraph = replaceGraphBuilder.BuildAndReset({output});
182 if (InferShape(replaceGraph, subgraphInputs) != SUCCESS) {
183 OP_LOGE(kPassName.c_str(), "Infershape failed.");
184 return nullptr;
185 }
186 return replaceGraph;
187}
188 
189REG_FUSION_PASS(BernoulliFusionPass).Stage(CustomPassStage::kCompatibleInherited);
190 
191} // namespace ge::fusion
Arandom/stateless_bernoulli/op_graph/fusion_pass/stateless_bernoulli_fusion_pass.h+35-0
@@ -0,0 +1,35 @@
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 * \file stateless_bernoulli_fusion_pass.h
13 * \brief StatelessBernoulli fusion pass: StatelessBernoulliV2 -> StatelessBernoulli
14 */
15 
16#ifndef OPS_MATH_STATELESS_BERNOULLI_FUSION_PASS_H_
17#define OPS_MATH_STATELESS_BERNOULLI_FUSION_PASS_H_
18 
19#include "ge/fusion/pass/pattern_fusion_pass.h"
20 
21namespace ge::fusion {
22using namespace ge;
23 
24class __attribute__((visibility("default"))) BernoulliFusionPass : public PatternFusionPass {
25protected:
26 std::vector<PatternUniqPtr> Patterns() override;
27 
28 bool MeetRequirements(const std::unique_ptr<MatchResult>& matchResult) override;
29 
30 std::unique_ptr<Graph> Replacement(const std::unique_ptr<MatchResult>& matchResult) override;
31};
32 
33} // namespace ge::fusion
34 
35#endif
Arandom/stateless_bernoulli/tests/ut/op_graph/test_stateless_bernoulli_fusion_pass.cpp+558-0
@@ -0,0 +1,558 @@
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 OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
7 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See
8 * LICENSE in the root of the software repository for the full text of the License.
9 */
10 
11#include <iostream>
12#include <vector>
13#include "gtest/gtest.h"
14#include "platform/platform_infos_def.h"
15#include "platform/platform_info.h"
16#include "ge/es_graph_builder.h"
17#include "es_math_ops.h"
18#include "log/log.h"
19#include "../../../op_graph/fusion_pass/stateless_bernoulli_fusion_pass.h"
20 
21using namespace std;
22using namespace ge;
23using namespace fe;
24using namespace fusion;
25 
26namespace {
27const std::string kPassName = "BernoulliFusionPass";
28}
29 
30class BernoulliFusionPassTest : public testing::Test {
31protected:
32 static void SetUpTestCase()
33 {
34 PlatformInfo platformInfo;
35 OptionalInfo optiCompilationInfo;
36 platformInfo.soc_info.ai_core_cnt = 64;
37 platformInfo.str_info.short_soc_version = "Ascend910_93";
38 optiCompilationInfo.soc_version = "Ascend910_93";
39 PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
40 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
41 }
42 
43 void SetUp() override
44 {
45 PlatformInfo platformInfo;
46 OptionalInfo optiCompilationInfo;
47 platformInfo.soc_info.ai_core_cnt = 64;
48 platformInfo.str_info.short_soc_version = "Ascend910_93";
49 optiCompilationInfo.soc_version = "Ascend910_93";
50 PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
51 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
52 }
53 
54 void SetPlatform950()
55 {
56 PlatformInfo platformInfo;
57 OptionalInfo optiCompilationInfo;
58 platformInfo.soc_info.ai_core_cnt = 64;
59 platformInfo.str_info.short_soc_version = "Ascend950";
60 optiCompilationInfo.soc_version = "Ascend950";
61 PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
62 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
63 }
64 
65 void SetPlatform91093()
66 {
67 PlatformInfo platformInfo;
68 OptionalInfo optiCompilationInfo;
69 platformInfo.soc_info.ai_core_cnt = 64;
70 platformInfo.str_info.short_soc_version = "Ascend910_93";
71 optiCompilationInfo.soc_version = "Ascend910_93";
72 PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
73 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
74 }
75};
76 
77TEST_F(BernoulliFusionPassTest, patternTest)
78{
79 BernoulliFusionPass pass;
80 std::vector<PatternUniqPtr> patterns = pass.Patterns();
81 EXPECT_GT(patterns.size(), 0);
82}
83 
84TEST_F(BernoulliFusionPassTest, unsupportedPlatformFail)
85{
86 PlatformInfo platformInfo;
87 OptionalInfo optiCompilationInfo;
88 platformInfo.soc_info.ai_core_cnt = 64;
89 platformInfo.str_info.short_soc_version = "Ascend910";
90 optiCompilationInfo.soc_version = "Ascend910";
91 PlatformInfoManager::Instance().platform_info_map_["Ascend910"] = platformInfo;
92 PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
93 
94 std::vector<int64_t> dimsX{-1, 3, 5, 4};
95 Shape shapeX(dimsX);
96 
97 auto graphBuilder = es::EsGraphBuilder("test");
98 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCHW, shapeX.GetDims());
99 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
100 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
101 
102 auto output = es::StatelessBernoulliV2(x, seed, offset);
103 
104 TensorDesc xDesc;
105 x.GetProducer()->GetOutputDesc(0, xDesc);
106 xDesc.SetDataType(DT_FLOAT16);
107 xDesc.SetShape(shapeX);
108 xDesc.SetFormat(FORMAT_NCHW);
109 x.GetProducer()->UpdateOutputDesc(0, xDesc);
110 
111 TensorDesc seedDesc;
112 seed.GetProducer()->GetOutputDesc(0, seedDesc);
113 seedDesc.SetDataType(DT_INT64);
114 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
115 seedDesc.SetFormat(FORMAT_ND);
116 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
117 
118 TensorDesc offsetDesc;
119 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
120 offsetDesc.SetDataType(DT_INT64);
121 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
122 offsetDesc.SetFormat(FORMAT_ND);
123 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
124 
125 
126 output.GetProducer()->UpdateInputDesc(0, xDesc);
127 output.GetProducer()->UpdateInputDesc(1, seedDesc);
128 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
129 
130 
131 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
132 
133 CustomPassContext passContext;
134 BernoulliFusionPass pass;
135 Status status = pass.Run(graph, passContext);
136 
137 EXPECT_EQ(status, GRAPH_NOT_CHANGED);
138}
139 
140TEST_F(BernoulliFusionPassTest, fusionSuccessFp16On950)
141{
142 SetPlatform950();
143 
144 std::vector<int64_t> dimsX{-1, 3, 5, 4};
145 Shape shapeX(dimsX);
146 
147 auto graphBuilder = es::EsGraphBuilder("test");
148 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCHW, shapeX.GetDims());
149 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
150 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
151 
152 auto output = es::StatelessBernoulliV2(x, seed, offset);
153 
154 TensorDesc xDesc;
155 x.GetProducer()->GetOutputDesc(0, xDesc);
156 xDesc.SetDataType(DT_FLOAT16);
157 xDesc.SetShape(shapeX);
158 xDesc.SetFormat(FORMAT_NCHW);
159 x.GetProducer()->UpdateOutputDesc(0, xDesc);
160 
161 TensorDesc seedDesc;
162 seed.GetProducer()->GetOutputDesc(0, seedDesc);
163 seedDesc.SetDataType(DT_INT64);
164 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
165 seedDesc.SetFormat(FORMAT_ND);
166 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
167 
168 TensorDesc offsetDesc;
169 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
170 offsetDesc.SetDataType(DT_INT64);
171 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
172 offsetDesc.SetFormat(FORMAT_ND);
173 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
174 TensorDesc outputDesc;
175 output.GetProducer()->GetOutputDesc(0, outputDesc);
176 outputDesc.SetDataType(DT_FLOAT16);
177 outputDesc.SetShape(shapeX);
178 outputDesc.SetFormat(FORMAT_NCHW);
179 output.GetProducer()->UpdateOutputDesc(0, outputDesc);
180 
181 output.GetProducer()->UpdateInputDesc(0, xDesc);
182 output.GetProducer()->UpdateInputDesc(1, seedDesc);
183 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
184 
185 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
186 
187 CustomPassContext passContext;
188 BernoulliFusionPass pass;
189 Status status = pass.Run(graph, passContext);
190 
191 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
192 
193 bool isFound = false;
194 for (auto node : graph->GetAllNodes()) {
195 AscendString type;
196 node.GetType(type);
197 if (type == "StatelessBernoulli") {
198 isFound = true;
199 break;
200 }
201 }
202 EXPECT_TRUE(isFound);
203}
204 
205TEST_F(BernoulliFusionPassTest, fusionSuccessFp16On91093)
206{
207 SetPlatform91093();
208 
209 std::vector<int64_t> dimsX{-1, 3, 5, 4};
210 Shape shapeX(dimsX);
211 
212 auto graphBuilder = es::EsGraphBuilder("test");
213 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCHW, shapeX.GetDims());
214 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
215 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
216 
217 auto output = es::StatelessBernoulliV2(x, seed, offset);
218 
219 TensorDesc xDesc;
220 x.GetProducer()->GetOutputDesc(0, xDesc);
221 xDesc.SetDataType(DT_FLOAT16);
222 xDesc.SetShape(shapeX);
223 xDesc.SetFormat(FORMAT_NCHW);
224 x.GetProducer()->UpdateOutputDesc(0, xDesc);
225 
226 TensorDesc seedDesc;
227 seed.GetProducer()->GetOutputDesc(0, seedDesc);
228 seedDesc.SetDataType(DT_INT64);
229 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
230 seedDesc.SetFormat(FORMAT_ND);
231 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
232 
233 TensorDesc offsetDesc;
234 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
235 offsetDesc.SetDataType(DT_INT64);
236 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
237 offsetDesc.SetFormat(FORMAT_ND);
238 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
239 
240 
241 output.GetProducer()->UpdateInputDesc(0, xDesc);
242 output.GetProducer()->UpdateInputDesc(1, seedDesc);
243 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
244 
245 
246 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
247 
248 CustomPassContext passContext;
249 BernoulliFusionPass pass;
250 Status status = pass.Run(graph, passContext);
251 
252 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
253 
254 bool isFound = false;
255 for (auto node : graph->GetAllNodes()) {
256 AscendString type;
257 node.GetType(type);
258 if (type == "StatelessBernoulli") {
259 isFound = true;
260 break;
261 }
262 }
263 EXPECT_TRUE(isFound);
264}
265 
266TEST_F(BernoulliFusionPassTest, fusionSuccessFp32)
267{
268 SetPlatform950();
269 
270 std::vector<int64_t> dimsX{-1, 3, 5, 4};
271 Shape shapeX(dimsX);
272 
273 auto graphBuilder = es::EsGraphBuilder("test");
274 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_NCHW, shapeX.GetDims());
275 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
276 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
277 
278 auto output = es::StatelessBernoulliV2(x, seed, offset);
279 
280 TensorDesc xDesc;
281 x.GetProducer()->GetOutputDesc(0, xDesc);
282 xDesc.SetDataType(DT_FLOAT);
283 xDesc.SetShape(shapeX);
284 xDesc.SetFormat(FORMAT_NCHW);
285 x.GetProducer()->UpdateOutputDesc(0, xDesc);
286 
287 TensorDesc seedDesc;
288 seed.GetProducer()->GetOutputDesc(0, seedDesc);
289 seedDesc.SetDataType(DT_INT64);
290 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
291 seedDesc.SetFormat(FORMAT_ND);
292 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
293 
294 TensorDesc offsetDesc;
295 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
296 offsetDesc.SetDataType(DT_INT64);
297 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
298 offsetDesc.SetFormat(FORMAT_ND);
299 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
300 
301 
302 output.GetProducer()->UpdateInputDesc(0, xDesc);
303 output.GetProducer()->UpdateInputDesc(1, seedDesc);
304 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
305 
306 
307 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
308 
309 CustomPassContext passContext;
310 BernoulliFusionPass pass;
311 Status status = pass.Run(graph, passContext);
312 
313 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
314 
315 bool isFound = false;
316 for (auto node : graph->GetAllNodes()) {
317 AscendString type;
318 node.GetType(type);
319 if (type == "StatelessBernoulli") {
320 isFound = true;
321 break;
322 }
323 }
324 EXPECT_TRUE(isFound);
325}
326 
327TEST_F(BernoulliFusionPassTest, fusionSuccessInt64Dtype)
328{
329 SetPlatform950();
330 
331 std::vector<int64_t> dimsX{-1, 3, 5, 4};
332 Shape shapeX(dimsX);
333 
334 auto graphBuilder = es::EsGraphBuilder("test");
335 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCHW, shapeX.GetDims());
336 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
337 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
338 
339 auto output = es::StatelessBernoulliV2(x, seed, offset, DT_INT64);
340 
341 TensorDesc xDesc;
342 x.GetProducer()->GetOutputDesc(0, xDesc);
343 xDesc.SetDataType(DT_FLOAT16);
344 xDesc.SetShape(shapeX);
345 xDesc.SetFormat(FORMAT_NCHW);
346 x.GetProducer()->UpdateOutputDesc(0, xDesc);
347 
348 TensorDesc seedDesc;
349 seed.GetProducer()->GetOutputDesc(0, seedDesc);
350 seedDesc.SetDataType(DT_INT64);
351 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
352 seedDesc.SetFormat(FORMAT_ND);
353 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
354 
355 TensorDesc offsetDesc;
356 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
357 offsetDesc.SetDataType(DT_INT64);
358 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
359 offsetDesc.SetFormat(FORMAT_ND);
360 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
361 
362 
363 output.GetProducer()->UpdateInputDesc(0, xDesc);
364 output.GetProducer()->UpdateInputDesc(1, seedDesc);
365 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
366 
367 
368 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
369 
370 CustomPassContext passContext;
371 BernoulliFusionPass pass;
372 Status status = pass.Run(graph, passContext);
373 
374 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
375 
376 bool isFound = false;
377 for (auto node : graph->GetAllNodes()) {
378 AscendString type;
379 node.GetType(type);
380 if (type == "StatelessBernoulli") {
381 isFound = true;
382 break;
383 }
384 }
385 EXPECT_TRUE(isFound);
386}
387 
388TEST_F(BernoulliFusionPassTest, fusionFailUnknownRank)
389{
390 SetPlatform950();
391 
392 std::vector<int64_t> dimsX{-2};
393 Shape shapeX(dimsX);
394 
395 auto graphBuilder = es::EsGraphBuilder("test");
396 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCHW, shapeX.GetDims());
397 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
398 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
399 
400 auto output = es::StatelessBernoulliV2(x, seed, offset, DT_INT64);
401 
402 TensorDesc xDesc;
403 x.GetProducer()->GetOutputDesc(0, xDesc);
404 xDesc.SetDataType(DT_FLOAT16);
405 xDesc.SetShape(shapeX);
406 xDesc.SetFormat(FORMAT_NCHW);
407 x.GetProducer()->UpdateOutputDesc(0, xDesc);
408 
409 TensorDesc seedDesc;
410 seed.GetProducer()->GetOutputDesc(0, seedDesc);
411 seedDesc.SetDataType(DT_INT64);
412 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
413 seedDesc.SetFormat(FORMAT_ND);
414 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
415 
416 TensorDesc offsetDesc;
417 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
418 offsetDesc.SetDataType(DT_INT64);
419 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
420 offsetDesc.SetFormat(FORMAT_ND);
421 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
422 
423 
424 output.GetProducer()->UpdateInputDesc(0, xDesc);
425 output.GetProducer()->UpdateInputDesc(1, seedDesc);
426 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
427 
428 
429 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
430 
431 CustomPassContext passContext;
432 BernoulliFusionPass pass;
433 Status status = pass.Run(graph, passContext);
434 
435 EXPECT_EQ(status, GRAPH_NOT_CHANGED);
436}
437 
438TEST_F(BernoulliFusionPassTest, fusionSuccessLargeShape)
439{
440 SetPlatform950();
441 
442 std::vector<int64_t> dimsX{-1, 7, 8, 6};
443 Shape shapeX(dimsX);
444 
445 auto graphBuilder = es::EsGraphBuilder("test");
446 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT, FORMAT_NCHW, shapeX.GetDims());
447 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
448 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
449 
450 auto output = es::StatelessBernoulliV2(x, seed, offset, DT_INT64);
451 
452 TensorDesc xDesc;
453 x.GetProducer()->GetOutputDesc(0, xDesc);
454 xDesc.SetDataType(DT_FLOAT);
455 xDesc.SetShape(shapeX);
456 xDesc.SetFormat(FORMAT_NCHW);
457 x.GetProducer()->UpdateOutputDesc(0, xDesc);
458 
459 TensorDesc seedDesc;
460 seed.GetProducer()->GetOutputDesc(0, seedDesc);
461 seedDesc.SetDataType(DT_INT64);
462 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
463 seedDesc.SetFormat(FORMAT_ND);
464 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
465 
466 TensorDesc offsetDesc;
467 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
468 offsetDesc.SetDataType(DT_INT64);
469 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
470 offsetDesc.SetFormat(FORMAT_ND);
471 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
472 
473 
474 output.GetProducer()->UpdateInputDesc(0, xDesc);
475 output.GetProducer()->UpdateInputDesc(1, seedDesc);
476 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
477 
478 
479 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
480 
481 CustomPassContext passContext;
482 BernoulliFusionPass pass;
483 Status status = pass.Run(graph, passContext);
484 
485 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
486 
487 bool isFound = false;
488 for (auto node : graph->GetAllNodes()) {
489 AscendString type;
490 node.GetType(type);
491 if (type == "StatelessBernoulli") {
492 isFound = true;
493 break;
494 }
495 }
496 EXPECT_TRUE(isFound);
497}
498 
499TEST_F(BernoulliFusionPassTest, fusionSuccessHighDim)
500{
501 SetPlatform950();
502 
503 std::vector<int64_t> dimsX{-1, 3, 5, 4, 4, 2, 2};
504 Shape shapeX(dimsX);
505 
506 auto graphBuilder = es::EsGraphBuilder("test");
507 auto x = graphBuilder.CreateInput(0, "x", DT_FLOAT16, FORMAT_NCHW, shapeX.GetDims());
508 auto seed = graphBuilder.CreateInput(1, "seed", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
509 auto offset = graphBuilder.CreateInput(2, "offset", DT_INT64, FORMAT_ND, std::vector<int64_t>{2});
510 
511 auto output = es::StatelessBernoulliV2(x, seed, offset, DT_INT64);
512 
513 TensorDesc xDesc;
514 x.GetProducer()->GetOutputDesc(0, xDesc);
515 xDesc.SetDataType(DT_FLOAT16);
516 xDesc.SetShape(shapeX);
517 xDesc.SetFormat(FORMAT_NCHW);
518 x.GetProducer()->UpdateOutputDesc(0, xDesc);
519 
520 TensorDesc seedDesc;
521 seed.GetProducer()->GetOutputDesc(0, seedDesc);
522 seedDesc.SetDataType(DT_INT64);
523 seedDesc.SetShape(Shape(std::vector<int64_t>{2}));
524 seedDesc.SetFormat(FORMAT_ND);
525 seed.GetProducer()->UpdateOutputDesc(0, seedDesc);
526 
527 TensorDesc offsetDesc;
528 offset.GetProducer()->GetOutputDesc(0, offsetDesc);
529 offsetDesc.SetDataType(DT_INT64);
530 offsetDesc.SetShape(Shape(std::vector<int64_t>{2}));
531 offsetDesc.SetFormat(FORMAT_ND);
532 offset.GetProducer()->UpdateOutputDesc(0, offsetDesc);
533 
534 
535 output.GetProducer()->UpdateInputDesc(0, xDesc);
536 output.GetProducer()->UpdateInputDesc(1, seedDesc);
537 output.GetProducer()->UpdateInputDesc(2, offsetDesc);
538 
539 
540 std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
541 
542 CustomPassContext passContext;
543 BernoulliFusionPass pass;
544 Status status = pass.Run(graph, passContext);
545 
546 EXPECT_TRUE(status == SUCCESS || status == GRAPH_NOT_CHANGED);
547 
548 bool isFound = false;
549 for (auto node : graph->GetAllNodes()) {
550 AscendString type;
551 node.GetType(type);
552 if (type == "StatelessBernoulli") {
553 isFound = true;
554 break;
555 }
556 }
557 EXPECT_TRUE(isFound);
558}