已关闭
Sigmoid算子AscendC实现 #425
天上的星星哪去了创建于 2025年12月16日关闭于 4月25日
Sigmoid算子AscendC实现 #425
已关闭
天上的星星哪去了创建于 2025年12月16日关闭于 4月25日
30 个文件变更+3976-0
@@ -0,0 +1,19 @@
1+# ----------------------------------------------------------------------------
2+# Copyright (c) 2025 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+file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
12+if(NOT ENABLE_TEST)
13+ list(REMOVE_ITEM CURRENT_DIRS tests)
14+endif()
15+foreach(SUB_DIR ${CURRENT_DIRS})
16+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt")
17+ add_subdirectory(${SUB_DIR})
18+ endif()
19+endforeach()
@@ -0,0 +1,499 @@
1+# aclnnSigmoid&aclnnInplaceSigmoid
2+ 
3+## 贡献说明
4+| 贡献者 | 贡献方 | 贡献算子 | 贡献时间 | 贡献内容 |
5+| ---- | ---- | ---- | ---- | ---- |
6+| 严浩 | 中国科学技术大学 | Sigmoid | 2026/2/9 | Sigmoid算子适配开源仓 |
7+ 
8+## 产品支持情况
9+ 
10+|产品 | 是否支持 |
11+|:-------------------------|:----------:|
12+| <term>Atlas A2 训练系列产品/Atlas 800I A2 推理产品/A200I A2 Box 异构组件</term> | √ |
13+ 
14+## 功能说明
15+ 
16+- 算子功能:对输入Tensor完成Sigmoid运算。
17+ 
18+- 计算公式:
19+ 
20+$$
21+out = {\frac{1} {1+{e}^{-input}}}
22+$$
23+ 
24+## 函数原型
25+- aclnnSigmoid和aclnnInplaceSigmoid实现相同的功能,使用区别如下,请根据自身实际场景选择合适的算子。
26+ - aclnnSigmoid:需新建一个输出张量对象存储计算结果。
27+ - aclnnInplaceSigmoid:无需新建输出张量对象,直接在输入张量的内存中存储计算结果。
28+- 每个算子分为[两段式接口](../../../docs/context/两段式接口.md),必须先调用 “aclnnSigmoidGetWorkspaceSize” 或者 “aclnnInplaceSigmoidGetWorkspaceSize” 接口获取入参并根据计算流程计算所需workspace大小,再调用 “aclnnSigmoid” 或者 “aclnnInplaceSigmoid” 接口执行计算。
29+ 
30+```Cpp
31+aclnnStatus aclnnSigmoidGetWorkspaceSize(
32+ const aclTensor *self,
33+ aclTensor *out,
34+ uint64_t *workspaceSize,
35+ aclOpExecutor **executor)
36+```
37+ 
38+```Cpp
39+aclnnStatus aclnnSigmoid(
40+ void* workspace,
41+ uint64_t workspaceSize,
42+ aclOpExecutor* executor,
43+ const aclrtStream stream)
44+```
45+ 
46+```Cpp
47+aclnnStatus aclnnInplaceSigmoidGetWorkspaceSize(
48+ aclTensor* selfRef,
49+ uint64_t* workspaceSize,
50+ aclOpExecutor** executor)
51+```
52+ 
53+```Cpp
54+aclnnStatus aclnnInplaceSigmoid(
55+ void* workspace,
56+ uint64_t workspaceSize,
57+ aclOpExecutor* executor,
58+ const aclrtStream stream)
59+```
60+ 
61+## aclnnSigmoidGetWorkspaceSize
62+ 
63+- **参数说明:**
64+ 
65+ <table style="undefined;table-layout: fixed; width: 1303px"><colgroup>
66+ <col style="width: 101px">
67+ <col style="width: 115px">
68+ <col style="width: 200px">
69+ <col style="width: 200px">
70+ <col style="width: 200px">
71+ <col style="width: 104px">
72+ <col style="width: 238px">
73+ <col style="width: 145px">
74+ </colgroup>
75+ <thead>
76+ <tr>
77+ <th>参数名</th>
78+ <th>输入/输出</th>
79+ <th>描述</th>
80+ <th>使用说明</th>
81+ <th>数据类型</th>
82+ <th>数据格式</th>
83+ <th>维度(shape)</th>
84+ <th>非连续Tensor</th>
85+ </tr></thead>
86+ <tbody>
87+ <tr>
88+ <td>self</td>
89+ <td>输入</td>
90+ <td>待进行Sigmoid计算的入参,公式中的input。</td>
91+ <td><ul><li>支持空Tensor。</li><li>shape需要与out一致。</li></ul></td>
92+ <td>FLOAT、FLOAT16、BFLOAT16</td>
93+ <td>ND</td>
94+ <td>0-8</td>
95+ <td>√</td>
96+ </tr>
97+ <tr>
98+ <td>out</td>
99+ <td>输出</td>
100+ <td>计算的出参。</td>
101+ <td>shape需要与self一致。</td>
102+ <td>FLOAT、FLOAT16、BFLOAT16</td>
103+ <td>ND</td>
104+ <td>0-8</td>
105+ <td>√</td>
106+ </tr>
107+ <tr>
108+ <td>workspaceSize</td>
109+ <td>输出</td>
110+ <td>返回需要在Device侧申请的workspace大小。</td>
111+ <td>-</td>
112+ <td>-</td>
113+ <td>-</td>
114+ <td>-</td>
115+ <td>-</td>
116+ </tr>
117+ <tr>
118+ <td>executor</td>
119+ <td>输出</td>
120+ <td>返回op执行器,包含了算子计算流程。</td>
121+ <td>-</td>
122+ <td>-</td>
123+ <td>-</td>
124+ <td>-</td>
125+ <td>-</td>
126+ </tr>
127+ </tbody>
128+ </table>
129+
130+ 
131+- **返回值:**
132+ 
133+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
134+ 第一段接口会完成入参校验,出现以下场景时报错:
135+ <table style="undefined;table-layout: fixed;width: 979px"><colgroup>
136+ <col style="width: 272px">
137+ <col style="width: 103px">
138+ <col style="width: 604px">
139+ </colgroup>
140+ <thead>
141+ <tr>
142+ <th>返回码</th>
143+ <th>错误码</th>
144+ <th>描述</th>
145+ </tr>
146+ </thead>
147+ <tbody>
148+ <tr>
149+ <td>ACLNN_ERR_PARAM_NULLPTR</td>
150+ <td>161001</td>
151+ <td>传入的self或out是空指针。</td>
152+ </tr>
153+ <tr>
154+ <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td>
155+ <td rowspan="8">161002</td>
156+ <td>self和out的数据类型不在支持的范围之内。</td>
157+ </tr>
158+ <tr>
159+ <td>self和out的shape不匹配。</td>
160+ </tr>
161+ </tbody></table>
162+ 
163+ 
164+## aclnnSigmoid
165+ 
166+- **参数说明:**
167+ 
168+ <table style="undefined;table-layout: fixed; width: 953px"><colgroup>
169+ <col style="width: 173px">
170+ <col style="width: 112px">
171+ <col style="width: 668px">
172+ </colgroup>
173+ <thead>
174+ <tr>
175+ <th>参数名</th>
176+ <th>输入/输出</th>
177+ <th>描述</th>
178+ </tr></thead>
179+ <tbody>
180+ <tr>
181+ <td>workspace</td>
182+ <td>输入</td>
183+ <td>在Device侧申请的workspace内存地址。</td>
184+ </tr>
185+ <tr>
186+ <td>workspaceSize</td>
187+ <td>输入</td>
188+ <td>在Device侧申请的workspace大小,由第一段接口aclnnSigmoidGetWorkspaceSize获取。</td>
189+ </tr>
190+ <tr>
191+ <td>executor</td>
192+ <td>输入</td>
193+ <td>op执行器,包含了算子计算流程。</td>
194+ </tr>
195+ <tr>
196+ <td>stream</td>
197+ <td>输入</td>
198+ <td>指定执行任务的Stream。</td>
199+ </tr>
200+ </tbody>
201+ </table>
202+ 
203+ 
204+- **返回值:**
205+ 
206+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
207+ 
208+## aclnnInplaceSigmoidGetWorkspaceSize
209+ 
210+- **参数说明:**
211+ 
212+ <table style="undefined;table-layout: fixed; width: 1235px"><colgroup>
213+ <col style="width: 101px">
214+ <col style="width: 115px">
215+ <col style="width: 247px">
216+ <col style="width: 108px">
217+ <col style="width: 177px">
218+ <col style="width: 104px">
219+ <col style="width: 238px">
220+ <col style="width: 145px">
221+ </colgroup>
222+ <thead>
223+ <tr>
224+ <th>参数名</th>
225+ <th>输入/输出</th>
226+ <th>描述</th>
227+ <th>使用说明</th>
228+ <th>数据类型</th>
229+ <th>数据格式</th>
230+ <th>维度(shape)</th>
231+ <th>非连续Tensor</th>
232+ </tr></thead>
233+ <tbody>
234+ <tr>
235+ <td>selfRef</td>
236+ <td>输入/输出</td>
237+ <td>计算的入参。</td>
238+ <td>-</td>
239+ <td>FLOAT、FLOAT16、BFLOAT16</td>
240+ <td>ND</td>
241+ <td>1-8</td>
242+ <td>√</td>
243+ </tr>
244+ <tr>
245+ <td>workspaceSize</td>
246+ <td>输出</td>
247+ <td>返回需要在Device侧申请的workspace大小。</td>
248+ <td>-</td>
249+ <td>-</td>
250+ <td>-</td>
251+ <td>-</td>
252+ <td>-</td>
253+ </tr>
254+ <tr>
255+ <td>executor</td>
256+ <td>输出</td>
257+ <td>返回op执行器,包含了算子计算流程。</td>
258+ <td>-</td>
259+ <td>-</td>
260+ <td>-</td>
261+ <td>-</td>
262+ <td>-</td>
263+ </tr>
264+ </tbody>
265+ </table>
266+
267+ 
268+- **返回值:**
269+ 
270+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
271+ 第一段接口会完成入参校验,出现以下场景时报错:
272+ <table style="undefined;table-layout: fixed;width: 979px"><colgroup>
273+ <col style="width: 272px">
274+ <col style="width: 103px">
275+ <col style="width: 604px">
276+ </colgroup>
277+ <thead>
278+ <tr>
279+ <th>返回码</th>
280+ <th>错误码</th>
281+ <th>描述</th>
282+ </tr>
283+ </thead>
284+ <tbody>
285+ <tr>
286+ <td>ACLNN_ERR_PARAM_NULLPTR</td>
287+ <td>161001</td>
288+ <td>传入的selfRef是空指针。</td>
289+ </tr>
290+ <tr>
291+ <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td>
292+ <td rowspan="8">161002</td>
293+ <td>selfRef的数据类型和数据格式不在支持的范围之内。</td>
294+ </tr>
295+ </tbody></table>
296+ 
297+ 
298+## aclnnInplaceSigmoid
299+ 
300+- **参数说明:**
301+ 
302+ <table style="undefined;table-layout: fixed; width: 953px"><colgroup>
303+ <col style="width: 173px">
304+ <col style="width: 112px">
305+ <col style="width: 668px">
306+ </colgroup>
307+ <thead>
308+ <tr>
309+ <th>参数名</th>
310+ <th>输入/输出</th>
311+ <th>描述</th>
312+ </tr></thead>
313+ <tbody>
314+ <tr>
315+ <td>workspace</td>
316+ <td>输入</td>
317+ <td>在Device侧申请的workspace内存地址。</td>
318+ </tr>
319+ <tr>
320+ <td>workspaceSize</td>
321+ <td>输入</td>
322+ <td>在Device侧申请的workspace大小,由第一段接口aclnnInplaceSigmoidGetWorkspaceSize获取。</td>
323+ </tr>
324+ <tr>
325+ <td>executor</td>
326+ <td>输入</td>
327+ <td>op执行器,包含了算子计算流程。</td>
328+ </tr>
329+ <tr>
330+ <td>stream</td>
331+ <td>输入</td>
332+ <td>指定执行任务的Stream。</td>
333+ </tr>
334+ </tbody>
335+ </table>
336+ 
337+ 
338+- **返回值:**
339+ 
340+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
341+ 
342+## 约束说明
343+ 
344+无。
345+ 
346+## 调用示例
347+示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../docs/context/编译与运行样例.md)。
348+```Cpp
349+#include <iostream>
350+#include <vector>
351+#include "acl/acl.h"
352+#include "aclnn_sigmoid.h"
353+ 
354+#define CHECK_RET(cond, return_expr) \
355+ do { \
356+ if (!(cond)) { \
357+ return_expr; \
358+ } \
359+ } while (0)
360+ 
361+#define LOG_PRINT(message, ...) \
362+ do { \
363+ printf(message, ##__VA_ARGS__); \
364+ } while (0)
365+ 
366+int64_t GetShapeSize(const std::vector<int64_t>& shape) {
367+ int64_t shapeSize = 1;
368+ for (auto i : shape) {
369+ shapeSize *= i;
370+ }
371+ return shapeSize;
372+}
373+ 
374+int Init(int32_t deviceId, aclrtStream* stream) {
375+ // 固定写法,资源初始化
376+ auto ret = aclInit(nullptr);
377+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
378+ ret = aclrtSetDevice(deviceId);
379+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
380+ ret = aclrtCreateStream(stream);
381+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
382+ return 0;
383+}
384+ 
385+template <typename T>
386+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
387+ aclDataType dataType, aclTensor** tensor) {
388+ auto size = GetShapeSize(shape) * sizeof(T);
389+ // 调用aclrtMalloc申请device侧内存
390+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
391+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
392+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
393+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
394+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
395+ 
396+ // 计算连续tensor的strides
397+ std::vector<int64_t> strides(shape.size(), 1);
398+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
399+ strides[i] = shape[i + 1] * strides[i + 1];
400+ }
401+ 
402+ // 调用aclCreateTensor接口创建aclTensor
403+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
404+ shape.data(), shape.size(), *deviceAddr);
405+ return 0;
406+}
407+ 
408+int main() {
409+ // 1. (固定写法)device/stream初始化,参考acl API手册
410+ // 根据自己的实际device填写deviceId
411+ int32_t deviceId = 0;
412+ aclrtStream stream;
413+ auto ret = Init(deviceId, &stream);
414+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
415+ 
416+ // 2. 构造输入与输出,需要根据API的接口自定义构造
417+ std::vector<int64_t> selfShape = {2, 2};
418+ std::vector<int64_t> outShape = {2, 2};
419+ void* selfDeviceAddr = nullptr;
420+ void* outDeviceAddr = nullptr;
421+ aclTensor* self = nullptr;
422+ aclTensor* out = nullptr;
423+ std::vector<float> selfHostData = {0, 1, 2, 3};
424+ std::vector<float> outHostData = {0, 0, 0, 0};
425+ // 创建self aclTensor
426+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
427+ CHECK_RET(ret == ACL_SUCCESS, return ret);
428+ // 创建out aclTensor
429+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
430+ CHECK_RET(ret == ACL_SUCCESS, return ret);
431+ 
432+ // 3. 调用CANN算子库API,需要修改为具体的Api名称
433+ uint64_t workspaceSize = 0;
434+ aclOpExecutor* executor;
435+ // 调用aclnnSigmoid第一段接口
436+ ret = aclnnSigmoidGetWorkspaceSize(self, out, &workspaceSize, &executor);
437+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSigmoidGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
438+ // 根据第一段接口计算出的workspaceSize申请device内存
439+ void* workspaceAddr = nullptr;
440+ if (workspaceSize > 0) {
441+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
442+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
443+ }
444+ // 调用aclnnSigmoid第二段接口
445+ ret = aclnnSigmoid(workspaceAddr, workspaceSize, executor, stream);
446+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSigmoid failed. ERROR: %d\n", ret); return ret);
447+ 
448+ uint64_t inplaceWorkspaceSize = 0;
449+ aclOpExecutor* inplaceExecutor;
450+ // 调用aclnnInplaceSigmoid第一段接口
451+ ret = aclnnInplaceSigmoidGetWorkspaceSize(self, &inplaceWorkspaceSize, &inplaceExecutor);
452+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceSigmoidGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
453+ // 根据第一段接口计算出的workspaceSize申请device内存
454+ void* inplaceWorkspaceAddr = nullptr;
455+ if (inplaceWorkspaceSize > 0) {
456+ ret = aclrtMalloc(&inplaceWorkspaceAddr, inplaceWorkspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
457+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
458+ }
459+ // 调用aclnnInplaceSigmoid第二段接口
460+ ret = aclnnInplaceSigmoid(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream);
461+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceSigmoid failed. ERROR: %d\n", ret); return ret);
462+ 
463+ // 4. (固定写法)同步等待任务执行结束
464+ ret = aclrtSynchronizeStream(stream);
465+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
466+ 
467+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
468+ auto size = GetShapeSize(outShape);
469+ std::vector<float> resultData(size, 0);
470+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
471+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
472+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
473+ for (int64_t i = 0; i < size; i++) {
474+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
475+ }
476+ 
477+ auto inplaceSize = GetShapeSize(selfShape);
478+ std::vector<float> inplaceResultData(inplaceSize, 0);
479+ ret = aclrtMemcpy(inplaceResultData.data(), inplaceResultData.size() * sizeof(inplaceResultData[0]), selfDeviceAddr, inplaceSize * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST);
480+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
481+ for (int64_t i = 0; i < inplaceSize; i++) {
482+ LOG_PRINT("inplaceResult[%ld] is: %f\n", i, inplaceResultData[i]);
483+ }
484+ 
485+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
486+ aclDestroyTensor(self);
487+ aclDestroyTensor(out);
488+ // 7. 释放device资源,需要根据具体API的接口定义参数
489+ aclrtFree(selfDeviceAddr);
490+ aclrtFree(outDeviceAddr);
491+ if (workspaceSize > 0) {
492+ aclrtFree(workspaceAddr);
493+ }
494+ aclrtDestroyStream(stream);
495+ aclrtResetDevice(deviceId);
496+ aclFinalize();
497+ return 0;
498+}
499+```
@@ -0,0 +1,412 @@
1+# aclnnGluBackward
2+ 
3+## 产品支持情况
4+ 
5+|产品 | 是否支持 |
6+|:-------------------------|:----------:|
7+| <term>Atlas A2 训练系列产品/Atlas 800I A2 推理产品/A200I A2 Box 异构组件</term> | √ |
8+ 
9+ 
10+## 功能说明
11+ 
12+- 算子功能:完成aclnnGlu的反向。
13+- 计算公式:
14+ 
15+ $$
16+ \frac{\partial GLU(a,b)}{\partial(a,b)}=cat(\sigma(b),\sigma(b) \otimes a \otimes (1-\sigma(b)))
17+ $$
18+ 
19+- 数学计算表达式:
20+ 
21+ 假设输出的GLUGrad有两部分组成:out=[a_grad, b_grad],则:
22+ sig_b = sigmoid(b)
23+ **a_grad** = y_grad * sig_b
24+ **b_grad** = a_grad * (a - a * sig_b)
25+ 其中:y_grad为gradOut,a表示的是输入张量根据指定dim进行均分后的前部分张量,b表示后半部分张量。
26+ 
27+## 函数原型
28+ 
29+每个算子分为[两段式接口](../../../docs/context/两段式接口.md),必须先调用“aclnnGluBackwardGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnGluBackward”接口执行计算。
30+ 
31+- `aclnnStatus aclnnGluBackwardGetWorkspaceSize(const aclTensor *gradOut, const aclTensor *self, int64_t dim, const aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor)`
32+- `aclnnStatus aclnnGluBackward(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)`
33+ 
34+```Cpp
35+aclnnStatus aclnnSigmoidGetWorkspaceSize(
36+ const aclTensor *self,
37+ aclTensor *out,
38+ uint64_t *workspaceSize,
39+ aclOpExecutor **executor)
40+```
41+ 
42+```Cpp
43+aclnnStatus aclnnSigmoid(
44+ void* workspace,
45+ uint64_t workspaceSize,
46+ aclOpExecutor* executor,
47+ const aclrtStream stream)
48+```
49+ 
50+## aclnnGluBackwardGetWorkspaceSize
51+ 
52+- **参数说明:**
53+ 
54+ <table style="undefined;table-layout: fixed; width: 1303px"><colgroup>
55+ <col style="width: 101px">
56+ <col style="width: 115px">
57+ <col style="width: 200px">
58+ <col style="width: 200px">
59+ <col style="width: 200px">
60+ <col style="width: 104px">
61+ <col style="width: 238px">
62+ <col style="width: 145px">
63+ </colgroup>
64+ <thead>
65+ <tr>
66+ <th>参数名</th>
67+ <th>输入/输出</th>
68+ <th>描述</th>
69+ <th>使用说明</th>
70+ <th>数据类型</th>
71+ <th>数据格式</th>
72+ <th>维度(shape)</th>
73+ <th>非连续Tensor</th>
74+ </tr></thead>
75+ <tbody>
76+ <tr>
77+ <td>gradOut</td>
78+ <td>输入</td>
79+ <td>表示梯度更新系数,公式中的`y_grad`。</td>
80+ <td><ul><li>支持空Tensor。</li><li>数据类型必须与self的数据类型一致。</li><li>shape为$(*_1,M,*_2)$其中$*$表示self中对应维度,$M = N /2$。</li></ul></td>
81+ <td>DOUBLE、FLOAT、FLOAT16、BFLOAT16</td>
82+ <td>ND</td>
83+ <td>0-8</td>
84+ <td>√</td>
85+ </tr>
86+ <tr>
87+ <td>self</td>
88+ <td>输入</td>
89+ <td>待进行GluBackward计算的入参。</td>
90+ <td><ul><li>支持空Tensor。</li><li>tensor的维度必须大于0,且shape必须在入参dim对应的维度上可以整除2,shape表示为$(*_1,N,*_2)$其中$*$表示任何数量的附加维,$N$表示dim指定的维度大小。</li></ul></td>
91+ <td>DOUBLE、FLOAT、FLOAT16、BFLOAT16</td>
92+ <td>ND</td>
93+ <td>0-8</td>
94+ <td>√</td>
95+ </tr>
96+ <tr>
97+ <td>dim</td>
98+ <td>输入</td>
99+ <td>表示要拆分输入self的维度。</td>
100+ <td>取值范围[-self.dim,self.dim-1]。</td>
101+ <td>INT</td>
102+ <td>-</td>
103+ <td>-</td>
104+ <td>-</td>
105+ </tr>
106+ <tr>
107+ <td>out</td>
108+ <td>输出</td>
109+ <td>计算的出参。</td>
110+ <td><ul><li>数据类型必须与self的数据类型一致。</li><li>shape必须与self的shape一致。</li></ul></td>
111+ <td>DOUBLE、FLOAT、FLOAT16、BFLOAT16</td>
112+ <td>ND</td>
113+ <td>0-8</td>
114+ <td>√</td>
115+ </tr>
116+ <tr>
117+ <td>workspaceSize</td>
118+ <td>输出</td>
119+ <td>返回需要在Device侧申请的workspace大小。</td>
120+ <td>-</td>
121+ <td>-</td>
122+ <td>-</td>
123+ <td>-</td>
124+ <td>-</td>
125+ </tr>
126+ <tr>
127+ <td>executor</td>
128+ <td>输出</td>
129+ <td>返回op执行器,包含了算子计算流程。</td>
130+ <td>-</td>
131+ <td>-</td>
132+ <td>-</td>
133+ <td>-</td>
134+ <td>-</td>
135+ </tr>
136+ </tbody>
137+ </table>
138+
139+ 
140+- **返回值:**
141+ 
142+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
143+ 第一段接口会完成入参校验,出现以下场景时报错:
144+ <table style="undefined;table-layout: fixed;width: 979px"><colgroup>
145+ <col style="width: 272px">
146+ <col style="width: 103px">
147+ <col style="width: 604px">
148+ </colgroup>
149+ <thead>
150+ <tr>
151+ <th>返回码</th>
152+ <th>错误码</th>
153+ <th>描述</th>
154+ </tr>
155+ </thead>
156+ <tbody>
157+ <tr>
158+ <td>ACLNN_ERR_PARAM_NULLPTR</td>
159+ <td>161001</td>
160+ <td>传入的gradOut、self、out是空指针时。</td>
161+ </tr>
162+ <tr>
163+ <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td>
164+ <td rowspan="8">161002</td>
165+ <td>gradOut、self和out的数据类型不在支持的范围之内。</td>
166+ </tr>
167+ <tr>
168+ <td>入参dim超出了self的shape可选维度范围[-self.dim,self.dim-1]。</td>
169+ </tr>
170+ <tr>
171+ <td>入参self根据指定的dim所对应的维度不能整除2。</td>
172+ </tr>
173+ <tr>
174+ <td>out的shape不等于self的shape。</td>
175+ </tr>
176+ <tr>
177+ <td>gradOut、out的数据类型不与self一致。</td>
178+ </tr>
179+ <tr>
180+ <td>gradOut的shape不满足(*1,M,*2)其中M = N /2,N为self根据dim指定的该维度上的数值。</td>
181+ </tr>
182+ <tr>
183+ <td>gradOut、self、out的维度大于8。</td>
184+ </tr>
185+ <tr>
186+ <td>self的维度等于0。</td>
187+ </tr>
188+ </tbody></table>
189+ 
190+ 
191+## aclnnGluBackward
192+ 
193+- **参数说明:**
194+ 
195+ <table style="undefined;table-layout: fixed; width: 953px"><colgroup>
196+ <col style="width: 173px">
197+ <col style="width: 112px">
198+ <col style="width: 668px">
199+ </colgroup>
200+ <thead>
201+ <tr>
202+ <th>参数名</th>
203+ <th>输入/输出</th>
204+ <th>描述</th>
205+ </tr></thead>
206+ <tbody>
207+ <tr>
208+ <td>workspace</td>
209+ <td>输入</td>
210+ <td>在Device侧申请的workspace内存地址。</td>
211+ </tr>
212+ <tr>
213+ <td>workspaceSize</td>
214+ <td>输入</td>
215+ <td>在Device侧申请的workspace大小,由第一段接口aclnnGluBackwardGetWorkspaceSize获取。</td>
216+ </tr>
217+ <tr>
218+ <td>executor</td>
219+ <td>输入</td>
220+ <td>op执行器,包含了算子计算流程。</td>
221+ </tr>
222+ <tr>
223+ <td>stream</td>
224+ <td>输入</td>
225+ <td>指定执行任务的Stream。</td>
226+ </tr>
227+ </tbody>
228+ </table>
229+ 
230+ 
231+- **返回值:**
232+ 
233+ aclnnStatus: 返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
234+ 
235+## 约束说明
236+无。
237+ 
238+## 调用示例
239+ 
240+示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../docs/context/编译与运行样例.md)。
241+ 
242+```Cpp
243+#include <iostream>
244+#include <vector>
245+#include "acl/acl.h"
246+#include "aclnn_glu_backward.h"
247+ 
248+#define CHECK_RET(cond, return_expr) \
249+ do { \
250+ if (!(cond)) { \
251+ return_expr; \
252+ } \
253+ } while (0)
254+ 
255+#define LOG_PRINT(message, ...) \
256+ do { \
257+ printf(message, ##__VA_ARGS__); \
258+ } while (0)
259+ 
260+int64_t GetShapeSize(const std::vector<int64_t>& shape) {
261+ int64_t shape_size = 1;
262+ for (auto i : shape) {
263+ shape_size *= i;
264+ }
265+ return shape_size;
266+}
267+ 
268+int Init(int32_t deviceId, aclrtStream* stream) {
269+ // 固定写法,资源初始化
270+ auto ret = aclInit(nullptr);
271+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
272+ ret = aclrtSetDevice(deviceId);
273+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
274+ ret = aclrtCreateStream(stream);
275+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
276+ return 0;
277+}
278+ 
279+template <typename T>
280+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
281+ aclDataType dataType, aclTensor** tensor) {
282+ auto size = GetShapeSize(shape) * sizeof(T);
283+ // 调用aclrtMalloc申请device侧内存
284+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
285+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
286+ 
287+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
288+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
289+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
290+ 
291+ // 计算连续tensor的strides
292+ std::vector<int64_t> strides(shape.size(), 1);
293+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
294+ strides[i] = shape[i + 1] * strides[i + 1];
295+ }
296+ 
297+ // 调用aclCreateTensor接口创建aclTensor
298+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
299+ shape.data(), shape.size(), *deviceAddr);
300+ return 0;
301+}
302+ 
303+int main() {
304+ // 1. (固定写法)device/stream初始化, 参考acl API手册
305+ // 根据自己的实际device填写deviceId
306+ int32_t deviceId = 0;
307+ aclrtStream stream;
308+ auto ret = Init(deviceId, &stream);
309+ // check根据自己的需要处理
310+ CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
311+ // 2. 构造输入与输出,需要根据API的接口自定义构造
312+ std::vector<int64_t> gradOutShape = {2,4,3};
313+ std::vector<int64_t> selfShape = {2,4,6};
314+ std::vector<int64_t> outShape = {2,4,6};
315+ void* gradOutDeviceAddr = nullptr;
316+ void* selfDeviceAddr = nullptr;
317+ void* outDeviceAddr = nullptr;
318+ aclTensor* gradOut = nullptr;
319+ aclTensor* self = nullptr;
320+ aclTensor* out = nullptr;
321+ 
322+ std::vector<float> gradOutHostData = {
323+ 1, 1, 1,
324+ 1, 1, 1,
325+ 1, 1, 1,
326+ 1, 1, 1,
327+ 1, 1, 1,
328+ 1, 1, 1,
329+ 1, 1, 1,
330+ 1, 1, 1
331+ };
332+ 
333+ std::vector<float> selfHostData = {
334+ 0.2948, 1.6331, 2.3158, -0.6872, 0.3036, 0.1575,
335+ 0.2992, 1.0893, -0.1126, 0.1910, -1.3675, 0.5587,
336+ 0.4928, 1.4385, 0.6834, -0.6529, 1.0361, -0.6160,
337+ 1.2554, -2.0038, 0.5361, -1.4009, -0.7497, -0.8814,
338+ 0.4113, 0.7549, -1.2869, -1.4354, 0.6939, 0.2192,
339+ 0.3932, 1.8506, -0.7737, 3.6379, -0.9404, -1.1261,
340+ -1.6927, 0.8456, 0.6500, 0.2738, 0.5115, 0.3356,
341+ 0.5763, 0.2667, -0.6570, -0.4159, 1.5258, 0.0843
342+ };
343+ std::vector<float> outHostData = {
344+ 0, 0, 0, 0, 0, 0,
345+ 0, 0, 0, 0, 0, 0,
346+ 0, 0, 0, 0, 0, 0,
347+ 0, 0, 0, 0, 0, 0,
348+ 0, 0, 0, 0, 0, 0,
349+ 0, 0, 0, 0, 0, 0,
350+ 0, 0, 0, 0, 0, 0,
351+ 0, 0, 0, 0, 0, 0
352+ };
353+ 
354+ // 创建gradOut aclTensor
355+ ret = CreateAclTensor(gradOutHostData, gradOutShape, &gradOutDeviceAddr, aclDataType::ACL_FLOAT, &gradOut);
356+ CHECK_RET(ret == ACL_SUCCESS, return ret);
357+ // 创建self aclTensor
358+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
359+ CHECK_RET(ret == ACL_SUCCESS, return ret);
360+ // 创建out aclTensor
361+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
362+ CHECK_RET(ret == ACL_SUCCESS, return ret);
363+ 
364+ int64_t dim = -1;
365+ 
366+ // 3. 调用CANN算子库API,需要修改为具体的API
367+ uint64_t workspaceSize = 0;
368+ aclOpExecutor* executor;
369+ // 调用aclnnGluBackward第一段接口
370+ ret = aclnnGluBackwardGetWorkspaceSize(gradOut, self, dim, out, &workspaceSize, &executor);
371+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGluBackwardGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
372+ // 根据第一段接口计算出的workspaceSize申请device内存
373+ void* workspaceAddr = nullptr;
374+ if (workspaceSize > 0) {
375+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
376+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
377+ }
378+ // 调用aclnnGluBackward第二段接口
379+ ret = aclnnGluBackward(workspaceAddr, workspaceSize, executor, stream);
380+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGluBackward failed. ERROR: %d\n", ret); return ret);
381+ // 4. (固定写法)同步等待任务执行结束
382+ ret = aclrtSynchronizeStream(stream);
383+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
384+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
385+ auto size = GetShapeSize(outShape);
386+ std::vector<float> resultData(size, 0);
387+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(float),
388+ ACL_MEMCPY_DEVICE_TO_HOST);
389+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
390+ for (int64_t i = 0; i < size; i++) {
391+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
392+ }
393+ 
394+ // 6. 释放aclTensor,需要根据具体API的接口定义修改
395+ aclDestroyTensor(gradOut);
396+ aclDestroyTensor(self);
397+ aclDestroyTensor(out);
398+ 
399+ // 7. 释放device资源,需要根据具体API的接口定义修改
400+ aclrtFree(selfDeviceAddr);
401+ aclrtFree(outDeviceAddr);
402+ aclrtFree(gradOutDeviceAddr);
403+ if (workspaceSize > 0) {
404+ aclrtFree(workspaceAddr);
405+ }
406+ aclrtDestroyStream(stream);
407+ aclrtResetDevice(deviceId);
408+ aclFinalize();
409+ return 0;
410+}
411+```
412+ 
@@ -0,0 +1,494 @@
1+# aclnnSigmoid&aclnnInplaceSigmoid
2+ 
3+## 产品支持情况
4+ 
5+|产品 | 是否支持 |
6+|:-------------------------|:----------:|
7+| <term>Atlas A2 训练系列产品/Atlas 800I A2 推理产品/A200I A2 Box 异构组件</term> | √ |
8+ 
9+## 功能说明
10+ 
11+- 算子功能:对输入Tensor完成Sigmoid运算。
12+ 
13+- 计算公式:
14+ 
15+$$
16+out = {\frac{1} {1+{e}^{-input}}}
17+$$
18+ 
19+## 函数原型
20+- aclnnSigmoid和aclnnInplaceSigmoid实现相同的功能,使用区别如下,请根据自身实际场景选择合适的算子。
21+ - aclnnSigmoid:需新建一个输出张量对象存储计算结果。
22+ - aclnnInplaceSigmoid:无需新建输出张量对象,直接在输入张量的内存中存储计算结果。
23+- 每个算子分为[两段式接口](../../../docs/context/两段式接口.md),必须先调用 “aclnnSigmoidGetWorkspaceSize” 或者 “aclnnInplaceSigmoidGetWorkspaceSize” 接口获取入参并根据计算流程计算所需workspace大小,再调用 “aclnnSigmoid” 或者 “aclnnInplaceSigmoid” 接口执行计算。
24+ 
25+```Cpp
26+aclnnStatus aclnnSigmoidGetWorkspaceSize(
27+ const aclTensor *self,
28+ aclTensor *out,
29+ uint64_t *workspaceSize,
30+ aclOpExecutor **executor)
31+```
32+ 
33+```Cpp
34+aclnnStatus aclnnSigmoid(
35+ void* workspace,
36+ uint64_t workspaceSize,
37+ aclOpExecutor* executor,
38+ const aclrtStream stream)
39+```
40+ 
41+```Cpp
42+aclnnStatus aclnnInplaceSigmoidGetWorkspaceSize(
43+ aclTensor* selfRef,
44+ uint64_t* workspaceSize,
45+ aclOpExecutor** executor)
46+```
47+ 
48+```Cpp
49+aclnnStatus aclnnInplaceSigmoid(
50+ void* workspace,
51+ uint64_t workspaceSize,
52+ aclOpExecutor* executor,
53+ const aclrtStream stream)
54+```
55+ 
56+## aclnnSigmoidGetWorkspaceSize
57+ 
58+- **参数说明:**
59+ 
60+ <table style="undefined;table-layout: fixed; width: 1303px"><colgroup>
61+ <col style="width: 101px">
62+ <col style="width: 115px">
63+ <col style="width: 200px">
64+ <col style="width: 200px">
65+ <col style="width: 200px">
66+ <col style="width: 104px">
67+ <col style="width: 238px">
68+ <col style="width: 145px">
69+ </colgroup>
70+ <thead>
71+ <tr>
72+ <th>参数名</th>
73+ <th>输入/输出</th>
74+ <th>描述</th>
75+ <th>使用说明</th>
76+ <th>数据类型</th>
77+ <th>数据格式</th>
78+ <th>维度(shape)</th>
79+ <th>非连续Tensor</th>
80+ </tr></thead>
81+ <tbody>
82+ <tr>
83+ <td>self</td>
84+ <td>输入</td>
85+ <td>待进行Sigmoid计算的入参,公式中的input。</td>
86+ <td><ul><li>支持空Tensor。</li><li>shape需要与out一致。</li></ul></td>
87+ <td>FLOAT、FLOAT16、DOUBLE、INT8、INT16、INT32、INT64、UINT8、BOOL、COMPLEX64、COMPLEX128、BFLOAT16</td>
88+ <td>ND</td>
89+ <td>0-8</td>
90+ <td>√</td>
91+ </tr>
92+ <tr>
93+ <td>out</td>
94+ <td>输出</td>
95+ <td>计算的出参。</td>
96+ <td>shape需要与self一致。</td>
97+ <td>FLOAT、FLOAT16、DOUBLE、COMPLEX64、COMPLEX128、BFLOAT16</td>
98+ <td>ND</td>
99+ <td>0-8</td>
100+ <td>√</td>
101+ </tr>
102+ <tr>
103+ <td>workspaceSize</td>
104+ <td>输出</td>
105+ <td>返回需要在Device侧申请的workspace大小。</td>
106+ <td>-</td>
107+ <td>-</td>
108+ <td>-</td>
109+ <td>-</td>
110+ <td>-</td>
111+ </tr>
112+ <tr>
113+ <td>executor</td>
114+ <td>输出</td>
115+ <td>返回op执行器,包含了算子计算流程。</td>
116+ <td>-</td>
117+ <td>-</td>
118+ <td>-</td>
119+ <td>-</td>
120+ <td>-</td>
121+ </tr>
122+ </tbody>
123+ </table>
124+
125+ 
126+- **返回值:**
127+ 
128+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
129+ 第一段接口会完成入参校验,出现以下场景时报错:
130+ <table style="undefined;table-layout: fixed;width: 979px"><colgroup>
131+ <col style="width: 272px">
132+ <col style="width: 103px">
133+ <col style="width: 604px">
134+ </colgroup>
135+ <thead>
136+ <tr>
137+ <th>返回码</th>
138+ <th>错误码</th>
139+ <th>描述</th>
140+ </tr>
141+ </thead>
142+ <tbody>
143+ <tr>
144+ <td>ACLNN_ERR_PARAM_NULLPTR</td>
145+ <td>161001</td>
146+ <td>传入的self或out是空指针。</td>
147+ </tr>
148+ <tr>
149+ <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td>
150+ <td rowspan="8">161002</td>
151+ <td>self和out的数据类型不在支持的范围之内。</td>
152+ </tr>
153+ <tr>
154+ <td>self和out的shape不匹配。</td>
155+ </tr>
156+ </tbody></table>
157+ 
158+ 
159+## aclnnSigmoid
160+ 
161+- **参数说明:**
162+ 
163+ <table style="undefined;table-layout: fixed; width: 953px"><colgroup>
164+ <col style="width: 173px">
165+ <col style="width: 112px">
166+ <col style="width: 668px">
167+ </colgroup>
168+ <thead>
169+ <tr>
170+ <th>参数名</th>
171+ <th>输入/输出</th>
172+ <th>描述</th>
173+ </tr></thead>
174+ <tbody>
175+ <tr>
176+ <td>workspace</td>
177+ <td>输入</td>
178+ <td>在Device侧申请的workspace内存地址。</td>
179+ </tr>
180+ <tr>
181+ <td>workspaceSize</td>
182+ <td>输入</td>
183+ <td>在Device侧申请的workspace大小,由第一段接口aclnnSigmoidGetWorkspaceSize获取。</td>
184+ </tr>
185+ <tr>
186+ <td>executor</td>
187+ <td>输入</td>
188+ <td>op执行器,包含了算子计算流程。</td>
189+ </tr>
190+ <tr>
191+ <td>stream</td>
192+ <td>输入</td>
193+ <td>指定执行任务的Stream。</td>
194+ </tr>
195+ </tbody>
196+ </table>
197+ 
198+ 
199+- **返回值:**
200+ 
201+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
202+ 
203+## aclnnInplaceSigmoidGetWorkspaceSize
204+ 
205+- **参数说明:**
206+ 
207+ <table style="undefined;table-layout: fixed; width: 1235px"><colgroup>
208+ <col style="width: 101px">
209+ <col style="width: 115px">
210+ <col style="width: 247px">
211+ <col style="width: 108px">
212+ <col style="width: 177px">
213+ <col style="width: 104px">
214+ <col style="width: 238px">
215+ <col style="width: 145px">
216+ </colgroup>
217+ <thead>
218+ <tr>
219+ <th>参数名</th>
220+ <th>输入/输出</th>
221+ <th>描述</th>
222+ <th>使用说明</th>
223+ <th>数据类型</th>
224+ <th>数据格式</th>
225+ <th>维度(shape)</th>
226+ <th>非连续Tensor</th>
227+ </tr></thead>
228+ <tbody>
229+ <tr>
230+ <td>selfRef</td>
231+ <td>输入/输出</td>
232+ <td>计算的入参。</td>
233+ <td>-</td>
234+ <td>FLOAT、FLOAT16、DOUBLE、COMPLEX64、COMPLEX128、BFLOAT16</td>
235+ <td>ND</td>
236+ <td>1-8</td>
237+ <td>√</td>
238+ </tr>
239+ <tr>
240+ <td>workspaceSize</td>
241+ <td>输出</td>
242+ <td>返回需要在Device侧申请的workspace大小。</td>
243+ <td>-</td>
244+ <td>-</td>
245+ <td>-</td>
246+ <td>-</td>
247+ <td>-</td>
248+ </tr>
249+ <tr>
250+ <td>executor</td>
251+ <td>输出</td>
252+ <td>返回op执行器,包含了算子计算流程。</td>
253+ <td>-</td>
254+ <td>-</td>
255+ <td>-</td>
256+ <td>-</td>
257+ <td>-</td>
258+ </tr>
259+ </tbody>
260+ </table>
261+
262+ 
263+- **返回值:**
264+ 
265+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
266+ 第一段接口会完成入参校验,出现以下场景时报错:
267+ <table style="undefined;table-layout: fixed;width: 979px"><colgroup>
268+ <col style="width: 272px">
269+ <col style="width: 103px">
270+ <col style="width: 604px">
271+ </colgroup>
272+ <thead>
273+ <tr>
274+ <th>返回码</th>
275+ <th>错误码</th>
276+ <th>描述</th>
277+ </tr>
278+ </thead>
279+ <tbody>
280+ <tr>
281+ <td>ACLNN_ERR_PARAM_NULLPTR</td>
282+ <td>161001</td>
283+ <td>传入的selfRef是空指针。</td>
284+ </tr>
285+ <tr>
286+ <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td>
287+ <td rowspan="8">161002</td>
288+ <td>selfRef的数据类型和数据格式不在支持的范围之内。</td>
289+ </tr>
290+ </tbody></table>
291+ 
292+ 
293+## aclnnInplaceSigmoid
294+ 
295+- **参数说明:**
296+ 
297+ <table style="undefined;table-layout: fixed; width: 953px"><colgroup>
298+ <col style="width: 173px">
299+ <col style="width: 112px">
300+ <col style="width: 668px">
301+ </colgroup>
302+ <thead>
303+ <tr>
304+ <th>参数名</th>
305+ <th>输入/输出</th>
306+ <th>描述</th>
307+ </tr></thead>
308+ <tbody>
309+ <tr>
310+ <td>workspace</td>
311+ <td>输入</td>
312+ <td>在Device侧申请的workspace内存地址。</td>
313+ </tr>
314+ <tr>
315+ <td>workspaceSize</td>
316+ <td>输入</td>
317+ <td>在Device侧申请的workspace大小,由第一段接口aclnnInplaceSigmoidGetWorkspaceSize获取。</td>
318+ </tr>
319+ <tr>
320+ <td>executor</td>
321+ <td>输入</td>
322+ <td>op执行器,包含了算子计算流程。</td>
323+ </tr>
324+ <tr>
325+ <td>stream</td>
326+ <td>输入</td>
327+ <td>指定执行任务的Stream。</td>
328+ </tr>
329+ </tbody>
330+ </table>
331+ 
332+ 
333+- **返回值:**
334+ 
335+ aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/context/aclnn返回码.md)。
336+ 
337+## 约束说明
338+ 
339+无。
340+ 
341+## 调用示例
342+示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../docs/context/编译与运行样例.md)。
343+```Cpp
344+#include <iostream>
345+#include <vector>
346+#include "acl/acl.h"
347+#include "aclnn_sigmoid.h"
348+ 
349+#define CHECK_RET(cond, return_expr) \
350+ do { \
351+ if (!(cond)) { \
352+ return_expr; \
353+ } \
354+ } while (0)
355+ 
356+#define LOG_PRINT(message, ...) \
357+ do { \
358+ printf(message, ##__VA_ARGS__); \
359+ } while (0)
360+ 
361+int64_t GetShapeSize(const std::vector<int64_t>& shape) {
362+ int64_t shapeSize = 1;
363+ for (auto i : shape) {
364+ shapeSize *= i;
365+ }
366+ return shapeSize;
367+}
368+ 
369+int Init(int32_t deviceId, aclrtStream* stream) {
370+ // 固定写法,资源初始化
371+ auto ret = aclInit(nullptr);
372+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
373+ ret = aclrtSetDevice(deviceId);
374+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
375+ ret = aclrtCreateStream(stream);
376+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
377+ return 0;
378+}
379+ 
380+template <typename T>
381+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
382+ aclDataType dataType, aclTensor** tensor) {
383+ auto size = GetShapeSize(shape) * sizeof(T);
384+ // 调用aclrtMalloc申请device侧内存
385+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
386+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
387+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
388+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
389+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
390+ 
391+ // 计算连续tensor的strides
392+ std::vector<int64_t> strides(shape.size(), 1);
393+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
394+ strides[i] = shape[i + 1] * strides[i + 1];
395+ }
396+ 
397+ // 调用aclCreateTensor接口创建aclTensor
398+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
399+ shape.data(), shape.size(), *deviceAddr);
400+ return 0;
401+}
402+ 
403+int main() {
404+ // 1. (固定写法)device/stream初始化,参考acl API手册
405+ // 根据自己的实际device填写deviceId
406+ int32_t deviceId = 0;
407+ aclrtStream stream;
408+ auto ret = Init(deviceId, &stream);
409+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
410+ 
411+ // 2. 构造输入与输出,需要根据API的接口自定义构造
412+ std::vector<int64_t> selfShape = {2, 2};
413+ std::vector<int64_t> outShape = {2, 2};
414+ void* selfDeviceAddr = nullptr;
415+ void* outDeviceAddr = nullptr;
416+ aclTensor* self = nullptr;
417+ aclTensor* out = nullptr;
418+ std::vector<float> selfHostData = {0, 1, 2, 3};
419+ std::vector<float> outHostData = {0, 0, 0, 0};
420+ // 创建self aclTensor
421+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
422+ CHECK_RET(ret == ACL_SUCCESS, return ret);
423+ // 创建out aclTensor
424+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
425+ CHECK_RET(ret == ACL_SUCCESS, return ret);
426+ 
427+ // 3. 调用CANN算子库API,需要修改为具体的Api名称
428+ uint64_t workspaceSize = 0;
429+ aclOpExecutor* executor;
430+ // 调用aclnnSigmoid第一段接口
431+ ret = aclnnSigmoidGetWorkspaceSize(self, out, &workspaceSize, &executor);
432+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSigmoidGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
433+ // 根据第一段接口计算出的workspaceSize申请device内存
434+ void* workspaceAddr = nullptr;
435+ if (workspaceSize > 0) {
436+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
437+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
438+ }
439+ // 调用aclnnSigmoid第二段接口
440+ ret = aclnnSigmoid(workspaceAddr, workspaceSize, executor, stream);
441+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSigmoid failed. ERROR: %d\n", ret); return ret);
442+ 
443+ uint64_t inplaceWorkspaceSize = 0;
444+ aclOpExecutor* inplaceExecutor;
445+ // 调用aclnnInplaceSigmoid第一段接口
446+ ret = aclnnInplaceSigmoidGetWorkspaceSize(self, &inplaceWorkspaceSize, &inplaceExecutor);
447+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceSigmoidGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
448+ // 根据第一段接口计算出的workspaceSize申请device内存
449+ void* inplaceWorkspaceAddr = nullptr;
450+ if (inplaceWorkspaceSize > 0) {
451+ ret = aclrtMalloc(&inplaceWorkspaceAddr, inplaceWorkspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
452+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
453+ }
454+ // 调用aclnnInplaceSigmoid第二段接口
455+ ret = aclnnInplaceSigmoid(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream);
456+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceSigmoid failed. ERROR: %d\n", ret); return ret);
457+ 
458+ // 4. (固定写法)同步等待任务执行结束
459+ ret = aclrtSynchronizeStream(stream);
460+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
461+ 
462+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
463+ auto size = GetShapeSize(outShape);
464+ std::vector<float> resultData(size, 0);
465+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
466+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
467+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
468+ for (int64_t i = 0; i < size; i++) {
469+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
470+ }
471+ 
472+ auto inplaceSize = GetShapeSize(selfShape);
473+ std::vector<float> inplaceResultData(inplaceSize, 0);
474+ ret = aclrtMemcpy(inplaceResultData.data(), inplaceResultData.size() * sizeof(inplaceResultData[0]), selfDeviceAddr, inplaceSize * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST);
475+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
476+ for (int64_t i = 0; i < inplaceSize; i++) {
477+ LOG_PRINT("inplaceResult[%ld] is: %f\n", i, inplaceResultData[i]);
478+ }
479+ 
480+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
481+ aclDestroyTensor(self);
482+ aclDestroyTensor(out);
483+ // 7. 释放device资源,需要根据具体API的接口定义参数
484+ aclrtFree(selfDeviceAddr);
485+ aclrtFree(outDeviceAddr);
486+ if (workspaceSize > 0) {
487+ aclrtFree(workspaceAddr);
488+ }
489+ aclrtDestroyStream(stream);
490+ aclrtResetDevice(deviceId);
491+ aclFinalize();
492+ return 0;
493+}
494+```
@@ -0,0 +1,177 @@
1+/**
2+ * Copyright (c) 2025 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_glu_backward.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 shape_size = 1;
29+ for (auto i : shape) {
30+ shape_size *= i;
31+ }
32+ return shape_size;
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+ 
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根据自己的需要处理
77+ CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
78+ // 2. 构造输入与输出,需要根据API的接口自定义构造
79+ std::vector<int64_t> gradOutShape = {2,4,3};
80+ std::vector<int64_t> selfShape = {2,4,6};
81+ std::vector<int64_t> outShape = {2,4,6};
82+ void* gradOutDeviceAddr = nullptr;
83+ void* selfDeviceAddr = nullptr;
84+ void* outDeviceAddr = nullptr;
85+ aclTensor* gradOut = nullptr;
86+ aclTensor* self = nullptr;
87+ aclTensor* out = nullptr;
88+ 
89+ std::vector<float> gradOutHostData = {
90+ 1, 1, 1,
91+ 1, 1, 1,
92+ 1, 1, 1,
93+ 1, 1, 1,
94+ 1, 1, 1,
95+ 1, 1, 1,
96+ 1, 1, 1,
97+ 1, 1, 1
98+ };
99+ 
100+ std::vector<float> selfHostData = {
101+ 0.2948, 1.6331, 2.3158, -0.6872, 0.3036, 0.1575,
102+ 0.2992, 1.0893, -0.1126, 0.1910, -1.3675, 0.5587,
103+ 0.4928, 1.4385, 0.6834, -0.6529, 1.0361, -0.6160,
104+ 1.2554, -2.0038, 0.5361, -1.4009, -0.7497, -0.8814,
105+ 0.4113, 0.7549, -1.2869, -1.4354, 0.6939, 0.2192,
106+ 0.3932, 1.8506, -0.7737, 3.6379, -0.9404, -1.1261,
107+ -1.6927, 0.8456, 0.6500, 0.2738, 0.5115, 0.3356,
108+ 0.5763, 0.2667, -0.6570, -0.4159, 1.5258, 0.0843
109+ };
110+ std::vector<float> outHostData = {
111+ 0, 0, 0, 0, 0, 0,
112+ 0, 0, 0, 0, 0, 0,
113+ 0, 0, 0, 0, 0, 0,
114+ 0, 0, 0, 0, 0, 0,
115+ 0, 0, 0, 0, 0, 0,
116+ 0, 0, 0, 0, 0, 0,
117+ 0, 0, 0, 0, 0, 0,
118+ 0, 0, 0, 0, 0, 0
119+ };
120+ 
121+ // 创建gradOut aclTensor
122+ ret = CreateAclTensor(gradOutHostData, gradOutShape, &gradOutDeviceAddr, aclDataType::ACL_FLOAT, &gradOut);
123+ CHECK_RET(ret == ACL_SUCCESS, return ret);
124+ // 创建self aclTensor
125+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
126+ CHECK_RET(ret == ACL_SUCCESS, return ret);
127+ // 创建out aclTensor
128+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
129+ CHECK_RET(ret == ACL_SUCCESS, return ret);
130+ 
131+ int64_t dim = -1;
132+ 
133+ // 3. 调用CANN算子库API,需要修改为具体的API
134+ uint64_t workspaceSize = 0;
135+ aclOpExecutor* executor;
136+ // 调用aclnnGluBackward第一段接口
137+ ret = aclnnGluBackwardGetWorkspaceSize(gradOut, self, dim, out, &workspaceSize, &executor);
138+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGluBackwardGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
139+ // 根据第一段接口计算出的workspaceSize申请device内存
140+ void* workspaceAddr = nullptr;
141+ if (workspaceSize > 0) {
142+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
143+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
144+ }
145+ // 调用aclnnGluBackward第二段接口
146+ ret = aclnnGluBackward(workspaceAddr, workspaceSize, executor, stream);
147+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGluBackward failed. ERROR: %d\n", ret); return ret);
148+ // 4. (固定写法)同步等待任务执行结束
149+ ret = aclrtSynchronizeStream(stream);
150+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
151+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
152+ auto size = GetShapeSize(outShape);
153+ std::vector<float> resultData(size, 0);
154+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(float),
155+ ACL_MEMCPY_DEVICE_TO_HOST);
156+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
157+ for (int64_t i = 0; i < size; i++) {
158+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
159+ }
160+ 
161+ // 6. 释放aclTensor,需要根据具体API的接口定义修改
162+ aclDestroyTensor(gradOut);
163+ aclDestroyTensor(self);
164+ aclDestroyTensor(out);
165+ 
166+ // 7. 释放device资源,需要根据具体API的接口定义修改
167+ aclrtFree(selfDeviceAddr);
168+ aclrtFree(outDeviceAddr);
169+ aclrtFree(gradOutDeviceAddr);
170+ if (workspaceSize > 0) {
171+ aclrtFree(workspaceAddr);
172+ }
173+ aclrtDestroyStream(stream);
174+ aclrtResetDevice(deviceId);
175+ aclFinalize();
176+ return 0;
177+}
@@ -0,0 +1,135 @@
1+/**
2+ * Copyright (c) 2025 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_sigmoid.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> selfShape = {2, 2};
79+ std::vector<int64_t> outShape = {2, 2};
80+ void* selfDeviceAddr = nullptr;
81+ void* outDeviceAddr = nullptr;
82+ aclTensor* self = nullptr;
83+ aclTensor* out = nullptr;
84+ std::vector<float> selfHostData = {0, 1, 2, 3};
85+ std::vector<float> outHostData = {0, 0, 0, 0};
86+ // 创建self aclTensor
87+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
88+ CHECK_RET(ret == ACL_SUCCESS, return ret);
89+ // 创建out aclTensor
90+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
91+ CHECK_RET(ret == ACL_SUCCESS, return ret);
92+ 
93+ // 3. 调用CANN算子库API,需要修改为具体的Api名称
94+ uint64_t inplaceWorkspaceSize = 0;
95+ aclOpExecutor* inplaceExecutor;
96+ // 调用aclnnInplaceSigmoid第一段接口
97+ ret = aclnnInplaceSigmoidGetWorkspaceSize(self, &inplaceWorkspaceSize, &inplaceExecutor);
98+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceSigmoidGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
99+ // 根据第一段接口计算出的workspaceSize申请device内存
100+ void* inplaceWorkspaceAddr = nullptr;
101+ if (inplaceWorkspaceSize > 0) {
102+ ret = aclrtMalloc(&inplaceWorkspaceAddr, inplaceWorkspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
103+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
104+ }
105+ // 调用aclnnInplaceSigmoid第二段接口
106+ ret = aclnnInplaceSigmoid(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream);
107+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceSigmoid failed. ERROR: %d\n", ret); return ret);
108+ 
109+ // 4. (固定写法)同步等待任务执行结束
110+ ret = aclrtSynchronizeStream(stream);
111+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
112+ 
113+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
114+ auto inplaceSize = GetShapeSize(selfShape);
115+ std::vector<float> inplaceResultData(inplaceSize, 0);
116+ ret = aclrtMemcpy(inplaceResultData.data(), inplaceResultData.size() * sizeof(inplaceResultData[0]), selfDeviceAddr, inplaceSize * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST);
117+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
118+ for (int64_t i = 0; i < inplaceSize; i++) {
119+ LOG_PRINT("inplaceResult[%ld] is: %f\n", i, inplaceResultData[i]);
120+ }
121+ 
122+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
123+ aclDestroyTensor(self);
124+ aclDestroyTensor(out);
125+ // 7. 释放device资源,需要根据具体API的接口定义参数
126+ aclrtFree(selfDeviceAddr);
127+ aclrtFree(outDeviceAddr);
128+ if (inplaceWorkspaceSize > 0) {
129+ aclrtFree(inplaceWorkspaceAddr);
130+ }
131+ aclrtDestroyStream(stream);
132+ aclrtResetDevice(deviceId);
133+ aclFinalize();
134+ return 0;
135+}
@@ -0,0 +1,136 @@
1+/**
2+ * Copyright (c) 2025 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_sigmoid.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> selfShape = {2, 2};
79+ std::vector<int64_t> outShape = {2, 2};
80+ void* selfDeviceAddr = nullptr;
81+ void* outDeviceAddr = nullptr;
82+ aclTensor* self = nullptr;
83+ aclTensor* out = nullptr;
84+ std::vector<float> selfHostData = {0, 1, 2, 3};
85+ std::vector<float> outHostData = {0, 0, 0, 0};
86+ // 创建self aclTensor
87+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
88+ CHECK_RET(ret == ACL_SUCCESS, return ret);
89+ // 创建out aclTensor
90+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
91+ CHECK_RET(ret == ACL_SUCCESS, return ret);
92+ 
93+ // 3. 调用CANN算子库API,需要修改为具体的Api名称
94+ uint64_t workspaceSize = 0;
95+ aclOpExecutor* executor;
96+ // 调用aclnnSigmoid第一段接口
97+ ret = aclnnSigmoidGetWorkspaceSize(self, out, &workspaceSize, &executor);
98+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSigmoidGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
99+ // 根据第一段接口计算出的workspaceSize申请device内存
100+ void* workspaceAddr = nullptr;
101+ if (workspaceSize > 0) {
102+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
103+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
104+ }
105+ // 调用aclnnSigmoid第二段接口
106+ ret = aclnnSigmoid(workspaceAddr, workspaceSize, executor, stream);
107+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSigmoid failed. ERROR: %d\n", ret); return ret);
108+ 
109+ // 4. (固定写法)同步等待任务执行结束
110+ ret = aclrtSynchronizeStream(stream);
111+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
112+ 
113+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
114+ auto size = GetShapeSize(outShape);
115+ std::vector<float> resultData(size, 0);
116+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
117+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
118+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
119+ for (int64_t i = 0; i < size; i++) {
120+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
121+ }
122+ 
123+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
124+ aclDestroyTensor(self);
125+ aclDestroyTensor(out);
126+ // 7. 释放device资源,需要根据具体API的接口定义参数
127+ aclrtFree(selfDeviceAddr);
128+ aclrtFree(outDeviceAddr);
129+ if (workspaceSize > 0) {
130+ aclrtFree(workspaceAddr);
131+ }
132+ aclrtDestroyStream(stream);
133+ aclrtResetDevice(deviceId);
134+ aclFinalize();
135+ return 0;
136+}
@@ -0,0 +1,11 @@
1+# ----------------------------------------------------------------------------
2+# Copyright (c) 2025 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+add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE sigmoid ACLNNTYPE aclnn_exclude)
@@ -0,0 +1,275 @@
1+/**
2+ * Copyright (c) 2025 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 "aclnn_glu_backward.h"
12+#include "sigmoid.h"
13+#include "level0/split_v.h"
14+#include "level0/mul.h"
15+#include "level0/sub.h"
16+#include "level0/concat.h"
17+#include "aclnn_kernels/cast.h"
18+#include "aclnn_kernels/contiguous.h"
19+#include "opdev/common_types.h"
20+#include "opdev/data_type_utils.h"
21+#include "opdev/shape_utils.h"
22+#include "opdev/format_utils.h"
23+#include "opdev/op_dfx.h"
24+#include "opdev/op_executor.h"
25+#include "opdev/op_log.h"
26+#include "opdev/tensor_view_utils.h"
27+#include "aclnn/aclnn_base.h"
28+#include "aclnn_kernels/common/op_error_check.h"
29+ 
30+using namespace op;
31+#ifdef __cplusplus
32+extern "C" {
33+#endif
34+ 
35+/* GLU反向算子的完整计算流程如下:
36+ * self
37+ * |
38+ * gradOut Contiguous(workspace_8)
39+ * \ |-----------------------|
40+ * \ | dim \
41+ * \ | / \ \
42+ * Contiguous(workspace_0) SplitV(workspace_1) SplitV(workspace_1)
43+ * \ / \ / \
44+ * \ Sigmoid(workspace_2) / \
45+ * \ / \ /--------/
46+ * Mul(workspace_3) Mul(workspace_4) /
47+ * | \ \ /
48+ * | \ Sub(workspace_5)
49+ * | \ /
50+ * dim | Mul(workspace_6)
51+ * \ | /
52+ * \ | /
53+ * ConcatD(workspace_7)
54+ * |
55+ * ViewCopy
56+ * |
57+ * out
58+ */
59+ 
60+constexpr size_t MAX_DIM_LEN = 8;
61+constexpr int64_t SPLIT_NUM = 2;
62+ 
63+static bool CheckNotNull(const aclTensor *gradOut, const aclTensor *self, const aclTensor *out) {
64+ OP_CHECK_NULL(self, return false);
65+ OP_CHECK_NULL(gradOut, return false);
66+ OP_CHECK_NULL(out, return false);
67+ return true;
68+}
69+ 
70+// 根据API定义,需要列出所能支持的所有dtype
71+static const std::initializer_list<op::DataType> ASCEND910_DTYPE_SUPPORT_LIST = {
72+ op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_DOUBLE};
73+ 
74+static const std::initializer_list<op::DataType> ASCEND910B_DTYPE_SUPPORT_LIST = {
75+ op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_DOUBLE, op::DataType::DT_BF16};
76+ 
77+static const std::initializer_list<DataType>& GetDtypeSupportList() {
L

代码中支持910和950,但只支持A2,请确认

likedislike
天上的星星哪去了
3月27日 评论:
78+ if (GetCurrentPlatformInfo().GetSocVersion() >= SocVersion::ASCEND910B &&
79+ GetCurrentPlatformInfo().GetSocVersion() <= SocVersion::ASCEND910E) {
80+ return ASCEND910B_DTYPE_SUPPORT_LIST;
81+ } else {
82+ return ASCEND910_DTYPE_SUPPORT_LIST;
83+ }
84+}
85+ 
86+static bool CheckDtypeValid(const aclTensor *gradOut, const aclTensor *self, const aclTensor *out) {
87+ const auto& supportList = GetDtypeSupportList();
88+ // 检查self数据类型是否在算子的支持列表内
89+ OP_CHECK_DTYPE_NOT_SUPPORT(self, supportList, return false);
90+ 
91+ // 检查gradOut的dtype必修与self一致
92+ OP_CHECK_DTYPE_NOT_MATCH(gradOut, self->GetDataType(), return false);
93+ 
94+ // 检查out的dtype必修与self一致
95+ OP_CHECK_DTYPE_NOT_MATCH(out, self->GetDataType(), return false);
96+ 
97+ return true;
98+}
99+ 
100+static bool CheckParamsDataAndShape(const aclTensor *gradOut, const aclTensor *self,
101+ int64_t dim, const aclTensor *out) {
102+ // self、out的维度大于 MAX_DIM_LEN
103+ OP_CHECK_MAX_DIM(self, MAX_DIM_LEN, return false);
104+ OP_CHECK_MAX_DIM(out, MAX_DIM_LEN, return false);
105+ OP_CHECK_MAX_DIM(gradOut, MAX_DIM_LEN, return false);
106+ 
107+ // self的维度必须大于0
108+ OP_CHECK_MIN_DIM(self, 1, return false);
109+ 
110+ // 入参dim超出了self的shape可选维度范围[-self.dim,self.dim-1]
111+ int64_t selfDim = static_cast<int64_t>(self->GetViewShape().GetDimNum());
112+ if (dim < -selfDim || dim >= selfDim) {
113+ OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Dimension out of range (expected to be in range of [%ld, %ld], but got %ld).",
114+ -selfDim, (selfDim - 1), dim);
115+ return false;
116+ }
117+ 
118+ // 获取dim的非负数维度值selfDim=3时(-3,-2,-1) -> (0,1,2)
119+ int64_t positiveDim = dim;
120+ if (dim < 0) {
121+ positiveDim += selfDim;
122+ }
123+ 
124+ // 入参self根据指定的dim所对应的维度不能整除2
125+ int64_t splitShape = self->GetViewShape().GetDim(positiveDim);
126+ if (splitShape % SPLIT_NUM != 0) {
127+ OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Halving dimension must be even, but dimension %ld is size %ld.", dim, splitShape);
128+ return false;
129+ }
130+ 
131+ // gradOut 的shape不等于self根据dim拆分后的shape
132+ op::Shape gradOutShapeExpect = self->GetViewShape();
133+ int64_t gradOutShapeExpectForDim = gradOutShapeExpect.GetDim(static_cast<size_t>(positiveDim)) / SPLIT_NUM;
134+ gradOutShapeExpect.SetDim(static_cast<size_t>(positiveDim), gradOutShapeExpectForDim);
135+ if (gradOutShapeExpect != gradOut->GetViewShape()) {
136+ OP_LOGE(ACLNN_ERR_PARAM_INVALID, "The shape of gradOut must be %s, but got %s.",
137+ op::ToString(gradOutShapeExpect).GetString(), op::ToString(gradOut->GetViewShape()).GetString());
138+ return false;
139+ }
140+ 
141+ // out 的shape不等于self的shape
142+ OP_CHECK_SHAPE_NOT_EQUAL(out, self, return false);
143+ 
144+ return true;
145+}
146+ 
147+static aclnnStatus CheckParams(const aclTensor *gradOut, const aclTensor *self, int64_t dim, const aclTensor *out) {
148+ // 1.检查入参参数是否为空指针
149+ CHECK_RET(CheckNotNull(gradOut, self, out), ACLNN_ERR_PARAM_NULLPTR);
150+ 
151+ // 2. 检查输入的数据类型是否在API支持的数据类型范围之内
152+ CHECK_RET(CheckDtypeValid(gradOut, self, out), ACLNN_ERR_PARAM_INVALID);
153+ 
154+ // 3. 检查输入数据的有效性
155+ CHECK_RET(CheckParamsDataAndShape(gradOut, self, dim, out), ACLNN_ERR_PARAM_INVALID);
156+ 
157+ return ACLNN_SUCCESS;
158+}
159+ 
160+static inline aclIntArray *getDimAndSplitSize(const aclTensor *self, int64_t &positiveDim, int64_t dim,
161+ aclOpExecutor *executor) {
162+ // 入参self根据指定的dim所对应的维度除2,获取SplitV需要的splitSize
163+ int64_t selfDim = static_cast<int64_t>(self->GetViewShape().GetDimNum());
164+ if (dim < 0) {
165+ positiveDim += selfDim;
166+ }
167+ int64_t splitShape = self->GetViewShape().GetDim(positiveDim) / SPLIT_NUM;
168+ int64_t splitSizeValue[] = {splitShape, splitShape};
169+ return executor->AllocIntArray(splitSizeValue, SPLIT_NUM);
170+}
171+ 
172+aclnnStatus aclnnGluBackwardGetWorkspaceSize(const aclTensor *gradOut, const aclTensor *self, int64_t dim,
173+ const aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor) {
174+ L2_DFX_PHASE_1(aclnnGluBackward, DFX_IN(gradOut, self, dim), DFX_OUT(out));
175+ // 固定写法,创建OpExecutor
176+ auto uniqueExecutor = CREATE_EXECUTOR();
177+ CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
178+ 
179+ // 入参参数检查
180+ auto ret = CheckParams(gradOut, self, dim, out);
181+ CHECK_RET(ret == ACLNN_SUCCESS, ret);
182+ 
183+ // 如果为空tensor,则直接返回空
184+ if (self->IsEmpty()) {
185+ *workspaceSize = 0;
186+ uniqueExecutor.ReleaseTo(executor);
187+ return ACLNN_SUCCESS;
188+ }
189+ 
190+ // 入参self根据指定的dim所对应的维度除2,获取SplitV需要的splitSize
191+ int64_t positiveDim = dim;
192+ auto splitSize = getDimAndSplitSize(self, positiveDim, dim, uniqueExecutor.get());
193+ 
194+ // 将输入self转换成连续的tensor
195+ auto selfContiguous = l0op::Contiguous(self, uniqueExecutor.get());
196+ CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
197+ 
198+ // 将输入gradOut转换成连续的tensor
199+ auto gradOutContiguous = l0op::Contiguous(gradOut, uniqueExecutor.get());
200+ CHECK_RET(gradOutContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
201+ 
202+ // 将fp16转为fp32计算
203+ bool bf16Type = (self->GetDataType() == op::DataType::DT_FLOAT16) ? true : false;
204+ if (bf16Type) {
205+ selfContiguous = l0op::Cast(selfContiguous, op::DataType::DT_FLOAT, uniqueExecutor.get());
L

提升性能减少内存占用,可以在算子kernel中进行cast操作

likedislike
天上的星星哪去了
3月1日 评论:
206+ CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
207+ 
208+ gradOutContiguous = l0op::Cast(gradOutContiguous, op::DataType::DT_FLOAT, uniqueExecutor.get());
209+ CHECK_RET(gradOutContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
210+ }
211+ 
212+ // 调用SplitV算子
213+ auto splitResult = l0op::SplitV(selfContiguous, splitSize, positiveDim, uniqueExecutor.get());
214+ CHECK_RET(splitResult != nullptr, ACLNN_ERR_INNER_NULLPTR);
215+ 
216+ if (splitResult->Size() != static_cast<size_t>(SPLIT_NUM)) {
217+ OP_LOGE(ACLNN_ERR_INNER, "The result of SplitV must be equal 2, but get %zu.", splitResult->Size());
218+ return ACLNN_ERR_INNER;
219+ }
220+ 
221+ auto splitFirst = (*splitResult)[0];
222+ auto splitSecond = (*splitResult)[1];
223+ // 调用Sigmoid算子Kernel,Inplace方式减少空间占用
224+ splitSecond = l0op::Sigmoid(splitSecond, uniqueExecutor.get());
225+ CHECK_RET(splitSecond != nullptr, ACLNN_ERR_INNER_NULLPTR);
226+ 
227+ // 调用Mul算子Kernel,获取a_grad ,Inplace方式减少空间占用
228+ gradOutContiguous = l0op::Mul(gradOutContiguous, splitSecond, uniqueExecutor.get());
229+ CHECK_RET(gradOutContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
230+ 
231+ // 调用Mul算子Kernel,获取sigmoid(b) * a ,Inplace方式减少空间占用
232+ splitSecond = l0op::Mul(splitFirst, splitSecond, uniqueExecutor.get());
233+ CHECK_RET(splitSecond != nullptr, ACLNN_ERR_INNER_NULLPTR);
234+ 
235+ // 调用Sub算子Kernel,获取 a - (sigmoid(b) * a) ,Inplace方式减少空间占用
236+ splitFirst = l0op::Sub(splitFirst, splitSecond, uniqueExecutor.get());
237+ CHECK_RET(splitFirst != nullptr, ACLNN_ERR_INNER_NULLPTR);
238+ 
239+ // 调用Mul算子Kernel,获取b_grad ,Inplace方式减少空间占用
240+ splitFirst = l0op::Mul(splitFirst, gradOutContiguous, uniqueExecutor.get());
241+ CHECK_RET(splitFirst != nullptr, ACLNN_ERR_INNER_NULLPTR);
242+ 
243+ // 调用ConcatD算子Kernel,获取out
244+ op::FVector<const aclTensor*> tensorListVector;
245+ tensorListVector.emplace_back(gradOutContiguous);
246+ tensorListVector.emplace_back(splitFirst);
247+ auto tensorList = uniqueExecutor.get()->AllocTensorList(tensorListVector.data(), tensorListVector.size());
248+ auto concatTensor = l0op::ConcatD(tensorList, positiveDim, uniqueExecutor.get());
249+ CHECK_RET(concatTensor != nullptr, ACLNN_ERR_INNER_NULLPTR);
250+ 
251+ const aclTensor* gluBackwardOut = concatTensor;
252+ if (bf16Type) {
253+ gluBackwardOut = l0op::Cast(concatTensor, op::DataType::DT_FLOAT16, uniqueExecutor.get());
254+ CHECK_RET(gluBackwardOut != nullptr, ACLNN_ERR_INNER_NULLPTR);
255+ }
256+ 
257+ // 将计算结果拷贝到输出out上,out可能是非连续的tensor
258+ auto viewCopyResult = l0op::ViewCopy(gluBackwardOut, out, uniqueExecutor.get());
259+ CHECK_RET(viewCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR);
260+ 
261+ // 获取计算过程中需要使用的workspace大小
262+ *workspaceSize = uniqueExecutor->GetWorkspaceSize();
263+ uniqueExecutor.ReleaseTo(executor);
264+ return ACLNN_SUCCESS;
265+}
266+ 
267+aclnnStatus aclnnGluBackward(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream) {
268+ L2_DFX_PHASE_2(aclnnGluBackward);
269+ // 固定写法,调用框架能力,完成计算
270+ return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
271+}
272+ 
273+#ifdef __cplusplus
274+}
275+#endif
@@ -0,0 +1,80 @@
1+/**
2+ * Copyright (c) 2025 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+#ifndef OP_API_INC_GLU_BACKWARD_H_
11+#define OP_API_INC_GLU_BACKWARD_H_
12+ 
13+#include "aclnn/aclnn_base.h"
14+#include "aclnn_util.h"
15+ 
16+#ifdef __cplusplus
17+extern "C" {
18+#endif
19+ 
20+/**
21+ * @brief aclnnGluBackward的第一段接口,根据具体的计算流程,计算workspace大小。
22+ * @domain aclnn_ops_train
23+ * 算子功能:GLU的反向。
24+ *
25+ * $$
26+ * \frac{\partial GLU(a,b)}{\partial(a,b)}=cat(\sigma(b),\sigma(b) \otimes a \otimes (1-\sigma(b)))
27+ * $$
28+ *
29+ * 数学计算表达式:
30+ * 假设输出的GLUGrad有两部分组成:out=[a_grad, b_grad],则:
31+ * sig_b = sigmoid(b)
32+ * **a_grad** = y_grad * sig_b
33+ * **b_grad** = a_grad * (a - a * sig_b)
34+ * 其中:y_grad 为gradOut,a表示的是输入张量根据指定dim进行均分后的前部分张量,b表示后半部分张量。
35+ *
36+ * 计算图:
37+ * ```mermaid
38+ * graph LR
39+ * A0[(gradOut)] -->B0([l0op::Contiguous])-->C1([l0op::Mul])-->C2([l0op::Mul])
40+ * A1[(self)] -->B1([l0op::Contiguous])
41+ * B1 -->D0([l0op::SplitV])--a--> C0-->G0([l0op::Sub])
42+ * D0--a-->G0-->C2--b_grad-->H0([l0op::ConcatD])
43+ * E0((dim)) -->D0--b-->D1([l0op::Sigmoid])-->C0([l0op::Mul])
44+ * D1-->C1--a_grad-->H0
45+ * E0-->H0
46+ * H0 -->F0([l0op::ViewCopy])--> J0[(out)]
47+ * ```
48+ *
49+ * @param [in] gradOut: 表示梯度更新系数,数据类型支持DOUBLE,FLOAT,FLOAT16数据类型,数据类型必须与self的数据类型一致,
50+ * shape为$(*_1,M,*_2)$其中$*$表示self中对应维度,$M = N /2$,支持非连续的Tensor,数据格式支持ND。
51+ * @param [in] self:
52+ * 数据类型支持DOUBLE,FLOAT,FLOAT16数据类型,tensor的维度必须大于0,且shape必须在入参dim对应的维度上可以整除2
53+ * shape表示为$(*_1,N,*_2)$其中$*$表示任何数量的附加维,$N$表示dim指定的维度大小,支持非连续的Tensor,数据格式支持ND。
54+ * @param [in] dim: 表示要拆分输入self的维度,数据类型支持INT64,取值范围[-self.dim,self.dim-1]。
55+ * @param [out] out: 数据类型支持DOUBLE,FLOAT,FLOAT16数据类型,数据类型必须与self的数据类型一致,
56+ * shape必须与self的shape一致,支持非连续的Tensor,数据格式支持ND。
57+ * @param [out] workspaceSize: 返回用户需要在npu device侧申请的workspace大小。
58+ * @param [out] executor: 返回op执行器,包含算子计算流程。
59+ * @return aclnnStatus: 返回状态码。
60+ */
61+ACLNN_API aclnnStatus aclnnGluBackwardGetWorkspaceSize(const aclTensor* gradOut, const aclTensor* self, int64_t dim,
62+ const aclTensor* out, uint64_t* workspaceSize,
63+ aclOpExecutor** executor);
64+ 
65+/**
66+ * @brief aclnnGluBackward的第二段接口,用于执行计算。
67+ * @param [in] workspace: 在npu device侧申请的workspace内存起址。
68+ * @param [in] workspaceSize: 在npu device侧申请的workspace大小,由第一段接口aclnnGtTensorGetWorkspaceSize获取。
69+ * @param [in] stream: acl stream流。
70+ * @param [in] executor: op执行器,包含了算子计算流程。
71+ * @return aclnnStatus: 返回状态码。
72+ */
73+ACLNN_API aclnnStatus aclnnGluBackward(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
74+ aclrtStream stream);
75+ 
76+#ifdef __cplusplus
77+}
78+#endif
79+ 
80+#endif // OP_API_INC_GLU_BACKWARD_H_
@@ -0,0 +1,204 @@
1+/**
2+ * Copyright (c) 2025 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+ * \file aclnn_sigmoid.cpp
13+ * \brief
14+ */
15+ 
16+#include "aclnn_sigmoid.h"
17+#include "aclnn_kernels/common/op_error_check.h"
18+#include "aclnn_kernels/cast.h"
19+#include "aclnn_kernels/contiguous.h"
20+#include "sigmoid.h"
21+#include "opdev/op_dfx.h"
22+ 
23+using namespace op;
24+#ifdef __cplusplus
25+extern "C" {
26+#endif
27+ 
28+// 根据API定义,需要列出所能支持的所有dtype
29+static const std::initializer_list<op::DataType> DTYPE_SUPPORT_LIST = {
30+ op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_DOUBLE, op::DataType::DT_INT8,
31+ op::DataType::DT_INT16, op::DataType::DT_INT32, op::DataType::DT_INT64, op::DataType::DT_BOOL,
32+ op::DataType::DT_COMPLEX64, op::DataType::DT_COMPLEX128, op::DataType::DT_BF16, op::DataType::DT_UINT8};
33+ 
34+static const std::initializer_list<op::DataType> DTYPE_OUT_LIST = {
35+ op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_DOUBLE,
36+ op::DataType::DT_COMPLEX64, op::DataType::DT_COMPLEX128, op::DataType::DT_BF16};
37+ 
38+static const std::initializer_list<DataType> ASCEND910_OUTPUT_DTYPE_SUPPORT_LIST = {
39+ DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_DOUBLE, DataType::DT_COMPLEX64,
40+ DataType::DT_COMPLEX128};
41+ 
42+static const std::initializer_list<DataType>& GetSelfRefDtypeList() {
43+ if (GetCurrentPlatformInfo().GetSocVersion() >= SocVersion::ASCEND910B &&
44+ GetCurrentPlatformInfo().GetSocVersion() <= SocVersion::ASCEND910E) {
45+ return DTYPE_OUT_LIST;
46+ } else {
47+ return ASCEND910_OUTPUT_DTYPE_SUPPORT_LIST;
48+ }
49+}
50+ 
51+static bool CheckInplaceDtypeValid(aclTensor *selfRef) {
52+ auto inplaceSupportList = GetSelfRefDtypeList();
53+ // 检查selfRef的数据类型是否在inplace sigmoid算子的支持列表内
54+ OP_CHECK_DTYPE_NOT_SUPPORT(selfRef, inplaceSupportList, return false);
55+ 
56+ return true;
57+}
58+ 
59+inline static bool CheckSocVersionIsSupportBf16(void)
L

在Sigmoid_def文件中定义支持910B与校验不符

likedislike
天上的星星哪去了
3月26日 评论:
60+{
61+ return GetCurrentPlatformInfo().GetSocVersion() >= SocVersion::ASCEND910B &&
62+ GetCurrentPlatformInfo().GetSocVersion() <= SocVersion::ASCEND910E;
63+}
64+ 
65+inline static bool CheckNotNull(const aclTensor *self, const aclTensor *out)
66+{
67+ OP_CHECK_NULL(self, return false);
68+ OP_CHECK_NULL(out, return false);
69+ return true;
70+}
71+ 
72+inline static bool CheckDtypeValid(const aclTensor *self, const aclTensor *out)
73+{
74+ // 检查self的数据类型是否在sigmoid算子的支持列表内
75+ OP_CHECK_DTYPE_NOT_SUPPORT(self, DTYPE_SUPPORT_LIST, return false);
76+ OP_CHECK_DTYPE_NOT_SUPPORT(out, DTYPE_OUT_LIST, return false);
77+ 
78+ bool bf16flag = CheckSocVersionIsSupportBf16();
79+ auto socVersion = GetCurrentPlatformInfo().GetSocVersion();
80+ if (!bf16flag && self->GetDataType() == op::DataType::DT_BF16) {
81+ OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Self dtype %s is unsupported by the current SOC version [%s].",
82+ op::ToString(self->GetDataType()).GetString(), op::ToString(socVersion).GetString());
83+ return false;
84+ }
85+ return true;
86+}
87+ 
88+inline static bool CheckShape(const aclTensor *self, const aclTensor *out)
89+{
90+ // self和out的shape必须一致
91+ OP_CHECK_SHAPE_NOT_EQUAL(self, out, return false);
92+ 
93+ // self的维度必须小于 9
94+ OP_CHECK_MAX_DIM(self, 8, return false);
95+ 
96+ return true;
97+}
98+ 
99+static aclnnStatus CheckParams(const aclTensor *self, const aclTensor *out)
100+{
101+ // 1. 检查参数是否为空指针
102+ CHECK_RET(CheckNotNull(self, out), ACLNN_ERR_PARAM_NULLPTR);
103+ 
104+ // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验
105+ CHECK_RET(CheckDtypeValid(self, out), ACLNN_ERR_PARAM_INVALID);
106+ 
107+ // 3. ND 算子不检查格式
108+ // 4. 检查self和out的shape是否一致
109+ CHECK_RET(CheckShape(self, out), ACLNN_ERR_PARAM_INVALID);
110+ 
111+ return ACLNN_SUCCESS;
112+}
113+ 
114+static aclnnStatus CheckInplaceParams(aclTensor *selfRef) {
115+ OP_CHECK_NULL(selfRef, return ACLNN_ERR_PARAM_NULLPTR);
116+ 
117+ // 检查selfRef的数据类型是否在inplace sigmoid算子的支持列表内
118+ CHECK_RET(CheckInplaceDtypeValid(selfRef), ACLNN_ERR_PARAM_INVALID);
119+ return ACLNN_SUCCESS;
120+}
121+ 
122+static aclnnStatus ExecSigmoidGetWorkspaceSize(const aclTensor *self, aclTensor *out, uint64_t *workspaceSize,
123+ aclOpExecutor **executor)
124+{
125+ // 固定写法,创建OpExecutor
126+ auto uniqueExecutor = CREATE_EXECUTOR();
127+ CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
128+ 
129+ // 固定写法,参数检查
130+ auto ret = CheckParams(self, out);
131+ CHECK_RET(ret == ACLNN_SUCCESS, ret);
132+ 
133+ // sigmoid算子的空tensor在kernel中支持,对标竞品根据算子实际情况补充
134+ if (self->IsEmpty()) {
135+ // 根据实际支持情况补充
136+ *workspaceSize = uniqueExecutor->GetWorkspaceSize();
137+ uniqueExecutor.ReleaseTo(executor);
138+ return ACLNN_SUCCESS;
139+ }
140+ 
141+ // 固定写法,将输入self转换成连续的tensor
142+ auto selfContiguous = l0op::Contiguous(self, uniqueExecutor.get());
143+ CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
144+ 
145+ // 调用cast算子将不支持的类型转化为float
146+ auto castDtype = selfContiguous->GetDataType();
L

double类型会导致精度下降,bf16和fp16会导致性能降低和内存占用增加,建议在kernel中进行cast操作

likedislike
天上的星星哪去了
3月26日 评论:
147+ if (!CheckType(castDtype, DTYPE_OUT_LIST)) {
148+ castDtype = out->GetDataType();
149+ }
150+ auto selfCast = l0op::Cast(selfContiguous, castDtype, uniqueExecutor.get());
151+ CHECK_RET(selfCast != nullptr, ACLNN_ERR_INNER_NULLPTR);
152+ // 调用Sigmoid算子Kernel
153+ auto sigmoidOpOut = l0op::Sigmoid(selfCast, uniqueExecutor.get());
154+ CHECK_RET(sigmoidOpOut != nullptr, ACLNN_ERR_INNER_NULLPTR);
155+ 
156+ // 固定写法,将计算结果转换成输出out的数据类型
157+ auto castOut = l0op::Cast(sigmoidOpOut, out->GetDataType(), uniqueExecutor.get());
158+ CHECK_RET(castOut != nullptr, ACLNN_ERR_INNER_NULLPTR);
159+ 
160+ // 固定写法,将计算结果拷贝到输出out上,out可能是非连续的tensor
161+ auto viewCopyResult = l0op::ViewCopy(castOut, out, uniqueExecutor.get());
162+ CHECK_RET(viewCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR);
163+ 
164+ // 固定写法,获取计算过程中需要使用的workspace大小
165+ *workspaceSize = uniqueExecutor->GetWorkspaceSize();
166+ uniqueExecutor.ReleaseTo(executor);
167+ return ACLNN_SUCCESS;
168+}
169+ 
170+aclnnStatus aclnnSigmoidGetWorkspaceSize(const aclTensor *self, aclTensor *out, uint64_t *workspaceSize,
171+ aclOpExecutor **executor)
172+{
173+ L2_DFX_PHASE_1(aclnnSigmoid, DFX_IN(self), DFX_OUT(out));
174+ return ExecSigmoidGetWorkspaceSize(self, out, workspaceSize, executor);
175+}
176+ 
177+aclnnStatus aclnnInplaceSigmoidGetWorkspaceSize(aclTensor *selfRef, uint64_t *workspaceSize,
178+ aclOpExecutor **executor)
179+{
180+ L2_DFX_PHASE_1(aclnnInplaceSigmoid, DFX_IN(selfRef), DFX_OUT(selfRef));
181+ auto ret = CheckInplaceParams(selfRef);
182+ CHECK_RET(ret == ACLNN_SUCCESS, ret);
183+ auto out = const_cast<aclTensor*>(selfRef);
184+ return ExecSigmoidGetWorkspaceSize(selfRef, out, workspaceSize, executor);
185+}
186+ 
187+aclnnStatus aclnnSigmoid(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, const aclrtStream stream)
188+{
189+ // 固定写法,调用框架能力,完成计算
190+ L2_DFX_PHASE_2(aclnnSigmoid);
191+ return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
192+}
193+ 
194+aclnnStatus aclnnInplaceSigmoid(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor,
195+ const aclrtStream stream)
196+{
197+ // 固定写法,调用框架能力,完成计算
198+ L2_DFX_PHASE_2(aclnnInplaceSigmoid);
199+ return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
200+}
201+ 
202+#ifdef __cplusplus
203+}
204+#endif
@@ -0,0 +1,81 @@
1+/**
2+ * Copyright (c) 2025 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+#ifndef OP_API_INC_SIGMOID_H_
12+#define OP_API_INC_SIGMOID_H_
13+ 
14+#include "aclnn/aclnn_base.h"
15+#include "aclnn_util.h"
16+ 
17+#ifdef __cplusplus
18+extern "C" {
19+#endif
20+ 
21+/**
22+ * @brief aclnnSigmoid的第一段接口,根据具体的计算流程,计算workspace大小。
23+ * @domain aclnn_ops_infer
24+ *
25+ * 算子功能: 对输入Tensor完成sigmoid操作
26+ * @param [in] self: npu device侧的aclTensor, 数据类型支持浮点类型,shape为非空,支持非连续的Tensor,数据格式支持ND,
27+ * 支持非连续的Tensor。
28+ * @param [in] out: npu device侧的aclTensor, 数据类型支持浮点类型, shape与self保持相同,数据格式支持ND。
29+ * @param [out] workspaceSize: 返回用户需要在npu device侧申请的workspace大小。
30+ * @param [out] executor: 返回op执行器,包含算子计算流程。
31+ * @return aclnnStatus: 返回状态码
32+ */
33+ACLNN_API aclnnStatus aclnnSigmoidGetWorkspaceSize(const aclTensor* self, aclTensor* out, uint64_t* workspaceSize,
34+ aclOpExecutor** executor);
35+ 
36+/**
37+ * @brief: aclnnSigmoid的第二段接口,用于执行计算
38+ *
39+ * 算子功能: 对输入Tensor完成sigmoid操作
40+ * @param [in] workspace: 在npu device侧申请的workspace内存起址。
41+ * @param [in] workspaceSize: 在npu device侧申请的workspace大小,由第一段接口aclnnSigmoidGetWorkspaceSize获取。
42+ * @param [in] stream: acl stream流。
43+ * @param [in] executor: op执行器,包含了算子计算流程。
44+ * @return aclnnStatus: 返回状态码。
45+ */
46+ACLNN_API aclnnStatus aclnnSigmoid(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
47+ const aclrtStream stream);
48+ 
49+/**
50+ * @brief aclnnInplaceSigmoid的第一段接口,根据具体的计算流程,计算workspace大小。
51+ * @domain aclnn_ops_infer
52+ *
53+ * 算子功能: 对输入Tensor完成sigmoid操作
54+ * @param [in] self: npu device侧的aclTensor,
55+ * 数据类型支持浮点类型,shape为非空,支持非连续的Tensor,数据格式支持ND、NCHW、
56+ * NHWC、支持非连续的Tensor,数据格式支持ND。
57+ * @param [out] workspaceSize: 返回用户需要在npu device侧申请的workspace大小。
58+ * @param [out] executor: 返回op执行器,包含算子计算流程。
59+ * @return aclnnStatus: 返回状态码
60+ */
61+ACLNN_API aclnnStatus aclnnInplaceSigmoidGetWorkspaceSize(aclTensor* selfRef, uint64_t* workspaceSize,
62+ aclOpExecutor** executor);
63+ 
64+/**
65+ * @brief: aclnnInplaceSigmoid的第二段接口,用于执行计算
66+ *
67+ * 算子功能: 对输入Tensor原地完成sigmoid操作
68+ * @param [in] workspace: 在npu device侧申请的workspace内存起址。
69+ * @param [in] workspaceSize: 在npu device侧申请的workspace大小,由第一段接口aclnnSigmoidGetWorkspaceSize获取。
70+ * @param [in] stream: acl stream流。
71+ * @param [in] executor: op执行器,包含了算子计算流程。
72+ * @return aclnnStatus: 返回状态码。
73+ */
74+ACLNN_API aclnnStatus aclnnInplaceSigmoid(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
75+ const aclrtStream stream);
76+ 
77+#ifdef __cplusplus
78+}
79+#endif
80+ 
81+#endif // OP_API_INC_SIGMOID_H_
@@ -0,0 +1,73 @@
1+/**
2+ * Copyright (c) 2025 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 "sigmoid.h"
12+#include "opdev/aicpu/aicpu_task.h"
13+#include "opdev/op_log.h"
14+#include "opdev/op_executor.h"
15+#include "opdev/make_op_executor.h"
16+#include "opdev/shape_utils.h"
17+#include "opdev/op_def.h"
18+#include "opdev/op_dfx.h"
19+#include "aclnn_kernels/common/op_error_check.h"
20+ 
21+using namespace op;
22+ 
23+namespace l0op {
24+ 
25+OP_TYPE_REGISTER(Sigmoid);
26+ 
27+static const std::initializer_list<op::DataType> AICORE_DTYPE_SUPPORT_LIST = {
28+ op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_BF16};
29+ 
30+// 根据芯片类型、dtype判断算子是否支持走aicore
31+inline static bool IsAiCoreSupport(const aclTensor *self)
32+{
33+ // Sigmoid只需要判断dtype
34+ return CheckType(self->GetDataType(), AICORE_DTYPE_SUPPORT_LIST);
35+}
36+ 
37+// AICORE算子kernel
38+inline static const aclTensor *SigmoidAiCore(const aclTensor *self, aclTensor *sigmoidOut, aclOpExecutor *executor)
39+{
40+ L0_DFX(SigmoidAiCore, self, sigmoidOut);
41+ // 使用框架宏ADD_TO_LAUNCHER_LIST_AICORE,将AiCore Sigmoid算子加入任务队列
42+ // Sigmoid是算子的OpType,self是算子的输入,sigmoidOut是算子的输出
43+ auto retAicore = ADD_TO_LAUNCHER_LIST_AICORE(Sigmoid, OP_INPUT(self), OP_OUTPUT(sigmoidOut));
44+ OP_CHECK_ADD_TO_LAUNCHER_LIST_AICORE(retAicore != ACLNN_SUCCESS, return nullptr,
45+ "Sigmoid ADD_TO_LAUNCHER_LIST_AICORE failed.");
46+ return sigmoidOut;
47+}
48+ 
49+// AICPU算子kernel
50+inline static const aclTensor *SigmoidAiCpu(const aclTensor *self, aclTensor *sigmoidOut, aclOpExecutor *executor)
51+{
52+ // 使用框架宏ADD_TO_CPU_LAUNCHER_LIST,将AiCpu Sigmoid算子加入任务队列
53+ // Sigmoid是算子的OpType,self是算子的输入,sigmoidOut是算子的输出
54+ L0_DFX(SigmoidAiCpu, self, sigmoidOut);
55+ 
56+ static internal::AicpuTaskSpace space("Sigmoid");
57+ auto ret = ADD_TO_LAUNCHER_LIST_AICPU(Sigmoid, OP_ATTR_NAMES(), OP_INPUT(self), OP_OUTPUT(sigmoidOut));
58+ CHECK_RET(ret == ACLNN_SUCCESS, nullptr);
59+ 
60+ return sigmoidOut;
61+}
62+ 
63+const aclTensor *Sigmoid(const aclTensor *self, aclOpExecutor *executor)
64+{
65+ auto sigmoidOut = executor->AllocTensor(self->GetViewShape(), self->GetDataType(), op::Format::FORMAT_ND);
66+ 
67+ if (IsAiCoreSupport(self)) {
68+ return SigmoidAiCore(self, sigmoidOut, executor);
69+ } else {
70+ return SigmoidAiCpu(self, sigmoidOut, executor);
71+ }
72+}
73+}
@@ -0,0 +1,20 @@
1+/**
2+ * Copyright (c) 2025 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+#ifndef PTA_NPU_OP_API_INC_LEVEL0_OP_SIGMOID_OP_H_
12+#define PTA_NPU_OP_API_INC_LEVEL0_OP_SIGMOID_OP_H_
13+ 
14+#include "opdev/op_executor.h"
15+ 
16+namespace l0op {
17+const aclTensor *Sigmoid(const aclTensor *self, aclOpExecutor *executor);
18+}
19+ 
20+#endif // PTA_NPU_OP_API_INC_LEVEL0_OP_SIGMOID_OP_H_
@@ -0,0 +1,36 @@
1+/**
2+ * Copyright (c) 2025 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+ * \file sigmoid.cpp
13+ * \brief
14+*/
15+#include "register/op_def_registry.h"
16+ 
17+namespace ops {
18+class Sigmoid : public OpDef {
19+public:
20+ explicit Sigmoid(const char* name) : OpDef(name)
21+ {
22+ this->Input("x")
23+ .ParamType(REQUIRED)
24+ .DataType({ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_BF16})
25+ .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND})
26+ .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
27+ this->Output("y")
28+ .ParamType(REQUIRED)
29+ .DataType({ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_BF16})
30+ .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND})
31+ .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
32+ this->AICore().AddConfig("ascend910b");
L

