已合并
新增Mul算子AICPU实现 #4111
liu-wei创建于 7月16日
新增Mul算子AICPU实现 #4111
已合并
共 6 个文件变更+1143-1
| @@ -1273,7 +1273,7 @@ | |||
| 1273 | <td>√</td> | 1273 | <td>√</td> |
| 1274 | <td>√</td> | 1274 | <td>√</td> |
| 1275 | <td>√</td> | 1275 | <td>√</td> |
| 1276 | - <td>AI Core</td> | 1276 | + <td>AI Core/AI CPU</td> |
| 1277 | <td>返回两个张量元素之间的乘积结果组成的新张量。</td> | 1277 | <td>返回两个张量元素之间的乘积结果组成的新张量。</td> |
| 1278 | </tr> | 1278 | </tr> |
| 1279 | <tr> | 1279 | <tr> |
| @@ -0,0 +1,309 @@ | |||
| 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 test_geir_mul.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +namespace ge { | ||
| 44 | +REG_OP(Data).INPUT(x, TensorType::ALL()).OUTPUT(y, TensorType::ALL()).ATTR(index, Int, 0).OP_END_FACTORY_REG(Data) | ||
| 45 | +} // namespace ge | ||
| 46 | + | ||
| 47 | +using namespace ge; | ||
| 48 | +using std::map; | ||
| 49 | +using std::string; | ||
| 50 | +using std::vector; | ||
| 51 | + | ||
| 52 | +string GetTime() | ||
| 53 | +{ | ||
| 54 | + time_t timep; | ||
| 55 | + time(&timep); | ||
| 56 | + char tmp[64]; | ||
| 57 | + strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep)); | ||
| 58 | + return tmp; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +uint32_t GetDataTypeSize(DataType dt) | ||
| 62 | +{ | ||
| 63 | + if (dt == ge::DT_FLOAT) { | ||
| 64 | + return 4; | ||
| 65 | + } else if (dt == ge::DT_FLOAT16) { | ||
| 66 | + return 2; | ||
| 67 | + } else if (dt == ge::DT_DOUBLE) { | ||
| 68 | + return 8; | ||
| 69 | + } else if (dt == ge::DT_COMPLEX64) { | ||
| 70 | + return 8; | ||
| 71 | + } else if (dt == ge::DT_COMPLEX128) { | ||
| 72 | + return 16; | ||
| 73 | + } else if (dt == ge::DT_INT32) { | ||
| 74 | + return 4; | ||
| 75 | + } else if (dt == ge::DT_INT64) { | ||
| 76 | + return 8; | ||
| 77 | + } | ||
| 78 | + return 0; | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +const char* DataTypeToString(DataType dt) | ||
| 82 | +{ | ||
| 83 | + switch (dt) { | ||
| 84 | + case DT_FLOAT: | ||
| 85 | + return "DT_FLOAT"; | ||
| 86 | + case DT_FLOAT16: | ||
| 87 | + return "DT_FLOAT16"; | ||
| 88 | + case DT_DOUBLE: | ||
| 89 | + return "DT_DOUBLE"; | ||
| 90 | + case DT_COMPLEX64: | ||
| 91 | + return "DT_COMPLEX64"; | ||
| 92 | + case DT_COMPLEX128: | ||
| 93 | + return "DT_COMPLEX128"; | ||
| 94 | + case DT_INT32: | ||
| 95 | + return "DT_INT32"; | ||
| 96 | + case DT_INT64: | ||
| 97 | + return "DT_INT64"; | ||
| 98 | + default: | ||
| 99 | + return "DTYPE(unknown)"; | ||
| 100 | + } | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +template <typename T> | ||
| 104 | +int32_t GenTensorData(const vector<int64_t>& shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, | ||
| 105 | + const vector<T>& values) | ||
| 106 | +{ | ||
| 107 | + input_tensor_desc.SetRealDimCnt(shapes.size()); | ||
| 108 | + size_t size = 1; | ||
| 109 | + for (uint32_t i = 0; i < shapes.size(); i++) { | ||
| 110 | + size *= shapes[i]; | ||
| 111 | + } | ||
| 112 | + if (size != values.size()) { | ||
| 113 | + return FAILED; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + size_t data_len = size * sizeof(T); | ||
| 117 | + T* p_data = new (std::nothrow) T[size]; | ||
| 118 | + if (p_data == nullptr) { | ||
| 119 | + return FAILED; | ||
| 120 | + } | ||
| 121 | + for (size_t i = 0; i < size; ++i) { | ||
| 122 | + p_data[i] = values[i]; | ||
| 123 | + } | ||
| 124 | + input_tensor = Tensor(input_tensor_desc, reinterpret_cast<uint8_t*>(p_data), data_len); | ||
| 125 | + delete[] p_data; | ||
| 126 | + return SUCCESS; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +int CreateOppInGraph(DataType input_dtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs, | ||
| 130 | + std::vector<Operator>& outputs, Graph& graph) | ||
| 131 | +{ | ||
| 132 | + Status ret = SUCCESS; | ||
| 133 | + auto mul_op = op::Mul("mul_op"); | ||
| 134 | + | ||
| 135 | + std::vector<int64_t> x1_shape = {2, 3}; | ||
| 136 | + std::vector<int64_t> x2_shape = {2, 3}; | ||
| 137 | + | ||
| 138 | + std::vector<std::complex<double>> x1_data = {{1.0, 0.0}, {2.0, 1.0}, {3.0, 0.0}, | ||
| 139 | + {4.0, -1.0}, {5.0, 0.0}, {6.0, 2.0}}; | ||
| 140 | + std::vector<std::complex<double>> x2_data = {{1.0, 1.0}, {1.0, 0.0}, {2.0, 0.0}, | ||
| 141 | + {1.0, -1.0}, {0.0, 1.0}, {1.0, 1.0}}; | ||
| 142 | + | ||
| 143 | + vector<int64_t> placeholder1_shape = x1_shape; | ||
| 144 | + auto placeholder1 = op::Data("placeholder1").set_attr_index(0); | ||
| 145 | + TensorDesc placeholder1_desc = TensorDesc(ge::Shape(placeholder1_shape), FORMAT_ND, input_dtype); | ||
| 146 | + placeholder1_desc.SetPlacement(ge::kPlacementHost); | ||
| 147 | + placeholder1_desc.SetFormat(FORMAT_ND); | ||
| 148 | + Tensor tensor_placeholder1; | ||
| 149 | + ret = GenTensorData(placeholder1_shape, tensor_placeholder1, placeholder1_desc, x1_data); | ||
| 150 | + if (ret != SUCCESS) { | ||
| 151 | + printf("%s - ERROR - [XIR]: Generate x1 data failed\n", GetTime().c_str()); | ||
| 152 | + return FAILED; | ||
| 153 | + } | ||
| 154 | + placeholder1.update_input_desc_x(placeholder1_desc); | ||
| 155 | + placeholder1.update_output_desc_y(placeholder1_desc); | ||
| 156 | + input.push_back(tensor_placeholder1); | ||
| 157 | + graph.AddOp(placeholder1); | ||
| 158 | + mul_op.set_input_x1(placeholder1); | ||
| 159 | + inputs.push_back(placeholder1); | ||
| 160 | + | ||
| 161 | + vector<int64_t> placeholder2_shape = x2_shape; | ||
| 162 | + auto placeholder2 = op::Data("placeholder2").set_attr_index(1); | ||
| 163 | + TensorDesc placeholder2_desc = TensorDesc(ge::Shape(placeholder2_shape), FORMAT_ND, input_dtype); | ||
| 164 | + placeholder2_desc.SetPlacement(ge::kPlacementHost); | ||
| 165 | + placeholder2_desc.SetFormat(FORMAT_ND); | ||
| 166 | + Tensor tensor_placeholder2; | ||
| 167 | + ret = GenTensorData(placeholder2_shape, tensor_placeholder2, placeholder2_desc, x2_data); | ||
| 168 | + if (ret != SUCCESS) { | ||
| 169 | + printf("%s - ERROR - [XIR]: Generate x2 data failed\n", GetTime().c_str()); | ||
| 170 | + return FAILED; | ||
| 171 | + } | ||
| 172 | + placeholder2.update_input_desc_x(placeholder2_desc); | ||
| 173 | + placeholder2.update_output_desc_y(placeholder2_desc); | ||
| 174 | + input.push_back(tensor_placeholder2); | ||
| 175 | + graph.AddOp(placeholder2); | ||
| 176 | + mul_op.set_input_x2(placeholder2); | ||
| 177 | + inputs.push_back(placeholder2); | ||
| 178 | + | ||
| 179 | + TensorDesc output_desc = TensorDesc(ge::Shape(x1_shape), FORMAT_ND, input_dtype); | ||
| 180 | + output_desc.SetPlacement(ge::kPlacementHost); | ||
| 181 | + output_desc.SetFormat(FORMAT_ND); | ||
| 182 | + mul_op.update_output_desc_y(output_desc); | ||
| 183 | + | ||
| 184 | + outputs.push_back(mul_op); | ||
| 185 | + return SUCCESS; | ||
| 186 | +} | ||
| 187 | + | ||
| 188 | +int main(int argc, char* argv[]) | ||
| 189 | +{ | ||
| 190 | + const char* graph_name = "tc_ge_irrun_test"; | ||
| 191 | + Graph graph(graph_name); | ||
| 192 | + std::vector<ge::Tensor> input; | ||
| 193 | + | ||
| 194 | + printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str()); | ||
| 195 | + std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}}; | ||
| 196 | + Status ret = ge::GEInitialize(global_options); | ||
| 197 | + if (ret != SUCCESS) { | ||
| 198 | + printf("%s - INFO - [XIR]: Initialize ge using ge global options failed.ret = %d\n", GetTime().c_str(), ret); | ||
| 199 | + return FAILED; | ||
| 200 | + } | ||
| 201 | + printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str()); | ||
| 202 | + | ||
| 203 | + std::vector<Operator> inputs{}; | ||
| 204 | + std::vector<Operator> outputs{}; | ||
| 205 | + | ||
| 206 | + if (argc > 1) { | ||
| 207 | + std::cout << argv[1] << std::endl; | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + DataType input_dtype = DT_COMPLEX128; | ||
| 211 | + | ||
| 212 | + ret = CreateOppInGraph(input_dtype, input, inputs, outputs, graph); | ||
| 213 | + if (ret != SUCCESS) { | ||
| 214 | + printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 215 | + GEFinalize(); | ||
| 216 | + return FAILED; | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + if (!inputs.empty() && !outputs.empty()) { | ||
| 220 | + graph.SetInputs(inputs).SetOutputs(outputs); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + std::map<AscendString, AscendString> build_options = {}; | ||
| 224 | + printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str()); | ||
| 225 | + ge::Session* session = new Session(build_options); | ||
| 226 | + if (session == nullptr) { | ||
| 227 | + printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 228 | + GEFinalize(); | ||
| 229 | + return FAILED; | ||
| 230 | + } | ||
| 231 | + printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str()); | ||
| 232 | + printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str()); | ||
| 233 | + | ||
| 234 | + std::map<AscendString, AscendString> graph_options = {}; | ||
| 235 | + uint32_t graph_id = 0; | ||
| 236 | + ret = session->AddGraph(graph_id, graph, graph_options); | ||
| 237 | + if (ret != SUCCESS) { | ||
| 238 | + printf("%s - ERROR - [XIR]: Session add ir compute graph failed\n", GetTime().c_str()); | ||
| 239 | + delete session; | ||
| 240 | + GEFinalize(); | ||
| 241 | + return FAILED; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str()); | ||
| 245 | + printf("%s - INFO - [XIR]: dump graph to txt\n", GetTime().c_str()); | ||
| 246 | + std::string file_path = "./dump"; | ||
| 247 | + aclgrphDumpGraph(graph, file_path.c_str(), file_path.length()); | ||
| 248 | + printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str()); | ||
| 249 | + | ||
| 250 | + std::vector<ge::Tensor> output; | ||
| 251 | + ret = session->RunGraph(graph_id, input, output); | ||
| 252 | + if (ret != SUCCESS) { | ||
| 253 | + printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str()); | ||
| 254 | + delete session; | ||
| 255 | + GEFinalize(); | ||
| 256 | + return FAILED; | ||
| 257 | + } | ||
| 258 | + printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str()); | ||
| 259 | + | ||
| 260 | + if (!output.empty()) { | ||
| 261 | + uint8_t* output_data = output[0].GetData(); | ||
| 262 | + int64_t output_shape_size = output[0].GetTensorDesc().GetShape().GetShapeSize(); | ||
| 263 | + DataType output_dtype = output[0].GetTensorDesc().GetDataType(); | ||
| 264 | + printf("%s - INFO - [XIR]: Output dtype: %s, shape size: %ld\n", GetTime().c_str(), | ||
| 265 | + DataTypeToString(output_dtype), output_shape_size); | ||
| 266 | + std::complex<double>* result = reinterpret_cast<std::complex<double>*>(output_data); | ||
| 267 | + | ||
| 268 | + std::complex<double> x1_vals[6] = {{1.0, 0.0}, {2.0, 1.0}, {3.0, 0.0}, {4.0, -1.0}, {5.0, 0.0}, {6.0, 2.0}}; | ||
| 269 | + std::complex<double> x2_vals[6] = {{1.0, 1.0}, {1.0, 0.0}, {2.0, 0.0}, {1.0, -1.0}, {0.0, 1.0}, {1.0, 1.0}}; | ||
| 270 | + bool match = true; | ||
| 271 | + for (int64_t i = 0; i < output_shape_size; ++i) { | ||
| 272 | + std::complex<double> expected = x1_vals[i] * x2_vals[i]; | ||
| 273 | + printf("result[%ld] = (%.6f, %.6f), expected = (%.6f, %.6f)\n", i, result[i].real(), result[i].imag(), | ||
| 274 | + expected.real(), expected.imag()); | ||
| 275 | + if (std::abs(result[i] - expected) > 1e-6) { | ||
| 276 | + printf("MISMATCH at[%ld]\n", i); | ||
| 277 | + match = false; | ||
| 278 | + } | ||
| 279 | + } | ||
| 280 | + if (match) { | ||
| 281 | + printf("%s - INFO - [XIR]: Output verification PASSED\n", GetTime().c_str()); | ||
| 282 | + } else { | ||
| 283 | + printf("%s - ERROR - [XIR]: Output verification FAILED\n", GetTime().c_str()); | ||
| 284 | + } | ||
| 285 | + } | ||
| 286 | + | ||
| 287 | + delete session; | ||
| 288 | + | ||
| 289 | + printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str()); | ||
| 290 | + ret = ge::GEFinalize(); | ||
| 291 | + if (ret != SUCCESS) { | ||
| 292 | + printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str()); | ||
| 293 | + return FAILED; | ||
| 294 | + } | ||
| 295 | + printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str()); | ||
| 296 | + | ||
| 297 | + ge::AscendString err_msg_asc = ge::GEGetErrorMsgV2(); | ||
| 298 | + std::string err_msg = err_msg_asc.GetString(); | ||
| 299 | + if (!err_msg.empty()) { | ||
| 300 | + printf("Error message: %s\n", err_msg.c_str()); | ||
| 301 | + } | ||
| 302 | + ge::AscendString warn_msg_asc = ge::GEGetWarningMsgV2(); | ||
| 303 | + std::string warn_msg = warn_msg_asc.GetString(); | ||
| 304 | + if (!warn_msg.empty()) { | ||
| 305 | + printf("Warning message: %s\n", warn_msg.c_str()); | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + return SUCCESS; | ||
| 309 | +} | ||
| @@ -0,0 +1,487 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace { | ||
| 22 | +const char* const kMul = "Mul"; | ||
| 23 | +constexpr uint32_t kInputNum = 2; | ||
| 24 | +constexpr uint32_t kOutputNum = 1; | ||
| 25 | +constexpr int64_t kParallelDataNum = 6 * 1024; | ||
| 26 | +constexpr int64_t kParallelDataNumMid = 33 * 1024; | ||
| 27 | +constexpr int64_t kParallelDataNumSameShape = 7 * 1024; | ||
| 28 | +} // namespace | ||
| 29 | + | ||
| 30 | +namespace aicpu { | ||
| 31 | +uint32_t MulCpuKernel::MulSameTypeCompute(const CpuKernelContext& ctx) | ||
| 32 | +{ | ||
| 33 | + auto data_type = static_cast<DataType>(ctx.Input(kFirstInputIndex)->GetDataType()); | ||
| 34 | + switch (data_type) { | ||
| 35 | + case DT_FLOAT16: | ||
| 36 | + return MulCompute<Eigen::half>(ctx); | ||
| 37 | + case DT_BFLOAT16: | ||
| 38 | + return MulCompute<Eigen::bfloat16>(ctx); | ||
| 39 | + case DT_FLOAT: | ||
| 40 | + return MulCompute<float>(ctx); | ||
| 41 | + case DT_DOUBLE: | ||
| 42 | + return MulCompute<double>(ctx); | ||
| 43 | + case DT_INT8: | ||
| 44 | + return MulCompute<int8_t>(ctx); | ||
| 45 | + case DT_INT16: | ||
| 46 | + return MulCompute<int16_t>(ctx); | ||
| 47 | + case DT_INT32: | ||
| 48 | + return MulCompute<int32_t>(ctx); | ||
| 49 | + case DT_INT64: | ||
| 50 | + return MulCompute<int64_t>(ctx); | ||
| 51 | + case DT_UINT8: | ||
| 52 | + return MulCompute<uint8_t>(ctx); | ||
| 53 | + case DT_UINT16: | ||
| 54 | + return MulCompute<uint16_t>(ctx); | ||
| 55 | + case DT_UINT32: | ||
| 56 | + return MulCompute<uint32_t>(ctx); | ||
| 57 | + case DT_UINT64: | ||
| 58 | + return MulCompute<uint64_t>(ctx); | ||
| 59 | + case DT_COMPLEX64: | ||
| 60 | + return MulCompute<std::complex<float>>(ctx); | ||
| 61 | + case DT_COMPLEX128: | ||
| 62 | + return MulCompute<std::complex<double>>(ctx); | ||
| 63 | + default: | ||
| 64 | + KERNEL_LOG_ERROR("[%s] Data type of input is not support, input data type is [%s].", | ||
| 65 | + ctx.GetOpType().c_str(), DTypeStr(data_type).c_str()); | ||
| 66 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 67 | + } | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +template <typename T> | ||
| 71 | +uint32_t MulCpuKernel::MulCompute(const CpuKernelContext& ctx) | ||
| 72 | +{ | ||
| 73 | + BCalcInfo calc_info; | ||
| 74 | + calc_info.input_0 = ctx.Input(kFirstInputIndex); | ||
| 75 | + calc_info.input_1 = ctx.Input(kSecondInputIndex); | ||
| 76 | + calc_info.output = ctx.Output(kFirstOutputIndex); | ||
| 77 | + KERNEL_CHECK_NULLPTR(calc_info.input_0->GetData(), KERNEL_STATUS_PARAM_INVALID, "[%s] Get input 0 data failed", | ||
| 78 | + ctx.GetOpType().c_str()) | ||
| 79 | + KERNEL_CHECK_NULLPTR(calc_info.input_1->GetData(), KERNEL_STATUS_PARAM_INVALID, "[%s] Get input 1 data failed", | ||
| 80 | + ctx.GetOpType().c_str()) | ||
| 81 | + KERNEL_CHECK_NULLPTR(calc_info.output->GetData(), KERNEL_STATUS_PARAM_INVALID, "[%s] Get output data failed", | ||
| 82 | + ctx.GetOpType().c_str()) | ||
| 83 | + KERNEL_LOG_INFO("[%s] Input[0] data size is [%lu], input[1] data size is [%lu], output data size is [%lu].", | ||
| 84 | + ctx.GetOpType().c_str(), calc_info.input_0->GetDataSize(), calc_info.input_1->GetDataSize(), | ||
| 85 | + calc_info.output->GetDataSize()); | ||
| 86 | + | ||
| 87 | + Bcast bcast; | ||
| 88 | + if (bcast.GenerateBcastInfo(calc_info) != KERNEL_STATUS_OK) { | ||
| 89 | + KERNEL_LOG_ERROR("[%s] Generate broadcast info failed.", ctx.GetOpType().c_str()); | ||
| 90 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 91 | + } | ||
| 92 | + bcast.GetBcastVec(calc_info); | ||
| 93 | + return MulDispatch<T>(calc_info); | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +template <typename T> | ||
| 97 | +uint32_t MulCpuKernel::MulDispatch(BCalcInfo& calc_info) | ||
| 98 | +{ | ||
| 99 | + int32_t rank = static_cast<int32_t>(calc_info.shape_out.size()); | ||
| 100 | + switch (rank) { | ||
| 101 | + case 0: { | ||
| 102 | + T v0 = *(reinterpret_cast<const T*>(calc_info.input_0->GetData())); | ||
| 103 | + T v1 = *(reinterpret_cast<const T*>(calc_info.input_1->GetData())); | ||
| 104 | + T* value_out = reinterpret_cast<T*>(calc_info.output->GetData()); | ||
| 105 | + *(value_out) = v0 * v1; | ||
| 106 | + return KERNEL_STATUS_OK; | ||
| 107 | + } | ||
| 108 | + case kRank1: | ||
| 109 | + return MulCalculateWithAlignedCheck<kRank1, T>(calc_info); | ||
| 110 | + case kRank2: | ||
| 111 | + return MulCalculateWithAlignedCheck<kRank2, T>(calc_info); | ||
| 112 | + case kRank3: | ||
| 113 | + return MulCalculateWithAlignedCheck<kRank3, T>(calc_info); | ||
| 114 | + case kRank4: | ||
| 115 | + return MulCalculateWithAlignedCheck<kRank4, T>(calc_info); | ||
| 116 | + case kRank5: | ||
| 117 | + return MulCalculateWithAlignedCheck<kRank5, T>(calc_info); | ||
| 118 | + case kRank6: | ||
| 119 | + return MulCalculateWithAlignedCheck<kRank6, T>(calc_info); | ||
| 120 | + case kRank7: | ||
| 121 | + return MulCalculateWithAlignedCheck<kRank7, T>(calc_info); | ||
| 122 | + case kRank8: | ||
| 123 | + return MulCalculateWithAlignedCheck<kRank8, T>(calc_info); | ||
| 124 | + default: | ||
| 125 | + KERNEL_LOG_ERROR("Rank of output should less than 8 but get [%zu].", calc_info.shape_out.size()); | ||
| 126 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 127 | + } | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +template <int32_t RANK, typename T> | ||
| 131 | +uint32_t MulCpuKernel::MulCalculateWithAlignedCheck(BCalcInfo& calc_info) | ||
| 132 | +{ | ||
| 133 | + if (AlignedCheck(calc_info)) { | ||
| 134 | + return MulCalculate<RANK, T, Eigen::Aligned>(calc_info); | ||
| 135 | + } | ||
| 136 | + return MulCalculate<RANK, T, Eigen::Unaligned>(calc_info); | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +bool MulCpuKernel::AlignedCheck(const BCalcInfo& calc_info) const | ||
| 140 | +{ | ||
| 141 | + return AddrAlignedCheck(calc_info.input_0->GetData()) && AddrAlignedCheck(calc_info.input_1->GetData()) && | ||
| 142 | + AddrAlignedCheck(calc_info.output->GetData()); | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +template <int32_t RANK, typename T, int32_t OPTION> | ||
| 146 | +uint32_t MulCpuKernel::MulCalculate(BCalcInfo& calc_info) | ||
| 147 | +{ | ||
| 148 | + Eigen::TensorMap<Eigen::Tensor<T, 1>, OPTION> input0(static_cast<T*>(calc_info.input_0->GetData()), | ||
| 149 | + calc_info.input_0->GetTensorShape()->NumElements()); | ||
| 150 | + Eigen::TensorMap<Eigen::Tensor<T, 1>, OPTION> input1(static_cast<T*>(calc_info.input_1->GetData()), | ||
| 151 | + calc_info.input_1->GetTensorShape()->NumElements()); | ||
| 152 | + Eigen::TensorMap<Eigen::Tensor<T, 1>, OPTION> output(static_cast<T*>(calc_info.output->GetData()), | ||
| 153 | + calc_info.output->GetTensorShape()->NumElements()); | ||
| 154 | + auto input_shape_0 = calc_info.input_0->GetTensorShape()->GetDimSizes(); | ||
| 155 | + auto input_shape_1 = calc_info.input_1->GetTensorShape()->GetDimSizes(); | ||
| 156 | + if (input_shape_0.empty()) { | ||
| 157 | + T v0 = *(reinterpret_cast<const T*>(calc_info.input_0->GetData())); | ||
| 158 | + output = v0 * input1; | ||
| 159 | + return KERNEL_STATUS_OK; | ||
| 160 | + } | ||
| 161 | + if (input_shape_1.empty()) { | ||
| 162 | + T v1 = *(reinterpret_cast<const T*>(calc_info.input_1->GetData())); | ||
| 163 | + output = input0 * v1; | ||
| 164 | + return KERNEL_STATUS_OK; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + Eigen::DSizes<Eigen::DenseIndex, RANK> reshape_0; | ||
| 168 | + Eigen::DSizes<Eigen::DenseIndex, RANK> reshape_1; | ||
| 169 | + Eigen::DSizes<Eigen::DenseIndex, RANK> shape_out; | ||
| 170 | + Eigen::array<Eigen::DenseIndex, RANK> bcast_0; | ||
| 171 | + Eigen::array<Eigen::DenseIndex, RANK> bcast_1; | ||
| 172 | + for (int32_t i = 0; i < RANK; i++) { | ||
| 173 | + reshape_0[(RANK - i) - 1] = calc_info.reshape_0[i]; | ||
| 174 | + reshape_1[(RANK - i) - 1] = calc_info.reshape_1[i]; | ||
| 175 | + shape_out[(RANK - i) - 1] = calc_info.shape_out[i]; | ||
| 176 | + bcast_0[(RANK - i) - 1] = calc_info.bcast_0[i]; | ||
| 177 | + bcast_1[(RANK - i) - 1] = calc_info.bcast_1[i]; | ||
| 178 | + } | ||
| 179 | + if (input_shape_0 == input_shape_1) { | ||
| 180 | + output.reshape(shape_out) = input0.reshape(reshape_0) * input1.reshape(reshape_1); | ||
| 181 | + } else { | ||
| 182 | + output.reshape(shape_out) = input0.reshape(reshape_0).broadcast(bcast_0) * | ||
| 183 | + input1.reshape(reshape_1).broadcast(bcast_1); | ||
| 184 | + } | ||
| 185 | + return KERNEL_STATUS_OK; | ||
| 186 | +} | ||
| 187 | + | ||
| 188 | +int64_t GetMulParallelCoreNum(const CpuKernelContext& ctx, int64_t data_num) | ||
| 189 | +{ | ||
| 190 | + uint32_t min_core_num = 1; | ||
| 191 | + int64_t max_core_num = std::max(static_cast<int64_t>(min_core_num), | ||
| 192 | + static_cast<int64_t>(aicpu::CpuKernelUtils::GetCPUNum(ctx)) - kResvCpuNum); | ||
| 193 | + if (data_num <= kParallelDataNumMid) { | ||
| 194 | + max_core_num = std::min(max_core_num, static_cast<int64_t>(4)); | ||
| 195 | + } | ||
| 196 | + if (max_core_num > data_num) { | ||
| 197 | + max_core_num = data_num; | ||
| 198 | + } | ||
| 199 | + if (max_core_num < 1) { | ||
| 200 | + max_core_num = 1; | ||
| 201 | + } | ||
| 202 | + return max_core_num; | ||
| 203 | +} | ||
| 204 | + | ||
| 205 | +template <typename TIn1, typename TIn2, typename TOut> | ||
| 206 | +typename std::enable_if<std::is_same<TIn1, TOut>::value, void>::type inline MulImpl(TIn1 a, TIn2 b, TOut& output) | ||
| 207 | +{ | ||
| 208 | + output = a * static_cast<TIn1>(b); | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +template <typename TIn1, typename TIn2, typename TOut> | ||
| 212 | +typename std::enable_if<std::is_same<TIn2, TOut>::value, void>::type inline MulImpl(TIn1 a, TIn2 b, TOut& output) | ||
| 213 | +{ | ||
| 214 | + output = static_cast<TIn2>(a) * b; | ||
| 215 | +} | ||
| 216 | + | ||
| 217 | +template <typename TIn1, typename TIn2, typename TOut> | ||
| 218 | +typename std::enable_if<!std::is_same<TIn1, TOut>::value && !std::is_same<TIn2, TOut>::value, | ||
| 219 | + void>::type inline MulImpl(TIn1 a, TIn2 b, TOut& output) | ||
| 220 | +{ | ||
| 221 | + output = static_cast<TOut>(a) * static_cast<TOut>(b); | ||
| 222 | +} | ||
| 223 | + | ||
| 224 | +template <typename TIn1, typename TIn2, typename TOut> | ||
| 225 | +uint32_t BcastCompute(const CpuKernelContext& ctx, const Bcast& bcast) | ||
| 226 | +{ | ||
| 227 | + auto in0 = reinterpret_cast<TIn1*>(ctx.Input(0)->GetData()); | ||
| 228 | + auto in1 = reinterpret_cast<TIn2*>(ctx.Input(1)->GetData()); | ||
| 229 | + auto out = reinterpret_cast<TOut*>(ctx.Output(0)->GetData()); | ||
| 230 | + int64_t data_num = ctx.Output(0)->NumElements(); | ||
| 231 | + if (data_num >= kParallelDataNum) { | ||
| 232 | + int64_t max_core_num = GetMulParallelCoreNum(ctx, data_num); | ||
| 233 | + if (max_core_num == 0) { | ||
| 234 | + KERNEL_LOG_ERROR("Mul max_core_num is zero, division by zero."); | ||
| 235 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 236 | + } | ||
| 237 | + auto sharder_mul = [&](int64_t start, int64_t end) { | ||
| 238 | + for (int64_t i = start; i < end; ++i) { | ||
| 239 | + MulImpl(*(in0 + bcast.GetBroadcastXIndex(i)), *(in1 + bcast.GetBroadcastYIndex(i)), *(out + i)); | ||
| 240 | + } | ||
| 241 | + }; | ||
| 242 | + KERNEL_HANDLE_ERROR(CpuKernelUtils::ParallelFor(ctx, data_num, data_num / max_core_num, sharder_mul), | ||
| 243 | + "Mul Compute failed.") | ||
| 244 | + } else { | ||
| 245 | + for (int64_t i = 0; i < data_num; ++i) { | ||
| 246 | + MulImpl(*(in0 + bcast.GetBroadcastXIndex(i)), *(in1 + bcast.GetBroadcastYIndex(i)), *(out + i)); | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + return KERNEL_STATUS_OK; | ||
| 250 | +} | ||
| 251 | + | ||
| 252 | +template <typename TIn1, typename TIn2, typename TOut> | ||
| 253 | +void SpecialCompute(BcastShapeType type, int64_t start, int64_t end, CpuKernelContext& ctx) | ||
| 254 | +{ | ||
| 255 | + auto in1 = reinterpret_cast<TIn1*>(ctx.Input(0)->GetData()); | ||
| 256 | + auto in2 = reinterpret_cast<TIn2*>(ctx.Input(1)->GetData()); | ||
| 257 | + auto output = reinterpret_cast<TOut*>(ctx.Output(0)->GetData()); | ||
| 258 | + switch (type) { | ||
| 259 | + case BcastShapeType::SAME_SHAPE: | ||
| 260 | + for (int64_t i = start; i < end; ++i) { | ||
| 261 | + MulImpl(*(in1 + i), *(in2 + i), *(output + i)); | ||
| 262 | + } | ||
| 263 | + break; | ||
| 264 | + case BcastShapeType::X_ONE_ELEMENT: | ||
| 265 | + for (int64_t i = start; i < end; ++i) { | ||
| 266 | + MulImpl(*in1, *(in2 + i), *(output + i)); | ||
| 267 | + } | ||
| 268 | + break; | ||
| 269 | + case BcastShapeType::Y_ONE_ELEMENT: | ||
| 270 | + for (int64_t i = start; i < end; ++i) { | ||
| 271 | + MulImpl(*(in1 + i), *in2, *(output + i)); | ||
| 272 | + } | ||
| 273 | + break; | ||
| 274 | + default: | ||
| 275 | + KERNEL_LOG_WARN("Invalid type [%d]", static_cast<int32_t>(type)); | ||
| 276 | + break; | ||
| 277 | + } | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | +template <typename TIn1, typename TIn2, typename TOut> | ||
| 281 | +uint32_t NoBcastCompute(CpuKernelContext& ctx) | ||
| 282 | +{ | ||
| 283 | + int64_t element_num_in0 = ctx.Input(0)->NumElements(); | ||
| 284 | + int64_t element_num_in1 = ctx.Input(1)->NumElements(); | ||
| 285 | + int64_t data_num = ctx.Output(0)->NumElements(); | ||
| 286 | + BcastShapeType type = (element_num_in0 == element_num_in1 ? | ||
| 287 | + BcastShapeType::SAME_SHAPE : | ||
| 288 | + (element_num_in0 == 1 ? BcastShapeType::X_ONE_ELEMENT : BcastShapeType::Y_ONE_ELEMENT)); | ||
| 289 | + if (data_num >= kParallelDataNumSameShape) { | ||
| 290 | + int64_t max_core_num = GetMulParallelCoreNum(ctx, data_num); | ||
| 291 | + if (max_core_num == 0) { | ||
| 292 | + KERNEL_LOG_ERROR("Mul max_core_num is zero, division by zero."); | ||
| 293 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 294 | + } | ||
| 295 | + auto sharder_mul = [&](int64_t start, int64_t end) { SpecialCompute<TIn1, TIn2, TOut>(type, start, end, ctx); }; | ||
| 296 | + KERNEL_HANDLE_ERROR(CpuKernelUtils::ParallelFor(ctx, data_num, data_num / max_core_num, sharder_mul), | ||
| 297 | + "Mul Compute failed.") | ||
| 298 | + } else { | ||
| 299 | + SpecialCompute<TIn1, TIn2, TOut>(type, 0, data_num, ctx); | ||
| 300 | + } | ||
| 301 | + return KERNEL_STATUS_OK; | ||
| 302 | +} | ||
| 303 | + | ||
| 304 | +template <typename TIn1, typename TIn2, typename TOut> | ||
| 305 | +uint32_t MulDiffTypeCompute(CpuKernelContext& ctx) | ||
| 306 | +{ | ||
| 307 | + Tensor* tensor_in0 = ctx.Input(0); | ||
| 308 | + auto shape_in0 = tensor_in0->GetTensorShape()->GetDimSizes(); | ||
| 309 | + Tensor* tensor_in1 = ctx.Input(1); | ||
| 310 | + auto shape_in1 = tensor_in1->GetTensorShape()->GetDimSizes(); | ||
| 311 | + | ||
| 312 | + bool no_need_bcast = (shape_in0 == shape_in1) || (tensor_in0->NumElements() == 1) || | ||
| 313 | + (tensor_in1->NumElements() == 1); | ||
| 314 | + if (no_need_bcast) { | ||
| 315 | + return NoBcastCompute<TIn1, TIn2, TOut>(ctx); | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + Bcast bcast(shape_in0, shape_in1); | ||
| 319 | + if (!bcast.IsValid()) { | ||
| 320 | + KERNEL_LOG_ERROR("[%s] broadcast failed.", ctx.GetOpType().c_str()); | ||
| 321 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 322 | + } | ||
| 323 | + return BcastCompute<TIn1, TIn2, TOut>(ctx, bcast); | ||
| 324 | +} | ||
| 325 | + | ||
| 326 | +static const std::unordered_map<int32_t, std::unordered_map<int32_t, std::function<uint32_t(CpuKernelContext&)>>>& | ||
| 327 | +GetMulDiffTypeCalls() | ||
| 328 | +{ | ||
| 329 | + static const std::unordered_map<int32_t, std::unordered_map<int32_t, std::function<uint32_t(CpuKernelContext&)>>> | ||
| 330 | + kcalls = { | ||
| 331 | + {DT_UINT8, | ||
| 332 | + {{DT_INT8, MulDiffTypeCompute<uint8_t, int8_t, int16_t>}, | ||
| 333 | + {DT_INT16, MulDiffTypeCompute<uint8_t, int16_t, int16_t>}, | ||
| 334 | + {DT_INT32, MulDiffTypeCompute<uint8_t, int32_t, int32_t>}, | ||
| 335 | + {DT_INT64, MulDiffTypeCompute<uint8_t, int64_t, int64_t>}, | ||
| 336 | + {DT_BFLOAT16, MulDiffTypeCompute<uint8_t, Eigen::bfloat16, Eigen::bfloat16>}, | ||
| 337 | + {DT_FLOAT16, MulDiffTypeCompute<uint8_t, Eigen::half, Eigen::half>}, | ||
| 338 | + {DT_FLOAT, MulDiffTypeCompute<uint8_t, float, float>}, | ||
| 339 | + {DT_DOUBLE, MulDiffTypeCompute<uint8_t, double, double>}, | ||
| 340 | + {DT_COMPLEX64, MulDiffTypeCompute<uint8_t, std::complex<float>, std::complex<float>>}, | ||
| 341 | + {DT_COMPLEX128, MulDiffTypeCompute<uint8_t, std::complex<double>, std::complex<double>>}}}, | ||
| 342 | + {DT_INT8, | ||
| 343 | + {{DT_INT16, MulDiffTypeCompute<int8_t, int16_t, int16_t>}, | ||
| 344 | + {DT_INT32, MulDiffTypeCompute<int8_t, int32_t, int32_t>}, | ||
| 345 | + {DT_INT64, MulDiffTypeCompute<int8_t, int64_t, int64_t>}, | ||
| 346 | + {DT_BFLOAT16, MulDiffTypeCompute<int8_t, Eigen::bfloat16, Eigen::bfloat16>}, | ||
| 347 | + {DT_FLOAT16, MulDiffTypeCompute<int8_t, Eigen::half, Eigen::half>}, | ||
| 348 | + {DT_FLOAT, MulDiffTypeCompute<int8_t, float, float>}, | ||
| 349 | + {DT_DOUBLE, MulDiffTypeCompute<int8_t, double, double>}, | ||
| 350 | + {DT_UINT8, MulDiffTypeCompute<int8_t, uint8_t, int16_t>}, | ||
| 351 | + {DT_COMPLEX64, MulDiffTypeCompute<int8_t, std::complex<float>, std::complex<float>>}, | ||
| 352 | + {DT_COMPLEX128, MulDiffTypeCompute<int8_t, std::complex<double>, std::complex<double>>}}}, | ||
| 353 | + {DT_INT16, | ||
| 354 | + {{DT_INT8, MulDiffTypeCompute<int16_t, int8_t, int16_t>}, | ||
| 355 | + {DT_INT32, MulDiffTypeCompute<int16_t, int32_t, int32_t>}, | ||
| 356 | + {DT_INT64, MulDiffTypeCompute<int16_t, int64_t, int64_t>}, | ||
| 357 | + {DT_BFLOAT16, MulDiffTypeCompute<int16_t, Eigen::bfloat16, Eigen::bfloat16>}, | ||
| 358 | + {DT_FLOAT16, MulDiffTypeCompute<int16_t, Eigen::half, Eigen::half>}, | ||
| 359 | + {DT_FLOAT, MulDiffTypeCompute<int16_t, float, float>}, | ||
| 360 | + {DT_DOUBLE, MulDiffTypeCompute<int16_t, double, double>}, | ||
| 361 | + {DT_UINT8, MulDiffTypeCompute<int16_t, uint8_t, int16_t>}, | ||
| 362 | + {DT_COMPLEX64, MulDiffTypeCompute<int16_t, std::complex<float>, std::complex<float>>}, | ||
| 363 | + {DT_COMPLEX128, MulDiffTypeCompute<int16_t, std::complex<double>, std::complex<double>>}}}, | ||
| 364 | + {DT_INT32, | ||
| 365 | + {{DT_INT8, MulDiffTypeCompute<int32_t, int8_t, int32_t>}, | ||
| 366 | + {DT_INT16, MulDiffTypeCompute<int32_t, int16_t, int32_t>}, | ||
| 367 | + {DT_INT64, MulDiffTypeCompute<int32_t, int64_t, int64_t>}, | ||
| 368 | + {DT_BFLOAT16, MulDiffTypeCompute<int32_t, Eigen::bfloat16, Eigen::bfloat16>}, | ||
| 369 | + {DT_FLOAT16, MulDiffTypeCompute<int32_t, Eigen::half, Eigen::half>}, | ||
| 370 | + {DT_FLOAT, MulDiffTypeCompute<int32_t, float, float>}, | ||
| 371 | + {DT_DOUBLE, MulDiffTypeCompute<int32_t, double, double>}, | ||
| 372 | + {DT_UINT8, MulDiffTypeCompute<int32_t, uint8_t, int32_t>}, | ||
| 373 | + {DT_COMPLEX64, MulDiffTypeCompute<int32_t, std::complex<float>, std::complex<float>>}, | ||
| 374 | + {DT_COMPLEX128, MulDiffTypeCompute<int32_t, std::complex<double>, std::complex<double>>}}}, | ||
| 375 | + {DT_INT64, | ||
| 376 | + {{DT_INT8, MulDiffTypeCompute<int64_t, int8_t, int64_t>}, | ||
| 377 | + {DT_INT16, MulDiffTypeCompute<int64_t, int16_t, int64_t>}, | ||
| 378 | + {DT_INT32, MulDiffTypeCompute<int64_t, int32_t, int64_t>}, | ||
| 379 | + {DT_BFLOAT16, MulDiffTypeCompute<int64_t, Eigen::bfloat16, Eigen::bfloat16>}, | ||
| 380 | + {DT_FLOAT16, MulDiffTypeCompute<int64_t, Eigen::half, Eigen::half>}, | ||
| 381 | + {DT_FLOAT, MulDiffTypeCompute<int64_t, float, float>}, | ||
| 382 | + {DT_DOUBLE, MulDiffTypeCompute<int64_t, double, double>}, | ||
| 383 | + {DT_UINT8, MulDiffTypeCompute<int64_t, uint8_t, int64_t>}, | ||
| 384 | + {DT_COMPLEX64, MulDiffTypeCompute<int64_t, std::complex<float>, std::complex<float>>}, | ||
| 385 | + {DT_COMPLEX128, MulDiffTypeCompute<int64_t, std::complex<double>, std::complex<double>>}}}, | ||
| 386 | + {DT_BFLOAT16, | ||
| 387 | + {{DT_INT8, MulDiffTypeCompute<Eigen::bfloat16, int8_t, Eigen::bfloat16>}, | ||
| 388 | + {DT_INT16, MulDiffTypeCompute<Eigen::bfloat16, int16_t, Eigen::bfloat16>}, | ||
| 389 | + {DT_INT32, MulDiffTypeCompute<Eigen::bfloat16, int32_t, Eigen::bfloat16>}, | ||
| 390 | + {DT_INT64, MulDiffTypeCompute<Eigen::bfloat16, int64_t, Eigen::bfloat16>}, | ||
| 391 | + {DT_FLOAT16, MulDiffTypeCompute<Eigen::bfloat16, Eigen::half, float>}, | ||
| 392 | + {DT_FLOAT, MulDiffTypeCompute<Eigen::bfloat16, float, float>}, | ||
| 393 | + {DT_DOUBLE, MulDiffTypeCompute<Eigen::bfloat16, double, double>}, | ||
| 394 | + {DT_UINT8, MulDiffTypeCompute<Eigen::bfloat16, uint8_t, Eigen::bfloat16>}, | ||
| 395 | + {DT_COMPLEX64, MulDiffTypeCompute<Eigen::bfloat16, std::complex<float>, std::complex<float>>}, | ||
| 396 | + {DT_COMPLEX128, MulDiffTypeCompute<Eigen::bfloat16, std::complex<double>, std::complex<double>>}}}, | ||
| 397 | + {DT_FLOAT16, | ||
| 398 | + {{DT_INT8, MulDiffTypeCompute<Eigen::half, int8_t, Eigen::half>}, | ||
| 399 | + {DT_INT16, MulDiffTypeCompute<Eigen::half, int16_t, Eigen::half>}, | ||
| 400 | + {DT_INT32, MulDiffTypeCompute<Eigen::half, int32_t, Eigen::half>}, | ||
| 401 | + {DT_INT64, MulDiffTypeCompute<Eigen::half, int64_t, Eigen::half>}, | ||
| 402 | + {DT_FLOAT, MulDiffTypeCompute<Eigen::half, float, float>}, | ||
| 403 | + {DT_BFLOAT16, MulDiffTypeCompute<Eigen::half, Eigen::bfloat16, float>}, | ||
| 404 | + {DT_DOUBLE, MulDiffTypeCompute<Eigen::half, double, double>}, | ||
| 405 | + {DT_UINT8, MulDiffTypeCompute<Eigen::half, uint8_t, Eigen::half>}, | ||
| 406 | + {DT_COMPLEX64, MulDiffTypeCompute<Eigen::half, std::complex<float>, std::complex<float>>}, | ||
| 407 | + {DT_COMPLEX128, MulDiffTypeCompute<Eigen::half, std::complex<double>, std::complex<double>>}}}, | ||
| 408 | + {DT_FLOAT, | ||
| 409 | + {{DT_INT8, MulDiffTypeCompute<float, int8_t, float>}, | ||
| 410 | + {DT_INT16, MulDiffTypeCompute<float, int16_t, float>}, | ||
| 411 | + {DT_INT32, MulDiffTypeCompute<float, int32_t, float>}, | ||
| 412 | + {DT_INT64, MulDiffTypeCompute<float, int64_t, float>}, | ||
| 413 | + {DT_BFLOAT16, MulDiffTypeCompute<float, Eigen::bfloat16, float>}, | ||
| 414 | + {DT_FLOAT16, MulDiffTypeCompute<float, Eigen::half, float>}, | ||
| 415 | + {DT_DOUBLE, MulDiffTypeCompute<float, double, double>}, | ||
| 416 | + {DT_UINT8, MulDiffTypeCompute<float, uint8_t, float>}, | ||
| 417 | + {DT_COMPLEX64, MulDiffTypeCompute<float, std::complex<float>, std::complex<float>>}, | ||
| 418 | + {DT_COMPLEX128, MulDiffTypeCompute<float, std::complex<double>, std::complex<double>>}}}, | ||
| 419 | + {DT_DOUBLE, | ||
| 420 | + {{DT_INT8, MulDiffTypeCompute<double, int8_t, double>}, | ||
| 421 | + {DT_INT16, MulDiffTypeCompute<double, int16_t, double>}, | ||
| 422 | + {DT_INT32, MulDiffTypeCompute<double, int32_t, double>}, | ||
| 423 | + {DT_INT64, MulDiffTypeCompute<double, int64_t, double>}, | ||
| 424 | + {DT_BFLOAT16, MulDiffTypeCompute<double, Eigen::bfloat16, double>}, | ||
| 425 | + {DT_FLOAT16, MulDiffTypeCompute<double, Eigen::half, double>}, | ||
| 426 | + {DT_FLOAT, MulDiffTypeCompute<double, float, double>}, | ||
| 427 | + {DT_UINT8, MulDiffTypeCompute<double, uint8_t, double>}, | ||
| 428 | + {DT_COMPLEX64, MulDiffTypeCompute<double, std::complex<float>, std::complex<double>>}, | ||
| 429 | + {DT_COMPLEX128, MulDiffTypeCompute<double, std::complex<double>, std::complex<double>>}}}, | ||
| 430 | + {DT_COMPLEX64, | ||
| 431 | + {{DT_INT8, MulDiffTypeCompute<std::complex<float>, int8_t, std::complex<float>>}, | ||
| 432 | + {DT_INT16, MulDiffTypeCompute<std::complex<float>, int16_t, std::complex<float>>}, | ||
| 433 | + {DT_INT32, MulDiffTypeCompute<std::complex<float>, int32_t, std::complex<float>>}, | ||
| 434 | + {DT_INT64, MulDiffTypeCompute<std::complex<float>, int64_t, std::complex<float>>}, | ||
| 435 | + {DT_BFLOAT16, MulDiffTypeCompute<std::complex<float>, Eigen::bfloat16, std::complex<float>>}, | ||
| 436 | + {DT_FLOAT16, MulDiffTypeCompute<std::complex<float>, Eigen::half, std::complex<float>>}, | ||
| 437 | + {DT_FLOAT, MulDiffTypeCompute<std::complex<float>, float, std::complex<float>>}, | ||
| 438 | + {DT_DOUBLE, MulDiffTypeCompute<std::complex<float>, double, std::complex<double>>}, | ||
| 439 | + {DT_UINT8, MulDiffTypeCompute<std::complex<float>, uint8_t, std::complex<float>>}, | ||
| 440 | + {DT_COMPLEX128, MulDiffTypeCompute<std::complex<float>, std::complex<double>, std::complex<double>>}}}, | ||
| 441 | + {DT_COMPLEX128, | ||
| 442 | + {{DT_INT8, MulDiffTypeCompute<std::complex<double>, int8_t, std::complex<double>>}, | ||
| 443 | + {DT_INT16, MulDiffTypeCompute<std::complex<double>, int16_t, std::complex<double>>}, | ||
| 444 | + {DT_INT32, MulDiffTypeCompute<std::complex<double>, int32_t, std::complex<double>>}, | ||
| 445 | + {DT_INT64, MulDiffTypeCompute<std::complex<double>, int64_t, std::complex<double>>}, | ||
| 446 | + {DT_BFLOAT16, MulDiffTypeCompute<std::complex<double>, Eigen::bfloat16, std::complex<double>>}, | ||
| 447 | + {DT_FLOAT16, MulDiffTypeCompute<std::complex<double>, Eigen::half, std::complex<double>>}, | ||
| 448 | + {DT_FLOAT, MulDiffTypeCompute<std::complex<double>, float, std::complex<double>>}, | ||
| 449 | + {DT_DOUBLE, MulDiffTypeCompute<std::complex<double>, double, std::complex<double>>}, | ||
| 450 | + {DT_UINT8, MulDiffTypeCompute<std::complex<double>, uint8_t, std::complex<double>>}, | ||
| 451 | + {DT_COMPLEX64, MulDiffTypeCompute<std::complex<double>, std::complex<float>, std::complex<double>>}}}}; | ||
| 452 | + return kcalls; | ||
| 453 | +} | ||
| 454 | + | ||
| 455 | +uint32_t MulCpuKernel::Compute(CpuKernelContext& ctx) | ||
| 456 | +{ | ||
| 457 | + if (NormalCheck(ctx, kInputNum, kOutputNum) != KERNEL_STATUS_OK) { | ||
| 458 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 459 | + } | ||
| 460 | + Tensor* input0 = ctx.Input(kFirstInputIndex); | ||
| 461 | + Tensor* input1 = ctx.Input(kSecondInputIndex); | ||
| 462 | + if ((input0->GetDataSize() == 0) || (input1->GetDataSize() == 0)) { | ||
| 463 | + KERNEL_LOG_INFO("[%s] Input is empty tensor.", ctx.GetOpType().c_str()); | ||
| 464 | + return KERNEL_STATUS_OK; | ||
| 465 | + } | ||
| 466 | + | ||
| 467 | + auto dtype_in1 = ctx.Input(kFirstInputIndex)->GetDataType(); | ||
| 468 | + auto dtype_in2 = ctx.Input(kSecondInputIndex)->GetDataType(); | ||
| 469 | + auto dtype_out = ctx.Output(kFirstOutputIndex)->GetDataType(); | ||
| 470 | + KERNEL_LOG_DEBUG("Mul kernel get input1 dtype[%s], input2 dtype[%s], output dtype[%s].", | ||
| 471 | + DTypeStr(dtype_in1).c_str(), DTypeStr(dtype_in2).c_str(), DTypeStr(dtype_out).c_str()); | ||
| 472 | + if (dtype_in1 == dtype_in2) { | ||
| 473 | + return MulSameTypeCompute(ctx); | ||
| 474 | + } | ||
| 475 | + | ||
| 476 | + const auto& func_map = GetMulDiffTypeCalls().find(dtype_in1); | ||
| 477 | + if (func_map != GetMulDiffTypeCalls().end()) { | ||
| 478 | + const auto& funcs = func_map->second.find(dtype_in2); | ||
| 479 | + if (funcs != func_map->second.end()) { | ||
| 480 | + return (funcs->second)(ctx); | ||
| 481 | + } | ||
| 482 | + } | ||
| 483 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 484 | +} | ||
| 485 | + | ||
| 486 | +REGISTER_CPU_KERNEL(kMul, MulCpuKernel); | ||
| 487 | +} // namespace aicpu | ||
| @@ -0,0 +1,46 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace aicpu { | ||
| 21 | +class MulCpuKernel : public CpuKernel { | ||
| 22 | +public: | ||
| 23 | + MulCpuKernel() = default; | ||
| 24 | + ~MulCpuKernel() override = default; | ||
| 25 | + uint32_t Compute(CpuKernelContext& ctx) override; | ||
| 26 | + | ||
| 27 | +private: | ||
| 28 | + template <typename T> | ||
| 29 | + uint32_t MulCompute(const CpuKernelContext& ctx); | ||
| 30 | + | ||
| 31 | + template <typename T> | ||
| 32 | + uint32_t MulDispatch(BCalcInfo& calc_info); | ||
| 33 | + | ||
| 34 | + bool AlignedCheck(const BCalcInfo& calc_info) const; | ||
| 35 | + | ||
| 36 | + template <int32_t RANK, typename T> | ||
| 37 | + uint32_t MulCalculateWithAlignedCheck(BCalcInfo& calc_info); | ||
| 38 | + | ||
| 39 | + template <int32_t RANK, typename T, int32_t OPTION> | ||
| 40 | + uint32_t MulCalculate(BCalcInfo& calc_info); | ||
| 41 | + | ||
| 42 | + uint32_t MulSameTypeCompute(const CpuKernelContext& ctx); | ||
| 43 | +}; | ||
| 44 | +} // namespace aicpu | ||
| 45 | + | ||
| 46 | + | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +namespace ops { | ||
| 15 | +class Mul : public OpDef { | ||
| 16 | +public: | ||
| 17 | + explicit Mul(const char* name) : OpDef(name) | ||
| 18 | + { | ||
| 19 | + const std::vector<ge::DataType> data_types = {ge::DT_INT8, ge::DT_INT16, ge::DT_UINT16, ge::DT_UINT8, | ||
| 20 | + ge::DT_INT32, ge::DT_INT64, ge::DT_UINT32, ge::DT_UINT64, | ||
| 21 | + ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16, ge::DT_DOUBLE, | ||
| 22 | + ge::DT_COMPLEX64, ge::DT_COMPLEX128}; | ||
| 23 | + this->Input("x1").ParamType(REQUIRED).DataType(data_types); | ||
| 24 | + this->Input("x2").ParamType(REQUIRED).DataType(data_types); | ||
| 25 | + this->Output("y").ParamType(REQUIRED).DataType(data_types); | ||
| 26 | + | ||
| 27 | + ApplyMathAicpuDefaultCfg(*this); | ||
| 28 | + this->AICPU().ExtendCfgInfo(OP_INFO_OPS_FLAG.c_str(), OPEN_OPS_FLAG.c_str()); | ||
| 29 | + } | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +OP_ADD(Mul); | ||
| 33 | +} // namespace ops | ||
| @@ -0,0 +1,267 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +using namespace std; | ||
| 29 | +using namespace aicpu; | ||
| 30 | + | ||
| 31 | +class TEST_MUL_AICPU_UT : public testing::Test {}; | ||
| 32 | + | ||
| 33 | +auto CreateMulNodeDef(const vector<vector<int64_t>>& shapes, const vector<DataType>& data_types, | ||
| 34 | + const vector<void*>& datas) -> decltype(CpuKernelUtils::CreateNodeDef()) | ||
| 35 | +{ | ||
| 36 | + auto node_def = CpuKernelUtils::CreateNodeDef(); | ||
| 37 | + NodeDefBuilder(node_def.get(), "Mul", "Mul") | ||
| 38 | + .Input({"x1", data_types[0], shapes[0], datas[0]}) | ||
| 39 | + .Input({"x2", data_types[1], shapes[1], datas[1]}) | ||
| 40 | + .Output({"y", data_types[2], shapes[2], datas[2]}); | ||
| 41 | + return node_def; | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +template <typename T> | ||
| 45 | +void RunMulKernel(const vector<vector<int64_t>>& shapes, const vector<DataType>& data_types, const vector<T>& input1, | ||
| 46 | + const vector<T>& input2, const vector<T>& expect_output, uint32_t expect_status = KERNEL_STATUS_OK) | ||
| 47 | +{ | ||
| 48 | + auto calc_size = [](const vector<int64_t>& shape) -> uint64_t { | ||
| 49 | + return shape.empty() ? 1 : accumulate(shape.begin(), shape.end(), 1LL, multiplies<int64_t>()); | ||
| 50 | + }; | ||
| 51 | + | ||
| 52 | + const uint64_t in0_size = calc_size(shapes[0]); | ||
| 53 | + const uint64_t in1_size = calc_size(shapes[1]); | ||
| 54 | + const uint64_t out_size = calc_size(shapes[2]); | ||
| 55 | + | ||
| 56 | + auto x1_data = make_unique<T[]>(in0_size); | ||
| 57 | + auto x2_data = make_unique<T[]>(in1_size); | ||
| 58 | + auto output_data = make_unique<T[]>(out_size); | ||
| 59 | + | ||
| 60 | + for (uint64_t i = 0; i < in0_size; ++i) { | ||
| 61 | + x1_data[i] = input1[i]; | ||
| 62 | + } | ||
| 63 | + for (uint64_t i = 0; i < in1_size; ++i) { | ||
| 64 | + x2_data[i] = input2[i]; | ||
| 65 | + } | ||
| 66 | + for (uint64_t i = 0; i < out_size; ++i) { | ||
| 67 | + output_data[i] = T(); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + vector<void*> datas = {static_cast<void*>(x1_data.get()), static_cast<void*>(x2_data.get()), | ||
| 71 | + static_cast<void*>(output_data.get())}; | ||
| 72 | + auto node_def = CreateMulNodeDef(shapes, data_types, datas); | ||
| 73 | + RUN_KERNEL(node_def, HOST, expect_status); | ||
| 74 | + | ||
| 75 | + if (expect_status == KERNEL_STATUS_OK) { | ||
| 76 | + auto expect = make_unique<T[]>(out_size); | ||
| 77 | + for (uint64_t i = 0; i < out_size; ++i) { | ||
| 78 | + expect[i] = expect_output[i]; | ||
| 79 | + } | ||
| 80 | + EXPECT_TRUE(CompareResult(output_data.get(), expect.get(), out_size)); | ||
| 81 | + } | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +TEST_F(TEST_MUL_AICPU_UT, FLOAT_SAME_SHAPE_SUCC) | ||
| 85 | +{ | ||
| 86 | + vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT}; | ||
| 87 | + vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}, {2, 3}}; | ||
| 88 | + vector<float> x1 = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; | ||
| 89 | + vector<float> x2 = {6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f}; | ||
| 90 | + vector<float> expect = {6.0f, 10.0f, 12.0f, 12.0f, 10.0f, 6.0f}; | ||
| 91 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +TEST_F(TEST_MUL_AICPU_UT, INT32_SAME_SHAPE_SUCC) | ||
| 95 | +{ | ||
| 96 | + vector<DataType> data_types = {DT_INT32, DT_INT32, DT_INT32}; | ||
| 97 | + vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}, {2, 3}}; | ||
| 98 | + vector<int32_t> x1 = {1, 2, 3, 4, 5, 6}; | ||
| 99 | + vector<int32_t> x2 = {6, 5, 4, 3, 2, 1}; | ||
| 100 | + vector<int32_t> expect = {6, 10, 12, 12, 10, 6}; | ||
| 101 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +TEST_F(TEST_MUL_AICPU_UT, DOUBLE_SAME_SHAPE_SUCC) | ||
| 105 | +{ | ||
| 106 | + vector<DataType> data_types = {DT_DOUBLE, DT_DOUBLE, DT_DOUBLE}; | ||
| 107 | + vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}, {2, 3}}; | ||
| 108 | + vector<double> x1 = {1.5, 2.5, 3.5, 4.5, 5.5, 6.5}; | ||
| 109 | + vector<double> x2 = {2.0, 2.0, 2.0, 2.0, 2.0, 2.0}; | ||
| 110 | + vector<double> expect = {3.0, 5.0, 7.0, 9.0, 11.0, 13.0}; | ||
| 111 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +TEST_F(TEST_MUL_AICPU_UT, FLOAT16_SAME_SHAPE_SUCC) | ||
| 115 | +{ | ||
| 116 | + vector<DataType> data_types = {DT_FLOAT16, DT_FLOAT16, DT_FLOAT16}; | ||
| 117 | + vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}, {2, 3}}; | ||
| 118 | + vector<Eigen::half> x1 = {Eigen::half(1.0), Eigen::half(2.0), Eigen::half(3.0), | ||
| 119 | + Eigen::half(4.0), Eigen::half(5.0), Eigen::half(6.0)}; | ||
| 120 | + vector<Eigen::half> x2 = {Eigen::half(6.0), Eigen::half(5.0), Eigen::half(4.0), | ||
| 121 | + Eigen::half(3.0), Eigen::half(2.0), Eigen::half(1.0)}; | ||
| 122 | + vector<Eigen::half> expect = {Eigen::half(6.0), Eigen::half(10.0), Eigen::half(12.0), | ||
| 123 | + Eigen::half(12.0), Eigen::half(10.0), Eigen::half(6.0)}; | ||
| 124 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +TEST_F(TEST_MUL_AICPU_UT, COMPLEX64_SAME_SHAPE_SUCC) | ||
| 128 | +{ | ||
| 129 | + vector<DataType> data_types = {DT_COMPLEX64, DT_COMPLEX64, DT_COMPLEX64}; | ||
| 130 | + vector<vector<int64_t>> shapes = {{2}, {2}, {2}}; | ||
| 131 | + vector<complex<float>> x1 = {{1.0f, 2.0f}, {3.0f, 4.0f}}; | ||
| 132 | + vector<complex<float>> x2 = {{5.0f, 6.0f}, {7.0f, 8.0f}}; | ||
| 133 | + vector<complex<float>> expect = {{1.0f * 5.0f - 2.0f * 6.0f, 1.0f * 6.0f + 2.0f * 5.0f}, | ||
| 134 | + {3.0f * 7.0f - 4.0f * 8.0f, 3.0f * 8.0f + 4.0f * 7.0f}}; | ||
| 135 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +TEST_F(TEST_MUL_AICPU_UT, FLOAT_SCALAR_SUCC) | ||
| 139 | +{ | ||
| 140 | + vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT}; | ||
| 141 | + vector<vector<int64_t>> shapes = {{}, {}, {}}; | ||
| 142 | + vector<float> x1 = {3.0f}; | ||
| 143 | + vector<float> x2 = {4.0f}; | ||
| 144 | + vector<float> expect = {12.0f}; | ||
| 145 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +TEST_F(TEST_MUL_AICPU_UT, FLOAT_BROADCAST_X_SCALAR_SUCC) | ||
| 149 | +{ | ||
| 150 | + vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT}; | ||
| 151 | + vector<vector<int64_t>> shapes = {{}, {2, 3}, {2, 3}}; | ||
| 152 | + vector<float> x1 = {3.0f}; | ||
| 153 | + vector<float> x2 = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; | ||
| 154 | + vector<float> expect = {3.0f, 6.0f, 9.0f, 12.0f, 15.0f, 18.0f}; | ||
| 155 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +TEST_F(TEST_MUL_AICPU_UT, FLOAT_BROADCAST_Y_SCALAR_SUCC) | ||
| 159 | +{ | ||
| 160 | + vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT}; | ||
| 161 | + vector<vector<int64_t>> shapes = {{2, 3}, {}, {2, 3}}; | ||
| 162 | + vector<float> x1 = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; | ||
| 163 | + vector<float> x2 = {3.0f}; | ||
| 164 | + vector<float> expect = {3.0f, 6.0f, 9.0f, 12.0f, 15.0f, 18.0f}; | ||
| 165 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | +TEST_F(TEST_MUL_AICPU_UT, FLOAT_BROADCAST_BOTH_SUCC) | ||
| 169 | +{ | ||
| 170 | + vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT}; | ||
| 171 | + vector<vector<int64_t>> shapes = {{1, 2}, {2, 1}, {2, 2}}; | ||
| 172 | + vector<float> x1 = {1.0f, 2.0f}; | ||
| 173 | + vector<float> x2 = {3.0f, 4.0f}; | ||
| 174 | + vector<float> expect = {3.0f, 6.0f, 4.0f, 8.0f}; | ||
| 175 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 176 | +} | ||
| 177 | + | ||
| 178 | +TEST_F(TEST_MUL_AICPU_UT, INT64_LARGE_PARALLEL_SUCC) | ||
| 179 | +{ | ||
| 180 | + vector<DataType> data_types = {DT_INT64, DT_INT64, DT_INT64}; | ||
| 181 | + vector<vector<int64_t>> shapes = {{4, 2048}, {4, 2048}, {4, 2048}}; | ||
| 182 | + vector<int64_t> x1(4 * 2048); | ||
| 183 | + vector<int64_t> x2(4 * 2048); | ||
| 184 | + vector<int64_t> expect(4 * 2048); | ||
| 185 | + for (int i = 0; i < 4 * 2048; ++i) { | ||
| 186 | + x1[i] = static_cast<int64_t>(i % 100); | ||
| 187 | + x2[i] = static_cast<int64_t>(2); | ||
| 188 | + expect[i] = x1[i] * x2[i]; | ||
| 189 | + } | ||
| 190 | + RunMulKernel(shapes, data_types, x1, x2, expect); | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +TEST_F(TEST_MUL_AICPU_UT, DIFF_TYPE_INT8_UINT8_SUCC) | ||
| 194 | +{ | ||
| 195 | + vector<DataType> data_types = {DT_INT8, DT_UINT8, DT_INT16}; | ||
| 196 | + vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}, {2, 3}}; | ||
| 197 | + int8_t x1[6] = {1, 2, 3, -1, -2, -3}; | ||
| 198 | + uint8_t x2[6] = {1, 2, 3, 1, 2, 3}; | ||
| 199 | + int16_t output[6] = {0}; | ||
| 200 | + vector<void*> datas = {static_cast<void*>(x1), static_cast<void*>(x2), static_cast<void*>(output)}; | ||
| 201 | + auto node_def = CreateMulNodeDef(shapes, data_types, datas); | ||
| 202 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK); | ||
| 203 | + int16_t expect[6] = {1, 4, 9, static_cast<int16_t>(-1), static_cast<int16_t>(-4), static_cast<int16_t>(-9)}; | ||
| 204 | + EXPECT_TRUE(CompareResult(output, expect, static_cast<uint64_t>(6))); | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +TEST_F(TEST_MUL_AICPU_UT, DIFF_TYPE_FLOAT_DOUBLE_SUCC) | ||
| 208 | +{ | ||
| 209 | + vector<DataType> data_types = {DT_FLOAT, DT_DOUBLE, DT_DOUBLE}; | ||
| 210 | + vector<vector<int64_t>> shapes = {{2}, {2}, {2}}; | ||
| 211 | + float x1[2] = {1.5f, 2.5f}; | ||
| 212 | + double x2[2] = {2.0, 4.0}; | ||
| 213 | + double output[2] = {0.0}; | ||
| 214 | + vector<void*> datas = {static_cast<void*>(x1), static_cast<void*>(x2), static_cast<void*>(output)}; | ||
| 215 | + auto node_def = CreateMulNodeDef(shapes, data_types, datas); | ||
| 216 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK); | ||
| 217 | + double expect[2] = {3.0, 10.0}; | ||
| 218 | + EXPECT_TRUE(CompareResult(output, expect, static_cast<uint64_t>(2))); | ||
| 219 | +} | ||
| 220 | + | ||
| 221 | +TEST_F(TEST_MUL_AICPU_UT, DIFF_TYPE_UINT8_INT32_SUCC) | ||
| 222 | +{ | ||
| 223 | + vector<DataType> data_types = {DT_UINT8, DT_INT32, DT_INT32}; | ||
| 224 | + vector<vector<int64_t>> shapes = {{4}, {4}, {4}}; | ||
| 225 | + uint8_t x1[4] = {0, 100, 200, 255}; | ||
| 226 | + int32_t x2[4] = {3, 3, 3, 3}; | ||
| 227 | + int32_t output[4] = {0}; | ||
| 228 | + vector<void*> datas = {static_cast<void*>(x1), static_cast<void*>(x2), static_cast<void*>(output)}; | ||
| 229 | + auto node_def = CreateMulNodeDef(shapes, data_types, datas); | ||
| 230 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK); | ||
| 231 | + int32_t expect[4] = {0, 300, 600, 765}; | ||
| 232 | + EXPECT_TRUE(CompareResult(output, expect, static_cast<uint64_t>(4))); | ||
| 233 | +} | ||
| 234 | + | ||
| 235 | +TEST_F(TEST_MUL_AICPU_UT, INPUT_DTYPE_UNSUPPORT) | ||
| 236 | +{ | ||
| 237 | + vector<DataType> data_types = {DT_BOOL, DT_BOOL, DT_BOOL}; | ||
| 238 | + vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}, {2, 3}}; | ||
| 239 | + bool x1[6] = {true}; | ||
| 240 | + bool x2[6] = {true}; | ||
| 241 | + bool output[6] = {false}; | ||
| 242 | + vector<void*> datas = {static_cast<void*>(x1), static_cast<void*>(x2), static_cast<void*>(output)}; | ||
| 243 | + auto node_def = CreateMulNodeDef(shapes, data_types, datas); | ||
| 244 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID); | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +TEST_F(TEST_MUL_AICPU_UT, BCAST_SHAPE_MISMATCH) | ||
| 248 | +{ | ||
| 249 | + vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT}; | ||
| 250 | + vector<vector<int64_t>> shapes = {{1, 3}, {1, 2}, {1, 3}}; | ||
| 251 | + float x1[3] = {1.0f, 2.0f, 3.0f}; | ||
| 252 | + float x2[2] = {4.0f, 5.0f}; | ||
| 253 | + float output[3] = {0.0f}; | ||
| 254 | + vector<void*> datas = {static_cast<void*>(x1), static_cast<void*>(x2), static_cast<void*>(output)}; | ||
| 255 | + auto node_def = CreateMulNodeDef(shapes, data_types, datas); | ||
| 256 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID); | ||
| 257 | +} | ||
| 258 | + | ||
| 259 | +TEST_F(TEST_MUL_AICPU_UT, INPUT_NULL_EXCEPTION) | ||
| 260 | +{ | ||
| 261 | + vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT}; | ||
| 262 | + vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}, {2, 3}}; | ||
| 263 | + float output[6] = {0.0f}; | ||
| 264 | + vector<void*> datas = {static_cast<void*>(nullptr), static_cast<void*>(nullptr), static_cast<void*>(output)}; | ||
| 265 | + auto node_def = CreateMulNodeDef(shapes, data_types, datas); | ||
| 266 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID); | ||
| 267 | +} | ||