已合并
[CANNBot]950新增softplusv2grad ascendc实现 #7046
Hana77创建于 7月6日
[CANNBot]950新增softplusv2grad ascendc实现 #7046
已合并
共 28 个文件变更+2757-30
| @@ -1,18 +1,21 @@ | |||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 1 | # ---------------------------------------------------------------------------- |
| 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 2 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. |
| 3 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | #/ | 9 | # ---------------------------------------------------------------------------- |
| 9 | message(STATUS "=== Debug: start ops.activation.softplus_v2_grad.CMakeLists.txt ") | 10 | # Generated By CANNBot |
| 10 | file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | 11 | |
| 11 | if(NOT ENABLE_TEST AND NOT BENCHMARK) | 12 | set(SUPPORT_COMPUTE_UNIT "ascend950") |
| 12 | list(REMOVE_ITEM CURRENT_DIRS tests) | 13 | set(SUPPORT_TILING_DIR "arch35") |
| 13 | endif() | 14 | |
| 14 | foreach(SUB_DIR ${CURRENT_DIRS}) | 15 | add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE |
| 15 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | 16 | DIR ${CMAKE_CURRENT_SOURCE_DIR} |
| 16 | add_subdirectory(${SUB_DIR}) | 17 | OPTYPE softplus_v2_grad |
| 17 | endif() | 18 | ACLNNTYPE aclnn_exclude |
| 18 | endforeach() | 19 | COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} |
| 20 | TILING_DIR ${SUPPORT_TILING_DIR} | ||
| 21 | ) | ||
| @@ -0,0 +1,277 @@ | |||
| 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 | /* Generated By CANNBot */ | ||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | |||
| 28 | |||
| 29 | |||
| 30 | |||
| 31 | |||
| 32 | |||
| 33 | |||
| 34 | |||
| 35 | |||
| 36 | using namespace ge; | ||
| 37 | using std::map; | ||
| 38 | using std::string; | ||
| 39 | using std::vector; | ||
| 40 | |||
| 41 | vector<int64_t> placeholder##intputIndex##_shape = inputShape; \ | ||
| 42 | auto placeholder##intputIndex = op::Data("placeholder" + intputIndex).set_attr_index(0); \ | ||
| 43 | TensorDesc placeholder##intputIndex##_desc = TensorDesc(ge::Shape(placeholder##intputIndex##_shape), FORMAT_ND, \ | ||
| 44 | intputDtype); \ | ||
| 45 | placeholder##intputIndex##_desc.SetPlacement(ge::kPlacementHost); \ | ||
| 46 | placeholder##intputIndex##_desc.SetFormat(FORMAT_ND); \ | ||
| 47 | Tensor tensor_placeholder##intputIndex; \ | ||
| 48 | ret = GenOnesDataFloat32(placeholder##intputIndex##_shape, tensor_placeholder##intputIndex, \ | ||
| 49 | placeholder##intputIndex##_desc, 2); \ | ||
| 50 | if (ret != SUCCESS) { \ | ||
| 51 | printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str()); \ | ||
| 52 | return FAILED; \ | ||
| 53 | } \ | ||
| 54 | placeholder##intputIndex.update_input_desc_x(placeholder##intputIndex##_desc); \ | ||
| 55 | placeholder##intputIndex.update_output_desc_y(placeholder##intputIndex##_desc); \ | ||
| 56 | input.push_back(tensor_placeholder##intputIndex); \ | ||
| 57 | graph.AddOp(placeholder##intputIndex); \ | ||
| 58 | softplusV2Grad1.set_input_##intputName(placeholder##intputIndex); \ | ||
| 59 | inputs.push_back(placeholder##intputIndex); | ||
| 60 | |||
| 61 | |||
| 62 | do { \ | ||
| 63 | printf(message, ##__VA_ARGS__); \ | ||
| 64 | } while (0) | ||
| 65 | |||
| 66 | string GetTime() | ||
| 67 | { | ||
| 68 | time_t timep; | ||
| 69 | time(&timep); | ||
| 70 | char tmp[64]; | ||
| 71 | strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep)); | ||
| 72 | return tmp; | ||
| 73 | } | ||
| 74 | |||
| 75 | uint32_t GetDataTypeSize(DataType dt) | ||
| 76 | { | ||
| 77 | uint32_t dilation = 1; | ||
| 78 | uint32_t oneByte = 1; | ||
| 79 | uint32_t twoByte = 2; | ||
| 80 | uint32_t fourByte = 4; | ||
| 81 | uint32_t eightByte = 8; | ||
| 82 | |||
| 83 | if (dt == ge::DT_FLOAT) { | ||
| 84 | dilation = fourByte; | ||
| 85 | } else if (dt == ge::DT_FLOAT16) { | ||
| 86 | dilation = twoByte; | ||
| 87 | } else if (dt == ge::DT_BF16) { | ||
| 88 | dilation = twoByte; | ||
| 89 | } else if (dt == ge::DT_INT16) { | ||
| 90 | dilation = twoByte; | ||
| 91 | } else if (dt == ge::DT_UINT16) { | ||
| 92 | dilation = twoByte; | ||
| 93 | } else if (dt == ge::DT_INT32) { | ||
| 94 | dilation = fourByte; | ||
| 95 | } else if (dt == ge::DT_UINT32) { | ||
| 96 | dilation = fourByte; | ||
| 97 | } else if (dt == ge::DT_INT64) { | ||
| 98 | dilation = eightByte; | ||
| 99 | } else if (dt == ge::DT_UINT64) { | ||
| 100 | dilation = eightByte; | ||
| 101 | } else if (dt == ge::DT_INT8) { | ||
| 102 | dilation = oneByte; | ||
| 103 | } | ||
| 104 | return dilation; | ||
| 105 | } | ||
| 106 | |||
| 107 | int32_t GenOnesDataFloat32(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, float value) | ||
| 108 | { | ||
| 109 | input_tensor_desc.SetRealDimCnt(shapes.size()); | ||
| 110 | size_t size = 1; | ||
| 111 | for (uint32_t i = 0; i < shapes.size(); i++) { | ||
| 112 | size *= shapes[i]; | ||
| 113 | } | ||
| 114 | uint32_t byteSizeFloat32 = 4; | ||
| 115 | uint32_t data_len = size * byteSizeFloat32; | ||
| 116 | float* pData = new (std::nothrow) float[size]; | ||
| 117 | |||
| 118 | for (size_t i = 0; i < size; ++i) { | ||
| 119 | *(pData + i) = value; | ||
| 120 | } | ||
| 121 | input_tensor = Tensor(input_tensor_desc, (uint8_t*)pData, data_len); | ||
| 122 | return SUCCESS; | ||
| 123 | } | ||
| 124 | |||
| 125 | int32_t GenOnesData(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, DataType data_type, | ||
| 126 | int value) | ||
| 127 | { | ||
| 128 | input_tensor_desc.SetRealDimCnt(shapes.size()); | ||
| 129 | size_t size = 1; | ||
| 130 | for (uint32_t i = 0; i < shapes.size(); i++) { | ||
| 131 | size *= shapes[i]; | ||
| 132 | } | ||
| 133 | uint32_t data_len = size * GetDataTypeSize(data_type); | ||
| 134 | int32_t* pData = new (std::nothrow) int32_t[data_len]; | ||
| 135 | for (uint32_t i = 0; i < size; ++i) { | ||
| 136 | *(pData + i) = value; | ||
| 137 | } | ||
| 138 | input_tensor = Tensor(input_tensor_desc, reinterpret_cast<uint8_t*>(pData), data_len); | ||
| 139 | return SUCCESS; | ||
| 140 | } | ||
| 141 | |||
| 142 | int32_t WriteDataToFile(string bin_file, uint64_t data_size, uint8_t* inputData) | ||
| 143 | { | ||
| 144 | FILE* fp; | ||
| 145 | fp = fopen(bin_file.c_str(), "w"); | ||
| 146 | fwrite(inputData, sizeof(uint8_t), data_size, fp); | ||
| 147 | fclose(fp); | ||
| 148 | return SUCCESS; | ||
| 149 | } | ||
| 150 | |||
| 151 | int CreateOppInGraph(DataType inDtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs, | ||
| 152 | std::vector<Operator>& outputs, Graph& graph) | ||
| 153 | { | ||
| 154 | Status ret = SUCCESS; | ||
| 155 | // 自定义代码:添加单算子定义到图中 | ||
| 156 | auto softplusV2Grad1 = op::SoftplusV2Grad("softplusV2Grad1"); | ||
| 157 | softplusV2Grad1.set_attr_beta(1.0f); | ||
| 158 | softplusV2Grad1.set_attr_threshold(20.0f); | ||
| 159 | std::vector<int64_t> xShape = {4, 2}; | ||
| 160 | ADD_INPUT(1, input_gradients, inDtype, xShape); | ||
| 161 | ADD_INPUT(2, input_features, inDtype, xShape); | ||
| 162 | |||
| 163 | outputs.push_back(softplusV2Grad1); | ||
| 164 | // 添加完毕 | ||
| 165 | return SUCCESS; | ||
| 166 | } | ||
| 167 | |||
| 168 | int main(int argc, char* argv[]) | ||
| 169 | { | ||
| 170 | const char* graph_name = "tc_ge_irrun_test"; | ||
| 171 | Graph graph(graph_name); | ||
| 172 | std::vector<ge::Tensor> input; | ||
| 173 | |||
| 174 | printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str()); | ||
| 175 | std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}}; | ||
| 176 | Status ret = ge::GEInitialize(global_options); | ||
| 177 | if (ret != SUCCESS) { | ||
| 178 | printf("%s - INFO - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str()); | ||
| 179 | return FAILED; | ||
| 180 | } | ||
| 181 | printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str()); | ||
| 182 | |||
| 183 | std::vector<Operator> inputs{}; | ||
| 184 | std::vector<Operator> outputs{}; | ||
| 185 | |||
| 186 | std::cout << argv[1] << std::endl; | ||
| 187 | char* endptr; | ||
| 188 | |||
| 189 | DataType inDtype = DT_FLOAT; | ||
| 190 | |||
| 191 | std::cout << inDtype << std::endl; | ||
| 192 | |||
| 193 | ret = CreateOppInGraph(inDtype, input, inputs, outputs, graph); | ||
| 194 | if (ret != SUCCESS) { | ||
| 195 | printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 196 | return FAILED; | ||
| 197 | } | ||
| 198 | |||
| 199 | if (!inputs.empty() && !outputs.empty()) { | ||
| 200 | graph.SetInputs(inputs).SetOutputs(outputs); | ||
| 201 | } | ||
| 202 | |||
| 203 | std::map<AscendString, AscendString> build_options = { | ||
| 204 | |||
| 205 | }; | ||
| 206 | printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str()); | ||
| 207 | ge::Session* session = new Session(build_options); | ||
| 208 | |||
| 209 | if (session == nullptr) { | ||
| 210 | printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 211 | return FAILED; | ||
| 212 | } | ||
| 213 | printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str()); | ||
| 214 | printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str()); | ||
| 215 | |||
| 216 | std::map<AscendString, AscendString> graph_options = { | ||
| 217 | |||
| 218 | }; | ||
| 219 | uint32_t graph_id = 0; | ||
| 220 | ret = session->AddGraph(graph_id, graph, graph_options); | ||
| 221 | |||
| 222 | printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str()); | ||
| 223 | printf("%s - INFO - [XIR]: dump graph to txt\n", GetTime().c_str()); | ||
| 224 | std::string file_path = "./dump"; | ||
| 225 | aclgrphDumpGraph(graph, file_path.c_str(), file_path.length()); | ||
| 226 | printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str()); | ||
| 227 | std::vector<ge::Tensor> output; | ||
| 228 | ret = session->RunGraph(graph_id, input, output); | ||
| 229 | if (ret != SUCCESS) { | ||
| 230 | printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str()); | ||
| 231 | delete session; | ||
| 232 | GEFinalize(); | ||
| 233 | return FAILED; | ||
| 234 | } | ||
| 235 | printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str()); | ||
| 236 | |||
| 237 | int input_num = input.size(); | ||
| 238 | for (int i = 0; i < input_num; i++) { | ||
| 239 | std::cout << "input " << i << " dtype : " << input[i].GetTensorDesc().GetDataType() << std::endl; | ||
| 240 | string input_file = "./tc_ge_irrun_test_0008_npu_input_" + std::to_string(i) + ".bin"; | ||
| 241 | uint8_t* input_data_i = input[i].GetData(); | ||
| 242 | int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize(); | ||
| 243 | std::cout << "this is " << i << "th input, input shape size =" << input_shape << std::endl; | ||
| 244 | uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType()); | ||
| 245 | WriteDataToFile((const char*)input_file.c_str(), data_size, input_data_i); | ||
| 246 | } | ||
| 247 | |||
| 248 | int output_num = output.size(); | ||
| 249 | for (int i = 0; i < output_num; i++) { | ||
| 250 | std::cout << "output " << i << " dtype : " << output[i].GetTensorDesc().GetDataType() << std::endl; | ||
| 251 | string output_file = "./tc_ge_irrun_test_0008_npu_output_" + std::to_string(i) + ".bin"; | ||
| 252 | uint8_t* output_data_i = output[i].GetData(); | ||
| 253 | int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize(); | ||
| 254 | std::cout << "this is " << i << "th output, output shape size =" << output_shape << std::endl; | ||
| 255 | uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType()); | ||
| 256 | WriteDataToFile((const char*)output_file.c_str(), data_size, output_data_i); | ||
| 257 | float* resultData = (float*)output_data_i; | ||
| 258 | for (int64_t j = 0; j < output_shape; j++) { | ||
| 259 | LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | ge::AscendString error_msg = ge::GEGetErrorMsgV2(); | ||
| 264 | std::string error_str(error_msg.GetString()); | ||
| 265 | std::cout << "Error message: " << error_str << std::endl; | ||
| 266 | ge::AscendString warning_msg = ge::GEGetWarningMsgV2(); | ||
| 267 | std::string warning_str(warning_msg.GetString()); | ||
| 268 | std::cout << "Warning message: " << warning_str << std::endl; | ||
| 269 | printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str()); | ||
| 270 | ret = ge::GEFinalize(); | ||
| 271 | if (ret != SUCCESS) { | ||
| 272 | printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str()); | ||
| 273 | return FAILED; | ||
| 274 | } | ||
| 275 | printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str()); | ||
| 276 | return SUCCESS; | ||
| 277 | } | ||
Ractivation/softplus_v2_grad/op_host/op_api/aclnn_softplus_backward.cpp→activation/softplus_v2_grad/op_api/aclnn_softplus_backward.cpp+6-0
| @@ -48,6 +48,9 @@ static const std::initializer_list<op::DataType> KERNEL_SUPPORT_LIST = { | |||
| 48 | 48 | ||
| 49 | static const std::initializer_list<DataType>& GetDtypeSupportList() | 49 | static const std::initializer_list<DataType>& GetDtypeSupportList() |
| 50 | { | 50 | { |
| 51 | if (Ops::NN::AclnnUtil::IsRegbase()) { | ||
| 52 | return ASCEND910B_DTYPE_SUPPORT_LIST; | ||
| 53 | } | ||
| 51 | if (GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910B || | 54 | if (GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910B || |
| 52 | GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910_93) { | 55 | GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910_93) { |
| 53 | return ASCEND910B_DTYPE_SUPPORT_LIST; | 56 | return ASCEND910B_DTYPE_SUPPORT_LIST; |
| @@ -58,6 +61,9 @@ static const std::initializer_list<DataType>& GetDtypeSupportList() | |||
| 58 | 61 | ||
| 59 | static const std::initializer_list<DataType>& GetSelfDtypeSupportList() | 62 | static const std::initializer_list<DataType>& GetSelfDtypeSupportList() |
| 60 | { | 63 | { |
| 64 | if (Ops::NN::AclnnUtil::IsRegbase()) { | ||
| 65 | return SELF_ASCEND910B_DTYPE_SUPPORT_LIST; | ||
| 66 | } | ||
| 61 | if (GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910B || | 67 | if (GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910B || |
| 62 | GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910_93) { | 68 | GetCurrentPlatformInfo().GetSocVersion() == SocVersion::ASCEND910_93) { |
| 63 | return SELF_ASCEND910B_DTYPE_SUPPORT_LIST; | 69 | return SELF_ASCEND910B_DTYPE_SUPPORT_LIST; |
Ractivation/softplus_v2_grad/op_host/op_api/aclnn_softplus_backward.h→activation/softplus_v2_grad/op_api/aclnn_softplus_backward.h+0-0
文件重命名但无更改。
Ractivation/softplus_v2_grad/op_host/op_api/softplus_v2_grad.cpp→activation/softplus_v2_grad/op_api/softplus_v2_grad.cpp+0-0
文件重命名但无更改。
Ractivation/softplus_v2_grad/op_host/op_api/softplus_v2_grad.h→activation/softplus_v2_grad/op_api/softplus_v2_grad.h+0-0
文件重命名但无更改。
| @@ -0,0 +1,57 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | /*! | ||
| 14 | * \file softplus_v2_grad_proto.h | ||
| 15 | * \brief SoftplusV2Grad 算子图模式 proto 定义 | ||
| 16 | */ | ||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | namespace ge { | ||
| 24 | |||
| 25 | /** | ||
| 26 | * @brief Calculates the reversed outputs of the function "softplus_v2". | ||
| 27 | |||
| 28 | * @par Inputs: | ||
| 29 | * Two inputs, including: | ||
| 30 | * @li input_gradients: A mutable tensor, which supports 1D-8D defaultly. Format support ND. | ||
| 31 | * Must be one of the following types: float16, float32, bfloat16. | ||
| 32 | * @li input_features: A mutable tensor of the same type, shape and format as "input_gradients". | ||
| 33 | |||
| 34 | * @par Attributes: | ||
| 35 | * @li beta: An optional float. Defaults to "1.0". | ||
| 36 | * Control the steepness of the beta function. | ||
| 37 | |||
| 38 | * @li threshold: An optional float. Defaults to "20.0". | ||
| 39 | * Define a function to switch the threshold from nonlinear to linear. | ||
| 40 | |||
| 41 | * @par Outputs: | ||
| 42 | * output_backprops: A mutable tensor of the same type, shape and format as "input_gradients". | ||
| 43 | |||
| 44 | * @par Third-party framework compatibility | ||
| 45 | * Compatible with the Pytorch operator SoftplusGrad. | ||
| 46 | */ | ||
| 47 | |||
| 48 | REG_OP(SoftplusV2Grad) | ||
| 49 | .INPUT(input_gradients, TensorType({DT_FLOAT, DT_FLOAT16, DT_BF16})) | ||
| 50 | .INPUT(input_features, TensorType({DT_FLOAT, DT_FLOAT16, DT_BF16})) | ||
| 51 | .OUTPUT(output_backprops, TensorType({DT_FLOAT, DT_FLOAT16, DT_BF16})) | ||
| 52 | .ATTR(beta, Float, 1.0) | ||
| 53 | .ATTR(threshold, Float, 20.0) | ||
| 54 | .OP_END_FACTORY_REG(SoftplusV2Grad) | ||
| 55 | |||
| 56 | } // namespace ge | ||
| 57 | |||
| @@ -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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | // SoftplusV2Grad Tiling — arch35 头文件 | ||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | // ============================================================ | ||
| 21 | // Tiling 函数模块(无状态,与 CANN 框架零耦合) | ||
| 22 | // 作用域:namespace softplus_v2_grad | ||
| 23 | // ============================================================ | ||
| 24 | |||
| 25 | namespace softplus_v2_grad { | ||
| 26 | |||
| 27 | bool CheckBroadcastShape(const std::vector<std::vector<int64_t>>& padded_in, | ||
| 28 | const std::vector<std::vector<int64_t>>& padded_out, int64_t max_rank); | ||
| 29 | |||
| 30 | bool PadAndSqueeze(const std::vector<std::vector<int64_t>>& input_shapes, | ||
| 31 | const std::vector<std::vector<int64_t>>& output_shapes, std::vector<int64_t>& maximum_bro_shape, | ||
| 32 | std::vector<std::vector<int64_t>>& normal_input_shapes, | ||
| 33 | std::vector<std::vector<int64_t>>& normal_output_shapes); | ||
| 34 | |||
| 35 | bool FindSplitAxis(const std::vector<int64_t>& max_bro_shape, int64_t dtype_size, int64_t ub_per_core, | ||
| 36 | int64_t phys_nodes, SplitResult& out); | ||
| 37 | |||
| 38 | bool MultiCoreSplit(const std::vector<int64_t>& max_bro_shape, const SplitResult& ub_split, int64_t max_cores, | ||
| 39 | MultiCoreResult& out); | ||
| 40 | |||
| 41 | bool PrecomputeStrides(const std::vector<int64_t>& s, std::vector<int64_t>& strides); | ||
| 42 | |||
| 43 | } // namespace softplus_v2_grad | ||
| 44 | |||
| 45 | // ============================================================ | ||
| 46 | // SoftplusV2GradTiling — CANN 主线:单次归一化 → 映射 rank → 模板填充 | ||
| 47 | // ============================================================ | ||
| 48 | namespace optiling { | ||
| 49 | |||
| 50 | struct SoftplusV2GradCompileInfo { | ||
| 51 | uint64_t coreNum; | ||
| 52 | uint64_t ubSize; | ||
| 53 | }; | ||
| 54 | |||
| 55 | class SoftplusV2GradTiling { | ||
| 56 | public: | ||
| 57 | explicit SoftplusV2GradTiling(gert::TilingContext* ctx); | ||
| 58 | ge::graphStatus RunTiling(); | ||
| 59 | |||
| 60 | private: | ||
| 61 | ge::graphStatus GetShapeInfo(); | ||
| 62 | template <int64_t R> | ||
| 63 | ge::graphStatus DoTilingAndSet(); | ||
| 64 | |||
| 65 | gert::TilingContext* ctx_; | ||
| 66 | std::vector<std::vector<int64_t>> raw_input_shapes_; | ||
| 67 | std::vector<std::vector<int64_t>> raw_output_shapes_; | ||
| 68 | std::vector<int64_t> max_bro_shape_; | ||
| 69 | std::vector<std::vector<int64_t>> normal_input_shapes_; | ||
| 70 | std::vector<std::vector<int64_t>> normal_output_shapes_; | ||
| 71 | int64_t dtype_size_ = 0; | ||
| 72 | int64_t rank_ = 0; | ||
| 73 | float beta_ = kDefaultBeta; | ||
| 74 | float threshold_ = kDefaultThreshold; | ||
| 75 | }; | ||
| 76 | |||
| 77 | } // namespace optiling | ||
| @@ -0,0 +1,58 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | /** | ||
| 14 | * SoftplusV2Grad OpDef — 算子注册 (2入1出 + 2属性) | ||
| 15 | */ | ||
| 16 | |||
| 17 | |||
| 18 | namespace ops { | ||
| 19 | class SoftplusV2Grad : public OpDef { | ||
| 20 | public: | ||
| 21 | explicit SoftplusV2Grad(const char* name) : OpDef(name) | ||
| 22 | { | ||
| 23 | this->Input("input_gradients") | ||
| 24 | .ParamType(REQUIRED) | ||
| 25 | .DataType({ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16}) | ||
| 26 | .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 27 | .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 28 | this->Input("input_features") | ||
| 29 | .ParamType(REQUIRED) | ||
| 30 | .DataType({ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16}) | ||
| 31 | .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 32 | .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 33 | this->Output("output_backprops") | ||
| 34 | .ParamType(REQUIRED) | ||
| 35 | .DataType({ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16}) | ||
| 36 | .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 37 | .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 38 | |||
| 39 | // 标量属性(均为 OPTIONAL,有默认值) | ||
| 40 | // 注意:默认值须与 op_kernel/arch35/softplus_v2_grad_tiling_struct.h 中 | ||
| 41 | // kDefaultBeta / kDefaultThreshold 保持一致(tiling 侧的运行期兜底默认)。 | ||
| 42 | this->Attr("beta").AttrType(OPTIONAL).Float(1.0f); | ||
| 43 | this->Attr("threshold").AttrType(OPTIONAL).Float(20.0f); | ||
| 44 | |||
| 45 | OpAICoreConfig aicoreConfig; | ||
| 46 | aicoreConfig.DynamicCompileStaticFlag(true) | ||
| 47 | .DynamicFormatFlag(false) | ||
| 48 | .DynamicRankSupportFlag(true) | ||
| 49 | .DynamicShapeSupportFlag(true) | ||
| 50 | .NeedCheckSupportFlag(false) | ||
| 51 | .PrecisionReduceFlag(true) | ||
| 52 | .ExtendCfgInfo("opFile.value", "softplus_v2_grad"); | ||
| 53 | this->AICore().AddConfig("ascend950", aicoreConfig); | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | |||
| 57 | OP_ADD(SoftplusV2Grad); | ||
| 58 | } // namespace ops | ||
| @@ -0,0 +1,28 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | using namespace Ops::Base; | ||
| 17 | namespace ops { | ||
| 18 | |||
| 19 | static ge::graphStatus InferShape4SoftplusV2Grad(gert::InferShapeContext* context) | ||
| 20 | { | ||
| 21 | // Broadcast: input_gradients + input_features → output output_backprops | ||
| 22 | constexpr size_t kBroadcastInputNum = 2; // input_gradients, input_features | ||
| 23 | return InferShape4Broadcast(context, kBroadcastInputNum); | ||
| 24 | } | ||
| 25 | |||
| 26 | IMPL_OP_INFERSHAPE(SoftplusV2Grad).InferShape(InferShape4SoftplusV2Grad); | ||
| 27 | |||
| 28 | } // namespace ops | ||
| @@ -0,0 +1,17 @@ | |||
| 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 | # Generated By CANNBot | ||
| 12 | |||
| 13 | add_kernel_sources( | ||
| 14 | KERNEL_SRC arch35/softplus_v2_grad.cpp | ||
| 15 | COMPUTE_UNITS ascend950 | ||
| 16 | AUTO_SYNC false | ||
| 17 | ) | ||
| @@ -0,0 +1,44 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | /** | ||
| 13 | * SoftplusV2Grad Kernel 入口 | ||
| 14 | * RANK 来自 TilingKey, DTYPE 来自 CANN 框架 (def 注册的 Input("input_gradients") 类型) | ||
| 15 | */ | ||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | using TilingData4 = SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>; | ||
| 21 | using TilingData8 = SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_8>; | ||
| 22 | |||
| 23 | template <int RANK> | ||
| 24 | __global__ __aicore__ void softplus_v2_grad(GM_ADDR input_gradients, GM_ADDR input_features, GM_ADDR output_backprops, | ||
| 25 | GM_ADDR workspace, GM_ADDR tiling) | ||
| 26 | { | ||
| 27 | GM_ADDR ins[kMaxInputSlots] = {input_gradients, input_features}; | ||
| 28 | GM_ADDR outs[kMaxOutputSlots] = {output_backprops}; | ||
| 29 | |||
| 30 | REGISTER_NONE_TILING; | ||
| 31 | KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); | ||
| 32 | |||
| 33 | if constexpr (RANK == SOFTPLUS_V2_GRAD_RANK_4) { | ||
| 34 | GET_TILING_DATA_WITH_STRUCT(TilingData4, td, tiling); | ||
| 35 | SoftplusV2GradKernel<DTYPE_INPUT_GRADIENTS, SOFTPLUS_V2_GRAD_RANK_4> kernel; | ||
| 36 | kernel.Init(ins, outs, &td); | ||
| 37 | kernel.Process(); | ||
| 38 | } else { | ||
| 39 | GET_TILING_DATA_WITH_STRUCT(TilingData8, td, tiling); | ||
| 40 | SoftplusV2GradKernel<DTYPE_INPUT_GRADIENTS, SOFTPLUS_V2_GRAD_RANK_8> kernel; | ||
| 41 | kernel.Init(ins, outs, &td); | ||
| 42 | kernel.Process(); | ||
| 43 | } | ||
| 44 | } | ||
| @@ -0,0 +1,383 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | /** | ||
| 14 | * SoftplusV2Grad Kernel — SoftplusV2GradKernel<T, RANK> | ||
| 15 | */ | ||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | __aicore__ inline void GetCoreRange(int64_t core_id, int64_t tiles_main, int64_t cores_tail, int64_t& start, | ||
| 22 | int64_t& end) | ||
| 23 | { | ||
| 24 | if (core_id < cores_tail) { | ||
| 25 | start = core_id * (tiles_main + 1); | ||
| 26 | end = start + tiles_main + 1; | ||
| 27 | } else { | ||
| 28 | start = cores_tail * (tiles_main + 1) + (core_id - cores_tail) * tiles_main; | ||
| 29 | end = start + tiles_main; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | __aicore__ inline int64_t GetUBSplitRange(int64_t a_o_off, int64_t a_o, int64_t a_i, int64_t a_i_tail) | ||
| 34 | { | ||
| 35 | return (a_o_off == a_o - 1) ? a_i_tail : a_i; | ||
| 36 | } | ||
| 37 | |||
| 38 | __aicore__ inline bool FlatToEffectiveCoord(int64_t flat, const int64_t* max_bro_shape, int64_t rank, | ||
| 39 | int64_t split_axis, int64_t a_i, int64_t a_o, int64_t* eff_coord) | ||
| 40 | { | ||
| 41 | for (int64_t d = 0; d < rank; d++) | ||
| 42 | eff_coord[d] = 0; | ||
| 43 | a_o = (a_o == 0) ? 1 : a_o; // 除零兜底:a_o 由 host tiling 保证 >=1,此处防御非法 TilingData | ||
| 44 | int64_t a_o_off = flat % a_o; | ||
| 45 | int64_t outer = flat / a_o; | ||
| 46 | for (int64_t d = split_axis - 1; d >= 0; d--) { | ||
| 47 | eff_coord[d] = outer % max_bro_shape[d]; | ||
| 48 | outer /= max_bro_shape[d]; | ||
| 49 | } | ||
| 50 | eff_coord[split_axis] = a_o_off * a_i; | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 54 | // input/output 偏移计算逻辑一致(Σ eff_coord[d]*strides[d]) | ||
| 55 | // 返回元素个数,用作 gmIn_[]/gmOut_[] 的 index | ||
| 56 | __aicore__ inline int64_t CalcOffset(const int64_t* eff_coord, const int64_t* strides, int64_t rank) | ||
| 57 | { | ||
| 58 | int64_t offset = 0; | ||
| 59 | for (int64_t d = 0; d < rank; d++) | ||
| 60 | offset += eff_coord[d] * strides[d]; | ||
| 61 | return offset; | ||
| 62 | } | ||
| 63 | |||
| 64 | // input/output 搬运元素数计算逻辑一致 | ||
| 65 | __aicore__ inline int64_t CalcTransferCount(const int64_t* normal_shape, int64_t rank, int64_t split_axis, | ||
| 66 | int64_t a_i_seg) | ||
| 67 | { | ||
| 68 | int64_t split_elems = (normal_shape[split_axis] == 1) ? 1 : a_i_seg; | ||
| 69 | int64_t inner_elems = 1; | ||
| 70 | for (int64_t d = split_axis + 1; d < rank; d++) | ||
| 71 | inner_elems *= normal_shape[d]; | ||
| 72 | return split_elems * inner_elems; | ||
| 73 | } | ||
| 74 | |||
| 75 | template <typename T> | ||
| 76 | __simd_vf__ inline void SoftplusV2GradVF(__ubuf__ T* dst, __ubuf__ T* src0, __ubuf__ T* src1, uint32_t count, | ||
| 77 | uint32_t VL, uint16_t rep, float beta, float threshold) | ||
| 78 | { | ||
| 79 | // 寄存器声明 | ||
| 80 | AscendC::Reg::RegTensor<T> src0Reg, src1Reg; | ||
| 81 | AscendC::Reg::RegTensor<T> regT1, regT2, regT3, regT4, regT5, dstReg; | ||
| 82 | AscendC::Reg::RegTensor<T> regThresh; | ||
| 83 | AscendC::Reg::MaskReg padMask; | ||
| 84 | AscendC::Reg::MaskReg cmpMask; | ||
| 85 | AscendC::Reg::AddrReg aReg; | ||
| 86 | |||
| 87 | for (uint16_t i = 0; i < rep; i++) { | ||
| 88 | aReg = AscendC::Reg::CreateAddrReg<T>(i, VL); | ||
| 89 | padMask = AscendC::Reg::UpdateMask<T>(count); | ||
| 90 | |||
| 91 | // --- Load: UB → Reg --- | ||
| 92 | AscendC::Reg::LoadAlign(src0Reg, src0, aReg); // 读 input_features | ||
| 93 | AscendC::Reg::LoadAlign(src1Reg, src1, aReg); // 读 input_gradients | ||
| 94 | |||
| 95 | // S1: Mul(beta, input_features) → T1 | ||
| 96 | // T1 = beta * input_features | ||
| 97 | AscendC::Reg::Muls<T>(regT1, src0Reg, beta, padMask); | ||
| 98 | |||
| 99 | // S2: Neg(T1) → T2 | ||
| 100 | AscendC::Reg::Neg<T>(regT2, regT1, padMask); | ||
| 101 | |||
| 102 | // S3: Exp(T2) → T3 | ||
| 103 | AscendC::Reg::Exp<T>(regT3, regT2, padMask); | ||
| 104 | |||
| 105 | // S4: Adds(T3, 1.0f) → T4 | ||
| 106 | AscendC::Reg::Adds<T>(regT4, regT3, static_cast<T>(1.0f), padMask); | ||
| 107 | |||
| 108 | // S5: Div(input_gradients, T4) → T5 | ||
| 109 | AscendC::Reg::Div<T>(regT5, src1Reg, regT4, padMask); | ||
| 110 | |||
| 111 | // S6: Sub(T1, T1) → regZero(零寄存器) | ||
| 112 | AscendC::Reg::Sub<T>(regT2, regT1, regT1, padMask); | ||
| 113 | |||
| 114 | // S7: Adds(regZero, threshold) → regThresh(阈值寄存器) | ||
| 115 | AscendC::Reg::Adds<T>(regThresh, regT2, threshold, padMask); | ||
| 116 | |||
| 117 | // S8: Compare(T1, regThresh, GT) → cmpMask | ||
| 118 | AscendC::Reg::Compare<T, AscendC::CMPMODE::GT>(cmpMask, regT1, regThresh, padMask); | ||
| 119 | |||
| 120 | // S9: Select(cmpMask, input_gradients, T5) → dstReg | ||
| 121 | AscendC::Reg::Select<T>(dstReg, src1Reg, regT5, cmpMask); | ||
| 122 | |||
| 123 | // --- Store: Reg → UB --- | ||
| 124 | AscendC::Reg::StoreAlign(dst, dstReg, aReg, padMask); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | // ============================================================ | ||
| 129 | // SoftplusV2GradKernel — Kernel 类 | ||
| 130 | // 模板参数: T (dtype), RANK (有效 rank) | ||
| 131 | // ============================================================ | ||
| 132 | template <typename T, int64_t RANK> | ||
| 133 | class SoftplusV2GradKernel { | ||
| 134 | // NDDMA 维度数 (最大 kMaxNdDmaDims), RANK 超出时外层走 Flat loop | ||
| 135 | static constexpr int64_t ND = (RANK <= kMaxNdDmaDims) ? RANK : kMaxNdDmaDims; | ||
| 136 | static constexpr uint32_t VL_F = AscendC::GetVecLen() / sizeof(float); | ||
| 137 | |||
| 138 | AscendC::TPipe pipe_; | ||
| 139 | const SoftplusV2GradTilingData<RANK>* td_; | ||
| 140 | AscendC::GlobalTensor<T> gmIn_[kMaxInputSlots]; | ||
| 141 | AscendC::GlobalTensor<T> gmOut_[kMaxOutputSlots]; | ||
| 142 | AscendC::TBuf<AscendC::TPosition::VECCALC> buf_[kPhysNodes]; | ||
| 143 | AscendC::MultiCopyParams<T, ND> nddmaParams_[kMaxInputSlots]; | ||
| 144 | int64_t nddmaOuterIters_[kMaxInputSlots]; | ||
| 145 | int64_t nddma_dims_; | ||
| 146 | float beta_; | ||
| 147 | float threshold_; | ||
| 148 | |||
| 149 | public: | ||
| 150 | __aicore__ inline void Init(GM_ADDR inputs[kMaxInputSlots], GM_ADDR outputs[kMaxOutputSlots], | ||
| 151 | const SoftplusV2GradTilingData<RANK>* td) | ||
| 152 | { | ||
| 153 | td_ = td; | ||
| 154 | for (int i = 0; i < kMaxInputSlots; i++) | ||
| 155 | gmIn_[i].SetGlobalBuffer((__gm__ T*)inputs[i]); | ||
| 156 | for (int i = 0; i < kMaxOutputSlots; i++) | ||
| 157 | gmOut_[i].SetGlobalBuffer((__gm__ T*)outputs[i]); | ||
| 158 | for (int i = 0; i < kPhysNodes; i++) | ||
| 159 | pipe_.InitBuffer(buf_[i], td_->per_buf_bytes); | ||
| 160 | |||
| 161 | // 标量参数从 TilingData 读取 | ||
| 162 | beta_ = td_->beta; | ||
| 163 | threshold_ = td_->threshold; | ||
| 164 | |||
| 165 | // NDDMA 参数预计算 | ||
| 166 | const int64_t* dstShape = td_->max_bro_shape; | ||
| 167 | int64_t k = td_->split.axis; | ||
| 168 | nddma_dims_ = (RANK - k <= ND) ? (RANK - k) : ND; | ||
| 169 | for (int inp = 0; inp < kMaxInputSlots; inp++) { | ||
| 170 | int64_t inner = 1; | ||
| 171 | int64_t nd = 0; | ||
| 172 | for (int64_t d = RANK - 1; d >= k && nd < ND; d--) { | ||
| 173 | nddmaParams_[inp].loopInfo.loopSize[nd] = (d == k) ? 0 : dstShape[d]; | ||
| 174 | nddmaParams_[inp].loopInfo.loopSrcStride[nd] = td_->input_strides[inp][d]; | ||
| 175 | nddmaParams_[inp].loopInfo.loopDstStride[nd] = inner; | ||
| 176 | nddmaParams_[inp].loopInfo.loopLpSize[nd] = 0; | ||
| 177 | nddmaParams_[inp].loopInfo.loopRpSize[nd] = 0; | ||
| 178 | inner *= (d == k) ? td_->split.a_i : dstShape[d]; | ||
| 179 | nd++; | ||
| 180 | } | ||
| 181 | for (; nd < ND; nd++) { | ||
| 182 | nddmaParams_[inp].loopInfo.loopSize[nd] = 1; | ||
| 183 | nddmaParams_[inp].loopInfo.loopSrcStride[nd] = 0; | ||
| 184 | nddmaParams_[inp].loopInfo.loopDstStride[nd] = inner; | ||
| 185 | nddmaParams_[inp].loopInfo.loopLpSize[nd] = 0; | ||
| 186 | nddmaParams_[inp].loopInfo.loopRpSize[nd] = 0; | ||
| 187 | } | ||
| 188 | nddmaOuterIters_[inp] = 1; | ||
| 189 | for (int64_t d = k; d < RANK - nddma_dims_; d++) | ||
| 190 | nddmaOuterIters_[inp] *= (d == k) ? td_->split.a_i : dstShape[d]; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | __aicore__ inline void Process() | ||
| 195 | { | ||
| 196 | int32_t evMTE2toV = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::MTE2_V)); | ||
| 197 | int32_t evVtoMTE2 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE2)); | ||
| 198 | int32_t evVtoMTE3 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE3)); | ||
| 199 | int32_t evMTE3toMTE2 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::MTE3_MTE2)); | ||
| 200 | |||
| 201 | int64_t start, end; | ||
| 202 | GetCoreRange(AscendC::GetBlockIdx(), td_->multicore.tiles_main, td_->multicore.cores_tail, start, end); | ||
| 203 | |||
| 204 | int64_t inner_count = 1; | ||
| 205 | for (int64_t d = td_->split.axis + 1; d < RANK; d++) | ||
| 206 | inner_count *= td_->max_bro_shape[d]; | ||
| 207 | |||
| 208 | int64_t coord[RANK] = {}; | ||
| 209 | |||
| 210 | if constexpr (std::is_same_v<T, float>) { | ||
| 211 | ProcessFP32(start, end, inner_count, coord, evMTE2toV, evVtoMTE3, evMTE3toMTE2); | ||
| 212 | } else { | ||
| 213 | ProcessFP16BF16(start, end, inner_count, coord, evMTE2toV, evVtoMTE2, evVtoMTE3, evMTE3toMTE2); | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | private: | ||
| 218 | // ============================================================ | ||
| 219 | // fp32 Process: P=3, 3 buffer slot, 3 sync pairs | ||
| 220 | // ============================================================ | ||
| 221 | __aicore__ inline void ProcessFP32(int64_t start, int64_t end, int64_t inner_count, int64_t* coord, | ||
| 222 | int32_t evMTE2toV, int32_t evVtoMTE3, int32_t evMTE3toMTE2) | ||
| 223 | { | ||
| 224 | constexpr int UB_GRAD_O = 0, UB_SELF = 1, UB_RESULT = 2; | ||
| 225 | |||
| 226 | for (int64_t flat = start; flat < end; flat++) { | ||
| 227 | int64_t a_i_seg = GetUBSplitRange(flat % td_->split.a_o, td_->split.a_o, td_->split.a_i, | ||
| 228 | td_->split.a_i_tail); | ||
| 229 | int64_t count = a_i_seg * inner_count; | ||
| 230 | FlatToEffectiveCoord(flat, td_->max_bro_shape, RANK, td_->split.axis, td_->split.a_i, td_->split.a_o, | ||
| 231 | coord); | ||
| 232 | |||
| 233 | if (flat != start) | ||
| 234 | AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(evMTE3toMTE2); | ||
| 235 | |||
| 236 | // S1: CopyIn input_gradients → UB_GRAD_O | ||
| 237 | CopyInBrc(coord, 0, UB_GRAD_O, a_i_seg); | ||
| 238 | |||
| 239 | // S2: CopyIn input_features → UB_SELF | ||
| 240 | CopyInBrc(coord, 1, UB_SELF, a_i_seg); | ||
| 241 | |||
| 242 | // MTE2→V sync | ||
| 243 | AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV); | ||
| 244 | AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV); | ||
| 245 | |||
| 246 | // S3: VF(UB_SELF, UB_GRAD_O → UB_RESULT) | ||
| 247 | uint16_t rep = AscendC::CeilDivision(count, VL_F); | ||
| 248 | asc_vf_call<SoftplusV2GradVF<float>>((__ubuf__ float*)buf_[UB_RESULT].Get<float>().GetPhyAddr(), | ||
| 249 | (__ubuf__ float*)buf_[UB_SELF].Get<float>().GetPhyAddr(), | ||
| 250 | (__ubuf__ float*)buf_[UB_GRAD_O].Get<float>().GetPhyAddr(), count, | ||
| 251 | VL_F, rep, beta_, threshold_); | ||
| 252 | |||
| 253 | // V→MTE3 sync | ||
| 254 | AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(evVtoMTE3); | ||
| 255 | AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(evVtoMTE3); | ||
| 256 | |||
| 257 | // S4: CopyOut UB_RESULT → GM | ||
| 258 | CopyOutOne(coord, 0, UB_RESULT, a_i_seg); | ||
| 259 | |||
| 260 | if (flat != end - 1) | ||
| 261 | AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(evMTE3toMTE2); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | // ============================================================ | ||
| 266 | // fp16/bf16 Process: P=4, 4 buffer slot, 4 sync pairs | ||
| 267 | // ============================================================ | ||
| 268 | __aicore__ inline void ProcessFP16BF16(int64_t start, int64_t end, int64_t inner_count, int64_t* coord, | ||
| 269 | int32_t evMTE2toV, int32_t evVtoMTE2, int32_t evVtoMTE3, | ||
| 270 | int32_t evMTE3toMTE2) | ||
| 271 | { | ||
| 272 | constexpr int UB_TEMP = 0; | ||
| 273 | constexpr int UB_SELF_FP32 = 1; | ||
| 274 | constexpr int UB_GRAD_O_FP32 = 2; | ||
| 275 | constexpr int UB_RESULT = 3; | ||
| 276 | |||
| 277 | for (int64_t flat = start; flat < end; flat++) { | ||
| 278 | int64_t a_i_seg = GetUBSplitRange(flat % td_->split.a_o, td_->split.a_o, td_->split.a_i, | ||
| 279 | td_->split.a_i_tail); | ||
| 280 | int64_t count = a_i_seg * inner_count; | ||
| 281 | FlatToEffectiveCoord(flat, td_->max_bro_shape, RANK, td_->split.axis, td_->split.a_i, td_->split.a_o, | ||
| 282 | coord); | ||
| 283 | |||
| 284 | if (flat != start) | ||
| 285 | AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(evMTE3toMTE2); | ||
| 286 | |||
| 287 | // S1a: CopyIn input_gradients(fp16) → UB_TEMP | ||
| 288 | CopyInBrc(coord, 0, UB_TEMP, a_i_seg); | ||
| 289 | AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV); | ||
| 290 | AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV); | ||
| 291 | |||
| 292 | // S1b: Cast UB_TEMP(fp16)→UB_GRAD_O_FP32(fp32), CAST_NONE(扩精度) | ||
| 293 | AscendC::Cast(buf_[UB_GRAD_O_FP32].template Get<float>(), buf_[UB_TEMP].template Get<T>(), | ||
| 294 | AscendC::RoundMode::CAST_NONE, count); | ||
| 295 | AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(evVtoMTE2); | ||
| 296 | AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(evVtoMTE2); | ||
| 297 | |||
| 298 | // S2a: CopyIn input_features(fp16)→UB_TEMP(复用) | ||
| 299 | CopyInBrc(coord, 1, UB_TEMP, a_i_seg); | ||
| 300 | AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV); | ||
| 301 | AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV); | ||
| 302 | |||
| 303 | // S2b: Cast UB_TEMP(fp16)→UB_SELF_FP32(fp32) | ||
| 304 | AscendC::Cast(buf_[UB_SELF_FP32].template Get<float>(), buf_[UB_TEMP].template Get<T>(), | ||
| 305 | AscendC::RoundMode::CAST_NONE, count); | ||
| 306 | AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(evVtoMTE2); | ||
| 307 | AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(evVtoMTE2); | ||
| 308 | |||
| 309 | // S3: VF(UB_SELF_FP32, UB_GRAD_O_FP32 → UB_RESULT) | ||
| 310 | uint16_t rep = AscendC::CeilDivision(count, VL_F); | ||
| 311 | asc_vf_call<SoftplusV2GradVF<float>>((__ubuf__ float*)buf_[UB_RESULT].Get<float>().GetPhyAddr(), | ||
| 312 | (__ubuf__ float*)buf_[UB_SELF_FP32].Get<float>().GetPhyAddr(), | ||
| 313 | (__ubuf__ float*)buf_[UB_GRAD_O_FP32].Get<float>().GetPhyAddr(), count, | ||
| 314 | VL_F, rep, beta_, threshold_); | ||
| 315 | |||
| 316 | // S4: Cast UB_RESULT(fp32)→UB_TEMP(fp16), CAST_RINT(缩精度) | ||
| 317 | AscendC::Cast(buf_[UB_TEMP].template Get<T>(), buf_[UB_RESULT].template Get<float>(), | ||
| 318 | AscendC::RoundMode::CAST_RINT, count); | ||
| 319 | AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(evVtoMTE3); | ||
| 320 | AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(evVtoMTE3); | ||
| 321 | |||
| 322 | // S5: CopyOut UB_TEMP → GM | ||
| 323 | CopyOutOne(coord, 0, UB_TEMP, a_i_seg); | ||
| 324 | |||
| 325 | if (flat != end - 1) | ||
| 326 | AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(evMTE3toMTE2); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | // ============================================================ | ||
| 331 | // CopyInBrc — NDDMA 多维广播搬运 | ||
| 332 | // ============================================================ | ||
| 333 | __aicore__ inline void CopyInBrc(const int64_t* coord, int inputIdx, int slot, int64_t a_i_seg) | ||
| 334 | { | ||
| 335 | int64_t k = td_->split.axis; | ||
| 336 | int64_t off = CalcOffset(coord, td_->input_strides[inputIdx], RANK); | ||
| 337 | const int64_t* dstShape = td_->max_bro_shape; | ||
| 338 | |||
| 339 | auto params = nddmaParams_[inputIdx]; | ||
| 340 | int64_t k_nd = RANK - 1 - k; | ||
| 341 | int64_t inner = 1; | ||
| 342 | for (int64_t nd = 0; nd < ND; nd++) { | ||
| 343 | if (nd == k_nd) | ||
| 344 | params.loopInfo.loopSize[nd] = a_i_seg; | ||
| 345 | params.loopInfo.loopDstStride[nd] = inner; | ||
| 346 | inner *= params.loopInfo.loopSize[nd]; | ||
| 347 | } | ||
| 348 | |||
| 349 | static constexpr AscendC::NdDmaConfig cfg = {false, AscendC::NdDmaConfig::unsetPad, | ||
| 350 | AscendC::NdDmaConfig::unsetPad, false}; | ||
| 351 | |||
| 352 | if constexpr (RANK <= kMaxNdDmaDims) { | ||
| 353 | AscendC::DataCopy<T, ND, cfg>(buf_[slot].Get<T>(), gmIn_[inputIdx][off], params); | ||
| 354 | } else { | ||
| 355 | AscendC::LocalTensor<T> buf = buf_[slot].Get<T>(); | ||
| 356 | int64_t elem_base = off; | ||
| 357 | for (int64_t oi = 0; oi < nddmaOuterIters_[inputIdx]; oi++) { | ||
| 358 | int64_t elem_adj = 0, tmp = oi; | ||
| 359 | for (int64_t d = RANK - nddma_dims_ - 1; d >= k; d--) { | ||
| 360 | int64_t sz = (d == k) ? a_i_seg : dstShape[d]; | ||
| 361 | elem_adj += (tmp % sz) * td_->input_strides[inputIdx][d]; | ||
| 362 | tmp /= sz; | ||
| 363 | } | ||
| 364 | AscendC::DataCopy<T, ND, cfg>(buf[oi * inner], gmIn_[inputIdx][elem_base + elem_adj], params); | ||
| 365 | } | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | // ============================================================ | ||
| 370 | // CopyOutOne — DataCopyPad 低维搬出 | ||
| 371 | // ============================================================ | ||
| 372 | __aicore__ inline void CopyOutOne(const int64_t* coord, int outputIdx, int slot, int64_t a_i_seg) | ||
| 373 | { | ||
| 374 | int64_t off = CalcOffset(coord, td_->output_strides[outputIdx], RANK); | ||
| 375 | int64_t cnt = CalcTransferCount(td_->output_shapes[outputIdx], RANK, td_->split.axis, a_i_seg); | ||
| 376 | AscendC::DataCopyExtParams extParams; | ||
| 377 | extParams.blockCount = 1; | ||
| 378 | extParams.blockLen = cnt * sizeof(T); | ||
| 379 | extParams.srcStride = 0; | ||
| 380 | extParams.dstStride = 0; | ||
| 381 | AscendC::DataCopyPad(gmOut_[outputIdx][off], buf_[slot].Get<T>(), extParams); | ||
| 382 | } | ||
| 383 | }; | ||
| @@ -0,0 +1,29 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | * | ||
| 10 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | // SoftplusV2Grad TilingKey 模板参数 | ||
| 14 | // 位置: operators/softplus_v2_grad/op_kernel/arch35/softplus_v2_grad_struct.h | ||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | ASCENDC_TPL_ARGS_DECL(SoftplusV2Grad, ASCENDC_TPL_UINT_DECL(RANK, 8, ASCENDC_TPL_UI_LIST, SOFTPLUS_V2_GRAD_RANK_4, | ||
| 24 | SOFTPLUS_V2_GRAD_RANK_8)); | ||
| 25 | |||
| 26 | ASCENDC_TPL_SEL(ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_UINT_SEL(RANK, ASCENDC_TPL_UI_LIST, SOFTPLUS_V2_GRAD_RANK_4)), | ||
| 27 | ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_UINT_SEL(RANK, ASCENDC_TPL_UI_LIST, SOFTPLUS_V2_GRAD_RANK_8))); | ||
| 28 | |||
| 29 | |||
| @@ -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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | // SoftplusV2Grad TilingData — 按 rank 模板化,体积分两档 | ||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | // === 算子特定常量 === | ||
| 18 | // 2 输入 (input_gradients, input_features), 1 输出 (output_backprops) | ||
| 19 | constexpr int64_t kMaxInputSlots = 2; | ||
| 20 | constexpr int64_t kMaxOutputSlots = 1; | ||
| 21 | // 物理存活节点 P = 4 (覆盖 fp16/bf16 含 Cast 路径) | ||
| 22 | constexpr int64_t kPhysNodes = 4; | ||
| 23 | |||
| 24 | // UB 对齐粒度: TBuf 硬件要求 32B 对齐 | ||
| 25 | constexpr int64_t kUbAlignBytes = 32; | ||
| 26 | // NDDMA 最大维数: 超出该维数的外层走 Flat loop | ||
| 27 | constexpr int64_t kMaxNdDmaDims = 5; | ||
| 28 | // 默认标量属性: 必须与 op_host/softplus_v2_grad_def.cpp 中 Attr 注册的默认值保持一致 | ||
| 29 | constexpr float kDefaultBeta = 1.0f; | ||
| 30 | constexpr float kDefaultThreshold = 20.0f; | ||
| 31 | // attr 索引: 与 def.cpp 中 Attr 注册顺序一致 (0=beta, 1=threshold) | ||
| 32 | constexpr int64_t kAttrIdxBeta = 0; | ||
| 33 | constexpr int64_t kAttrIdxThreshold = 1; | ||
| 34 | |||
| 35 | struct SplitResult { | ||
| 36 | int64_t axis; | ||
| 37 | int64_t a_i; | ||
| 38 | int64_t a_o; | ||
| 39 | int64_t a_i_tail; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct MultiCoreResult { | ||
| 43 | int64_t num_cores; | ||
| 44 | int64_t total_tiles; | ||
| 45 | int64_t tiles_main; | ||
| 46 | int64_t cores_tail; | ||
| 47 | }; | ||
| 48 | |||
| 49 | template <int64_t kRank> | ||
| 50 | struct SoftplusV2GradTilingData { | ||
| 51 | SplitResult split; | ||
| 52 | MultiCoreResult multicore; | ||
| 53 | int64_t rank; // 实际 rank (0~8),Kernel 运行期读取 | ||
| 54 | int64_t per_buf_bytes; // UB/P 向下对齐 32B,Kernel 用此初始化 TBuf | ||
| 55 | int64_t max_bro_shape[kRank]; | ||
| 56 | int64_t num_inputs; | ||
| 57 | int64_t num_outputs; | ||
| 58 | int64_t input_shapes[kMaxInputSlots][kRank]; | ||
| 59 | int64_t input_strides[kMaxInputSlots][kRank]; | ||
| 60 | int64_t output_shapes[kMaxOutputSlots][kRank]; | ||
| 61 | int64_t output_strides[kMaxOutputSlots][kRank]; | ||
| 62 | float beta; // 标量属性: softplus 陡峭度 (默认 1.0) | ||
| 63 | float threshold; // 标量属性: 数值稳定性阈值 (默认 20.0) | ||
| 64 | }; | ||
| @@ -1,8 +1,8 @@ | |||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 7 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | #/ | 8 | #/ |
| @@ -1,8 +1,8 @@ | |||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 7 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | #/ | 8 | #/ |
| @@ -15,4 +15,4 @@ foreach(SUB_DIR ${CURRENT_SOURCE_DIRS}) | |||
| 15 | if(EXISTS "${SUB_DIR}/CMakeLists.txt") | 15 | if(EXISTS "${SUB_DIR}/CMakeLists.txt") |
| 16 | add_subdirectory(${SUB_DIR}) | 16 | add_subdirectory(${SUB_DIR}) |
| 17 | endif() | 17 | endif() |
| 18 | endforeach() | 18 | endforeach() |
| @@ -1,13 +1,14 @@ | |||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 7 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | #/ | 8 | #/ |
| 9 | 9 | ||
| 10 | message(STATUS "=== Debug: start ops.activation.softplus_v2_grad.tests.ut.CMakeLists.txt ") | 10 | message(STATUS "=== Debug: start ops.activation.softplus_v2_grad.tests.ut.op_host.CMakeLists.txt ") |
| 11 | # 递归子目录(op_api UT 挂在 op_api/ 子目录下,此处保持不变) | ||
| 11 | file(GLOB CURRENT_SOURCE_DIRS LIST_DIRECTORIES true ${CMAKE_CURRENT_SOURCE_DIR}/*) | 12 | file(GLOB CURRENT_SOURCE_DIRS LIST_DIRECTORIES true ${CMAKE_CURRENT_SOURCE_DIR}/*) |
| 12 | message(STATUS "=== Debug: CURRENT_SOURCE_DIRS =${CURRENT_SOURCE_DIRS} ") | 13 | message(STATUS "=== Debug: CURRENT_SOURCE_DIRS =${CURRENT_SOURCE_DIRS} ") |
| 13 | foreach(SUB_DIR ${CURRENT_SOURCE_DIRS}) | 14 | foreach(SUB_DIR ${CURRENT_SOURCE_DIRS}) |
| @@ -15,3 +16,9 @@ foreach(SUB_DIR ${CURRENT_SOURCE_DIRS}) | |||
| 15 | add_subdirectory(${SUB_DIR}) | 16 | add_subdirectory(${SUB_DIR}) |
| 16 | endif() | 17 | endif() |
| 17 | endforeach() | 18 | endforeach() |
| 19 | |||
| 20 | # 本目录下的 tiling / infershape UT(DIR 为当前目录,仅收录本层 *.cpp,不递归子目录) | ||
| 21 | if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 22 | add_modules_ut_sources(HOSTNAME ${OP_TILING_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 23 | add_modules_ut_sources(HOSTNAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 24 | endif() | ||
| @@ -0,0 +1,490 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | // SoftplusV2Grad Tiling UT — 纯函数 + 框架级全覆盖 | ||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | |||
| 28 | |||
| 29 | |||
| 30 | using namespace std; | ||
| 31 | using namespace ut_util; | ||
| 32 | |||
| 33 | class SoftplusV2GradTilingTest : public testing::Test { | ||
| 34 | protected: | ||
| 35 | static void SetUpTestCase() { std::cout << "SoftplusV2GradTilingTest SetUp" << std::endl; } | ||
| 36 | static void TearDownTestCase() { std::cout << "SoftplusV2GradTilingTest TearDown" << std::endl; } | ||
| 37 | }; | ||
| 38 | |||
| 39 | // ============================================================ | ||
| 40 | // 1. CheckBroadcastShape | ||
| 41 | // ============================================================ | ||
| 42 | TEST_F(SoftplusV2GradTilingTest, broadcast_same_shape_single_in_out) | ||
| 43 | { | ||
| 44 | // input {2,3}, output {2,3} — 完全一致 | ||
| 45 | std::vector<std::vector<int64_t>> padded_in = {{2, 3}}; | ||
| 46 | std::vector<std::vector<int64_t>> padded_out = {{2, 3}}; | ||
| 47 | EXPECT_TRUE(softplus_v2_grad::CheckBroadcastShape(padded_in, padded_out, 2)); | ||
| 48 | } | ||
| 49 | |||
| 50 | TEST_F(SoftplusV2GradTilingTest, broadcast_two_inputs_same) | ||
| 51 | { | ||
| 52 | // 2 个 input 都是 {4,4}, 1 个 output {4,4} | ||
| 53 | std::vector<std::vector<int64_t>> padded_in = {{4, 4}, {4, 4}}; | ||
| 54 | std::vector<std::vector<int64_t>> padded_out = {{4, 4}}; | ||
| 55 | EXPECT_TRUE(softplus_v2_grad::CheckBroadcastShape(padded_in, padded_out, 2)); | ||
| 56 | } | ||
| 57 | |||
| 58 | TEST_F(SoftplusV2GradTilingTest, broadcast_input_dim_is_one) | ||
| 59 | { | ||
| 60 | // input {1,4}, output {4,4} — input=1 的维度不冲突 | ||
| 61 | std::vector<std::vector<int64_t>> padded_in = {{1, 4}}; | ||
| 62 | std::vector<std::vector<int64_t>> padded_out = {{4, 4}}; | ||
| 63 | EXPECT_TRUE(softplus_v2_grad::CheckBroadcastShape(padded_in, padded_out, 2)); | ||
| 64 | } | ||
| 65 | |||
| 66 | TEST_F(SoftplusV2GradTilingTest, broadcast_output_dim_is_one) | ||
| 67 | { | ||
| 68 | // input {4,4}, output {1,4} — output=1 的维度不冲突 | ||
| 69 | std::vector<std::vector<int64_t>> padded_in = {{4, 4}}; | ||
| 70 | std::vector<std::vector<int64_t>> padded_out = {{1, 4}}; | ||
| 71 | EXPECT_TRUE(softplus_v2_grad::CheckBroadcastShape(padded_in, padded_out, 2)); | ||
| 72 | } | ||
| 73 | |||
| 74 | TEST_F(SoftplusV2GradTilingTest, broadcast_two_inputs_different_non_one) | ||
| 75 | { | ||
| 76 | // 两个 input 在同一维上取值不同且都不是 1 → 不兼容 | ||
| 77 | std::vector<std::vector<int64_t>> padded_in = {{2, 3}, {4, 3}}; | ||
| 78 | std::vector<std::vector<int64_t>> padded_out = {{4, 3}}; | ||
| 79 | EXPECT_FALSE(softplus_v2_grad::CheckBroadcastShape(padded_in, padded_out, 2)); | ||
| 80 | } | ||
| 81 | |||
| 82 | TEST_F(SoftplusV2GradTilingTest, broadcast_input_output_diff_non_one) | ||
| 83 | { | ||
| 84 | // input {2,3}, output {4,3} 且 input dim0=2 ≠ 1, output dim0=4 ≠ 1 → 不兼容 | ||
| 85 | std::vector<std::vector<int64_t>> padded_in = {{2, 3}}; | ||
| 86 | std::vector<std::vector<int64_t>> padded_out = {{4, 3}}; | ||
| 87 | EXPECT_FALSE(softplus_v2_grad::CheckBroadcastShape(padded_in, padded_out, 2)); | ||
| 88 | } | ||
| 89 | |||
| 90 | // ============================================================ | ||
| 91 | // 2. PadAndSqueeze | ||
| 92 | // ============================================================ | ||
| 93 | |||
| 94 | TEST_F(SoftplusV2GradTilingTest, pad_squeeze_same_rank) | ||
| 95 | { | ||
| 96 | // 两个 input 同 rank,output 同 rank → 无需补 | ||
| 97 | std::vector<std::vector<int64_t>> in_shapes = {{2, 3}, {2, 3}}; | ||
| 98 | std::vector<std::vector<int64_t>> out_shapes = {{2, 3}}; | ||
| 99 | std::vector<int64_t> max_bro; | ||
| 100 | std::vector<std::vector<int64_t>> norm_in, norm_out; | ||
| 101 | EXPECT_TRUE(softplus_v2_grad::PadAndSqueeze(in_shapes, out_shapes, max_bro, norm_in, norm_out)); | ||
| 102 | EXPECT_EQ(max_bro, std::vector<int64_t>({2, 3})); | ||
| 103 | EXPECT_EQ(norm_in.size(), 2u); | ||
| 104 | EXPECT_EQ(norm_out.size(), 1u); | ||
| 105 | EXPECT_EQ(norm_in[0], std::vector<int64_t>({2, 3})); | ||
| 106 | EXPECT_EQ(norm_out[0], std::vector<int64_t>({2, 3})); | ||
| 107 | } | ||
| 108 | |||
| 109 | TEST_F(SoftplusV2GradTilingTest, pad_squeeze_different_rank) | ||
| 110 | { | ||
| 111 | // input: {2,3} (rank 2), output: {2} (rank 1) → output 右对齐补 1 | ||
| 112 | std::vector<std::vector<int64_t>> in_shapes = {{2, 3}}; | ||
| 113 | std::vector<std::vector<int64_t>> out_shapes = {{3}}; | ||
| 114 | std::vector<int64_t> max_bro; | ||
| 115 | std::vector<std::vector<int64_t>> norm_in, norm_out; | ||
| 116 | EXPECT_TRUE(softplus_v2_grad::PadAndSqueeze(in_shapes, out_shapes, max_bro, norm_in, norm_out)); | ||
| 117 | // max_rank=2: input {2,3}, output padded to {1,3} | ||
| 118 | // broadcast result should be {2,3} | ||
| 119 | EXPECT_EQ(max_bro, std::vector<int64_t>({2, 3})); | ||
| 120 | EXPECT_EQ(norm_in[0], std::vector<int64_t>({2, 3})); | ||
| 121 | // output padded dim0=1 不挤压(因为有非1的输入维)→ 保持 {1,3} | ||
| 122 | EXPECT_EQ(norm_out[0], std::vector<int64_t>({1, 3})); | ||
| 123 | } | ||
| 124 | |||
| 125 | TEST_F(SoftplusV2GradTilingTest, pad_squeeze_all_ones) | ||
| 126 | { | ||
| 127 | // 全部是 1 → max_bro_shape 为 {1} | ||
| 128 | std::vector<std::vector<int64_t>> in_shapes = {{1}}; | ||
| 129 | std::vector<std::vector<int64_t>> out_shapes = {{1}}; | ||
| 130 | std::vector<int64_t> max_bro; | ||
| 131 | std::vector<std::vector<int64_t>> norm_in, norm_out; | ||
| 132 | EXPECT_TRUE(softplus_v2_grad::PadAndSqueeze(in_shapes, out_shapes, max_bro, norm_in, norm_out)); | ||
| 133 | EXPECT_EQ(max_bro, std::vector<int64_t>({1})); | ||
| 134 | EXPECT_EQ(norm_in[0], std::vector<int64_t>({1})); | ||
| 135 | EXPECT_EQ(norm_out[0], std::vector<int64_t>({1})); | ||
| 136 | } | ||
| 137 | |||
| 138 | TEST_F(SoftplusV2GradTilingTest, pad_squeeze_4d) | ||
| 139 | { | ||
| 140 | // 4D tensor: {1,4,4,8} | ||
| 141 | std::vector<std::vector<int64_t>> in_shapes = {{1, 4, 4, 8}}; | ||
| 142 | std::vector<std::vector<int64_t>> out_shapes = {{1, 4, 4, 8}}; | ||
| 143 | std::vector<int64_t> max_bro; | ||
| 144 | std::vector<std::vector<int64_t>> norm_in, norm_out; | ||
| 145 | EXPECT_TRUE(softplus_v2_grad::PadAndSqueeze(in_shapes, out_shapes, max_bro, norm_in, norm_out)); | ||
| 146 | // dim0=1 squeezed out, 剩下 {4,4,8} | ||
| 147 | EXPECT_EQ(max_bro, std::vector<int64_t>({4, 4, 8})); | ||
| 148 | } | ||
| 149 | |||
| 150 | // ============================================================ | ||
| 151 | // 3. FindSplitAxis | ||
| 152 | // ============================================================ | ||
| 153 | |||
| 154 | TEST_F(SoftplusV2GradTilingTest, split_axis_small_shape_no_split) | ||
| 155 | { | ||
| 156 | // shape {2,3}, dtype_size=4, ub=262144, phys_nodes=4 | ||
| 157 | // per_buf_bytes = (262144/4) & ~31 = 65504 | ||
| 158 | // per_buf_elems = 65504/4 = 16376 | ||
| 159 | // inner: k=1: 3*1=3 ≤ 16376, inner*=3 → k=0: 2*3=6 ≤ 16376 | ||
| 160 | // 不切: a_i=2, a_o=1, a_i_tail=2, axis=0 | ||
| 161 | std::vector<int64_t> shape = {2, 3}; | ||
| 162 | SplitResult out; | ||
| 163 | EXPECT_TRUE(softplus_v2_grad::FindSplitAxis(shape, /*dtype_size=*/4, /*ub=*/262144, /*phys_nodes=*/4, out)); | ||
| 164 | EXPECT_EQ(out.axis, 0); | ||
| 165 | EXPECT_EQ(out.a_o, 1); | ||
| 166 | EXPECT_EQ(out.a_i, 2); | ||
| 167 | EXPECT_EQ(out.a_i_tail, 2); | ||
| 168 | } | ||
| 169 | |||
| 170 | TEST_F(SoftplusV2GradTilingTest, split_axis_large_shape_needs_split) | ||
| 171 | { | ||
| 172 | // shape {1, 65536}, dtype_size=4, ub=262144, phys_nodes=4 | ||
| 173 | // per_buf_bytes = (262144/4) & ~31 = 65536; per_buf_elems = 65536/4 = 16384 | ||
| 174 | // k=1: 65536 > 16384 → split on axis 1 | ||
| 175 | // a_i = 16384/1 = 16384; a_o = ceil(65536/16384) = 4; rem = 0 → a_i_tail = 16384 | ||
| 176 | std::vector<int64_t> shape = {1, 65536}; | ||
| 177 | SplitResult out; | ||
| 178 | EXPECT_TRUE(softplus_v2_grad::FindSplitAxis(shape, /*dtype_size=*/4, /*ub=*/262144, /*phys_nodes=*/4, out)); | ||
| 179 | EXPECT_EQ(out.axis, 1); | ||
| 180 | EXPECT_EQ(out.a_o, 4); | ||
| 181 | EXPECT_EQ(out.a_i, 16384); | ||
| 182 | EXPECT_EQ(out.a_i_tail, 16384); | ||
| 183 | } | ||
| 184 | |||
| 185 | TEST_F(SoftplusV2GradTilingTest, split_axis_invalid_dtype_size) | ||
| 186 | { | ||
| 187 | std::vector<int64_t> shape = {2, 3}; | ||
| 188 | SplitResult out; | ||
| 189 | EXPECT_FALSE(softplus_v2_grad::FindSplitAxis(shape, /*dtype_size=*/0, /*ub=*/262144, /*phys_nodes=*/4, out)); | ||
| 190 | } | ||
| 191 | |||
| 192 | TEST_F(SoftplusV2GradTilingTest, split_axis_invalid_phys_nodes) | ||
| 193 | { | ||
| 194 | std::vector<int64_t> shape = {2, 3}; | ||
| 195 | SplitResult out; | ||
| 196 | EXPECT_FALSE(softplus_v2_grad::FindSplitAxis(shape, /*dtype_size=*/4, /*ub=*/262144, /*phys_nodes=*/0, out)); | ||
| 197 | } | ||
| 198 | |||
| 199 | TEST_F(SoftplusV2GradTilingTest, split_axis_very_small_ub) | ||
| 200 | { | ||
| 201 | // ub=64: per_buf_bytes = (64/4) & ~31 = 0 → per_buf_elems = 0 → 直接失败 | ||
| 202 | std::vector<int64_t> shape = {2, 3}; | ||
| 203 | SplitResult out; | ||
| 204 | EXPECT_FALSE(softplus_v2_grad::FindSplitAxis(shape, /*dtype_size=*/4, /*ub=*/64, /*phys_nodes=*/4, out)); | ||
| 205 | } | ||
| 206 | |||
| 207 | // ============================================================ | ||
| 208 | // 4. MultiCoreSplit | ||
| 209 | // ============================================================ | ||
| 210 | |||
| 211 | TEST_F(SoftplusV2GradTilingTest, multicore_few_tiles) | ||
| 212 | { | ||
| 213 | // split.axis=0, shape {2,3}: outer_prod=1, total_tiles = 1*1 = 1 | ||
| 214 | // max_cores=64, num_cores = min(1,64) = 1 | ||
| 215 | SplitResult split = {0, 2, 1, 2}; | ||
| 216 | std::vector<int64_t> shape = {2, 3}; | ||
| 217 | MultiCoreResult out; | ||
| 218 | EXPECT_TRUE(softplus_v2_grad::MultiCoreSplit(shape, split, 64, out)); | ||
| 219 | EXPECT_EQ(out.num_cores, 1); | ||
| 220 | EXPECT_EQ(out.total_tiles, 1); | ||
| 221 | EXPECT_EQ(out.tiles_main, 1); | ||
| 222 | EXPECT_EQ(out.cores_tail, 0); | ||
| 223 | } | ||
| 224 | |||
| 225 | TEST_F(SoftplusV2GradTilingTest, multicore_many_tiles) | ||
| 226 | { | ||
| 227 | // split.axis=1, shape {1,65536}: outer_prod=1, a_o=5 | ||
| 228 | // total_tiles = 1*5 = 5, num_cores=5 | ||
| 229 | SplitResult split = {1, 16376, 5, 4}; | ||
| 230 | std::vector<int64_t> shape = {1, 65536}; | ||
| 231 | MultiCoreResult out; | ||
| 232 | EXPECT_TRUE(softplus_v2_grad::MultiCoreSplit(shape, split, 64, out)); | ||
| 233 | EXPECT_EQ(out.num_cores, 5); | ||
| 234 | EXPECT_EQ(out.total_tiles, 5); | ||
| 235 | EXPECT_EQ(out.tiles_main, 1); | ||
| 236 | EXPECT_EQ(out.cores_tail, 0); | ||
| 237 | } | ||
| 238 | |||
| 239 | TEST_F(SoftplusV2GradTilingTest, multicore_caps_at_max_cores) | ||
| 240 | { | ||
| 241 | // shape {100, 8}: axis=0, a_o=5, outer_prod=1, total_tiles=5 | ||
| 242 | // max_cores=3: num_cores=min(5,3)=3 → tiles_main=5/3=1, cores_tail=5%3=2 | ||
| 243 | SplitResult split = {0, 2, 5, 2}; | ||
| 244 | std::vector<int64_t> shape = {100, 8}; | ||
| 245 | MultiCoreResult out; | ||
| 246 | EXPECT_TRUE(softplus_v2_grad::MultiCoreSplit(shape, split, 3, out)); | ||
| 247 | EXPECT_EQ(out.num_cores, 3); | ||
| 248 | EXPECT_EQ(out.total_tiles, 5); | ||
| 249 | EXPECT_EQ(out.tiles_main, 1); | ||
| 250 | EXPECT_EQ(out.cores_tail, 2); | ||
| 251 | } | ||
| 252 | |||
| 253 | TEST_F(SoftplusV2GradTilingTest, multicore_tail_cores) | ||
| 254 | { | ||
| 255 | // shape {5}: split.axis=0, a_o=1, total_tiles=1 → outer_prod=1 | ||
| 256 | // max_cores=3: num_cores=1 → tiles_main=1, cores_tail=0 | ||
| 257 | SplitResult split = {0, 3, 2, 2}; // 5 元素: a_o=2, a_i=3, a_i_tail=2 | ||
| 258 | std::vector<int64_t> shape = {5}; | ||
| 259 | MultiCoreResult out; | ||
| 260 | EXPECT_TRUE(softplus_v2_grad::MultiCoreSplit(shape, split, 3, out)); | ||
| 261 | EXPECT_EQ(out.total_tiles, 2); // outer_prod(1)*a_o(2)=2 | ||
| 262 | EXPECT_EQ(out.num_cores, 2); // min(2,3)=2 | ||
| 263 | EXPECT_EQ(out.tiles_main, 1); // 2/2=1 | ||
| 264 | EXPECT_EQ(out.cores_tail, 0); // 2%2=0 | ||
| 265 | } | ||
| 266 | |||
| 267 | TEST_F(SoftplusV2GradTilingTest, multicore_zero_total_tiles) | ||
| 268 | { | ||
| 269 | // shape {0} (空 tensor): outer_prod=1, a_o=0 → total_tiles=0, num_cores=0 → false | ||
| 270 | SplitResult split = {0, 1, 0, 1}; | ||
| 271 | std::vector<int64_t> shape = {0}; | ||
| 272 | MultiCoreResult out; | ||
| 273 | EXPECT_FALSE(softplus_v2_grad::MultiCoreSplit(shape, split, 64, out)); | ||
| 274 | } | ||
| 275 | |||
| 276 | // ============================================================ | ||
| 277 | // 5. PrecomputeStrides | ||
| 278 | // ============================================================ | ||
| 279 | |||
| 280 | TEST_F(SoftplusV2GradTilingTest, strides_1d) | ||
| 281 | { | ||
| 282 | std::vector<int64_t> shape = {5}; | ||
| 283 | std::vector<int64_t> strides; | ||
| 284 | EXPECT_TRUE(softplus_v2_grad::PrecomputeStrides(shape, strides)); | ||
| 285 | // 1D: 最内维 stride=1 | ||
| 286 | EXPECT_EQ(strides, std::vector<int64_t>({1})); | ||
| 287 | } | ||
| 288 | |||
| 289 | TEST_F(SoftplusV2GradTilingTest, strides_2d) | ||
| 290 | { | ||
| 291 | std::vector<int64_t> shape = {3, 4}; | ||
| 292 | std::vector<int64_t> strides; | ||
| 293 | EXPECT_TRUE(softplus_v2_grad::PrecomputeStrides(shape, strides)); | ||
| 294 | // d=1: s[1]=4 → prod=1 → stride[1]=1; d=0: prod=s[1]=4 → stride[0]=4 | ||
| 295 | EXPECT_EQ(strides, std::vector<int64_t>({4, 1})); | ||
| 296 | } | ||
| 297 | |||
| 298 | TEST_F(SoftplusV2GradTilingTest, strides_dim_one_yields_zero_stride) | ||
| 299 | { | ||
| 300 | // dim=1 → stride=0 (broadcast dim) | ||
| 301 | std::vector<int64_t> shape = {1, 8, 1}; | ||
| 302 | std::vector<int64_t> strides; | ||
| 303 | EXPECT_TRUE(softplus_v2_grad::PrecomputeStrides(shape, strides)); | ||
| 304 | // d=2: s[2]=1 → 0; d=1: s[1]=8 → prod=1 → 1; d=0: s[0]=1 → 0 | ||
| 305 | EXPECT_EQ(strides, std::vector<int64_t>({0, 1, 0})); | ||
| 306 | } | ||
| 307 | |||
| 308 | TEST_F(SoftplusV2GradTilingTest, strides_3d) | ||
| 309 | { | ||
| 310 | std::vector<int64_t> shape = {2, 3, 4}; | ||
| 311 | std::vector<int64_t> strides; | ||
| 312 | EXPECT_TRUE(softplus_v2_grad::PrecomputeStrides(shape, strides)); | ||
| 313 | // d=2: s[2]=4 → 1; d=1: prod=4 → 4; d=0: prod=3*4=12 → 12 | ||
| 314 | EXPECT_EQ(strides, std::vector<int64_t>({12, 4, 1})); | ||
| 315 | } | ||
| 316 | |||
| 317 | // ============================================================ | ||
| 318 | // 集成: PadAndSqueeze + CheckBroadcastShape 联合正确性 | ||
| 319 | // ============================================================ | ||
| 320 | |||
| 321 | TEST_F(SoftplusV2GradTilingTest, integration_pad_and_check) | ||
| 322 | { | ||
| 323 | // 确保 PadAndSqueeze 产出的归一化 shape 能通过 CheckBroadcastShape | ||
| 324 | std::vector<std::vector<int64_t>> in_shapes = {{4, 8}, {4, 8}}; | ||
| 325 | std::vector<std::vector<int64_t>> out_shapes = {{4, 8}}; | ||
| 326 | std::vector<int64_t> max_bro; | ||
| 327 | std::vector<std::vector<int64_t>> norm_in, norm_out; | ||
| 328 | ASSERT_TRUE(softplus_v2_grad::PadAndSqueeze(in_shapes, out_shapes, max_bro, norm_in, norm_out)); | ||
| 329 | EXPECT_TRUE(softplus_v2_grad::CheckBroadcastShape(norm_in, norm_out, max_bro.size())); | ||
| 330 | } | ||
| 331 | |||
| 332 | // ============================================================ | ||
| 333 | // 集成: FindSplitAxis + MultiCoreSplit 一致性 | ||
| 334 | // ============================================================ | ||
| 335 | |||
| 336 | TEST_F(SoftplusV2GradTilingTest, integration_split_and_multicore) | ||
| 337 | { | ||
| 338 | // 验证 split 和 multicore 对同一 shape 的结果一致性 | ||
| 339 | std::vector<int64_t> shape = {32, 128}; | ||
| 340 | SplitResult split; | ||
| 341 | ASSERT_TRUE(softplus_v2_grad::FindSplitAxis(shape, /*dtype_size=*/4, /*ub=*/262144, /*phys_nodes=*/4, split)); | ||
| 342 | MultiCoreResult mc; | ||
| 343 | ASSERT_TRUE(softplus_v2_grad::MultiCoreSplit(shape, split, 64, mc)); | ||
| 344 | // 确保多核划分 cover 所有 tile | ||
| 345 | EXPECT_EQ(mc.total_tiles, mc.num_cores * mc.tiles_main + mc.cores_tail); | ||
| 346 | // num_cores ≤ 64 | ||
| 347 | EXPECT_LE(mc.num_cores, 64); | ||
| 348 | } | ||
| 349 | |||
| 350 | // ============================================================ | ||
| 351 | // 框架级 Tiling UT — 使用 TilingContextFaker | ||
| 352 | // 覆盖 GetShapeInfo / DoTilingAndSet / RunTiling / FillShapesAndStrides / LogTilingData | ||
| 353 | // ============================================================ | ||
| 354 | |||
| 355 | class SoftplusV2GradTilingIntegrationTest : public testing::Test { | ||
| 356 | protected: | ||
| 357 | static void SetUpTestCase() { std::cout << "SoftplusV2GradTilingIntegration SetUp" << std::endl; } | ||
| 358 | static void TearDownTestCase() { std::cout << "SoftplusV2GradTilingIntegration TearDown" << std::endl; } | ||
| 359 | }; | ||
| 360 | |||
| 361 | // 辅助: 验证 TilingData 基本合法性 | ||
| 362 | // SoftplusV2GradTilingData 内存布局: | ||
| 363 | // SplitResult(4xint64) + MultiCoreResult(4xint64) + rank(1) + per_buf_bytes(1) = 10 个 int64 | ||
| 364 | // raw[8] = rank, raw[9] = per_buf_bytes, raw[4] = multicore.num_cores | ||
| 365 | static void VerifyTilingDataValid(const gert::TilingData* tiling_data) | ||
| 366 | { | ||
| 367 | ASSERT_NE(tiling_data, nullptr); | ||
| 368 | ASSERT_GT(tiling_data->GetDataSize(), (size_t)0); | ||
| 369 | auto* raw = reinterpret_cast<const int64_t*>(tiling_data->GetData()); | ||
| 370 | int64_t rank_val = raw[8]; | ||
| 371 | int64_t per_buf = raw[9]; | ||
| 372 | int64_t num_cores = raw[4]; | ||
| 373 | EXPECT_GT(rank_val, 0); | ||
| 374 | EXPECT_GT(per_buf, 0); | ||
| 375 | EXPECT_GE(num_cores, 1); | ||
| 376 | EXPECT_LE(num_cores, 64); | ||
| 377 | } | ||
| 378 | |||
| 379 | // 通用 tiling 全链路测试模板 | ||
| 380 | static void RunTilingIntegrationTest(const gert::StorageShape& in_a, const gert::StorageShape& in_b, | ||
| 381 | const gert::StorageShape& out, ge::DataType dtype, ge::DataType out_dtype, | ||
| 382 | ge::graphStatus expect_status) | ||
| 383 | { | ||
| 384 | gert::StorageShape in_copy_a = in_a; | ||
| 385 | gert::StorageShape in_copy_b = in_b; | ||
| 386 | gert::StorageShape out_copy = out; | ||
| 387 | std::map<std::string, std::string> soc_infos, aicore_spec, intrinsics; | ||
| 388 | std::map<std::string, std::string> soc_version = {{"Short_SoC_version", "Ascend950"}, {"NpuArch", "3510"}}; | ||
| 389 | std::string compile_str = R"({ | ||
| 390 | "hardware_info": { | ||
| 391 | "BT_SIZE": 0, "load3d_constraints": "1", | ||
| 392 | "Intrinsic_fix_pipe_l0c2out": false, "Intrinsic_data_move_l12ub": true, | ||
| 393 | "Intrinsic_data_move_l0c2ub": true, "Intrinsic_data_move_out2l1_nd2nz": false, | ||
| 394 | "UB_SIZE": 245760, "L2_SIZE": 33554432, "L1_SIZE": 524288, | ||
| 395 | "L0A_SIZE": 65536, "L0B_SIZE": 65536, "L0C_SIZE": 131072, "CORE_NUM": 64 | ||
| 396 | } | ||
| 397 | })"; | ||
| 398 | GetPlatFormInfos(compile_str.c_str(), soc_infos, aicore_spec, intrinsics); | ||
| 399 | |||
| 400 | fe::PlatFormInfos platform_info; | ||
| 401 | platform_info.Init(); | ||
| 402 | optiling::SoftplusV2GradCompileInfo compile_info; | ||
| 403 | std::string op_type("SoftplusV2Grad"); | ||
| 404 | |||
| 405 | auto op_impl = gert::OpImplRegistry::GetInstance().GetOpImpl(op_type.c_str()); | ||
| 406 | ASSERT_NE(op_impl, nullptr); | ||
| 407 | auto tiling_func = op_impl->tiling; | ||
| 408 | auto tiling_parse_func = op_impl->tiling_parse; | ||
| 409 | |||
| 410 | auto kernel_holder = gert::KernelRunContextFaker() | ||
| 411 | .KernelIONum(1, 1) | ||
| 412 | .Inputs({const_cast<char*>(compile_str.c_str()), reinterpret_cast<void*>(&platform_info)}) | ||
| 413 | .Outputs({&compile_info}) | ||
| 414 | .Build(); | ||
| 415 | ASSERT_TRUE(kernel_holder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->Init()); | ||
| 416 | kernel_holder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("SoCInfo", soc_infos); | ||
| 417 | kernel_holder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("AICoreSpec", aicore_spec); | ||
| 418 | kernel_holder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetCoreNumByCoreType("AICore"); | ||
| 419 | kernel_holder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("AICoreintrinsicDtypeMap", | ||
| 420 | intrinsics); | ||
| 421 | kernel_holder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("version", soc_version); | ||
| 422 | ASSERT_EQ(tiling_parse_func(kernel_holder.GetContext<gert::KernelContext>()), ge::GRAPH_SUCCESS); | ||
| 423 | |||
| 424 | auto param = gert::TilingData::CreateCap(8192); | ||
| 425 | ASSERT_NE(param, nullptr); | ||
| 426 | auto ws_holder = gert::ContinuousVector::Create<size_t>(4096); | ||
| 427 | auto ws_size = reinterpret_cast<gert::ContinuousVector*>(ws_holder.get()); | ||
| 428 | |||
| 429 | auto holder = gert::TilingContextFaker() | ||
| 430 | .SetOpType(op_type) | ||
| 431 | .NodeIoNum(2, 1) | ||
| 432 | .IrInstanceNum({1}) | ||
| 433 | .InputShapes({&in_copy_a, &in_copy_b}) | ||
| 434 | .OutputShapes({&out_copy}) | ||
| 435 | .CompileInfo(&compile_info) | ||
| 436 | .PlatformInfo(reinterpret_cast<char*>(&platform_info)) | ||
| 437 | .NodeInputTd(0, dtype, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 438 | .NodeInputTd(1, dtype, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 439 | .NodeOutputTd(0, out_dtype, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 440 | .TilingData(param.get()) | ||
| 441 | .Workspace(ws_size) | ||
| 442 | .Build(); | ||
| 443 | auto* ctx = holder.GetContext<gert::TilingContext>(); | ||
| 444 | ASSERT_NE(ctx->GetPlatformInfo(), nullptr); | ||
| 445 | ctx->GetPlatformInfo()->SetPlatformRes("SoCInfo", soc_infos); | ||
| 446 | ctx->GetPlatformInfo()->SetPlatformRes("AICoreSpec", aicore_spec); | ||
| 447 | ctx->GetPlatformInfo()->SetCoreNumByCoreType("AICore"); | ||
| 448 | ctx->GetPlatformInfo()->SetPlatformRes("AICoreintrinsicDtypeMap", intrinsics); | ||
| 449 | |||
| 450 | EXPECT_EQ(tiling_func(ctx), expect_status); | ||
| 451 | if (expect_status == ge::GRAPH_SUCCESS) { | ||
| 452 | VerifyTilingDataValid(ctx->GetRawTilingData()); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | TEST_F(SoftplusV2GradTilingIntegrationTest, tiling_fp32_2d) | ||
| 457 | { | ||
| 458 | gert::StorageShape shape = {{4, 8}, {4, 8}}; | ||
| 459 | RunTilingIntegrationTest(shape, shape, shape, ge::DT_FLOAT, ge::DT_FLOAT, ge::GRAPH_SUCCESS); | ||
| 460 | } | ||
| 461 | |||
| 462 | TEST_F(SoftplusV2GradTilingIntegrationTest, tiling_fp16_4d) | ||
| 463 | { | ||
| 464 | gert::StorageShape shape = {{1, 4, 4, 8}, {1, 4, 4, 8}}; | ||
| 465 | RunTilingIntegrationTest(shape, shape, shape, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::GRAPH_SUCCESS); | ||
| 466 | } | ||
| 467 | |||
| 468 | TEST_F(SoftplusV2GradTilingIntegrationTest, tiling_bf16_5d_rank8) | ||
| 469 | { | ||
| 470 | gert::StorageShape shape = {{1, 1, 2, 3, 4}, {1, 1, 2, 3, 4}}; | ||
| 471 | RunTilingIntegrationTest(shape, shape, shape, ge::DT_BF16, ge::DT_BF16, ge::GRAPH_SUCCESS); | ||
| 472 | } | ||
| 473 | |||
| 474 | TEST_F(SoftplusV2GradTilingIntegrationTest, tiling_fp32_1d) | ||
| 475 | { | ||
| 476 | gert::StorageShape shape = {{256}, {256}}; | ||
| 477 | RunTilingIntegrationTest(shape, shape, shape, ge::DT_FLOAT, ge::DT_FLOAT, ge::GRAPH_SUCCESS); | ||
| 478 | } | ||
| 479 | |||
| 480 | TEST_F(SoftplusV2GradTilingIntegrationTest, tiling_fp32_large_2d) | ||
| 481 | { | ||
| 482 | gert::StorageShape shape = {{1, 65536}, {1, 65536}}; | ||
| 483 | RunTilingIntegrationTest(shape, shape, shape, ge::DT_FLOAT, ge::DT_FLOAT, ge::GRAPH_SUCCESS); | ||
| 484 | } | ||
| 485 | |||
| 486 | TEST_F(SoftplusV2GradTilingIntegrationTest, tiling_unsupported_dtype_failed) | ||
| 487 | { | ||
| 488 | gert::StorageShape shape = {{2, 3}, {2, 3}}; | ||
| 489 | RunTilingIntegrationTest(shape, shape, shape, ge::DT_INT32, ge::DT_INT32, ge::GRAPH_FAILED); | ||
| 490 | } | ||
| @@ -1,8 +1,8 @@ | |||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 7 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | #/ | 8 | #/ |
| @@ -9,7 +9,7 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | #include "../../../../op_host/op_api/aclnn_softplus_backward.h" | 12 | #include "../../../../op_api/aclnn_softplus_backward.h" |
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | 15 | ||
| @@ -0,0 +1,55 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | class SoftplusV2Grad : public testing::Test { | ||
| 21 | protected: | ||
| 22 | static void SetUpTestCase() { std::cout << "SoftplusV2Grad InferShape SetUp" << std::endl; } | ||
| 23 | |||
| 24 | static void TearDownTestCase() { std::cout << "SoftplusV2Grad InferShape TearDown" << std::endl; } | ||
| 25 | }; | ||
| 26 | |||
| 27 | // 同 shape 广播: 2 输入相同 → 输出相同 | ||
| 28 | TEST_F(SoftplusV2Grad, SoftplusV2Grad_infershape_same_shape) | ||
| 29 | { | ||
| 30 | ge::op::SoftplusV2Grad op; | ||
| 31 | op.UpdateInputDesc("input_gradients", create_desc({4, 1, 1280}, ge::DT_FLOAT16)); | ||
| 32 | op.UpdateInputDesc("input_features", create_desc({4, 1, 1280}, ge::DT_FLOAT16)); | ||
| 33 | |||
| 34 | EXPECT_EQ(InferShapeTest(op), ge::GRAPH_SUCCESS); | ||
| 35 | } | ||
| 36 | |||
| 37 | // 可广播 shape: {4,1,1280} + {1,3,1280} → {4,3,1280} | ||
| 38 | TEST_F(SoftplusV2Grad, SoftplusV2Grad_infershape_broadcast) | ||
| 39 | { | ||
| 40 | ge::op::SoftplusV2Grad op; | ||
| 41 | op.UpdateInputDesc("input_gradients", create_desc({4, 1, 1280}, ge::DT_FLOAT)); | ||
| 42 | op.UpdateInputDesc("input_features", create_desc({1, 3, 1280}, ge::DT_FLOAT)); | ||
| 43 | |||
| 44 | EXPECT_EQ(InferShapeTest(op), ge::GRAPH_SUCCESS); | ||
| 45 | } | ||
| 46 | |||
| 47 | // rank 不同 + 标量广播: {2,3,4} + {4} | ||
| 48 | TEST_F(SoftplusV2Grad, SoftplusV2Grad_infershape_rank_diff) | ||
| 49 | { | ||
| 50 | ge::op::SoftplusV2Grad op; | ||
| 51 | op.UpdateInputDesc("input_gradients", create_desc({2, 3, 4}, ge::DT_BF16)); | ||
| 52 | op.UpdateInputDesc("input_features", create_desc({4}, ge::DT_BF16)); | ||
| 53 | |||
| 54 | EXPECT_EQ(InferShapeTest(op), ge::GRAPH_SUCCESS); | ||
| 55 | } | ||
Ractivation/softplus_v2_grad/op_host/CMakeLists.txt→activation/softplus_v2_grad/tests/ut/op_kernel/CMakeLists.txt+8-5
| @@ -1,9 +1,12 @@ | |||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 1 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. |
| 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 2 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 3 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 7 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | #/ | 8 | # Generated By CANNBot |
| 9 | add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE softplus_v2_grad ACLNNTYPE aclnn) | 9 | |
| 10 | if ((UT_TEST_ALL OR OP_KERNEL_UT) AND NOT UT_DONE) | ||
| 11 | AddOpTestCase(softplus_v2_grad "ascend950pr_9599" "-DDTYPE_INPUT_GRADIENTS=float") | ||
| 12 | endif() | ||
| @@ -0,0 +1,76 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 9 | # See LICENSE in the root of the software repository for the full text of the License. | ||
| 10 | |||
| 11 | # Generated By CANNBot | ||
| 12 | # | ||
| 13 | # Compares <tag>_npuout.bin against <tag>_golden.bin. | ||
| 14 | # Usage: python3 compare_data.py <tag> <dtype> | ||
| 15 | # Exit code 0 on PASS, 1 on FAIL (so the C++ harness ExecuteCommand detects failures). | ||
| 16 | |||
| 17 | import sys | ||
| 18 | import os | ||
| 19 | import numpy as np | ||
| 20 | |||
| 21 | curr_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| 22 | |||
| 23 | |||
| 24 | def bf16_u16_to_fp32(arr_u16): | ||
| 25 | u32 = arr_u16.astype(np.uint32) << 16 | ||
| 26 | return u32.view(np.float32) | ||
| 27 | |||
| 28 | |||
| 29 | def compare(tag, dtype): | ||
| 30 | golden_file = os.path.join(curr_dir, f"{tag}_golden.bin") | ||
| 31 | out_file = os.path.join(curr_dir, f"{tag}_npuout.bin") | ||
| 32 | |||
| 33 | if not os.path.exists(golden_file) or not os.path.exists(out_file): | ||
| 34 | print(f"COMPARE DATA FAILED! missing file: {golden_file} or {out_file}") | ||
| 35 | return False | ||
| 36 | |||
| 37 | if dtype == "float32": | ||
| 38 | rtol, atol = 1e-4, 1e-5 | ||
| 39 | g = np.fromfile(golden_file, np.float32) | ||
| 40 | o = np.fromfile(out_file, np.float32) | ||
| 41 | elif dtype == "float16": | ||
| 42 | rtol, atol = 1e-2, 1e-3 | ||
| 43 | g = np.fromfile(golden_file, np.float16).astype(np.float32) | ||
| 44 | o = np.fromfile(out_file, np.float16).astype(np.float32) | ||
| 45 | elif dtype == "bfloat16": | ||
| 46 | rtol, atol = 1e-2, 1e-2 | ||
| 47 | g = bf16_u16_to_fp32(np.fromfile(golden_file, np.uint16)) | ||
| 48 | o = bf16_u16_to_fp32(np.fromfile(out_file, np.uint16)) | ||
| 49 | else: | ||
| 50 | print(f"COMPARE DATA FAILED! unsupported dtype {dtype}") | ||
| 51 | return False | ||
| 52 | |||
| 53 | if g.shape != o.shape: | ||
| 54 | print(f"COMPARE DATA FAILED! shape mismatch golden={g.shape} out={o.shape}") | ||
| 55 | return False | ||
| 56 | |||
| 57 | close = np.isclose(o, g, rtol=rtol, atol=atol, equal_nan=True) | ||
| 58 | bad = np.where(~close)[0] | ||
| 59 | if len(bad) == 0: | ||
| 60 | print("COMPARE DATA PASSED!") | ||
| 61 | return True | ||
| 62 | |||
| 63 | print( | ||
| 64 | f"COMPARE DATA FAILED! {len(bad)}/{g.size} mismatches (rtol={rtol}, atol={atol})" | ||
| 65 | ) | ||
| 66 | for idx in bad[:8]: | ||
| 67 | print(f" index {idx}: out={o[idx]} golden={g[idx]}") | ||
| 68 | return False | ||
| 69 | |||
| 70 | |||
| 71 | if __name__ == "__main__": | ||
| 72 | if len(sys.argv) != 3: | ||
| 73 | print("Usage: python3 compare_data.py <tag> <dtype>") | ||
| 74 | sys.exit(1) | ||
| 75 | ok = compare(sys.argv[1], sys.argv[2]) | ||
| 76 | sys.exit(0 if ok else 1) | ||
| @@ -0,0 +1,102 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 9 | # See LICENSE in the root of the software repository for the full text of the License. | ||
| 10 | |||
| 11 | # Generated By CANNBot | ||
| 12 | # | ||
| 13 | # SoftplusV2Grad golden data generator. | ||
| 14 | # gradInput = gradOut * ( 1/(1+exp(-beta*self)) if beta*self <= threshold | ||
| 15 | # else 1 ) | ||
| 16 | # Broadcasting of gradOut / features to out shape is supported (numpy semantics). | ||
| 17 | # | ||
| 18 | # Usage: | ||
| 19 | # python3 gen_data.py <tag> <grad_shape> <feat_shape> <out_shape> <dtype> <beta> <threshold> | ||
| 20 | # Example: | ||
| 21 | # python3 gen_data.py case1 '(4,64)' '(4,64)' '(4,64)' float32 1.0 20.0 | ||
| 22 | # | ||
| 23 | # Files written (in cwd): | ||
| 24 | # <tag>_grad.bin, <tag>_features.bin, <tag>_golden.bin | ||
| 25 | |||
| 26 | import sys | ||
| 27 | import numpy as np | ||
| 28 | |||
| 29 | |||
| 30 | def parse_shape(shape_str): | ||
| 31 | s = shape_str.strip().strip("'").strip('"').strip("(").strip(")") | ||
| 32 | parts = [p for p in s.replace(" ", "").split(",") if p != ""] | ||
| 33 | return tuple(int(x) for x in parts) | ||
| 34 | |||
| 35 | |||
| 36 | def fp32_to_bf16_u16(arr_fp32): | ||
| 37 | # Truncate fp32 to bf16 by taking the high 16 bits (little-endian: bytes 2..4). | ||
| 38 | arr_fp32 = np.ascontiguousarray(arr_fp32.astype(np.float32)) | ||
| 39 | u32 = arr_fp32.view(np.uint32) | ||
| 40 | return (u32 >> 16).astype(np.uint16) | ||
| 41 | |||
| 42 | |||
| 43 | def bf16_u16_to_fp32(arr_u16): | ||
| 44 | u32 = arr_u16.astype(np.uint32) << 16 | ||
| 45 | return u32.view(np.float32) | ||
| 46 | |||
| 47 | |||
| 48 | def softplus_v2_grad_golden(grad_f32, feat_f32, beta, threshold): | ||
| 49 | bx = beta * feat_f32 | ||
| 50 | sig = 1.0 / (1.0 + np.exp(-bx)) | ||
| 51 | # where beta*self <= threshold use sigmoid, else pass gradient through (factor 1). | ||
| 52 | factor = np.where(bx <= threshold, sig, np.ones_like(sig)) | ||
| 53 | return grad_f32 * factor | ||
| 54 | |||
| 55 | |||
| 56 | def gen(tag, grad_shape, feat_shape, out_shape, dtype, beta, threshold): | ||
| 57 | np.random.seed(1234 + (abs(hash(tag)) % 100000)) | ||
| 58 | |||
| 59 | # features spread wide enough (with beta) to straddle the threshold on both sides. | ||
| 60 | feat_fp32 = np.random.uniform(-6.0, 6.0, feat_shape).astype(np.float32) | ||
| 61 | grad_fp32 = np.random.uniform(-2.0, 2.0, grad_shape).astype(np.float32) | ||
| 62 | |||
| 63 | if dtype == "bfloat16": | ||
| 64 | # Round inputs to bf16 first, then compute golden on the rounded values. | ||
| 65 | feat_u16 = fp32_to_bf16_u16(feat_fp32) | ||
| 66 | grad_u16 = fp32_to_bf16_u16(grad_fp32) | ||
| 67 | feat_r = bf16_u16_to_fp32(feat_u16) | ||
| 68 | grad_r = bf16_u16_to_fp32(grad_u16) | ||
| 69 | golden = softplus_v2_grad_golden(grad_r, feat_r, beta, threshold) | ||
| 70 | golden_b = np.broadcast_to(golden, out_shape) | ||
| 71 | grad_u16.reshape(grad_shape).tofile(f"./{tag}_grad.bin") | ||
| 72 | feat_u16.reshape(feat_shape).tofile(f"./{tag}_features.bin") | ||
| 73 | fp32_to_bf16_u16(golden_b).reshape(out_shape).tofile(f"./{tag}_golden.bin") | ||
| 74 | return | ||
| 75 | |||
| 76 | np_dtype = {"float32": np.float32, "float16": np.float16}[dtype] | ||
| 77 | feat_c = feat_fp32.astype(np_dtype) | ||
| 78 | grad_c = grad_fp32.astype(np_dtype) | ||
| 79 | golden = softplus_v2_grad_golden( | ||
| 80 | grad_c.astype(np.float32), feat_c.astype(np.float32), beta, threshold | ||
| 81 | ).astype(np_dtype) | ||
| 82 | golden_b = np.broadcast_to(golden, out_shape) | ||
| 83 | grad_c.tofile(f"./{tag}_grad.bin") | ||
| 84 | feat_c.tofile(f"./{tag}_features.bin") | ||
| 85 | np.ascontiguousarray(golden_b).tofile(f"./{tag}_golden.bin") | ||
| 86 | |||
| 87 | |||
| 88 | if __name__ == "__main__": | ||
| 89 | if len(sys.argv) != 8: | ||
| 90 | print( | ||
| 91 | "Usage: python3 gen_data.py <tag> <grad_shape> <feat_shape> " | ||
| 92 | "<out_shape> <dtype> <beta> <threshold>" | ||
| 93 | ) | ||
| 94 | sys.exit(1) | ||
| 95 | tag = sys.argv[1] | ||
| 96 | gs = parse_shape(sys.argv[2]) | ||
| 97 | fs = parse_shape(sys.argv[3]) | ||
| 98 | os_ = parse_shape(sys.argv[4]) | ||
| 99 | dt = sys.argv[5] | ||
| 100 | be = float(sys.argv[6]) | ||
| 101 | th = float(sys.argv[7]) | ||
| 102 | gen(tag, gs, fs, os_, dt, be, th) | ||
| @@ -0,0 +1,34 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | // UT tiling-definition shim for softplus_v2_grad. | ||
| 14 | // | ||
| 15 | // The op_kernel entry uses REGISTER_NONE_TILING, which the build-system tiling-header | ||
| 16 | // generator does not recognize (it only handles REGISTER_TILING_DEFAULT / BroadcastSch), | ||
| 17 | // so GET_TILING_DATA_WITH_STRUCT is not auto-generated for this op. When this | ||
| 18 | // <op>_tiling_def.h exists, ut.cmake force-includes it (and skips generation), so we | ||
| 19 | // define the macro here. The kernel simply needs a local TilingData struct populated | ||
| 20 | // from the raw tiling GM buffer; a byte copy is exactly what the generated macro does | ||
| 21 | // (minus the internal REGISTER_TILINGDATA_SIZE bookkeeping, which is unnecessary for UT). | ||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | |||
| 28 | |||
| 29 | |||
| 30 | tiling_struct tiling_data; \ | ||
| 31 | std::memcpy(reinterpret_cast<void*>(&tiling_data), reinterpret_cast<const void*>(tiling_arg), sizeof(tiling_struct)) | ||
| 32 | |||
| 33 | |||
| 34 | |||
| @@ -0,0 +1,438 @@ | |||
| 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 | * Generated By CANNBot | ||
| 11 | */ | ||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | // Bring in the real kernel entry (defines softplus_v2_grad<RANK> for DTYPE_INPUT_GRADIENTS=float) | ||
| 26 | // as well as the kernel class / tiling struct headers it includes. | ||
| 27 | |||
| 28 | |||
| 29 | using namespace std; | ||
| 30 | |||
| 31 | // ============================================================ | ||
| 32 | // Host-side re-implementation of the tiling math (mirrors | ||
| 33 | // op_host/arch35/softplus_v2_grad_tiling_arch35.cpp) so that the | ||
| 34 | // TilingData handed to the kernel is byte-for-byte what the real | ||
| 35 | // host tiling would produce. This is metadata construction only; | ||
| 36 | // the kernel under test is the real implementation. | ||
| 37 | // ============================================================ | ||
| 38 | namespace svg_ut { | ||
| 39 | |||
| 40 | constexpr int64_t kUB = 253952; // UB size (matches host compile info UB_SIZE) | ||
| 41 | |||
| 42 | // FindSplitAxis — verbatim algorithm from host tiling. | ||
| 43 | static bool FindSplitAxis(const std::vector<int64_t>& max_bro_shape, int64_t dtype_size, int64_t ub_per_core, | ||
| 44 | int64_t phys_nodes, SplitResult& out) | ||
| 45 | { | ||
| 46 | if (phys_nodes <= 0 || dtype_size <= 0) | ||
| 47 | return false; | ||
| 48 | int64_t per_buf_bytes = (ub_per_core / phys_nodes) & ~(kUbAlignBytes - 1); | ||
| 49 | int64_t per_buf_elems = per_buf_bytes / dtype_size; | ||
| 50 | if (per_buf_elems <= 0) | ||
| 51 | return false; | ||
| 52 | int64_t rank = (int64_t)max_bro_shape.size(); | ||
| 53 | int64_t inner = 1; | ||
| 54 | for (int64_t k = rank - 1; k >= 0; k--) { | ||
| 55 | if (max_bro_shape[k] * inner > per_buf_elems) { | ||
| 56 | out.a_i = per_buf_elems / inner; | ||
| 57 | if (out.a_i <= 0) | ||
| 58 | return false; | ||
| 59 | out.a_o = (max_bro_shape[k] + out.a_i - 1) / out.a_i; | ||
| 60 | int64_t rem = max_bro_shape[k] % out.a_i; | ||
| 61 | out.a_i_tail = (rem == 0) ? out.a_i : rem; | ||
| 62 | out.axis = k; | ||
| 63 | return true; | ||
| 64 | } | ||
| 65 | if (k == 0) { | ||
| 66 | out.axis = 0; | ||
| 67 | out.a_i = max_bro_shape[0]; | ||
| 68 | out.a_o = 1; | ||
| 69 | out.a_i_tail = max_bro_shape[0]; | ||
| 70 | return true; | ||
| 71 | } | ||
| 72 | inner *= max_bro_shape[k]; | ||
| 73 | } | ||
| 74 | return true; | ||
| 75 | } | ||
| 76 | |||
| 77 | // MultiCoreSplit — verbatim algorithm from host tiling. | ||
| 78 | static bool MultiCoreSplit(const std::vector<int64_t>& max_bro_shape, const SplitResult& ub_split, int64_t max_cores, | ||
| 79 | MultiCoreResult& out) | ||
| 80 | { | ||
| 81 | int64_t k = ub_split.axis, outer_prod = 1; | ||
| 82 | for (int64_t j = 0; j < k; j++) | ||
| 83 | outer_prod *= max_bro_shape[j]; | ||
| 84 | out.total_tiles = outer_prod * ub_split.a_o; | ||
| 85 | out.num_cores = (out.total_tiles < max_cores) ? out.total_tiles : max_cores; | ||
| 86 | if (out.num_cores <= 0) | ||
| 87 | return false; | ||
| 88 | out.tiles_main = out.total_tiles / out.num_cores; | ||
| 89 | out.cores_tail = out.total_tiles % out.num_cores; | ||
| 90 | return true; | ||
| 91 | } | ||
| 92 | |||
| 93 | // PrecomputeStrides — verbatim from host tiling (size-1 dims -> stride 0). | ||
| 94 | static void PrecomputeStrides(const std::vector<int64_t>& s, std::vector<int64_t>& strides) | ||
| 95 | { | ||
| 96 | int64_t rank = (int64_t)s.size(); | ||
| 97 | strides.assign(rank, 0); | ||
| 98 | for (int64_t d = rank - 1; d >= 0; d--) { | ||
| 99 | if (s[d] == 1) { | ||
| 100 | strides[d] = 0; | ||
| 101 | continue; | ||
| 102 | } | ||
| 103 | int64_t prod = 1; | ||
| 104 | for (int64_t j = d + 1; j < rank; j++) | ||
| 105 | prod *= s[j]; | ||
| 106 | strides[d] = prod; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | // Front-pad src[0..n) into dst[delta..delta+n), dst[0..delta)=padValue. | ||
| 111 | static void PadRow(int64_t* dst, const int64_t* src, int64_t n, int64_t delta, int64_t padValue) | ||
| 112 | { | ||
| 113 | for (int64_t d = 0; d < delta; d++) | ||
| 114 | dst[d] = padValue; | ||
| 115 | for (int64_t d = 0; d < n; d++) | ||
| 116 | dst[d + delta] = src[d]; | ||
| 117 | } | ||
| 118 | |||
| 119 | // Build a SoftplusV2GradTilingData<R> from already-squeezed max_bro_shape + per-slot normal | ||
| 120 | // shapes (all rank_ length, no dims squeezed for the shapes chosen in these tests). | ||
| 121 | // Returns false if tiling is infeasible. | ||
| 122 | template <int64_t R> | ||
| 123 | static bool BuildTiling(uint8_t* buf, const std::vector<int64_t>& max_bro_shape, | ||
| 124 | const std::vector<std::vector<int64_t>>& in_shapes, const std::vector<int64_t>& out_shape, | ||
| 125 | float beta, float threshold, int64_t core_num) | ||
| 126 | { | ||
| 127 | auto* t = reinterpret_cast<SoftplusV2GradTilingData<R>*>(buf); | ||
| 128 | int64_t rank_ = (int64_t)max_bro_shape.size(); | ||
| 129 | int64_t delta = R - rank_; | ||
| 130 | if (delta < 0) | ||
| 131 | return false; | ||
| 132 | |||
| 133 | int64_t per_buf_bytes = (kUB / kPhysNodes) & ~(kUbAlignBytes - 1); | ||
| 134 | if (!FindSplitAxis(max_bro_shape, sizeof(float), kUB, kPhysNodes, t->split)) | ||
| 135 | return false; | ||
| 136 | if (!MultiCoreSplit(max_bro_shape, t->split, core_num, t->multicore)) | ||
| 137 | return false; | ||
| 138 | |||
| 139 | t->per_buf_bytes = per_buf_bytes; | ||
| 140 | t->beta = beta; | ||
| 141 | t->threshold = threshold; | ||
| 142 | t->rank = rank_; | ||
| 143 | t->num_inputs = (int64_t)in_shapes.size(); | ||
| 144 | t->num_outputs = 1; | ||
| 145 | |||
| 146 | // max_bro_shape: front-pad 1. | ||
| 147 | PadRow(t->max_bro_shape, max_bro_shape.data(), rank_, delta, 1); | ||
| 148 | // split axis shifted right by delta. | ||
| 149 | t->split.axis += delta; | ||
| 150 | |||
| 151 | // input slots | ||
| 152 | for (int64_t i = 0; i < kMaxInputSlots; i++) { | ||
| 153 | if (i < (int64_t)in_shapes.size()) { | ||
| 154 | std::vector<int64_t> st; | ||
| 155 | PrecomputeStrides(in_shapes[i], st); | ||
| 156 | PadRow(t->input_shapes[i], in_shapes[i].data(), rank_, delta, 1); | ||
| 157 | PadRow(t->input_strides[i], st.data(), rank_, delta, 0); | ||
| 158 | } else { | ||
| 159 | for (int64_t d = 0; d < R; d++) { | ||
| 160 | t->input_shapes[i][d] = 1; | ||
| 161 | t->input_strides[i][d] = 0; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | // output slot 0 | ||
| 166 | { | ||
| 167 | std::vector<int64_t> st; | ||
| 168 | PrecomputeStrides(out_shape, st); | ||
| 169 | PadRow(t->output_shapes[0], out_shape.data(), rank_, delta, 1); | ||
| 170 | PadRow(t->output_strides[0], st.data(), rank_, delta, 0); | ||
| 171 | } | ||
| 172 | return true; | ||
| 173 | } | ||
| 174 | |||
| 175 | } // namespace svg_ut | ||
| 176 | |||
| 177 | // ============================================================ | ||
| 178 | // Direct-invocation wrappers around the real kernel class. | ||
| 179 | // These call the exact implementation in | ||
| 180 | // op_kernel/arch35/softplus_v2_grad_kernel.h with the requested | ||
| 181 | // dtype/RANK, letting one binary cover fp32 + fp16 + bf16. | ||
| 182 | // ============================================================ | ||
| 183 | template <typename T, int64_t RANK> | ||
| 184 | __global__ __aicore__ void RunSoftplusKernel(GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR workspace, GM_ADDR tiling) | ||
| 185 | { | ||
| 186 | KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); | ||
| 187 | GM_ADDR ins[kMaxInputSlots] = {grad, feat}; | ||
| 188 | GM_ADDR outs[kMaxOutputSlots] = {out}; | ||
| 189 | const auto* td = reinterpret_cast<const SoftplusV2GradTilingData<RANK>*>(tiling); | ||
| 190 | SoftplusV2GradKernel<T, RANK> kernel; | ||
| 191 | kernel.Init(ins, outs, td); | ||
| 192 | kernel.Process(); | ||
| 193 | } | ||
| 194 | |||
| 195 | namespace { | ||
| 196 | |||
| 197 | const char* kDataDirRel = "activation/softplus_v2_grad/tests/ut/op_kernel/softplus_v2_grad_data"; | ||
| 198 | const char* kDataLocal = "softplus_v2_grad_data"; | ||
| 199 | |||
| 200 | size_t Prod(const std::vector<int64_t>& s) | ||
| 201 | { | ||
| 202 | size_t p = 1; | ||
| 203 | for (auto v : s) | ||
| 204 | p *= (size_t)v; | ||
| 205 | return p; | ||
| 206 | } | ||
| 207 | |||
| 208 | // dtype tags used by gen_data.py / compare_data.py and their element byte sizes. | ||
| 209 | struct DTypeInfo { | ||
| 210 | const char* pyName; | ||
| 211 | size_t bytes; | ||
| 212 | }; | ||
| 213 | |||
| 214 | class softplus_v2_grad_test : public testing::Test { | ||
| 215 | protected: | ||
| 216 | static void SetUpTestCase() { cout << "softplus_v2_grad_test SetUp\n" << endl; } | ||
| 217 | static void TearDownTestCase() | ||
| 218 | { | ||
| 219 | cout << "softplus_v2_grad_test TearDown\n" << endl; | ||
| 220 | kernel_ut::CleanGeneratedBinFiles("./softplus_v2_grad_data"); | ||
| 221 | } | ||
| 222 | }; | ||
| 223 | |||
| 224 | // Shared driver: generate data, build tiling, run kernel via ICPU_RUN_KF, compare golden. | ||
| 225 | // KernelInvoker is a callable (lambda) matching the ICPU_RUN_KF signature. | ||
| 226 | template <typename KernelInvoker> | ||
| 227 | void RunAndVerify(const std::string& tag, const std::vector<int64_t>& grad_shape, | ||
| 228 | const std::vector<int64_t>& feat_shape, const std::vector<int64_t>& out_shape, const DTypeInfo& dt, | ||
| 229 | float beta, float threshold, uint32_t blockDim, uint8_t* tiling, KernelInvoker invoker) | ||
| 230 | { | ||
| 231 | kernel_ut::SetupTestEnvironment(kDataDirRel, kDataLocal); | ||
| 232 | |||
| 233 | auto shapeStr = [](const std::vector<int64_t>& s) { | ||
| 234 | std::string r = "'("; | ||
| 235 | for (size_t i = 0; i < s.size(); i++) { | ||
| 236 | r += std::to_string(s[i]); | ||
| 237 | if (i + 1 < s.size()) | ||
| 238 | r += ","; | ||
| 239 | } | ||
| 240 | r += ")'"; | ||
| 241 | return r; | ||
| 242 | }; | ||
| 243 | |||
| 244 | kernel_ut::RunGenData("./softplus_v2_grad_data", | ||
| 245 | {tag, shapeStr(grad_shape), shapeStr(feat_shape), shapeStr(out_shape), dt.pyName, | ||
| 246 | std::to_string(beta), std::to_string(threshold)}); | ||
| 247 | |||
| 248 | std::string path = kernel_ut::GetTestWorkDir(); | ||
| 249 | size_t gradBytes = Prod(grad_shape) * dt.bytes; | ||
| 250 | size_t featBytes = Prod(feat_shape) * dt.bytes; | ||
| 251 | size_t outBytes = Prod(out_shape) * dt.bytes; | ||
| 252 | |||
| 253 | uint8_t* grad = (uint8_t*)AscendC::GmAlloc(gradBytes); | ||
| 254 | uint8_t* feat = (uint8_t*)AscendC::GmAlloc(featBytes); | ||
| 255 | uint8_t* out = (uint8_t*)AscendC::GmAlloc(outBytes); | ||
| 256 | uint8_t* workspace = (uint8_t*)AscendC::GmAlloc(16 * 1024 * 1024); | ||
| 257 | |||
| 258 | ReadFile(path + "/softplus_v2_grad_data/" + tag + "_grad.bin", gradBytes, grad, gradBytes); | ||
| 259 | ReadFile(path + "/softplus_v2_grad_data/" + tag + "_features.bin", featBytes, feat, featBytes); | ||
| 260 | |||
| 261 | AscendC::SetKernelMode(KernelMode::AIV_MODE); | ||
| 262 | ICPU_SET_TILING_KEY(0); | ||
| 263 | ICPU_RUN_KF(invoker, blockDim, grad, feat, out, workspace, tiling); | ||
| 264 | |||
| 265 | WriteFile(path + "/softplus_v2_grad_data/" + tag + "_npuout.bin", out, outBytes); | ||
| 266 | |||
| 267 | AscendC::GmFree(grad); | ||
| 268 | AscendC::GmFree(feat); | ||
| 269 | AscendC::GmFree(out); | ||
| 270 | AscendC::GmFree(workspace); | ||
| 271 | |||
| 272 | // compare_data.py exits non-zero on mismatch; RunCompareData returns false in that case. | ||
| 273 | bool ok = kernel_ut::RunCompareData("./softplus_v2_grad_data", {tag, dt.pyName}); | ||
| 274 | EXPECT_TRUE(ok) << "golden compare failed for tag=" << tag; | ||
| 275 | } | ||
| 276 | |||
| 277 | const DTypeInfo kFp32{"float32", 4}; | ||
| 278 | const DTypeInfo kFp16{"float16", 2}; | ||
| 279 | const DTypeInfo kBf16{"bfloat16", 2}; | ||
| 280 | |||
| 281 | // ---- Case 1: fp32, {4,64}, default attrs -> ProcessFP32 + VF formula branch, RANK_4 (NDDMA branch) | ||
| 282 | TEST_F(softplus_v2_grad_test, case1_fp32_rank2_formula) | ||
| 283 | { | ||
| 284 | std::vector<int64_t> g{4, 64}, f{4, 64}, o{4, 64}; | ||
| 285 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 286 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 1))); | ||
| 287 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 288 | RunSoftplusKernel<float, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 289 | }; | ||
| 290 | RunAndVerify("case1", g, f, o, kFp32, 1.0f, 20.0f, 1, tiling, inv); | ||
| 291 | AscendC::GmFree(tiling); | ||
| 292 | } | ||
| 293 | |||
| 294 | // ---- Case 2: fp32, small threshold -> exercises BOTH Select branches of the VF | ||
| 295 | TEST_F(softplus_v2_grad_test, case2_fp32_threshold_both_branches) | ||
| 296 | { | ||
| 297 | std::vector<int64_t> g{8, 64}, f{8, 64}, o{8, 64}; | ||
| 298 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 299 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 1.0f, 1))); | ||
| 300 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 301 | RunSoftplusKernel<float, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 302 | }; | ||
| 303 | RunAndVerify("case2", g, f, o, kFp32, 1.0f, 1.0f, 1, tiling, inv); | ||
| 304 | AscendC::GmFree(tiling); | ||
| 305 | } | ||
| 306 | |||
| 307 | // ---- Case 3: fp16 -> ProcessFP16BF16 + Cast NONE/RINT | ||
| 308 | TEST_F(softplus_v2_grad_test, case3_fp16_rank2) | ||
| 309 | { | ||
| 310 | std::vector<int64_t> g{8, 128}, f{8, 128}, o{8, 128}; | ||
| 311 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 312 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 1))); | ||
| 313 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 314 | RunSoftplusKernel<half, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 315 | }; | ||
| 316 | RunAndVerify("case3", g, f, o, kFp16, 1.0f, 20.0f, 1, tiling, inv); | ||
| 317 | AscendC::GmFree(tiling); | ||
| 318 | } | ||
| 319 | |||
| 320 | // ---- Case 4: bf16 -> ProcessFP16BF16 bf16 | ||
| 321 | TEST_F(softplus_v2_grad_test, case4_bf16_rank2) | ||
| 322 | { | ||
| 323 | std::vector<int64_t> g{8, 128}, f{8, 128}, o{8, 128}; | ||
| 324 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 325 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 1))); | ||
| 326 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 327 | RunSoftplusKernel<bfloat16_t, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 328 | }; | ||
| 329 | RunAndVerify("case4", g, f, o, kBf16, 1.0f, 20.0f, 1, tiling, inv); | ||
| 330 | AscendC::GmFree(tiling); | ||
| 331 | } | ||
| 332 | |||
| 333 | // ---- Case 5: broadcast g{4,1,8} f{1,3,8} out{4,3,8} -> CopyInBrc broadcast strides, RANK_4 | ||
| 334 | TEST_F(softplus_v2_grad_test, case5_fp32_broadcast) | ||
| 335 | { | ||
| 336 | std::vector<int64_t> g{4, 1, 8}, f{1, 3, 8}, o{4, 3, 8}; | ||
| 337 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 338 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 1))); | ||
| 339 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 340 | RunSoftplusKernel<float, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 341 | }; | ||
| 342 | RunAndVerify("case5", g, f, o, kFp32, 1.0f, 20.0f, 1, tiling, inv); | ||
| 343 | AscendC::GmFree(tiling); | ||
| 344 | } | ||
| 345 | |||
| 346 | // ---- Case 6: rank5 -> RANK_8 template, CopyInBrc flat-loop branch (R=8 > kMaxNdDmaDims) | ||
| 347 | TEST_F(softplus_v2_grad_test, case6_fp32_rank5) | ||
| 348 | { | ||
| 349 | std::vector<int64_t> s{2, 3, 2, 3, 4}; | ||
| 350 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_8>)); | ||
| 351 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_8>(tiling, s, {s, s}, s, 1.0f, 20.0f, 1))); | ||
| 352 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 353 | RunSoftplusKernel<float, SOFTPLUS_V2_GRAD_RANK_8>(grad, feat, out, ws, t); | ||
| 354 | }; | ||
| 355 | RunAndVerify("case6", s, s, s, kFp32, 1.0f, 20.0f, 1, tiling, inv); | ||
| 356 | AscendC::GmFree(tiling); | ||
| 357 | } | ||
| 358 | |||
| 359 | // ---- Case 7: rank6, explicit beta/threshold -> RANK_8 flat-loop, mixed Select branches | ||
| 360 | TEST_F(softplus_v2_grad_test, case7_fp32_rank6_attrs) | ||
| 361 | { | ||
| 362 | std::vector<int64_t> s{2, 2, 2, 2, 2, 4}; | ||
| 363 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_8>)); | ||
| 364 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_8>(tiling, s, {s, s}, s, 2.0f, 5.0f, 1))); | ||
| 365 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 366 | RunSoftplusKernel<float, SOFTPLUS_V2_GRAD_RANK_8>(grad, feat, out, ws, t); | ||
| 367 | }; | ||
| 368 | RunAndVerify("case7", s, s, s, kFp32, 2.0f, 5.0f, 1, tiling, inv); | ||
| 369 | AscendC::GmFree(tiling); | ||
| 370 | } | ||
| 371 | |||
| 372 | // ---- Case 8a/8b: apt.cpp entry (real softplus_v2_grad<RANK>) covers RANK dispatch + GET_TILING_DATA | ||
| 373 | TEST_F(softplus_v2_grad_test, case8_apt_entry_rank4) | ||
| 374 | { | ||
| 375 | std::vector<int64_t> g{4, 64}, f{4, 64}, o{4, 64}; | ||
| 376 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 377 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 1))); | ||
| 378 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 379 | ::softplus_v2_grad<SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 380 | }; | ||
| 381 | RunAndVerify("case8a", g, f, o, kFp32, 1.0f, 20.0f, 1, tiling, inv); | ||
| 382 | AscendC::GmFree(tiling); | ||
| 383 | } | ||
| 384 | |||
| 385 | TEST_F(softplus_v2_grad_test, case8_apt_entry_rank8) | ||
| 386 | { | ||
| 387 | std::vector<int64_t> s{2, 3, 2, 3, 4}; | ||
| 388 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_8>)); | ||
| 389 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_8>(tiling, s, {s, s}, s, 1.0f, 20.0f, 1))); | ||
| 390 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 391 | ::softplus_v2_grad<SOFTPLUS_V2_GRAD_RANK_8>(grad, feat, out, ws, t); | ||
| 392 | }; | ||
| 393 | RunAndVerify("case8b", s, s, s, kFp32, 1.0f, 20.0f, 1, tiling, inv); | ||
| 394 | AscendC::GmFree(tiling); | ||
| 395 | } | ||
| 396 | |||
| 397 | // ---- Case 9: multi-core (coreNum=4, not divisible) -> GetCoreRange tail-branch coverage | ||
| 398 | TEST_F(softplus_v2_grad_test, case9_fp32_multicore) | ||
| 399 | { | ||
| 400 | std::vector<int64_t> g{10, 64}, f{10, 64}, o{10, 64}; | ||
| 401 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 402 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 4))); | ||
| 403 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 404 | RunSoftplusKernel<float, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 405 | }; | ||
| 406 | RunAndVerify("case9", g, f, o, kFp32, 1.0f, 20.0f, 4, tiling, inv); | ||
| 407 | AscendC::GmFree(tiling); | ||
| 408 | } | ||
| 409 | |||
| 410 | // ---- Case 10: fp32 UB-split (a_o>1) + non-divisible cores -> ProcessFP32 multi-tile-per-core | ||
| 411 | // (covers GetCoreRange cores_tail branch and the "flat != end-1" MTE3_MTE2 SetFlag) | ||
| 412 | TEST_F(softplus_v2_grad_test, case10_fp32_ubsplit_multitile) | ||
| 413 | { | ||
| 414 | std::vector<int64_t> g{2, 20000}, f{2, 20000}, o{2, 20000}; | ||
| 415 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 416 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 3))); | ||
| 417 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 418 | RunSoftplusKernel<float, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 419 | }; | ||
| 420 | RunAndVerify("case10", g, f, o, kFp32, 1.0f, 20.0f, 3, tiling, inv); | ||
| 421 | AscendC::GmFree(tiling); | ||
| 422 | } | ||
| 423 | |||
| 424 | // ---- Case 11: fp16 UB-split (a_o>1) + non-divisible cores -> ProcessFP16BF16 multi-tile-per-core | ||
| 425 | // (covers the fp16/bf16 path "flat != end-1" MTE3_MTE2 SetFlag) | ||
| 426 | TEST_F(softplus_v2_grad_test, case11_fp16_ubsplit_multitile) | ||
| 427 | { | ||
| 428 | std::vector<int64_t> g{2, 20000}, f{2, 20000}, o{2, 20000}; | ||
| 429 | uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(SoftplusV2GradTilingData<SOFTPLUS_V2_GRAD_RANK_4>)); | ||
| 430 | ASSERT_TRUE((svg_ut::BuildTiling<SOFTPLUS_V2_GRAD_RANK_4>(tiling, o, {g, f}, o, 1.0f, 20.0f, 3))); | ||
| 431 | auto inv = [](GM_ADDR grad, GM_ADDR feat, GM_ADDR out, GM_ADDR ws, GM_ADDR t) { | ||
| 432 | RunSoftplusKernel<half, SOFTPLUS_V2_GRAD_RANK_4>(grad, feat, out, ws, t); | ||
| 433 | }; | ||
| 434 | RunAndVerify("case11", g, f, o, kFp16, 1.0f, 20.0f, 3, tiling, inv); | ||
| 435 | AscendC::GmFree(tiling); | ||
| 436 | } | ||
| 437 | |||
| 438 | } // namespace | ||