这里与aclnn中支持的芯片不一致

likedislike
天上的星星哪去了
3月26日 评论:
33+ }
34+};
35+OP_ADD(Sigmoid); // 添加算子信息库
36+} // namespace ops
@@ -0,0 +1,43 @@
1+/**
2+ * Copyright (c) 2025 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+ * \file sigmoid_infershape.cpp
13+ * \brief
14+*/
15+#include "register/op_impl_registry.h"
16+#include "log/log.h"
17+ 
18+using namespace ge;
19+ 
20+namespace ops {
21+static constexpr int64_t IDX_0 = 0;
22+ 
23+static ge::graphStatus InferShapeSigmoid(gert::InferShapeContext* context)
24+{
25+ OP_CHECK_IF(context == nullptr, OP_LOGE(context, "context is nullptr"), return ge::GRAPH_FAILED);
26+ OP_LOGD(context->GetNodeName(), "Begin to do InferShapeSigmoid");
27+ 
28+ // get input shapes
29+ const gert::Shape* xShape = context->GetInputShape(IDX_0);
30+ OP_CHECK_NULL_WITH_CONTEXT(context, xShape);
31+ 
32+ // get output shapes
33+ gert::Shape* yShape = context->GetOutputShape(IDX_0);
34+ OP_CHECK_NULL_WITH_CONTEXT(context, yShape);
35+ 
36+ // 填充输出shape大小
37+ *yShape = *xShape;
38+ OP_LOGD(context->GetNodeName(), "End to do InferShapeSigmoid");
39+ return GRAPH_SUCCESS;
40+}
41+ 
42+IMPL_OP_INFERSHAPE(Sigmoid).InferShape(InferShapeSigmoid);
43+}
@@ -0,0 +1,297 @@
1+/**
2+ * Copyright (c) 2025 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+ * \file sigmoid_tiling.cpp
13+ * \brief
14+ */
15+#include "log/log.h"
16+#include "util/math_util.h"
17+#include "tiling_base/tiling_util.h"
18+#include "tiling/platform/platform_ascendc.h"
19+#include "register/op_impl_registry.h"
20+#include "tiling_base/tiling_templates_registry.h"
21+#include "util/platform_util.h"
22+#include "../op_kernel/sigmoid_tiling_data.h"
23+#include "../op_kernel/sigmoid_tiling_key.h"
24+ 
25+namespace optiling {
26+ 
27+using namespace Ops::NN::OpTiling;
28+ 
29+uint32_t blockSize;
30+constexpr uint32_t BUFFER_NUM = 2;
31+constexpr uint32_t WS_SYS_SIZE = 0;
32+ 
33+constexpr uint64_t THRESHOLD_4K = 4096;
34+constexpr uint64_t THRESHOLD_16K = 16384;
35+constexpr uint64_t THRESHOLD_64K = 65536;
36+constexpr uint64_t THRESHOLD_128K = 131072;
37+constexpr uint64_t THRESHOLD_512K = 524288;
38+constexpr uint64_t DATA_PER_CORE = 1024;
39+ 
40+constexpr uint64_t CORES_TIER1 = 4;
41+constexpr uint64_t CORES_TIER2 = 8;
42+constexpr uint64_t CORES_TIER3 = 16;
43+ 
44+// UB Data Number Constants
45+constexpr uint64_t UB_DATA_NUM_HIGH_PERF_310P_BF16 = 10;
46+constexpr uint64_t UB_DATA_NUM_HIGH_PERF_310P_OTHER = 6;
47+constexpr uint64_t UB_DATA_NUM_CAST_TO_FLOAT = 8;
48+constexpr uint64_t UB_DATA_NUM_NATIVE = 5;
49+ 
50+struct SigmoidCompileInfo {};
51+ 
52+static ge::graphStatus TilingParseForSigmoid([[maybe_unused]] gert::TilingParseContext* context)
53+{
54+ OP_CHECK_IF(context == nullptr, OP_LOGE(context, "context is nullptr"), return ge::GRAPH_FAILED);
55+ return ge::GRAPH_SUCCESS;
56+}
57+ 
58+static ge::graphStatus GetPlatformInfo(gert::TilingContext* context, uint64_t& ubSize, int64_t& coreNum)
59+{
60+ OP_CHECK_IF(context == nullptr, OP_LOGE(context, "context is nullptr"), return ge::GRAPH_FAILED);
61+
62+ // 获取ubsize coreNum
63+ auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
64+ ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSize);
65+ coreNum = ascendcPlatform.GetCoreNum();
66+ blockSize = Ops::Base::GetUbBlockSize(context);
67+ OP_CHECK_IF(blockSize <= 0, OP_LOGE(context, "blockSize is less than or equal to 0"), return ge::GRAPH_FAILED);
68+ OP_CHECK_IF(coreNum <= 0, OP_LOGE(context, "coreNum is less than or equal to 0"), return ge::GRAPH_FAILED);
69+ OP_CHECK_IF(ubSize == 0, OP_LOGE(context, "ubSize is 0"), return ge::GRAPH_FAILED);
70+
71+ return ge::GRAPH_SUCCESS;
72+}
73+ 
74+static ge::graphStatus GetWorkspaceSize(gert::TilingContext* context)
75+{
76+ OP_CHECK_IF(context == nullptr, OP_LOGE(context, "context is nullptr"), return ge::GRAPH_FAILED);
77+
78+ size_t usrSize = 0;
79+ auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
80+ uint32_t sysWorkspaceSize = ascendcPlatform.GetLibApiWorkSpaceSize();
81+
82+ // 通过框架获取workspace的指针,GetWorkspaceSizes入参为所需workspace的块数。当前限制使用一块。
83+ size_t* currentWorkspace = context->GetWorkspaceSizes(1);
84+ OP_CHECK_IF(currentWorkspace == nullptr, OP_LOGE(context, "currentWorkspace is nullptr"), return ge::GRAPH_FAILED);
85+
86+ currentWorkspace[0] = usrSize + sysWorkspaceSize;
87+ return ge::GRAPH_SUCCESS;
88+}
89+ 
90+static uint64_t GetUbDataNum(gert::TilingContext* context)
91+{
92+ OP_CHECK_IF(context == nullptr, OP_LOGE(context, "context is nullptr"), return ge::GRAPH_FAILED);
93+ 
94+ auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
95+ auto socVersion = ascendcPlatform.GetSocVersion();
96+ auto dataType = context->GetInputDesc(0)->GetDataType();
97+ 
98+ uint64_t ubDataNumber = 0;
99+ bool isHighPerf = false;
100+#if defined(HIGH_PERFORMANCE) && HIGH_PERFORMANCE == 1
101+ isHighPerf = true;
102+#endif
103+ bool isBf16 = (dataType == ge::DT_BF16);
104+ bool isFp16 = (dataType == ge::DT_FLOAT16);
105+ 
106+ if (isHighPerf && socVersion == platform_ascendc::SocVersion::ASCEND310P) {
107+ // --- 310P 高性能模式 (Poly) ---
108+ if (isBf16) {
109+ // In(2) + Out(2) + Poly1(2*2B) + Poly2(2*2B) + Cast(2*2B) = 4 + 2 + 2 + 2 = 10
110+ ubDataNumber = UB_DATA_NUM_HIGH_PERF_310P_BF16;
111+ } else {
112+ // FP16/FP32: In(2) + Out(2) + Poly1(1) + Poly2(1) = 6
113+ ubDataNumber = UB_DATA_NUM_HIGH_PERF_310P_OTHER;
114+ }
115+ } else {
116+ // --- 常规计算模式 ---
117+ // 判断是否需要 Cast 到 Float (BF16 必须,FP16 在特定情况需要)
118+ bool needCastToFloat = isBf16;
119+ if (!isHighPerf && isFp16 &&
120+ (socVersion == platform_ascendc::SocVersion::ASCEND310P ||
121+ socVersion == platform_ascendc::SocVersion::ASCEND910 ||
122+ socVersion == platform_ascendc::SocVersion::ASCEND910B ||
123+ socVersion == platform_ascendc::SocVersion::ASCEND910_93)) {
124+ needCastToFloat = true;
125+ }
126+ 
127+ if (needCastToFloat) {
128+ // In(2) + Out(2) + CastBuffer(2*float/dtype) + OnesBuffer(2*float/dtype)
129+ // 对于 BF16/FP16,float 是 2 倍大小,所以是 2+2+2+2 = 8
130+ ubDataNumber = UB_DATA_NUM_CAST_TO_FLOAT;
131+ } else {
132+ // Native FP32 or Native FP16
133+ // In(2) + Out(2) + Ones(1) = 5
134+ ubDataNumber = UB_DATA_NUM_NATIVE;
135+ }
136+ }
137+ return ubDataNumber;
138+}
139+ 
140+static ge::graphStatus GetShapeAttrsInfo(
141+ gert::TilingContext* context, uint64_t ubSize, uint64_t& inputNum, uint64_t& inputBytes, uint64_t& tileBlockNum,
142+ uint64_t& tileDataNum, uint64_t& inputLengthAlgin32)
143+{
144+ OP_CHECK_IF(context == nullptr, OP_LOGE(context, "context is nullptr"), return ge::GRAPH_FAILED);
145+ OP_CHECK_IF(context->GetInputShape(0) == nullptr, OP_LOGE(context, "InputShape is nullptr"), return ge::GRAPH_FAILED);
146+
147+ inputNum = context->GetInputShape(0)->GetStorageShape().GetShapeSize();
148+ uint32_t typeLength = 0;
149+ ge::TypeUtils::GetDataTypeLength(context->GetInputDesc(0)->GetDataType(), typeLength);
150+
151+ uint64_t inputLength = inputNum * typeLength;
152+ if (inputNum == 0) {
condfuse_3
condfuse_3condfuse_32025年12月24日
已过期

异常返回 添加打印

likedislike
153+ OP_LOGE(context, "inputNum is 0");
154+ return ge::GRAPH_FAILED;
155+ }
156+ inputBytes = inputLength / inputNum;
157+ uint64_t ubDataNumber = GetUbDataNum(context);
158+ if(ubDataNumber == 0) {
159+ OP_LOGE(context, "ubDataNumber is 0");
160+ return ge::GRAPH_FAILED;
161+ }
162+ if (blockSize == 0) {
163+ OP_LOGE(context, "blockSize is 0");
164+ return ge::GRAPH_FAILED;
165+ }
166+ tileBlockNum = (ubSize / blockSize) / ubDataNumber;
167+
168+ if (inputBytes == 0) {
condfuse_3
condfuse_3condfuse_32025年12月24日
已过期

异常返回 添加打印

likedislike
169+ OP_LOGE(context, "inputBytes is 0");
170+ return ge::GRAPH_FAILED;
171+ }
172+
173+ tileDataNum = (tileBlockNum * blockSize) / inputBytes;
174+ inputLengthAlgin32 = (((inputLength + blockSize - 1) / blockSize) * blockSize);
175+
176+ return ge::GRAPH_SUCCESS;
177+}
178+ 
179+static ge::graphStatus CalculateCoreBlockNums(gert::TilingContext* context,
180+ uint64_t inputLengthAlgin32, int64_t coreNum, uint64_t tileBlockNum, uint64_t inputBytes, uint64_t tileDataNum,
181+ uint64_t& smallCoreDataNum, uint64_t& bigCoreDataNum, uint64_t& smallTailDataNum, uint64_t& bigTailDataNum,
182+ uint64_t& finalSmallTileNum, uint64_t& finalBigTileNum, uint64_t& tailBlockNum)
183+{
184+ if (blockSize == 0 || coreNum <= 0 || tileBlockNum == 0 || inputBytes == 0) {
185+ OP_LOGE(context, "invalid blockSize/coreNum/tileBlockNum/inputBytes");
186+ return ge::GRAPH_FAILED;
187+ }
188+
189+ uint64_t coreNumUint = static_cast<uint64_t>(coreNum);
190+ uint64_t everyCoreInputBlockNum = inputLengthAlgin32 / blockSize / coreNumUint;
191+ tailBlockNum = (inputLengthAlgin32 / blockSize) % coreNumUint;
192+
193+ smallCoreDataNum = everyCoreInputBlockNum * blockSize / inputBytes;
194+ uint64_t smallTileNum = everyCoreInputBlockNum / tileBlockNum;
195+ finalSmallTileNum = (everyCoreInputBlockNum % tileBlockNum) == 0 ? smallTileNum : smallTileNum + 1;
196+ smallTailDataNum = smallCoreDataNum - (tileDataNum * smallTileNum);
197+ smallTailDataNum = smallTailDataNum == 0 ? tileDataNum : smallTailDataNum;
198+ 
199+ everyCoreInputBlockNum += 1;
200+ bigCoreDataNum = everyCoreInputBlockNum * blockSize / inputBytes;
201+ uint64_t bigTileNum = everyCoreInputBlockNum / tileBlockNum;
202+ finalBigTileNum = (everyCoreInputBlockNum % tileBlockNum) == 0 ? bigTileNum : bigTileNum + 1;
203+ bigTailDataNum = bigCoreDataNum - tileDataNum * bigTileNum;
204+ bigTailDataNum = bigTailDataNum == 0 ? tileDataNum : bigTailDataNum;
205+ 
206+ return ge::GRAPH_SUCCESS;
207+}
208+ 
209+static uint64_t LimitCoreNum(int64_t maxCoreNum, uint64_t inputNum)
210+{
211+ if (inputNum < THRESHOLD_4K) {
212+ // 每1024个数据使用1个核心,至少使用1核
213+ uint64_t cores = (inputNum + DATA_PER_CORE - 1) / DATA_PER_CORE;
214+ return cores > 0 ? cores : 1;
215+ } else if (inputNum < THRESHOLD_16K) {
216+ return CORES_TIER1;
217+ } else if (inputNum < THRESHOLD_64K) {
218+ return CORES_TIER2;
219+ } else if (inputNum < THRESHOLD_512K) {
220+ return CORES_TIER3;
221+ } else {
222+ return maxCoreNum;
223+ }
224+}
225+ 
226+ 
227+ 
228+static ge::graphStatus SigmoidTilingFunc(gert::TilingContext* context)
229+{
230+ SigmoidTilingData* tiling = context->GetTilingData<SigmoidTilingData>();
231+ OP_CHECK_NULL_WITH_CONTEXT(context, tiling);
232+ OP_CHECK_IF(
233+ memset_s(tiling, sizeof(SigmoidTilingData), 0, sizeof(SigmoidTilingData)) != EOK,
234+ OP_LOGE(context, "set tiling data error"), return ge::GRAPH_FAILED);
235+
236+ // 获取平台运行信息
237+ uint64_t ubSize = 0;
238+ int64_t coreNum = 0;
239+ ge::graphStatus ret = GetPlatformInfo(context, ubSize, coreNum);
240+ OP_CHECK_IF(ret != ge::GRAPH_SUCCESS, OP_LOGE(context, "GetPlatformInfo error"), return ge::GRAPH_FAILED);
241+
242+ // 获取输入数据信息
243+ uint64_t inputNum, inputBytes, tileBlockNum, tileDataNum, inputLengthAlgin32;
244+ ret = GetShapeAttrsInfo(context, ubSize, inputNum, inputBytes, tileBlockNum, tileDataNum, inputLengthAlgin32);
245+ OP_CHECK_IF(ret != ge::GRAPH_SUCCESS, OP_LOGE(context, "GetShapeAttrsInfo error"), return ge::GRAPH_FAILED);
246+
247+ // 用限制之后的核数当最大核数进行计算
248+ uint64_t limitedCoreNum = LimitCoreNum(coreNum, inputNum);
249+
250+ // 计算coreNum
251+ if (tileDataNum >= inputNum) {
252+ coreNum = 1;
253+ } else {
254+ // There is at least 32B of data on each core, satisfying several settings for several cores.
255+ // The maximum number of audits is the actual number of audits
256+ if (blockSize == 0) {
257+ OP_LOGE(context, "blockSize is 0");
258+ return ge::GRAPH_FAILED;
259+ }
260+ uint64_t maxBlocks = inputLengthAlgin32 / blockSize;
261+ coreNum = (limitedCoreNum < maxBlocks) ? static_cast<int64_t>(limitedCoreNum) : static_cast<int64_t>(maxBlocks);
262+ }
263+
264+ // 计算每个core处理的数据块数
265+ uint64_t smallCoreDataNum, bigCoreDataNum, smallTailDataNum, bigTailDataNum;
266+ uint64_t finalSmallTileNum, finalBigTileNum, tailBlockNum;
267+
268+ ret = CalculateCoreBlockNums(context,
269+ inputLengthAlgin32, coreNum, tileBlockNum, inputBytes, tileDataNum, smallCoreDataNum, bigCoreDataNum,
270+ smallTailDataNum, bigTailDataNum, finalSmallTileNum, finalBigTileNum, tailBlockNum);
271+ OP_CHECK_IF(ret != ge::GRAPH_SUCCESS, OP_LOGE(context, "CalculateCoreBlockNums error"), return ge::GRAPH_FAILED);
272+
273+ // 设置tiling数据
274+ tiling->smallCoreDataNum = smallCoreDataNum;
275+ tiling->bigCoreDataNum = bigCoreDataNum;
276+ tiling->tileDataNum = tileDataNum;
277+ tiling->smallTailDataNum = smallTailDataNum;
278+ tiling->bigTailDataNum = bigTailDataNum;
279+ tiling->finalSmallTileNum = finalSmallTileNum;
280+ tiling->finalBigTileNum = finalBigTileNum;
281+ tiling->tailBlockNum = tailBlockNum;
282+
283+ // 计算workspace大小
284+ OP_CHECK_IF(
285+ GetWorkspaceSize(context) != ge::GRAPH_SUCCESS, OP_LOGE(context, "GetWorkspaceSize error"),
286+ return ge::GRAPH_FAILED);
287+
288+ uint64_t tilingKey = GET_TPL_TILING_KEY(0);
289+ context->SetTilingKey(tilingKey);
290+ context->SetBlockDim(coreNum);
291+
292+ return ge::GRAPH_SUCCESS;
293+}
294+ 
295+// tiling注册入口.
296+IMPL_OP_OPTILING(Sigmoid).Tiling(SigmoidTilingFunc).TilingParse<SigmoidCompileInfo>(TilingParseForSigmoid);
297+} // namespace optiling