已合并
[CANNBot] 迁移RandomStandardNormal融合规则到新pass框架 #2420
xuejinghui创建于 4月24日
[CANNBot] 迁移RandomStandardNormal融合规则到新pass框架 #2420
已合并
xuejinghui创建于 4月24日
已删除 :fussion-pass合入到cann/ops-mathmaster
5 个文件变更+565-2
@@ -156,6 +156,7 @@ function(add_op_graph_ut_modules OP_GRAPH_MODULE_NAME)
156 gtest156 gtest
157 register157 register
158 ge_compiler158 ge_compiler
159+ ge_common
159 )160 )
160 161 
161 target_compile_options(162 target_compile_options(
@@ -0,0 +1,210 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file random_standard_normal_fusion_pass.cpp
13+ * \brief RandomStandardNormal fusion pass (RandomStandardNormal --> RandomStandardNormalV2)
14+ *
15+ * Pattern:
16+ * shape shape offset(const 0)
17+ * | | /
18+ * RandomStandardNormal ==> RandomStandardNormalV2
19+ * | | \
20+ * output output offset
21+ *
22+ * The key transformation:
23+ * - RandomStandardNormal has 1 input: shape, 1 output: y
24+ * - RandomStandardNormalV2 has 2 inputs: shape + offset, 2 outputs: y + offset
25+ * - An offset constant (value 0, dtype int64) is created as the additional input
26+ * - Attributes seed, seed2, dtype are transferred to the new node
27+ */
28+ 
29+#include <vector>
30+#include <string>
31+#include <set>
32+#include "es_math_ops.h"
33+#include "platform/platform_info.h"
34+#include "ge/ge_utils.h"
35+#include "log/log.h"
36+#include "random_standard_normal_fusion_pass.h"
37+ 
38+using namespace ge;
39+using namespace ge::fusion;
40+using namespace fe;
41+ 
42+namespace ops {
43+ 
44+static const std::string kPassName = "RandomStandardNormalFusionPass";
45+static const int64_t kCaptureIdx = 0L;
46+ 
47+static const std::set<ge::DataType> kSupportedDtypes = {ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16};
48+ 
49+static void GetInputsInfo(const std::vector<SubgraphInput>& subgraphInputs,
50+ std::vector<Shape>& inputShapes,
51+ std::vector<DataType>& inputDtypes,
52+ std::vector<Format>& inputFormats)
53+{
54+ for (const auto& subgraphInput : subgraphInputs) {
55+ auto matchNode = subgraphInput.GetAllInputs().at(0);
56+ TensorDesc tensorDesc;
57+ matchNode.node.GetInputDesc(matchNode.index, tensorDesc);
58+ inputShapes.emplace_back(tensorDesc.GetShape());
59+ inputDtypes.emplace_back(tensorDesc.GetDataType());
60+ inputFormats.emplace_back(tensorDesc.GetFormat());
61+ }
62+}
63+ 
64+std::vector<PatternUniqPtr> RandomStandardNormalFusionPass::Patterns()
65+{
66+ OP_LOGD(kPassName.c_str(), "Enter Patterns for RandomStandardNormalFusionPass");
67+ std::vector<PatternUniqPtr> patternGraphs;
68+ 
69+ auto graphBuilder = es::EsGraphBuilder(kPassName.c_str());
70+ auto shape = graphBuilder.CreateInput(0);
71+ 
72+ auto graphPtr = graphBuilder.GetCGraphBuilder()->GetGraph();
73+ auto srcBuilder = es::CompliantNodeBuilder(graphPtr);
74+ srcBuilder.OpType("RandomStandardNormal")
75+ .Name("pattern_random_standard_normal")
76+ .IrDefInputs({{"shape", es::CompliantNodeBuilder::kEsIrInputRequired, ""}})
77+ .IrDefOutputs({{"y", es::CompliantNodeBuilder::kEsIrOutputRequired, ""}})
78+ .IrDefAttrs({
79+ {"seed", es::CompliantNodeBuilder::kEsAttrOptional, "Int", es::CreateFrom(static_cast<int64_t>(0))},
80+ {"seed2", es::CompliantNodeBuilder::kEsAttrOptional, "Int", es::CreateFrom(static_cast<int64_t>(0))},
81+ {"dtype", es::CompliantNodeBuilder::kEsAttrOptional, "Type", es::CreateFrom(DT_FLOAT)}
82+ });
83+ GNode srcNode = srcBuilder.Build();
84+ 
85+ auto dataNode = shape.GetProducer();
86+ if (dataNode != nullptr) {
87+ es::AddEdgeAndUpdatePeerDesc(*graphPtr, *dataNode, 0, srcNode, 0);
88+ }
89+ 
90+ es::EsGraphBuilder::SetOutput(shape, 0);
91+ auto graph = graphBuilder.BuildAndReset();
92+ 
93+ std::vector<std::pair<GNode, int32_t>> outputs = {{srcNode, 0}};
94+ graph->SetOutputs(outputs);
95+ 
96+ auto pattern = std::make_unique<Pattern>(std::move(*graph));
97+ pattern->CaptureTensor({srcNode, 0});
98+ 
99+ patternGraphs.emplace_back(std::move(pattern));
100+ return patternGraphs;
101+}
102+ 
103+ 
104+bool RandomStandardNormalFusionPass::MeetRequirements(const std::unique_ptr<MatchResult>& matchResult)
105+{
106+ OP_LOGD(kPassName.c_str(), "Enter MeetRequirements for RandomStandardNormalFusionPass");
107+ 
108+ // 1. Platform check - regbase architectures only
109+ PlatformInfo platformInfo;
110+ OptionalInfo optionalInfo;
111+ if (PlatformInfoManager::Instance().GetPlatformInfoWithOutSocVersion(platformInfo, optionalInfo) != SUCCESS) {
112+ OP_LOGE(kPassName.c_str(), "Get platform info failed.");
113+ return false;
114+ }
115+ const std::string soc = platformInfo.str_info.short_soc_version;
116+ if (soc != "Ascend950") {
117+ OP_LOGD(kPassName.c_str(), "Platform %s is not supported, skip.", soc.c_str());
118+ return false;
119+ }
120+ 
121+ // 2. Get captured RandomStandardNormal node
122+ NodeIo nodeIo;
123+ if (matchResult->GetCapturedTensor(kCaptureIdx, nodeIo) != SUCCESS) {
124+ OP_LOGE(kPassName.c_str(), "Failed to get captured tensor.");
125+ return false;
126+ }
127+ 
128+ // 3. Check dtype attribute
129+ ge::DataType dtype = ge::DT_FLOAT;
130+ if (nodeIo.node.GetAttr("dtype", dtype) != GRAPH_SUCCESS) {
131+ OP_LOGD(kPassName.c_str(), "Failed to get dtype attribute, using default DT_FLOAT.");
132+ }
133+ if (kSupportedDtypes.count(dtype) == 0) {
134+ OP_LOGD(kPassName.c_str(),
135+ "RandomStandardNormalV2 dtype only supports float32/float16/bfloat16, got %d, skip.",
136+ static_cast<int32_t>(dtype));
137+ return false;
138+ }
139+ 
140+ return true;
141+}
142+ 
143+std::unique_ptr<Graph> RandomStandardNormalFusionPass::Replacement(const std::unique_ptr<MatchResult>& matchResult)
144+{
145+ OP_LOGD(kPassName.c_str(), "Enter Replacement for RandomStandardNormalFusionPass");
146+ 
147+ std::vector<SubgraphInput> subgraphInputs;
148+ matchResult->ToSubgraphBoundary()->GetAllInputs(subgraphInputs);
149+ 
150+ if (subgraphInputs.empty()) {
151+ OP_LOGE(kPassName.c_str(), "SubgraphInputs is empty, cannot get input info.");
152+ return nullptr;
153+ }
154+ 
155+ std::vector<Shape> inputShapes;
156+ std::vector<DataType> inputDtypes;
157+ std::vector<Format> inputFormats;
158+ GetInputsInfo(subgraphInputs, inputShapes, inputDtypes, inputFormats);
159+ 
160+ NodeIo nodeIo;
161+ if (matchResult->GetCapturedTensor(kCaptureIdx, nodeIo) != SUCCESS) {
162+ OP_LOGE(kPassName.c_str(), "Failed to GetCaptured tensor in Replacement.");
163+ return nullptr;
164+ }
165+ 
S
Ssongkai1114月27日

inputDtypes[0]inputFormats[0]inputShapes[0] 直接按下标访问,没有对 subgraphInputs 做空检查。虽然正常匹配流程下不应该为空,但如果 GetAllInputs 返回空容器,这里会有越界访问的风险。建议加一个防御性检查。

likedislike
166+ DataType dtype = DT_FLOAT;
167+ nodeIo.node.GetAttr("dtype", dtype);
168+ int64_t dtypeInt = static_cast<int64_t>(dtype);
169+ 
170+ int64_t seed = 0;
171+ nodeIo.node.GetAttr("seed", seed);
172+ 
173+ int64_t seed2 = 0;
174+ nodeIo.node.GetAttr("seed2", seed2);
175+ 
176+ auto replaceGraphBuilder = es::EsGraphBuilder("replacement");
177+ 
178+ auto rShape = replaceGraphBuilder.CreateInput(0, "shape", inputDtypes[0], inputFormats[0], inputShapes[0].GetDims());
179+ 
180+ AscendString nodeName;
181+ if (nodeIo.node.GetName(nodeName) != GRAPH_SUCCESS) {
182+ OP_LOGE(kPassName.c_str(), "Failed to get node name.");
183+ return nullptr;
184+ }
185+ std::string varName = std::string(nodeName.GetString()) + "/offsetVariable";
186+ 
187+ TensorDesc offsetDesc(Shape({1}), FORMAT_ND, DT_INT64);
188+ 
189+ auto rOffset = replaceGraphBuilder.CreateVariable(1, varName.c_str());
190+ 
191+ auto v2Output = es::RandomStandardNormalV2(rShape, rOffset, seed, seed2, dtypeInt);
192+ GNode v2NodePtr = *v2Output.y.GetProducer();
193+ 
194+ TensorDesc shapeInputDesc(inputShapes[0], inputFormats[0], inputDtypes[0]);
195+ v2NodePtr.UpdateInputDesc(0, shapeInputDesc);
196+ v2NodePtr.UpdateInputDesc(1, offsetDesc);
197+ 
198+ TensorDesc outputYDesc;
199+ nodeIo.node.GetOutputDesc(0, outputYDesc);
200+ v2NodePtr.UpdateOutputDesc(0, outputYDesc);
201+ v2NodePtr.UpdateOutputDesc(1, offsetDesc);
202+ 
203+ es::EsGraphBuilder::SetOutput(v2Output.y, 0);
204+ GraphUniqPtr replaceGraph = replaceGraphBuilder.BuildAndReset({v2Output.y});
205+ return replaceGraph;
206+}
207+ 
208+REG_FUSION_PASS(RandomStandardNormalFusionPass).Stage(CustomPassStage::kCompatibleInherited);
209+ 
210+} // namespace ops
@@ -0,0 +1,29 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#ifndef OPS_MATH_RANDOM_STANDARD_NORMAL_FUSION_PASS_H_
12+#define OPS_MATH_RANDOM_STANDARD_NORMAL_FUSION_PASS_H_
13+ 
14+#include "ge/fusion/pass/pattern_fusion_pass.h"
15+ 
16+namespace ops {
17+ 
18+class __attribute__((visibility("default"))) RandomStandardNormalFusionPass : public ge::fusion::PatternFusionPass {
19+protected:
20+ std::vector<ge::fusion::PatternUniqPtr> Patterns() override;
21+ 
22+ bool MeetRequirements(const std::unique_ptr<ge::fusion::MatchResult>& matchResult) override;
23+ 
24+ std::unique_ptr<ge::Graph> Replacement(const std::unique_ptr<ge::fusion::MatchResult>& matchResult) override;
25+};
26+ 
27+} // namespace ops
28+ 
29+#endif // OPS_MATH_RANDOM_STANDARD_NORMAL_FUSION_PASS_H_
@@ -0,0 +1,325 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <iostream>
12+#include <vector>
13+#include <string>
14+#include <gtest/gtest.h>
15+#include "platform/platform_info.h"
16+#include "ge/es_graph_builder.h"
17+#include "es_math_ops.h"
18+#include "random/random_standard_normal_v2/op_graph/fusion_pass/random_standard_normal_fusion_pass.h"
19+#include "register/register_custom_pass.h"
20+ 
21+using namespace std;
22+using namespace ge;
23+using namespace fe;
24+using namespace fusion;
25+using namespace ops;
26+ 
27+class RandomStandardNormalFusionPassTest : public testing::Test {
28+protected:
29+ static void SetUpTestCase()
30+ {
31+ fe::PlatformInfo platformInfo;
32+ fe::OptionalInfo optiCompilationInfo;
33+ platformInfo.soc_info.ai_core_cnt = 64;
34+ platformInfo.str_info.short_soc_version = "Ascend910_93";
35+ optiCompilationInfo.soc_version = "Ascend910_93";
36+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
37+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
38+ }
39+ 
40+ void SetUp() override
41+ {
42+ fe::PlatformInfo platformInfo;
43+ fe::OptionalInfo optiCompilationInfo;
44+ platformInfo.soc_info.ai_core_cnt = 64;
45+ platformInfo.str_info.short_soc_version = "Ascend910_93";
46+ optiCompilationInfo.soc_version = "Ascend910_93";
47+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend910_93"] = platformInfo;
48+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
49+ }
50+};
51+ 
52+// Test 1: Verify Pattern can be created correctly
53+TEST_F(RandomStandardNormalFusionPassTest, patternTest)
54+{
55+ ops::RandomStandardNormalFusionPass pass;
56+ std::vector<PatternUniqPtr> patterns = pass.Patterns();
57+ EXPECT_GT(patterns.size(), 0);
58+}
59+ 
60+// Test 2: Verify unsupported dtype returns GRAPH_NOT_CHANGED
61+TEST_F(RandomStandardNormalFusionPassTest, unsupportedDtypeFail)
62+{
63+ std::vector<int64_t> shapeDims{2};
64+ 
65+ auto graphBuilder = es::EsGraphBuilder("test");
66+ auto shape = graphBuilder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, shapeDims);
67+ // DT_INT32 is not in the supported dtype list
68+ auto output = es::RandomStandardNormal(shape, DT_INT32, 1024, 2048);
69+ 
70+ TensorDesc shapeDesc;
71+ shape.GetProducer()->GetOutputDesc(0, shapeDesc);
72+ shapeDesc.SetDataType(DT_INT64);
73+ shapeDesc.SetShape(Shape(shapeDims));
74+ shapeDesc.SetFormat(FORMAT_ND);
75+ shape.GetProducer()->UpdateOutputDesc(0, shapeDesc);
76+ 
77+ std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
78+ CustomPassContext passContext;
79+ ops::RandomStandardNormalFusionPass pass;
80+ Status status = pass.Run(graph, passContext);
81+ 
82+ EXPECT_EQ(status, GRAPH_NOT_CHANGED);
83+}
84+ 
85+// Test 3: Verify unsupported platform returns GRAPH_NOT_CHANGED
86+TEST_F(RandomStandardNormalFusionPassTest, unsupportedPlatformFail)
87+{
88+ fe::PlatformInfo platformInfo;
89+ fe::OptionalInfo optiCompilationInfo;
90+ platformInfo.str_info.short_soc_version = "Ascend310";
91+ optiCompilationInfo.soc_version = "Ascend310";
92+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend310"] = platformInfo;
93+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
94+ 
95+ std::vector<int64_t> shapeDims{2};
96+ 
97+ auto graphBuilder = es::EsGraphBuilder("test");
98+ auto shape = graphBuilder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, shapeDims);
99+ auto output = es::RandomStandardNormal(shape, DT_FLOAT, 1024, 2048);
100+ 
101+ TensorDesc shapeDesc;
102+ shape.GetProducer()->GetOutputDesc(0, shapeDesc);
103+ shapeDesc.SetDataType(DT_INT64);
104+ shapeDesc.SetShape(Shape(shapeDims));
105+ shapeDesc.SetFormat(FORMAT_ND);
106+ shape.GetProducer()->UpdateOutputDesc(0, shapeDesc);
107+ 
108+ std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
109+ CustomPassContext passContext;
110+ ops::RandomStandardNormalFusionPass pass;
111+ Status status = pass.Run(graph, passContext);
112+ 
113+ EXPECT_EQ(status, GRAPH_NOT_CHANGED);
114+}
115+ 
116+// Test 4: Verify successful fusion with float32 dtype
117+TEST_F(RandomStandardNormalFusionPassTest, fusionFloatSuccess)
118+{
119+ fe::PlatformInfo platformInfo;
120+ fe::OptionalInfo optiCompilationInfo;
121+ platformInfo.soc_info.ai_core_cnt = 64;
122+ platformInfo.str_info.short_soc_version = "Ascend950";
123+ optiCompilationInfo.soc_version = "Ascend950";
124+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
125+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
126+ 
127+ std::vector<int64_t> shapeDims{2};
128+ 
129+ auto graphBuilder = es::EsGraphBuilder("test");
130+ auto shape = graphBuilder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, shapeDims);
131+ auto output = es::RandomStandardNormal(shape, DT_FLOAT, 1024, 2048);
132+ 
133+ TensorDesc shapeDesc;
134+ shape.GetProducer()->GetOutputDesc(0, shapeDesc);
135+ shapeDesc.SetDataType(DT_INT64);
136+ shapeDesc.SetShape(Shape(shapeDims));
137+ shapeDesc.SetFormat(FORMAT_ND);
138+ shape.GetProducer()->UpdateOutputDesc(0, shapeDesc);
139+ 
140+ std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
141+ CustomPassContext passContext;
142+ ops::RandomStandardNormalFusionPass pass;
143+ Status status = pass.Run(graph, passContext);
144+ 
145+ EXPECT_EQ(status, SUCCESS);
146+ 
147+ // Verify RandomStandardNormalV2 node exists
148+ bool foundV2 = false;
149+ for (auto node : graph->GetAllNodes()) {
150+ AscendString type;
151+ node.GetType(type);
152+ if (std::string(type.GetString()) == "RandomStandardNormalV2") {
153+ foundV2 = true;
154+ }
155+ }
156+ EXPECT_TRUE(foundV2);
157+}
158+ 
159+// Test 5: Verify successful fusion with float16 dtype
160+TEST_F(RandomStandardNormalFusionPassTest, fusionFloat16Success)
161+{
162+ fe::PlatformInfo platformInfo;
163+ fe::OptionalInfo optiCompilationInfo;
S
Ssongkai1114月27日

kSupportedDtypes 包含 DT_BF16,但测试中只验证了 DT_FLOATDT_FLOAT16 的融合成功场景,缺少 DT_BF16 的正向测试用例。建议补充一个 DT_BF16 的融合成功测试。

likedislike
xuejinghui
4月28日 评论:
164+ platformInfo.soc_info.ai_core_cnt = 64;
165+ platformInfo.str_info.short_soc_version = "Ascend950";
166+ optiCompilationInfo.soc_version = "Ascend950";
167+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
168+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
169+ 
170+ std::vector<int64_t> shapeDims{3};
171+ 
172+ auto graphBuilder = es::EsGraphBuilder("test");
173+ auto shape = graphBuilder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, shapeDims);
174+ auto output = es::RandomStandardNormal(shape, DT_FLOAT16, 0, 0);
175+ 
176+ TensorDesc shapeDesc;
177+ shape.GetProducer()->GetOutputDesc(0, shapeDesc);
178+ shapeDesc.SetDataType(DT_INT64);
179+ shapeDesc.SetShape(Shape(shapeDims));
180+ shapeDesc.SetFormat(FORMAT_ND);
181+ shape.GetProducer()->UpdateOutputDesc(0, shapeDesc);
182+ 
183+ std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
184+ CustomPassContext passContext;
185+ ops::RandomStandardNormalFusionPass pass;
186+ Status status = pass.Run(graph, passContext);
187+ 
188+ EXPECT_EQ(status, SUCCESS);
189+ 
190+ bool foundV2 = false;
191+ for (auto node : graph->GetAllNodes()) {
192+ AscendString type;
193+ node.GetType(type);
194+ if (std::string(type.GetString()) == "RandomStandardNormalV2") {
195+ foundV2 = true;
196+ }
197+ }
198+ EXPECT_TRUE(foundV2);
199+}
200+ 
201+// Test 6: Verify successful fusion with bfloat16 dtype
202+TEST_F(RandomStandardNormalFusionPassTest, fusionBf16Success)
203+{
204+ fe::PlatformInfo platformInfo;
205+ fe::OptionalInfo optiCompilationInfo;
206+ platformInfo.soc_info.ai_core_cnt = 64;
207+ platformInfo.str_info.short_soc_version = "Ascend950";
208+ optiCompilationInfo.soc_version = "Ascend950";
209+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
210+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
211+ 
212+ std::vector<int64_t> shapeDims{2};
213+ 
214+ auto graphBuilder = es::EsGraphBuilder("test");
215+ auto shape = graphBuilder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, shapeDims);
216+ auto output = es::RandomStandardNormal(shape, DT_BF16, 512, 1024);
217+ 
218+ TensorDesc shapeDesc;
219+ shape.GetProducer()->GetOutputDesc(0, shapeDesc);
220+ shapeDesc.SetDataType(DT_INT64);
221+ shapeDesc.SetShape(Shape(shapeDims));
222+ shapeDesc.SetFormat(FORMAT_ND);
223+ shape.GetProducer()->UpdateOutputDesc(0, shapeDesc);
224+ 
225+ std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
226+ CustomPassContext passContext;
227+ ops::RandomStandardNormalFusionPass pass;
228+ Status status = pass.Run(graph, passContext);
229+ 
230+ EXPECT_EQ(status, SUCCESS);
231+ 
232+ bool foundV2 = false;
233+ for (auto node : graph->GetAllNodes()) {
234+ AscendString type;
235+ node.GetType(type);
236+ if (std::string(type.GetString()) == "RandomStandardNormalV2") {
237+ foundV2 = true;
238+ }
239+ }
240+ EXPECT_TRUE(foundV2);
241+}
242+ 
243+// Test 7: Verify successful fusion on Ascend950 platform
244+TEST_F(RandomStandardNormalFusionPassTest, fusion950Success)
245+{
246+ fe::PlatformInfo platformInfo;
247+ fe::OptionalInfo optiCompilationInfo;
248+ platformInfo.soc_info.ai_core_cnt = 64;
249+ platformInfo.str_info.short_soc_version = "Ascend950";
250+ optiCompilationInfo.soc_version = "Ascend950";
251+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
252+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
253+ 
254+ std::vector<int64_t> shapeDims{4};
255+ 
256+ auto graphBuilder = es::EsGraphBuilder("test");
257+ auto shape = graphBuilder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, shapeDims);
258+ auto output = es::RandomStandardNormal(shape, DT_FLOAT, 512, 1024);
259+ 
260+ TensorDesc shapeDesc;
261+ shape.GetProducer()->GetOutputDesc(0, shapeDesc);
262+ shapeDesc.SetDataType(DT_INT64);
263+ shapeDesc.SetShape(Shape(shapeDims));
264+ shapeDesc.SetFormat(FORMAT_ND);
265+ shape.GetProducer()->UpdateOutputDesc(0, shapeDesc);
266+ 
267+ std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
268+ CustomPassContext passContext;
269+ ops::RandomStandardNormalFusionPass pass;
270+ Status status = pass.Run(graph, passContext);
271+ 
272+ EXPECT_EQ(status, SUCCESS);
273+ 
274+ bool foundV2 = false;
275+ for (auto node : graph->GetAllNodes()) {
276+ AscendString type;
277+ node.GetType(type);
278+ if (std::string(type.GetString()) == "RandomStandardNormalV2") {
279+ foundV2 = true;
280+ }
281+ }
282+ EXPECT_TRUE(foundV2);
283+}
284+ 
285+// Test 8: Verify successful fusion with different shape dimension
286+TEST_F(RandomStandardNormalFusionPassTest, fusionDifferentShapeSuccess)
287+{
288+ fe::PlatformInfo platformInfo;
289+ fe::OptionalInfo optiCompilationInfo;
290+ platformInfo.soc_info.ai_core_cnt = 64;
291+ platformInfo.str_info.short_soc_version = "Ascend950";
292+ optiCompilationInfo.soc_version = "Ascend950";
293+ fe::PlatformInfoManager::Instance().platform_info_map_["Ascend950"] = platformInfo;
294+ fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(optiCompilationInfo);
295+ 
296+ std::vector<int64_t> shapeDims{4};
297+ 
298+ auto graphBuilder = es::EsGraphBuilder("test");
299+ auto shape = graphBuilder.CreateInput(0, "shape", DT_INT64, FORMAT_ND, shapeDims);
300+ auto output = es::RandomStandardNormal(shape, DT_FLOAT, 0, 0);
301+ 
302+ TensorDesc shapeDesc;
303+ shape.GetProducer()->GetOutputDesc(0, shapeDesc);
304+ shapeDesc.SetDataType(DT_INT64);
305+ shapeDesc.SetShape(Shape(shapeDims));
306+ shapeDesc.SetFormat(FORMAT_ND);
307+ shape.GetProducer()->UpdateOutputDesc(0, shapeDesc);
308+ 
309+ std::shared_ptr<Graph> graph = graphBuilder.BuildAndReset({output});
310+ CustomPassContext passContext;
311+ ops::RandomStandardNormalFusionPass pass;
312+ Status status = pass.Run(graph, passContext);
313+ 
314+ EXPECT_EQ(status, SUCCESS);
315+ 
316+ bool foundV2 = false;
317+ for (auto node : graph->GetAllNodes()) {
318+ AscendString type;
319+ node.GetType(type);
320+ if (std::string(type.GetString()) == "RandomStandardNormalV2") {
321+ foundV2 = true;
322+ }
323+ }
324+ EXPECT_TRUE(foundV2);
325+}
@@ -47,12 +47,10 @@ if(UT_TEST_ALL OR OP_GRAPH_UT)
47 -Wl,--no-whole-archive47 -Wl,--no-whole-archive
48 -Wl,--no-as-needed48 -Wl,--no-as-needed
49 metadef49 metadef
50- ge_common
51 -Wl,--as-needed50 -Wl,--as-needed
52 error_manager51 error_manager
53 exe_graph52 exe_graph
54 graph_base53 graph_base
55- ge_common
56 gtest54 gtest
57 graph55 graph
58 register56 register