已合并
aclnnGlobalMaxPool 新资料模板修改 #2163
sunchun创建于 4月10日
aclnnGlobalMaxPool 新资料模板修改 #2163
已合并
sunchun创建于 4月10日
已删除 :aclnnglobalmaxpool合入到cann/ops-mathmaster
1 个文件变更+199-141
@@ -15,37 +15,106 @@
15 15 
16## 功能说明16## 功能说明
17 17 
18-输入一个张量,并对同一通道中的值取最大值18+输入一个张量,并对同一通道中的值取最大值
19 19 
20## 函数原型20## 函数原型
21 21 
22-每个算子分为[两段式接口](../../../docs/zh/context/两段式接口.md),必须先调用aclnnGlobalMaxPoolGetWorkspaceSize接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用aclnnGlobalMaxPool接口执行计算。22+每个算子分为[两段式接口](../../../docs/zh/context/两段式接口.md),必须先调用"aclnnGlobalMaxPoolGetWorkspaceSize"接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用"aclnnGlobalMaxPool"接口执行计算。
23 23 
24-- `aclnnStatus aclnnGlobalMaxPoolGetWorkspaceSize(const aclTensor* self, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)`24+```Cpp
25-- `aclnnStatus aclnnGlobalMaxPool(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, const aclrtStream stream)`25+aclnnStatus aclnnGlobalMaxPoolGetWorkspaceSize(
26+ const aclTensor* self,
27+ aclTensor* out,
28+ uint64_t* workspaceSize,
29+ aclOpExecutor** executor)
30+```
31+ 
32+```Cpp
33+aclnnStatus aclnnGlobalMaxPool(
34+ void* workspace,
35+ uint64_t workspaceSize,
36+ aclOpExecutor* executor,
37+ const aclrtStream stream)
38+```
26 39 
27## aclnnGlobalMaxPoolGetWorkspaceSize40## aclnnGlobalMaxPoolGetWorkspaceSize
28 41 
29- **参数说明:**42- **参数说明:**
30 43 
31- - self(aclTensor*, 计算输入):Device侧的aclTensor,数据类型支持FLOAT、FLOAT16、DOUBLE。支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md),[数据格式](../../../docs/zh/context/数据格式.md)支持ND、NCHW、NCDHW。44+ <table style="undefined;table-layout: fixed; width: 1555px"><colgroup>
45+ <col style="width: 217px">
46+ <col style="width: 125px">
47+ <col style="width: 247px">
48+ <col style="width: 317px">
49+ <col style="width: 233px">
50+ <col style="width: 126px">
51+ <col style="width: 144px">
52+ <col style="width: 146px">
53+ </colgroup>
54+ <thead>
55+ <tr>
56+ <th>参数名</th>
57+ <th>输入/输出</th>
58+ <th>描述</th>
59+ <th>使用说明</th>
60+ <th>数据类型</th>
61+ <th>数据格式</th>
62+ <th>维度(shape)</th>
63+ <th>非连续Tensor</th>
64+ </tr></thead>
65+ <tbody>
66+ <tr>
67+ <td>self(aclTensor*)</td>
68+ <td>输入</td>
69+ <td>输入tensor。</td>
70+ <td>-</td>
71+ <td>FLOAT、FLOAT16、DOUBLE</td>
72+ <td>ND、NCHW、NCDHW</td>
73+ <td>4-8维</td>
74+ <td>√</td>
75+ </tr>
76+ <tr>
77+ <td>out(aclTensor*)</td>
78+ <td>输出</td>
79+ <td>输出tensor。</td>
80+ <td>需要与self数据类型相同。out前两维与self相同,其他维度均为1。</td>
81+ <td>FLOAT、FLOAT16、DOUBLE</td>
82+ <td>ND、NCHW、NCDHW</td>
83+ <td>4-8维</td>
84+ <td>√</td>
85+ </tr>
86+ <tr>
87+ <td>workspaceSize(uint64_t*)</td>
88+ <td>输出</td>
89+ <td>返回需要在Device侧申请的workspace大小。</td>
90+ <td>-</td>
91+ <td>-</td>
92+ <td>-</td>
93+ <td>-</td>
94+ <td>-</td>
95+ </tr>
96+ <tr>
97+ <td>executor(aclOpExecutor**)</td>
98+ <td>输出</td>
99+ <td>返回op执行器,包含了算子计算流程。</td>
100+ <td>-</td>
101+ <td>-</td>
102+ <td>-</td>
103+ <td>-</td>
104+ <td>-</td>
105+ </tr>
106+ </tbody></table>
32 107 
33- - out(aclTensor*, 计算输出)Device侧的aclTensor,数据类型支持FLOAT、FLOAT16、DOUBLE。支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md),[数据格式](../../../docs/zh/context/数据格式.md)支持ND、NCHW、NCDHW。108+- **返回值**
34- 
35- - workspaceSize(uint64_t*, 出参):返回需要在Device侧申请的workspace大小。
36- 
37- - executor(aclOpExecutor**, 出参):返回op执行器,包含了算子计算流程。
38- 
39-- **返回码:**
40 109 
41 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。110 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。
42 111 
43- 第一段接口完成入参校验,出现下场景时报错:112+ 第一段接口完成入参校验,出现下场景时报错:
44 113 
45 <table style="undefined;table-layout: fixed; width: 1150px"><colgroup>114 <table style="undefined;table-layout: fixed; width: 1150px"><colgroup>
46- <col style="width: 287px">115+ <col style="width: 300px">
47- <col style="width: 124px">116+ <col style="width: 134px">
48- <col style="width: 739px">117+ <col style="width: 716px">
49 </colgroup>118 </colgroup>
50 <thead>119 <thead>
51 <tr>120 <tr>
@@ -57,7 +126,7 @@
57 <tr>126 <tr>
58 <td>ACLNN_ERR_PARAM_NULLPTR</td>127 <td>ACLNN_ERR_PARAM_NULLPTR</td>
59 <td>161001</td>128 <td>161001</td>
60- <td>传入的selfout是空指针。</td>129+ <td>传入的selfout是空指针。</td>
61 </tr>130 </tr>
62 <tr>131 <tr>
63 <td rowspan="3">ACLNN_ERR_PARAM_INVALID</td>132 <td rowspan="3">ACLNN_ERR_PARAM_INVALID</td>
@@ -77,10 +146,10 @@
77 146 
78- **参数说明:**147- **参数说明:**
79 148 
80- <table style="undefined;table-layout: fixed; width: 1149px"><colgroup>149+ <table style="undefined;table-layout: fixed; width: 1151px"><colgroup>
81- <col style="width: 167px">150+ <col style="width: 184px">
82 <col style="width: 134px">151 <col style="width: 134px">
83- <col style="width: 848px">152+ <col style="width: 833px">
84 </colgroup>153 </colgroup>
85 <thead>154 <thead>
86 <tr>155 <tr>
@@ -112,7 +181,7 @@
112 </tbody>181 </tbody>
113 </table>182 </table>
114 183 
115-- **返回:**184+- **返回:**
116 185 
117 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。186 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。
118 187 
@@ -132,146 +201,135 @@
132#include "aclnnop/aclnn_global_max_pool.h"201#include "aclnnop/aclnn_global_max_pool.h"
133 202 
134#define CHECK_RET(cond, return_expr) \203#define CHECK_RET(cond, return_expr) \
135- do { \204+ do { \
136- if (!(cond)) { \205+ if (!(cond)) { \
137- return_expr; \206+ return_expr; \
138- } \207+ } \
139- } while (0)208+ } while (0)
140 209 
141-#define LOG_PRINT(message, ...) \210+#define LOG_PRINT(message, ...) \
142- do { \211+ do { \
143- printf(message, ##__VA_ARGS__); \212+ printf(message, ##__VA_ARGS__); \
144- } while (0)213+ } while (0)
145 214 
146-int64_t GetShapeSize(const std::vector<int64_t>& shape) {215+int64_t GetShapeSize(const std::vector<int64_t>& shape)
147- int64_t shape_size = 1;216+{
148- for (auto i : shape) {217+ int64_t shapeSize = 1;
149- shape_size *= i;218+ for (auto i : shape) {
150- }219+ shapeSize *= i;
151- return shape_size;220+ }
221+ return shapeSize;
152}222}
153 223 
154-int Init(int32_t deviceId, aclrtStream* stream) {224+int Init(int32_t deviceId, aclrtStream* stream)
155- // 固定写法,资源初始化225+{
156- auto ret = aclInit(nullptr);226+ // 固定写法,资源初始化
157- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);227+ auto ret = aclInit(nullptr);
158- ret = aclrtSetDevice(deviceId);228+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
159- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);229+ ret = aclrtSetDevice(deviceId);
160- ret = aclrtCreateStream(stream);230+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
161- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);231+ ret = aclrtCreateStream(stream);
162- return 0;232+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
233+ return 0;
163}234}
164 235 
165template <typename T>236template <typename T>
166-int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,237+int CreateAclTensor(
167- aclDataType dataType, aclTensor** tensor) {238+ const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType,
168- auto size = GetShapeSize(shape) * sizeof(T);239+ aclTensor** tensor)
169- // 调用aclrtMalloc申请device侧内存240+{
170- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);241+ auto size = GetShapeSize(shape) * sizeof(T);
171- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);242+ // 调用aclrtMalloc申请device侧内存
243+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
244+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
245+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
246+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
247+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
172 248 
173- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上249+ // 计算连续tensor的strides
174- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);250+ std::vector<int64_t> strides(shape.size(), 1);
175- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);251+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
252+ strides[i] = shape[i + 1] * strides[i + 1];
253+ }
176 254 
177- // 计算连续tensor的strides255+ // 调用aclCreateTensor接口创建aclTensor
178- std::vector<int64_t> strides(shape.size(), 1);256+ *tensor = aclCreateTensor(
179- for (int64_t i = shape.size() - 2; i >= 0; i--) {257+ shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(),
180- strides[i] = shape[i + 1] * strides[i + 1];258+ *deviceAddr);
181- }259+ return 0;
182- 
183- // 调用aclCreateTensor接口创建aclTensor
184- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
185- shape.data(), shape.size(), *deviceAddr);
186- return 0;
187}260}
188 261 
189-template <typename T>262+int main()
190-int CreateAclIntArray(const std::vector<T>& hostData, void** deviceAddr, aclIntArray** intArray) {263+{
191- auto size = GetShapeSize(hostData) * sizeof(T);264+ // device/stream初始化,参考acl API手册
192- // 调用aclrtMalloc申请device侧内存265+ int32_t deviceId = 0;
193- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);266+ aclrtStream stream;
194- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);267+ auto ret = Init(deviceId, &stream);
268+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
195 269 
196- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上270+ std::vector<int64_t> selfShape = {1, 3, 2, 2};
197- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);271+ std::vector<int64_t> outShape = {1, 3, 1, 1};
198- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
199 272 
200- // 调用aclCreateIntArray接口创建aclIntArray273+ void* selfDeviceAddr = nullptr;
201- *intArray = aclCreateIntArray(hostData.data(), hostData.size());274+ void* outDeviceAddr = nullptr;
202- return 0;275+ aclTensor* self = nullptr;
203-}276+ aclTensor* out = nullptr;
204 277 
205-int main() {278+ std::vector<float> selfHostData = {2, 3, 5, 8, 4, 12, 6, 7, 5, 3, 7, 6};
206- // 1. (固定写法)device/stream初始化,参考acl API手册279+ std::vector<float> outHostData = {4.5, 7.25, 5.25};
207- // 根据自己的实际device填写deviceId
208- int32_t deviceId = 0;
209- aclrtStream stream;
210- auto ret = Init(deviceId, &stream);
211- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
212 280 
213- // 2. 构造输入与输出,需要根据API的接口自定义构造281+ // 创建self aclTensor
214- std::vector<int64_t> selfShape = {1, 3, 2, 2};282+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
215- std::vector<int64_t> outShape = {1, 3, 1, 1};283+ CHECK_RET(ret == ACL_SUCCESS, return ret);
284+ // 创建out aclTensor
285+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
286+ CHECK_RET(ret == ACL_SUCCESS, return ret);
216 287 
217- void* selfDeviceAddr = nullptr;288+ // 调用CANN算子库API
218- void* outDeviceAddr = nullptr;289+ uint64_t workspaceSize = 0;
219- aclTensor* self = nullptr;290+ aclOpExecutor* executor;
220- aclTensor* out = nullptr;291+ // 调用aclnnGlobalMaxPool第一段接口
292+ ret = aclnnGlobalMaxPoolGetWorkspaceSize(self, out, &workspaceSize, &executor);
293+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGlobalMaxPoolGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
294+ // 根据第一段接口计算出的workspaceSize申请device内存
295+ void* workspaceAddr = nullptr;
296+ if (workspaceSize > 0) {
297+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
298+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
299+ }
300+ // 调用aclnnGlobalMaxPool第二段接口
301+ ret = aclnnGlobalMaxPool(workspaceAddr, workspaceSize, executor, stream);
302+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGlobalMaxPool failed. ERROR: %d\n", ret); return ret);
221 303 
222- std::vector<float> selfHostData = {2, 3, 5, 8, 4, 12, 6, 7, 5, 3, 7, 6};304+ // 同步等待任务执行结束
223- std::vector<float> outHostData = {4.5, 7.25, 5.25};305+ ret = aclrtSynchronizeStream(stream);
306+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
224 307 
225- // 创建self aclTensor308+ // 获取输出的值,将device侧内存上的结果拷贝至host侧
226- ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);309+ auto size = GetShapeSize(outShape);
227- CHECK_RET(ret == ACL_SUCCESS, return ret);310+ std::vector<float> resultData(size, 0);
228- // 创建out aclTensor311+ ret = aclrtMemcpy(
229- ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);312+ resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
230- CHECK_RET(ret == ACL_SUCCESS, return ret);313+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
314+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
315+ for (int64_t i = 0; i < size; i++) {
316+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
317+ }
231 318 
232- // 3. 调用CANN算子库API319+ // 释放aclTensor
233- uint64_t workspaceSize = 0;320+ aclDestroyTensor(self);
234- aclOpExecutor* executor;321+ aclDestroyTensor(out);
235- // 调用aclnnGlobalMaxPool第一段接口
236- ret = aclnnGlobalMaxPoolGetWorkspaceSize(self, out, &workspaceSize, &executor);
237- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGlobalMaxPoolGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
238- // 根据第一段接口计算出的workspaceSize申请device内存
239- void* workspaceAddr = nullptr;
240- if (workspaceSize > 0) {
241- ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
242- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
243- }
244- // 调用aclnnGlobalMaxPool第二段接口
245- ret = aclnnGlobalMaxPool(workspaceAddr, workspaceSize, executor, stream);
246- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGlobalMaxPool failed. ERROR: %d\n", ret); return ret);
247 322 
248- // 4. (固定写法)同步等待任务执行结束323+ // 释放资源
249- ret = aclrtSynchronizeStream(stream);324+ aclrtFree(selfDeviceAddr);
250- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);325+ aclrtFree(outDeviceAddr);
326+ if (workspaceSize > 0) {
327+ aclrtFree(workspaceAddr);
328+ }
329+ aclrtDestroyStream(stream);
330+ aclrtResetDevice(deviceId);
331+ aclFinalize();
251 332 
252- // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改333+ return 0;
253- auto size = GetShapeSize(outShape);
254- std::vector<float> resultData(size, 0);
255- ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]),
256- outDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
257- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy resultData from device to host failed. ERROR: %d\n", ret); return ret);
258- for (int64_t i = 0; i < size; i++) {
259- LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
260- }
261- 
262- // 6. 释放aclTensor,需要根据具体API的接口定义修改
263- aclDestroyTensor(self);
264- aclDestroyTensor(out);
265- 
266- // 7. 释放device资源,需要根据具体API的接口定义修改
267- aclrtFree(selfDeviceAddr);
268- aclrtFree(outDeviceAddr);
269- if (workspaceSize > 0) {
270- aclrtFree(workspaceAddr);
271- }
272- aclrtDestroyStream(stream);
273- aclrtResetDevice(deviceId);
274- aclFinalize();
275- return 0;
276}334}
277```335```