已合并
fix: migrate simple onnx parse params plugins #9161
clinglai0517创建于 12 天前
fix: migrate simple onnx parse params plugins #9161
已合并
clinglai0517创建于 12 天前
23 个文件变更+619-241
@@ -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 ut164 # 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 of3+ * 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 GE32+ }
33-REGISTER_CUSTOM_OP("Elu")33+ }
atomgit-bot
atomgit-botatomgit-bot12 天前

🟠 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,因此这是本次迁移引入的功能回归。

改动建议
33
+ if (attr.value("name", "") == "alpha" && attr.contains("f")) {
34
+ std::string alpha_str = attr["f"];
35
+ if (!StrToFloat(alpha_str, alpha_value)) {
36
+ OP_LOGE(GetOpName(op_dest).c_str(), "invalid alpha value: %s", alpha_str.c_str());
37
+ return FAILED;
38
+ }
33
39
  }
应用建议
likedislike
clinglai0517
12 天前 评论:
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
Cchenqi31712 天前

[Suggestion] catch(...) 过于宽泛,错误信息缺乏定位价值

Elu/LeakyRelu/HardMax 三个插件均使用 catch (...) 捕获所有异常,仅输出 "get unknown exception" 通用消息。当 JSON 格式错误、类型不匹配(如 attr["f"] 是数字而非字符串)时,无法定位具体原因。

建议改为 catch (const nlohmann::json::exception& e) 并输出 e.what(),帮助用户快速定位问题。例如:

} catch (const nlohmann::json::exception& e) {
    OP_LOGE(GetOpName(op_dest).c_str(), "JSON parse error: %s", e.what());
    return FAILED;
} catch (...) {
    OP_LOGE(GetOpName(op_dest).c_str(), "get unknown exception, please check compile info json.");
    return FAILED;
}
likedislike
clinglai0517
11 天前 评论:
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 domi43+ }
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+#include <gtest/gtest.h>
12+ 
13+#include "../../../framework/elu_onnx_plugin.cpp"
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 * \brief13 * \brief
14 */14 */
15 15 
16-#include "onnx_common.h"16+#include "plugin_util.h"
17+#include "register/register.h"
18+#include "graph/operator.h"
17 19 
18namespace domi {20namespace 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 
32REGISTER_CUSTOM_OP("FastGelu")23REGISTER_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 domi32+} // 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+#include <gtest/gtest.h>
12+ 
13+#include "../../../framework/npu_fast_gelu_onnx_plugin.cpp"
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 of3+ * 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+ }
atomgit-bot
atomgit-botatomgit-bot12 天前

🟠 High Priority

变更行:新增的 ParseParamsLeakyRelu 中 negative_slope = 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:21std::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" 并以相同方式解析(StrToFloat 定义于本仓库 common/inc/framework/onnx_common.h:34,已被本文件包含)。

失败模式:当 ONNX 模型中的 LeakyRelu 节点带 alpha 属性(导出器通常会显式写出,包括默认 0.01)时,JSON 中 "f" 为字符串,nlohmann::json::get<float>() 抛出 type_error.302("type must be number, but is string"),被 catch (...) 捕获后返回 FAILED,导致算子解析/图编译失败;即使框架容忍 FAILED,negative_slope 也会被静默丢弃而回退到默认 0.01。旧实现 attr.f() 能正确解析,此为本次迁移引入的功能回归。

改动建议
33
+ if (attr.value("name", "") == "alpha" && attr.contains("f")) {
34
+ std::string slope_str = attr["f"];
35
+ if (!StrToFloat(slope_str, negative_slope)) {
36
+ OP_LOGE(GetOpName(op_dst).c_str(), "invalid alpha value: %s", slope_str.c_str());
37
+ return FAILED;
38
+ }
33
39
  }
应用建议
likedislike
clinglai0517
12 天前 评论:
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 domi43+ }
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+#include <gtest/gtest.h>
12+ 
13+#include "../../../framework/leaky_relu_onnx_plugin.cpp"
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 of3+ * 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 GE25+ .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+#include <gtest/gtest.h>
12+ 
13+#include "../../../framework/mish_onnx_plugin.cpp"
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 )
130endfunction()130endfunction()
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+ 
132function(add_opapi_ut_modules OP_API_MODULE_NAME)182function(add_opapi_ut_modules OP_API_MODULE_NAME)
133 ## add opapi ut L2 obj183 ## 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()
390endfunction()450endfunction()
391 451 
392if (UT_TEST_ALL OR OP_KERNEL_UT)452if (UT_TEST_ALL OR OP_KERNEL_UT)
@@ -28,35 +28,10 @@
28#include "graph/graph.h"28#include "graph/graph.h"
29#include "base/err_msg.h"29#include "base/err_msg.h"
30#include "log/log.h"30#include "log/log.h"
31+#include "plugin_util.h"
31#include "onnx/proto/ge_onnx.pb.h"32#include "onnx/proto/ge_onnx.pb.h"
32 33 
33namespace domi {34namespace 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 
61template <typename T>36template <typename T>
62inline ge::Tensor Vec2Tensor(vector<T>& vals, const vector<int64_t>& dims, ge::DataType dtype,37inline ge::Tensor Vec2Tensor(vector<T>& vals, const vector<int64_t>& dims, ge::DataType dtype,
@@ -16,11 +16,30 @@
16#ifndef FRAMEWORK_PLUGIN_UTIL_H16#ifndef FRAMEWORK_PLUGIN_UTIL_H
17#define FRAMEWORK_PLUGIN_UTIL_H17#define FRAMEWORK_PLUGIN_UTIL_H
18 18 
19+#include <cerrno>
20+#include <cstdlib>
21+#include <string>
22+ 
19#include "log/log.h"23#include "log/log.h"
20#include "graph/ascend_string.h"24#include "graph/ascend_string.h"
21 25 
22namespace domi {26namespace 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+ 
24template <typename T>43template <typename T>
25inline std::string GetOpName(const T& op)44inline 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 of3+ * 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 domi41+ 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 of3+ * 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 GE27+ 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+#include <gtest/gtest.h>
12+ 
13+#include "../../../src/framework/hardmax_onnx_plugin.cpp"
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+#include <gtest/gtest.h>
12+ 
13+#include "../../../src/framework/size_onnx_plugin.cpp"
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 so28 ## 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-archive79 -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-archive83 -Wl,--no-whole-archive
76 -Wl,--no-as-needed84 -Wl,--no-as-needed
77 metadef85 metadef