Merged
feat: ConfusionMatrix 算子下一代实现 #5444
feat: ConfusionMatrix 算子下一代实现 #5444
Merged
shengleAdd on Sep 8
Total: 25 files changed+3036-38
@@ -425,44 +425,6 @@ REG_OP(ExpandDims)
425 .ATTR(keep_dim, Bool, false)425 .ATTR(keep_dim, Bool, false)
426 .OP_END_FACTORY_REG(Bitcast)426 .OP_END_FACTORY_REG(Bitcast)
427 427 
428- /**
429- * @brief Computes the confusion matrix from predictions and labels .
430- 
431- * @par Inputs:
432- * Three inputs, including:
433- * @li labels: A Tensor. Must be one of the following types: float16, float32,
434- * int32, int8, uint8. 1D. Has format ND.
435- * @li predictions: A Tensor. Must be one of the following types: float16,
436- * float32, int32, int8, uint8. 1D. Has format ND.
437- * @li weights: A optional Tensor. Must be one of the following types: float16, float32,
438- * int32, int8, uint8. 1D. Has format ND. \n
439- 
440- * @par Attributes:
441- * @li num_classes: An integer for the shape of the output matrix.
442- * @li dtype: Data type of the confusion matrix. \n
443- 
444- * @par Outputs:
445- * y: A Tensor. 1D. Has format ND. Has the same type and format as input "labels" . \n
446- 
447- * @attention Constraints:
448- * @li "weights", "labels", and "predictions" are 1D tensors.
449- * @li The output is with shape (num_classes, num_classes),
450- * where, 1 <= num_classes <= 4096 . \n
451- 
452- * @see Region()
453- 
454- * @par Third-party framework compatibility
455- * Compatible with the TensorFlow operator ConfusionMatrix.
456- */
457- REG_OP(ConfusionMatrix)
458- .INPUT(labels, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
459- .INPUT(predictions, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
460- .OPTIONAL_INPUT(weights, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
461- .OUTPUT(y, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
462- .REQUIRED_ATTR(num_classes, Int)
463- .REQUIRED_ATTR(dtype, String)
464- .OP_END_FACTORY_REG(ConfusionMatrix)
465- 
466 /**428 /**
467 * @brief Computes the cumulative product of the tensor "x" along "axis" .429 * @brief Computes the cumulative product of the tensor "x" along "axis" .
468 430 
@@ -605,6 +605,16 @@
605 <td>√</td>605 <td>√</td>
606 <td>AI Core/AI CPU</td>606 <td>AI Core/AI CPU</td>
607 <td>该算子对输入Tensor完成linear_cross运算。</td>607 <td>该算子对输入Tensor完成linear_cross运算。</td>
608+ </tr>
609+ <tr>
610+ <td>math</td>
611+ <td><a href="../../math/confusion_matrix/README.md">confusion_matrix</a></td>
612+ <td>√</td>
613+ <td>√</td>
614+ <td>×</td>
615+ <td>√</td>
616+ <td>AI Core</td>
617+ <td>计算分类任务的混淆矩阵,统计每个(标签, 预测)对的出现次数或加权累加和,输出num_classes×num_classes矩阵。</td>
608 </tr>618 </tr>
609 <tr>619 <tr>
610 <td>math</td>620 <td>math</td>
@@ -0,0 +1,15 @@
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+set(SUPPORT_COMPUTE_UNIT "ascend950")
13+# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译
14+set(SUPPORT_TILING_DIR "arch35")
15+add_all_modules_sources(OPTYPE confusion_matrix ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE)
@@ -0,0 +1,106 @@
1+# ConfusionMatrix
2+ 
3+## 产品支持情况
4+ 
5+| 产品 | 是否支持 |
6+| :----------------------------------------------------------- | :------: |
7+| <term>Ascend 950PR&950DT系列产品</term> | √ |
G

[Major] README 产品支持表与实际注册范围不符(仅注册 ascend950)

README 产品支持表声明 6 大产品(950PR&950DT、A3、A2、200I/500 A2、推理系列、训练系列)全部支持,但 confusion_matrix_def.cpp 仅 AddConfig("ascend950"),tiling 实现仅位于 op_host/arch35/(DAV_3510 专属)且 binary json 仅在 op_host/config/ascend950/ 下。其余 5 类产品既无算子注册也无对应架构 tiling,用户按文档在 A2/A3 等平台调用会直接失败。建议将产品支持表收敛为实际注册的 Ascend 950 系列,或补齐其它产品的注册与 arch22 tiling 后再声明支持。


(来自自动检视代理,以 gubaocheng 身份提交)

likedislike
shengle
shengle
Oct 8 Comments:
8+| <term>Atlas A3系列产品</term> | √ |
9+| <term>Atlas A2系列产品</term> | √ |
10+| <term>Atlas 200I/500 A2推理产品</term> | √ |
11+| <term>Atlas推理系列产品</term> | √ |
12+| <term>Atlas训练系列产品</term> | √ |
13+ 
14+## 功能说明
15+ 
16+- 算子功能:计算分类任务的混淆矩阵。给定真实标签labels和预测标签predictions,统计每个(label, prediction)对的出现次数,生成num_classes×num_classes的矩阵。当weights不为空时,每次匹配的贡献为对应的权重值而非1。
17+ 
18+- 计算公式:
19+ 
20+ 如果指定了weights,则
21+ 
22+ $$
23+ y[labels_i, predictions_i] = y[labels_i, predictions_i] + weights_i
24+ $$
25+ 
26+ 否则:
27+ 
28+ $$
29+ y[labels_i, predictions_i] = y[labels_i, predictions_i] + 1
30+ $$
31+ 
32+## 参数说明
33+ 
34+<table style="undefined;table-layout: fixed; width: 980px"><colgroup>
35+ <col style="width: 100px">
36+ <col style="width: 150px">
37+ <col style="width: 280px">
38+ <col style="width: 330px">
39+ <col style="width: 120px">
40+ </colgroup>
41+ <thead>
42+ <tr>
43+ <th>参数名</th>
44+ <th>输入/输出/属性</th>
45+ <th>描述</th>
46+ <th>数据类型</th>
47+ <th>数据格式</th>
48+ </tr></thead>
49+ <tbody>
50+ <tr>
51+ <td>labels</td>
52+ <td>输入</td>
53+ <td>真实标签,1维tensor,取值范围[0, num_classes)。</td>
54+ <td>INT8、INT32、UINT8、FLOAT16、FLOAT</td>
55+ <td>ND</td>
56+ </tr>
57+ <tr>
58+ <td>predictions</td>
59+ <td>输入</td>
60+ <td>预测标签,1维tensor,shape和dtype与labels一致。</td>
61+ <td>INT8、INT32、UINT8、FLOAT16、FLOAT</td>
62+ <td>ND</td>
63+ </tr>
64+ <tr>
65+ <td>weights</td>
66+ <td>输入</td>
67+ <td>每个样本的权重,可为空。shape与labels一致。</td>
68+ <td>FLOAT、FLOAT16、INT32、INT8、UINT8</td>
69+ <td>ND</td>
70+ </tr>
71+ <tr>
72+ <td>num_classes</td>
73+ <td>属性</td>
74+ <td>类别数量,取值范围[1, 4096]。</td>
75+ <td>INT</td>
76+ <td>-</td>
77+ </tr>
78+ <tr>
79+ <td>dtype</td>
80+ <td>属性</td>
81+ <td>输出tensor的数据类型。</td>
82+ <td>STRING</td>
83+ <td>-</td>
84+ </tr>
85+ <tr>
86+ <td>y</td>
87+ <td>输出</td>
88+ <td>混淆矩阵,shape为[num_classes, num_classes]。</td>
89+ <td>FLOAT、FLOAT16、INT32、INT8、UINT8</td>
90+ <td>ND</td>
91+ </tr>
92+ </tbody></table>
93+ 
94+## 约束说明
95+ 
96+- labels和predictions的shape必须一致。
97+- labels和predictions的dtype必须一致。
98+- weights不为空时,其shape必须与labels一致。
99+- labels和predictions中的值必须在[0, num_classes)范围内。
100+- num_classes取值范围为[1, 4096]。
101+ 
102+## 调用说明
103+ 
104+| 调用方式 | 调用样例 | 说明 |
105+|--------------|--------|------|
106+| 图模式调用 | [test_geir_confusion_matrix](./examples/test_geir_confusion_matrix.cpp) | 通过[算子IR](./op_graph/confusion_matrix_proto.h)构图方式调用ConfusionMatrix算子。 |
@@ -0,0 +1,296 @@
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 <iostream>
12+#include <fstream>
13+#include <string.h>
14+#include <stdint.h>
15+#include <vector>
16+#include <string>
17+#include <map>
18+#include "assert.h"
19+ 
20+#include "graph.h"
21+#include "types.h"
22+#include "tensor.h"
23+#include "ge_error_codes.h"
24+#include "ge_api_types.h"
25+#include "ge_api.h"
26+#include "array_ops.h"
27+#include "ge_ir_build.h"
28+ 
29+#include "nn_other.h"
30+#include "../op_graph/confusion_matrix_proto.h"
31+ 
32+#define FAILED -1
33+#define SUCCESS 0
34+ 
35+using namespace ge;
36+using std::map;
37+using std::string;
38+using std::vector;
39+ 
40+#define ADD_INPUT(inputIndex, inputName, inputDtype, inputShape) \
41+ vector<int64_t> placeholder##inputIndex##_shape = inputShape; \
42+ auto placeholder##inputIndex = op::Data("placeholder" + std::to_string(inputIndex)); \
43+ placeholder##inputIndex.set_attr_index(0); \
44+ TensorDesc placeholder##inputIndex##_desc = TensorDesc(ge::Shape(placeholder##inputIndex##_shape), FORMAT_ND, \
45+ inputDtype); \
46+ placeholder##inputIndex##_desc.SetPlacement(ge::kPlacementHost); \
47+ placeholder##inputIndex##_desc.SetFormat(FORMAT_ND); \
48+ Tensor tensor_placeholder##inputIndex; \
49+ ret = GenOnesData(placeholder##inputIndex##_shape, tensor_placeholder##inputIndex, placeholder##inputIndex##_desc, \
50+ inputDtype, 1); \
51+ if (ret != SUCCESS) { \
52+ printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str()); \
53+ return FAILED; \
54+ } \
55+ placeholder##inputIndex.update_input_desc_x(placeholder##inputIndex##_desc); \
56+ input.push_back(tensor_placeholder##inputIndex); \
57+ graph.AddOp(placeholder##inputIndex); \
58+ op1.set_input_##inputName(placeholder##inputIndex); \
59+ inputs.push_back(placeholder##inputIndex);
60+ 
61+#define ADD_OUTPUT(outputIndex, outputName, outputDtype, outputShape) \
62+ TensorDesc outputName##outputIndex##_desc = TensorDesc(ge::Shape(outputShape), FORMAT_ND, outputDtype); \
63+ op1.update_output_desc_##outputName(outputName##outputIndex##_desc);
64+ 
65+string GetTime()
66+{
67+ time_t timep;
68+ time(&timep);
69+ char tmp[64];
70+ strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep));
71+ return tmp;
72+}
73+ 
74+uint32_t GetDataTypeSize(DataType dt)
75+{
76+ uint32_t dilation = 1;
77+ if (dt == ge::DT_FLOAT) {
78+ dilation = 4;
79+ } else if (dt == ge::DT_FLOAT16) {
80+ dilation = 2;
81+ } else if (dt == ge::DT_BF16) {
82+ dilation = 2;
83+ } else if (dt == ge::DT_INT16) {
84+ dilation = 2;
85+ } else if (dt == ge::DT_UINT16) {
86+ dilation = 2;
87+ } else if (dt == ge::DT_INT32) {
88+ dilation = 4;
89+ } else if (dt == ge::DT_UINT32) {
90+ dilation = 4;
91+ } else if (dt == ge::DT_INT64) {
92+ dilation = 8;
93+ } else if (dt == ge::DT_UINT64) {
94+ dilation = 8;
95+ } else if (dt == ge::DT_INT8) {
96+ dilation = 1;
97+ }
98+ return dilation;
99+}
100+ 
101+int32_t GenOnesData(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, DataType data_type,
102+ int value)
103+{
104+ input_tensor_desc.SetRealDimCnt(shapes.size());
105+ size_t size = 1;
106+ for (uint32_t i = 0; i < shapes.size(); i++) {
107+ size *= shapes[i];
108+ }
109+ size_t data_len = size * GetDataTypeSize(data_type);
110+ uint8_t* pData = new (std::nothrow) uint8_t[data_len];
111+ if (pData == nullptr) {
112+ return FAILED;
113+ }
114+ // 按 dtype 实际宽度逐元素写入:固定按 int32 写会在 dtype < 4 字节时堆越界,
115+ // dtype > 4 字节时留下未初始化数据,且 float 会被写成 1.4e-45 而非 1.0
116+ for (size_t i = 0; i < size; ++i) {
117+ switch (data_type) {
118+ case ge::DT_FLOAT:
119+ *(reinterpret_cast<float*>(pData) + i) = static_cast<float>(value);
120+ break;
121+ case ge::DT_FLOAT16: // 1.0 的 FP16 位型
122+ *(reinterpret_cast<uint16_t*>(pData) + i) = 0x3C00;
123+ break;
124+ case ge::DT_BF16: // 1.0 的 BF16 位型
125+ *(reinterpret_cast<uint16_t*>(pData) + i) = 0x3F80;
126+ break;
127+ case ge::DT_INT8:
128+ *(reinterpret_cast<int8_t*>(pData) + i) = static_cast<int8_t>(value);
129+ break;
130+ case ge::DT_UINT8:
131+ *(reinterpret_cast<uint8_t*>(pData) + i) = static_cast<uint8_t>(value);
132+ break;
133+ case ge::DT_INT16:
134+ *(reinterpret_cast<int16_t*>(pData) + i) = static_cast<int16_t>(value);
135+ break;
136+ case ge::DT_UINT16:
137+ *(reinterpret_cast<uint16_t*>(pData) + i) = static_cast<uint16_t>(value);
138+ break;
139+ case ge::DT_INT32:
140+ *(reinterpret_cast<int32_t*>(pData) + i) = value;
141+ break;
142+ case ge::DT_UINT32:
143+ *(reinterpret_cast<uint32_t*>(pData) + i) = static_cast<uint32_t>(value);
144+ break;
145+ case ge::DT_INT64:
146+ *(reinterpret_cast<int64_t*>(pData) + i) = static_cast<int64_t>(value);
147+ break;
148+ case ge::DT_UINT64:
149+ *(reinterpret_cast<uint64_t*>(pData) + i) = static_cast<uint64_t>(value);
150+ break;
151+ default:
152+ printf("%s - ERROR - [XIR]: GenOnesData unsupported dtype %d\n", GetTime().c_str(),
153+ static_cast<int32_t>(data_type));
154+ return FAILED;
155+ }
156+ }
157+ input_tensor = Tensor(input_tensor_desc, pData, data_len);
158+ return SUCCESS;
159+}
160+ 
161+int32_t WriteDataToFile(string bin_file, uint64_t data_size, uint8_t* inputData)
162+{
163+ FILE* fp = fopen(bin_file.c_str(), "w");
164+ if (fp == nullptr) {
165+ return FAILED;
166+ }
167+ fwrite(inputData, sizeof(uint8_t), data_size, fp);
168+ fclose(fp);
169+ return SUCCESS;
170+}
171+ 
172+int CreateOppInGraph(DataType inDtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs,
173+ std::vector<Operator>& outputs, Graph& graph)
174+{
175+ Status ret = SUCCESS;
176+ // ConfusionMatrix: 3 inputs (labels, predictions, weights), 1 output
177+ auto op1 = op::ConfusionMatrix("confusion_matrix1");
178+ 
179+ // labels: shape [8], dtype int32
180+ std::vector<int64_t> labelsShape = {8};
181+ ADD_INPUT(1, labels, ge::DT_INT32, labelsShape);
182+ 
183+ // predictions: shape [8], dtype int32
184+ std::vector<int64_t> predictionsShape = {8};
185+ ADD_INPUT(2, predictions, ge::DT_INT32, predictionsShape);
186+ 
187+ // weights: shape [8], dtype float32
188+ std::vector<int64_t> weightsShape = {8};
189+ ADD_INPUT(3, weights, ge::DT_FLOAT, weightsShape);
190+ 
191+ // output: shape [num_classes, num_classes], dtype float32
192+ std::vector<int64_t> outputShape = {4, 4};
193+ ADD_OUTPUT(1, y, ge::DT_FLOAT, outputShape);
194+ 
195+ // attrs: num_classes (required int), dtype (required string)
196+ op1.set_attr_num_classes(4);
197+ op1.set_attr_dtype("float32");
198+ 
199+ outputs.push_back(op1);
200+ return SUCCESS;
201+}
202+ 
203+int main(int argc, char* argv[])
204+{
205+ const char* graph_name = "tc_ge_irrun_test";
206+ Graph graph(graph_name);
207+ std::vector<ge::Tensor> input;
208+ 
209+ printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str());
210+ std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
211+ Status ret = ge::GEInitialize(global_options);
212+ if (ret != SUCCESS) {
213+ printf("%s - INFO - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str());
214+ return FAILED;
215+ }
216+ printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str());
217+ 
218+ std::vector<Operator> inputs{};
219+ std::vector<Operator> outputs{};
220+ 
221+ DataType inDtype = DT_FLOAT;
222+ 
223+ ret = CreateOppInGraph(inDtype, input, inputs, outputs, graph);
224+ if (ret != SUCCESS) {
225+ printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str());
226+ return FAILED;
227+ }
228+ 
229+ if (!inputs.empty() && !outputs.empty()) {
230+ graph.SetInputs(inputs).SetOutputs(outputs);
231+ }
232+ 
233+ std::map<AscendString, AscendString> build_options = {};
234+ printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str());
235+ ge::Session* session = new Session(build_options);
236+ 
237+ if (session == nullptr) {
238+ printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str());
239+ return FAILED;
240+ }
241+ printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str());
242+ printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str());
243+ 
244+ std::map<AscendString, AscendString> graph_options = {};
245+ uint32_t graph_id = 0;
246+ ret = session->AddGraph(graph_id, graph, graph_options);
247+ if (ret != SUCCESS) {
248+ printf("%s - ERROR - [XIR]: Add graph failed\n", GetTime().c_str());
249+ delete session;
250+ GEFinalize();
251+ return FAILED;
252+ }
253+ 
254+ printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str());
255+ printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str());
256+ std::vector<ge::Tensor> output;
257+ ret = session->RunGraph(graph_id, input, output);
258+ if (ret != SUCCESS) {
259+ printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str());
260+ delete session;
261+ GEFinalize();
262+ return FAILED;
263+ }
264+ printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str());
265+ 
266+ int input_num = input.size();
267+ for (int i = 0; i < input_num; i++) {
268+ std::cout << "input " << i << " dtype : " << input[i].GetTensorDesc().GetDataType() << std::endl;
269+ string input_file = "./tc_ge_irrun_test_0008_npu_input_" + std::to_string(i) + ".bin";
270+ uint8_t* input_data_i = input[i].GetData();
271+ int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize();
272+ uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType());
273+ WriteDataToFile((const char*)input_file.c_str(), data_size, input_data_i);
274+ }
275+ 
276+ int output_num = output.size();
277+ for (int i = 0; i < output_num; i++) {
278+ std::cout << "output " << i << " dtype : " << output[i].GetTensorDesc().GetDataType() << std::endl;
279+ string output_file = "./tc_ge_irrun_test_0008_npu_output_" + std::to_string(i) + ".bin";
280+ uint8_t* output_data_i = output[i].GetData();
281+ int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize();
282+ uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType());
283+ WriteDataToFile((const char*)output_file.c_str(), data_size, output_data_i);
284+ }
285+ 
286+ printf("%s - INFO - [XIR]: Precision is ok\n", GetTime().c_str());
287+ printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str());
288+ delete session;
289+ ret = ge::GEFinalize();
290+ if (ret != SUCCESS) {
291+ printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str());
292+ return FAILED;
293+ }
294+ printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str());
295+ return SUCCESS;
296+}
@@ -0,0 +1,60 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_graph_infer.cpp
13+ * \brief Infer data type implementation for ConfusionMatrix operator
14+ */
15+ 
16+#include "register/op_impl_registry.h"
17+#include "log/log.h"
18+ 
19+#include <string>
20+ 
21+using namespace ge;
22+namespace ops {
23+static constexpr size_t kAttrIndexDtype = 1U;
24+static constexpr size_t kOutputIndexY = 0U;
25+ 
26+static ge::graphStatus InferDataTypeForConfusionMatrix(gert::InferDataTypeContext* context)
27+{
28+ OP_LOGI(context->GetNodeName(), "Begin to do InferDataTypeForConfusionMatrix");
29+ 
30+ auto attrs = context->GetAttrs();
31+ OP_CHECK_NULL_WITH_CONTEXT(context, attrs);
32+ 
33+ const char* dtypeStr = attrs->GetAttrPointer<char>(kAttrIndexDtype);
34+ OP_CHECK_NULL_WITH_CONTEXT(context, dtypeStr);
35+ 
36+ ge::DataType outputDtype = ge::DT_FLOAT;
37+ std::string dtypeString(dtypeStr);
38+ if (dtypeString == "float32") {
39+ outputDtype = ge::DT_FLOAT;
40+ } else if (dtypeString == "int32") {
41+ outputDtype = ge::DT_INT32;
42+ } else if (dtypeString == "int8") {
43+ outputDtype = ge::DT_INT8;
44+ } else if (dtypeString == "float16") {
45+ outputDtype = ge::DT_FLOAT16;
46+ } else if (dtypeString == "uint8") {
47+ outputDtype = ge::DT_UINT8;
48+ } else {
49+ OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context->GetNodeName(), "dtype", dtypeStr,
50+ "dtype must be one of: float32, int32, int8, float16, uint8.");
51+ return ge::GRAPH_FAILED;
52+ }
53+ 
54+ context->SetOutputDataType(kOutputIndexY, outputDtype);
55+ OP_LOGI(context->GetNodeName(), "End to do InferDataTypeForConfusionMatrix");
56+ return ge::GRAPH_SUCCESS;
57+}
58+ 
59+IMPL_OP(ConfusionMatrix).InferDataType(InferDataTypeForConfusionMatrix);
60+} // namespace ops
@@ -0,0 +1,64 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_proto.h
13+ * \brief
14+ */
15+#ifndef OPS_OP_PROTO_INC_CONFUSION_MATRIX_H_
16+#define OPS_OP_PROTO_INC_CONFUSION_MATRIX_H_
17+ 
18+#include "graph/operator_reg.h"
19+#include "graph/types.h"
20+ 
21+namespace ge {
22+ 
23+/**
24+*@brief Computes the confusion matrix from predictions and labels .
25+ 
26+*@par Inputs:
27+*Three inputs, including:
28+*@li labels: A Tensor. Must be one of the following types: float16, float32,
29+*int32, int8, uint8. 1D. Has format ND.
30+*@li predictions: A Tensor. Must be one of the following types: float16,
31+*float32, int32, int8, uint8. 1D. Has format ND.
32+*@li weights: A optional Tensor. Must be one of the following types: float16, float32,
33+*int32, int8, uint8. 1D. Has format ND. \n
34+ 
35+*@par Attributes:
36+*@li num_classes: An integer for the shape of the output matrix.
37+*@li dtype: Data type of the confusion matrix. \n
38+ 
39+*@par Outputs:
40+*y: A Tensor. 1D. Has format ND. Has the same type and format as input "labels" . \n
41+ 
42+*@attention Constraints:
43+*@li "weights", "labels", and "predictions" are 1D tensors.
44+*@li The output is with shape (num_classes, num_classes),
45+*where, 1 <= num_classes <= 4096 . \n
46+ 
47+*@par Third-party framework compatibility
48+*Compatible with the TensorFlow operator ConfusionMatrix.
49+*/
50+#ifndef OPS_PROTO_DEF_CONFUSIONMATRIX
51+#define OPS_PROTO_DEF_CONFUSIONMATRIX
52+REG_OP(ConfusionMatrix)
53+ .INPUT(labels, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
54+ .INPUT(predictions, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
55+ .OPTIONAL_INPUT(weights, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
56+ .OUTPUT(y, TensorType({DT_FLOAT, DT_INT32, DT_FLOAT16, DT_INT8, DT_UINT8}))
57+ .REQUIRED_ATTR(num_classes, Int)
58+ .REQUIRED_ATTR(dtype, String)
59+ .OP_END_FACTORY_REG(ConfusionMatrix)
60+#endif // OPS_PROTO_DEF_CONFUSIONMATRIX
61+ 
62+} // namespace ge
63+ 
64+#endif // OPS_OP_PROTO_INC_CONFUSION_MATRIX_H_
@@ -0,0 +1,358 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software; you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_tiling.cpp
13+ * \brief confusion_matrix_tiling file
14+ */
15+ 
16+#include <iostream>
17+#include <cstring>
18+#include <string>
19+#include "register/op_impl_registry.h"
20+#include "platform/platform_info.h"
21+#include "op_host/tiling_base_util.h"
22+#include "log/log.h"
23+#include "confusion_matrix_tiling.h"
24+#include "util/math_util.h"
25+#include "util/const_util.h"
26+ 
27+namespace optiling {
28+ge::graphStatus ConfusionMatrixTiling::Init()
29+{
30+ OP_LOGD(context_->GetNodeName(), "ConfusionMatrixTiling init enter.");
31+ if (tilingData_ == nullptr) {
32+ tilingData_ = context_->GetTilingData<ConfusionMatrixTilingData>();
33+ OP_CHECK_IF(tilingData_ == nullptr, OP_LOGE(context_->GetNodeName(), "get tilingdata ptr failed"),
34+ return ge::GRAPH_FAILED);
35+ }
36+ OP_CHECK_IF((memset_s(tilingData_, sizeof(ConfusionMatrixTilingData), 0, sizeof(ConfusionMatrixTilingData)) != EOK),
37+ OP_LOGE(context_->GetNodeName(), "memset tilingdata failed"), return ge::GRAPH_FAILED);
38+ OP_LOGD(context_->GetNodeName(), "ConfusionMatrixTiling init exit.");
39+ return ge::GRAPH_SUCCESS;
40+}
41+ 
42+ge::graphStatus ConfusionMatrixTiling::ConfusionMatrixGetPlatformData(
43+ const AscendCConfusionMatrixCompileInfo* compileInfo)
44+{
45+ coreNum_ = compileInfo->totalCoreNum;
46+ ubSize_ = static_cast<int64_t>(compileInfo->totalUbSize - SIMD_SIMT_DCACHE_SIZE);
47+ isDetermine_ = context_->GetDeterministic() == 1 ? 1 : 0;
48+ OP_LOGI(context_->GetNodeName(),
49+ "ConfusionMatrixGetPlatformData ubSize is %ld, coreNum_ is %ld, isDetermine is %ld", ubSize_, coreNum_,
50+ isDetermine_);
51+ return ge::GRAPH_SUCCESS;
52+}
53+ 
54+ge::graphStatus ConfusionMatrixTiling::CheckShape()
55+{
56+ auto labelsShape = context_->GetInputShape(INPUT_IDX_LABELS);
57+ OP_CHECK_NULL_WITH_CONTEXT(context_, labelsShape);
58+ OP_CHECK_IF(labelsShape->GetStorageShape().GetDimNum() != DIM_1,
59+ OP_LOGE_FOR_INVALID_SHAPEDIM(context_->GetNodeName(), "labels",
60+ std::to_string(labelsShape->GetStorageShape().GetDimNum()).c_str(), "1D"),
61+ return ge::GRAPH_FAILED);
62+ 
63+ auto predictionsShape = context_->GetInputShape(INPUT_IDX_PREDICTIONS);
64+ OP_CHECK_NULL_WITH_CONTEXT(context_, predictionsShape);
65+ OP_CHECK_IF(
66+ predictionsShape->GetStorageShape().GetDimNum() != DIM_1,
67+ OP_LOGE_FOR_INVALID_SHAPEDIM(context_->GetNodeName(), "predictions",
68+ std::to_string(predictionsShape->GetStorageShape().GetDimNum()).c_str(), "1D"),
69+ return ge::GRAPH_FAILED);
70+ 
71+ auto labelsShapeSize = labelsShape->GetStorageShape().GetShapeSize();
72+ auto predictionsShapeSize = predictionsShape->GetStorageShape().GetShapeSize();
73+ OP_CHECK_IF(labelsShapeSize != predictionsShapeSize,
74+ OP_LOGE_FOR_INVALID_SHAPESIZE_WITH_REASON(
75+ context_->GetNodeName(), "labels and predictions",
76+ (std::to_string(labelsShapeSize) + " and " + std::to_string(predictionsShapeSize)).c_str(),
77+ "The shapes of labels and predictions must be the same"),
78+ return ge::GRAPH_FAILED);
79+ 
80+ auto weightsShape = context_->GetInputShape(INPUT_IDX_WEIGHTS);
81+ if (weightsShape != nullptr) {
82+ OP_CHECK_IF(
83+ weightsShape->GetStorageShape().GetDimNum() != DIM_1,
84+ OP_LOGE_FOR_INVALID_SHAPEDIM(context_->GetNodeName(), "weights",
85+ std::to_string(weightsShape->GetStorageShape().GetDimNum()).c_str(), "1D"),
86+ return ge::GRAPH_FAILED);
87+ auto weightsShapeSize = weightsShape->GetStorageShape().GetShapeSize();
88+ if (weightsShapeSize != 0) {
89+ OP_CHECK_IF(weightsShapeSize != labelsShapeSize,
90+ OP_LOGE_FOR_INVALID_SHAPESIZE_WITH_REASON(
91+ context_->GetNodeName(), "weights",
92+ (std::to_string(weightsShapeSize) + " and " + std::to_string(labelsShapeSize)).c_str(),
93+ "The shape of weights must be the same as labels when provided"),
94+ return ge::GRAPH_FAILED);
95+ }
96+ }
97+ 
98+ auto yShape = context_->GetOutputShape(OUTPUT_IDX_Y);
99+ OP_CHECK_NULL_WITH_CONTEXT(context_, yShape);
100+ OP_CHECK_IF(yShape->GetStorageShape().GetDimNum() != DIM_2,
101+ OP_LOGE_FOR_INVALID_SHAPEDIM(context_->GetNodeName(), "y",
102+ std::to_string(yShape->GetStorageShape().GetDimNum()).c_str(), "2D"),
103+ return ge::GRAPH_FAILED);
104+ 
105+ return ge::GRAPH_SUCCESS;
106+}
107+ 
108+ge::graphStatus ConfusionMatrixTiling::CheckDtype()
109+{
110+ auto attrs = context_->GetAttrs();
111+ OP_CHECK_NULL_WITH_CONTEXT(context_, attrs);
112+ 
113+ const char* dtypePtr = attrs->GetAttrPointer<char>(ATTR_IDX_DTYPE);
114+ OP_CHECK_NULL_WITH_CONTEXT(context_, dtypePtr);
115+ std::string dtypeStr(dtypePtr);
116+ 
117+ if (dtypeStr == "float32") {
118+ outputDtype_ = OUTPUT_DTYPE_FLOAT;
119+ sizeOfOutputDtype_ = static_cast<int64_t>(SIZE_DTYPE_FLOAT);
120+ } else if (dtypeStr == "int32") {
121+ outputDtype_ = OUTPUT_DTYPE_INT32;
122+ sizeOfOutputDtype_ = static_cast<int64_t>(SIZE_DTYPE_INT32);
123+ } else if (dtypeStr == "float16") {
124+ outputDtype_ = OUTPUT_DTYPE_FLOAT16;
125+ sizeOfOutputDtype_ = static_cast<int64_t>(SIZE_DTYPE_FLOAT16);
126+ } else if (dtypeStr == "int8") {
127+ outputDtype_ = OUTPUT_DTYPE_INT8;
128+ sizeOfOutputDtype_ = static_cast<int64_t>(SIZE_DTYPE_INT8);
129+ } else if (dtypeStr == "uint8") {
130+ outputDtype_ = OUTPUT_DTYPE_UINT8;
131+ sizeOfOutputDtype_ = static_cast<int64_t>(SIZE_DTYPE_UINT8);
132+ } else {
133+ OP_LOGE_FOR_INVALID_VALUE(context_->GetNodeName(), "dtype", dtypeStr.c_str(),
134+ "float32, int32, float16, int8 or uint8");
135+ return ge::GRAPH_FAILED;
136+ }
137+ 
138+ return ge::GRAPH_SUCCESS;
139+}
140+ 
141+ge::graphStatus ConfusionMatrixTiling::CheckInputParams()
142+{
143+ auto attrs = context_->GetAttrs();
144+ OP_CHECK_NULL_WITH_CONTEXT(context_, attrs);
145+ 
146+ const int64_t* numClassesPtr = attrs->GetAttrPointer<int64_t>(ATTR_IDX_NUM_CLASSES);
147+ OP_CHECK_NULL_WITH_CONTEXT(context_, numClassesPtr);
148+ numClasses_ = *numClassesPtr;
149+ OP_CHECK_IF((numClasses_ < NUM_CLASSES_MIN || numClasses_ > NUM_CLASSES_MAX),
150+ OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context_->GetNodeName(), "num_classes",
151+ std::to_string(numClasses_).c_str(),
152+ "num_classes must be in range [1, 4096]."),
153+ return ge::GRAPH_FAILED);
154+ 
155+ auto labelsShape = context_->GetInputShape(INPUT_IDX_LABELS);
156+ OP_CHECK_NULL_WITH_CONTEXT(context_, labelsShape);
157+ inputSize_ = labelsShape->GetStorageShape().GetShapeSize();
158+ 
159+ auto weightsShape = context_->GetInputShape(INPUT_IDX_WEIGHTS);
160+ if (weightsShape != nullptr) {
161+ int64_t weightsShapeSize = weightsShape->GetStorageShape().GetShapeSize();
162+ if (weightsShapeSize != 0) {
163+ isWeight_ = WEIGHT;
164+ }
165+ }
166+ OP_LOGI(context_->GetNodeName(), "inputSize is %ld, isWeight is %ld, numClasses is %ld", inputSize_, isWeight_,
167+ numClasses_);
168+ 
169+ outputSize_ = numClasses_ * numClasses_;
170+ OP_LOGI(context_->GetNodeName(), "outputSize is %ld", outputSize_);
171+ 
172+ return ge::GRAPH_SUCCESS;
173+}
174+ 
175+inline bool ConfusionMatrixTiling::IsMatchSimtBatchLoadMode()
176+{
177+ return (2 * inputSize_) > outputSize_ / GM_ATOMIC_ADD_FACTOR;
178+}
179+ 
180+ge::graphStatus ConfusionMatrixTiling::ComputeTilingStrategy()
181+{
182+ OP_LOGD(context_->GetNodeName(), "ComputeTilingStrategy enter.");
183+ ubNumCanUse_ = static_cast<int64_t>(ubSize_ / sizeOfOutputDtype_);
184+ 
185+ // For int8/uint8 output, asc_atomic_add does not support these types.
186+ // Force DETERMINE mode which uses direct += on disjoint output ranges
187+ // (no atomic operations needed).
188+ if (isDetermine_ || outputDtype_ == OUTPUT_DTYPE_INT8 || outputDtype_ == OUTPUT_DTYPE_UINT8) {
189+ schId_ = SCH_ID_SIMT_DETERMIN;
190+ return ComputeTilingSimtDetermine();
191+ }
192+ 
193+ if (outputSize_ < ubNumCanUse_) {
194+ schId_ = SCH_ID_SIMT_FULL_LOAD;
195+ } else if (IsMatchSimtBatchLoadMode()) {
196+ ubLoopNum_ = Ops::Base::CeilDiv(outputSize_, ubNumCanUse_);
197+ if (ubLoopNum_ <= MAX_UB_LOOP_FOR_BATCH) {
198+ schId_ = SCH_ID_SIMT_BATCH_LOAD;
199+ } else {
200+ schId_ = SCH_ID_SIMT_NOT_FULL_LOAD;
201+ }
202+ } else {
203+ schId_ = SCH_ID_SIMT_NOT_FULL_LOAD;
204+ }
205+ 
206+ return ComputeTilingSimtNotDetermine();
207+}
208+ 
209+ge::graphStatus ConfusionMatrixTiling::ComputeTilingSimtNotDetermine()
210+{
211+ OP_LOGD(context_->GetNodeName(), "ComputeTilingSimtNotDetermine enter.");
212+ ubLoopNum_ = Ops::Base::CeilDiv(outputSize_, ubNumCanUse_);
213+ if (inputSize_ > 0) {
214+ formerLength_ = Ops::Base::CeilDiv(inputSize_, coreNum_);
215+ OP_CHECK_IF(formerLength_ == 0, OP_LOGE(context_->GetNodeName(), "formerLength_ must not be 0."),
216+ return ge::GRAPH_FAILED);
217+ needXCoreNum_ = Ops::Base::CeilDiv(inputSize_, formerLength_);
218+ tailLength_ = inputSize_ - (needXCoreNum_ - 1) * formerLength_;
219+ } else {
220+ formerLength_ = 1;
221+ needXCoreNum_ = 1;
222+ tailLength_ = 0;
223+ }
224+ 
225+ clearYFactor_ = Ops::Base::CeilDiv(outputSize_, coreNum_);
226+ OP_CHECK_IF(clearYFactor_ == 0, OP_LOGE(context_->GetNodeName(), "clearYFactor_ must not be 0."),
227+ return ge::GRAPH_FAILED);
228+ clearYCoreNum_ = Ops::Base::CeilDiv(outputSize_, clearYFactor_);
229+ clearYTail_ = outputSize_ - (clearYCoreNum_ - 1) * clearYFactor_;
230+ needCoreNum_ = std::max(needXCoreNum_, clearYCoreNum_);
231+ OP_LOGD(context_->GetNodeName(), "ComputeTilingSimtNotDetermine end.");
232+ return ge::GRAPH_SUCCESS;
233+}
234+ 
235+ge::graphStatus ConfusionMatrixTiling::ComputeTilingSimtDetermine()
236+{
237+ OP_LOGD(context_->GetNodeName(), "ComputeTilingSimtDetermine enter.");
238+ binsFormerLength_ = Ops::Base::CeilDiv(outputSize_, coreNum_);
239+ OP_CHECK_IF(binsFormerLength_ == 0, OP_LOGE(context_->GetNodeName(), "binsFormerLength_ must not be 0."),
240+ return ge::GRAPH_FAILED);
241+ needBinsCoreNum_ = Ops::Base::CeilDiv(outputSize_, binsFormerLength_);
242+ binsTailLength_ = outputSize_ - (needBinsCoreNum_ - 1) * binsFormerLength_;
243+ needCoreNum_ = needBinsCoreNum_;
244+ OP_LOGD(context_->GetNodeName(), "ComputeTilingSimtDetermine end.");
245+ return ge::GRAPH_SUCCESS;
246+}
247+ 
248+void ConfusionMatrixTiling::PrintTilingData()
249+{
250+ OP_LOGI(context_->GetNodeName(),
251+ "ConfusionMatrix tilingData needCoreNum_ is %ld, numClasses is %ld,"
252+ "ubNumCanUse is %ld, ubLoopNum is %ld, needXCoreNum is %ld, formerLength is %ld, tailLength is %ld,"
253+ "clearYCoreNum is %ld, clearYFactor is %ld, clearYTail is %ld, binsFormerLength is %ld"
254+ "needBinsCoreNum is %ld, binsTailLength is %ld",
255+ needCoreNum_, tilingData_->numClasses, tilingData_->ubNumCanUse, tilingData_->ubLoopNum,
256+ tilingData_->needXCoreNum, tilingData_->formerLength, tilingData_->tailLength, tilingData_->clearYCoreNum,
257+ tilingData_->clearYFactor, tilingData_->clearYTail, tilingData_->binsFormerLength,
258+ tilingData_->needBinsCoreNum, tilingData_->binsTailLength);
259+ return;
260+}
261+ 
262+ge::graphStatus ConfusionMatrixTiling::SetTilingData()
263+{
264+ OP_LOGD(context_->GetNodeName(), "SetTilingData enter.");
265+ tilingData_->numClasses = numClasses_;
266+ tilingData_->inputSize = inputSize_;
267+ tilingData_->ubNumCanUse = ubNumCanUse_;
268+ tilingData_->ubLoopNum = ubLoopNum_;
269+ tilingData_->needXCoreNum = needXCoreNum_;
270+ tilingData_->formerLength = formerLength_;
271+ tilingData_->tailLength = tailLength_;
272+ tilingData_->clearYCoreNum = clearYCoreNum_;
273+ tilingData_->clearYFactor = clearYFactor_;
274+ tilingData_->clearYTail = clearYTail_;
275+ tilingData_->binsFormerLength = binsFormerLength_;
276+ tilingData_->needBinsCoreNum = needBinsCoreNum_;
277+ tilingData_->binsTailLength = binsTailLength_;
278+ // UB buffer 字节数由 host 一次算准,kernel 只透传(避免 host/内核两套算法)
279+ tilingData_->fullLoadBufSize = outputSize_ * sizeOfOutputDtype_;
280+ tilingData_->batchUbBufSize = ubNumCanUse_ * sizeOfOutputDtype_;
281+ OP_LOGI(context_->GetNodeName(), "schId is %ld, outputDtype is %ld, isWeight is %ld", schId_, outputDtype_,
282+ isWeight_);
283+ const uint64_t tilingKey = GET_TPL_TILING_KEY(schId_, outputDtype_, isWeight_);
284+ OP_LOGI(context_->GetNodeName(), "tilingKey is %ld", tilingKey);
285+ context_->SetTilingKey(tilingKey);
286+ context_->SetBlockDim(needCoreNum_);
287+ context_->SetLocalMemorySize(ubSize_);
288+ context_->SetScheduleMode(1); // SyncAll need set
289+ size_t* workspaces = context_->GetWorkspaceSizes(1);
290+ OP_CHECK_NULL_WITH_CONTEXT(context_, workspaces);
291+ workspaces[0] = WORK_SPACE_SIZE;
292+ PrintTilingData();
293+ return ge::GRAPH_SUCCESS;
294+}
295+ 
296+static ge::graphStatus Tiling4ConfusionMatrix(gert::TilingContext* context)
297+{
298+ auto compileInfo = reinterpret_cast<const AscendCConfusionMatrixCompileInfo*>(context->GetCompileInfo());
299+ OP_CHECK_NULL_WITH_CONTEXT(context, compileInfo);
300+ ConfusionMatrixTiling tilingObject(context);
301+ if (tilingObject.Init() != ge::GRAPH_SUCCESS) {
302+ OP_LOGE(context->GetNodeName(), "Init failed.");
303+ return ge::GRAPH_FAILED;
304+ }
305+ if (tilingObject.ConfusionMatrixGetPlatformData(compileInfo) != ge::GRAPH_SUCCESS) {
306+ OP_LOGE(context->GetNodeName(), "ConfusionMatrixGetPlatformData return failed.");
307+ return ge::GRAPH_FAILED;
308+ }
309+ if (tilingObject.CheckShape() != ge::GRAPH_SUCCESS) {
310+ OP_LOGE(context->GetNodeName(), "CheckShape return failed.");
311+ return ge::GRAPH_FAILED;
312+ }
313+ if (tilingObject.CheckDtype() != ge::GRAPH_SUCCESS) {
314+ OP_LOGE(context->GetNodeName(), "CheckDtype return failed.");
315+ return ge::GRAPH_FAILED;
316+ }
317+ if (tilingObject.CheckInputParams() != ge::GRAPH_SUCCESS) {
318+ OP_LOGE(context->GetNodeName(), "CheckInputParams return failed.");
319+ return ge::GRAPH_FAILED;
320+ }
321+ if (tilingObject.ComputeTilingStrategy() != ge::GRAPH_SUCCESS) {
322+ OP_LOGE(context->GetNodeName(), "ComputeTilingStrategy return failed.");
323+ return ge::GRAPH_FAILED;
324+ }
325+ if (tilingObject.SetTilingData() != ge::GRAPH_SUCCESS) {
326+ OP_LOGE(context->GetNodeName(), "SetTilingData return failed.");
327+ return ge::GRAPH_FAILED;
328+ }
329+ return ge::GRAPH_SUCCESS;
330+}
331+ 
332+static ge::graphStatus TilingPrepare4ConfusionMatrix(gert::TilingParseContext* context)
333+{
334+ OP_LOGI(context->GetNodeName(), "TilingPrepare4ConfusionMatrix running.");
335+ auto compileInfo = context->GetCompiledInfo<AscendCConfusionMatrixCompileInfo>();
336+ OP_CHECK_NULL_WITH_CONTEXT(context, compileInfo);
337+ auto platformInfo = context->GetPlatformInfo();
338+ OP_CHECK_NULL_WITH_CONTEXT(context, platformInfo);
339+ auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfo);
340+ compileInfo->totalCoreNum = static_cast<int32_t>(ascendcPlatform.GetCoreNumAiv());
341+ OP_CHECK_IF((compileInfo->totalCoreNum <= 0),
342+ OP_LOGE(context->GetNodeName(), "coreNum is invalid, must greater than zero"), return ge::GRAPH_FAILED);
343+ 
344+ uint64_t ubSizePlatForm = 0;
345+ ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSizePlatForm);
346+ compileInfo->totalUbSize = static_cast<int64_t>(ubSizePlatForm);
347+ OP_CHECK_IF((compileInfo->totalUbSize <= 0),
348+ OP_LOGE(context->GetNodeName(), "ubSize is invalid, must greater than zero"), return ge::GRAPH_FAILED);
349+ OP_LOGD(context->GetNodeName(), "totalUbSize is %lu.", compileInfo->totalUbSize);
350+ 
351+ return ge::GRAPH_SUCCESS;
352+}
353+ 
354+IMPL_OP_OPTILING(ConfusionMatrix)
355+ .Tiling(Tiling4ConfusionMatrix)
356+ .TilingParse<AscendCConfusionMatrixCompileInfo>(TilingPrepare4ConfusionMatrix);
357+ 
358+} // namespace optiling
@@ -0,0 +1,121 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_tiling.h
13+ * \brief confusion_matrix_tiling head file
14+ */
15+ 
16+#ifndef OPS_MATH_CONFUSION_MATRIX_TILING_H
17+#define OPS_MATH_CONFUSION_MATRIX_TILING_H
18+ 
19+#include "register/op_def_registry.h"
20+#include "op_host/tiling_base_class.h"
21+#include "../../op_kernel/arch35/confusion_matrix_tiling_key.h"
22+#include "../../op_kernel/arch35/confusion_matrix_tiling_data.h"
23+ 
24+namespace optiling {
25+ 
26+constexpr size_t WORK_SPACE_SIZE = static_cast<size_t>(16 * 1024 * 1024);
27+constexpr uint64_t DIM_0 = 0;
28+constexpr uint64_t DIM_1 = 1;
29+constexpr uint64_t DIM_2 = 2;
30+ 
31+constexpr int64_t INPUT_IDX_LABELS = 0;
32+constexpr int64_t INPUT_IDX_PREDICTIONS = 1;
33+constexpr int64_t INPUT_IDX_WEIGHTS = 2;
34+constexpr int64_t OUTPUT_IDX_Y = 0;
35+ 
36+constexpr int64_t ATTR_IDX_NUM_CLASSES = 0;
37+constexpr int64_t ATTR_IDX_DTYPE = 1;
38+ 
39+constexpr uint64_t SIZE_DTYPE_FLOAT = 4;
40+constexpr uint64_t SIZE_DTYPE_INT32 = 4;
41+constexpr uint64_t SIZE_DTYPE_FLOAT16 = 2;
42+constexpr uint64_t SIZE_DTYPE_INT8 = 1;
43+constexpr uint64_t SIZE_DTYPE_UINT8 = 1;
44+ 
45+constexpr uint64_t EMPTY_WEIGHT = 0;
46+constexpr uint64_t WEIGHT = 1;
47+ 
48+constexpr uint64_t OUTPUT_DTYPE_FLOAT = 0;
49+constexpr uint64_t OUTPUT_DTYPE_INT32 = 1;
50+constexpr uint64_t OUTPUT_DTYPE_FLOAT16 = 2;
51+constexpr uint64_t OUTPUT_DTYPE_INT8 = 3;
52+constexpr uint64_t OUTPUT_DTYPE_UINT8 = 4;
53+ 
54+constexpr uint64_t SCH_ID_SIMT_FULL_LOAD = 0; // full load to UB
55+constexpr uint64_t SCH_ID_SIMT_BATCH_LOAD = 1; // batch load to UB
56+constexpr uint64_t SCH_ID_SIMT_NOT_FULL_LOAD = 2; // not load to UB
57+constexpr uint64_t SCH_ID_SIMT_DETERMIN = 3;
58+ 
59+constexpr int64_t GM_ATOMIC_ADD_FACTOR = 100;
60+constexpr uint64_t SIMD_SIMT_DCACHE_SIZE = static_cast<uint64_t>(32 * 1024);
61+constexpr int64_t MAX_UB_LOOP_FOR_BATCH = 8;
62+ 
63+constexpr int64_t NUM_CLASSES_MIN = 1;
64+constexpr int64_t NUM_CLASSES_MAX = 4096;
65+ 
66+struct AscendCConfusionMatrixCompileInfo {
67+ int32_t totalCoreNum = 0;
68+ uint64_t totalUbSize = 0;
69+};
70+ 
71+class ConfusionMatrixTiling {
72+public:
73+ explicit ConfusionMatrixTiling(gert::TilingContext* context) : context_(context) {};
74+ ge::graphStatus Init();
75+ ge::graphStatus ConfusionMatrixGetPlatformData(const AscendCConfusionMatrixCompileInfo* compileInfo);
76+ ge::graphStatus CheckShape();
77+ ge::graphStatus CheckDtype();
78+ ge::graphStatus CheckInputParams();
79+ 
80+ inline bool IsMatchSimtBatchLoadMode();
81+ ge::graphStatus ComputeTilingStrategy();
82+ ge::graphStatus ComputeTilingSimtDetermine();
83+ ge::graphStatus ComputeTilingSimtNotDetermine();
84+ ge::graphStatus SetTilingData();
85+ void PrintTilingData();
86+ 
87+private:
88+ gert::TilingContext* context_ = nullptr;
89+ ConfusionMatrixTilingData* tilingData_ = nullptr;
90+ // tiling key template param
91+ uint64_t schId_ = 0;
92+ uint64_t isWeight_ = EMPTY_WEIGHT;
93+ uint64_t outputDtype_ = 0;
94+ // configed info
95+ int64_t coreNum_ = 0;
96+ int64_t ubSize_ = 0;
97+ int64_t isDetermine_ = 0;
98+ int64_t sizeOfOutputDtype_ = 0;
99+ 
100+ // tiling info
101+ int64_t inputSize_ = 0;
102+ int64_t numClasses_ = 0;
103+ int64_t outputSize_ = 0;
104+ int64_t needCoreNum_ = 0;
105+ 
106+ int64_t ubNumCanUse_ = 0;
107+ int64_t ubLoopNum_ = 0;
108+ int64_t needXCoreNum_ = 0;
109+ int64_t formerLength_ = 0;
110+ int64_t tailLength_ = 0;
111+ int64_t clearYCoreNum_ = 0;
112+ int64_t clearYFactor_ = 0;
113+ int64_t clearYTail_ = 0;
114+ int64_t binsFormerLength_ = 0;
115+ int64_t needBinsCoreNum_ = 0;
116+ int64_t binsTailLength_ = 0;
117+};
118+ 
119+} // namespace optiling
120+ 
121+#endif // OPS_MATH_CONFUSION_MATRIX_TILING_H
@@ -0,0 +1,380 @@
1+{
2+ "op_type": "ConfusionMatrix",
3+ "op_list": [
4+ {
5+ "bin_filename": "ConfusionMatrix_float16_float16_float16_float16",
6+ "inputs": [
7+ { "name": "labels", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
8+ { "name": "predictions", "index": 1, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
9+ { "name": "weights", "index": 2, "dtype": "float16", "format": "ND", "paramType": "optional", "shape": [-2] }
10+ ],
11+ "outputs": [
12+ { "name": "y", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] }
13+ ],
14+ "attrs": [
15+ { "name": "num_classes", "dtype": "int", "value": null },
16+ { "name": "dtype", "dtype": "string", "value": "float16" }
17+ ]
18+ },
19+ {
20+ "bin_filename": "ConfusionMatrix_float16_float16_float32_float32",
21+ "inputs": [
22+ { "name": "labels", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
23+ { "name": "predictions", "index": 1, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
24+ { "name": "weights", "index": 2, "dtype": "float32", "format": "ND", "paramType": "optional", "shape": [-2] }
25+ ],
26+ "outputs": [
27+ { "name": "y", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] }
28+ ],
29+ "attrs": [
30+ { "name": "num_classes", "dtype": "int", "value": null },
31+ { "name": "dtype", "dtype": "string", "value": "float32" }
32+ ]
33+ },
34+ {
35+ "bin_filename": "ConfusionMatrix_float16_float16_int32_int32",
36+ "inputs": [
37+ { "name": "labels", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
38+ { "name": "predictions", "index": 1, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
39+ { "name": "weights", "index": 2, "dtype": "int32", "format": "ND", "paramType": "optional", "shape": [-2] }
40+ ],
41+ "outputs": [
42+ { "name": "y", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] }
43+ ],
44+ "attrs": [
45+ { "name": "num_classes", "dtype": "int", "value": null },
46+ { "name": "dtype", "dtype": "string", "value": "int32" }
47+ ]
48+ },
49+ {
50+ "bin_filename": "ConfusionMatrix_float16_float16_int8_int8",
51+ "inputs": [
52+ { "name": "labels", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
53+ { "name": "predictions", "index": 1, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
54+ { "name": "weights", "index": 2, "dtype": "int8", "format": "ND", "paramType": "optional", "shape": [-2] }
55+ ],
56+ "outputs": [
57+ { "name": "y", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] }
58+ ],
59+ "attrs": [
60+ { "name": "num_classes", "dtype": "int", "value": null },
61+ { "name": "dtype", "dtype": "string", "value": "int8" }
62+ ]
63+ },
64+ {
65+ "bin_filename": "ConfusionMatrix_float16_float16_uint8_uint8",
66+ "inputs": [
67+ { "name": "labels", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
68+ { "name": "predictions", "index": 1, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] },
69+ { "name": "weights", "index": 2, "dtype": "uint8", "format": "ND", "paramType": "optional", "shape": [-2] }
70+ ],
71+ "outputs": [
72+ { "name": "y", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] }
73+ ],
74+ "attrs": [
75+ { "name": "num_classes", "dtype": "int", "value": null },
76+ { "name": "dtype", "dtype": "string", "value": "uint8" }
77+ ]
78+ },
79+ {
80+ "bin_filename": "ConfusionMatrix_float32_float32_float16_float16",
81+ "inputs": [
82+ { "name": "labels", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
83+ { "name": "predictions", "index": 1, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
84+ { "name": "weights", "index": 2, "dtype": "float16", "format": "ND", "paramType": "optional", "shape": [-2] }
85+ ],
86+ "outputs": [
87+ { "name": "y", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] }
88+ ],
89+ "attrs": [
90+ { "name": "num_classes", "dtype": "int", "value": null },
91+ { "name": "dtype", "dtype": "string", "value": "float16" }
92+ ]
93+ },
94+ {
95+ "bin_filename": "ConfusionMatrix_float32_float32_float32_float32",
96+ "inputs": [
97+ { "name": "labels", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
98+ { "name": "predictions", "index": 1, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
99+ { "name": "weights", "index": 2, "dtype": "float32", "format": "ND", "paramType": "optional", "shape": [-2] }
100+ ],
101+ "outputs": [
102+ { "name": "y", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] }
103+ ],
104+ "attrs": [
105+ { "name": "num_classes", "dtype": "int", "value": null },
106+ { "name": "dtype", "dtype": "string", "value": "float32" }
107+ ]
108+ },
109+ {
110+ "bin_filename": "ConfusionMatrix_float32_float32_int32_int32",
111+ "inputs": [
112+ { "name": "labels", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
113+ { "name": "predictions", "index": 1, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
114+ { "name": "weights", "index": 2, "dtype": "int32", "format": "ND", "paramType": "optional", "shape": [-2] }
115+ ],
116+ "outputs": [
117+ { "name": "y", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] }
118+ ],
119+ "attrs": [
120+ { "name": "num_classes", "dtype": "int", "value": null },
121+ { "name": "dtype", "dtype": "string", "value": "int32" }
122+ ]
123+ },
124+ {
125+ "bin_filename": "ConfusionMatrix_float32_float32_int8_int8",
126+ "inputs": [
127+ { "name": "labels", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
128+ { "name": "predictions", "index": 1, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
129+ { "name": "weights", "index": 2, "dtype": "int8", "format": "ND", "paramType": "optional", "shape": [-2] }
130+ ],
131+ "outputs": [
132+ { "name": "y", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] }
133+ ],
134+ "attrs": [
135+ { "name": "num_classes", "dtype": "int", "value": null },
136+ { "name": "dtype", "dtype": "string", "value": "int8" }
137+ ]
138+ },
139+ {
140+ "bin_filename": "ConfusionMatrix_float32_float32_uint8_uint8",
141+ "inputs": [
142+ { "name": "labels", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
143+ { "name": "predictions", "index": 1, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] },
144+ { "name": "weights", "index": 2, "dtype": "uint8", "format": "ND", "paramType": "optional", "shape": [-2] }
145+ ],
146+ "outputs": [
147+ { "name": "y", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] }
148+ ],
149+ "attrs": [
150+ { "name": "num_classes", "dtype": "int", "value": null },
151+ { "name": "dtype", "dtype": "string", "value": "uint8" }
152+ ]
153+ },
154+ {
155+ "bin_filename": "ConfusionMatrix_int32_int32_float16_float16",
156+ "inputs": [
157+ { "name": "labels", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
158+ { "name": "predictions", "index": 1, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
159+ { "name": "weights", "index": 2, "dtype": "float16", "format": "ND", "paramType": "optional", "shape": [-2] }
160+ ],
161+ "outputs": [
162+ { "name": "y", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] }
163+ ],
164+ "attrs": [
165+ { "name": "num_classes", "dtype": "int", "value": null },
166+ { "name": "dtype", "dtype": "string", "value": "float16" }
167+ ]
168+ },
169+ {
170+ "bin_filename": "ConfusionMatrix_int32_int32_float32_float32",
171+ "inputs": [
172+ { "name": "labels", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
173+ { "name": "predictions", "index": 1, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
174+ { "name": "weights", "index": 2, "dtype": "float32", "format": "ND", "paramType": "optional", "shape": [-2] }
175+ ],
176+ "outputs": [
177+ { "name": "y", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] }
178+ ],
179+ "attrs": [
180+ { "name": "num_classes", "dtype": "int", "value": null },
181+ { "name": "dtype", "dtype": "string", "value": "float32" }
182+ ]
183+ },
184+ {
185+ "bin_filename": "ConfusionMatrix_int32_int32_int32_int32",
186+ "inputs": [
187+ { "name": "labels", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
188+ { "name": "predictions", "index": 1, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
189+ { "name": "weights", "index": 2, "dtype": "int32", "format": "ND", "paramType": "optional", "shape": [-2] }
190+ ],
191+ "outputs": [
192+ { "name": "y", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] }
193+ ],
194+ "attrs": [
195+ { "name": "num_classes", "dtype": "int", "value": null },
196+ { "name": "dtype", "dtype": "string", "value": "int32" }
197+ ]
198+ },
199+ {
200+ "bin_filename": "ConfusionMatrix_int32_int32_int8_int8",
201+ "inputs": [
202+ { "name": "labels", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
203+ { "name": "predictions", "index": 1, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
204+ { "name": "weights", "index": 2, "dtype": "int8", "format": "ND", "paramType": "optional", "shape": [-2] }
205+ ],
206+ "outputs": [
207+ { "name": "y", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] }
208+ ],
209+ "attrs": [
210+ { "name": "num_classes", "dtype": "int", "value": null },
211+ { "name": "dtype", "dtype": "string", "value": "int8" }
212+ ]
213+ },
214+ {
215+ "bin_filename": "ConfusionMatrix_int32_int32_uint8_uint8",
216+ "inputs": [
217+ { "name": "labels", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
218+ { "name": "predictions", "index": 1, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] },
219+ { "name": "weights", "index": 2, "dtype": "uint8", "format": "ND", "paramType": "optional", "shape": [-2] }
220+ ],
221+ "outputs": [
222+ { "name": "y", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] }
223+ ],
224+ "attrs": [
225+ { "name": "num_classes", "dtype": "int", "value": null },
226+ { "name": "dtype", "dtype": "string", "value": "uint8" }
227+ ]
228+ },
229+ {
230+ "bin_filename": "ConfusionMatrix_int8_int8_float16_float16",
231+ "inputs": [
232+ { "name": "labels", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
233+ { "name": "predictions", "index": 1, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
234+ { "name": "weights", "index": 2, "dtype": "float16", "format": "ND", "paramType": "optional", "shape": [-2] }
235+ ],
236+ "outputs": [
237+ { "name": "y", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] }
238+ ],
239+ "attrs": [
240+ { "name": "num_classes", "dtype": "int", "value": null },
241+ { "name": "dtype", "dtype": "string", "value": "float16" }
242+ ]
243+ },
244+ {
245+ "bin_filename": "ConfusionMatrix_int8_int8_float32_float32",
246+ "inputs": [
247+ { "name": "labels", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
248+ { "name": "predictions", "index": 1, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
249+ { "name": "weights", "index": 2, "dtype": "float32", "format": "ND", "paramType": "optional", "shape": [-2] }
250+ ],
251+ "outputs": [
252+ { "name": "y", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] }
253+ ],
254+ "attrs": [
255+ { "name": "num_classes", "dtype": "int", "value": null },
256+ { "name": "dtype", "dtype": "string", "value": "float32" }
257+ ]
258+ },
259+ {
260+ "bin_filename": "ConfusionMatrix_int8_int8_int32_int32",
261+ "inputs": [
262+ { "name": "labels", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
263+ { "name": "predictions", "index": 1, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
264+ { "name": "weights", "index": 2, "dtype": "int32", "format": "ND", "paramType": "optional", "shape": [-2] }
265+ ],
266+ "outputs": [
267+ { "name": "y", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] }
268+ ],
269+ "attrs": [
270+ { "name": "num_classes", "dtype": "int", "value": null },
271+ { "name": "dtype", "dtype": "string", "value": "int32" }
272+ ]
273+ },
274+ {
275+ "bin_filename": "ConfusionMatrix_int8_int8_int8_int8",
276+ "inputs": [
277+ { "name": "labels", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
278+ { "name": "predictions", "index": 1, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
279+ { "name": "weights", "index": 2, "dtype": "int8", "format": "ND", "paramType": "optional", "shape": [-2] }
280+ ],
281+ "outputs": [
282+ { "name": "y", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] }
283+ ],
284+ "attrs": [
285+ { "name": "num_classes", "dtype": "int", "value": null },
286+ { "name": "dtype", "dtype": "string", "value": "int8" }
287+ ]
288+ },
289+ {
290+ "bin_filename": "ConfusionMatrix_int8_int8_uint8_uint8",
291+ "inputs": [
292+ { "name": "labels", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
293+ { "name": "predictions", "index": 1, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] },
294+ { "name": "weights", "index": 2, "dtype": "uint8", "format": "ND", "paramType": "optional", "shape": [-2] }
295+ ],
296+ "outputs": [
297+ { "name": "y", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] }
298+ ],
299+ "attrs": [
300+ { "name": "num_classes", "dtype": "int", "value": null },
301+ { "name": "dtype", "dtype": "string", "value": "uint8" }
302+ ]
303+ },
304+ {
305+ "bin_filename": "ConfusionMatrix_uint8_uint8_float16_float16",
306+ "inputs": [
307+ { "name": "labels", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
308+ { "name": "predictions", "index": 1, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
309+ { "name": "weights", "index": 2, "dtype": "float16", "format": "ND", "paramType": "optional", "shape": [-2] }
310+ ],
311+ "outputs": [
312+ { "name": "y", "index": 0, "dtype": "float16", "format": "ND", "paramType": "required", "shape": [-2] }
313+ ],
314+ "attrs": [
315+ { "name": "num_classes", "dtype": "int", "value": null },
316+ { "name": "dtype", "dtype": "string", "value": "float16" }
317+ ]
318+ },
319+ {
320+ "bin_filename": "ConfusionMatrix_uint8_uint8_float32_float32",
321+ "inputs": [
322+ { "name": "labels", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
323+ { "name": "predictions", "index": 1, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
324+ { "name": "weights", "index": 2, "dtype": "float32", "format": "ND", "paramType": "optional", "shape": [-2] }
325+ ],
326+ "outputs": [
327+ { "name": "y", "index": 0, "dtype": "float32", "format": "ND", "paramType": "required", "shape": [-2] }
328+ ],
329+ "attrs": [
330+ { "name": "num_classes", "dtype": "int", "value": null },
331+ { "name": "dtype", "dtype": "string", "value": "float32" }
332+ ]
333+ },
334+ {
335+ "bin_filename": "ConfusionMatrix_uint8_uint8_int32_int32",
336+ "inputs": [
337+ { "name": "labels", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
338+ { "name": "predictions", "index": 1, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
339+ { "name": "weights", "index": 2, "dtype": "int32", "format": "ND", "paramType": "optional", "shape": [-2] }
340+ ],
341+ "outputs": [
342+ { "name": "y", "index": 0, "dtype": "int32", "format": "ND", "paramType": "required", "shape": [-2] }
343+ ],
344+ "attrs": [
345+ { "name": "num_classes", "dtype": "int", "value": null },
346+ { "name": "dtype", "dtype": "string", "value": "int32" }
347+ ]
348+ },
349+ {
350+ "bin_filename": "ConfusionMatrix_uint8_uint8_int8_int8",
351+ "inputs": [
352+ { "name": "labels", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
353+ { "name": "predictions", "index": 1, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
354+ { "name": "weights", "index": 2, "dtype": "int8", "format": "ND", "paramType": "optional", "shape": [-2] }
355+ ],
356+ "outputs": [
357+ { "name": "y", "index": 0, "dtype": "int8", "format": "ND", "paramType": "required", "shape": [-2] }
358+ ],
359+ "attrs": [
360+ { "name": "num_classes", "dtype": "int", "value": null },
361+ { "name": "dtype", "dtype": "string", "value": "int8" }
362+ ]
363+ },
364+ {
365+ "bin_filename": "ConfusionMatrix_uint8_uint8_uint8_uint8",
366+ "inputs": [
367+ { "name": "labels", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
368+ { "name": "predictions", "index": 1, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] },
369+ { "name": "weights", "index": 2, "dtype": "uint8", "format": "ND", "paramType": "optional", "shape": [-2] }
370+ ],
371+ "outputs": [
372+ { "name": "y", "index": 0, "dtype": "uint8", "format": "ND", "paramType": "required", "shape": [-2] }
373+ ],
374+ "attrs": [
375+ { "name": "num_classes", "dtype": "int", "value": null },
376+ { "name": "dtype", "dtype": "string", "value": "uint8" }
377+ ]
378+ }
379+ ]
380+}
@@ -0,0 +1,2 @@
1+[ConfusionMatrix]
2+default=0
@@ -0,0 +1,74 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_def.cpp
13+ * \brief confusion_matrix def
14+ */
15+ 
16+#include "register/op_def_registry.h"
17+ 
18+namespace ops {
19+ 
20+static const std::vector<ge::DataType> labelsPredictionsDtypes = {
21+ ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_FLOAT,
22+ ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32,
23+ ge::DT_INT32, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_UINT8,
24+ ge::DT_UINT8, ge::DT_UINT8, ge::DT_UINT8, ge::DT_UINT8};
25+ 
26+static const std::vector<ge::DataType> weightsOutputDtypes = {
27+ ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32, ge::DT_INT8, ge::DT_UINT8, ge::DT_FLOAT16, ge::DT_FLOAT,
28+ ge::DT_INT32, ge::DT_INT8, ge::DT_UINT8, ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32, ge::DT_INT8,
29+ ge::DT_UINT8, ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32, ge::DT_INT8, ge::DT_UINT8, ge::DT_FLOAT16,
30+ ge::DT_FLOAT, ge::DT_INT32, ge::DT_INT8, ge::DT_UINT8};
31+ 
32+static const std::vector<ge::Format> kFormats = {
33+ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND,
34+ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND,
35+ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND,
36+ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND};
37+ 
38+class ConfusionMatrix : public OpDef {
39+public:
40+ explicit ConfusionMatrix(const char* name) : OpDef(name)
41+ {
42+ this->Input("labels")
43+ .ParamType(REQUIRED)
44+ .DataType(labelsPredictionsDtypes)
45+ .Format(kFormats)
46+ .UnknownShapeFormat(kFormats);
47+ this->Input("predictions")
48+ .ParamType(REQUIRED)
49+ .DataType(labelsPredictionsDtypes)
50+ .Format(kFormats)
51+ .UnknownShapeFormat(kFormats);
52+ this->Input("weights")
53+ .ParamType(OPTIONAL)
54+ .DataType(weightsOutputDtypes)
55+ .Format(kFormats)
56+ .UnknownShapeFormat(kFormats);
57+ this->Output("y")
58+ .ParamType(REQUIRED)
59+ .DataType(weightsOutputDtypes)
60+ .Format(kFormats)
61+ .UnknownShapeFormat(kFormats);
62+ this->Attr("num_classes").AttrType(REQUIRED).Int();
63+ this->Attr("dtype").AttrType(REQUIRED).String("float32");
64+ OpAICoreConfig aicoreConfig;
65+ aicoreConfig.DynamicCompileStaticFlag(true)
66+ .DynamicFormatFlag(false)
67+ .DynamicRankSupportFlag(true)
68+ .DynamicShapeSupportFlag(true)
69+ .ExtendCfgInfo("opFile.value", "confusion_matrix");
70+ this->AICore().AddConfig("ascend950", aicoreConfig);
71+ }
72+};
73+OP_ADD(ConfusionMatrix);
74+} // namespace ops
@@ -0,0 +1,77 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_infershape.cpp
13+ * \brief Infer shape implementation for ConfusionMatrix operator
14+ */
15+ 
16+#include "log/log.h"
17+#include "register/op_impl_registry.h"
18+#include "util/shape_util.h"
19+ 
20+#include <string>
21+ 
22+using namespace ge;
23+namespace ops {
24+static constexpr size_t kAttrIndexNumClasses = 0U;
25+static constexpr size_t kInputIndexLabels = 0U;
26+static constexpr size_t kInputIndexPredictions = 1U;
27+static constexpr size_t kOutputIndexY = 0U;
28+static constexpr int64_t kNumClassesMin = 1;
29+static constexpr int64_t kNumClassesMax = 4096;
30+static constexpr size_t kOutputDimNum = 2U;
31+static constexpr size_t kOutputDim0 = 0U;
32+static constexpr size_t kOutputDim1 = 1U;
33+ 
34+ge::graphStatus InferShapeForConfusionMatrix(gert::InferShapeContext* context)
35+{
36+ OP_LOGI(context->GetNodeName(), "Begin to do InferShapeForConfusionMatrix");
37+ 
38+ auto attrs = context->GetAttrs();
39+ OP_CHECK_NULL_WITH_CONTEXT(context, attrs);
40+ 
41+ const int64_t* numClassesPtr = attrs->GetAttrPointer<int64_t>(kAttrIndexNumClasses);
42+ OP_CHECK_NULL_WITH_CONTEXT(context, numClassesPtr);
43+ 
44+ int64_t numClasses = *numClassesPtr;
45+ OP_CHECK_IF(
46+ (numClasses < kNumClassesMin || numClasses > kNumClassesMax),
47+ OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context->GetNodeName(), "num_classes", std::to_string(numClasses).c_str(),
48+ "num_classes must be in range [1, 4096]."),
49+ return ge::GRAPH_FAILED);
50+ 
51+ gert::Shape* yShape = context->GetOutputShape(kOutputIndexY);
52+ OP_CHECK_NULL_WITH_CONTEXT(context, yShape);
53+ 
54+ const gert::Shape* labelsShape = context->GetInputShape(kInputIndexLabels);
55+ OP_CHECK_NULL_WITH_CONTEXT(context, labelsShape);
56+ const gert::Shape* predictionsShape = context->GetInputShape(kInputIndexPredictions);
57+ OP_CHECK_NULL_WITH_CONTEXT(context, predictionsShape);
58+ 
59+ // labels/predictions 为 unknown rank(-2) 时无法校验 1D 约束,输出透传 unknown rank;
60+ // unknown shape(-1,rank 已知)时输出仍由 num_classes 决定,走下方固定 [num_classes, num_classes] 分支
61+ if (Ops::Base::IsUnknownRank(*labelsShape) || Ops::Base::IsUnknownRank(*predictionsShape)) {
62+ Ops::Base::SetUnknownRank(*yShape);
63+ OP_LOGI(context->GetNodeName(), "labels/predictions is unknown rank, set output to unknown rank");
64+ return ge::GRAPH_SUCCESS;
65+ }
66+ 
67+ yShape->SetDimNum(kOutputDimNum);
68+ yShape->SetDim(kOutputDim0, numClasses);
69+ yShape->SetDim(kOutputDim1, numClasses);
70+ 
71+ OP_LOGI(context->GetNodeName(), "End to do InferShapeForConfusionMatrix");
72+ return ge::GRAPH_SUCCESS;
73+}
74+ 
75+IMPL_OP_INFERSHAPE(ConfusionMatrix).InferShape(InferShapeForConfusionMatrix);
76+ 
77+} // namespace ops
@@ -0,0 +1,126 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software; you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_determine.h
13+ * \brief confusion_matrix determine realization
14+ */
15+ 
16+#ifndef CONFUSION_MATRIX_DETERMINE_H
17+#define CONFUSION_MATRIX_DETERMINE_H
18+ 
19+#include "confusion_matrix_tiling_data.h"
20+ 
21+namespace ConfusionMatrixSimt {
22+using namespace AscendC;
23+ 
24+template <typename LABEL_TYPE, typename Y_TYPE>
25+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void DetermineSimtCompute(
26+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __gm__ Y_TYPE* yGmAddr,
27+ const int64_t binsHeadIndex, const int64_t binsDataLength, const int64_t inputSize, const int64_t numClasses)
28+{
29+ for (int64_t index = static_cast<int64_t>(Simt::GetThreadIdx()); index < binsDataLength;
30+ index += static_cast<int64_t>(Simt::GetThreadNum<0>())) {
31+ yGmAddr[binsHeadIndex + index] = static_cast<Y_TYPE>(0);
32+ for (int64_t inputIndex = 0; inputIndex < inputSize; inputIndex++) {
33+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputIndex]);
34+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputIndex]);
35+ int64_t offset = label * numClasses + prediction;
36+ if (offset == binsHeadIndex + index) {
37+ yGmAddr[binsHeadIndex + index] += static_cast<Y_TYPE>(WEIGHT_ONE);
38+ }
39+ }
40+ }
41+}
42+ 
43+template <typename LABEL_TYPE, typename Y_TYPE>
44+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void DetermineSimtComputeWithWeight(
45+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __gm__ Y_TYPE* weightsGmAddr,
46+ __gm__ Y_TYPE* yGmAddr, const int64_t binsHeadIndex, const int64_t binsDataLength, const int64_t inputSize,
47+ const int64_t numClasses)
48+{
49+ for (int64_t index = static_cast<int64_t>(Simt::GetThreadIdx()); index < binsDataLength;
50+ index += static_cast<int64_t>(Simt::GetThreadNum<0>())) {
51+ yGmAddr[binsHeadIndex + index] = static_cast<Y_TYPE>(0);
52+ for (int64_t inputIndex = 0; inputIndex < inputSize; inputIndex++) {
53+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputIndex]);
54+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputIndex]);
55+ int64_t offset = label * numClasses + prediction;
56+ if (offset == binsHeadIndex + index) {
57+ yGmAddr[binsHeadIndex + index] += weightsGmAddr[inputIndex];
58+ }
59+ }
60+ }
61+}
62+ 
63+template <typename LABEL_TYPE, typename Y_TYPE>
64+class ConfusionMatrixDetermine : public ConfusionMatrixSimtBase<LABEL_TYPE, Y_TYPE> {
65+public:
66+ __aicore__ inline ConfusionMatrixDetermine(){};
67+ __aicore__ inline void Init(GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
68+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe,
69+ bool isWeightEmpty);
70+ __aicore__ inline void Process();
71+ 
72+private:
73+ __aicore__ inline void Compute();
74+ 
75+private:
76+ int64_t binsFormerLength_ = 0;
77+ int64_t needBinsCoreNum_ = 0;
78+ int64_t binsTailLength_ = 0;
79+};
80+ 
81+template <typename LABEL_TYPE, typename Y_TYPE>
82+__aicore__ inline void ConfusionMatrixDetermine<LABEL_TYPE, Y_TYPE>::Init(
83+ GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
84+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe, bool isWeightEmpty)
85+{
86+ this->BaseInit(labels, predictions, weights, y, tilingData, tPipe, isWeightEmpty);
87+ binsFormerLength_ = tilingData->binsFormerLength;
88+ needBinsCoreNum_ = tilingData->needBinsCoreNum;
89+ binsTailLength_ = tilingData->binsTailLength;
90+}
91+ 
92+template <typename LABEL_TYPE, typename Y_TYPE>
93+__aicore__ inline void ConfusionMatrixDetermine<LABEL_TYPE, Y_TYPE>::Process()
94+{
95+ if (this->blockIdx_ >= GetBlockNum()) {
96+ return;
97+ }
98+ 
99+ if (this->blockIdx_ < needBinsCoreNum_) {
100+ Compute();
101+ }
102+}
103+ 
104+template <typename LABEL_TYPE, typename Y_TYPE>
105+__aicore__ inline void ConfusionMatrixDetermine<LABEL_TYPE, Y_TYPE>::Compute()
106+{
107+ __gm__ LABEL_TYPE* labelsGmAddr = (__gm__ LABEL_TYPE*)this->labelsGm_.GetPhyAddr();
108+ __gm__ LABEL_TYPE* predictionsGmAddr = (__gm__ LABEL_TYPE*)this->predictionsGm_.GetPhyAddr();
109+ __gm__ Y_TYPE* yGmAddr = (__gm__ Y_TYPE*)this->yGm_.GetPhyAddr();
110+ int64_t binsHeadIndex = this->blockIdx_ * binsFormerLength_;
111+ int64_t binsDataLength = (this->blockIdx_ == needBinsCoreNum_ - 1) ? binsTailLength_ : binsFormerLength_;
112+ 
113+ if (this->isWeightEmpty_) {
114+ Simt::VF_CALL<DetermineSimtCompute<LABEL_TYPE, Y_TYPE>>(Simt::Dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr,
115+ yGmAddr, binsHeadIndex, binsDataLength,
116+ this->inputSize_, this->numClasses_);
117+ } else {
118+ __gm__ Y_TYPE* weightsGmAddr = (__gm__ Y_TYPE*)this->weightsGm_.GetPhyAddr();
119+ Simt::VF_CALL<DetermineSimtComputeWithWeight<LABEL_TYPE, Y_TYPE>>(
120+ Simt::Dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr, weightsGmAddr, yGmAddr, binsHeadIndex,
121+ binsDataLength, this->inputSize_, this->numClasses_);
122+ }
123+}
124+ 
125+} // namespace ConfusionMatrixSimt
126+#endif // CONFUSION_MATRIX_DETERMINE_H
@@ -0,0 +1,103 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software; you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_simt_base.h
13+ * \brief The base class of confusion_matrix. The main function of this file is:
14+ */
15+ 
16+#ifndef CONFUSION_MATRIX_SIMT_BASE_H
17+#define CONFUSION_MATRIX_SIMT_BASE_H
18+ 
19+#include "confusion_matrix_tiling_data.h"
20+ 
21+namespace ConfusionMatrixSimt {
22+using namespace AscendC;
23+ 
24+constexpr uint32_t OUT_QUE_DEPTH = 1;
25+ 
26+constexpr uint32_t NUM_DOUBLE_BUFFER = 1;
27+ 
28+constexpr uint16_t DATA_COPY_PAD_BLOCK_COUNT = 1;
29+ 
30+constexpr int32_t WEIGHT_ONE = 1;
31+ 
32+constexpr uint32_t THREAD_NUM = 1024;
33+ 
34+template <typename LABEL_TYPE, typename Y_TYPE>
35+class ConfusionMatrixSimtBase {
36+public:
37+ __aicore__ inline ConfusionMatrixSimtBase(){};
38+ __aicore__ inline void BaseInit(GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
39+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe,
40+ bool isWeightEmpty);
41+ 
42+protected:
43+ __aicore__ inline void ParseTilingData(const ConfusionMatrixTilingData* __restrict tilingData);
44+ 
45+protected:
46+ GlobalTensor<LABEL_TYPE> labelsGm_;
47+ GlobalTensor<LABEL_TYPE> predictionsGm_;
48+ GlobalTensor<Y_TYPE> weightsGm_;
49+ GlobalTensor<Y_TYPE> yGm_;
50+ 
51+ int32_t blockIdx_ = 0;
52+ 
53+ bool isWeightEmpty_ = false;
54+ int64_t numClasses_ = 0;
55+ int64_t outputSize_ = 0;
56+ int64_t inputSize_ = 0;
57+ int64_t needCoreNum_ = 0;
58+ int64_t formerLength_ = 0;
59+ int64_t tailLength_ = 0;
60+ int64_t resetBinsCoreNum_ = 0;
61+ int64_t resetBinsLength_ = 0;
62+ int64_t resetBinsTailLength_ = 0;
63+ int64_t fullLoadBufSize_ = 0;
64+ int64_t batchUbBufSize_ = 0;
65+};
66+ 
67+template <typename LABEL_TYPE, typename Y_TYPE>
68+__aicore__ inline void ConfusionMatrixSimtBase<LABEL_TYPE, Y_TYPE>::BaseInit(
69+ GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
70+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe, bool isWeightEmpty)
71+{
72+ ParseTilingData(tilingData);
73+ isWeightEmpty_ = isWeightEmpty;
74+ labelsGm_.SetGlobalBuffer(reinterpret_cast<__gm__ LABEL_TYPE*>(labels));
75+ predictionsGm_.SetGlobalBuffer(reinterpret_cast<__gm__ LABEL_TYPE*>(predictions));
76+ if (!isWeightEmpty_) {
77+ weightsGm_.SetGlobalBuffer(reinterpret_cast<__gm__ Y_TYPE*>(weights));
78+ }
79+ yGm_.SetGlobalBuffer(reinterpret_cast<__gm__ Y_TYPE*>(y));
80+ 
81+ blockIdx_ = static_cast<int32_t>(GetBlockIdx());
82+}
83+ 
84+template <typename LABEL_TYPE, typename Y_TYPE>
85+__aicore__ inline void ConfusionMatrixSimtBase<LABEL_TYPE, Y_TYPE>::ParseTilingData(
86+ const ConfusionMatrixTilingData* __restrict tilingData)
87+{
88+ numClasses_ = tilingData->numClasses;
89+ outputSize_ = numClasses_ * numClasses_;
90+ inputSize_ = tilingData->inputSize;
91+ needCoreNum_ = tilingData->needXCoreNum;
92+ formerLength_ = tilingData->formerLength;
93+ tailLength_ = tilingData->tailLength;
94+ resetBinsCoreNum_ = tilingData->clearYCoreNum;
95+ resetBinsLength_ = tilingData->clearYFactor;
96+ resetBinsTailLength_ = tilingData->clearYTail;
97+ fullLoadBufSize_ = tilingData->fullLoadBufSize;
98+ batchUbBufSize_ = tilingData->batchUbBufSize;
99+}
100+ 
101+} // namespace ConfusionMatrixSimt
102+ 
103+#endif // CONFUSION_MATRIX_SIMT_BASE_H
@@ -0,0 +1,161 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software; you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_simt_full_load.h
13+ * \brief The implementation of confusion_matrix by full load in ub.
14+ */
15+ 
16+#ifndef CONFUSION_MATRIX_SIMT_FULL_LOAD_H
17+#define CONFUSION_MATRIX_SIMT_FULL_LOAD_H
18+ 
19+#include "kernel_operator.h"
20+#include "confusion_matrix_simt_base.h"
21+#include "confusion_matrix_tiling_data.h"
22+#include "simt_api/asc_simt.h"
23+#include "simt_api/device_atomic_functions.h"
24+#include "simt_api/asc_fp16.h"
25+#include "simt_api/asc_bf16.h"
26+ 
27+namespace ConfusionMatrixSimt {
28+using namespace AscendC;
29+ 
30+template <typename LABEL_TYPE, typename Y_TYPE>
31+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void UbSimtCompute(
32+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __ubuf__ Y_TYPE* yLocalAddr,
33+ const int64_t inputOffset, const int64_t inputDataLength, const int64_t numClasses)
34+{
35+ for (int64_t index = static_cast<int64_t>(threadIdx.x); index < inputDataLength;
36+ index += static_cast<int64_t>(blockDim.x)) {
37+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputOffset + index]);
38+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputOffset + index]);
39+ int64_t offset = label * numClasses + prediction;
40+ asc_atomic_add(yLocalAddr + offset, static_cast<Y_TYPE>(WEIGHT_ONE));
41+ }
42+}
43+ 
44+template <typename LABEL_TYPE, typename Y_TYPE>
45+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void UbSimtComputeWithWeight(
46+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __gm__ Y_TYPE* weightsGmAddr,
47+ __ubuf__ Y_TYPE* yLocalAddr, const int64_t inputOffset, const int64_t inputDataLength, const int64_t numClasses)
48+{
49+ for (int64_t index = static_cast<int64_t>(threadIdx.x); index < inputDataLength;
50+ index += static_cast<int64_t>(blockDim.x)) {
51+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputOffset + index]);
52+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputOffset + index]);
53+ int64_t offset = label * numClasses + prediction;
54+ asc_atomic_add(yLocalAddr + offset, weightsGmAddr[inputOffset + index]);
55+ }
56+}
57+ 
58+template <typename LABEL_TYPE, typename Y_TYPE>
59+class ConfusionMatrixSimtFullLoad : public ConfusionMatrixSimtBase<LABEL_TYPE, Y_TYPE> {
60+public:
61+ __aicore__ inline ConfusionMatrixSimtFullLoad(){};
62+ __aicore__ inline void Init(GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
63+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe,
64+ bool isWeightEmpty);
65+ __aicore__ inline void Process();
66+ 
67+private:
68+ __aicore__ inline void ResetBins();
69+ __aicore__ inline void Compute();
70+ __aicore__ inline void CopyOut(int64_t offsetInGm, uint32_t stride);
71+ 
72+private:
73+ LocalTensor<Y_TYPE> yLocal_;
74+ TPipe* tPipe_;
75+ TQue<TPosition::VECOUT, OUT_QUE_DEPTH> yQue_;
76+};
77+ 
78+template <typename LABEL_TYPE, typename Y_TYPE>
79+__aicore__ inline void ConfusionMatrixSimtFullLoad<LABEL_TYPE, Y_TYPE>::Init(
80+ GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
81+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe, bool isWeightEmpty)
82+{
83+ this->BaseInit(labels, predictions, weights, y, tilingData, tPipe, isWeightEmpty);
84+ tPipe_ = tPipe;
85+ tPipe_->InitBuffer(yQue_, NUM_DOUBLE_BUFFER, this->fullLoadBufSize_);
86+}
87+ 
88+template <typename LABEL_TYPE, typename Y_TYPE>
89+__aicore__ inline void ConfusionMatrixSimtFullLoad<LABEL_TYPE, Y_TYPE>::Process()
90+{
91+ if (this->blockIdx_ >= GetBlockNum()) {
92+ return;
93+ }
94+ 
95+ ResetBins();
96+ SyncAll();
97+ Compute();
98+}
99+ 
100+template <typename LABEL_TYPE, typename Y_TYPE>
101+__aicore__ inline void ConfusionMatrixSimtFullLoad<LABEL_TYPE, Y_TYPE>::ResetBins()
102+{
103+ if (this->blockIdx_ >= this->resetBinsCoreNum_) {
104+ return;
105+ }
106+ 
107+ yLocal_ = yQue_.template AllocTensor<Y_TYPE>();
108+ Duplicate<Y_TYPE>(yLocal_, 0, this->outputSize_);
109+ yQue_.EnQue(yLocal_);
110+ yLocal_ = yQue_.template DeQue<Y_TYPE>();
111+ 
112+ int64_t resetBinsDataLength = this->blockIdx_ == this->resetBinsCoreNum_ - 1 ? this->resetBinsTailLength_ :
113+ this->resetBinsLength_;
114+ uint32_t resetBinsDataByteSize = static_cast<uint32_t>(resetBinsDataLength * sizeof(Y_TYPE));
115+ DataCopyExtParams dataCopyExtParams{DATA_COPY_PAD_BLOCK_COUNT, resetBinsDataByteSize, 0, 0, 0};
116+ DataCopyPad(this->yGm_[this->blockIdx_ * this->resetBinsLength_], yLocal_, dataCopyExtParams);
117+ yQue_.template FreeTensor<Y_TYPE>(yLocal_);
118+}
119+ 
120+template <typename LABEL_TYPE, typename Y_TYPE>
121+__aicore__ inline void ConfusionMatrixSimtFullLoad<LABEL_TYPE, Y_TYPE>::Compute()
122+{
123+ if (this->blockIdx_ >= this->needCoreNum_) {
124+ return;
125+ }
126+ 
127+ yLocal_ = yQue_.template AllocTensor<Y_TYPE>();
128+ Duplicate<Y_TYPE>(yLocal_, 0, this->outputSize_);
129+ int64_t inputOffset = this->blockIdx_ * this->formerLength_;
130+ int64_t inputDataLength = this->blockIdx_ == this->needCoreNum_ - 1 ? this->tailLength_ : this->formerLength_;
131+ __gm__ LABEL_TYPE* labelsGmAddr = (__gm__ LABEL_TYPE*)this->labelsGm_.GetPhyAddr();
132+ __gm__ LABEL_TYPE* predictionsGmAddr = (__gm__ LABEL_TYPE*)this->predictionsGm_.GetPhyAddr();
133+ __ubuf__ Y_TYPE* yLocalAddr = (__ubuf__ Y_TYPE*)yLocal_.GetPhyAddr();
134+ 
135+ if (this->isWeightEmpty_) {
136+ asc_vf_call<UbSimtCompute<LABEL_TYPE, Y_TYPE>>(dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr, yLocalAddr,
137+ inputOffset, inputDataLength, this->numClasses_);
138+ } else {
139+ __gm__ Y_TYPE* weightsGmAddr = (__gm__ Y_TYPE*)this->weightsGm_.GetPhyAddr();
140+ asc_vf_call<UbSimtComputeWithWeight<LABEL_TYPE, Y_TYPE>>(dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr,
141+ weightsGmAddr, yLocalAddr, inputOffset,
142+ inputDataLength, this->numClasses_);
143+ }
144+ 
145+ CopyOut(0, static_cast<uint32_t>(this->outputSize_ * sizeof(Y_TYPE)));
146+ yQue_.template FreeTensor<Y_TYPE>(yLocal_);
147+}
148+ 
149+template <typename LABEL_TYPE, typename Y_TYPE>
150+__aicore__ inline void ConfusionMatrixSimtFullLoad<LABEL_TYPE, Y_TYPE>::CopyOut(int64_t offsetInGm, uint32_t stride)
151+{
152+ yQue_.EnQue(yLocal_);
153+ yLocal_ = yQue_.template DeQue<Y_TYPE>();
154+ SetAtomicAdd<Y_TYPE>();
155+ DataCopyExtParams dataCopyExtParams{DATA_COPY_PAD_BLOCK_COUNT, stride, 0, 0, 0};
156+ DataCopyPad(this->yGm_[offsetInGm], yLocal_, dataCopyExtParams);
157+ SetAtomicNone();
158+}
159+ 
160+} // namespace ConfusionMatrixSimt
161+#endif // CONFUSION_MATRIX_SIMT_FULL_LOAD_H
@@ -0,0 +1,129 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software; you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_simt_not_full_load_gm.h
13+ * \brief The implementation of confusion_matrix by not full load in gm.
14+ */
15+ 
16+#ifndef CONFUSION_MATRIX_SIMT_NOT_FULL_LOAD_GM_H
17+#define CONFUSION_MATRIX_SIMT_NOT_FULL_LOAD_GM_H
18+ 
19+#include "confusion_matrix_tiling_data.h"
20+#include "simt_api/asc_simt.h"
21+#include "simt_api/device_atomic_functions.h"
22+#include "simt_api/asc_fp16.h"
23+#include "simt_api/asc_bf16.h"
24+ 
25+namespace ConfusionMatrixSimt {
26+using namespace AscendC;
27+ 
28+template <typename LABEL_TYPE, typename Y_TYPE>
29+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void GmSimtCompute(
30+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __gm__ Y_TYPE* yGmAddr,
31+ const int64_t inputOffset, const int64_t inputDataLength, const int64_t numClasses)
32+{
33+ for (int64_t index = static_cast<int64_t>(threadIdx.x); index < inputDataLength;
34+ index += static_cast<int64_t>(blockDim.x)) {
35+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputOffset + index]);
36+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputOffset + index]);
37+ int64_t offset = label * numClasses + prediction;
38+ asc_atomic_add(yGmAddr + offset, static_cast<Y_TYPE>(WEIGHT_ONE));
39+ }
40+}
41+ 
42+template <typename LABEL_TYPE, typename Y_TYPE>
43+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void GmSimtComputeWithWeight(
44+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __gm__ Y_TYPE* weightsGmAddr,
45+ __gm__ Y_TYPE* yGmAddr, const int64_t inputOffset, const int64_t inputDataLength, const int64_t numClasses)
46+{
47+ for (int64_t index = static_cast<int64_t>(threadIdx.x); index < inputDataLength;
48+ index += static_cast<int64_t>(blockDim.x)) {
49+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputOffset + index]);
50+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputOffset + index]);
51+ int64_t offset = label * numClasses + prediction;
52+ asc_atomic_add(yGmAddr + offset, weightsGmAddr[inputOffset + index]);
53+ }
54+}
55+ 
56+template <typename LABEL_TYPE, typename Y_TYPE>
57+class ConfusionMatrixSimtNotFullLoadGm : public ConfusionMatrixSimtBase<LABEL_TYPE, Y_TYPE> {
58+public:
59+ __aicore__ inline ConfusionMatrixSimtNotFullLoadGm(){};
60+ __aicore__ inline void Init(GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
61+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe,
62+ bool isWeightEmpty);
63+ __aicore__ inline void Process();
64+ 
65+private:
66+ __aicore__ inline void ResetBins();
67+ __aicore__ inline void Compute();
68+};
69+ 
70+template <typename LABEL_TYPE, typename Y_TYPE>
71+__aicore__ inline void ConfusionMatrixSimtNotFullLoadGm<LABEL_TYPE, Y_TYPE>::Init(
72+ GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
73+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe, bool isWeightEmpty)
74+{
75+ this->BaseInit(labels, predictions, weights, y, tilingData, tPipe, isWeightEmpty);
76+}
77+ 
78+template <typename LABEL_TYPE, typename Y_TYPE>
79+__aicore__ inline void ConfusionMatrixSimtNotFullLoadGm<LABEL_TYPE, Y_TYPE>::Process()
80+{
81+ if (this->blockIdx_ >= GetBlockNum()) {
82+ return;
83+ }
84+ 
85+ ResetBins();
86+ SyncAll();
87+ Compute();
88+}
89+ 
90+template <typename LABEL_TYPE, typename Y_TYPE>
91+__aicore__ inline void ConfusionMatrixSimtNotFullLoadGm<LABEL_TYPE, Y_TYPE>::ResetBins()
92+{
93+ if (this->blockIdx_ >= this->resetBinsCoreNum_) {
94+ return;
95+ }
96+ 
97+ int64_t resetBinsHeadIndex = this->blockIdx_ * this->resetBinsLength_;
98+ int64_t resetBinsDataLength = (this->blockIdx_ == this->resetBinsCoreNum_ - 1) ? this->resetBinsTailLength_ :
99+ this->resetBinsLength_;
100+ 
101+ InitOutput<Y_TYPE>(this->yGm_[resetBinsHeadIndex], resetBinsDataLength, static_cast<Y_TYPE>(0));
102+}
103+ 
104+template <typename LABEL_TYPE, typename Y_TYPE>
105+__aicore__ inline void ConfusionMatrixSimtNotFullLoadGm<LABEL_TYPE, Y_TYPE>::Compute()
106+{
107+ if (this->blockIdx_ >= this->needCoreNum_) {
108+ return;
109+ }
110+ 
111+ int64_t inputOffset = this->blockIdx_ * this->formerLength_;
112+ int64_t inputDataLength = (this->blockIdx_ == this->needCoreNum_ - 1) ? this->tailLength_ : this->formerLength_;
113+ __gm__ LABEL_TYPE* labelsGmAddr = (__gm__ LABEL_TYPE*)this->labelsGm_.GetPhyAddr();
114+ __gm__ LABEL_TYPE* predictionsGmAddr = (__gm__ LABEL_TYPE*)this->predictionsGm_.GetPhyAddr();
115+ __gm__ Y_TYPE* yGmAddr = (__gm__ Y_TYPE*)this->yGm_.GetPhyAddr();
116+ 
117+ if (this->isWeightEmpty_) {
118+ asc_vf_call<GmSimtCompute<LABEL_TYPE, Y_TYPE>>(dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr, yGmAddr,
119+ inputOffset, inputDataLength, this->numClasses_);
120+ } else {
121+ __gm__ Y_TYPE* weightsGmAddr = (__gm__ Y_TYPE*)this->weightsGm_.GetPhyAddr();
122+ asc_vf_call<GmSimtComputeWithWeight<LABEL_TYPE, Y_TYPE>>(dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr,
123+ weightsGmAddr, yGmAddr, inputOffset, inputDataLength,
124+ this->numClasses_);
125+ }
126+}
127+ 
128+} // namespace ConfusionMatrixSimt
129+#endif // CONFUSION_MATRIX_SIMT_NOT_FULL_LOAD_GM_H
@@ -0,0 +1,177 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software; you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_simt_not_full_load_ub.h
13+ * \brief The implementation of confusion_matrix by not full load in ub.
14+ */
15+ 
16+#ifndef CONFUSION_MATRIX_SIMT_NOT_FULL_LOAD_UB_H
17+#define CONFUSION_MATRIX_SIMT_NOT_FULL_LOAD_UB_H
18+ 
19+#include "kernel_operator.h"
20+#include "confusion_matrix_simt_base.h"
21+#include "confusion_matrix_tiling_data.h"
22+#include "simt_api/asc_simt.h"
23+#include "simt_api/device_atomic_functions.h"
24+#include "simt_api/asc_fp16.h"
25+#include "simt_api/asc_bf16.h"
26+ 
27+namespace ConfusionMatrixSimt {
28+using namespace AscendC;
29+ 
30+template <typename LABEL_TYPE, typename Y_TYPE>
31+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void UbSimtComputeLoop(
32+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __ubuf__ Y_TYPE* yLocalAddr,
33+ const int64_t inputOffset, const int64_t inputDataLength, const int64_t ubLoop, const int64_t availableUbSize,
34+ const int64_t numClasses)
35+{
36+ for (int64_t index = static_cast<int64_t>(threadIdx.x); index < inputDataLength;
37+ index += static_cast<int64_t>(blockDim.x)) {
38+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputOffset + index]);
39+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputOffset + index]);
40+ int64_t offset = label * numClasses + prediction;
41+ int64_t currentLoopMinAddr = ubLoop * availableUbSize;
42+ int64_t currentLoopMaxAddr = currentLoopMinAddr + availableUbSize;
43+ if (offset >= currentLoopMinAddr && offset < currentLoopMaxAddr) {
44+ int64_t arrayOffset = offset - currentLoopMinAddr;
45+ asc_atomic_add(yLocalAddr + arrayOffset, static_cast<Y_TYPE>(WEIGHT_ONE));
46+ }
47+ }
48+}
49+ 
50+template <typename LABEL_TYPE, typename Y_TYPE>
51+__simt_vf__ __aicore__ LAUNCH_BOUND(THREAD_NUM) inline void UbSimtComputeWithWeightLoop(
52+ __gm__ LABEL_TYPE* labelsGmAddr, __gm__ LABEL_TYPE* predictionsGmAddr, __gm__ Y_TYPE* weightsGmAddr,
53+ __ubuf__ Y_TYPE* yLocalAddr, const int64_t inputOffset, const int64_t inputDataLength, const int64_t ubLoop,
54+ const int64_t availableUbSize, const int64_t numClasses)
55+{
56+ for (int64_t index = static_cast<int64_t>(threadIdx.x); index < inputDataLength;
57+ index += static_cast<int64_t>(blockDim.x)) {
58+ int64_t label = static_cast<int64_t>(labelsGmAddr[inputOffset + index]);
59+ int64_t prediction = static_cast<int64_t>(predictionsGmAddr[inputOffset + index]);
60+ int64_t offset = label * numClasses + prediction;
61+ int64_t currentLoopMinAddr = ubLoop * availableUbSize;
62+ int64_t currentLoopMaxAddr = currentLoopMinAddr + availableUbSize;
63+ if (offset >= currentLoopMinAddr && offset < currentLoopMaxAddr) {
64+ int64_t arrayOffset = offset - currentLoopMinAddr;
65+ asc_atomic_add(yLocalAddr + arrayOffset, weightsGmAddr[inputOffset + index]);
66+ }
67+ }
68+}
69+ 
70+template <typename LABEL_TYPE, typename Y_TYPE>
71+class ConfusionMatrixSimtBatchLoad : public ConfusionMatrixSimtBase<LABEL_TYPE, Y_TYPE> {
72+public:
73+ __aicore__ inline ConfusionMatrixSimtBatchLoad(){};
74+ __aicore__ inline void Init(GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
75+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe,
76+ bool isWeightEmpty);
77+ __aicore__ inline void Process();
78+ 
79+private:
80+ __aicore__ inline void ResetBins();
81+ __aicore__ inline void Compute();
82+ __aicore__ inline void CopyOut(int64_t offsetInGm, uint32_t stride);
83+ 
84+private:
85+ LocalTensor<Y_TYPE> yLocal_;
86+ TPipe* tPipe_;
87+ TQue<TPosition::VECOUT, OUT_QUE_DEPTH> yQue_;
88+ 
89+ int64_t availableUbSize_ = 0;
90+ int64_t ubLoopCount_ = 0;
91+};
92+ 
93+template <typename LABEL_TYPE, typename Y_TYPE>
94+__aicore__ inline void ConfusionMatrixSimtBatchLoad<LABEL_TYPE, Y_TYPE>::Init(
95+ GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
96+ const ConfusionMatrixTilingData* __restrict tilingData, TPipe* tPipe, bool isWeightEmpty)
97+{
98+ this->BaseInit(labels, predictions, weights, y, tilingData, tPipe, isWeightEmpty);
99+ 
100+ availableUbSize_ = tilingData->ubNumCanUse;
101+ ubLoopCount_ = tilingData->ubLoopNum;
102+ 
103+ tPipe_ = tPipe;
104+ tPipe_->InitBuffer(yQue_, NUM_DOUBLE_BUFFER, this->batchUbBufSize_);
105+}
106+ 
107+template <typename LABEL_TYPE, typename Y_TYPE>
108+__aicore__ inline void ConfusionMatrixSimtBatchLoad<LABEL_TYPE, Y_TYPE>::Process()
109+{
110+ if (this->blockIdx_ >= GetBlockNum()) {
111+ return;
112+ }
113+ 
114+ ResetBins();
115+ SyncAll();
116+ Compute();
117+}
118+ 
119+template <typename LABEL_TYPE, typename Y_TYPE>
120+__aicore__ inline void ConfusionMatrixSimtBatchLoad<LABEL_TYPE, Y_TYPE>::ResetBins()
121+{
122+ int64_t resetBinsHeadIndex = this->blockIdx_ * this->resetBinsLength_;
123+ int64_t resetBinsDataLength = (this->blockIdx_ == this->resetBinsCoreNum_ - 1) ? this->resetBinsTailLength_ :
124+ this->resetBinsLength_;
125+ 
126+ InitOutput<Y_TYPE>(this->yGm_[resetBinsHeadIndex], resetBinsDataLength, static_cast<Y_TYPE>(0));
127+}
128+ 
129+template <typename LABEL_TYPE, typename Y_TYPE>
130+__aicore__ inline void ConfusionMatrixSimtBatchLoad<LABEL_TYPE, Y_TYPE>::Compute()
131+{
132+ if (this->blockIdx_ >= this->needCoreNum_) {
133+ return;
134+ }
135+ 
136+ int64_t inputOffset = this->blockIdx_ * this->formerLength_;
137+ int64_t inputDataLength = (this->blockIdx_ == this->needCoreNum_ - 1) ? this->tailLength_ : this->formerLength_;
138+ __gm__ LABEL_TYPE* labelsGmAddr = (__gm__ LABEL_TYPE*)this->labelsGm_.GetPhyAddr();
139+ __gm__ LABEL_TYPE* predictionsGmAddr = (__gm__ LABEL_TYPE*)this->predictionsGm_.GetPhyAddr();
140+ 
141+ for (int64_t index = 0; index < this->ubLoopCount_; index++) {
142+ int64_t outputLength = (index == this->ubLoopCount_ - 1) ?
143+ (this->outputSize_ - (this->ubLoopCount_ - 1) * this->availableUbSize_) :
144+ this->availableUbSize_;
145+ yLocal_ = yQue_.template AllocTensor<Y_TYPE>();
146+ Duplicate<Y_TYPE>(yLocal_, 0, outputLength);
147+ 
148+ __ubuf__ Y_TYPE* yLocalAddr = (__ubuf__ Y_TYPE*)yLocal_.GetPhyAddr();
149+ if (this->isWeightEmpty_) {
150+ asc_vf_call<UbSimtComputeLoop<LABEL_TYPE, Y_TYPE>>(dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr,
151+ yLocalAddr, inputOffset, inputDataLength, index,
152+ this->availableUbSize_, this->numClasses_);
153+ } else {
154+ __gm__ Y_TYPE* weightsGmAddr = (__gm__ Y_TYPE*)this->weightsGm_.GetPhyAddr();
155+ asc_vf_call<UbSimtComputeWithWeightLoop<LABEL_TYPE, Y_TYPE>>(
156+ dim3{THREAD_NUM}, labelsGmAddr, predictionsGmAddr, weightsGmAddr, yLocalAddr, inputOffset,
157+ inputDataLength, index, this->availableUbSize_, this->numClasses_);
158+ }
159+ 
160+ CopyOut(index * this->availableUbSize_, static_cast<uint32_t>(outputLength * sizeof(Y_TYPE)));
161+ yQue_.template FreeTensor<Y_TYPE>(yLocal_);
162+ }
163+}
164+ 
165+template <typename LABEL_TYPE, typename Y_TYPE>
166+__aicore__ inline void ConfusionMatrixSimtBatchLoad<LABEL_TYPE, Y_TYPE>::CopyOut(int64_t offsetInGm, uint32_t stride)
167+{
168+ yQue_.EnQue(yLocal_);
169+ yLocal_ = yQue_.template DeQue<Y_TYPE>();
170+ SetAtomicAdd<Y_TYPE>();
171+ DataCopyExtParams dataCopyExtParams{DATA_COPY_PAD_BLOCK_COUNT, stride, 0, 0, 0};
172+ DataCopyPad(this->yGm_[offsetInGm], yLocal_, dataCopyExtParams);
173+ SetAtomicNone();
174+}
175+ 
176+} // namespace ConfusionMatrixSimt
177+#endif // CONFUSION_MATRIX_SIMT_NOT_FULL_LOAD_UB_H
@@ -0,0 +1,36 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_tiling_data.h
13+ * \brief confusion_matrix_tiling_data.h
14+ */
15+ 
16+#ifndef _CONFUSION_MATRIX_TILING_DATA_H_
17+#define _CONFUSION_MATRIX_TILING_DATA_H_
18+ 
19+struct ConfusionMatrixTilingData {
20+ int64_t numClasses = 0;
21+ int64_t inputSize = 0;
22+ int64_t ubNumCanUse = 0;
23+ int64_t ubLoopNum = 0;
24+ int64_t needXCoreNum = 0;
25+ int64_t formerLength = 0;
26+ int64_t tailLength = 0;
27+ int64_t clearYCoreNum = 0;
28+ int64_t clearYFactor = 0;
29+ int64_t clearYTail = 0;
30+ int64_t binsFormerLength = 0;
31+ int64_t needBinsCoreNum = 0;
32+ int64_t binsTailLength = 0;
33+ int64_t fullLoadBufSize = 0;
34+ int64_t batchUbBufSize = 0;
35+};
36+#endif
@@ -0,0 +1,51 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix_tiling_key.h
13+ * \brief confusion_matrix tiling key declare
14+ */
15+ 
16+#ifndef _CONFUSION_MATRIX_TILING_KEY_DECL_H_
17+#define _CONFUSION_MATRIX_TILING_KEY_DECL_H_
18+#include "ascendc/host_api/tiling/template_argument.h"
19+ 
20+#define TPL_SCH_ID_FULL_LOAD 0 // full load to UB
21+#define TPL_SCH_ID_BATCH_LOAD 1 // batch load to UB
22+#define TPL_SCH_ID_NOT_FULL_LOAD 2 // not load to UB
23+#define TPL_SCH_ID_DETERMINE 3 // determine
24+ 
25+#define TPL_OUTPUT_DTYPE_FLOAT 0
26+#define TPL_OUTPUT_DTYPE_INT32 1
27+#define TPL_OUTPUT_DTYPE_FLOAT16 2
28+#define TPL_OUTPUT_DTYPE_INT8 3
29+#define TPL_OUTPUT_DTYPE_UINT8 4
30+ 
31+#define TPL_EMPTY_WEIGHT 0
32+#define TPL_HAS_WEIGHT 1
33+ 
34+#define CONFUSION_MATRIX_TPL_KEY_DECL() \
35+ ASCENDC_TPL_UINT_DECL(schId, ASCENDC_TPL_8_BW, ASCENDC_TPL_UI_LIST, TPL_SCH_ID_FULL_LOAD, TPL_SCH_ID_BATCH_LOAD, \
36+ TPL_SCH_ID_NOT_FULL_LOAD, TPL_SCH_ID_DETERMINE), \
37+ ASCENDC_TPL_UINT_DECL(outputDtype, ASCENDC_TPL_8_BW, ASCENDC_TPL_UI_LIST, TPL_OUTPUT_DTYPE_FLOAT, \
38+ TPL_OUTPUT_DTYPE_INT32, TPL_OUTPUT_DTYPE_FLOAT16, TPL_OUTPUT_DTYPE_INT8, \
39+ TPL_OUTPUT_DTYPE_UINT8), \
40+ ASCENDC_TPL_UINT_DECL(isWeight, ASCENDC_TPL_8_BW, ASCENDC_TPL_UI_LIST, 0, 1),
41+ 
42+#define CONFUSION_MATRIX_TPL_KEY_SEL() \
43+ ASCENDC_TPL_UINT_SEL(schId, ASCENDC_TPL_UI_RANGE, 1, 0, TPL_SCH_ID_DETERMINE), \
44+ ASCENDC_TPL_UINT_SEL(outputDtype, ASCENDC_TPL_UI_LIST, TPL_OUTPUT_DTYPE_FLOAT, TPL_OUTPUT_DTYPE_INT32, \
45+ TPL_OUTPUT_DTYPE_FLOAT16, TPL_OUTPUT_DTYPE_INT8, TPL_OUTPUT_DTYPE_UINT8), \
46+ ASCENDC_TPL_UINT_SEL(isWeight, ASCENDC_TPL_UI_LIST, TPL_EMPTY_WEIGHT, TPL_HAS_WEIGHT),
47+ 
48+ASCENDC_TPL_ARGS_DECL(ConfusionMatrix, CONFUSION_MATRIX_TPL_KEY_DECL());
49+ 
50+ASCENDC_TPL_SEL(ASCENDC_TPL_ARGS_SEL(CONFUSION_MATRIX_TPL_KEY_SEL()));
51+#endif
@@ -0,0 +1,148 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software; you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file confusion_matrix.cpp
13+ * \brief The kernel function of confusion_matrix and the entrance for using confusion_matrix.
14+ */
15+ 
16+#include "kernel_tiling/kernel_tiling.h"
17+#include "kernel_operator.h"
18+#include "arch35/confusion_matrix_tiling_data.h"
19+#include "arch35/confusion_matrix_tiling_key.h"
20+#include "arch35/confusion_matrix_simt_base.h"
21+#include "arch35/confusion_matrix_simt_full_load.h"
22+#include "arch35/confusion_matrix_simt_not_full_load_ub.h"
23+#include "arch35/confusion_matrix_simt_not_full_load_gm.h"
24+#include "arch35/confusion_matrix_determine.h"
25+ 
26+using namespace AscendC;
27+ 
28+#define TPL_SCH_ID_FULL_LOAD 0 // full load to UB
29+#define TPL_SCH_ID_BATCH_LOAD 1 // batch load to UB
30+#define TPL_SCH_ID_NOT_FULL_LOAD 2 // not load to UB
31+#define TPL_SCH_ID_DETERMINE 3 // determine
32+ 
33+#define TPL_OUTPUT_DTYPE_FLOAT 0
34+#define TPL_OUTPUT_DTYPE_INT32 1
35+#define TPL_OUTPUT_DTYPE_FLOAT16 2
36+#define TPL_OUTPUT_DTYPE_INT8 3
37+#define TPL_OUTPUT_DTYPE_UINT8 4
38+ 
39+#define TPL_EMPTY_WEIGHT 0
40+#define TPL_HAS_WEIGHT 1
41+ 
42+template <uint64_t schId, uint64_t outputDtype, uint64_t isWeight>
43+__global__ __aicore__ void confusion_matrix(GM_ADDR labels, GM_ADDR predictions, GM_ADDR weights, GM_ADDR y,
44+ GM_ADDR workspace, GM_ADDR tiling)
45+{
46+ if (g_coreType == AscendC::AIC) {
47+ return;
48+ }
49+ KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_MIX_AIV_1_0);
50+ 
51+ using LABEL_TYPE = DTYPE_LABELS;
52+ 
53+ AscendC::TPipe tPipe;
54+ 
55+ REGISTER_TILING_DEFAULT(ConfusionMatrixTilingData);
56+ GET_TILING_DATA_WITH_STRUCT(ConfusionMatrixTilingData, tilingDataIn, tiling);
57+ const ConfusionMatrixTilingData* __restrict tilingData = &tilingDataIn;
58+ 
59+ bool isWeightEmpty = isWeight == TPL_EMPTY_WEIGHT ? true : false;
60+ 
61+ // For int8/uint8 output: only DETERMINE mode is supported.
62+ // asc_atomic_add does not support int8_t/uint8_t, so FULL_LOAD,
63+ // BATCH_LOAD, and NOT_FULL_LOAD (which rely on asc_atomic_add) cannot
64+ // be used. Tiling forces DETERMINE (schId=3) for these types.
65+ // DETERMINE mode uses direct += on disjoint output ranges per core,
66+ // so no atomic operations are needed and int8_t/uint8_t work correctly.
67+ if constexpr (outputDtype == TPL_OUTPUT_DTYPE_INT8 || outputDtype == TPL_OUTPUT_DTYPE_UINT8) {
68+ if (schId == TPL_SCH_ID_DETERMINE) {
69+ if (outputDtype == TPL_OUTPUT_DTYPE_INT8) {
70+ ConfusionMatrixSimt::ConfusionMatrixDetermine<LABEL_TYPE, int8_t> op;
71+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
72+ op.Process();
73+ } else {
74+ ConfusionMatrixSimt::ConfusionMatrixDetermine<LABEL_TYPE, uint8_t> op;
75+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
76+ op.Process();
77+ }
78+ }
79+ } else {
80+ // FULL_LOAD
81+ if (schId == TPL_SCH_ID_FULL_LOAD && outputDtype == TPL_OUTPUT_DTYPE_FLOAT) {
82+ ConfusionMatrixSimt::ConfusionMatrixSimtFullLoad<LABEL_TYPE, float> op;
83+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
84+ op.Process();
85+ }
86+ if (schId == TPL_SCH_ID_FULL_LOAD && outputDtype == TPL_OUTPUT_DTYPE_INT32) {
87+ ConfusionMatrixSimt::ConfusionMatrixSimtFullLoad<LABEL_TYPE, int32_t> op;
88+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
89+ op.Process();
90+ }
91+ if (schId == TPL_SCH_ID_FULL_LOAD && outputDtype == TPL_OUTPUT_DTYPE_FLOAT16) {
92+ ConfusionMatrixSimt::ConfusionMatrixSimtFullLoad<LABEL_TYPE, half> op;
93+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
94+ op.Process();
95+ }
96+ 
97+ // BATCH_LOAD
98+ if (schId == TPL_SCH_ID_BATCH_LOAD && outputDtype == TPL_OUTPUT_DTYPE_FLOAT) {
99+ ConfusionMatrixSimt::ConfusionMatrixSimtBatchLoad<LABEL_TYPE, float> op;
100+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
101+ op.Process();
102+ }
103+ if (schId == TPL_SCH_ID_BATCH_LOAD && outputDtype == TPL_OUTPUT_DTYPE_INT32) {
104+ ConfusionMatrixSimt::ConfusionMatrixSimtBatchLoad<LABEL_TYPE, int32_t> op;
105+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
106+ op.Process();
107+ }
108+ if (schId == TPL_SCH_ID_BATCH_LOAD && outputDtype == TPL_OUTPUT_DTYPE_FLOAT16) {
109+ ConfusionMatrixSimt::ConfusionMatrixSimtBatchLoad<LABEL_TYPE, half> op;
110+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
111+ op.Process();
112+ }
113+ 
114+ // NOT_FULL_LOAD (GM)
115+ if (schId == TPL_SCH_ID_NOT_FULL_LOAD && outputDtype == TPL_OUTPUT_DTYPE_FLOAT) {
116+ ConfusionMatrixSimt::ConfusionMatrixSimtNotFullLoadGm<LABEL_TYPE, float> op;
117+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
118+ op.Process();
119+ }
120+ if (schId == TPL_SCH_ID_NOT_FULL_LOAD && outputDtype == TPL_OUTPUT_DTYPE_INT32) {
121+ ConfusionMatrixSimt::ConfusionMatrixSimtNotFullLoadGm<LABEL_TYPE, int32_t> op;
122+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
123+ op.Process();
124+ }
125+ if (schId == TPL_SCH_ID_NOT_FULL_LOAD && outputDtype == TPL_OUTPUT_DTYPE_FLOAT16) {
126+ ConfusionMatrixSimt::ConfusionMatrixSimtNotFullLoadGm<LABEL_TYPE, half> op;
127+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
128+ op.Process();
129+ }
130+ 
131+ // DETERMINE
132+ if (schId == TPL_SCH_ID_DETERMINE && outputDtype == TPL_OUTPUT_DTYPE_FLOAT) {
133+ ConfusionMatrixSimt::ConfusionMatrixDetermine<LABEL_TYPE, float> op;
134+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
135+ op.Process();
136+ }
137+ if (schId == TPL_SCH_ID_DETERMINE && outputDtype == TPL_OUTPUT_DTYPE_INT32) {
138+ ConfusionMatrixSimt::ConfusionMatrixDetermine<LABEL_TYPE, int32_t> op;
139+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
140+ op.Process();
141+ }
142+ if (schId == TPL_SCH_ID_DETERMINE && outputDtype == TPL_OUTPUT_DTYPE_FLOAT16) {
143+ ConfusionMatrixSimt::ConfusionMatrixDetermine<LABEL_TYPE, half> op;
144+ op.Init(labels, predictions, weights, y, tilingData, &tPipe, isWeightEmpty);
145+ op.Process();
146+ }
147+ }
148+}
@@ -0,0 +1,184 @@
1+#!/usr/bin/env python3
2+# -*- coding: UTF-8 -*-
3+# ----------------------------------------------------------------------------
4+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
5+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6+# CANN Open Software License Agreement Version 2.0 (the "License").
7+# Please refer to the License for details. You may not use this file except in compliance with the License.
8+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10+# See LICENSE in the root of the software repository for the full text of the License.
11+# ----------------------------------------------------------------------------
12+"""ConfusionMatrix 多通路 golden(TestSpec 范式)。
13+ 
14+通路支持表(本算子交付面):
15+| 通路 | 支持 | 依据 |
16+|--------|------|------|
17+| kernel | ✅ | op_kernel/arch35 有实现 |
18+| geir | ✅ | op_graph/confusion_matrix_proto.h 有 REG_OP(ConfusionMatrix) |
19+| aclnn | ❌ | Ascend910B/910C built-in 无 aclnn 接口,本算子对齐该支持面不交付 |
20+| e2e | ❌ | torch_npu 无绑定(无 aclnn 接口 → 无可调用入口) |
21+ 
22+int8/uint8 输出:整型计数语义、差 1 就是错 → binary_equal(非量化场景,输入含整型,
23+不适用 quant 的浮点输入前提)。int8/uint8 中间累加用 int32 防 scatter_add 回绕。
24+"""
25+ 
26+__spec__ = {
27+ "confusion_matrix": "ConfusionMatrixKernelSpec",
28+}
29+ 
30+import numpy as np
31+import torch
32+ 
33+_DTYPE_MAP = {
34+ "float32": torch.float32,
35+ "float64": torch.float64,
36+ "float16": torch.float16,
37+ "int32": torch.int32,
38+ "int8": torch.int8,
39+ "uint8": torch.uint8,
40+}
41+ 
42+_TOL = {
43+ "float32": {"standard": "cross_check", "level": "L1"},
44+ "float16": {"standard": "cross_check", "level": "L1"},
45+}
46+ 
47+ 
48+def _attr(kwargs, name, default):
49+ """CSV 里的 attributes 都是字符串,统一转成 default 的类型。"""
50+ v = kwargs.get(name, default)
51+ if isinstance(v, str):
52+ s = v.strip().lower()
53+ if s in ("true", "false", "yes", "no", "1", "0"):
54+ return s in ("true", "yes", "1")
55+ try:
56+ return type(default)(v)
57+ except Exception:
58+ return default
59+ return v
60+ 
61+ 
62+def _normalize(val):
63+ if isinstance(val, (np.ndarray, np.generic)):
64+ return val.item() if val.ndim == 0 else val.tolist()
65+ if isinstance(val, bytes):
66+ return val.decode()
67+ return val
68+ 
69+ 
70+def _resolve_compute_dtype(**kwargs):
71+ """累加精度基准:取 TTK 下发的 output_dtypes(Promote 后的值)。
72+ 
73+ 三方比对(cross_check)下 TTK 已按 Promote 抬高 output_dtypes(fp16->fp32、
74+ fp32->fp64),golden 据此在抬高后的精度上累加出高精度真值;两方比对未抬高,
75+ 则跟随算子声明精度。取不到 output_dtypes 时回落算子声明的 dtype。
76+ 返回 (compute_dtype, final_dtype):int8/uint8 时 compute 为 int32 中转、
77+ final 为目标 dtype;其余两者相同。
78+ """
79+ dtype_str = _normalize(kwargs.get("dtype", "float32"))
80+ final_dtype = _DTYPE_MAP.get(dtype_str, torch.float32)
81+ od = kwargs.get("output_dtypes") or []
82+ if od:
83+ first = od[0]
84+ if isinstance(first, (list, tuple)):
85+ first = first[0] if first else None
86+ if first is not None:
87+ final_dtype = _DTYPE_MAP.get(str(first), final_dtype)
88+ compute_dtype = (
89+ torch.int32 if final_dtype in (torch.int8, torch.uint8) else final_dtype
90+ )
91+ return compute_dtype, final_dtype
92+ 
93+ 
94+def _compute(labels, predictions, weights, **kwargs):
95+ """计算核(torch 进 torch 出)。golden 用 torch.scatter_add 竞品接口拼接。
96+ 
97+ 累加精度按 _resolve_compute_dtype:三方比对下在 Promote 抬高后的精度上算
98+ 高精度真值;两方比对跟随算子声明精度。int8/uint8 输出用 int32 中间累加再
99+ cast 回(加法环同态下与窄整型累加等价,规避 torch 窄整型 scatter_add 的
100+ 中间量行为差异)。
101+ """
102+ num_classes = _attr(kwargs, "num_classes", 0)
103+ num_classes = _normalize(num_classes)
104+ 
105+ labels_int = labels.to(torch.int64)
106+ preds_int = predictions.to(torch.int64)
107+ flat_index = labels_int * num_classes + preds_int
108+ 
109+ compute_dtype, final_dtype = _resolve_compute_dtype(**kwargs)
110+ 
111+ y_flat = torch.zeros(num_classes * num_classes, dtype=compute_dtype)
112+ if weights is not None and weights.numel() > 0:
113+ y_flat.scatter_add_(0, flat_index, weights.to(compute_dtype))
114+ else:
115+ y_flat.scatter_add_(
116+ 0, flat_index, torch.ones(labels_int.shape[0], dtype=compute_dtype)
117+ )
118+ 
119+ if compute_dtype != final_dtype:
120+ y_flat = y_flat.to(final_dtype)
121+ return [y_flat.view(num_classes, num_classes)]
122+ 
123+ 
124+class _Compose:
125+ """三方标杆(远端 GPU server 执行)。属性喂 __init__、输入喂 __call__。
126+ 
127+ 参数名与 proto REG_OP 注册名逐字一致(labels/predictions/weights/num_classes/dtype)。
128+ 实现与 _compute 同为 torch.scatter_add 拼接(本算子即竞品拼接型,无更高层 API)。
129+ 浮点输出 cast 回 NPU 输出 dtype(防 ratio 失真)。
130+ """
131+ 
132+ def __init__(self, **kwargs):
133+ self.num_classes = _attr(kwargs, "num_classes", 0)
134+ self.num_classes = _normalize(self.num_classes)
135+ self.dtype = _normalize(kwargs.get("dtype", "float32"))
136+ self.out_dtype = _DTYPE_MAP.get(self.dtype, torch.float32)
137+ 
138+ def __call__(self, labels, predictions, weights, **kwargs):
139+ nc = self.num_classes
140+ flat_index = labels.to(torch.int64) * nc + predictions.to(torch.int64)
141+ compute_dtype = self.out_dtype
142+ if compute_dtype in (torch.int8, torch.uint8):
143+ compute_dtype = torch.int32
144+ y_flat = torch.zeros(nc * nc, dtype=compute_dtype, device=labels.device)
145+ if weights is not None and weights.numel() > 0:
146+ y_flat.scatter_add_(0, flat_index, weights.to(compute_dtype))
147+ else:
148+ y_flat.scatter_add_(
149+ 0,
150+ flat_index,
151+ torch.ones(
152+ flat_index.shape[0], dtype=compute_dtype, device=labels.device
153+ ),
154+ )
155+ if compute_dtype != self.out_dtype:
156+ y_flat = y_flat.to(self.out_dtype)
157+ return [y_flat.view(nc, nc)]
158+ 
159+ 
160+class ConfusionMatrixKernelSpec:
161+ """kernel + geir 共用。golden 收 numpy.ndarray,返 numpy.ndarray。
162+ 参数名照 op_host/confusion_matrix_def.cpp(labels/predictions/weights + num_classes/dtype)。
163+ """
164+ 
165+ def golden(*inputs, **kwargs):
166+ t = [
167+ torch.from_numpy(np.ascontiguousarray(a)) if a is not None else None
168+ for a in inputs
169+ ]
170+ outs = _compute(*t, **kwargs)
171+ od = kwargs.get("output_dtypes") or []
172+ od = [d[0] if isinstance(d, (list, tuple)) else str(d) for d in od]
173+ return [
174+ o.numpy().astype(od[i]) if i < len(od) else o.numpy()
175+ for i, o in enumerate(outs)
176+ ]
177+ 
178+ third_party = {"torch": _Compose}
179+ tolerance = _TOL
180+ 
181+ 
182+# 【不存在】aclnn 通路:Ascend910B/910C built-in 无 aclnn 源码 → 对齐该支持面,本算子不交付 aclnn。
183+# 【不存在】e2e 通路:torch_npu 无本算子绑定。无 aclnn 源码 → 无编译产物 → torch_npu 无可
184+# 调用入口;验证环境 torch_npu dispatcher 全表 grep "confusion" 无命中。
@@ -0,0 +1,13 @@
1+testcase_name,network_name,op_name,input_shapes,input_dtypes,input_formats,output_shapes,output_dtypes,output_formats,input_ori_shapes,input_ori_formats,output_ori_shapes,output_ori_formats,attributes,input_data_ranges,precision_tolerances,absolute_precision,output_inplace_indexes,output_shape_unknown_indexes,is_enabled,remark,soc_series,priority,dump_file_prefix,manual_input_binaries,manual_golden_binaries
2+confusion_matrix_000,,confusion_matrix,"[[100], [100], [100]]","['int32','int32','float32']","['ND','ND','ND']","[[5,5]]",['float32'],['ND'],,,,,"{'num_classes':5,'dtype':'float32'}","((0,4),(0,4),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
3+confusion_matrix_001,,confusion_matrix,"[[100], [100], [100]]","['int32','int32','int32']","['ND','ND','ND']","[[5,5]]",['int32'],['ND'],,,,,"{'num_classes':5,'dtype':'int32'}","((0,4),(0,4),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
4+confusion_matrix_002,,confusion_matrix,"[[100], [100], [100]]","['int32','int32','float16']","['ND','ND','ND']","[[5,5]]",['float16'],['ND'],,,,,"{'num_classes':5,'dtype':'float16'}","((0,4),(0,4),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
5+confusion_matrix_003,,confusion_matrix,"[[100], [100], [100]]","['int32','int32','int8']","['ND','ND','ND']","[[5,5]]",['int8'],['ND'],,,,,"{'num_classes':5,'dtype':'int8'}","((0,4),(0,4),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
6+confusion_matrix_004,,confusion_matrix,"[[100], [100], [100]]","['int32','int32','uint8']","['ND','ND','ND']","[[5,5]]",['uint8'],['ND'],,,,,"{'num_classes':5,'dtype':'uint8'}","((0,4),(0,4),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
7+confusion_matrix_005,,confusion_matrix,"[[100], [100], [0]]","['int32','int32','float32']","['ND','ND','ND']","[[10,10]]",['float32'],['ND'],,,,,"{'num_classes':10,'dtype':'float32'}","((0,9),(0,9),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
8+confusion_matrix_006,,confusion_matrix,"[[1000], [1000], [1000]]","['int32','int32','float32']","['ND','ND','ND']","[[10,10]]",['float32'],['ND'],,,,,"{'num_classes':10,'dtype':'float32'}","((0,9),(0,9),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
9+confusion_matrix_007,,confusion_matrix,"[[1], [1], [1]]","['int32','int32','float32']","['ND','ND','ND']","[[5,5]]",['float32'],['ND'],,,,,"{'num_classes':5,'dtype':'float32'}","((0,4),(0,4),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
10+confusion_matrix_008,,confusion_matrix,"[[10000], [10000], [10000]]","['int32','int32','float32']","['ND','ND','ND']","[[100,100]]",['float32'],['ND'],,,,,"{'num_classes':100,'dtype':'float32'}","((0,99),(0,99),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
11+confusion_matrix_009,,confusion_matrix,"[[5000], [5000], [5000]]","['float16','float16','float16']","['ND','ND','ND']","[[50,50]]",['float16'],['ND'],,,,,"{'num_classes':50,'dtype':'float16'}","((0,49),(0,49),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
12+confusion_matrix_010,,confusion_matrix,"[[5000], [5000], [5000]]","['int8','int8','int8']","['ND','ND','ND']","[[50,50]]",['int8'],['ND'],,,,,"{'num_classes':50,'dtype':'int8'}","((0,49),(0,49),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
13+confusion_matrix_011,,confusion_matrix,"[[5000], [5000], [5000]]","['uint8','uint8','uint8']","['ND','ND','ND']","[[50,50]]",['uint8'],['ND'],,,,,"{'num_classes':50,'dtype':'uint8'}","((0,49),(0,49),(0,1))",,1.00E-03,(),(),True,,,0,,(),()
@@ -0,0 +1,211 @@
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 <iostream>
12+#include <gtest/gtest.h>
13+#include "math/confusion_matrix/op_host/arch35/confusion_matrix_tiling.h"
14+#include "tiling_context_faker.h"
15+#include "tiling_case_executor.h"
16+#include "any_value.h"
17+ 
18+using namespace std;
19+ 
20+class ConfusionMatrixTilingTest : public testing::Test {
21+protected:
22+ static void SetUpTestCase() { std::cout << "ConfusionMatrixTilingTest SetUp" << std::endl; }
23+ 
24+ static void TearDownTestCase() { std::cout << "ConfusionMatrixTilingTest TearDown" << std::endl; }
25+};
26+ 
27+static gert::TilingContextPara::OpAttr MakeNumClassesAttr(int64_t numClasses)
28+{
29+ return gert::TilingContextPara::OpAttr("num_classes", Ops::Math::AnyValue::CreateFrom<int64_t>(numClasses));
30+}
31+ 
32+static gert::TilingContextPara::OpAttr MakeDtypeAttr(const std::string& dtype)
33+{
34+ return gert::TilingContextPara::OpAttr("dtype", Ops::Math::AnyValue::CreateFrom<std::string>(dtype));
35+}
36+ 
37+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_float32_with_weights)
38+{
39+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
40+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
41+ {
42+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
43+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
44+ {{{100}, {100}}, ge::DT_FLOAT, ge::FORMAT_ND},
45+ },
46+ {
47+ {{{5, 5}, {5, 5}}, ge::DT_FLOAT, ge::FORMAT_ND},
48+ },
49+ {
50+ MakeNumClassesAttr(5),
51+ MakeDtypeAttr("float32"),
52+ },
53+ &compileInfo);
54+ uint64_t expectTilingKey = 65536;
55+ std::vector<size_t> expectWorkspaces = {16777216};
56+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
57+}
58+ 
59+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_float32_no_weights)
60+{
61+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
62+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
63+ {
64+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
65+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
66+ {{{0}, {0}}, ge::DT_FLOAT, ge::FORMAT_ND},
67+ },
68+ {
69+ {{{5, 5}, {5, 5}}, ge::DT_FLOAT, ge::FORMAT_ND},
70+ },
71+ {
72+ MakeNumClassesAttr(5),
73+ MakeDtypeAttr("float32"),
74+ },
75+ &compileInfo);
76+ uint64_t expectTilingKey = 0;
77+ std::vector<size_t> expectWorkspaces = {16777216};
78+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
79+}
80+ 
81+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_int32_with_weights)
82+{
83+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
84+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
85+ {
86+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
87+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
88+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
89+ },
90+ {
91+ {{{10, 10}, {10, 10}}, ge::DT_INT32, ge::FORMAT_ND},
92+ },
93+ {
94+ MakeNumClassesAttr(10),
95+ MakeDtypeAttr("int32"),
96+ },
97+ &compileInfo);
98+ uint64_t expectTilingKey = 65792;
99+ std::vector<size_t> expectWorkspaces = {16777216};
100+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
101+}
102+ 
103+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_int32_no_weights)
104+{
105+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
106+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
107+ {
108+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
109+ {{{100}, {100}}, ge::DT_INT32, ge::FORMAT_ND},
110+ {{{0}, {0}}, ge::DT_INT32, ge::FORMAT_ND},
111+ },
112+ {
113+ {{{10, 10}, {10, 10}}, ge::DT_INT32, ge::FORMAT_ND},
114+ },
115+ {
116+ MakeNumClassesAttr(10),
117+ MakeDtypeAttr("int32"),
118+ },
119+ &compileInfo);
120+ uint64_t expectTilingKey = 256;
121+ std::vector<size_t> expectWorkspaces = {16777216};
122+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
123+}
124+ 
125+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_float16_with_weights)
126+{
127+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
128+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
129+ {
130+ {{{100}, {100}}, ge::DT_FLOAT16, ge::FORMAT_ND},
131+ {{{100}, {100}}, ge::DT_FLOAT16, ge::FORMAT_ND},
132+ {{{100}, {100}}, ge::DT_FLOAT16, ge::FORMAT_ND},
133+ },
134+ {
135+ {{{5, 5}, {5, 5}}, ge::DT_FLOAT16, ge::FORMAT_ND},
136+ },
137+ {
138+ MakeNumClassesAttr(5),
139+ MakeDtypeAttr("float16"),
140+ },
141+ &compileInfo);
142+ uint64_t expectTilingKey = 66048;
143+ std::vector<size_t> expectWorkspaces = {16777216};
144+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
145+}
146+ 
147+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_int8_no_weights)
148+{
149+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
150+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
151+ {
152+ {{{100}, {100}}, ge::DT_INT8, ge::FORMAT_ND},
153+ {{{100}, {100}}, ge::DT_INT8, ge::FORMAT_ND},
154+ {{{0}, {0}}, ge::DT_INT8, ge::FORMAT_ND},
155+ },
156+ {
157+ {{{10, 10}, {10, 10}}, ge::DT_INT8, ge::FORMAT_ND},
158+ },
159+ {
160+ MakeNumClassesAttr(10),
161+ MakeDtypeAttr("int8"),
162+ },
163+ &compileInfo);
164+ uint64_t expectTilingKey = 771;
165+ std::vector<size_t> expectWorkspaces = {16777216};
166+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
167+}
168+ 
169+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_uint8_with_weights)
170+{
171+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
172+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
173+ {
174+ {{{100}, {100}}, ge::DT_UINT8, ge::FORMAT_ND},
175+ {{{100}, {100}}, ge::DT_UINT8, ge::FORMAT_ND},
176+ {{{100}, {100}}, ge::DT_UINT8, ge::FORMAT_ND},
177+ },
178+ {
179+ {{{10, 10}, {10, 10}}, ge::DT_UINT8, ge::FORMAT_ND},
180+ },
181+ {
182+ MakeNumClassesAttr(10),
183+ MakeDtypeAttr("uint8"),
184+ },
185+ &compileInfo);
186+ uint64_t expectTilingKey = 66563;
187+ std::vector<size_t> expectWorkspaces = {16777216};
188+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
189+}
190+ 
191+TEST_F(ConfusionMatrixTilingTest, confusion_matrix_tiling_large_num_classes)
192+{
193+ optiling::AscendCConfusionMatrixCompileInfo compileInfo = {64, 262144};
194+ gert::TilingContextPara tilingContextPara("ConfusionMatrix",
195+ {
196+ {{{10000}, {10000}}, ge::DT_INT32, ge::FORMAT_ND},
197+ {{{10000}, {10000}}, ge::DT_INT32, ge::FORMAT_ND},
198+ {{{10000}, {10000}}, ge::DT_FLOAT, ge::FORMAT_ND},
199+ },
200+ {
201+ {{{1000, 1000}, {1000, 1000}}, ge::DT_FLOAT, ge::FORMAT_ND},
202+ },
203+ {
204+ MakeNumClassesAttr(1000),
205+ MakeDtypeAttr("float32"),
206+ },
207+ &compileInfo);
208+ uint64_t expectTilingKey = 65538;
209+ std::vector<size_t> expectWorkspaces = {16777216};
210+ ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, expectWorkspaces);
211+}