已合并
add ops aclnnInplaceErfinv and aclnnInplaceMish example code #3857
guijianwei创建于 4月16日
add ops aclnnInplaceErfinv and aclnnInplaceMish example code #3857
已合并
guijianwei创建于 4月16日
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_erfinv.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,
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+#include <iostream>
11+#include <vector>
12+#include "acl/acl.h"
13+#include "aclnnop/aclnn_mish.h"
14+ 
15+#define CHECK_RET(cond, return_expr) \
16+ do { \
17+ if (!(cond)) { \
18+ return_expr; \
19+ } \
20+ } while (0)
21+ 
22+#define LOG_PRINT(message, ...) \
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+}