已合并
迁移drop_out_v3和stateless_bernoulli融合规则到ops-math仓 #2191
liangtongxue创建于 4月13日
迁移drop_out_v3和stateless_bernoulli融合规则到ops-math仓 #2191
已合并
共 13 个文件变更+2389-30
| @@ -12,4 +12,4 @@ | |||
| 12 | set(SUPPORT_COMPUTE_UNIT "ascend310p" "ascend910_93" "ascend910b" "ascend950") | 12 | set(SUPPORT_COMPUTE_UNIT "ascend310p" "ascend910_93" "ascend910b" "ascend950") |
| 13 | # 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译 | 13 | # 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译 |
| 14 | set(SUPPORT_TILING_DIR "arch32" "arch32" "arch32" "arch35") | 14 | set(SUPPORT_TILING_DIR "arch32" "arch32" "arch32" "arch35") |
| 15 | add_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) | 15 | add_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) |
| @@ -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 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | namespace ge::fusion { | ||
| 28 | |||
| 29 | using namespace ge; | ||
| 30 | using namespace fe; | ||
| 31 | |||
| 32 | namespace { | ||
| 33 | const std::string kPassName = "DropOutV3FusionPass"; | ||
L | |||
| 34 | constexpr int64_t kGenMaskCaptureIdx = 0; | ||
| 35 | constexpr int64_t kDoMaskCaptureIdx = 1; | ||
| 36 | |||
| 37 | constexpr size_t kIdxX = 0; | ||
| 38 | constexpr size_t kIdxShape = 1; | ||
| 39 | constexpr size_t kIdxProb = 2; | ||
| 40 | constexpr size_t kIdxSeed = 3; | ||
| 41 | constexpr size_t kIdxOffset = 4; | ||
| 42 | |||
| 43 | constexpr size_t kGenMaskIdxProb = 1; | ||
| 44 | constexpr size_t kGenMaskIdxSeed = 2; | ||
| 45 | constexpr size_t kGenMaskIdxOffset = 4; | ||
| 46 | |||
| 47 | struct 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 | |||
| 64 | std::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 | |||
| 73 | std::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 | |||
| 81 | Format GetInputFormat(const std::vector<Format>& inputFormats, size_t idx) | ||
| 82 | { | ||
| 83 | return (idx < inputFormats.size()) ? inputFormats[idx] : FORMAT_ND; | ||
| 84 | } | ||
| 85 | |||
| 86 | DataType GetInputDtype(const std::vector<DataType>& inputDtypes, size_t idx) | ||
| 87 | { | ||
| 88 | return (idx < inputDtypes.size()) ? inputDtypes[idx] : DT_FLOAT; | ||
| 89 | } | ||
| 90 | |||
| 91 | void 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 | |||
| 105 | Status 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 | |||
| 117 | void 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 | |||
| 126 | bool CheckDtype(DataType dtype, const std::vector<DataType>& validTypes) | ||
| 127 | { | ||
| 128 | return std::find(validTypes.begin(), validTypes.end(), dtype) != validTypes.end(); | ||
| 129 | } | ||
| 130 | |||
| 131 | bool 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 | |||
| 140 | InputParams 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 | |||
| 165 | es::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 | |||
| 186 | std::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 | |||
| 210 | bool 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 | |||
| 225 | bool 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 | |||
| 275 | bool 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 | |||
| 311 | GraphUniqPtr 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 | |||
| 335 | REG_FUSION_PASS(DropOutV3FusionPass).Stage(CustomPassStage::kCompatibleInherited); | ||
| 336 | } | ||
| @@ -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 | |||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | namespace ge::fusion { | ||
| 17 | using namespace ge; | ||
| 18 | |||
| 19 | class __attribute__((visibility("default"))) DropOutV3FusionPass : public PatternFusionPass { | ||
| 20 | protected: | ||
| 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 | |||
| 27 | private: | ||
| 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 | |||
| @@ -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 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | |||
| 28 | namespace ge::fusion { | ||
| 29 | |||
| 30 | using namespace ge; | ||
| 31 | using namespace fe; | ||
| 32 | |||
| 33 | namespace { | ||
| 34 | const std::string kPassName = "DropOutV3SplitFusionPass"; | ||
| 35 | |||
| 36 | constexpr size_t kIdxX = 0; | ||
| 37 | constexpr size_t kIdxP = 2; | ||
| 38 | constexpr size_t kIdxSeed = 3; | ||
| 39 | constexpr size_t kIdxOffset = 4; | ||
| 40 | |||
| 41 | constexpr int32_t kMaxDimBound = 8; | ||
| 42 | |||
| 43 | bool CheckDtype(DataType dtype, const std::vector<DataType>& validTypes) | ||
| 44 | { | ||
| 45 | return std::find(validTypes.begin(), validTypes.end(), dtype) != validTypes.end(); | ||
| 46 | } | ||
| 47 | |||
| 48 | std::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 | |||
| 58 | bool 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 | |||
| 73 | bool 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 | |||
| 116 | bool 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 | |||
| 147 | InputInfo 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 | |||
| 174 | void 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 | |||
| 221 | GraphUniqPtr 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 | |||
| 249 | std::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 | |||
| 277 | Status 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 | |||
| 329 | REG_FUSION_PASS(DropOutV3SplitFusionPass).Stage(CustomPassStage::kCompatibleInherited); | ||
| 330 | } | ||
| @@ -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 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | namespace ge::fusion { | ||
| 22 | |||
| 23 | using namespace ge; | ||
| 24 | |||
| 25 | struct 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 | |||
| 38 | class __attribute__((visibility("default"))) DropOutV3SplitFusionPass : public FusionBasePass { | ||
| 39 | public: | ||
| 40 | Status Run(GraphPtr &graph, CustomPassContext &pass_context) override; | ||
| 41 | |||
| 42 | private: | ||
| 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 | |||
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 | # ---------------------------------------------------------------------------- | ||
| @@ -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 | |||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | using namespace std; | ||
| 22 | using namespace ge; | ||
| 23 | using namespace fe; | ||
| 24 | using namespace fusion; | ||
| 25 | |||
| 26 | namespace { | ||
| 27 | const std::string kPassName = "DropOutV3FusionPass"; | ||
| 28 | } | ||
| 29 | |||
| 30 | class DropOutV3FusionPassTest : public testing::Test { | ||
| 31 | protected: | ||
| 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 | ||
| 79 | TEST_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 | ||
| 87 | TEST_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 | ||
| 112 | TEST_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); | ||
| 167 | } | ||
| 168 | |||
| 169 | // Test: Shape {14, 12, 16, 2, 8} - matches canndev test_2 | ||
| 170 | TEST_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 | ||
| 202 | TEST_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 | ||
| 234 | TEST_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 | ||
| 266 | TEST_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 | ||
| 298 | TEST_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 | ||
| 330 | TEST_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 | ||
| 362 | TEST_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 | ||
| 395 | TEST_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 | ||
| 438 | TEST_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 | ||
| 470 | TEST_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 | } | ||
| @@ -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 | |||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | using namespace std; | ||
| 22 | using namespace ge; | ||
| 23 | using namespace fe; | ||
| 24 | using namespace fusion; | ||
| 25 | |||
| 26 | namespace { | ||
| 27 | const std::string kPassName = "DropOutV3SplitFusionPass"; | ||
| 28 | |||
| 29 | std::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 | |||
| 40 | void 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 | |||
| 87 | class DropOutV3SplitFusionPassTest : public testing::Test { | ||
| 88 | protected: | ||
| 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 | |||
| 134 | TEST_F(DropOutV3SplitFusionPassTest, passCreationTest) | ||
| 135 | { | ||
| 136 | DropOutV3SplitFusionPass pass; | ||
| 137 | } | ||
| 138 | |||
| 139 | TEST_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 | |||
| 170 | TEST_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 | |||
| 201 | TEST_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 | |||
| 227 | TEST_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 | |||
| 251 | TEST_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 | |||
| 275 | TEST_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 | |||
| 299 | TEST_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 | |||
| 323 | TEST_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 | |||
| 344 | EXPECT_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 | |||
| 11 | add_graph_plugin_sources() | ||
| @@ -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 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | using namespace ge; | ||
| 26 | using namespace fe; | ||
| 27 | |||
| 28 | namespace ge::fusion { | ||
| 29 | |||
| 30 | namespace { | ||
| 31 | const std::string kPassName = "BernoulliFusionPass"; | ||
| 32 | constexpr int64_t kCaptureIdxV2Node = 0l; | ||
| 33 | |||
| 34 | std::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 | |||
| 43 | Status 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 | |||
| 55 | void 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 | |||
| 64 | bool CheckPlatform(const std::string& soc) | ||
| 65 | { | ||
| 66 | return (soc == "Ascend910_93" || soc == "Ascend950"); | ||
| 67 | } | ||
| 68 | |||
| 69 | bool CheckDtype(DataType dtype, const std::vector<DataType>& validTypes) | ||
| 70 | { | ||
| 71 | return std::find(validTypes.begin(), validTypes.end(), dtype) != validTypes.end(); | ||
| 72 | } | ||
| 73 | } // namespace | ||
| 74 | |||
| 75 | std::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 | |||
| 94 | bool 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 | |||
| 134 | std::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 | |||
少了个刷新format ![]() ![]() | |||
| 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 | |||
| 189 | REG_FUSION_PASS(BernoulliFusionPass).Stage(CustomPassStage::kCompatibleInherited); | ||
| 190 | |||
| 191 | } // namespace ge::fusion | ||
| @@ -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 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | namespace ge::fusion { | ||
| 22 | using namespace ge; | ||
| 23 | |||
| 24 | class __attribute__((visibility("default"))) BernoulliFusionPass : public PatternFusionPass { | ||
| 25 | protected: | ||
| 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 | |||
| @@ -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 | |||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | using namespace std; | ||
| 22 | using namespace ge; | ||
| 23 | using namespace fe; | ||
| 24 | using namespace fusion; | ||
| 25 | |||
| 26 | namespace { | ||
| 27 | const std::string kPassName = "BernoulliFusionPass"; | ||
| 28 | } | ||
| 29 | |||
| 30 | class BernoulliFusionPassTest : public testing::Test { | ||
| 31 | protected: | ||
| 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 | |||
| 77 | TEST_F(BernoulliFusionPassTest, patternTest) | ||
| 78 | { | ||
| 79 | BernoulliFusionPass pass; | ||
| 80 | std::vector<PatternUniqPtr> patterns = pass.Patterns(); | ||
| 81 | EXPECT_GT(patterns.size(), 0); | ||
| 82 | } | ||
| 83 | |||
| 84 | TEST_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 | |||
| 140 | TEST_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 | |||
| 205 | TEST_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 | |||
| 266 | TEST_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 | |||
| 327 | TEST_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 | |||
| 388 | TEST_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 | |||
| 438 | TEST_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 | |||
| 499 | TEST_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 | } | ||


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