已合并
add ops aclnnInplaceErfinv and aclnnInplaceMish example code #3857
guijianwei创建于 4月16日
add ops aclnnInplaceErfinv and aclnnInplaceMish example code #3857
已合并
共 2 个文件变更+273-0
| @@ -0,0 +1,142 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | + | ||
| 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, | ||
| 66 | + shape.data(), shape.size(), *deviceAddr); | ||
| 67 | + return 0; | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +int main() { | ||
| 71 | + // 1. (固定写法)device/stream初始化,参考acl API手册 | ||
| 72 | + // 根据自己的实际device填写deviceId | ||
| 73 | + int32_t deviceId = 0; | ||
| 74 | + aclrtStream stream; | ||
| 75 | + auto ret = Init(deviceId, &stream); | ||
| 76 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 77 | + | ||
| 78 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 79 | + std::vector<int64_t> selfShape = {4, 4}; | ||
| 80 | + std::vector<int64_t> outShape = {4, 4}; | ||
| 81 | + void* selfDeviceAddr = nullptr; | ||
| 82 | + void* outDeviceAddr = nullptr; | ||
| 83 | + aclTensor* self = nullptr; | ||
| 84 | + aclTensor* out = nullptr; | ||
| 85 | + std::vector<float> selfHostData = {0, 1.123, -2.001, 303.45, 40009, -50.1234, 60.666, -7.6543, | ||
| 86 | + 8000, -9.009, 1024, -11.23345, 12, 1356, -14.99, -15.34023}; | ||
| 87 | + std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 88 | + | ||
| 89 | + // 创建self aclTensor | ||
| 90 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 91 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 92 | + // 创建out aclTensor | ||
| 93 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 94 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 95 | + | ||
| 96 | + // 以下为aclnnInplaceErfinv调用示例 | ||
| 97 | + // 1. 调用CANN算子库API,需要修改为具体的Api名称 | ||
| 98 | + uint64_t inplaceWorkspaceSize = 0; | ||
| 99 | + aclOpExecutor* inplaceExecutor; | ||
| 100 | + // 调用aclnnInplaceErfinv第一段接口 | ||
| 101 | + ret = aclnnInplaceErfinvGetWorkspaceSize(self, &inplaceWorkspaceSize, &inplaceExecutor); | ||
| 102 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceErfinvGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 103 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 104 | + void* inplaceWorkspaceAddr = nullptr; | ||
| 105 | + if (inplaceWorkspaceSize > 0) { | ||
| 106 | + ret = aclrtMalloc(&inplaceWorkspaceAddr, inplaceWorkspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;); | ||
| 108 | + } | ||
| 109 | + // 调用aclnnInplaceErfinv第二段接口 | ||
| 110 | + ret = aclnnInplaceErfinv(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream); | ||
| 111 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceErfinv failed. ERROR: %d\n", ret); return ret); | ||
| 112 | + | ||
| 113 | + // 2.(固定写法)同步等待任务执行结束 | ||
| 114 | + ret = aclrtSynchronizeStream(stream); | ||
| 115 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 116 | + | ||
| 117 | + // 3. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 118 | + auto inplaceSize = GetShapeSize(selfShape); | ||
| 119 | + std::vector<float> inplaceResultData(inplaceSize, 0); | ||
| 120 | + ret = aclrtMemcpy(inplaceResultData.data(), inplaceResultData.size() * sizeof(inplaceResultData[0]), selfDeviceAddr, | ||
| 121 | + inplaceSize * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 122 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 123 | + for (int64_t i = 0; i < inplaceSize; i++) { | ||
| 124 | + LOG_PRINT("inplaceResult[%ld] is: %f\n", i, inplaceResultData[i]); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + // 4. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 128 | + aclDestroyTensor(self); | ||
| 129 | + aclDestroyTensor(out); | ||
| 130 | + | ||
| 131 | + // 5. 释放device资源,需要根据具体API的接口定义修改 | ||
| 132 | + aclrtFree(selfDeviceAddr); | ||
| 133 | + aclrtFree(outDeviceAddr); | ||
| 134 | + if (inplaceWorkspaceSize > 0) { | ||
| 135 | + aclrtFree(inplaceWorkspaceAddr); | ||
| 136 | + } | ||
| 137 | + aclrtDestroyStream(stream); | ||
| 138 | + aclrtResetDevice(deviceId); | ||
| 139 | + aclFinalize(); | ||
| 140 | + | ||
| 141 | + return 0; | ||
| 142 | +} | ||
| @@ -0,0 +1,131 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + do { \ | ||
| 24 | + printf(message, ##__VA_ARGS__); \ | ||
| 25 | + } while (0) | ||
| 26 | + | ||
| 27 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 28 | + int64_t shapeSize = 1; | ||
| 29 | + for (auto i : shape) { | ||
| 30 | + shapeSize *= i; | ||
| 31 | + } | ||
| 32 | + return shapeSize; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 36 | + // 固定写法,资源初始化 | ||
| 37 | + auto ret = aclInit(nullptr); | ||
| 38 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 39 | + ret = aclrtSetDevice(deviceId); | ||
| 40 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 41 | + ret = aclrtCreateStream(stream); | ||
| 42 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 43 | + return 0; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +template <typename T> | ||
| 47 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 48 | + aclDataType dataType, aclTensor** tensor) { | ||
| 49 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 50 | + // 调用aclrtMalloc申请device侧内存 | ||
| 51 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 52 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 53 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 54 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + | ||
| 57 | + // 计算连续tensor的strides | ||
| 58 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 59 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 60 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 64 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 65 | + 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> selfRefShape = {4, 2}; | ||
| 79 | + | ||
| 80 | + void* selfRefDeviceAddr = nullptr; | ||
| 81 | + aclTensor* selfRef = nullptr; | ||
| 82 | + | ||
| 83 | + std::vector<float> selfRefHostData = {1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 8.0, 9.0}; | ||
| 84 | + | ||
| 85 | + // 创建selfRef aclTensor | ||
| 86 | + ret = CreateAclTensor(selfRefHostData, selfRefShape, &selfRefDeviceAddr, aclDataType::ACL_FLOAT, &selfRef); | ||
| 87 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 88 | + | ||
| 89 | + // 3. 调用CANN算子库API,需要修改为具体的Api名称 | ||
| 90 | + uint64_t workspaceSize = 0; | ||
| 91 | + aclOpExecutor* executor; | ||
| 92 | + // 调用aclnnInplaceMish第一段接口 | ||
| 93 | + ret = aclnnInplaceMishGetWorkspaceSize(selfRef, &workspaceSize, &executor); | ||
| 94 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceMishGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 95 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 96 | + void* workspaceAddr = nullptr; | ||
| 97 | + if (workspaceSize > 0) { | ||
| 98 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 99 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 100 | + } | ||
| 101 | + // 调用aclnnInplaceMish第二段接口 | ||
| 102 | + ret = aclnnInplaceMish(workspaceAddr, workspaceSize, executor, stream); | ||
| 103 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceMish failed. ERROR: %d\n", ret); return ret); | ||
| 104 | + | ||
| 105 | + // 4. (固定写法)同步等待任务执行结束 | ||
| 106 | + ret = aclrtSynchronizeStream(stream); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 108 | + | ||
| 109 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 110 | + auto size = GetShapeSize(selfRefShape); | ||
| 111 | + std::vector<float> resultData(size, 0); | ||
| 112 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), selfRefDeviceAddr, | ||
| 113 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 114 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 115 | + for (int64_t i = 0; i < size; i++) { | ||
| 116 | + LOG_PRINT("inplace result[%ld] is: %f\n", i, resultData[i]); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + // 6. 释放aclTensor,需要根据具体API的接口定义修改 | ||
| 120 | + aclDestroyTensor(selfRef); | ||
| 121 | + | ||
| 122 | + // 7. 释放device资源,需要根据具体API的接口定义修改 | ||
| 123 | + aclrtFree(selfRefDeviceAddr); | ||
| 124 | + if (workspaceSize > 0) { | ||
| 125 | + aclrtFree(workspaceAddr); | ||
| 126 | + } | ||
| 127 | + aclrtDestroyStream(stream); | ||
| 128 | + aclrtResetDevice(deviceId); | ||
| 129 | + aclFinalize(); | ||
| 130 | + return 0; | ||
| 131 | +} | ||