Merged
feat: 补充部分算子缺失的 aclnn API 示例 #4575
zhangqijia1Add on Aug 11
feat: 补充部分算子缺失的 aclnn API 示例 #4575
Merged
Total: 25 files changed+1952-468
| @@ -16,11 +16,11 @@ | |||
| 16 | ## 功能说明 | 16 | ## 功能说明 |
| 17 | 17 | ||
| 18 | - 算子功能:根据输入的二维张量,提取由diagonal指定的对角线元素。 | 18 | - 算子功能:根据输入的二维张量,提取由diagonal指定的对角线元素。 |
| 19 | - | 19 | + |
| 20 | 如果diagonal = 0,选择主对角线; | 20 | 如果diagonal = 0,选择主对角线; |
| 21 | - | 21 | + |
| 22 | 如果diagonal > 0,选择主对角线上方的第diagonal条对角线; | 22 | 如果diagonal > 0,选择主对角线上方的第diagonal条对角线; |
| 23 | - | 23 | + |
| 24 | 如果diagonal < 0,选择主对角线下方的第-diagonal条对角线。 | 24 | 如果diagonal < 0,选择主对角线下方的第-diagonal条对角线。 |
| 25 | 25 | ||
| 26 | ## 参数说明 | 26 | ## 参数说明 |
| @@ -76,4 +76,5 @@ | |||
| 76 | 76 | ||
| 77 | | 调用方式 | 调用样例 | 说明 | | 77 | | 调用方式 | 调用样例 | 说明 | |
| 78 | |--------------|------------------------------------------------------------------------|--------------------------------------------------------------| | 78 | |--------------|------------------------------------------------------------------------|--------------------------------------------------------------| |
| 79 | +| aclnn调用 | [test_aclnn_diag](./examples/test_aclnn_diag.cpp) | 通过[aclnnDiag](./docs/aclnnDiag.md)接口方式调用DiagV2算子。 | | ||
| 79 | | 图模式调用 | [test_geir_diag_v2](./examples/test_geir_diag_v2.cpp) | 通过[算子IR](./op_graph/diag_v2_proto.h)构图方式调用DiagV2算子。 | | 80 | | 图模式调用 | [test_geir_diag_v2](./examples/test_geir_diag_v2.cpp) | 通过[算子IR](./op_graph/diag_v2_proto.h)构图方式调用DiagV2算子。 | |
| @@ -0,0 +1,145 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_diag.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 58 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 59 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 60 | + | ||
| 61 | + // 计算连续tensor的strides | ||
| 62 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 63 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 64 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 68 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 69 | + shape.data(), shape.size(), *deviceAddr); | ||
| 70 | + return 0; | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +int main() | ||
| 74 | +{ | ||
| 75 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 76 | + // 根据自己的实际device填写deviceId | ||
| 77 | + int32_t deviceId = 0; | ||
| 78 | + aclrtStream stream; | ||
| 79 | + auto ret = Init(deviceId, &stream); | ||
| 80 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 81 | + | ||
| 82 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 83 | + std::vector<int64_t> selfShape = {2, 2}; | ||
| 84 | + std::vector<int64_t> outShape = {2}; | ||
| 85 | + void* selfDeviceAddr = nullptr; | ||
| 86 | + void* outDeviceAddr = nullptr; | ||
| 87 | + aclTensor* self = nullptr; | ||
| 88 | + aclTensor* out = nullptr; | ||
| 89 | + std::vector<float> selfHostData = {1, 2, 3, 4}; | ||
| 90 | + std::vector<float> outHostData(2, 0); | ||
| 91 | + int64_t diagonalVal = 0; | ||
| 92 | + | ||
| 93 | + // 创建self aclTensor | ||
| 94 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 95 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 96 | + // 创建out aclTensor | ||
| 97 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 98 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 99 | + | ||
| 100 | + // 3.调用CANN算子库API,需要修改为具体的Api名称 | ||
| 101 | + uint64_t workspaceSize = 0; | ||
| 102 | + aclOpExecutor* executor; | ||
| 103 | + // 调用aclnnDiag第一段接口 | ||
| 104 | + ret = aclnnDiagGetWorkspaceSize(self, diagonalVal, out, &workspaceSize, &executor); | ||
| 105 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDiagGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 106 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 107 | + void* workspaceAddr = nullptr; | ||
| 108 | + if (workspaceSize > 0) { | ||
| 109 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 110 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 111 | + } | ||
| 112 | + // 调用aclnnDiag第二段接口 | ||
| 113 | + ret = aclnnDiag(workspaceAddr, workspaceSize, executor, stream); | ||
| 114 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDiag failed. ERROR: %d\n", ret); return ret); | ||
| 115 | + | ||
| 116 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 117 | + ret = aclrtSynchronizeStream(stream); | ||
| 118 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 119 | + | ||
| 120 | + // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 121 | + auto size = GetShapeSize(outShape); | ||
| 122 | + std::vector<float> resultData(size, 0); | ||
| 123 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, | ||
| 124 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 125 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 126 | + for (int64_t i = 0; i < size; i++) { | ||
| 127 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + // 6.释放aclTensor,需要根据具体API的接口定义修改 | ||
| 131 | + aclDestroyTensor(self); | ||
| 132 | + aclDestroyTensor(out); | ||
| 133 | + | ||
| 134 | + // 7.释放Device资源,需要根据具体API的接口定义修改 | ||
| 135 | + aclrtFree(selfDeviceAddr); | ||
| 136 | + aclrtFree(outDeviceAddr); | ||
| 137 | + if (workspaceSize > 0) { | ||
| 138 | + aclrtFree(workspaceAddr); | ||
| 139 | + } | ||
| 140 | + aclrtDestroyStream(stream); | ||
| 141 | + aclrtResetDevice(deviceId); | ||
| 142 | + aclFinalize(); | ||
| 143 | + | ||
| 144 | + return 0; | ||
| 145 | +} | ||
| @@ -123,3 +123,9 @@ | |||
| 123 | ## 约束说明 | 123 | ## 约束说明 |
| 124 | 124 | ||
| 125 | 无 | 125 | 无 |
| 126 | + | ||
| 127 | +## 调用说明 | ||
| 128 | + | ||
| 129 | +| 调用方式 | 调用样例 | 说明 | | ||
| 130 | +|---------|---------|------| | ||
| 131 | +| aclnn调用 | [test_aclnn_amp_update_scale](./examples/test_aclnn_amp_update_scale.cpp) | 通过[aclnnAmpUpdateScale](./docs/aclnnAmpUpdateScale.md)接口方式调用AmpUpdateScale算子。 | | ||
| @@ -0,0 +1,181 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_amp_update_scale.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 58 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 59 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 60 | + | ||
| 61 | + // 计算连续tensor的strides | ||
| 62 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 63 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 64 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 68 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 69 | + shape.data(), shape.size(), *deviceAddr); | ||
| 70 | + return 0; | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +int main() | ||
| 74 | +{ | ||
| 75 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 76 | + // 根据自己的实际device填写deviceId | ||
| 77 | + int32_t deviceId = 0; | ||
| 78 | + aclrtStream stream; | ||
| 79 | + auto ret = Init(deviceId, &stream); | ||
| 80 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 81 | + | ||
| 82 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 83 | + std::vector<int64_t> scalarShape = {1}; | ||
| 84 | + void* currentScaleDeviceAddr = nullptr; | ||
| 85 | + void* growthTrackerDeviceAddr = nullptr; | ||
| 86 | + void* foundInfDeviceAddr = nullptr; | ||
| 87 | + void* updatedScaleDeviceAddr = nullptr; | ||
| 88 | + void* updatedGrowthTrackerDeviceAddr = nullptr; | ||
| 89 | + aclTensor* currentScale = nullptr; | ||
| 90 | + aclTensor* growthTracker = nullptr; | ||
| 91 | + aclTensor* foundInf = nullptr; | ||
| 92 | + aclTensor* updatedScale = nullptr; | ||
| 93 | + aclTensor* updatedGrowthTracker = nullptr; | ||
| 94 | + | ||
| 95 | + // 创建currentScale | ||
| 96 | + std::vector<float> currentScaleHost = {65536.0f}; | ||
| 97 | + ret = CreateAclTensor(currentScaleHost, scalarShape, ¤tScaleDeviceAddr, ACL_FLOAT, ¤tScale); | ||
| 98 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 99 | + | ||
| 100 | + // 创建growthTracker | ||
| 101 | + std::vector<int32_t> growthTrackerHost = {900}; | ||
| 102 | + ret = CreateAclTensor(growthTrackerHost, scalarShape, &growthTrackerDeviceAddr, ACL_INT32, &growthTracker); | ||
| 103 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 104 | + | ||
| 105 | + // 创建foundInf | ||
| 106 | + std::vector<float> foundInfHost = {0.0f}; | ||
| 107 | + ret = CreateAclTensor(foundInfHost, scalarShape, &foundInfDeviceAddr, ACL_FLOAT, &foundInf); | ||
| 108 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 109 | + | ||
| 110 | + // 创建输出updatedScale | ||
| 111 | + std::vector<float> updatedScaleHost = {0.0f}; | ||
| 112 | + ret = CreateAclTensor(updatedScaleHost, scalarShape, &updatedScaleDeviceAddr, ACL_FLOAT, &updatedScale); | ||
| 113 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 114 | + | ||
| 115 | + // 创建输出updatedGrowthTracker | ||
| 116 | + std::vector<int32_t> updatedGrowthTrackerHost = {0}; | ||
| 117 | + ret = CreateAclTensor(updatedGrowthTrackerHost, scalarShape, &updatedGrowthTrackerDeviceAddr, ACL_INT32, | ||
| 118 | + &updatedGrowthTracker); | ||
| 119 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 120 | + | ||
| 121 | + // 3. 调用第一段接口,获取workspace大小和执行器 | ||
| 122 | + float growthFactor = 2.0f; | ||
| 123 | + float backoffFactor = 0.5f; | ||
| 124 | + int64_t growthInterval = 1000; | ||
| 125 | + | ||
| 126 | + uint64_t workspaceSize = 0; | ||
| 127 | + aclOpExecutor* executor = nullptr; | ||
| 128 | + ret = aclnnAmpUpdateScaleGetWorkspaceSize(currentScale, growthTracker, foundInf, growthFactor, backoffFactor, | ||
| 129 | + growthInterval, updatedScale, updatedGrowthTracker, &workspaceSize, | ||
| 130 | + &executor); | ||
| 131 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAmpUpdateScaleGetWorkspaceSize failed. ERROR: %d\n", ret); | ||
| 132 | + return ret); | ||
| 133 | + | ||
| 134 | + // 4. 根据workspaceSize申请workspace内存 | ||
| 135 | + void* workspace = nullptr; | ||
| 136 | + if (workspaceSize > 0) { | ||
| 137 | + ret = aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 138 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + // 5. 调用第二段接口,执行计算 | ||
| 142 | + ret = aclnnAmpUpdateScale(workspace, workspaceSize, executor, stream); | ||
| 143 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAmpUpdateScale failed. ERROR: %d\n", ret); return ret); | ||
| 144 | + | ||
| 145 | + // 6. 同步等待任务执行结束 | ||
| 146 | + ret = aclrtSynchronizeStream(stream); | ||
| 147 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 148 | + | ||
| 149 | + // 7. 将输出数据从device拷贝到host,并打印结果 | ||
| 150 | + float updatedScaleVal = 0.0f; | ||
| 151 | + int32_t updatedGrowthTrackerVal = 0; | ||
| 152 | + ret = aclrtMemcpy(&updatedScaleVal, sizeof(float), updatedScaleDeviceAddr, sizeof(float), | ||
| 153 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 154 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy updatedScale failed. ERROR: %d\n", ret); return ret); | ||
| 155 | + ret = aclrtMemcpy(&updatedGrowthTrackerVal, sizeof(int32_t), updatedGrowthTrackerDeviceAddr, sizeof(int32_t), | ||
| 156 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 157 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy updatedGrowthTracker failed. ERROR: %d\n", ret); return ret); | ||
| 158 | + LOG_PRINT("aclnnAmpUpdateScale result: updatedScale = %f, updatedGrowthTracker = %d\n", updatedScaleVal, | ||
| 159 | + updatedGrowthTrackerVal); | ||
| 160 | + | ||
| 161 | + // 8.(固定写法)释放资源 | ||
| 162 | + aclDestroyTensor(currentScale); | ||
| 163 | + aclDestroyTensor(growthTracker); | ||
| 164 | + aclDestroyTensor(foundInf); | ||
| 165 | + aclDestroyTensor(updatedScale); | ||
| 166 | + aclDestroyTensor(updatedGrowthTracker); | ||
| 167 | + aclrtFree(currentScaleDeviceAddr); | ||
| 168 | + aclrtFree(growthTrackerDeviceAddr); | ||
| 169 | + aclrtFree(foundInfDeviceAddr); | ||
| 170 | + aclrtFree(updatedScaleDeviceAddr); | ||
| 171 | + aclrtFree(updatedGrowthTrackerDeviceAddr); | ||
| 172 | + if (workspaceSize > 0) { | ||
| 173 | + aclrtFree(workspace); | ||
| 174 | + } | ||
| 175 | + aclrtDestroyStream(stream); | ||
| 176 | + auto aclRet = aclrtResetDevice(deviceId); | ||
| 177 | + CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("reset device failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 178 | + aclRet = aclFinalize(); | ||
| 179 | + CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("finalize acl failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 180 | + return 0; | ||
| 181 | +} | ||
| @@ -67,4 +67,5 @@ $$ | |||
| 67 | 67 | ||
| 68 | | 调用方式 | 调用样例 | 说明 | | 68 | | 调用方式 | 调用样例 | 说明 | |
| 69 | |--------------|------------------------------------------------------------------------|--------------------------------------------------------------| | 69 | |--------------|------------------------------------------------------------------------|--------------------------------------------------------------| |
| 70 | +| aclnn调用 | [test_aclnn_angle_v2](./examples/test_aclnn_angle_v2.cpp) | 通过[aclnnAngleV2](./docs/aclnnAngleV2.md)接口方式调用AngleV2算子。 | | ||
| 70 | | 图模式调用 | [test_geir_angle_v2](./examples/test_geir_angle_v2.cpp) | 通过[算子IR](./op_graph/angle_v2_proto.h)构图方式调用AngleV2算子。 | | 71 | | 图模式调用 | [test_geir_angle_v2](./examples/test_geir_angle_v2.cpp) | 通过[算子IR](./op_graph/angle_v2_proto.h)构图方式调用AngleV2算子。 | |
| @@ -0,0 +1,152 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_angle_v2.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr) | ||
| 38 | +{ | ||
| 39 | + auto size = GetShapeSize(shape); | ||
| 40 | + std::vector<float> resultData(size, 0); | ||
| 41 | + auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr, | ||
| 42 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return); | ||
| 44 | + for (int64_t i = 0; i < size; i++) { | ||
| 45 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 46 | + } | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 50 | +{ | ||
| 51 | + // 固定写法,初始化 | ||
| 52 | + auto ret = aclInit(nullptr); | ||
| 53 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 54 | + ret = aclrtSetDevice(deviceId); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + ret = aclrtCreateStream(stream); | ||
| 57 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 58 | + return 0; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +template <typename T> | ||
| 62 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 63 | + aclDataType dataType, aclTensor** tensor) | ||
| 64 | +{ | ||
| 65 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 66 | + // 调用aclrtMalloc申请device侧内存 | ||
| 67 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 68 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 69 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 70 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 71 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 72 | + | ||
| 73 | + // 计算连续tensor的strides | ||
| 74 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 75 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 76 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 80 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 81 | + shape.data(), shape.size(), *deviceAddr); | ||
| 82 | + return 0; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +int main() | ||
| 86 | +{ | ||
| 87 | + // 1.(固定写法)device/stream初始化,参考acl API文档 | ||
| 88 | + int32_t deviceId = 0; | ||
| 89 | + aclrtStream stream; | ||
| 90 | + auto ret = Init(deviceId, &stream); | ||
| 91 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 92 | + | ||
| 93 | + // 2. 构造输入与输出 | ||
| 94 | + std::vector<int64_t> xShape = {2, 3}; | ||
| 95 | + std::vector<int64_t> yShape = {2, 3}; | ||
| 96 | + | ||
| 97 | + void* xDeviceAddr = nullptr; | ||
| 98 | + void* yDeviceAddr = nullptr; | ||
| 99 | + | ||
| 100 | + aclTensor* x = nullptr; | ||
| 101 | + aclTensor* y = nullptr; | ||
| 102 | + | ||
| 103 | + std::vector<float> xHostData = {1.0, 0.0, 0.0, 1.0, -1.0, 0.0}; | ||
| 104 | + std::vector<float> yHostData = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; | ||
| 105 | + | ||
| 106 | + ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 108 | + ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_FLOAT, &y); | ||
| 109 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 110 | + | ||
| 111 | + // 3. 调用CANN算子库API | ||
| 112 | + uint64_t workspaceSize = 0; | ||
| 113 | + aclOpExecutor* executor; | ||
| 114 | + | ||
| 115 | + // 调用aclnnAngleV2第一段接口 | ||
| 116 | + ret = aclnnAngleV2GetWorkspaceSize(x, y, &workspaceSize, &executor); | ||
| 117 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAngleV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 118 | + | ||
| 119 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 120 | + void* workspaceAddr = nullptr; | ||
| 121 | + if (workspaceSize > 0) { | ||
| 122 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 123 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + // 调用aclnnAngleV2第二段接口 | ||
| 127 | + ret = aclnnAngleV2(workspaceAddr, workspaceSize, executor, stream); | ||
| 128 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAngleV2 failed. ERROR: %d\n", ret); return ret); | ||
| 129 | + | ||
| 130 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 131 | + ret = aclrtSynchronizeStream(stream); | ||
| 132 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 133 | + | ||
| 134 | + // 5. 获取输出的值 | ||
| 135 | + PrintOutResult(yShape, &yDeviceAddr); | ||
| 136 | + | ||
| 137 | + // 6. 释放aclTensor | ||
| 138 | + aclDestroyTensor(x); | ||
| 139 | + aclDestroyTensor(y); | ||
| 140 | + | ||
| 141 | + // 7. 释放device资源 | ||
| 142 | + aclrtFree(xDeviceAddr); | ||
| 143 | + aclrtFree(yDeviceAddr); | ||
| 144 | + if (workspaceSize > 0) { | ||
| 145 | + aclrtFree(workspaceAddr); | ||
| 146 | + } | ||
| 147 | + aclrtDestroyStream(stream); | ||
| 148 | + aclrtResetDevice(deviceId); | ||
| 149 | + aclFinalize(); | ||
| 150 | + | ||
| 151 | + return 0; | ||
| 152 | +} | ||
| @@ -1,3 +1,87 @@ | |||
| 1 | # Cdist | 1 | # Cdist |
Y | |||
| 2 | 2 | ||
| 3 | -本目录仅包含Cdist算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 | 3 | +## 产品支持情况 |
| 4 | + | ||
| 5 | +| 产品 | 是否支持 | | ||
| 6 | +| :--- | :------: | | ||
| 7 | +| <term>Ascend 950PR/Ascend 950DT</term> | √ | | ||
| 8 | +| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | ||
| 9 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 10 | +| <term>Atlas 200I/500 A2 推理产品</term> | × | | ||
| 11 | +| <term>Atlas 推理系列产品</term> | × | | ||
| 12 | +| <term>Atlas 训练系列产品</term> | × | | ||
| 13 | + | ||
| 14 | +## 功能说明 | ||
| 15 | + | ||
| 16 | +- 算子功能:计算两个向量集合中每对向量之间的p范数距离。 | ||
| 17 | +- 计算公式:对于输入张量x1和x2,设其shape分别为$[B, P, M]$和$[B, R, M]$,输出张量y的shape为$[B, P, R]$。 | ||
| 18 | + | ||
| 19 | + 当$p>0$时: | ||
| 20 | + | ||
| 21 | + $$ | ||
| 22 | + y_{b,i,j}=\left(\sum_{k=1}^{M}|x1_{b,i,k}-x2_{b,j,k}|^p\right)^{\frac{1}{p}} | ||
| 23 | + $$ | ||
| 24 | + | ||
| 25 | + 当$p=0$时,输出为对应向量中不相等元素的数量;当$p=+\infty$时,输出为对应向量元素差值绝对值的最大值。 | ||
| 26 | + | ||
| 27 | +## 参数说明 | ||
| 28 | + | ||
| 29 | +<table style="undefined;table-layout: fixed; width: 980px"><colgroup> | ||
| 30 | + <col style="width: 100px"> | ||
| 31 | + <col style="width: 150px"> | ||
| 32 | + <col style="width: 280px"> | ||
| 33 | + <col style="width: 330px"> | ||
| 34 | + <col style="width: 120px"> | ||
| 35 | + </colgroup> | ||
| 36 | + <thead> | ||
| 37 | + <tr> | ||
| 38 | + <th>参数名</th> | ||
| 39 | + <th>输入/输出/属性</th> | ||
| 40 | + <th>描述</th> | ||
| 41 | + <th>数据类型</th> | ||
| 42 | + <th>数据格式</th> | ||
| 43 | + </tr></thead> | ||
| 44 | + <tbody> | ||
| 45 | + <tr> | ||
| 46 | + <td>x1</td> | ||
| 47 | + <td>输入</td> | ||
| 48 | + <td>第一个输入张量,shape为[B, P, M]。</td> | ||
| 49 | + <td>BFLOAT16、FLOAT16、FLOAT</td> | ||
| 50 | + <td>ND</td> | ||
| 51 | + </tr> | ||
| 52 | + <tr> | ||
| 53 | + <td>x2</td> | ||
| 54 | + <td>输入</td> | ||
| 55 | + <td>第二个输入张量,shape为[B, R, M]。</td> | ||
| 56 | + <td>BFLOAT16、FLOAT16、FLOAT</td> | ||
| 57 | + <td>ND</td> | ||
| 58 | + </tr> | ||
| 59 | + <tr> | ||
| 60 | + <td>y</td> | ||
| 61 | + <td>输出</td> | ||
| 62 | + <td>p范数距离计算结果,shape为[B, P, R]。</td> | ||
| 63 | + <td>BFLOAT16、FLOAT16、FLOAT</td> | ||
| 64 | + <td>ND</td> | ||
| 65 | + </tr> | ||
| 66 | + <tr> | ||
| 67 | + <td>p</td> | ||
| 68 | + <td>可选属性</td> | ||
| 69 | + <td>范数阶数,取值范围为[0, +∞],默认值为2.0。</td> | ||
| 70 | + <td>FLOAT</td> | ||
| 71 | + <td>-</td> | ||
| 72 | + </tr> | ||
| 73 | + </tbody></table> | ||
| 74 | + | ||
| 75 | +## 约束说明 | ||
| 76 | + | ||
| 77 | +- x1、x2和y的数据类型必须一致。 | ||
| 78 | +- x1和x2的维度范围为2~8,最后一维长度必须相同。 | ||
| 79 | +- x1和x2除最后两维外的其他维度必须满足broadcast关系;输出对应维度为broadcast后的shape。 | ||
| 80 | +- 若x1的倒数第二维为P,x2的倒数第二维为R,则输出的最后两维为[P, R]。 | ||
| 81 | +- p必须大于或等于0,支持+∞,常用取值为0、1.0、2.0和+∞。 | ||
| 82 | + | ||
| 83 | +## 调用说明 | ||
| 84 | + | ||
| 85 | +| 调用方式 | 调用样例 | 说明 | | ||
| 86 | +| :--- | :--- | :--- | | ||
| 87 | +| aclnn调用 | [test_aclnn_cdist](./examples/test_aclnn_cdist.cpp) | 通过[aclnnCdist](./docs/aclnnCdist.md)接口方式调用Cdist算子。 | | ||
| @@ -79,4 +79,5 @@ | |||
| 79 | 79 | ||
| 80 | | 调用方式 | 调用样例 | 说明 | | 80 | | 调用方式 | 调用样例 | 说明 | |
| 81 | |--------------|------------------------------------------------------------------------|----------------------------------------------------------------| | 81 | |--------------|------------------------------------------------------------------------|----------------------------------------------------------------| |
| 82 | +| aclnn调用 | [test_aclnn_histc](./examples/test_aclnn_histc.cpp) | 通过[aclnnHistc](./docs/aclnnHistc.md)接口方式调用HistogramV2算子。 | | ||
| 82 | | 图模式调用 | [test_geir_histogram_v2](./examples/test_geir_histogram_v2.cpp) | 通过[算子IR](./op_graph/histogram_v2_proto.h)构图方式调用HistogramV2算子。 | | 83 | | 图模式调用 | [test_geir_histogram_v2](./examples/test_geir_histogram_v2.cpp) | 通过[算子IR](./op_graph/histogram_v2_proto.h)构图方式调用HistogramV2算子。 | |
| @@ -0,0 +1,156 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_histc.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 58 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 59 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 60 | + | ||
| 61 | + // 计算连续tensor的strides | ||
| 62 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 63 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 64 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 68 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 69 | + shape.data(), shape.size(), *deviceAddr); | ||
| 70 | + return 0; | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +int main() | ||
| 74 | +{ | ||
| 75 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 76 | + // 根据自己的实际device填写deviceId | ||
| 77 | + int32_t deviceId = 0; | ||
| 78 | + aclrtStream stream; | ||
| 79 | + auto ret = Init(deviceId, &stream); | ||
| 80 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 81 | + | ||
| 82 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 83 | + std::vector<int64_t> selfShape = {3, 3}; | ||
| 84 | + std::vector<int64_t> outShape = {3}; | ||
| 85 | + void* selfDeviceAddr = nullptr; | ||
| 86 | + void* outDeviceAddr = nullptr; | ||
| 87 | + aclTensor* self = nullptr; | ||
| 88 | + aclScalar* min = nullptr; | ||
| 89 | + aclScalar* max = nullptr; | ||
| 90 | + aclTensor* out = nullptr; | ||
| 91 | + std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; | ||
| 92 | + std::vector<float> outHostData = {0, 0, 0}; | ||
| 93 | + int64_t bins = 3; | ||
| 94 | + float minValue = 1.0f; | ||
| 95 | + float maxValue = 9.0f; | ||
| 96 | + // 创建self aclTensor | ||
| 97 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 98 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 99 | + // 创建min aclScalar | ||
| 100 | + min = aclCreateScalar(&minValue, aclDataType::ACL_FLOAT); | ||
| 101 | + CHECK_RET(min != nullptr, return ret); | ||
| 102 | + // 创建max aclScalar | ||
| 103 | + max = aclCreateScalar(&maxValue, aclDataType::ACL_FLOAT); | ||
| 104 | + CHECK_RET(max != nullptr, return ret); | ||
| 105 | + // 创建out aclTensor | ||
| 106 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 108 | + | ||
| 109 | + // 3. 调用CANN算子库API,需要修改为具体的API名称 | ||
| 110 | + uint64_t workspaceSize = 0; | ||
| 111 | + aclOpExecutor* executor; | ||
| 112 | + // 调用aclnnHistc第一段接口 | ||
| 113 | + ret = aclnnHistcGetWorkspaceSize(self, bins, min, max, out, &workspaceSize, &executor); | ||
| 114 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHistcGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 115 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 116 | + void* workspaceAddr = nullptr; | ||
| 117 | + if (workspaceSize > 0) { | ||
| 118 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 119 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 120 | + } | ||
| 121 | + // 调用aclnnHistc第二段接口 | ||
| 122 | + ret = aclnnHistc(workspaceAddr, workspaceSize, executor, stream); | ||
| 123 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHistc failed. ERROR: %d\n", ret); return ret); | ||
| 124 | + | ||
| 125 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 126 | + ret = aclrtSynchronizeStream(stream); | ||
| 127 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 128 | + | ||
| 129 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 130 | + auto size = GetShapeSize(outShape); | ||
| 131 | + std::vector<float> resultData(size, 0); | ||
| 132 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, | ||
| 133 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 134 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 135 | + for (int64_t i = 0; i < size; i++) { | ||
| 136 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 140 | + aclDestroyTensor(self); | ||
| 141 | + aclDestroyScalar(min); | ||
| 142 | + aclDestroyScalar(max); | ||
| 143 | + aclDestroyTensor(out); | ||
| 144 | + | ||
| 145 | + // 7. 释放Device资源,需要根据具体API的接口定义修改 | ||
| 146 | + aclrtFree(selfDeviceAddr); | ||
| 147 | + aclrtFree(outDeviceAddr); | ||
| 148 | + if (workspaceSize > 0) { | ||
| 149 | + aclrtFree(workspaceAddr); | ||
| 150 | + } | ||
| 151 | + aclrtDestroyStream(stream); | ||
| 152 | + aclrtResetDevice(deviceId); | ||
| 153 | + aclFinalize(); | ||
| 154 | + | ||
| 155 | + return 0; | ||
| 156 | +} | ||
| @@ -1,3 +1,9 @@ | |||
| 1 | # ReduceNansum | 1 | # ReduceNansum |
| 2 | 2 | ||
| 3 | 本目录仅包含ReduceNansum算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 | 3 | 本目录仅包含ReduceNansum算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 |
| 4 | + | ||
| 5 | +## 调用说明 | ||
| 6 | + | ||
| 7 | +| 调用方式 | 调用样例 | 说明 | | ||
| 8 | +|---------|---------|------| | ||
| 9 | +| aclnn调用 | [test_aclnn_reduce_nansum](./examples/test_aclnn_reduce_nansum.cpp) | 通过[aclnnReduceNansum](./docs/aclnnReduceNansum.md)接口方式调用ReduceNansum算子。 | | ||
| @@ -1,145 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * This program is free software, you can redistribute it and/or modify. | ||
| 3 | - * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | - * This file is a part of the CANN Open Software. | ||
| 5 | - * Licensed under 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, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | -#include <iostream> | ||
| 12 | -#include <vector> | ||
| 13 | -#include "acl/acl.h" | ||
| 14 | -#include "aclnnop/aclnn_reduce_nansum.h" | ||
| 15 | - | ||
| 16 | -#define CHECK_RET(cond, return_expr) \ | ||
| 17 | - do { \ | ||
| 18 | - if (!(cond)) { \ | ||
| 19 | - return_expr; \ | ||
| 20 | - } \ | ||
| 21 | - } while (0) | ||
| 22 | - | ||
| 23 | -#define LOG_PRINT(message, ...) \ | ||
| 24 | - do { \ | ||
| 25 | - printf(message, ##__VA_ARGS__); \ | ||
| 26 | - } while (0) | ||
| 27 | - | ||
| 28 | -int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 29 | - int64_t shapeSize = 1; | ||
| 30 | - for (auto i : shape) { | ||
| 31 | - shapeSize *= i; | ||
| 32 | - } | ||
| 33 | - return shapeSize; | ||
| 34 | -} | ||
| 35 | - | ||
| 36 | -int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 37 | - // 固定写法,资源初始化 | ||
| 38 | - auto ret = aclInit(nullptr); | ||
| 39 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 40 | - ret = aclrtSetDevice(deviceId); | ||
| 41 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 42 | - ret = aclrtCreateStream(stream); | ||
| 43 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 44 | - return 0; | ||
| 45 | -} | ||
| 46 | - | ||
| 47 | -template <typename T> | ||
| 48 | -int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 49 | - aclDataType dataType, aclTensor** tensor) { | ||
| 50 | - auto size = GetShapeSize(shape) * sizeof(T); | ||
| 51 | - // 调用aclrtMalloc申请device侧内存 | ||
| 52 | - auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 53 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 54 | - // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 55 | - ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 56 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 57 | - | ||
| 58 | - // 计算连续tensor的strides | ||
| 59 | - std::vector<int64_t> strides(shape.size(), 1); | ||
| 60 | - for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 61 | - strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | - // 调用aclCreateTensor接口创建aclTensor | ||
| 65 | - *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); | ||
| 66 | - return 0; | ||
| 67 | -} | ||
| 68 | - | ||
| 69 | -int main() { | ||
| 70 | - // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 71 | - // 根据自己的实际device填写deviceId | ||
| 72 | - int32_t deviceId = 0; | ||
| 73 | - aclrtStream stream; | ||
| 74 | - auto ret = Init(deviceId, &stream); | ||
| 75 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 76 | - | ||
| 77 | - // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 78 | - std::vector<int64_t> selfShape = {4, 2}; | ||
| 79 | - std::vector<int64_t> outShape = {2}; | ||
| 80 | - void* selfDeviceAddr = nullptr; | ||
| 81 | - void* outDeviceAddr = nullptr; | ||
| 82 | - aclTensor* self = nullptr; | ||
| 83 | - aclIntArray* dim = nullptr; | ||
| 84 | - aclTensor* out = nullptr; | ||
| 85 | - std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 86 | - std::vector<float> outHostData = {0, 0}; | ||
| 87 | - std::vector<int64_t> dimData = {0}; | ||
| 88 | - bool keepDim = false; | ||
| 89 | - auto dtype = aclDataType::ACL_FLOAT; | ||
| 90 | - // 创建self aclTensor | ||
| 91 | - ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 92 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 93 | - // 创建out aclTensor | ||
| 94 | - ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 95 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 96 | - // 创建dim aclIntArray | ||
| 97 | - dim = aclCreateIntArray(dimData.data(), 1); | ||
| 98 | - CHECK_RET(dim != nullptr, return ret); | ||
| 99 | - | ||
| 100 | -// 3.调用CANN算子库API,需要修改为具体的Api名称 | ||
| 101 | - uint64_t workspaceSize = 0; | ||
| 102 | - aclOpExecutor* executor; | ||
| 103 | - // 调用aclnnReduceNansum第一段接口 | ||
| 104 | - ret = aclnnReduceNansumGetWorkspaceSize(self, dim, keepDim, dtype, out, &workspaceSize, &executor); | ||
| 105 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansumGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 106 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 107 | - void* workspaceAddr = nullptr; | ||
| 108 | - if (workspaceSize > 0) { | ||
| 109 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 110 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 111 | - } | ||
| 112 | - // 调用aclnnReduceNansum第二段接口 | ||
| 113 | - ret = aclnnReduceNansum(workspaceAddr, workspaceSize, executor, stream); | ||
| 114 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansum failed. ERROR: %d\n", ret); return ret); | ||
| 115 | - | ||
| 116 | - // 4.(固定写法)同步等待任务执行结束 | ||
| 117 | - ret = aclrtSynchronizeStream(stream); | ||
| 118 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 119 | - | ||
| 120 | - // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 121 | - auto size = GetShapeSize(outShape); | ||
| 122 | - std::vector<float> resultData(size, 0); | ||
| 123 | - ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, | ||
| 124 | - size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 125 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 126 | - for (int64_t i = 0; i < size; i++) { | ||
| 127 | - LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - // 6.释放aclTensor和aclIntArray,需要根据具体API的接口定义修改 | ||
| 131 | - aclDestroyTensor(self); | ||
| 132 | - aclDestroyIntArray(dim); | ||
| 133 | - aclDestroyTensor(out); | ||
| 134 | - | ||
| 135 | - // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 136 | - aclrtFree(selfDeviceAddr); | ||
| 137 | - aclrtFree(outDeviceAddr); | ||
| 138 | - if (workspaceSize > 0) { | ||
| 139 | - aclrtFree(workspaceAddr); | ||
| 140 | - } | ||
| 141 | - aclrtDestroyStream(stream); | ||
| 142 | - aclrtResetDevice(deviceId); | ||
| 143 | - aclFinalize(); | ||
| 144 | - return 0; | ||
| 145 | -} | ||
| @@ -0,0 +1,150 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_reduce_nansum.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 58 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 59 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 60 | + | ||
| 61 | + // 计算连续tensor的strides | ||
| 62 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 63 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 64 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 68 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 69 | + shape.data(), shape.size(), *deviceAddr); | ||
| 70 | + return 0; | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +int main() | ||
| 74 | +{ | ||
| 75 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 76 | + // 根据自己的实际device填写deviceId | ||
| 77 | + int32_t deviceId = 0; | ||
| 78 | + aclrtStream stream; | ||
| 79 | + auto ret = Init(deviceId, &stream); | ||
| 80 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 81 | + | ||
| 82 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 83 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 84 | + std::vector<int64_t> outShape = {2}; | ||
| 85 | + void* selfDeviceAddr = nullptr; | ||
| 86 | + void* outDeviceAddr = nullptr; | ||
| 87 | + aclTensor* self = nullptr; | ||
| 88 | + aclIntArray* dim = nullptr; | ||
| 89 | + aclTensor* out = nullptr; | ||
| 90 | + std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 91 | + std::vector<float> outHostData = {0, 0}; | ||
| 92 | + std::vector<int64_t> dimData = {0}; | ||
| 93 | + bool keepDim = false; | ||
| 94 | + auto dtype = aclDataType::ACL_FLOAT; | ||
| 95 | + // 创建self aclTensor | ||
| 96 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 97 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 98 | + // 创建out aclTensor | ||
| 99 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 100 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 101 | + // 创建dim aclIntArray | ||
| 102 | + dim = aclCreateIntArray(dimData.data(), 1); | ||
| 103 | + CHECK_RET(dim != nullptr, return ret); | ||
| 104 | + | ||
| 105 | + // 3.调用CANN算子库API,需要修改为具体的Api名称 | ||
| 106 | + uint64_t workspaceSize = 0; | ||
| 107 | + aclOpExecutor* executor; | ||
| 108 | + // 调用aclnnReduceNansum第一段接口 | ||
| 109 | + ret = aclnnReduceNansumGetWorkspaceSize(self, dim, keepDim, dtype, out, &workspaceSize, &executor); | ||
| 110 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansumGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 111 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 112 | + void* workspaceAddr = nullptr; | ||
| 113 | + if (workspaceSize > 0) { | ||
| 114 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 115 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 116 | + } | ||
| 117 | + // 调用aclnnReduceNansum第二段接口 | ||
| 118 | + ret = aclnnReduceNansum(workspaceAddr, workspaceSize, executor, stream); | ||
| 119 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansum failed. ERROR: %d\n", ret); return ret); | ||
| 120 | + | ||
| 121 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 122 | + ret = aclrtSynchronizeStream(stream); | ||
| 123 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 124 | + | ||
| 125 | + // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 126 | + auto size = GetShapeSize(outShape); | ||
| 127 | + std::vector<float> resultData(size, 0); | ||
| 128 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, | ||
| 129 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 130 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 131 | + for (int64_t i = 0; i < size; i++) { | ||
| 132 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + // 6.释放aclTensor和aclIntArray,需要根据具体API的接口定义修改 | ||
| 136 | + aclDestroyTensor(self); | ||
| 137 | + aclDestroyIntArray(dim); | ||
| 138 | + aclDestroyTensor(out); | ||
| 139 | + | ||
| 140 | + // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 141 | + aclrtFree(selfDeviceAddr); | ||
| 142 | + aclrtFree(outDeviceAddr); | ||
| 143 | + if (workspaceSize > 0) { | ||
| 144 | + aclrtFree(workspaceAddr); | ||
| 145 | + } | ||
| 146 | + aclrtDestroyStream(stream); | ||
| 147 | + aclrtResetDevice(deviceId); | ||
| 148 | + aclFinalize(); | ||
| 149 | + return 0; | ||
| 150 | +} | ||
| @@ -1,3 +1,10 @@ | |||
| 1 | # ReduceStdWithMean | 1 | # ReduceStdWithMean |
| 2 | 2 | ||
| 3 | 本目录仅包含ReduceStdWithMean算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 | 3 | 本目录仅包含ReduceStdWithMean算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 |
| 4 | + | ||
| 5 | +## 调用说明 | ||
| 6 | + | ||
| 7 | +| 调用方式 | 调用样例 | 说明 | | ||
| 8 | +|---------|---------|------| | ||
| 9 | +| aclnn调用 | [test_aclnn_batch_norm_stats](./examples/test_aclnn_batch_norm_stats.cpp) | 通过[aclnnBatchNormStats](./docs/aclnnBatchNormStats.md)接口方式调用ReduceStdWithMean算子。 | | ||
| 10 | +| aclnn调用 | [test_aclnn_std_mean_correction](./examples/test_aclnn_std_mean_correction.cpp) | 通过[aclnnStdMeanCorrection](./docs/aclnnStdMeanCorrection.md)接口方式调用ReduceStdWithMean算子。 | | ||
| @@ -1,158 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * This program is free software, you can redistribute it and/or modify. | ||
| 3 | - * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | - * This file is a part of the CANN Open Software. | ||
| 5 | - * Licensed under 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, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | -#include <iostream> | ||
| 12 | -#include <vector> | ||
| 13 | -#include "acl/acl.h" | ||
| 14 | -#include "aclnnop/aclnn_batch_norm_stats.h" | ||
| 15 | - | ||
| 16 | -#define CHECK_RET(cond, return_expr) \ | ||
| 17 | - do { \ | ||
| 18 | - if (!(cond)) { \ | ||
| 19 | - return_expr; \ | ||
| 20 | - } \ | ||
| 21 | - } while (0) | ||
| 22 | - | ||
| 23 | -#define LOG_PRINT(message, ...) \ | ||
| 24 | - do { \ | ||
| 25 | - printf(message, ##__VA_ARGS__); \ | ||
| 26 | - } while (0) | ||
| 27 | - | ||
| 28 | -int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 29 | - int64_t shapeSize = 1; | ||
| 30 | - for (auto i : shape) { | ||
| 31 | - shapeSize *= i; | ||
| 32 | - } | ||
| 33 | - return shapeSize; | ||
| 34 | -} | ||
| 35 | - | ||
| 36 | -int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 37 | - // 固定写法,资源初始化 | ||
| 38 | - auto ret = aclInit(nullptr); | ||
| 39 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 40 | - ret = aclrtSetDevice(deviceId); | ||
| 41 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 42 | - ret = aclrtCreateStream(stream); | ||
| 43 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 44 | - return 0; | ||
| 45 | -} | ||
| 46 | - | ||
| 47 | -template <typename T> | ||
| 48 | -int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 49 | - aclDataType dataType, aclTensor** tensor) { | ||
| 50 | - auto size = GetShapeSize(shape) * sizeof(T); | ||
| 51 | - // 调用aclrtMalloc申请Device侧内存 | ||
| 52 | - auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 53 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 54 | - | ||
| 55 | - // 调用aclrtMemcpy将Host侧数据拷贝到Device侧内存上 | ||
| 56 | - ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 57 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 58 | - | ||
| 59 | - // 计算连续tensor的strides | ||
| 60 | - std::vector<int64_t> strides(shape.size(), 1); | ||
| 61 | - for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 62 | - strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - // 调用aclCreateTensor接口创建aclTensor | ||
| 66 | - *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 67 | - shape.data(), shape.size(), *deviceAddr); | ||
| 68 | - return 0; | ||
| 69 | -} | ||
| 70 | - | ||
| 71 | -int main() { | ||
| 72 | - // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 73 | - // 根据自己的实际device填写deviceId | ||
| 74 | - int32_t deviceId = 0; | ||
| 75 | - aclrtStream stream; | ||
| 76 | - auto ret = Init(deviceId, &stream); | ||
| 77 | - // check根据自己的需要处理 | ||
| 78 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 79 | - | ||
| 80 | - // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 81 | - std::vector<int64_t> inputShape = {2, 3}; | ||
| 82 | - std::vector<int64_t> outShape = {3,}; | ||
| 83 | - void* inputDeviceAddr = nullptr; | ||
| 84 | - void* meanDeviceAddr = nullptr; | ||
| 85 | - void* invstdDeviceAddr = nullptr; | ||
| 86 | - aclTensor* input = nullptr; | ||
| 87 | - aclTensor* mean = nullptr; | ||
| 88 | - aclTensor* invstd = nullptr; | ||
| 89 | - std::vector<float> inputHostData = {1, 2, 3, 4, 5, 6}; | ||
| 90 | - std::vector<float> meanHostData = {0, 0, 0}; | ||
| 91 | - std::vector<float> invstdHostData = {0, 0, 0}; | ||
| 92 | - double eps = 1e-5; | ||
| 93 | - | ||
| 94 | - // 创建self aclTensor | ||
| 95 | - ret = CreateAclTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input); | ||
| 96 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 97 | - // 创建mean aclTensor | ||
| 98 | - ret = CreateAclTensor(meanHostData, outShape, &meanDeviceAddr, aclDataType::ACL_FLOAT, &mean); | ||
| 99 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 100 | - // 创建invstd aclTensor | ||
| 101 | - ret = CreateAclTensor(invstdHostData, outShape, &invstdDeviceAddr, aclDataType::ACL_FLOAT, &invstd); | ||
| 102 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 103 | - | ||
| 104 | - uint64_t workspaceSize = 0; | ||
| 105 | - aclOpExecutor* executor; | ||
| 106 | - // aclnnBatchNormStats接口调用示例 | ||
| 107 | - // 3.调用CANN算子库API,需要修改为具体的API名称 | ||
| 108 | - // 调用aclnnBatchNormStats第一段接口 | ||
| 109 | - ret = aclnnBatchNormStatsGetWorkspaceSize(input, eps, mean, invstd, &workspaceSize, &executor); | ||
| 110 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStatsGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 111 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 112 | - void* workspaceAddr = nullptr; | ||
| 113 | - if (workspaceSize > 0) { | ||
| 114 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 115 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 116 | - } | ||
| 117 | - // 调用aclnnBatchNormStats第二段接口 | ||
| 118 | - ret = aclnnBatchNormStats(workspaceAddr, workspaceSize, executor, stream); | ||
| 119 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStats failed. ERROR: %d\n", ret); return ret); | ||
| 120 | - | ||
| 121 | - // 4.(固定写法)同步等待任务执行结束 | ||
| 122 | - ret = aclrtSynchronizeStream(stream); | ||
| 123 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 124 | - | ||
| 125 | - // 5.获取输出的值,将Device侧内存上的结果拷贝至Host侧,需要根据具体API的接口定义修改 | ||
| 126 | - auto size = GetShapeSize(outShape); | ||
| 127 | - std::vector<float> meanData(size, 0); | ||
| 128 | - ret = aclrtMemcpy(meanData.data(), meanData.size() * sizeof(meanData[0]), meanDeviceAddr, | ||
| 129 | - size * sizeof(meanData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 130 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 131 | - for (int64_t i = 0; i < size; i++) { | ||
| 132 | - LOG_PRINT("mean result[%ld] is: %f\n", i, meanData[i]); | ||
| 133 | - } | ||
| 134 | - std::vector<float> invstdData(size, 0); | ||
| 135 | - ret = aclrtMemcpy(invstdData.data(), invstdData.size() * sizeof(invstdData[0]), invstdDeviceAddr, | ||
| 136 | - size * sizeof(invstdData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 137 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 138 | - for (int64_t i = 0; i < size; i++) { | ||
| 139 | - LOG_PRINT("mean result[%ld] is: %f\n", i, invstdData[i]); | ||
| 140 | - } | ||
| 141 | - | ||
| 142 | - // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 143 | - aclDestroyTensor(input); | ||
| 144 | - aclDestroyTensor(mean); | ||
| 145 | - aclDestroyTensor(invstd); | ||
| 146 | - | ||
| 147 | - // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 148 | - aclrtFree(inputDeviceAddr); | ||
| 149 | - aclrtFree(meanDeviceAddr); | ||
| 150 | - aclrtFree(invstdDeviceAddr); | ||
| 151 | - if (workspaceSize > 0) { | ||
| 152 | - aclrtFree(workspaceAddr); | ||
| 153 | - } | ||
| 154 | - aclrtDestroyStream(stream); | ||
| 155 | - aclrtResetDevice(deviceId); | ||
| 156 | - aclFinalize(); | ||
| 157 | - return 0; | ||
| 158 | -} | ||
| @@ -1,161 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * This program is free software, you can redistribute it and/or modify. | ||
| 3 | - * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | - * This file is a part of the CANN Open Software. | ||
| 5 | - * Licensed under 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, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | -#include <iostream> | ||
| 12 | -#include <vector> | ||
| 13 | -#include "acl/acl.h" | ||
| 14 | -#include "aclnnop/aclnn_std_mean_correction.h" | ||
| 15 | - | ||
| 16 | -#define CHECK_RET(cond, return_expr) \ | ||
| 17 | - do { \ | ||
| 18 | - if (!(cond)) { \ | ||
| 19 | - return_expr; \ | ||
| 20 | - } \ | ||
| 21 | - } while (0) | ||
| 22 | - | ||
| 23 | -#define LOG_PRINT(message, ...) \ | ||
| 24 | - do { \ | ||
| 25 | - printf(message, ##__VA_ARGS__); \ | ||
| 26 | - } while (0) | ||
| 27 | - | ||
| 28 | -int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 29 | - int64_t shape_size = 1; | ||
| 30 | - for (auto i : shape) { | ||
| 31 | - shape_size *= i; | ||
| 32 | - } | ||
| 33 | - return shape_size; | ||
| 34 | -} | ||
| 35 | - | ||
| 36 | -int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 37 | - // 固定写法,资源初始化 | ||
| 38 | - auto ret = aclInit(nullptr); | ||
| 39 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 40 | - ret = aclrtSetDevice(deviceId); | ||
| 41 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 42 | - ret = aclrtCreateStream(stream); | ||
| 43 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 44 | - return 0; | ||
| 45 | -} | ||
| 46 | - | ||
| 47 | -template <typename T> | ||
| 48 | -int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 49 | - aclDataType dataType, aclTensor** tensor) { | ||
| 50 | - auto size = GetShapeSize(shape) * sizeof(T); | ||
| 51 | - // 调用aclrtMalloc申请device侧内存 | ||
| 52 | - auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 53 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 54 | - | ||
| 55 | - // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 56 | - ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 57 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 58 | - | ||
| 59 | - // 计算连续tensor的strides | ||
| 60 | - std::vector<int64_t> strides(shape.size(), 1); | ||
| 61 | - for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 62 | - strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - // 调用aclCreateTensor接口创建aclTensor | ||
| 66 | - *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 67 | - shape.data(), shape.size(), *deviceAddr); | ||
| 68 | - return 0; | ||
| 69 | -} | ||
| 70 | - | ||
| 71 | -int main() { | ||
| 72 | - // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 73 | - // 根据自己的实际device填写deviceId | ||
| 74 | - int32_t deviceId = 0; | ||
| 75 | - aclrtStream stream; | ||
| 76 | - auto ret = Init(deviceId, &stream); | ||
| 77 | - // check根据自己的需要处理 | ||
| 78 | - CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 79 | - // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 80 | - std::vector<int64_t> selfShape = {2, 3, 4}; | ||
| 81 | - std::vector<int64_t> stdOutShape = {2, 4}; | ||
| 82 | - std::vector<int64_t> meanOutShape = {2, 4}; | ||
| 83 | - void* selfDeviceAddr = nullptr; | ||
| 84 | - void* stdOutDeviceAddr = nullptr; | ||
| 85 | - void* meanOutDeviceAddr = nullptr; | ||
| 86 | - aclTensor* self = nullptr; | ||
| 87 | - aclTensor* stdOut = nullptr; | ||
| 88 | - aclTensor* meanOut = nullptr; | ||
| 89 | - std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, | ||
| 90 | - 19, 20, 21, 22, 23, 24}; | ||
| 91 | - std::vector<float> stdOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0}; | ||
| 92 | - std::vector<float> meanOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0}; | ||
| 93 | - std::vector<int64_t> dimData = {1}; | ||
| 94 | - int64_t correction = 1; | ||
| 95 | - bool keepdim = false; | ||
| 96 | - // 创建self aclTensor | ||
| 97 | - ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 98 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 99 | - // 创建stdOut aclTensor | ||
| 100 | - ret = CreateAclTensor(stdOutHostData, stdOutShape, &stdOutDeviceAddr, aclDataType::ACL_FLOAT, &stdOut); | ||
| 101 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 102 | - // 创建meanOut aclTensor | ||
| 103 | - ret = CreateAclTensor(meanOutHostData, meanOutShape, &meanOutDeviceAddr, aclDataType::ACL_FLOAT, &meanOut); | ||
| 104 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 105 | - | ||
| 106 | - const aclIntArray *dim = aclCreateIntArray(dimData.data(), dimData.size()); | ||
| 107 | - CHECK_RET(dim != nullptr, return ACL_ERROR_INTERNAL_ERROR); | ||
| 108 | - | ||
| 109 | - // 3.调用CANN算子库API,需要修改为具体的API | ||
| 110 | - uint64_t workspaceSize = 0; | ||
| 111 | - aclOpExecutor* executor; | ||
| 112 | - // 调用aclnnStdMeanCorrection第一段接口 | ||
| 113 | - ret = aclnnStdMeanCorrectionGetWorkspaceSize(self, dim, correction, keepdim, stdOut, meanOut, &workspaceSize, &executor); | ||
| 114 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrectionGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 115 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 116 | - void* workspaceAddr = nullptr; | ||
| 117 | - if (workspaceSize > 0) { | ||
| 118 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 119 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;); | ||
| 120 | - } | ||
| 121 | - // 调用aclnnStdMeanCorrection第二段接口 | ||
| 122 | - ret = aclnnStdMeanCorrection(workspaceAddr, workspaceSize, executor, stream); | ||
| 123 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrection failed. ERROR: %d\n", ret); return ret); | ||
| 124 | - // 4.(固定写法)同步等待任务执行结束 | ||
| 125 | - ret = aclrtSynchronizeStream(stream); | ||
| 126 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 127 | - // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 128 | - auto size = GetShapeSize(stdOutShape); | ||
| 129 | - std::vector<float> stdResultData(size, 0); | ||
| 130 | - ret = aclrtMemcpy(stdResultData.data(), stdResultData.size() * sizeof(stdResultData[0]), stdOutDeviceAddr, size * sizeof(float), | ||
| 131 | - ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 132 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 133 | - for (int64_t i = 0; i < size; i++) { | ||
| 134 | - LOG_PRINT("stdResultData[%ld] is: %f\n", i, stdResultData[i]); | ||
| 135 | - } | ||
| 136 | - | ||
| 137 | - std::vector<float> meanResultData(size, 0); | ||
| 138 | - ret = aclrtMemcpy(meanResultData.data(), meanResultData.size() * sizeof(meanResultData[0]), meanOutDeviceAddr, size * sizeof(float), | ||
| 139 | - ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 140 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 141 | - for (int64_t i = 0; i < size; i++) { | ||
| 142 | - LOG_PRINT("meanResultData[%ld] is: %f\n", i, meanResultData[i]); | ||
| 143 | - } | ||
| 144 | - | ||
| 145 | - // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 146 | - aclDestroyTensor(self); | ||
| 147 | - aclDestroyTensor(stdOut); | ||
| 148 | - aclDestroyTensor(meanOut); | ||
| 149 | - | ||
| 150 | - // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 151 | - aclrtFree(selfDeviceAddr); | ||
| 152 | - aclrtFree(stdOutDeviceAddr); | ||
| 153 | - aclrtFree(meanOutDeviceAddr); | ||
| 154 | - if (workspaceSize > 0) { | ||
| 155 | - aclrtFree(workspaceAddr); | ||
| 156 | - } | ||
| 157 | - aclrtDestroyStream(stream); | ||
| 158 | - aclrtResetDevice(deviceId); | ||
| 159 | - aclFinalize(); | ||
| 160 | - return 0; | ||
| 161 | -} | ||
| @@ -0,0 +1,165 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_batch_norm_stats.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请Device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + | ||
| 58 | + // 调用aclrtMemcpy将Host侧数据拷贝到Device侧内存上 | ||
| 59 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 60 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 61 | + | ||
| 62 | + // 计算连续tensor的strides | ||
| 63 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 64 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 65 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 69 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 70 | + shape.data(), shape.size(), *deviceAddr); | ||
| 71 | + return 0; | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +int main() | ||
| 75 | +{ | ||
| 76 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 77 | + // 根据自己的实际device填写deviceId | ||
| 78 | + int32_t deviceId = 0; | ||
| 79 | + aclrtStream stream; | ||
| 80 | + auto ret = Init(deviceId, &stream); | ||
| 81 | + // check根据自己的需要处理 | ||
| 82 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 83 | + | ||
| 84 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 85 | + std::vector<int64_t> inputShape = {2, 3}; | ||
| 86 | + std::vector<int64_t> outShape = { | ||
| 87 | + 3, | ||
| 88 | + }; | ||
| 89 | + void* inputDeviceAddr = nullptr; | ||
| 90 | + void* meanDeviceAddr = nullptr; | ||
| 91 | + void* invstdDeviceAddr = nullptr; | ||
| 92 | + aclTensor* input = nullptr; | ||
| 93 | + aclTensor* mean = nullptr; | ||
| 94 | + aclTensor* invstd = nullptr; | ||
| 95 | + std::vector<float> inputHostData = {1, 2, 3, 4, 5, 6}; | ||
| 96 | + std::vector<float> meanHostData = {0, 0, 0}; | ||
| 97 | + std::vector<float> invstdHostData = {0, 0, 0}; | ||
| 98 | + double eps = 1e-5; | ||
| 99 | + | ||
| 100 | + // 创建self aclTensor | ||
| 101 | + ret = CreateAclTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input); | ||
| 102 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 103 | + // 创建mean aclTensor | ||
| 104 | + ret = CreateAclTensor(meanHostData, outShape, &meanDeviceAddr, aclDataType::ACL_FLOAT, &mean); | ||
| 105 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 106 | + // 创建invstd aclTensor | ||
| 107 | + ret = CreateAclTensor(invstdHostData, outShape, &invstdDeviceAddr, aclDataType::ACL_FLOAT, &invstd); | ||
| 108 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 109 | + | ||
| 110 | + uint64_t workspaceSize = 0; | ||
| 111 | + aclOpExecutor* executor; | ||
| 112 | + // aclnnBatchNormStats接口调用示例 | ||
| 113 | + // 3.调用CANN算子库API,需要修改为具体的API名称 | ||
| 114 | + // 调用aclnnBatchNormStats第一段接口 | ||
| 115 | + ret = aclnnBatchNormStatsGetWorkspaceSize(input, eps, mean, invstd, &workspaceSize, &executor); | ||
| 116 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStatsGetWorkspaceSize failed. ERROR: %d\n", ret); | ||
| 117 | + return ret); | ||
| 118 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 119 | + void* workspaceAddr = nullptr; | ||
| 120 | + if (workspaceSize > 0) { | ||
| 121 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 122 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 123 | + } | ||
| 124 | + // 调用aclnnBatchNormStats第二段接口 | ||
| 125 | + ret = aclnnBatchNormStats(workspaceAddr, workspaceSize, executor, stream); | ||
| 126 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStats failed. ERROR: %d\n", ret); return ret); | ||
| 127 | + | ||
| 128 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 129 | + ret = aclrtSynchronizeStream(stream); | ||
| 130 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 131 | + | ||
| 132 | + // 5.获取输出的值,将Device侧内存上的结果拷贝至Host侧,需要根据具体API的接口定义修改 | ||
| 133 | + auto size = GetShapeSize(outShape); | ||
| 134 | + std::vector<float> meanData(size, 0); | ||
| 135 | + ret = aclrtMemcpy(meanData.data(), meanData.size() * sizeof(meanData[0]), meanDeviceAddr, | ||
| 136 | + size * sizeof(meanData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 137 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 138 | + for (int64_t i = 0; i < size; i++) { | ||
| 139 | + LOG_PRINT("mean result[%ld] is: %f\n", i, meanData[i]); | ||
| 140 | + } | ||
| 141 | + std::vector<float> invstdData(size, 0); | ||
| 142 | + ret = aclrtMemcpy(invstdData.data(), invstdData.size() * sizeof(invstdData[0]), invstdDeviceAddr, | ||
| 143 | + size * sizeof(invstdData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 144 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 145 | + for (int64_t i = 0; i < size; i++) { | ||
| 146 | + LOG_PRINT("mean result[%ld] is: %f\n", i, invstdData[i]); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 150 | + aclDestroyTensor(input); | ||
| 151 | + aclDestroyTensor(mean); | ||
| 152 | + aclDestroyTensor(invstd); | ||
| 153 | + | ||
| 154 | + // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 155 | + aclrtFree(inputDeviceAddr); | ||
| 156 | + aclrtFree(meanDeviceAddr); | ||
| 157 | + aclrtFree(invstdDeviceAddr); | ||
| 158 | + if (workspaceSize > 0) { | ||
| 159 | + aclrtFree(workspaceAddr); | ||
| 160 | + } | ||
| 161 | + aclrtDestroyStream(stream); | ||
| 162 | + aclrtResetDevice(deviceId); | ||
| 163 | + aclFinalize(); | ||
| 164 | + return 0; | ||
| 165 | +} | ||
| @@ -0,0 +1,167 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_std_mean_correction.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shape_size = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shape_size *= i; | ||
| 33 | + } | ||
| 34 | + return shape_size; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + | ||
| 58 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 59 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 60 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 61 | + | ||
| 62 | + // 计算连续tensor的strides | ||
| 63 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 64 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 65 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 69 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 70 | + shape.data(), shape.size(), *deviceAddr); | ||
| 71 | + return 0; | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +int main() | ||
| 75 | +{ | ||
| 76 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 77 | + // 根据自己的实际device填写deviceId | ||
| 78 | + int32_t deviceId = 0; | ||
| 79 | + aclrtStream stream; | ||
| 80 | + auto ret = Init(deviceId, &stream); | ||
| 81 | + // check根据自己的需要处理 | ||
| 82 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 83 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 84 | + std::vector<int64_t> selfShape = {2, 3, 4}; | ||
| 85 | + std::vector<int64_t> stdOutShape = {2, 4}; | ||
| 86 | + std::vector<int64_t> meanOutShape = {2, 4}; | ||
| 87 | + void* selfDeviceAddr = nullptr; | ||
| 88 | + void* stdOutDeviceAddr = nullptr; | ||
| 89 | + void* meanOutDeviceAddr = nullptr; | ||
| 90 | + aclTensor* self = nullptr; | ||
| 91 | + aclTensor* stdOut = nullptr; | ||
| 92 | + aclTensor* meanOut = nullptr; | ||
| 93 | + std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, | ||
| 94 | + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; | ||
| 95 | + std::vector<float> stdOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0}; | ||
| 96 | + std::vector<float> meanOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0}; | ||
| 97 | + std::vector<int64_t> dimData = {1}; | ||
| 98 | + int64_t correction = 1; | ||
| 99 | + bool keepdim = false; | ||
| 100 | + // 创建self aclTensor | ||
| 101 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 102 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 103 | + // 创建stdOut aclTensor | ||
| 104 | + ret = CreateAclTensor(stdOutHostData, stdOutShape, &stdOutDeviceAddr, aclDataType::ACL_FLOAT, &stdOut); | ||
| 105 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 106 | + // 创建meanOut aclTensor | ||
| 107 | + ret = CreateAclTensor(meanOutHostData, meanOutShape, &meanOutDeviceAddr, aclDataType::ACL_FLOAT, &meanOut); | ||
| 108 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 109 | + | ||
| 110 | + const aclIntArray* dim = aclCreateIntArray(dimData.data(), dimData.size()); | ||
| 111 | + CHECK_RET(dim != nullptr, return ACL_ERROR_INTERNAL_ERROR); | ||
| 112 | + | ||
| 113 | + // 3.调用CANN算子库API,需要修改为具体的API | ||
| 114 | + uint64_t workspaceSize = 0; | ||
| 115 | + aclOpExecutor* executor; | ||
| 116 | + // 调用aclnnStdMeanCorrection第一段接口 | ||
| 117 | + ret = aclnnStdMeanCorrectionGetWorkspaceSize(self, dim, correction, keepdim, stdOut, meanOut, &workspaceSize, | ||
| 118 | + &executor); | ||
| 119 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrectionGetWorkspaceSize failed. ERROR: %d\n", ret); | ||
| 120 | + return ret); | ||
| 121 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 122 | + void* workspaceAddr = nullptr; | ||
| 123 | + if (workspaceSize > 0) { | ||
| 124 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 125 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;); | ||
| 126 | + } | ||
| 127 | + // 调用aclnnStdMeanCorrection第二段接口 | ||
| 128 | + ret = aclnnStdMeanCorrection(workspaceAddr, workspaceSize, executor, stream); | ||
| 129 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrection failed. ERROR: %d\n", ret); return ret); | ||
| 130 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 131 | + ret = aclrtSynchronizeStream(stream); | ||
| 132 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 133 | + // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 134 | + auto size = GetShapeSize(stdOutShape); | ||
| 135 | + std::vector<float> stdResultData(size, 0); | ||
| 136 | + ret = aclrtMemcpy(stdResultData.data(), stdResultData.size() * sizeof(stdResultData[0]), stdOutDeviceAddr, | ||
| 137 | + size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 138 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 139 | + for (int64_t i = 0; i < size; i++) { | ||
| 140 | + LOG_PRINT("stdResultData[%ld] is: %f\n", i, stdResultData[i]); | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + std::vector<float> meanResultData(size, 0); | ||
| 144 | + ret = aclrtMemcpy(meanResultData.data(), meanResultData.size() * sizeof(meanResultData[0]), meanOutDeviceAddr, | ||
| 145 | + size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 146 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 147 | + for (int64_t i = 0; i < size; i++) { | ||
| 148 | + LOG_PRINT("meanResultData[%ld] is: %f\n", i, meanResultData[i]); | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 152 | + aclDestroyTensor(self); | ||
| 153 | + aclDestroyTensor(stdOut); | ||
| 154 | + aclDestroyTensor(meanOut); | ||
| 155 | + | ||
| 156 | + // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 157 | + aclrtFree(selfDeviceAddr); | ||
| 158 | + aclrtFree(stdOutDeviceAddr); | ||
| 159 | + aclrtFree(meanOutDeviceAddr); | ||
| 160 | + if (workspaceSize > 0) { | ||
| 161 | + aclrtFree(workspaceAddr); | ||
| 162 | + } | ||
| 163 | + aclrtDestroyStream(stream); | ||
| 164 | + aclrtResetDevice(deviceId); | ||
| 165 | + aclFinalize(); | ||
| 166 | + return 0; | ||
| 167 | +} | ||
| @@ -92,4 +92,6 @@ | |||
| 92 | 92 | ||
| 93 | | 调用方式 | 调用样例 | 说明 | | 93 | | 调用方式 | 调用样例 | 说明 | |
| 94 | |--------|-------------------------------------------------------------------|------------------------------------------------------------------------| | 94 | |--------|-------------------------------------------------------------------|------------------------------------------------------------------------| |
| 95 | +| aclnn调用 | [test_aclnn_search_sorted](./examples/test_aclnn_search_sorted.cpp) | 通过[aclnnSearchSorted](./docs/aclnnSearchSorted.md)接口方式调用SearchSorted算子。 | | ||
| 96 | +| aclnn调用 | [test_aclnn_search_sorteds](./examples/test_aclnn_search_sorteds.cpp) | 通过[aclnnSearchSorteds](./docs/aclnnSearchSorteds.md)接口方式调用SearchSorted算子。 | | ||
| 95 | | 图模式调用 | [test_geir_search_sorted](./examples/test_geir_search_sorted.cpp) | 通过[算子IR](./op_graph/search_sorted_proto.h)构图方式调用SearchSorted算子。 | | 97 | | 图模式调用 | [test_geir_search_sorted](./examples/test_geir_search_sorted.cpp) | 通过[算子IR](./op_graph/search_sorted_proto.h)构图方式调用SearchSorted算子。 | |
| @@ -0,0 +1,165 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_searchsorted.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shape_size = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shape_size *= i; | ||
| 33 | + } | ||
| 34 | + return shape_size; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + | ||
| 58 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 59 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 60 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 61 | + | ||
| 62 | + // 计算连续tensor的strides | ||
| 63 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 64 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 65 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 69 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 70 | + shape.data(), shape.size(), *deviceAddr); | ||
| 71 | + return 0; | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +int main() | ||
| 75 | +{ | ||
| 76 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 77 | + // 根据自己的实际device填写deviceId | ||
| 78 | + int32_t deviceId = 0; | ||
| 79 | + aclrtStream stream; | ||
| 80 | + auto ret = Init(deviceId, &stream); | ||
| 81 | + // check根据自己的需要处理 | ||
| 82 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 83 | + | ||
| 84 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 85 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 86 | + std::vector<int64_t> sortedSequenceShape = {4, 4}; | ||
| 87 | + std::vector<int64_t> sorterShape = {4, 4}; | ||
| 88 | + std::vector<int64_t> outShape = {4, 2}; | ||
| 89 | + void* selfDeviceAddr = nullptr; | ||
| 90 | + void* sortedSequenceDeviceAddr = nullptr; | ||
| 91 | + void* sorterDeviceAddr = nullptr; | ||
| 92 | + void* outDeviceAddr = nullptr; | ||
| 93 | + aclTensor* self = nullptr; | ||
| 94 | + aclTensor* sortedSequence = nullptr; | ||
| 95 | + aclTensor* sorter = nullptr; | ||
| 96 | + aclTensor* out = nullptr; | ||
| 97 | + std::vector<float> selfHostData = {1, 3, 6, 8, 10, 11, 14, 16}; | ||
| 98 | + std::vector<float> sortedSequenceHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; | ||
| 99 | + std::vector<int64_t> sorterHostData = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}; | ||
| 100 | + std::vector<int64_t> outHostData = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 101 | + | ||
| 102 | + // 创建self aclTensor | ||
| 103 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 104 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 105 | + // 创建sortedSequence aclTensor | ||
| 106 | + ret = CreateAclTensor(sortedSequenceHostData, sortedSequenceShape, &sortedSequenceDeviceAddr, | ||
| 107 | + aclDataType::ACL_FLOAT, &sortedSequence); | ||
| 108 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 109 | + // 创建sorter aclTensor | ||
| 110 | + ret = CreateAclTensor(sorterHostData, sorterShape, &sorterDeviceAddr, aclDataType::ACL_INT64, &sorter); | ||
| 111 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 112 | + // 创建out aclTensor | ||
| 113 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_INT64, &out); | ||
| 114 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 115 | + bool outInt32 = false; | ||
| 116 | + bool right = false; | ||
| 117 | + // 3.调用CANN算子库API,需要修改为具体的API | ||
| 118 | + uint64_t workspaceSize = 0; | ||
| 119 | + aclOpExecutor* executor; | ||
| 120 | + // 调用aclnnSearchSorted第一段接口 | ||
| 121 | + ret = aclnnSearchSortedGetWorkspaceSize(sortedSequence, self, outInt32, right, sorter, out, &workspaceSize, | ||
| 122 | + &executor); | ||
| 123 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSortedGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 124 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 125 | + void* workspaceAddr = nullptr; | ||
| 126 | + if (workspaceSize > 0) { | ||
| 127 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 128 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;); | ||
| 129 | + } | ||
| 130 | + // 调用aclnnSearchSorted第二段接口 | ||
| 131 | + ret = aclnnSearchSorted(workspaceAddr, workspaceSize, executor, stream); | ||
| 132 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSorted failed. ERROR: %d\n", ret); return ret); | ||
| 133 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 134 | + ret = aclrtSynchronizeStream(stream); | ||
| 135 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 136 | + // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 137 | + auto size = GetShapeSize(outShape); | ||
| 138 | + std::vector<int64_t> resultData(size, 0); | ||
| 139 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, | ||
| 140 | + size * sizeof(int64_t), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 141 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 142 | + for (int64_t i = 0; i < size; i++) { | ||
| 143 | + LOG_PRINT("result[%ld] is: %ld\n", i, resultData[i]); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + // 6.释放aclTensor,需要根据具体API的接口定义修改 | ||
| 147 | + aclDestroyTensor(self); | ||
| 148 | + aclDestroyTensor(sortedSequence); | ||
| 149 | + aclDestroyTensor(sorter); | ||
| 150 | + aclDestroyTensor(out); | ||
| 151 | + | ||
| 152 | + // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 153 | + aclrtFree(selfDeviceAddr); | ||
| 154 | + aclrtFree(sortedSequenceDeviceAddr); | ||
| 155 | + aclrtFree(sorterDeviceAddr); | ||
| 156 | + aclrtFree(outDeviceAddr); | ||
| 157 | + if (workspaceSize > 0) { | ||
| 158 | + aclrtFree(workspaceAddr); | ||
| 159 | + } | ||
| 160 | + aclrtDestroyStream(stream); | ||
| 161 | + aclrtResetDevice(deviceId); | ||
| 162 | + aclFinalize(); | ||
| 163 | + | ||
| 164 | + return 0; | ||
| 165 | +} | ||
| @@ -0,0 +1,159 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_searchsorted.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shape_size = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shape_size *= i; | ||
| 33 | + } | ||
| 34 | + return shape_size; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 51 | + aclDataType dataType, aclTensor** tensor) | ||
| 52 | +{ | ||
| 53 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 54 | + // 调用aclrtMalloc申请device侧内存 | ||
| 55 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 57 | + | ||
| 58 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 59 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 60 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 61 | + | ||
| 62 | + // 计算连续tensor的strides | ||
| 63 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 64 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 65 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 69 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 70 | + shape.data(), shape.size(), *deviceAddr); | ||
| 71 | + return 0; | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +int main() | ||
| 75 | +{ | ||
| 76 | + // 1.(固定写法)device/stream初始化,参考acl API手册 | ||
| 77 | + // 根据自己的实际device填写deviceId | ||
| 78 | + int32_t deviceId = 0; | ||
| 79 | + aclrtStream stream; | ||
| 80 | + auto ret = Init(deviceId, &stream); | ||
| 81 | + // check根据自己的需要处理 | ||
| 82 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 83 | + | ||
| 84 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 85 | + std::vector<int64_t> sortedSequenceShape = {4}; | ||
| 86 | + std::vector<int64_t> sorterShape = {4}; | ||
| 87 | + std::vector<int64_t> outShape = {1}; | ||
| 88 | + void* sortedSequenceDeviceAddr = nullptr; | ||
| 89 | + void* sorterDeviceAddr = nullptr; | ||
| 90 | + void* outDeviceAddr = nullptr; | ||
| 91 | + aclTensor* sortedSequence = nullptr; | ||
| 92 | + aclTensor* sorter = nullptr; | ||
| 93 | + aclTensor* out = nullptr; | ||
| 94 | + std::vector<float> sortedSequenceHostData = {1, 3, 6, 8}; | ||
| 95 | + std::vector<int64_t> sorterHostData = {0, 1, 2, 3}; | ||
| 96 | + std::vector<int64_t> outHostData = {0}; | ||
| 97 | + | ||
| 98 | + // 创建sortedSequence aclTensor | ||
| 99 | + ret = CreateAclTensor(sortedSequenceHostData, sortedSequenceShape, &sortedSequenceDeviceAddr, | ||
| 100 | + aclDataType::ACL_FLOAT, &sortedSequence); | ||
| 101 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 102 | + // 创建sorter aclTensor | ||
| 103 | + ret = CreateAclTensor(sorterHostData, sorterShape, &sorterDeviceAddr, aclDataType::ACL_INT64, &sorter); | ||
| 104 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 105 | + // 创建out aclTensor | ||
| 106 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_INT64, &out); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 108 | + float value = 5; | ||
| 109 | + auto self = aclCreateScalar(&value, aclDataType::ACL_FLOAT); | ||
| 110 | + CHECK_RET(self != nullptr, LOG_PRINT("aclCreateScalar failed.\n"); return -1); | ||
| 111 | + bool outInt32 = false; | ||
| 112 | + bool right = false; | ||
| 113 | + // 3.调用CANN算子库API,需要修改为具体的API | ||
| 114 | + uint64_t workspaceSize = 0; | ||
| 115 | + aclOpExecutor* executor; | ||
| 116 | + // 调用aclnnSearchSorteds第一段接口 | ||
| 117 | + ret = aclnnSearchSortedsGetWorkspaceSize(sortedSequence, self, outInt32, right, sorter, out, &workspaceSize, | ||
| 118 | + &executor); | ||
| 119 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSortedsGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 120 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 121 | + void* workspaceAddr = nullptr; | ||
| 122 | + if (workspaceSize > 0) { | ||
| 123 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 124 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;); | ||
| 125 | + } | ||
| 126 | + // 调用aclnnSearchSorteds第二段接口 | ||
| 127 | + ret = aclnnSearchSorteds(workspaceAddr, workspaceSize, executor, stream); | ||
| 128 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSorteds failed. ERROR: %d\n", ret); return ret); | ||
| 129 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 130 | + ret = aclrtSynchronizeStream(stream); | ||
| 131 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 132 | + // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 133 | + auto size = GetShapeSize(outShape); | ||
| 134 | + std::vector<int64_t> resultData(size, 0); | ||
| 135 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, | ||
| 136 | + size * sizeof(int64_t), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 137 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 138 | + for (int64_t i = 0; i < size; i++) { | ||
| 139 | + LOG_PRINT("result[%ld] is: %ld\n", i, resultData[i]); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + // 6.释放aclTensor,需要根据具体API的接口定义修改 | ||
| 143 | + aclDestroyScalar(self); | ||
| 144 | + aclDestroyTensor(sortedSequence); | ||
| 145 | + aclDestroyTensor(sorter); | ||
| 146 | + aclDestroyTensor(out); | ||
| 147 | + | ||
| 148 | + // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 149 | + aclrtFree(sortedSequenceDeviceAddr); | ||
| 150 | + aclrtFree(sorterDeviceAddr); | ||
| 151 | + aclrtFree(outDeviceAddr); | ||
| 152 | + if (workspaceSize > 0) { | ||
| 153 | + aclrtFree(workspaceAddr); | ||
| 154 | + } | ||
| 155 | + aclrtDestroyStream(stream); | ||
| 156 | + aclrtResetDevice(deviceId); | ||
| 157 | + aclFinalize(); | ||
| 158 | + return 0; | ||
| 159 | +} | ||
| @@ -1,3 +1,9 @@ | |||
| 1 | # SilentCheck | 1 | # SilentCheck |
| 2 | 2 | ||
| 3 | 本目录仅包含SilentCheck算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 | 3 | 本目录仅包含SilentCheck算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 |
| 4 | + | ||
| 5 | +## 调用说明 | ||
| 6 | + | ||
| 7 | +| 调用方式 | 调用样例 | 说明 | | ||
| 8 | +|---------|---------|------| | ||
| 9 | +| aclnn调用 | [test_aclnn_silent_check](./examples/test_aclnn_silent_check.cpp) | 通过[aclnnSilentCheck](./docs/aclnnSilentCheck.md)接口方式调用SilentCheck算子。 | | ||
| @@ -0,0 +1,185 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_silent_check.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr) | ||
| 38 | +{ | ||
| 39 | + auto size = GetShapeSize(shape); | ||
| 40 | + std::vector<int32_t> resultData(size, 0); | ||
| 41 | + auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr, | ||
| 42 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return); | ||
| 44 | + for (int64_t i = 0; i < size; i++) { | ||
| 45 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 46 | + } | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 50 | +{ | ||
| 51 | + // 固定写法,acl初始化 | ||
| 52 | + auto ret = aclInit(nullptr); | ||
| 53 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 54 | + ret = aclrtSetDevice(deviceId); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + ret = aclrtCreateStream(stream); | ||
| 57 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 58 | + return 0; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +template <typename T> | ||
| 62 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 63 | + aclDataType dataType, aclTensor** tensor) | ||
| 64 | +{ | ||
| 65 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 66 | + // 调用aclrtMalloc申请device侧内存 | ||
| 67 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 68 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 69 | + | ||
| 70 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 71 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 72 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 73 | + | ||
| 74 | + // 计算连续tensor的strides | ||
| 75 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 76 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 77 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 81 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 82 | + shape.data(), shape.size(), *deviceAddr); | ||
| 83 | + return 0; | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +int main() | ||
| 87 | +{ | ||
| 88 | + // 1.(固定写法)device/stream初始化,参考acl对外接口列表 | ||
| 89 | + // 根据自己的实际device填写deviceId | ||
| 90 | + int32_t deviceId = 0; | ||
| 91 | + aclrtStream stream; | ||
| 92 | + auto ret = Init(deviceId, &stream); | ||
| 93 | + // check根据自己的需要处理 | ||
| 94 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 95 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 96 | + std::vector<int64_t> valShape = {}; | ||
| 97 | + std::vector<int64_t> inputGradShape = {4, 2}; | ||
| 98 | + std::vector<int64_t> sfdaShape = {3}; | ||
| 99 | + std::vector<int64_t> stepShape = {1}; | ||
| 100 | + std::vector<int64_t> resultShape = {1}; | ||
| 101 | + void* valDeviceAddr = nullptr; | ||
| 102 | + void* inputGradDeviceAddr = nullptr; | ||
| 103 | + void* sfdaDeviceAddr = nullptr; | ||
| 104 | + void* stepDeviceAddr = nullptr; | ||
| 105 | + void* resultDeviceAddr = nullptr; | ||
| 106 | + aclTensor* val = nullptr; | ||
| 107 | + aclTensor* inputGrad = nullptr; | ||
| 108 | + aclTensor* sfda = nullptr; | ||
| 109 | + aclTensor* step = nullptr; | ||
| 110 | + aclTensor* result = nullptr; | ||
| 111 | + std::vector<float> valHostData = {160.0}; | ||
| 112 | + std::vector<float> inputGradHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 113 | + std::vector<float> sfdaHostData = {70.0, 200.0, 400.0}; | ||
| 114 | + std::vector<int64_t> stepHostData = {7}; | ||
| 115 | + std::vector<int32_t> resultHostData = {0}; | ||
| 116 | + int32_t c_min_steps = 7; | ||
| 117 | + float c_thresh_l1 = 1000000; | ||
| 118 | + float c_coeff_l1 = 100000; | ||
| 119 | + float c_thresh_l2 = 10000; | ||
| 120 | + float c_coeff_l2 = 5000; | ||
| 121 | + int32_t npu_asd_detect = 3; | ||
| 122 | + | ||
| 123 | + // 创建val aclTensor | ||
| 124 | + ret = CreateAclTensor(valHostData, valShape, &valDeviceAddr, aclDataType::ACL_FLOAT, &val); | ||
| 125 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 126 | + // 创建input_grad aclTensor | ||
| 127 | + ret = CreateAclTensor(inputGradHostData, inputGradShape, &inputGradDeviceAddr, aclDataType::ACL_FLOAT, &inputGrad); | ||
| 128 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 129 | + // 创建sfda aclTensor | ||
| 130 | + ret = CreateAclTensor(sfdaHostData, sfdaShape, &sfdaDeviceAddr, aclDataType::ACL_FLOAT, &sfda); | ||
| 131 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 132 | + // 创建step aclTensor | ||
| 133 | + ret = CreateAclTensor(stepHostData, stepShape, &stepDeviceAddr, aclDataType::ACL_INT64, &step); | ||
| 134 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 135 | + // 创建result aclTensor | ||
| 136 | + ret = CreateAclTensor(resultHostData, resultShape, &resultDeviceAddr, aclDataType::ACL_INT32, &result); | ||
| 137 | + if (result == nullptr) { | ||
| 138 | + std::cout << "result is nullptr!" << std::endl; | ||
| 139 | + return 0; | ||
| 140 | + } | ||
| 141 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 142 | + | ||
| 143 | + // 3.调用CANN算子库API,需要修改为具体的HostApi | ||
| 144 | + uint64_t workspaceSize = 0; | ||
| 145 | + aclOpExecutor* executor; | ||
| 146 | + // 调用aclnnSilentCheck第一段接口 | ||
| 147 | + ret = aclnnSilentCheckGetWorkspaceSize(val, inputGrad, sfda, step, c_min_steps, c_thresh_l1, c_coeff_l1, | ||
| 148 | + c_thresh_l2, c_coeff_l2, npu_asd_detect, result, &workspaceSize, &executor); | ||
| 149 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheckGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 150 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 151 | + void* workspaceAddr = nullptr; | ||
| 152 | + if (workspaceSize > 0) { | ||
| 153 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 154 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 155 | + } | ||
| 156 | + // 调用aclnnSilentCheck第二段接口 | ||
| 157 | + ret = aclnnSilentCheck(workspaceAddr, workspaceSize, executor, stream); | ||
| 158 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheck failed. ERROR: %d\n", ret); return ret); | ||
| 159 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 160 | + ret = aclrtSynchronizeStream(stream); | ||
| 161 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 162 | + // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 163 | + PrintOutResult(resultShape, &resultDeviceAddr); | ||
| 164 | + | ||
| 165 | + // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 166 | + aclDestroyTensor(val); | ||
| 167 | + aclDestroyTensor(inputGrad); | ||
| 168 | + aclDestroyTensor(sfda); | ||
| 169 | + aclDestroyTensor(step); | ||
| 170 | + aclDestroyTensor(result); | ||
| 171 | + | ||
| 172 | + // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 173 | + aclrtFree(valDeviceAddr); | ||
| 174 | + aclrtFree(inputGradDeviceAddr); | ||
| 175 | + aclrtFree(sfdaDeviceAddr); | ||
| 176 | + aclrtFree(stepDeviceAddr); | ||
| 177 | + aclrtFree(resultDeviceAddr); | ||
| 178 | + if (workspaceSize > 0) { | ||
| 179 | + aclrtFree(workspaceAddr); | ||
| 180 | + } | ||
| 181 | + aclrtDestroyStream(stream); | ||
| 182 | + aclrtResetDevice(deviceId); | ||
| 183 | + aclFinalize(); | ||
| 184 | + return 0; | ||
| 185 | +} | ||
| @@ -1,3 +1,9 @@ | |||
| 1 | # SilentCheckV2 | 1 | # SilentCheckV2 |
| 2 | 2 | ||
| 3 | 本目录仅包含SilentCheckV2算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 | 3 | 本目录仅包含SilentCheckV2算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。 |
| 4 | + | ||
| 5 | +## 调用说明 | ||
| 6 | + | ||
| 7 | +| 调用方式 | 调用样例 | 说明 | | ||
| 8 | +|---------|---------|------| | ||
| 9 | +| aclnn调用 | [test_aclnn_silent_check_v2](./examples/test_aclnn_silent_check_v2.cpp) | 通过[aclnnSilentCheckV2](./docs/aclnnSilentCheckV2.md)接口方式调用SilentCheckV2算子。 | | ||
| @@ -0,0 +1,203 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include "acl/acl.h" | ||
| 14 | +#include "aclnnop/aclnn_silent_check_v2.h" | ||
| 15 | + | ||
| 16 | +#define CHECK_RET(cond, return_expr) \ | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | +#define LOG_PRINT(message, ...) \ | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr) | ||
| 38 | +{ | ||
| 39 | + auto size = GetShapeSize(shape); | ||
| 40 | + std::vector<int32_t> resultData(size, 0); | ||
| 41 | + auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr, | ||
| 42 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return); | ||
| 44 | + for (int64_t i = 0; i < size; i++) { | ||
| 45 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 46 | + } | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 50 | +{ | ||
| 51 | + // 固定写法,acl初始化 | ||
| 52 | + auto ret = aclInit(nullptr); | ||
| 53 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 54 | + ret = aclrtSetDevice(deviceId); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + ret = aclrtCreateStream(stream); | ||
| 57 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 58 | + return 0; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +template <typename T> | ||
| 62 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 63 | + aclDataType dataType, aclTensor** tensor) | ||
| 64 | +{ | ||
| 65 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 66 | + // 调用aclrtMalloc申请device侧内存 | ||
| 67 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 68 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 69 | + | ||
| 70 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 71 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 72 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 73 | + | ||
| 74 | + // 计算连续tensor的strides | ||
| 75 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 76 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 77 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 81 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 82 | + shape.data(), shape.size(), *deviceAddr); | ||
| 83 | + return 0; | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +int main() | ||
| 87 | +{ | ||
| 88 | + // 1.(固定写法)device/stream初始化,参考acl对外接口列表 | ||
| 89 | + // 根据自己的实际device填写deviceId | ||
| 90 | + int32_t deviceId = 0; | ||
| 91 | + aclrtStream stream; | ||
| 92 | + auto ret = Init(deviceId, &stream); | ||
| 93 | + // check根据自己的需要处理 | ||
| 94 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 95 | + // 2.构造输入与输出,需要根据API的接口自定义构造 | ||
| 96 | + std::vector<int64_t> valShape = {1}; | ||
| 97 | + std::vector<int64_t> maxShape = {1}; | ||
| 98 | + std::vector<int64_t> avgRefShape = {1}; | ||
| 99 | + std::vector<int64_t> inputGradRefShape = {2, 3}; | ||
| 100 | + std::vector<int64_t> stepRefShape = {1}; | ||
| 101 | + std::vector<int64_t> resultShape = {1}; | ||
| 102 | + void* valDeviceAddr = nullptr; | ||
| 103 | + void* maxDeviceAddr = nullptr; | ||
| 104 | + void* avgRefDeviceAddr = nullptr; | ||
| 105 | + void* inputGradRefDeviceAddr = nullptr; | ||
| 106 | + void* stepRefDeviceAddr = nullptr; | ||
| 107 | + void* resultDeviceAddr = nullptr; | ||
| 108 | + aclTensor* val = nullptr; | ||
| 109 | + aclTensor* max = nullptr; | ||
| 110 | + aclTensor* avgRef = nullptr; | ||
| 111 | + aclTensor* inputGradRef = nullptr; | ||
| 112 | + aclTensor* stepRef = nullptr; | ||
| 113 | + aclTensor* result = nullptr; | ||
| 114 | + std::vector<float> valHostData = {160.0}; | ||
| 115 | + std::vector<float> maxHostData = {400.0}; | ||
| 116 | + std::vector<float> avgRefHostData = {200.0}; | ||
| 117 | + std::vector<float> inputGradRefHostData = {0, 1, 2, 3, 4, 5}; | ||
| 118 | + std::vector<int64_t> stepRefHostData = {0}; | ||
| 119 | + std::vector<int64_t> dstSizeData = {2, 3}; | ||
| 120 | + std::vector<int64_t> dstStrideData = {3, 1}; | ||
| 121 | + std::vector<int64_t> dstOffsetData = {0}; | ||
| 122 | + std::vector<int32_t> resultHostData = {0}; | ||
| 123 | + aclIntArray* dstSize = aclCreateIntArray(dstSizeData.data(), 2); | ||
| 124 | + aclIntArray* dstStride = aclCreateIntArray(dstStrideData.data(), 2); | ||
| 125 | + aclIntArray* dstOffset = aclCreateIntArray(dstOffsetData.data(), 1); | ||
| 126 | + float cThreshL1 = 1000000; | ||
| 127 | + float cThreshL2 = 10000; | ||
| 128 | + float beta1 = 0.99; | ||
| 129 | + int32_t npuAsdDetect = 3; | ||
| 130 | + | ||
| 131 | + // 创建val aclTensor | ||
| 132 | + ret = CreateAclTensor(valHostData, valShape, &valDeviceAddr, aclDataType::ACL_FLOAT, &val); | ||
| 133 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 134 | + // 创建max aclTensor | ||
| 135 | + ret = CreateAclTensor(maxHostData, maxShape, &maxDeviceAddr, aclDataType::ACL_FLOAT, &max); | ||
| 136 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 137 | + // 创建avgRef aclTensor | ||
| 138 | + ret = CreateAclTensor(avgRefHostData, avgRefShape, &avgRefDeviceAddr, aclDataType::ACL_FLOAT, &avgRef); | ||
| 139 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 140 | + // 创建inputGradRef aclTensor | ||
| 141 | + ret = CreateAclTensor(inputGradRefHostData, inputGradRefShape, &inputGradRefDeviceAddr, aclDataType::ACL_FLOAT, | ||
| 142 | + &inputGradRef); | ||
| 143 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 144 | + // 创建stepRef aclTensor | ||
| 145 | + ret = CreateAclTensor(stepRefHostData, stepRefShape, &stepRefDeviceAddr, aclDataType::ACL_INT64, &stepRef); | ||
| 146 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 147 | + // 创建result aclTensor | ||
| 148 | + ret = CreateAclTensor(resultHostData, resultShape, &resultDeviceAddr, aclDataType::ACL_INT32, &result); | ||
| 149 | + if (result == nullptr) { | ||
| 150 | + std::cout << "result is nullptr!" << std::endl; | ||
| 151 | + return 0; | ||
| 152 | + } | ||
| 153 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 154 | + | ||
| 155 | + // 3.调用CANN算子库API,需要修改为具体的HostApi | ||
| 156 | + uint64_t workspaceSize = 0; | ||
| 157 | + aclOpExecutor* executor; | ||
| 158 | + // 调用aclnnSilentCheckV2第一段接口 | ||
| 159 | + ret = aclnnSilentCheckV2GetWorkspaceSize(val, max, avgRef, inputGradRef, stepRef, dstSize, dstStride, dstOffset, | ||
| 160 | + cThreshL1, cThreshL2, beta1, npuAsdDetect, result, &workspaceSize, | ||
| 161 | + &executor); | ||
| 162 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheckV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 163 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 164 | + void* workspaceAddr = nullptr; | ||
| 165 | + if (workspaceSize > 0) { | ||
| 166 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 167 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 168 | + } | ||
| 169 | + // 调用aclnnSilentCheckV2第二段接口 | ||
| 170 | + ret = aclnnSilentCheckV2(workspaceAddr, workspaceSize, executor, stream); | ||
| 171 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheckV2 failed. ERROR: %d\n", ret); return ret); | ||
| 172 | + // 4.(固定写法)同步等待任务执行结束 | ||
| 173 | + ret = aclrtSynchronizeStream(stream); | ||
| 174 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 175 | + // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 176 | + PrintOutResult(resultShape, &resultDeviceAddr); | ||
| 177 | + | ||
| 178 | + // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 179 | + aclDestroyTensor(val); | ||
| 180 | + aclDestroyTensor(max); | ||
| 181 | + aclDestroyTensor(avgRef); | ||
| 182 | + aclDestroyTensor(inputGradRef); | ||
| 183 | + aclDestroyTensor(stepRef); | ||
| 184 | + aclDestroyIntArray(dstSize); | ||
| 185 | + aclDestroyIntArray(dstStride); | ||
| 186 | + aclDestroyIntArray(dstOffset); | ||
| 187 | + aclDestroyTensor(result); | ||
| 188 | + | ||
| 189 | + // 7.释放device资源,需要根据具体API的接口定义修改 | ||
| 190 | + aclrtFree(valDeviceAddr); | ||
| 191 | + aclrtFree(maxDeviceAddr); | ||
| 192 | + aclrtFree(avgRefDeviceAddr); | ||
| 193 | + aclrtFree(inputGradRefDeviceAddr); | ||
| 194 | + aclrtFree(stepRefDeviceAddr); | ||
| 195 | + aclrtFree(resultDeviceAddr); | ||
| 196 | + if (workspaceSize > 0) { | ||
| 197 | + aclrtFree(workspaceAddr); | ||
| 198 | + } | ||
| 199 | + aclrtDestroyStream(stream); | ||
| 200 | + aclrtResetDevice(deviceId); | ||
| 201 | + aclFinalize(); | ||
| 202 | + return 0; | ||
| 203 | +} | ||


这里的信息不对,应补充算子kernel相关的定义和介绍