[High] GetComputeNodeInfo() 返回值未判空即解引用
文件位置:
activation/softplus_v2_grad/op_host/arch35/softplus_v2_grad_tiling_arch35.cpp:233问题说明
ctx_->GetComputeNodeInfo() 返回值在用于 ->GetInputsNum()/->GetOutputsNum() 前未判空,若返回 nullptr 将触发空指针解引用
假设检验分析
H0: GetComputeNodeInfo() 始终返回非空 → H1: 可能返回 nullptr。证据:代码对 compileInfo(第232行)和 shape(第234行)都做了判空,但 GetComputeNodeInfo() 返回值在 ->GetInputsNum()/->GetOutputsNum() 调用前未判空。对照 review_checklist.md §10.2(context指针nullptr检查,84条评审)和 §10.33(GetInputDesc每次调用均需判空),多级指针需逐步检查。校验:若框架异常初始化返回 nullptr,->GetInputsNum() 触发空指针解引用。决策:确认存在指针保护缺失,自信值 75%
代码片段
229: ge::graphStatus SoftplusV2GradTiling::GetShapeInfo() 230: { 231: auto compileInfo = reinterpret_cast<const SoftplusV2GradCompileInfo*>(ctx_->GetCompileInfo()); 232: OP_CHECK_NULL_WITH_CONTEXT(ctx_, compileInfo); 233: for (size_t i = 0; i < ctx_->GetComputeNodeInfo()->GetInputsNum(); ++i) { // <-- 未判空 234: auto shape = ctx_->GetInputShape(i); OP_CHECK_NULL_WITH_CONTEXT(ctx_, shape); ... 240: for (size_t i = 0; i < ctx_->GetComputeNodeInfo()->GetOutputsNum(); ++i) { // <-- 未判空引用规则
cpp-secure.md §3.5 指针操作使用前必须要判空; review_checklist.md §10.2 context指针nullptr检查
建议修复
auto* computeNodeInfo = ctx_->GetComputeNodeInfo(); OP_CHECK_NULL_WITH_CONTEXT(ctx_, computeNodeInfo); for (size_t i = 0; i < computeNodeInfo->GetInputsNum(); ++i) { ... } for (size_t i = 0; i < computeNodeInfo->GetOutputsNum(); ++i) { ... }