| @@ -156,6 +156,9 @@ if(ENABLE_TEST) | |||
| 156 | set(OP_TILING_MODULE_NAME ${PKG_NAME}_op_tiling_ut) | 156 | set(OP_TILING_MODULE_NAME ${PKG_NAME}_op_tiling_ut) |
| 157 | 157 | ||
| 158 | set(OP_INFERSHAPE_MODULE_NAME ${PKG_NAME}_op_infershape_ut) | 158 | set(OP_INFERSHAPE_MODULE_NAME ${PKG_NAME}_op_infershape_ut) |
| 159 | + | ||
| 160 | + # onnx 插件(framework)解析逻辑属 host 侧,随 op_host ut 一起构建 | ||
| 161 | + set(OP_FRAMEWORK_MODULE_NAME ${PKG_NAME}_op_framework_ut) | ||
| 159 | endif() | 162 | endif() |
| 160 | 163 | ||
| 161 | # op api ut | 164 | # op api ut |
| @@ -1,43 +1,58 @@ | |||
| 1 | -/** | 1 | +/** |
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 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, | 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. | 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. | 8 | + * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | - */ | 9 | + */ |
| 10 | - | 10 | + |
| 11 | -#include "onnx_common.h" | 11 | +#include "plugin_util.h" |
| 12 | - | 12 | +#include "register/register.h" |
| 13 | -namespace domi { | 13 | +#include "graph/operator.h" |
| 14 | -using NodeProto = ge::onnx::NodeProto; | 14 | +#include "nlohmann/json.hpp" |
| 15 | -static Status ParseParamsElu(const Message* op_src, ge::Operator& op_dest) | 15 | + |
| 16 | -{ | 16 | +namespace domi { |
| 17 | - const NodeProto* node = reinterpret_cast<const NodeProto*>(op_src); | 17 | +using json = nlohmann::json; |
| 18 | - if (node == nullptr) { | 18 | +static Status ParseParamsElu(const ge::Operator& op_src, ge::Operator& op_dest) |
| 19 | - OP_LOGE(GetOpName(op_dest).c_str(), "Dynamic cast op_src to NodeProto failed."); | 19 | +{ |
| 20 | - return FAILED; | 20 | + float alpha_value = 1.0; |
| 21 | - } | 21 | + ge::AscendString attrs_string; |
| 22 | - float alpha_value = 1.0; | 22 | + if (op_src.GetAttr("attribute", attrs_string) == ge::GRAPH_SUCCESS) { |
| 23 | - op_dest.SetAttr("alpha", alpha_value); | 23 | + try { |
| 24 | - for (const auto& attr : node->attribute()) { | 24 | + json attrs = json::parse(attrs_string.GetString()); |
| 25 | - if (attr.name() == "alpha" && attr.type() == ge::onnx::AttributeProto::FLOAT) { | 25 | + if (attrs.contains("attribute") && attrs["attribute"].is_array()) { |
| 26 | - alpha_value = attr.f(); | 26 | + for (json& attr : attrs["attribute"]) { |
| 27 | - op_dest.SetAttr("alpha", alpha_value); | 27 | + if (attr.value("name", "") == "alpha" && attr.contains("f")) { |
| 28 | - } | 28 | + std::string alpha_str = attr["f"]; |
| 29 | - } | 29 | + if (!StrToFloat(alpha_str, alpha_value)) { |
| 30 | - return SUCCESS; | 30 | + OP_LOGE(GetOpName(op_dest).c_str(), "invalid alpha value: %s", alpha_str.c_str()); |
| 31 | -} | 31 | + return FAILED; |
| 32 | -// register Elu op info to GE | 32 | + } |
| 33 | -REGISTER_CUSTOM_OP("Elu") | 33 | + } |
| 34 | - .FrameworkType(ONNX) | 34 | + } |
| 35 | - .OriginOpType({ge::AscendString("ai.onnx::8::Elu"), ge::AscendString("ai.onnx::9::Elu"), | 35 | + } |
| 36 | - ge::AscendString("ai.onnx::10::Elu"), ge::AscendString("ai.onnx::11::Elu"), | 36 | + } catch (const nlohmann::json::exception& e) { |
| 37 | - ge::AscendString("ai.onnx::12::Elu"), ge::AscendString("ai.onnx::13::Elu"), | 37 | + OP_LOGE(GetOpName(op_dest).c_str(), "JSON parse error: %s", e.what()); |
| 38 | - ge::AscendString("ai.onnx::14::Elu"), ge::AscendString("ai.onnx::15::Elu"), | 38 | + return FAILED; |
| 39 | - ge::AscendString("ai.onnx::16::Elu"), ge::AscendString("ai.onnx::17::Elu"), | 39 | + } catch (...) { |
C [Suggestion] catch(...) 过于宽泛,错误信息缺乏定位价值 Elu/LeakyRelu/HardMax 三个插件均使用 建议改为
![]() ![]() | |||
| 40 | - ge::AscendString("ai.onnx::18::Elu")}) | 40 | + OP_LOGE(GetOpName(op_dest).c_str(), "get unknown exception, please check compile info json."); |
| 41 | - .ParseParamsFn(ParseParamsElu) | 41 | + return FAILED; |
| 42 | - .ImplyType(ImplyType::TVM); | 42 | + } |
| 43 | -} // namespace domi | 43 | + } |
| 44 | + op_dest.SetAttr("alpha", alpha_value); | ||
| 45 | + return SUCCESS; | ||
| 46 | +} | ||
| 47 | +// register Elu op info to GE | ||
| 48 | +REGISTER_CUSTOM_OP("Elu") | ||
| 49 | + .FrameworkType(ONNX) | ||
| 50 | + .OriginOpType({ge::AscendString("ai.onnx::8::Elu"), ge::AscendString("ai.onnx::9::Elu"), | ||
| 51 | + ge::AscendString("ai.onnx::10::Elu"), ge::AscendString("ai.onnx::11::Elu"), | ||
| 52 | + ge::AscendString("ai.onnx::12::Elu"), ge::AscendString("ai.onnx::13::Elu"), | ||
| 53 | + ge::AscendString("ai.onnx::14::Elu"), ge::AscendString("ai.onnx::15::Elu"), | ||
| 54 | + ge::AscendString("ai.onnx::16::Elu"), ge::AscendString("ai.onnx::17::Elu"), | ||
| 55 | + ge::AscendString("ai.onnx::18::Elu")}) | ||
| 56 | + .ParseParamsByOperatorFn(ParseParamsElu) | ||
| 57 | + .ImplyType(ImplyType::TVM); | ||
| 58 | +} // namespace domi | ||
| @@ -0,0 +1,14 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 13 | + add_modules_ut_sources(HOSTNAME ${OP_FRAMEWORK_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | +endif() | ||
| @@ -0,0 +1,46 @@ | |||
| 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 | +namespace { | ||
| 16 | +ge::Operator CreateOperator(const std::string& name) { return ge::Operator(name, "TestOp"); } | ||
| 17 | + | ||
| 18 | +ge::Operator CreateSourceOperator(const std::string& attrs) | ||
| 19 | +{ | ||
| 20 | + ge::Operator op_src = CreateOperator("src"); | ||
| 21 | + op_src.SetAttr("attribute", ge::AscendString(attrs.c_str())); | ||
| 22 | + return op_src; | ||
| 23 | +} | ||
| 24 | +} // namespace | ||
| 25 | + | ||
| 26 | +TEST(OnnxEluPluginTest, ParseFloatAttributeFromString) | ||
| 27 | +{ | ||
| 28 | + ge::Operator op_src = CreateSourceOperator(R"({"attribute":[{"name":"alpha","type":1,"f":"0.25"}]})"); | ||
| 29 | + ge::Operator op_dest = CreateOperator("elu"); | ||
| 30 | + float alpha = 0.0f; | ||
| 31 | + | ||
| 32 | + EXPECT_EQ(domi::ParseParamsElu(op_src, op_dest), domi::SUCCESS); | ||
| 33 | + EXPECT_EQ(op_dest.GetAttr("alpha", alpha), ge::GRAPH_SUCCESS); | ||
| 34 | + EXPECT_FLOAT_EQ(alpha, 0.25f); | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +TEST(OnnxEluPluginTest, KeepsDefaultWithoutAttributeArray) | ||
| 38 | +{ | ||
| 39 | + ge::Operator op_src = CreateSourceOperator(R"({"attribute":{}})"); | ||
| 40 | + ge::Operator op_dest = CreateOperator("elu"); | ||
| 41 | + float alpha = 0.0f; | ||
| 42 | + | ||
| 43 | + EXPECT_EQ(domi::ParseParamsElu(op_src, op_dest), domi::SUCCESS); | ||
| 44 | + EXPECT_EQ(op_dest.GetAttr("alpha", alpha), ge::GRAPH_SUCCESS); | ||
| 45 | + EXPECT_FLOAT_EQ(alpha, 1.0f); | ||
| 46 | +} | ||
| @@ -13,21 +13,12 @@ | |||
| 13 | * \brief | 13 | * \brief |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | -#include "onnx_common.h" | 16 | +#include "plugin_util.h" |
| 17 | + | ||
| 18 | + | ||
| 17 | 19 | ||
| 18 | namespace domi { | 20 | namespace domi { |
| 19 | -using NodeProto = ge::onnx::NodeProto; | 21 | +static Status ParseParamsNpuFastGelu(const ge::Operator&, ge::Operator&) { return SUCCESS; } |
| 20 | - | ||
| 21 | -static Status ParseParamsNpuFastGelu(const Message* op_src, ge::Operator& op_dest) | ||
| 22 | -{ | ||
| 23 | - const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); | ||
| 24 | - if (node == nullptr) { | ||
| 25 | - OP_LOGE(GetOpName(op_dest).c_str(), "Dynamic cast op_src to NodeProto failed."); | ||
| 26 | - return FAILED; | ||
| 27 | - } | ||
| 28 | - | ||
| 29 | - return SUCCESS; | ||
| 30 | -} | ||
| 31 | 22 | ||
| 32 | REGISTER_CUSTOM_OP("FastGelu") | 23 | REGISTER_CUSTOM_OP("FastGelu") |
| 33 | .FrameworkType(ONNX) | 24 | .FrameworkType(ONNX) |
| @@ -36,6 +27,6 @@ REGISTER_CUSTOM_OP("FastGelu") | |||
| 36 | ge::AscendString("ai.onnx::14::NPUFastGelu"), ge::AscendString("ai.onnx::15::NPUFastGelu"), | 27 | ge::AscendString("ai.onnx::14::NPUFastGelu"), ge::AscendString("ai.onnx::15::NPUFastGelu"), |
| 37 | ge::AscendString("ai.onnx::16::NPUFastGelu"), ge::AscendString("ai.onnx::17::NPUFastGelu"), | 28 | ge::AscendString("ai.onnx::16::NPUFastGelu"), ge::AscendString("ai.onnx::17::NPUFastGelu"), |
| 38 | ge::AscendString("ai.onnx::18::NPUFastGelu")}) | 29 | ge::AscendString("ai.onnx::18::NPUFastGelu")}) |
| 39 | - .ParseParamsFn(ParseParamsNpuFastGelu) | 30 | + .ParseParamsByOperatorFn(ParseParamsNpuFastGelu) |
| 40 | .ImplyType(ImplyType::TVM); | 31 | .ImplyType(ImplyType::TVM); |
| 41 | -} // namespace domi | 32 | +} // namespace domi |
| @@ -0,0 +1,14 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 13 | + add_modules_ut_sources(HOSTNAME ${OP_FRAMEWORK_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | +endif() | ||
| @@ -0,0 +1,25 @@ | |||
| 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 | +namespace { | ||
| 16 | +ge::Operator CreateOperator(const std::string& name) { return ge::Operator(name, "TestOp"); } | ||
| 17 | +} // namespace | ||
| 18 | + | ||
| 19 | +TEST(OnnxNpuFastGeluPluginTest, NoAttributeParseReturnsSuccess) | ||
| 20 | +{ | ||
| 21 | + ge::Operator op_src = CreateOperator("src"); | ||
| 22 | + ge::Operator op_dest = CreateOperator("npu_fast_gelu"); | ||
| 23 | + | ||
| 24 | + EXPECT_EQ(domi::ParseParamsNpuFastGelu(op_src, op_dest), domi::SUCCESS); | ||
| 25 | +} | ||
| @@ -1,43 +1,58 @@ | |||||||||||||||||
| 1 | -/** | 1 | +/** | ||||||||||||||
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 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, | 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. | 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. | 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||||||||||||||
| 9 | - */ | 9 | + */ | ||||||||||||||
| 10 | - | 10 | + | ||||||||||||||
| 11 | -#include "onnx_common.h" | 11 | +#include "plugin_util.h" | ||||||||||||||
| 12 | - | 12 | +#include "register/register.h" | ||||||||||||||
| 13 | -namespace domi { | 13 | +#include "graph/operator.h" | ||||||||||||||
| 14 | -using NodeProto = ge::onnx::NodeProto; | 14 | +#include "nlohmann/json.hpp" | ||||||||||||||
| 15 | -static Status ParseParamsLeakyRelu(const Message* op_src, ge::Operator& op_dst) | 15 | + | ||||||||||||||
| 16 | -{ | 16 | +namespace domi { | ||||||||||||||
| 17 | - const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); | 17 | +using json = nlohmann::json; | ||||||||||||||
| 18 | - if (node == nullptr) { | 18 | +static Status ParseParamsLeakyRelu(const ge::Operator& op_src, ge::Operator& op_dst) | ||||||||||||||
| 19 | - OP_LOGE(GetOpName(op_dst).c_str(), "Dynamic cast op_src to NodeProto failed."); | 19 | +{ | ||||||||||||||
| 20 | - return FAILED; | 20 | + float negative_slope = 0.01f; | ||||||||||||||
| 21 | - } | 21 | + ge::AscendString attrs_string; | ||||||||||||||
| 22 | - | 22 | + if (op_src.GetAttr("attribute", attrs_string) == ge::GRAPH_SUCCESS) { | ||||||||||||||
| 23 | - float negative_slope = 0.01f; | 23 | + try { | ||||||||||||||
| 24 | - for (auto attr : node->attribute()) { | 24 | + json attrs = json::parse(attrs_string.GetString()); | ||||||||||||||
| 25 | - if (attr.name() == "alpha" && attr.type() == ge::onnx::AttributeProto::FLOAT) { | 25 | + if (attrs.contains("attribute") && attrs["attribute"].is_array()) { | ||||||||||||||
| 26 | - negative_slope = attr.f(); | 26 | + for (json& attr : attrs["attribute"]) { | ||||||||||||||
| 27 | - } | 27 | + if (attr.value("name", "") == "alpha" && attr.contains("f")) { | ||||||||||||||
| 28 | - } | 28 | + std::string alpha_str = attr["f"]; | ||||||||||||||
| 29 | - op_dst.SetAttr("negative_slope", negative_slope); | 29 | + if (!StrToFloat(alpha_str, negative_slope)) { | ||||||||||||||
| 30 | - return SUCCESS; | 30 | + OP_LOGE(GetOpName(op_dst).c_str(), "invalid alpha value: %s", alpha_str.c_str()); | ||||||||||||||
| 31 | -} | 31 | + return FAILED; | ||||||||||||||
| 32 | - | 32 | + } | ||||||||||||||
| 33 | -REGISTER_CUSTOM_OP("LeakyRelu") | 33 | + } | ||||||||||||||
🟠 High Priority 变更行:新增的 ParseParamsLeakyRelu 中 受影响的契约:本框架的 ONNX 节点属性 JSON(op_src 上名为 "attribute" 的 attr)中,标量 float 属性字段 "f" 被序列化为 JSON 字符串而非 JSON number。同一仓库先例均按此契约读取: 失败模式:当 ONNX 模型中的 LeakyRelu 节点带 alpha 属性(导出器通常会显式写出,包括默认 0.01)时,JSON 中 "f" 为字符串, 改动建议
![]() ![]() | |||||||||||||||||
| 34 | - .FrameworkType(ONNX) | 34 | + } | ||||||||||||||
| 35 | - .OriginOpType({ge::AscendString("ai.onnx::8::LeakyRelu"), ge::AscendString("ai.onnx::9::LeakyRelu"), | 35 | + } | ||||||||||||||
| 36 | - ge::AscendString("ai.onnx::10::LeakyRelu"), ge::AscendString("ai.onnx::11::LeakyRelu"), | 36 | + } catch (const nlohmann::json::exception& e) { | ||||||||||||||
| 37 | - ge::AscendString("ai.onnx::12::LeakyRelu"), ge::AscendString("ai.onnx::13::LeakyRelu"), | 37 | + OP_LOGE(GetOpName(op_dst).c_str(), "JSON parse error: %s", e.what()); | ||||||||||||||
| 38 | - ge::AscendString("ai.onnx::14::LeakyRelu"), ge::AscendString("ai.onnx::15::LeakyRelu"), | 38 | + return FAILED; | ||||||||||||||
| 39 | - ge::AscendString("ai.onnx::16::LeakyRelu"), ge::AscendString("ai.onnx::17::LeakyRelu"), | 39 | + } catch (...) { | ||||||||||||||
| 40 | - ge::AscendString("ai.onnx::18::LeakyRelu")}) | 40 | + OP_LOGE(GetOpName(op_dst).c_str(), "get unknown exception, please check compile info json."); | ||||||||||||||
| 41 | - .ParseParamsFn(ParseParamsLeakyRelu) | 41 | + return FAILED; | ||||||||||||||
| 42 | - .ImplyType(ImplyType::TVM); | 42 | + } | ||||||||||||||
| 43 | -} // namespace domi | 43 | + } | ||||||||||||||
| 44 | + op_dst.SetAttr("negative_slope", negative_slope); | ||||||||||||||||
| 45 | + return SUCCESS; | ||||||||||||||||
| 46 | +} | ||||||||||||||||
| 47 | + | ||||||||||||||||
| 48 | +REGISTER_CUSTOM_OP("LeakyRelu") | ||||||||||||||||
| 49 | + .FrameworkType(ONNX) | ||||||||||||||||
| 50 | + .OriginOpType({ge::AscendString("ai.onnx::8::LeakyRelu"), ge::AscendString("ai.onnx::9::LeakyRelu"), | ||||||||||||||||
| 51 | + ge::AscendString("ai.onnx::10::LeakyRelu"), ge::AscendString("ai.onnx::11::LeakyRelu"), | ||||||||||||||||
| 52 | + ge::AscendString("ai.onnx::12::LeakyRelu"), ge::AscendString("ai.onnx::13::LeakyRelu"), | ||||||||||||||||
| 53 | + ge::AscendString("ai.onnx::14::LeakyRelu"), ge::AscendString("ai.onnx::15::LeakyRelu"), | ||||||||||||||||
| 54 | + ge::AscendString("ai.onnx::16::LeakyRelu"), ge::AscendString("ai.onnx::17::LeakyRelu"), | ||||||||||||||||
| 55 | + ge::AscendString("ai.onnx::18::LeakyRelu")}) | ||||||||||||||||
| 56 | + .ParseParamsByOperatorFn(ParseParamsLeakyRelu) | ||||||||||||||||
| 57 | + .ImplyType(ImplyType::TVM); | ||||||||||||||||
| 58 | +} // namespace domi | ||||||||||||||||
| @@ -0,0 +1,14 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 13 | + add_modules_ut_sources(HOSTNAME ${OP_FRAMEWORK_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | +endif() | ||
| @@ -0,0 +1,46 @@ | |||
| 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 | +namespace { | ||
| 16 | +ge::Operator CreateOperator(const std::string& name) { return ge::Operator(name, "TestOp"); } | ||
| 17 | + | ||
| 18 | +ge::Operator CreateSourceOperator(const std::string& attrs) | ||
| 19 | +{ | ||
| 20 | + ge::Operator op_src = CreateOperator("src"); | ||
| 21 | + op_src.SetAttr("attribute", ge::AscendString(attrs.c_str())); | ||
| 22 | + return op_src; | ||
| 23 | +} | ||
| 24 | +} // namespace | ||
| 25 | + | ||
| 26 | +TEST(OnnxLeakyReluPluginTest, ParseFloatAttributeFromString) | ||
| 27 | +{ | ||
| 28 | + ge::Operator op_src = CreateSourceOperator(R"({"attribute":[{"name":"alpha","type":1,"f":"0.125"}]})"); | ||
| 29 | + ge::Operator op_dest = CreateOperator("leaky_relu"); | ||
| 30 | + float negative_slope = 0.0f; | ||
| 31 | + | ||
| 32 | + EXPECT_EQ(domi::ParseParamsLeakyRelu(op_src, op_dest), domi::SUCCESS); | ||
| 33 | + EXPECT_EQ(op_dest.GetAttr("negative_slope", negative_slope), ge::GRAPH_SUCCESS); | ||
| 34 | + EXPECT_FLOAT_EQ(negative_slope, 0.125f); | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +TEST(OnnxLeakyReluPluginTest, KeepsDefaultWhenAttributeMissing) | ||
| 38 | +{ | ||
| 39 | + ge::Operator op_src = CreateSourceOperator(R"({})"); | ||
| 40 | + ge::Operator op_dest = CreateOperator("leaky_relu"); | ||
| 41 | + float negative_slope = 0.0f; | ||
| 42 | + | ||
| 43 | + EXPECT_EQ(domi::ParseParamsLeakyRelu(op_src, op_dest), domi::SUCCESS); | ||
| 44 | + EXPECT_EQ(op_dest.GetAttr("negative_slope", negative_slope), ge::GRAPH_SUCCESS); | ||
| 45 | + EXPECT_FLOAT_EQ(negative_slope, 0.01f); | ||
| 46 | +} | ||
| @@ -1,35 +1,27 @@ | |||
| 1 | -/** | 1 | +/** |
| 2 | - * Copyright (c) 2026 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 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, | 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. | 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. | 8 | + * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | - */ | 9 | + */ |
| 10 | - | 10 | + |
| 11 | -#include "onnx_common.h" | 11 | +#include "plugin_util.h" |
| 12 | - | 12 | +#include "register/register.h" |
| 13 | -namespace domi { | 13 | +#include "graph/operator.h" |
| 14 | -using NodeProto = ge::onnx::NodeProto; | 14 | + |
| 15 | -static Status ParseParamsMish(const Message* op_src, ge::Operator& op_dest) | 15 | +namespace domi { |
| 16 | -{ | 16 | +static Status ParseParamsMish(const ge::Operator&, ge::Operator&) { return SUCCESS; } |
| 17 | - const NodeProto* node = reinterpret_cast<const NodeProto*>(op_src); | 17 | +// register Mish op info to GE |
| 18 | - if (node == nullptr) { | 18 | +REGISTER_CUSTOM_OP("Mish") |
| 19 | - OP_LOGE(GetOpName(op_dest).c_str(), "Dynamic cast op_src to NodeProto failed."); | 19 | + .FrameworkType(ONNX) |
| 20 | - return FAILED; | 20 | + .OriginOpType({ge::AscendString("ai.onnx::18::Mish"), ge::AscendString("npu::1::NPUMish"), |
| 21 | - } | 21 | + ge::AscendString("ai.onnx::11::NPUMish"), ge::AscendString("ai.onnx::12::NPUMish"), |
| 22 | - | 22 | + ge::AscendString("ai.onnx::13::NPUMish"), ge::AscendString("ai.onnx::14::NPUMish"), |
| 23 | - return SUCCESS; | 23 | + ge::AscendString("ai.onnx::15::NPUMish"), ge::AscendString("ai.onnx::16::NPUMish"), |
| 24 | -} | 24 | + ge::AscendString("ai.onnx::17::NPUMish"), ge::AscendString("ai.onnx::18::NPUMish")}) |
| 25 | -// register Mish op info to GE | 25 | + .ParseParamsByOperatorFn(ParseParamsMish) |
| 26 | -REGISTER_CUSTOM_OP("Mish") | 26 | + .ImplyType(ImplyType::TVM); |
| 27 | - .FrameworkType(ONNX) | 27 | +} // namespace domi |
| 28 | - .OriginOpType({ge::AscendString("ai.onnx::18::Mish"), ge::AscendString("npu::1::NPUMish"), | ||
| 29 | - ge::AscendString("ai.onnx::11::NPUMish"), ge::AscendString("ai.onnx::12::NPUMish"), | ||
| 30 | - ge::AscendString("ai.onnx::13::NPUMish"), ge::AscendString("ai.onnx::14::NPUMish"), | ||
| 31 | - ge::AscendString("ai.onnx::15::NPUMish"), ge::AscendString("ai.onnx::16::NPUMish"), | ||
| 32 | - ge::AscendString("ai.onnx::17::NPUMish"), ge::AscendString("ai.onnx::18::NPUMish")}) | ||
| 33 | - .ParseParamsFn(ParseParamsMish) | ||
| 34 | - .ImplyType(ImplyType::TVM); | ||
| 35 | -} // namespace domi | ||
| @@ -0,0 +1,14 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 13 | + add_modules_ut_sources(HOSTNAME ${OP_FRAMEWORK_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | +endif() | ||
| @@ -0,0 +1,25 @@ | |||
| 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 | +namespace { | ||
| 16 | +ge::Operator CreateOperator(const std::string& name) { return ge::Operator(name, "TestOp"); } | ||
| 17 | +} // namespace | ||
| 18 | + | ||
| 19 | +TEST(OnnxMishPluginTest, NoAttributeParseReturnsSuccess) | ||
| 20 | +{ | ||
| 21 | + ge::Operator op_src = CreateOperator("src"); | ||
| 22 | + ge::Operator op_dest = CreateOperator("mish"); | ||
| 23 | + | ||
| 24 | + EXPECT_EQ(domi::ParseParamsMish(op_src, op_dest), domi::SUCCESS); | ||
| 25 | +} | ||
| @@ -1329,6 +1329,10 @@ macro(add_all_ut_sources) | |||
| 1329 | add_modules_ut_sources(HOSTNAME ${OP_TILING_MODULE_NAME} MODE PRIVATE DIR ${_UT_ROOT}/op_host) | 1329 | add_modules_ut_sources(HOSTNAME ${OP_TILING_MODULE_NAME} MODE PRIVATE DIR ${_UT_ROOT}/op_host) |
| 1330 | add_modules_ut_sources(HOSTNAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${_UT_ROOT}/op_host) | 1330 | add_modules_ut_sources(HOSTNAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${_UT_ROOT}/op_host) |
| 1331 | endif() | 1331 | endif() |
| 1332 | + # onnx 插件(framework)解析逻辑属 host 侧,目录结构与 tiling/infershape 逻辑类似 | ||
| 1333 | + if(DEFINED OP_FRAMEWORK_MODULE_NAME AND EXISTS "${_UT_ROOT}/framework") | ||
| 1334 | + add_modules_ut_sources(HOSTNAME ${OP_FRAMEWORK_MODULE_NAME} MODE PRIVATE DIR ${_UT_ROOT}/framework) | ||
| 1335 | + endif() | ||
| 1332 | endif() | 1336 | endif() |
| 1333 | 1337 | ||
| 1334 | if(UT_TEST_ALL OR OP_GRAPH_UT) | 1338 | if(UT_TEST_ALL OR OP_GRAPH_UT) |
| @@ -129,6 +129,56 @@ function(add_infershape_ut_modules OP_INFERSHAPE_MODULE_NAME) | |||
| 129 | ) | 129 | ) |
| 130 | endfunction() | 130 | endfunction() |
| 131 | 131 | ||
| 132 | +function(add_framework_ut_modules OP_FRAMEWORK_MODULE_NAME) | ||
| 133 | + # 与 tiling/infershape UT 模块逻辑类似:ONNX 插件(framework)解析逻辑属 host 侧, | ||
| 134 | + # 用例按算子拆分存放于各算子 tests/ut/framework 目录下,统一汇入 op_host UT 可执行文件。 | ||
| 135 | + set(UT_COMMON_INC ${PROJECT_SOURCE_DIR}/tests/ut/common) | ||
| 136 | + add_opbase_ut_common() | ||
| 137 | + # add framework (onnx plugin) ut test cases obj | ||
| 138 | + add_library(${OP_FRAMEWORK_MODULE_NAME}_cases_obj OBJECT) | ||
| 139 | + add_dependencies(${OP_FRAMEWORK_MODULE_NAME}_cases_obj json) | ||
| 140 | + target_include_directories(${OP_FRAMEWORK_MODULE_NAME}_cases_obj PRIVATE | ||
| 141 | + ${UT_COMMON_INC} | ||
| 142 | + ${ONNX_PLUGIN_INCLUDE} | ||
| 143 | + ${JSON_INCLUDE} | ||
| 144 | + ${GTEST_INCLUDE} | ||
| 145 | + ${OPBASE_INC_DIRS} | ||
| 146 | + ${PROJECT_SOURCE_DIR}/common/inc | ||
| 147 | + ${ASCEND_DIR}/include | ||
| 148 | + ${ASCEND_DIR}/pkg_inc | ||
| 149 | + ${ASCEND_DIR}/include/external | ||
| 150 | + ${ASCEND_DIR}/include/exe_graph | ||
| 151 | + ${ASCEND_DIR}/include/base/context_builder | ||
| 152 | + ) | ||
| 153 | + target_link_libraries(${OP_FRAMEWORK_MODULE_NAME}_cases_obj PRIVATE | ||
| 154 | + $<BUILD_INTERFACE:intf_llt_pub_asan_cxx17> | ||
| 155 | + $<BUILD_INTERFACE:dlog_headers> | ||
| 156 | + metadef | ||
| 157 | + graph | ||
| 158 | + gtest | ||
| 159 | + ) | ||
| 160 | + | ||
| 161 | + target_compile_options(${OP_FRAMEWORK_MODULE_NAME}_cases_obj PRIVATE | ||
| 162 | + ${UT_DEBUG_FLAG} | ||
| 163 | + -fno-access-control | ||
| 164 | + -Dgoogle=ascend_private | ||
| 165 | + ) | ||
| 166 | + | ||
| 167 | + target_compile_definitions(${OP_FRAMEWORK_MODULE_NAME}_cases_obj PRIVATE | ||
| 168 | + _GLIBCXX_USE_CXX11_ABI=0 | ||
| 169 | + LOG_CPP | ||
| 170 | + ) | ||
| 171 | + | ||
| 172 | + # add framework ut static lib | ||
| 173 | + add_library(${OP_FRAMEWORK_MODULE_NAME}_static_lib STATIC | ||
| 174 | + $<TARGET_OBJECTS:${OP_FRAMEWORK_MODULE_NAME}_cases_obj> | ||
| 175 | + ) | ||
| 176 | + target_link_libraries(${OP_FRAMEWORK_MODULE_NAME}_static_lib PRIVATE | ||
| 177 | + ${OP_FRAMEWORK_MODULE_NAME}_cases_obj | ||
| 178 | + opbase_ut_common | ||
| 179 | + ) | ||
| 180 | +endfunction() | ||
| 181 | + | ||
| 132 | function(add_opapi_ut_modules OP_API_MODULE_NAME) | 182 | function(add_opapi_ut_modules OP_API_MODULE_NAME) |
| 133 | ## add opapi ut L2 obj | 183 | ## add opapi ut L2 obj |
| 134 | add_library(${OP_API_MODULE_NAME}_cases_obj OBJECT) | 184 | add_library(${OP_API_MODULE_NAME}_cases_obj OBJECT) |
| @@ -387,6 +437,16 @@ function(add_modules_ut_sources) | |||
| 387 | target_sources(${MODULE_HOSTNAME}_cases_obj ${MODULE_MODE} ${OPHOST_OPGRAPH_SRCS}) | 437 | target_sources(${MODULE_HOSTNAME}_cases_obj ${MODULE_MODE} ${OPHOST_OPGRAPH_SRCS}) |
| 388 | message(STATUS "=== Debug<add_modules_ut_sources>: ${MODULE_HOSTNAME}_cases_obj ${OPHOST_OPGRAPH_SRCS}") | 438 | message(STATUS "=== Debug<add_modules_ut_sources>: ${MODULE_HOSTNAME}_cases_obj ${OPHOST_OPGRAPH_SRCS}") |
| 389 | endif() | 439 | endif() |
| 440 | + | ||
| 441 | + string(FIND "${MODULE_HOSTNAME}_cases_obj" "framework" FRAMEWORK_FOUND_INDEX) | ||
| 442 | + if(${FRAMEWORK_FOUND_INDEX} GREATER_EQUAL 0) | ||
| 443 | + file(GLOB OPHOST_FRAMEWORK_SRCS ${MODULE_DIR}/test_*_onnx_plugin.cpp) | ||
| 444 | + if (NOT TARGET ${MODULE_HOSTNAME}_cases_obj) | ||
| 445 | + add_framework_ut_modules(${OP_FRAMEWORK_MODULE_NAME}) | ||
| 446 | + endif() | ||
| 447 | + target_sources(${MODULE_HOSTNAME}_cases_obj ${MODULE_MODE} ${OPHOST_FRAMEWORK_SRCS}) | ||
| 448 | + message(STATUS "=== Debug<add_modules_ut_sources>: ${MODULE_HOSTNAME}_cases_obj ${OPHOST_FRAMEWORK_SRCS}") | ||
| 449 | + endif() | ||
| 390 | endfunction() | 450 | endfunction() |
| 391 | 451 | ||
| 392 | if (UT_TEST_ALL OR OP_KERNEL_UT) | 452 | if (UT_TEST_ALL OR OP_KERNEL_UT) |
| @@ -28,35 +28,10 @@ | |||
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | + | ||
| 31 | 32 | ||
| 32 | 33 | ||
| 33 | namespace domi { | 34 | namespace domi { |
| 34 | -inline bool StrToFloat(const std::string& str, float& value) | ||
| 35 | -{ | ||
| 36 | - if (str.empty()) { | ||
| 37 | - return false; | ||
| 38 | - } | ||
| 39 | - errno = 0; | ||
| 40 | - char* end_ptr = nullptr; | ||
| 41 | - const float parsed = std::strtof(str.c_str(), &end_ptr); | ||
| 42 | - if (end_ptr == str.c_str() || *end_ptr != '\0' || errno == ERANGE) { | ||
| 43 | - return false; | ||
| 44 | - } | ||
| 45 | - value = parsed; | ||
| 46 | - return true; | ||
| 47 | -} | ||
| 48 | - | ||
| 49 | -template <typename T> | ||
| 50 | -inline std::string GetOpName(const T& op) | ||
| 51 | -{ | ||
| 52 | - ge::AscendString op_ascend_name; | ||
| 53 | - ge::graphStatus ret = op.GetName(op_ascend_name); | ||
| 54 | - if (ret != ge::GRAPH_SUCCESS) { | ||
| 55 | - std::string op_name = "None"; | ||
| 56 | - return op_name; | ||
| 57 | - } | ||
| 58 | - return op_ascend_name.GetString(); | ||
| 59 | -} | ||
| 60 | 35 | ||
| 61 | template <typename T> | 36 | template <typename T> |
| 62 | inline ge::Tensor Vec2Tensor(vector<T>& vals, const vector<int64_t>& dims, ge::DataType dtype, | 37 | inline ge::Tensor Vec2Tensor(vector<T>& vals, const vector<int64_t>& dims, ge::DataType dtype, |
| @@ -16,11 +16,30 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 19 | 23 | ||
| 20 | 24 | ||
| 21 | 25 | ||
| 22 | namespace domi { | 26 | namespace domi { |
| 23 | 27 | ||
| 28 | +inline bool StrToFloat(const std::string& str, float& value) | ||
| 29 | +{ | ||
| 30 | + if (str.empty()) { | ||
| 31 | + return false; | ||
| 32 | + } | ||
| 33 | + errno = 0; | ||
| 34 | + char* end_ptr = nullptr; | ||
| 35 | + const float parsed = std::strtof(str.c_str(), &end_ptr); | ||
| 36 | + if (end_ptr == str.c_str() || *end_ptr != '\0' || errno == ERANGE) { | ||
| 37 | + return false; | ||
| 38 | + } | ||
| 39 | + value = parsed; | ||
| 40 | + return true; | ||
| 41 | +} | ||
| 42 | + | ||
| 24 | template <typename T> | 43 | template <typename T> |
| 25 | inline std::string GetOpName(const T& op) | 44 | inline std::string GetOpName(const T& op) |
| 26 | { | 45 | { |
| @@ -1,41 +1,54 @@ | |||
| 1 | -/** | 1 | +/** |
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 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, | 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. | 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. | 8 | + * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | - */ | 9 | + */ |
| 10 | - | 10 | + |
| 11 | -#include "onnx_common.h" | 11 | +#include "plugin_util.h" |
| 12 | - | 12 | +#include "register/register.h" |
| 13 | -namespace domi { | 13 | +#include "graph/operator.h" |
| 14 | -static Status parse_params_hard_max(const Message* op_src, ge::Operator& op_dest) | 14 | +#include "nlohmann/json.hpp" |
| 15 | -{ | 15 | + |
| 16 | - const ge::onnx::NodeProto* node = reinterpret_cast<const ge::onnx::NodeProto*>(op_src); | 16 | +namespace domi { |
| 17 | - if (node == nullptr) { | 17 | +using json = nlohmann::json; |
| 18 | - OP_LOGE(GetOpName(op_dest).c_str(), "Dynamic cast op_src to NodeProto failed."); | 18 | +static Status parse_params_hard_max(const ge::Operator& op_src, ge::Operator& op_dest) |
| 19 | - return FAILED; | 19 | +{ |
| 20 | - } | 20 | + int axis = -1; |
| 21 | - int axis = -1; | 21 | + ge::AscendString attrs_string; |
| 22 | - for (auto attr : node->attribute()) { | 22 | + if (op_src.GetAttr("attribute", attrs_string) == ge::GRAPH_SUCCESS) { |
| 23 | - if (attr.name() == "axis") { | 23 | + try { |
| 24 | - axis = attr.i(); | 24 | + json attrs = json::parse(attrs_string.GetString()); |
| 25 | - } | 25 | + if (attrs.contains("attribute") && attrs["attribute"].is_array()) { |
| 26 | - } | 26 | + for (json& attr : attrs["attribute"]) { |
| 27 | - op_dest.SetAttr("axis", axis); | 27 | + if (attr.value("name", "") == "axis" && attr.contains("i")) { |
| 28 | - return SUCCESS; | 28 | + axis = attr["i"].get<int>(); |
| 29 | -} | 29 | + } |
| 30 | - | 30 | + } |
| 31 | -REGISTER_CUSTOM_OP("HardMax") | 31 | + } |
| 32 | - .FrameworkType(ONNX) | 32 | + } catch (const nlohmann::json::exception& e) { |
| 33 | - .OriginOpType({ge::AscendString("ai.onnx::8::Hardmax"), ge::AscendString("ai.onnx::9::Hardmax"), | 33 | + OP_LOGE(GetOpName(op_dest).c_str(), "JSON parse error: %s", e.what()); |
| 34 | - ge::AscendString("ai.onnx::10::Hardmax"), ge::AscendString("ai.onnx::11::Hardmax"), | 34 | + return FAILED; |
| 35 | - ge::AscendString("ai.onnx::12::Hardmax"), ge::AscendString("ai.onnx::13::Hardmax"), | 35 | + } catch (...) { |
| 36 | - ge::AscendString("ai.onnx::14::Hardmax"), ge::AscendString("ai.onnx::15::Hardmax"), | 36 | + OP_LOGE(GetOpName(op_dest).c_str(), "get unknown exception, please check compile info json."); |
| 37 | - ge::AscendString("ai.onnx::16::Hardmax"), ge::AscendString("ai.onnx::17::Hardmax"), | 37 | + return FAILED; |
| 38 | - ge::AscendString("ai.onnx::18::Hardmax")}) | 38 | + } |
| 39 | - .ParseParamsFn(parse_params_hard_max) | 39 | + } |
| 40 | - .ImplyType(ImplyType::TVM); | 40 | + op_dest.SetAttr("axis", axis); |
| 41 | -} // namespace domi | 41 | + return SUCCESS; |
| 42 | +} | ||
| 43 | + | ||
| 44 | +REGISTER_CUSTOM_OP("HardMax") | ||
| 45 | + .FrameworkType(ONNX) | ||
| 46 | + .OriginOpType({ge::AscendString("ai.onnx::8::Hardmax"), ge::AscendString("ai.onnx::9::Hardmax"), | ||
| 47 | + ge::AscendString("ai.onnx::10::Hardmax"), ge::AscendString("ai.onnx::11::Hardmax"), | ||
| 48 | + ge::AscendString("ai.onnx::12::Hardmax"), ge::AscendString("ai.onnx::13::Hardmax"), | ||
| 49 | + ge::AscendString("ai.onnx::14::Hardmax"), ge::AscendString("ai.onnx::15::Hardmax"), | ||
| 50 | + ge::AscendString("ai.onnx::16::Hardmax"), ge::AscendString("ai.onnx::17::Hardmax"), | ||
| 51 | + ge::AscendString("ai.onnx::18::Hardmax")}) | ||
| 52 | + .ParseParamsByOperatorFn(parse_params_hard_max) | ||
| 53 | + .ImplyType(ImplyType::TVM); | ||
| 54 | +} // namespace domi | ||
| @@ -1,38 +1,34 @@ | |||
| 1 | -/** | 1 | +/** |
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 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, | 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. | 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. | 8 | + * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | - */ | 9 | + */ |
| 10 | - | 10 | + |
| 11 | -#include "onnx_common.h" | 11 | +#include "plugin_util.h" |
| 12 | - | 12 | +#include "register/register.h" |
| 13 | -namespace domi { | 13 | +#include "graph/operator.h" |
| 14 | -using NodeProto = ge::onnx::NodeProto; | 14 | + |
| 15 | -static Status ParseParamsSize(const Message* op_src, ge::Operator& op_dest) | 15 | +namespace domi { |
| 16 | -{ | 16 | +static Status ParseParamsSize(const ge::Operator&, ge::Operator& op_dest) |
| 17 | - const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); | 17 | +{ |
| 18 | - if (node == nullptr) { | 18 | + // set output's default type to int64. |
| 19 | - OP_LOGE(GetOpName(op_dest).c_str(), "Dynamic cast op_src to NodeProto failed."); | 19 | + ge::DataType output_type = ge::DT_INT64; |
| 20 | - return FAILED; | 20 | + op_dest.SetAttr("dtype", output_type); |
| 21 | - } | 21 | + return SUCCESS; |
| 22 | - // set output's default type to int64. | 22 | +} |
| 23 | - ge::DataType output_type = ge::DT_INT64; | 23 | +// register Size op info to GE |
| 24 | - op_dest.SetAttr("dtype", output_type); | 24 | +REGISTER_CUSTOM_OP("Size") |
| 25 | - return SUCCESS; | 25 | + .FrameworkType(ONNX) |
| 26 | -} | 26 | + .OriginOpType({ge::AscendString("ai.onnx::8::Size"), ge::AscendString("ai.onnx::9::Size"), |
| 27 | -// register Size op info to GE | 27 | + ge::AscendString("ai.onnx::10::Size"), ge::AscendString("ai.onnx::11::Size"), |
| 28 | -REGISTER_CUSTOM_OP("Size") | 28 | + ge::AscendString("ai.onnx::12::Size"), ge::AscendString("ai.onnx::13::Size"), |
| 29 | - .FrameworkType(ONNX) | 29 | + ge::AscendString("ai.onnx::14::Size"), ge::AscendString("ai.onnx::15::Size"), |
| 30 | - .OriginOpType({ge::AscendString("ai.onnx::8::Size"), ge::AscendString("ai.onnx::9::Size"), | 30 | + ge::AscendString("ai.onnx::16::Size"), ge::AscendString("ai.onnx::17::Size"), |
| 31 | - ge::AscendString("ai.onnx::10::Size"), ge::AscendString("ai.onnx::11::Size"), | 31 | + ge::AscendString("ai.onnx::18::Size")}) |
| 32 | - ge::AscendString("ai.onnx::12::Size"), ge::AscendString("ai.onnx::13::Size"), | 32 | + .ParseParamsByOperatorFn(ParseParamsSize) |
| 33 | - ge::AscendString("ai.onnx::14::Size"), ge::AscendString("ai.onnx::15::Size"), | 33 | + .ImplyType(ImplyType::TVM); |
| 34 | - ge::AscendString("ai.onnx::16::Size"), ge::AscendString("ai.onnx::17::Size"), | 34 | +} // namespace domi |
| 35 | - ge::AscendString("ai.onnx::18::Size")}) | ||
| 36 | - .ParseParamsFn(ParseParamsSize) | ||
| 37 | - .ImplyType(ImplyType::TVM); | ||
| 38 | -} // namespace domi | ||
| @@ -0,0 +1,14 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 13 | + add_modules_ut_sources(HOSTNAME ${OP_FRAMEWORK_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | +endif() | ||
| @@ -0,0 +1,46 @@ | |||
| 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 | +namespace { | ||
| 16 | +ge::Operator CreateOperator(const std::string& name) { return ge::Operator(name, "TestOp"); } | ||
| 17 | + | ||
| 18 | +ge::Operator CreateSourceOperator(const std::string& attrs) | ||
| 19 | +{ | ||
| 20 | + ge::Operator op_src = CreateOperator("src"); | ||
| 21 | + op_src.SetAttr("attribute", ge::AscendString(attrs.c_str())); | ||
| 22 | + return op_src; | ||
| 23 | +} | ||
| 24 | +} // namespace | ||
| 25 | + | ||
| 26 | +TEST(OnnxHardMaxPluginTest, ParseAxisAttribute) | ||
| 27 | +{ | ||
| 28 | + ge::Operator op_src = CreateSourceOperator(R"({"attribute":[{"name":"axis","type":2,"i":2}]})"); | ||
| 29 | + ge::Operator op_dest = CreateOperator("hardmax"); | ||
| 30 | + int64_t axis = 0; | ||
| 31 | + | ||
| 32 | + EXPECT_EQ(domi::parse_params_hard_max(op_src, op_dest), domi::SUCCESS); | ||
| 33 | + EXPECT_EQ(op_dest.GetAttr("axis", axis), ge::GRAPH_SUCCESS); | ||
| 34 | + EXPECT_EQ(axis, 2); | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +TEST(OnnxHardMaxPluginTest, KeepsDefaultWithoutAttributes) | ||
| 38 | +{ | ||
| 39 | + ge::Operator op_src = CreateOperator("src"); | ||
| 40 | + ge::Operator op_dest = CreateOperator("hardmax"); | ||
| 41 | + int64_t axis = 0; | ||
| 42 | + | ||
| 43 | + EXPECT_EQ(domi::parse_params_hard_max(op_src, op_dest), domi::SUCCESS); | ||
| 44 | + EXPECT_EQ(op_dest.GetAttr("axis", axis), ge::GRAPH_SUCCESS); | ||
| 45 | + EXPECT_EQ(axis, -1); | ||
| 46 | +} | ||
| @@ -0,0 +1,29 @@ | |||
| 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 | +namespace { | ||
| 16 | +ge::Operator CreateOperator(const std::string& name) { return ge::Operator(name, "TestOp"); } | ||
| 17 | +} // namespace | ||
| 18 | + | ||
| 19 | +TEST(OnnxSizePluginTest, SetsInt64Dtype) | ||
| 20 | +{ | ||
| 21 | + ge::Operator op_src = CreateOperator("src"); | ||
| 22 | + ge::Operator op_dest = CreateOperator("size"); | ||
| 23 | + // SetAttr 走 ge::DataType 精确重载存储,读取时用同类型 | ||
| 24 | + ge::DataType dtype = ge::DT_UNDEFINED; | ||
| 25 | + | ||
| 26 | + EXPECT_EQ(domi::ParseParamsSize(op_src, op_dest), domi::SUCCESS); | ||
| 27 | + EXPECT_EQ(op_dest.GetAttr("dtype", dtype), ge::GRAPH_SUCCESS); | ||
| 28 | + EXPECT_EQ(dtype, ge::DT_INT64); | ||
| 29 | +} | ||
| @@ -18,6 +18,13 @@ if(UT_TEST_ALL OR OP_HOST_UT OR OP_GRAPH_UT OR OP_API_UT) | |||
| 18 | endif() | 18 | endif() |
| 19 | endforeach() | 19 | endforeach() |
| 20 | 20 | ||
| 21 | + if(EXISTS ${OPS_NN_DIR}/common/tests/ut/framework/CMakeLists.txt) | ||
| 22 | + if(NOT ASCEND_OP_NAME) | ||
| 23 | + add_subdirectory(${OPS_NN_DIR}/common/tests/ut/framework | ||
| 24 | + ${CMAKE_CURRENT_BINARY_DIR}/common_op_framework) | ||
| 25 | + endif() | ||
| 26 | + endif() | ||
| 27 | + | ||
| 21 | ## add ophost_nn_ut so | 28 | ## add ophost_nn_ut so |
| 22 | if(TARGET ${OPHOST_NAME}_infer_obj) | 29 | if(TARGET ${OPHOST_NAME}_infer_obj) |
| 23 | message(STATUS "Found infershape file.") | 30 | message(STATUS "Found infershape file.") |
| @@ -72,6 +79,7 @@ if(UT_TEST_ALL OR OP_HOST_UT OR OP_GRAPH_UT OR OP_API_UT) | |||
| 72 | -Wl,--whole-archive | 79 | -Wl,--whole-archive |
| 73 | $<$<TARGET_EXISTS:${OP_TILING_MODULE_NAME}_static_lib>:${OP_TILING_MODULE_NAME}_static_lib> | 80 | $<$<TARGET_EXISTS:${OP_TILING_MODULE_NAME}_static_lib>:${OP_TILING_MODULE_NAME}_static_lib> |
| 74 | $<$<TARGET_EXISTS:${OP_INFERSHAPE_MODULE_NAME}_static_lib>:${OP_INFERSHAPE_MODULE_NAME}_static_lib> | 81 | $<$<TARGET_EXISTS:${OP_INFERSHAPE_MODULE_NAME}_static_lib>:${OP_INFERSHAPE_MODULE_NAME}_static_lib> |
| 82 | + $<$<TARGET_EXISTS:${OP_FRAMEWORK_MODULE_NAME}_static_lib>:${OP_FRAMEWORK_MODULE_NAME}_static_lib> | ||
| 75 | -Wl,--no-whole-archive | 83 | -Wl,--no-whole-archive |
| 76 | -Wl,--no-as-needed | 84 | -Wl,--no-as-needed |
| 77 | metadef | 85 | metadef |


🟠 High Priority
变更行:新增的 ParseParamsElu 中
alpha_value = attr["f"].get<float>();(第 26 行)。受影响的契约:本框架的 ONNX 节点属性 JSON(即 op_src 上名为 "attribute" 的 attr)中,标量 float 属性字段 "f" 被序列化为 JSON 字符串而非 JSON number。同一仓库的先例插件均按此契约读取:
common/src/framework/group_normal_relu_onnx_plugin.cpp:21使用std::string eps_str = attr["f"];再经StrToFloat转换;common/src/framework/bounding_box_decode_onnx_plugin.cpp:41-45明确注释 "float type in json has accuracy loss, so we use string type to store it" 并同样std::string wh_ratio_clip_str = attr["f"];+StrToFloat转换(StrToFloat定义于本仓库common/inc/framework/onnx_common.h:34,该头文件已被本文件包含)。失败模式:当 ONNX 模型中 Elu 节点带有 alpha 属性(导出器通常显式写出 alpha,甚至默认值也会写出)时,JSON 中 "f" 字段为字符串,
nlohmann::json::get<float>()对字符串会抛出 type_error.302("type must be number, but is string"),该异常被catch (...)捕获后函数返回 FAILED。按 ParseParamsByOperatorFn 契约,FAILED 返回会导致该算子解析/图编译失败;即使框架容忍 FAILED,alpha 也会被静默丢弃而使用默认值 1.0。旧实现attr.f()能正确解析 float,因此这是本次迁移引入的功能回归。