已关闭
Sigmoid算子AscendC实现 #425
天上的星星哪去了创建于 2025年12月16日关闭于 4月25日
Sigmoid算子AscendC实现 #425
已关闭
共 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + do { \ | ||
| 24 | + printf(message, ##__VA_ARGS__); \ | ||
| 25 | + } while (0) | ||
| 26 | + | ||
| 27 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 28 | + int64_t 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + do { \ | ||
| 24 | + printf(message, ##__VA_ARGS__); \ | ||
| 25 | + } while (0) | ||
| 26 | + | ||
| 27 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 28 | + int64_t shapeSize = 1; | ||
| 29 | + for (auto i : shape) { | ||
| 30 | + shapeSize *= i; | ||
| 31 | + } | ||
| 32 | + return shapeSize; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 36 | + // 固定写法,资源初始化 | ||
| 37 | + auto ret = aclInit(nullptr); | ||
| 38 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 39 | + ret = aclrtSetDevice(deviceId); | ||
| 40 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 41 | + ret = aclrtCreateStream(stream); | ||
| 42 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 43 | + return 0; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +template <typename T> | ||
| 47 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 48 | + aclDataType dataType, aclTensor** tensor) { | ||
| 49 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 50 | + // 调用aclrtMalloc申请device侧内存 | ||
| 51 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 52 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 53 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 54 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + | ||
| 57 | + // 计算连续tensor的strides | ||
| 58 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 59 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 60 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 64 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 65 | + shape.data(), shape.size(), *deviceAddr); | ||
| 66 | + return 0; | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +int main() { | ||
| 70 | + // 1. (固定写法)device/stream初始化,参考acl API | ||
| 71 | + // 根据自己的实际device填写deviceId | ||
| 72 | + int32_t deviceId = 0; | ||
| 73 | + aclrtStream stream; | ||
| 74 | + auto ret = Init(deviceId, &stream); | ||
| 75 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 76 | + | ||
| 77 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 78 | + std::vector<int64_t> 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + do { \ | ||
| 24 | + printf(message, ##__VA_ARGS__); \ | ||
| 25 | + } while (0) | ||
| 26 | + | ||
| 27 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 28 | + int64_t shapeSize = 1; | ||
| 29 | + for (auto i : shape) { | ||
| 30 | + shapeSize *= i; | ||
| 31 | + } | ||
| 32 | + return shapeSize; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 36 | + // 固定写法,资源初始化 | ||
| 37 | + auto ret = aclInit(nullptr); | ||
| 38 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 39 | + ret = aclrtSetDevice(deviceId); | ||
| 40 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 41 | + ret = aclrtCreateStream(stream); | ||
| 42 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 43 | + return 0; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +template <typename T> | ||
| 47 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 48 | + aclDataType dataType, aclTensor** tensor) { | ||
| 49 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 50 | + // 调用aclrtMalloc申请device侧内存 | ||
| 51 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 52 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 53 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 54 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + | ||
| 57 | + // 计算连续tensor的strides | ||
| 58 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 59 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 60 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 64 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 65 | + shape.data(), shape.size(), *deviceAddr); | ||
| 66 | + return 0; | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +int main() { | ||
| 70 | + // 1. (固定写法)device/stream初始化,参考acl API | ||
| 71 | + // 根据自己的实际device填写deviceId | ||
| 72 | + int32_t deviceId = 0; | ||
| 73 | + aclrtStream stream; | ||
| 74 | + auto ret = Init(deviceId, &stream); | ||
| 75 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 76 | + | ||
| 77 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 78 | + std::vector<int64_t> 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +using namespace op; | ||
| 31 | + | ||
| 32 | +extern "C" { | ||
| 33 | + | ||
| 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 | |||
| 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操作 ![]() ![]() | |||
| 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 | + | ||
| 274 | +} | ||
| 275 | + | ||
| @@ -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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +extern "C" { | ||
| 18 | + | ||
| 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 | + | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | + | ||
| 80 | + | ||
| @@ -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 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +using namespace op; | ||
| 24 | + | ||
| 25 | +extern "C" { | ||
| 26 | + | ||
| 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与校验不符 ![]() ![]() | |||
| 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操作 ![]() ![]() | |||
| 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 | + | ||
| 203 | +} | ||
| 204 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +extern "C" { | ||
| 19 | + | ||
| 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 | + | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace l0op { | ||
| 17 | +const aclTensor *Sigmoid(const aclTensor *self, aclOpExecutor *executor); | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | + | ||
| @@ -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 | + | ||
| 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中支持的芯片不一致 ![]() ![]() | |||
| 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 | + | ||
| 16 | + | ||
| 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 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 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 | + | ||
| 101 | + isHighPerf = true; | ||
| 102 | + | ||
| 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) { | ||
已过期 异常返回 添加打印 ![]() ![]() | |||
| 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) { | ||
已过期 异常返回 添加打印 ![]() ![]() | |||
| 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 | ||


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