已合并
[Requirement|需求建议]: 【社区任务】Relu算子新增INT16数据类型支持 #6387
cxj01创建于 6月23日
[Requirement|需求建议]: 【社区任务】Relu算子新增INT16数据类型支持 #6387
已合并
共 47 个文件变更+5664-1174
看评论的意思是无需保留activattion下的relu的新增实现,提交涉及文件应该是只在experimental/activation/relu_v2


| @@ -1,20 +1,15 @@ | |||
| 1 | # ---------------------------------------------------------------------------- | 1 | # ---------------------------------------------------------------------------- |
| 2 | -# This program is free software, you can redistribute it and/or modify. | 2 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. |
| 3 | -# 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 | -# This file is a part of the CANN Open Software. | 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | -# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 7 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 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. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ---------------------------------------------------------------------------- | 9 | # ---------------------------------------------------------------------------- |
| 10 | 10 | ||
| 11 | -file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | 11 | +# 设置算子定义时支持的芯片类型 |
| 12 | -if(NOT ENABLE_TEST) | 12 | +set(SUPPORT_COMPUTE_UNIT "ascend950" "mc62cm12a" "ascend910b" "ascend910_93") |
| 13 | - list(REMOVE_ITEM CURRENT_DIRS tests) | 13 | +# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译 |
| 14 | -endif() | 14 | +set(SUPPORT_TILING_DIR "arch35" "arch35" "ascend910b" "ascend910b") |
| 15 | -foreach(SUB_DIR ${CURRENT_DIRS}) | 15 | +add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE relu_v2 ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE) |
| 16 | - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 17 | - add_subdirectory(${SUB_DIR}) | ||
| 18 | - endif() | ||
| 19 | -endforeach() | ||
| 20 | - | ||
| @@ -0,0 +1,70 @@ | |||
| 1 | +# Relu_V2 | ||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +| 产品 | 是否支持 | | ||
| 6 | +| :----------------------------------------------------------- | :------: | | ||
| 7 | +| <term>Ascend 950PR/Ascend 950DT</term> | √ | | ||
| 8 | +| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | ||
| 9 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 10 | +| <term>Atlas 200I/500 A2 推理产品</term> | × | | ||
| 11 | + | ||
| 12 | +## 功能说明 | ||
| 13 | + | ||
| 14 | +- 算子功能:激活函数,返回与输入tensor shape相同的tensor,tensor中value大于等于0时,取该value,小于0,取0。 | ||
| 15 | +- 计算公式: | ||
| 16 | + | ||
| 17 | +$$ | ||
| 18 | +relu(self) = \begin{cases} self, & self\gt 0 \\ 0, & self\le 0 \end{cases} | ||
| 19 | +$$ | ||
| 20 | + | ||
| 21 | +## 参数说明 | ||
| 22 | + | ||
| 23 | + <table style="undefined;table-layout: fixed; width: 1305px"><colgroup> | ||
| 24 | + <col style="width: 171px"> | ||
| 25 | + <col style="width: 115px"> | ||
| 26 | + <col style="width: 247px"> | ||
| 27 | + <col style="width: 108px"> | ||
| 28 | + <col style="width: 177px"> | ||
| 29 | + <col style="width: 104px"> | ||
| 30 | + <col style="width: 238px"> | ||
| 31 | + <col style="width: 145px"> | ||
| 32 | + </colgroup> | ||
| 33 | + <thead> | ||
| 34 | + <tr> | ||
| 35 | + <th>参数名</th> | ||
| 36 | + <th>输入/输出</th> | ||
| 37 | + <th>描述</th> | ||
| 38 | + <th>数据类型</th> | ||
| 39 | + <th>数据格式</th> | ||
| 40 | + </tr></thead> | ||
| 41 | + <tbody> | ||
| 42 | + <tr> | ||
| 43 | + <td>x</td> | ||
| 44 | + <td>输入</td> | ||
| 45 | + <td>待进行Relu计算的入参。</td> | ||
| 46 | + <td>FLOAT、FLOAT16、INT8、INT32、INT64、BFLOAT16</td> | ||
| 47 | + <td>ND</td> | ||
| 48 | + </tr> | ||
| 49 | + <tr> | ||
| 50 | + <td>y</td> | ||
| 51 | + <td>输出</td> | ||
| 52 | + <td>进行Relu计算后的输出</td> | ||
| 53 | + <td>FLOAT、FLOAT16、INT8、INT32、INT64、BFLOAT16</td> | ||
| 54 | + <td>ND</td> | ||
| 55 | + </tr> | ||
| 56 | + </tbody> | ||
| 57 | + </table> | ||
| 58 | + | ||
| 59 | +## 约束说明 | ||
| 60 | + | ||
| 61 | +- 无 | ||
| 62 | + | ||
| 63 | +## 调用说明 | ||
| 64 | + | ||
| 65 | +| 调用方式 | 调用样例 | 说明 | | ||
| 66 | +|--------------|------------------------------------------------------------------------|--------------------------------------------------------------| | ||
| 67 | +| aclnn调用 | [test_aclnn_relu](examples/test_aclnn_relu.cpp) | 通过[aclnnRelu&aclnnInplaceRelu](docs/aclnnRelu&aclnnInplaceRelu.md)接口方式调用Relu算子。 | | ||
| 68 | +| aclnn调用 | [test_aclnn_inplace_relu](examples/test_aclnn_inplace_relu.cpp) | 通过[aclnnRelu&aclnnInplaceRelu](docs/aclnnRelu&aclnnInplaceRelu.md)接口方式调用Relu算子。 | | ||
| 69 | + | ||
| 70 | +| 图模式 | - | 通过[算子IR](op_graph/relu_v2_proto.h)构图方式调用Relu算子。 | | ||
| @@ -0,0 +1,602 @@ | |||
| 1 | +# aclnnAddRelu&aclnnInplaceAddRelu | ||
| 2 | + | ||
| 3 | +[📄 查看源码](https://gitcode.com/cann/ops-nn/tree/master/activation/relu) | ||
| 4 | + | ||
| 5 | +## 产品支持情况 | ||
| 6 | + | ||
| 7 | +|产品 | 是否支持 | | ||
| 8 | +|:-------------------------|:----------:| | ||
| 9 | +| <term>Ascend 950PR/Ascend 950DT</term> | √ | | ||
| 10 | +| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | ||
| 11 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 推理产品</term> | × | | ||
| 13 | +| <term>Atlas 推理系列产品</term> | × | | ||
| 14 | +| <term>Atlas 训练系列产品</term> | √ | | ||
| 15 | + | ||
| 16 | +## 功能说明 | ||
| 17 | + | ||
| 18 | +- 接口功能:完成加法计算后得到结果再进行激活。 | ||
| 19 | +- 计算公式: | ||
| 20 | + | ||
| 21 | + $$ | ||
| 22 | + out_i = self_i+alpha \times other_i | ||
| 23 | + $$ | ||
| 24 | + | ||
| 25 | + $$ | ||
| 26 | + relu(self) = \begin{cases} self, & self\gt 0 \\ 0, & self\le 0 \end{cases} | ||
| 27 | + $$ | ||
| 28 | + | ||
| 29 | +## 函数原型 | ||
| 30 | + | ||
| 31 | +- aclnnAddRelu和aclnnInplaceAddRelu实现相同的功能,使用区别如下,请根据自身实际场景选择合适的算子。 | ||
| 32 | + | ||
| 33 | + - aclnnAddRelu:需新建一个输出张量对象存储计算结果。 | ||
| 34 | + - aclnnInplaceAddRelu:无需新建输出张量对象,直接在输入张量的内存中存储计算结果。 | ||
| 35 | + | ||
| 36 | +- 每个算子分为[两段式接口](../../../../docs/zh/context/two_phase_api.md),必须先调用“aclnnAddReluGetWorkspaceSize”或者“aclnnInplaceAddReluGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnAddRelu”或者“aclnnInplaceAddRelu”接口执行计算。 | ||
| 37 | + | ||
| 38 | + ```Cpp | ||
| 39 | + aclnnStatus aclnnAddReluGetWorkspaceSize( | ||
| 40 | + const aclTensor *self, | ||
| 41 | + const aclTensor *other, | ||
| 42 | + aclScalar *alpha, | ||
| 43 | + aclTensor *out, | ||
| 44 | + uint64_t *workspaceSize, | ||
| 45 | + aclOpExecutor **executor) | ||
| 46 | + ``` | ||
| 47 | + | ||
| 48 | + ```Cpp | ||
| 49 | + aclnnStatus aclnnAddRelu( | ||
| 50 | + void *workspace, | ||
| 51 | + uint64_t workspaceSize, | ||
| 52 | + aclOpExecutor *executor, | ||
| 53 | + aclrtStream stream) | ||
| 54 | + ``` | ||
| 55 | + | ||
| 56 | + ```Cpp | ||
| 57 | + aclnnStatus aclnnInplaceAddReluGetWorkspaceSize( | ||
| 58 | + aclTensor *selfRef, | ||
| 59 | + const aclTensor *other, | ||
| 60 | + aclScalar *alpha, | ||
| 61 | + uint64_t *workspaceSize, | ||
| 62 | + aclOpExecutor **executor) | ||
| 63 | + ``` | ||
| 64 | + | ||
| 65 | + ```Cpp | ||
| 66 | + aclnnStatus aclnnInplaceAddRelu( | ||
| 67 | + void *workspace, | ||
| 68 | + uint64_t workspaceSize, | ||
| 69 | + aclOpExecutor *executor, | ||
| 70 | + aclrtStream stream) | ||
| 71 | + ``` | ||
| 72 | + | ||
| 73 | +## aclnnAddReluGetWorkspaceSize | ||
| 74 | + | ||
| 75 | +- **参数说明:** | ||
| 76 | + | ||
| 77 | + <table style="undefined;table-layout: fixed; width: 1478px"><colgroup> | ||
| 78 | + <col style="width: 249px"> | ||
| 79 | + <col style="width: 121px"> | ||
| 80 | + <col style="width: 164px"> | ||
| 81 | + <col style="width: 253px"> | ||
| 82 | + <col style="width: 262px"> | ||
| 83 | + <col style="width: 148px"> | ||
| 84 | + <col style="width: 135px"> | ||
| 85 | + <col style="width: 146px"> | ||
| 86 | + </colgroup> | ||
| 87 | + <thead> | ||
| 88 | + <tr> | ||
| 89 | + <th>参数名</th> | ||
| 90 | + <th>输入/输出</th> | ||
| 91 | + <th>描述</th> | ||
| 92 | + <th>使用说明</th> | ||
| 93 | + <th>数据类型</th> | ||
| 94 | + <th>数据格式</th> | ||
| 95 | + <th>维度(shape)</th> | ||
| 96 | + <th>非连续Tensor</th> | ||
| 97 | + </tr></thead> | ||
| 98 | + <tbody> | ||
| 99 | + <tr> | ||
| 100 | + <td>self(aclTensor*)</td> | ||
| @@ -0,0 +1,611 @@ | |||
| 1 | +# aclnnRelu&aclnnInplaceRelu | ||
| 2 | + | ||
| 3 | +[📄 查看源码](https://gitcode.com/cann/ops-nn/tree/master/activation/relu) | ||
| 4 | + | ||
| 5 | +## 产品支持情况 | ||
| 6 | + | ||
| 7 | +|产品 | 是否支持 | | ||
| 8 | +|:-------------------------|:----------:| | ||
| 9 | +| <term>Ascend 950PR/Ascend 950DT</term> | √ | | ||
| 10 | +| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | ||
| 11 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 推理产品</term> | × | | ||
| 13 | +| <term>Atlas 推理系列产品</term> | × | | ||
| 14 | +| <term>Atlas 训练系列产品</term> | √ | | ||
| 15 | + | ||
| 16 | +## 功能说明 | ||
| 17 | + | ||
| 18 | +- 接口功能:激活函数,返回与输入tensor shape相同的tensor,tensor中value大于等于0时,取该value,小于0,取0。 | ||
| 19 | +- 计算公式: | ||
| 20 | + | ||
| 21 | +$$ | ||
| 22 | +relu(self) = \begin{cases} self, & self\gt 0 \\ 0, & self\le 0 \end{cases} | ||
| 23 | +$$ | ||
| 24 | + | ||
| 25 | +## 函数原型 | ||
| 26 | + | ||
| 27 | +- aclnnRelu和aclnnInplaceRelu实现相同的功能,使用区别如下,请根据自身实际场景选择合适的算子。 | ||
| 28 | + - aclnnRelu:需新建一个输出张量对象存储计算结果。 | ||
| 29 | + - aclnnInplaceRelu:无需新建输出张量对象,直接在输入张量的内存中存储计算结果。 | ||
| 30 | + | ||
| 31 | +- 每个算子分为[两段式接口](../../../../docs/zh/context/two_phase_api.md),必须先调用“aclnnReluGetWorkspaceSize”或者“aclnnInplaceReluGetWorkspaceSize”接口获取入参并根据计算流程计算所需workspace大小,再调用“aclnnRelu”或者“aclnnInplaceRelu”接口执行计算。 | ||
| 32 | + | ||
| 33 | +```Cpp | ||
| 34 | +aclnnStatus aclnnReluGetWorkspaceSize( | ||
| 35 | + const aclTensor* self, | ||
| 36 | + const aclTensor* out, | ||
| 37 | + uint64_t* workspaceSize, | ||
| 38 | + aclOpExecutor **executor) | ||
| 39 | +``` | ||
| 40 | + | ||
| 41 | +```Cpp | ||
| 42 | +aclnnStatus aclnnRelu( | ||
| 43 | + void* workspace, | ||
| 44 | + uint64_t workspaceSize, | ||
| 45 | + aclOpExecutor* executor, | ||
| 46 | + const aclrtStream stream) | ||
| 47 | +``` | ||
| 48 | + | ||
| 49 | +```Cpp | ||
| 50 | +aclnnStatus aclnnInplaceReluGetWorkspaceSize( | ||
| 51 | + aclTensor* selfRef, | ||
| 52 | + uint64_t *workspaceSize, | ||
| 53 | + aclOpExecutor **executor) | ||
| 54 | +``` | ||
| 55 | + | ||
| 56 | +```Cpp | ||
| 57 | +aclnnStatus aclnnInplaceRelu( | ||
| 58 | + void *workspace, | ||
| 59 | + uint64_t workspaceSize, | ||
| 60 | + aclOpExecutor *executor, | ||
| 61 | + const aclrtStream stream) | ||
| 62 | +``` | ||
| 63 | + | ||
| 64 | +## aclnnReluGetWorkspaceSize | ||
| 65 | + | ||
| 66 | +- **参数说明:** | ||
| 67 | + | ||
| 68 | + <table style="undefined;table-layout: fixed; width: 1370px"><colgroup> | ||
| 69 | + <col style="width: 271px"> | ||
| 70 | + <col style="width: 115px"> | ||
| 71 | + <col style="width: 200px"> | ||
| 72 | + <col style="width: 220px"> | ||
| 73 | + <col style="width: 177px"> | ||
| 74 | + <col style="width: 104px"> | ||
| 75 | + <col style="width: 138px"> | ||
| 76 | + <col style="width: 145px"> | ||
| 77 | + </colgroup> | ||
| 78 | + <thead> | ||
| 79 | + <tr> | ||
| 80 | + <th>参数名</th> | ||
| 81 | + <th>输入/输出</th> | ||
| 82 | + <th>描述</th> | ||
| 83 | + <th>使用说明</th> | ||
| 84 | + <th>数据类型</th> | ||
| 85 | + <th>数据格式</th> | ||
| 86 | + <th>维度(shape)</th> | ||
| 87 | + <th>非连续Tensor</th> | ||
| 88 | + </tr></thead> | ||
| 89 | + <tbody> | ||
| 90 | + <tr> | ||
| 91 | + <td>self(aclTensor*)</td> | ||
| 92 | + <td>输入</td> | ||
| 93 | + <td>待进行Relu计算的入参,公式中的输入self。</td> | ||
| 94 | + <td><ul><li>支持空Tensor。</li><li>shape需要与out一致。</li></ul></td> | ||
| 95 | + <td>FLOAT、FLOAT16、INT8、INT32、INT64、BFLOAT16</td> | ||
| 96 | + <td>ND</td> | ||
| 97 | + <td>0-8</td> | ||
| 98 | + <td>√</td> | ||
| 99 | + </tr> | ||
| 100 | + <tr> | ||
Rexperimental/activation/relu_v2/examples/test_aclnn_relu_v2.cpp→experimental/activation/relu_v2/examples/test_aclnn_add_relu.cpp+72-88
| @@ -1,30 +1,17 @@ | |||
| 1 | /** | 1 | /** |
| 2 | - * This file is part of the OpenBOAT project at Harbin Institute of Technology (HIT) | 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | - * and is contributed to the CANN Open Software. | 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | - * | 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | - * Copyright (c) 2025 AISS Group, Harbin Institute of Technology (HIT). | 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | - * All Rights Reserved. | 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | - * | ||
| 8 | - * Authors (accounts): | ||
| 9 | - | ||
| 10 | - * - Tu Yuanhang <@TuYHAAAAAA> | ||
| 11 | - * - Su Tonghua <@sutonghua> | ||
| 12 | - * | ||
| 13 | - * This program is free software: you can redistribute it and/or modify it. | ||
| 14 | - * Licensed under the CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 15 | - * You may not use this file except in compliance with the License. | ||
| 16 | - * See the LICENSE file at the root of the repository for the full text of the License. | ||
| 17 | - * | ||
| 18 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, | ||
| 19 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 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. | ||
| 20 | */ | 9 | */ |
| 21 | #include <iostream> | 10 | #include <iostream> |
| 22 | -#include <memory> | ||
| 23 | #include <vector> | 11 | #include <vector> |
| 24 | #include "acl/acl.h" | 12 | #include "acl/acl.h" |
| 25 | -#include "aclnn_relu_v2.h" | 13 | +#include "aclnnop/aclnn_add_relu.h" |
| 26 | -// 修改测试数据类型 | 14 | + |
| 27 | -using DataType = int16_t; | ||
| 28 | #define CHECK_RET(cond, return_expr) \ | 15 | #define CHECK_RET(cond, return_expr) \ |
| 29 | do { \ | 16 | do { \ |
| 30 | if (!(cond)) { \ | 17 | if (!(cond)) { \ |
| @@ -46,22 +33,9 @@ int64_t GetShapeSize(const std::vector<int64_t>& shape) | |||
| 46 | return shapeSize; | 33 | return shapeSize; |
| 47 | } | 34 | } |
| 48 | 35 | ||
| 49 | -void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr) | ||
| 50 | -{ | ||
| 51 | - auto size = GetShapeSize(shape); | ||
| 52 | - std::vector<DataType> resultData(size, 0); | ||
| 53 | - auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr, | ||
| 54 | - size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 55 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ); | ||
| 56 | - for (int64_t i = 0; i < size; i++) { | ||
| 57 | - // LOG_PRINT("mean result[%ld] is: %f\n", i, resultData[i]); // float | ||
| 58 | - LOG_PRINT("mean result[%ld] is: %d\n", i, resultData[i]); // int | ||
| 59 | - } | ||
| 60 | -} | ||
| 61 | - | ||
| 62 | int Init(int32_t deviceId, aclrtStream* stream) | 36 | int Init(int32_t deviceId, aclrtStream* stream) |
| 63 | { | 37 | { |
| 64 | - // 固定写法,初始化 | 38 | + // 固定写法,资源初始化 |
| 65 | auto ret = aclInit(nullptr); | 39 | auto ret = aclInit(nullptr); |
| 66 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | 40 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); |
| 67 | ret = aclrtSetDevice(deviceId); | 41 | ret = aclrtSetDevice(deviceId); |
| @@ -76,10 +50,10 @@ int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& | |||
| 76 | aclDataType dataType, aclTensor** tensor) | 50 | aclDataType dataType, aclTensor** tensor) |
| 77 | { | 51 | { |
| 78 | auto size = GetShapeSize(shape) * sizeof(T); | 52 | auto size = GetShapeSize(shape) * sizeof(T); |
| 79 | - // 2. 申请device侧内存 | 53 | + // 调用aclrtMalloc申请device侧内存 |
| 80 | auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | 54 | auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); |
| 81 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | 55 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); |
| 82 | - // 3. 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | 56 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 |
| 83 | ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | 57 | ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); |
| 84 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | 58 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); |
| 85 | 59 | ||
| @@ -95,81 +69,91 @@ int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& | |||
| 95 | return 0; | 69 | return 0; |
| 96 | } | 70 | } |
| 97 | 71 | ||
| 98 | -int aclnnReluV2Test(int32_t deviceId, aclrtStream& stream) | 72 | +int main() |
| 99 | { | 73 | { |
| 100 | - // 1. 调用acl进行device/stream初始化 | 74 | + // 1. (固定写法)device/stream初始化,参考acl API手册 |
| 75 | + // 根据自己的实际device填写deviceId | ||
| 76 | + int32_t deviceId = 0; | ||
| 77 | + aclrtStream stream; | ||
| 101 | auto ret = Init(deviceId, &stream); | 78 | auto ret = Init(deviceId, &stream); |
| 102 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | 79 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); |
| 103 | 80 | ||
| 104 | // 2. 构造输入与输出,需要根据API的接口自定义构造 | 81 | // 2. 构造输入与输出,需要根据API的接口自定义构造 |
| 105 | - aclTensor* selfX = nullptr; | 82 | + std::vector<int64_t> selfShape = {4, 2}; |
| 106 | - void* selfXDeviceAddr = nullptr; | 83 | + std::vector<int64_t> otherShape = {4, 2}; |
| 107 | - std::vector<int64_t> selfXShape = {123, 7, 7}; | 84 | + std::vector<int64_t> outShape = {4, 2}; |
| 108 | - std::vector<DataType> selfXHostData(6027, 7); | 85 | + void* selfDeviceAddr = nullptr; |
| 109 | - ret = CreateAclTensor(selfXHostData, selfXShape, &selfXDeviceAddr, aclDataType::ACL_INT16, &selfX); | 86 | + void* otherDeviceAddr = nullptr; |
| 110 | - // 当前样例算子未进行shape、dtype全泛化,其他输入场景可能存在不支持情况 | ||
| 111 | - // 通过智能指针自动释放aclTensor和device资源 | ||
| 112 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> selfXPtr(selfX, aclDestroyTensor); | ||
| 113 | - std::unique_ptr<void, aclError (*)(void*)> selfXDeviceAddrPtr(selfXDeviceAddr, aclrtFree); | ||
| 114 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 115 | - | ||
| 116 | - aclTensor* out = nullptr; | ||
| 117 | void* outDeviceAddr = nullptr; | 87 | void* outDeviceAddr = nullptr; |
| 118 | - std::vector<int64_t> outShape = {123, 7, 7}; | 88 | + aclTensor* self = nullptr; |
| 119 | - std::vector<DataType> outHostData(6027, 0); | 89 | + aclTensor* other = nullptr; |
| 120 | - ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_INT16, &out); | 90 | + aclScalar* alpha = nullptr; |
| 121 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> outPtr(out, aclDestroyTensor); | 91 | + aclTensor* out = nullptr; |
| 122 | - std::unique_ptr<void, aclError (*)(void*)> outDeviceAddrPtr(outDeviceAddr, aclrtFree); | 92 | + std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; |
| 93 | + std::vector<float> otherHostData = {1, 1, 1, 2, 2, 2, 3, 3}; | ||
| 94 | + std::vector<float> outHostData(8, 0); | ||
| 95 | + float alphaValue = 1.2f; | ||
| 96 | + // 创建self aclTensor | ||
| 97 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 98 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 99 | + // 创建other aclTensor | ||
| 100 | + ret = CreateAclTensor(otherHostData, otherShape, &otherDeviceAddr, aclDataType::ACL_FLOAT, &other); | ||
| 101 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 102 | + // 创建alpha aclScalar | ||
| 103 | + alpha = aclCreateScalar(&alphaValue, aclDataType::ACL_FLOAT); | ||
| 104 | + CHECK_RET(alpha != nullptr, return ret); | ||
| 105 | + // 创建out aclTensor | ||
| 106 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 123 | CHECK_RET(ret == ACL_SUCCESS, return ret); | 107 | CHECK_RET(ret == ACL_SUCCESS, return ret); |
| 124 | 108 | ||
| 125 | - // 3. 调用CANN算子库API,需要修改为具体的Api名称 | ||
| 126 | uint64_t workspaceSize = 0; | 109 | uint64_t workspaceSize = 0; |
| 127 | aclOpExecutor* executor; | 110 | aclOpExecutor* executor; |
| 128 | 111 | ||
| 129 | - LOG_PRINT("Before GetWorkspaceSize: selfX=%p, out=%p\n", (void*)selfX, (void*)out); | 112 | + // aclnnAddRelu接口调用示例 |
| 130 | - LOG_PRINT("Before GetWorkspaceSize: selfXDeviceAddr=%p, selfYDeviceAddr=%p, outDeviceAddr=%p\n", selfXDeviceAddr, | 113 | + // 3. 调用CANN算子库API |
| 131 | - outDeviceAddr); | 114 | + // 调用aclnnAddRelu第一段接口 |
| 132 | - // 4. 调用aclnnReluV2第一段接口 | 115 | + ret = aclnnAddReluGetWorkspaceSize(self, other, alpha, out, &workspaceSize, &executor); |
| 133 | - ret = aclnnReluV2GetWorkspaceSize(selfX, out, &workspaceSize, &executor); | 116 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAddReluGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); |
| 134 | - LOG_PRINT("aclnnReluV2GetWorkspaceSize returned %d, workspaceSize=%llu, executor=%p\n", ret, | ||
| 135 | - (unsigned long long)workspaceSize, (void*)executor); | ||
| 136 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReluV2ExampleGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 137 | - | ||
| 138 | // 根据第一段接口计算出的workspaceSize申请device内存 | 117 | // 根据第一段接口计算出的workspaceSize申请device内存 |
| 139 | void* workspaceAddr = nullptr; | 118 | void* workspaceAddr = nullptr; |
| 140 | - std::unique_ptr<void, aclError (*)(void*)> workspaceAddrPtr(nullptr, aclrtFree); | 119 | + if (workspaceSize > 0) { |
| 141 | - if (workspaceSize > static_cast<uint64_t>(0)) { | ||
| 142 | ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | 120 | 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); | 121 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); |
| 144 | - workspaceAddrPtr.reset(workspaceAddr); | ||
| 145 | } | 122 | } |
| 123 | + // 调用aclnnAddRelu第二段接口 | ||
| 124 | + ret = aclnnAddRelu(workspaceAddr, workspaceSize, executor, stream); | ||
| 125 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAddRelu failed. ERROR: %d\n", ret); return ret); | ||
| 146 | 126 | ||
| 147 | - // 5. 调用aclnnAddExample第二段接口 | 127 | + // 4. (固定写法)同步等待任务执行结束 |
| 148 | - ret = aclnnReluV2(workspaceAddr, workspaceSize, executor, stream); | ||
| 149 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAddExample failed. ERROR: %d\n", ret); return ret); | ||
| 150 | - | ||
| 151 | - // 6. (固定写法)同步等待任务执行结束 | ||
| 152 | ret = aclrtSynchronizeStream(stream); | 128 | ret = aclrtSynchronizeStream(stream); |
| 153 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | 129 | CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); |
| 154 | 130 | ||
| 155 | - // 7. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | 131 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 |
| 156 | - std::vector<int64_t> outShape1 = {8}; | 132 | + auto size = GetShapeSize(outShape); |
| 157 | - PrintOutResult(outShape1, &outDeviceAddr); | 133 | + std::vector<float> resultData(size, 0); |
| 158 | - return ACL_SUCCESS; | 134 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, |
| 159 | -} | 135 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); |
| 136 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 137 | + for (int64_t i = 0; i < size; i++) { | ||
| 138 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 139 | + } | ||
| 160 | 140 | ||
| 161 | -int main() | 141 | + // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 |
| 162 | -{ | 142 | + aclDestroyTensor(self); |
| 163 | - int32_t deviceId = 0; | 143 | + aclDestroyTensor(other); |
| 164 | - aclrtStream stream; | 144 | + aclDestroyScalar(alpha); |
| 145 | + aclDestroyTensor(out); | ||
| 165 | 146 | ||
| 166 | - auto ret = aclnnReluV2Test(deviceId, stream); | 147 | + // 7. 释放Device资源,需要根据具体API的接口定义修改 |
| 167 | - // 释放device资源以及acl去初始化 | 148 | + aclrtFree(selfDeviceAddr); |
| 149 | + aclrtFree(otherDeviceAddr); | ||
| 150 | + aclrtFree(outDeviceAddr); | ||
| 151 | + if (workspaceSize > 0) { | ||
| 152 | + aclrtFree(workspaceAddr); | ||
| 153 | + } | ||
| 168 | aclrtDestroyStream(stream); | 154 | aclrtDestroyStream(stream); |
| 169 | aclrtResetDevice(deviceId); | 155 | aclrtResetDevice(deviceId); |
| 170 | aclFinalize(); | 156 | aclFinalize(); |
| 171 | 157 | ||
| 172 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReluV2Test failed. ERROR: %d\n", ret); return ret); | ||
| 173 | - | ||
| 174 | return 0; | 158 | return 0; |
| 175 | -} | 159 | +} |
| @@ -0,0 +1,161 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | +#include <iostream> | ||
| 11 | +#include <vector> | ||
| 12 | +#include "acl/acl.h" | ||
| 13 | +#include "aclnnop/aclnn_add_relu.h" | ||
| 14 | + | ||
| 15 | +#define CHECK_RET(cond, return_expr) \ | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | +#define LOG_PRINT(message, ...) \ | ||
| 23 | + do { \ | ||
| 24 | + printf(message, ##__VA_ARGS__); \ | ||
| 25 | + } while (0) | ||
| 26 | + | ||
| 27 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 28 | +{ | ||
| 29 | + int64_t shapeSize = 1; | ||
| 30 | + for (auto i : shape) { | ||
| 31 | + shapeSize *= i; | ||
| 32 | + } | ||
| 33 | + return shapeSize; | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 37 | +{ | ||
| 38 | + // 固定写法,资源初始化 | ||
| 39 | + auto ret = aclInit(nullptr); | ||
| 40 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 41 | + ret = aclrtSetDevice(deviceId); | ||
| 42 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 43 | + ret = aclrtCreateStream(stream); | ||
| 44 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 45 | + return 0; | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +template <typename T> | ||
| 49 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 50 | + aclDataType dataType, aclTensor** tensor) | ||
| 51 | +{ | ||
| 52 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 53 | + // 调用aclrtMalloc申请device侧内存 | ||
| 54 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 57 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 58 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 59 | + | ||
| 60 | + // 计算连续tensor的strides | ||
| 61 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 62 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 63 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 67 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 68 | + shape.data(), shape.size(), *deviceAddr); | ||
| 69 | + return 0; | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +int main() | ||
| 73 | +{ | ||
| 74 | + // 1. (固定写法)device/stream初始化,参考acl API手册 | ||
| 75 | + // 根据自己的实际device填写deviceId | ||
| 76 | + int32_t deviceId = 0; | ||
| 77 | + aclrtStream stream; | ||
| 78 | + auto ret = Init(deviceId, &stream); | ||
| 79 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 80 | + | ||
| 81 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 82 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 83 | + std::vector<int64_t> otherShape = {4, 2}; | ||
| 84 | + std::vector<int64_t> outShape = {4, 2}; | ||
| 85 | + void* selfDeviceAddr = nullptr; | ||
| 86 | + void* otherDeviceAddr = nullptr; | ||
| 87 | + void* outDeviceAddr = nullptr; | ||
| 88 | + aclTensor* self = nullptr; | ||
| 89 | + aclTensor* other = nullptr; | ||
| 90 | + aclScalar* alpha = nullptr; | ||
| 91 | + aclTensor* out = nullptr; | ||
| 92 | + std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 93 | + std::vector<float> otherHostData = {1, 1, 1, 2, 2, 2, 3, 3}; | ||
| 94 | + std::vector<float> outHostData(8, 0); | ||
| 95 | + float alphaValue = 1.2f; | ||
| 96 | + // 创建self aclTensor | ||
| 97 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 98 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 99 | + // 创建other aclTensor | ||
| 100 | + ret = CreateAclTensor(otherHostData, otherShape, &otherDeviceAddr, aclDataType::ACL_FLOAT, &other); | ||
| 101 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 102 | + // 创建alpha aclScalar | ||
| 103 | + alpha = aclCreateScalar(&alphaValue, aclDataType::ACL_FLOAT); | ||
| 104 | + CHECK_RET(alpha != nullptr, return ret); | ||
| 105 | + // 创建out aclTensor | ||
| 106 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 108 | + | ||
| 109 | + uint64_t workspaceSize = 0; | ||
| 110 | + aclOpExecutor* executor; | ||
| 111 | + | ||
| 112 | + // aclnnInplaceAddRelu接口调用示例 | ||
| 113 | + // 3. 调用CANN算子库API | ||
| 114 | + LOG_PRINT("\ntest aclnnInplaceAddRelu\n"); | ||
| 115 | + // 调用aclnnInplaceAddRelu第一段接口 | ||
| 116 | + ret = aclnnInplaceAddReluGetWorkspaceSize(self, other, alpha, &workspaceSize, &executor); | ||
| 117 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceAddReluGetWorkspaceSize failed. ERROR: %d\n", ret); | ||
| 118 | + return ret); | ||
| 119 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 120 | + void* workspaceAddr = nullptr; | ||
| 121 | + if (workspaceSize > 0) { | ||
| 122 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 123 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 124 | + } | ||
| 125 | + // 调用aclnnInplaceAddRelu第二段接口 | ||
| 126 | + ret = aclnnInplaceAddRelu(workspaceAddr, workspaceSize, executor, stream); | ||
| 127 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceAddRelu failed. ERROR: %d\n", ret); return ret); | ||
| 128 | + | ||
| 129 | + // 4. (固定写法)同步等待任务执行结束 | ||
| 130 | + ret = aclrtSynchronizeStream(stream); | ||
| 131 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 132 | + | ||
| 133 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 134 | + auto size = GetShapeSize(outShape); | ||
| 135 | + std::vector<float> resultData(size, 0); | ||
| 136 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), selfDeviceAddr, | ||
| 137 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 138 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 139 | + for (int64_t i = 0; i < size; i++) { | ||
| 140 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 144 | + aclDestroyTensor(self); | ||
| 145 | + aclDestroyTensor(other); | ||
| 146 | + aclDestroyScalar(alpha); | ||
| 147 | + aclDestroyTensor(out); | ||
| 148 | + | ||
| 149 | + // 7. 释放Device资源,需要根据具体API的接口定义修改 | ||
| 150 | + aclrtFree(selfDeviceAddr); | ||
| 151 | + aclrtFree(otherDeviceAddr); | ||
| 152 | + aclrtFree(outDeviceAddr); | ||
| 153 | + if (workspaceSize > 0) { | ||
| 154 | + aclrtFree(workspaceAddr); | ||
| 155 | + } | ||
| 156 | + aclrtDestroyStream(stream); | ||
| 157 | + aclrtResetDevice(deviceId); | ||
| 158 | + aclFinalize(); | ||
| 159 | + | ||
| 160 | + return 0; | ||
| 161 | +} | ||
| @@ -0,0 +1,134 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | +#include <iostream> | ||
| 11 | +#include <vector> | ||
| 12 | +#include "acl/acl.h" | ||
| 13 | +#include "aclnnop/aclnn_relu.h" | ||
| 14 | + | ||
| 15 | +#define CHECK_RET(cond, return_expr) \ | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | +#define LOG_PRINT(message, ...) \ | ||
| 22 | + do { \ | ||
| 23 | + printf(message, ##__VA_ARGS__); \ | ||
| 24 | + } while (0) | ||
| 25 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 26 | +{ | ||
| 27 | + int64_t shapeSize = 1; | ||
| 28 | + for (auto i : shape) { | ||
| 29 | + shapeSize *= i; | ||
| 30 | + } | ||
| 31 | + return shapeSize; | ||
| 32 | +} | ||
| 33 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 34 | +{ | ||
| 35 | + // 固定写法,资源初始化 | ||
| 36 | + auto ret = aclInit(nullptr); | ||
| 37 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 38 | + ret = aclrtSetDevice(deviceId); | ||
| 39 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 40 | + ret = aclrtCreateStream(stream); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + return 0; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +template <typename T> | ||
| 46 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 47 | + aclDataType dataType, aclTensor** tensor) | ||
| 48 | +{ | ||
| 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 | + // 计算连续tensor的strides | ||
| 57 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 58 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 59 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 60 | + } | ||
| 61 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 62 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 63 | + shape.data(), shape.size(), *deviceAddr); | ||
| 64 | + return 0; | ||
| 65 | +} | ||
| 66 | +int main() | ||
| 67 | +{ | ||
| 68 | + // 1. (固定写法)device/stream初始化,参考acl API手册 | ||
| 69 | + // 根据自己的实际device填写deviceId | ||
| 70 | + int32_t deviceId = 0; | ||
| 71 | + aclrtStream stream; | ||
| 72 | + auto ret = Init(deviceId, &stream); | ||
| 73 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 74 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 75 | + std::vector<int64_t> selfShape = {2, 2}; | ||
| 76 | + std::vector<int64_t> outShape = {2, 2}; | ||
| 77 | + void* selfDeviceAddr = nullptr; | ||
| 78 | + void* outDeviceAddr = nullptr; | ||
| 79 | + aclTensor* self = nullptr; | ||
| 80 | + aclTensor* out = nullptr; | ||
| 81 | + std::vector<float> selfHostData = {0, 1, 2, 3}; | ||
| 82 | + std::vector<float> outHostData = {0, 0, 0, 0}; | ||
| 83 | + // 创建self aclTensor | ||
| 84 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 85 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 86 | + // 创建out aclTensor | ||
| 87 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 88 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 89 | + // 3. 调用CANN算子库API,需要修改为具体的API名称 | ||
| 90 | + // aclnnInplaceRelu接口调用示例 | ||
| 91 | + uint64_t inplaceWorkspaceSize = 0; | ||
| 92 | + aclOpExecutor* inplaceExecutor; | ||
| 93 | + // 调用aclnnInplaceRelu第一段接口 | ||
| 94 | + ret = aclnnInplaceReluGetWorkspaceSize(self, &inplaceWorkspaceSize, &inplaceExecutor); | ||
| 95 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceReluGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 96 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 97 | + void* inplaceWorkspaceAddr = nullptr; | ||
| 98 | + if (inplaceWorkspaceSize > 0) { | ||
| 99 | + ret = aclrtMalloc(&inplaceWorkspaceAddr, inplaceWorkspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 100 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 101 | + } | ||
| 102 | + // 调用aclnnInplaceRelu第二段接口 | ||
| 103 | + ret = aclnnInplaceRelu(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream); | ||
| 104 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceRelu failed. ERROR: %d\n", ret); return ret); | ||
| 105 | + | ||
| 106 | + // 4. (固定写法)同步等待任务执行结束 | ||
| 107 | + ret = aclrtSynchronizeStream(stream); | ||
| 108 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 109 | + | ||
| 110 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 111 | + auto inplaceSize = GetShapeSize(selfShape); | ||
| 112 | + std::vector<float> inplaceResultData(inplaceSize, 0); | ||
| 113 | + ret = aclrtMemcpy(inplaceResultData.data(), inplaceResultData.size() * sizeof(inplaceResultData[0]), selfDeviceAddr, | ||
| 114 | + inplaceSize * sizeof(inplaceResultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 115 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 116 | + for (int64_t i = 0; i < inplaceSize; i++) { | ||
| 117 | + LOG_PRINT("aclnnInplaceRelu result[%ld] is: %f\n", i, inplaceResultData[i]); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 121 | + aclDestroyTensor(self); | ||
| 122 | + aclDestroyTensor(out); | ||
| 123 | + | ||
| 124 | + // 7. 释放device资源,需要根据具体API的接口定义修改 | ||
| 125 | + aclrtFree(selfDeviceAddr); | ||
| 126 | + aclrtFree(outDeviceAddr); | ||
| 127 | + if (inplaceWorkspaceSize > 0) { | ||
| 128 | + aclrtFree(inplaceWorkspaceAddr); | ||
| 129 | + } | ||
| 130 | + aclrtDestroyStream(stream); | ||
| 131 | + aclrtResetDevice(deviceId); | ||
| 132 | + aclFinalize(); | ||
| 133 | + return 0; | ||
| 134 | +} | ||
| @@ -0,0 +1,134 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | +#include <iostream> | ||
| 11 | +#include <vector> | ||
| 12 | +#include "acl/acl.h" | ||
| 13 | +#include "aclnnop/aclnn_relu.h" | ||
| 14 | + | ||
| 15 | +#define CHECK_RET(cond, return_expr) \ | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | +#define LOG_PRINT(message, ...) \ | ||
| 22 | + do { \ | ||
| 23 | + printf(message, ##__VA_ARGS__); \ | ||
| 24 | + } while (0) | ||
| 25 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 26 | +{ | ||
| 27 | + int64_t shapeSize = 1; | ||
| 28 | + for (auto i : shape) { | ||
| 29 | + shapeSize *= i; | ||
| 30 | + } | ||
| 31 | + return shapeSize; | ||
| 32 | +} | ||
| 33 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 34 | +{ | ||
| 35 | + // 固定写法,资源初始化 | ||
| 36 | + auto ret = aclInit(nullptr); | ||
| 37 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 38 | + ret = aclrtSetDevice(deviceId); | ||
| 39 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 40 | + ret = aclrtCreateStream(stream); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + return 0; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +template <typename T> | ||
| 46 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 47 | + aclDataType dataType, aclTensor** tensor) | ||
| 48 | +{ | ||
| 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 | + // 计算连续tensor的strides | ||
| 57 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 58 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 59 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 60 | + } | ||
| 61 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 62 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 63 | + shape.data(), shape.size(), *deviceAddr); | ||
| 64 | + return 0; | ||
| 65 | +} | ||
| 66 | +int main() | ||
| 67 | +{ | ||
| 68 | + // 1. (固定写法)device/stream初始化,参考acl API手册 | ||
| 69 | + // 根据自己的实际device填写deviceId | ||
| 70 | + int32_t deviceId = 0; | ||
| 71 | + aclrtStream stream; | ||
| 72 | + auto ret = Init(deviceId, &stream); | ||
| 73 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 74 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 75 | + std::vector<int64_t> selfShape = {2, 2}; | ||
| 76 | + std::vector<int64_t> outShape = {2, 2}; | ||
| 77 | + void* selfDeviceAddr = nullptr; | ||
| 78 | + void* outDeviceAddr = nullptr; | ||
| 79 | + aclTensor* self = nullptr; | ||
| 80 | + aclTensor* out = nullptr; | ||
| 81 | + std::vector<float> selfHostData = {0, 1, 2, 3}; | ||
| 82 | + std::vector<float> outHostData = {0, 0, 0, 0}; | ||
| 83 | + // 创建self aclTensor | ||
| 84 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 85 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 86 | + // 创建out aclTensor | ||
| 87 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 88 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 89 | + // 3. 调用CANN算子库API,需要修改为具体的API名称 | ||
| 90 | + // aclnnRelu接口调用示例 | ||
| 91 | + uint64_t workspaceSize = 0; | ||
| 92 | + aclOpExecutor* executor; | ||
| 93 | + // 调用aclnnRelu第一段接口 | ||
| 94 | + ret = aclnnReluGetWorkspaceSize(self, out, &workspaceSize, &executor); | ||
| 95 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReluGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 96 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 97 | + void* workspaceAddr = nullptr; | ||
| 98 | + if (workspaceSize > 0) { | ||
| 99 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 100 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 101 | + } | ||
| 102 | + // 调用aclnnRelu第二段接口 | ||
| 103 | + ret = aclnnRelu(workspaceAddr, workspaceSize, executor, stream); | ||
| 104 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRelu failed. ERROR: %d\n", ret); return ret); | ||
| 105 | + | ||
| 106 | + // 4. (固定写法)同步等待任务执行结束 | ||
| 107 | + ret = aclrtSynchronizeStream(stream); | ||
| 108 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 109 | + | ||
| 110 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 111 | + auto size = GetShapeSize(outShape); | ||
| 112 | + std::vector<float> resultData(size, 0); | ||
| 113 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, | ||
| 114 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 115 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 116 | + for (int64_t i = 0; i < size; i++) { | ||
| 117 | + LOG_PRINT("aclnnRelu result[%ld] is: %f\n", i, resultData[i]); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 121 | + aclDestroyTensor(self); | ||
| 122 | + aclDestroyTensor(out); | ||
| 123 | + | ||
| 124 | + // 7. 释放device资源,需要根据具体API的接口定义修改 | ||
| 125 | + aclrtFree(selfDeviceAddr); | ||
| 126 | + aclrtFree(outDeviceAddr); | ||
| 127 | + if (workspaceSize > 0) { | ||
| 128 | + aclrtFree(workspaceAddr); | ||
| 129 | + } | ||
| 130 | + aclrtDestroyStream(stream); | ||
| 131 | + aclrtResetDevice(deviceId); | ||
| 132 | + aclFinalize(); | ||
| 133 | + return 0; | ||
| 134 | +} | ||
| @@ -1,326 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * This file is part of the OpenBOAT project at Harbin Institute of Technology (HIT) | ||
| 3 | - * and is contributed to the CANN Open Software. | ||
| 4 | - * | ||
| 5 | - * Copyright (c) 2025 AISS Group, Harbin Institute of Technology (HIT). | ||
| 6 | - * All Rights Reserved. | ||
| 7 | - * | ||
| 8 | - * Authors (accounts): | ||
| 9 | - | ||
| 10 | - * - Tu Yuanhang <@TuYHAAAAAA> | ||
| 11 | - * - Su Tonghua <@sutonghua> | ||
| 12 | - * | ||
| 13 | - * This program is free software: you can redistribute it and/or modify it. | ||
| 14 | - * Licensed under the CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 15 | - * You may not use this file except in compliance with the License. | ||
| 16 | - * See the LICENSE file at the root of the repository for the full text of the License. | ||
| 17 | - * | ||
| 18 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, | ||
| 19 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 20 | - */ | ||
| 21 | -#include <iostream> | ||
| 22 | -#include <fstream> | ||
| 23 | -#include <string.h> | ||
| 24 | -#include <stdint.h> | ||
| 25 | -#include <vector> | ||
| 26 | -#include <string> | ||
| 27 | -#include <map> | ||
| 28 | -#include "assert.h" | ||
| 29 | - | ||
| 30 | -#include "graph.h" | ||
| 31 | -#include "types.h" | ||
| 32 | -#include "tensor.h" | ||
| 33 | -#include "ge_error_codes.h" | ||
| 34 | -#include "ge_api_types.h" | ||
| 35 | -#include "ge_api.h" | ||
| 36 | -#include "array_ops.h" | ||
| 37 | -#include "ge_ir_build.h" | ||
| 38 | - | ||
| 39 | -#include "experiment_ops.h" | ||
| 40 | -#include "nn_other.h" | ||
| 41 | -#include "../op_graph/relu_v2_proto.h" | ||
| 42 | - | ||
| 43 | -#define FAILED -1 | ||
| 44 | -#define SUCCESS 0 | ||
| 45 | - | ||
| 46 | -using namespace ge; | ||
| 47 | -using std::map; | ||
| 48 | -using std::string; | ||
| 49 | -using std::vector; | ||
| 50 | - | ||
| 51 | -#define ADD_INPUT(intputIndex, intputName, intputDtype, inputShape, value) \ | ||
| 52 | - vector<int64_t> placeholder##intputIndex##_shape = inputShape; \ | ||
| 53 | - auto placeholder##intputIndex = op::Data("placeholder" + intputIndex).set_attr_index(0); \ | ||
| 54 | - TensorDesc placeholder##intputIndex##_desc = TensorDesc(ge::Shape(placeholder##intputIndex##_shape), FORMAT_ND, \ | ||
| 55 | - intputDtype); \ | ||
| 56 | - placeholder##intputIndex##_desc.SetPlacement(ge::kPlacementHost); \ | ||
| 57 | - placeholder##intputIndex##_desc.SetFormat(FORMAT_ND); \ | ||
| 58 | - Tensor tensor_placeholder##intputIndex; \ | ||
| 59 | - if (intputDtype == DT_FLOAT || intputDtype == DT_FLOAT16) { \ | ||
| 60 | - ret = GenOnesDataFloat32(placeholder##intputIndex##_shape, tensor_placeholder##intputIndex, \ | ||
| 61 | - placeholder##intputIndex##_desc, static_cast<float>(value)); \ | ||
| 62 | - } else if (intputDtype == DT_INT32 || intputDtype == DT_INT16) { \ | ||
| 63 | - ret = GenOnesData(placeholder##intputIndex##_shape, tensor_placeholder##intputIndex, \ | ||
| 64 | - placeholder##intputIndex##_desc, intputDtype, static_cast<int>(value)); \ | ||
| 65 | - } \ | ||
| 66 | - if (ret != SUCCESS) { \ | ||
| 67 | - printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str()); \ | ||
| 68 | - return FAILED; \ | ||
| 69 | - } \ | ||
| 70 | - placeholder##intputIndex.update_input_desc_x(placeholder##intputIndex##_desc); \ | ||
| 71 | - input.push_back(tensor_placeholder##intputIndex); \ | ||
| 72 | - graph.AddOp(placeholder##intputIndex); \ | ||
| 73 | - add1.set_input_##intputName(placeholder##intputIndex); \ | ||
| 74 | - inputs.push_back(placeholder##intputIndex); | ||
| 75 | - | ||
| 76 | -#define ADD_CONST_INPUT(intputIndex, intputName, intputDtype, inputShape, value) \ | ||
| 77 | - vector<int64_t> placeholder##intputIndex##_shape = inputShape; \ | ||
| 78 | - auto placeholder##intputIndex = op::Const("placeholder" + intputIndex); \ | ||
| 79 | - TensorDesc placeholder##intputIndex##_desc = TensorDesc(ge::Shape(placeholder##intputIndex##_shape), FORMAT_ND, \ | ||
| 80 | - intputDtype); \ | ||
| 81 | - placeholder##intputIndex##_desc.SetPlacement(ge::kPlacementHost); \ | ||
| 82 | - placeholder##intputIndex##_desc.SetFormat(FORMAT_ND); \ | ||
| 83 | - Tensor tensor_placeholder##intputIndex; \ | ||
| 84 | - if (intputDtype == DT_FLOAT || intputDtype == DT_FLOAT16) { \ | ||
| 85 | - ret = GenOnesDataFloat32(placeholder##intputIndex##_shape, tensor_placeholder##intputIndex, \ | ||
| 86 | - placeholder##intputIndex##_desc, static_cast<float>(value)); \ | ||
| 87 | - } else if (intputDtype == DT_INT32 || intputDtype == DT_INT16) { \ | ||
| 88 | - ret = GenOnesData(placeholder##intputIndex##_shape, tensor_placeholder##intputIndex, \ | ||
| 89 | - placeholder##intputIndex##_desc, intputDtype, static_cast<int>(value)); \ | ||
| 90 | - } \ | ||
| 91 | - if (ret != SUCCESS) { \ | ||
| 92 | - printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str()); \ | ||
| 93 | - return FAILED; \ | ||
| 94 | - } \ | ||
| 95 | - placeholder##intputIndex.SetAttr("value", tensor_placeholder##intputIndex); \ | ||
| 96 | - placeholder##intputIndex.update_output_desc_y(placeholder##intputIndex##_desc); \ | ||
| 97 | - graph.AddOp(placeholder##intputIndex); \ | ||
| 98 | - add1.set_input_##intputName(placeholder##intputIndex); \ | ||
| 99 | - add1.update_input_desc_##intputName(placeholder##intputIndex##_desc); \ | ||
| 100 | - inputs.push_back(placeholder##intputIndex); | ||
| 101 | - | ||
| 102 | -#define ADD_OUTPUT(outputIndex, outputName, outputDtype, outputShape) \ | ||
| 103 | - TensorDesc outputName##outputIndex##_desc = TensorDesc(ge::Shape(outputShape), FORMAT_ND, outputDtype); \ | ||
| 104 | - add1.update_output_desc_##outputName(outputName##outputIndex##_desc); | ||
| 105 | -//新加 | ||
| 106 | -#define LOG_PRINT(message, ...) \ | ||
| 107 | - do { \ | ||
| 108 | - printf(message, ##__VA_ARGS__); \ | ||
| 109 | - } while (0) | ||
| 110 | - | ||
| 111 | -string GetTime() | ||
| 112 | -{ | ||
| 113 | - time_t timep; | ||
| 114 | - time(&timep); | ||
| 115 | - char tmp[64]; | ||
| 116 | - strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep)); | ||
| 117 | - return tmp; | ||
| 118 | -} | ||
| 119 | - | ||
| 120 | -uint32_t GetDataTypeSize(DataType dt) | ||
| 121 | -{ | ||
| 122 | - uint32_t dilation = 1; | ||
| 123 | - uint32_t oneByte = 1; | ||
| 124 | - uint32_t twoByte = 2; | ||
| 125 | - uint32_t fourByte = 4; | ||
| 126 | - uint32_t eightByte = 8; | ||
| 127 | - | ||
| 128 | - if (dt == ge::DT_FLOAT) { | ||
| 129 | - dilation = fourByte; | ||
| 130 | - } else if (dt == ge::DT_FLOAT16) { | ||
| 131 | - dilation = twoByte; | ||
| 132 | - } else if (dt == ge::DT_BF16) { | ||
| 133 | - dilation = twoByte; | ||
| 134 | - } else if (dt == ge::DT_INT16) { | ||
| 135 | - dilation = twoByte; | ||
| 136 | - } else if (dt == ge::DT_UINT16) { | ||
| 137 | - dilation = twoByte; | ||
| 138 | - } else if (dt == ge::DT_INT32) { | ||
| 139 | - dilation = fourByte; | ||
| 140 | - } else if (dt == ge::DT_UINT32) { | ||
| 141 | - dilation = fourByte; | ||
| 142 | - } else if (dt == ge::DT_INT64) { | ||
| 143 | - dilation = eightByte; | ||
| 144 | - } else if (dt == ge::DT_UINT64) { | ||
| 145 | - dilation = eightByte; | ||
| 146 | - } else if (dt == ge::DT_INT8) { | ||
| 147 | - dilation = oneByte; | ||
| 148 | - } | ||
| 149 | - return dilation; | ||
| 150 | -} | ||
| 151 | - | ||
| 152 | -int32_t GenOnesDataFloat32(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, float value) | ||
| 153 | -{ | ||
| 154 | - input_tensor_desc.SetRealDimCnt(shapes.size()); | ||
| 155 | - size_t size = 1; | ||
| 156 | - for (uint32_t i = 0; i < shapes.size(); i++) { | ||
| 157 | - size *= shapes[i]; | ||
| 158 | - } | ||
| 159 | - uint32_t byteSizeFloat32 = 4; | ||
| 160 | - uint32_t data_len = size * byteSizeFloat32; | ||
| 161 | - float* pData = new (std::nothrow) float[size]; | ||
| 162 | - | ||
| 163 | - for (size_t i = 0; i < size; ++i) { | ||
| 164 | - *(pData + i) = value; | ||
| 165 | - } | ||
| 166 | - input_tensor = Tensor(input_tensor_desc, (uint8_t*)pData, data_len); | ||
| 167 | - return SUCCESS; | ||
| 168 | -} | ||
| 169 | - | ||
| 170 | -int32_t GenOnesData(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, DataType data_type, | ||
| 171 | - int value) | ||
| 172 | -{ | ||
| 173 | - input_tensor_desc.SetRealDimCnt(shapes.size()); | ||
| 174 | - size_t size = 1; | ||
| 175 | - for (uint32_t i = 0; i < shapes.size(); i++) { | ||
| 176 | - size *= shapes[i]; | ||
| 177 | - } | ||
| 178 | - uint32_t data_len = size * GetDataTypeSize(data_type); | ||
| 179 | - int32_t* pData = new (std::nothrow) int32_t[size]; | ||
| 180 | - for (uint32_t i = 0; i < size; ++i) { | ||
| 181 | - *(pData + i) = value; | ||
| 182 | - } | ||
| 183 | - input_tensor = Tensor(input_tensor_desc, reinterpret_cast<uint8_t*>(pData), data_len); | ||
| 184 | - return SUCCESS; | ||
| 185 | -} | ||
| 186 | - | ||
| 187 | -int32_t WriteDataToFile(string bin_file, uint64_t data_size, uint8_t* inputData) | ||
| 188 | -{ | ||
| 189 | - FILE* fp; | ||
| 190 | - fp = fopen(bin_file.c_str(), "w"); | ||
| 191 | - fwrite(inputData, sizeof(uint8_t), data_size, fp); | ||
| 192 | - fclose(fp); | ||
| 193 | - return SUCCESS; | ||
| 194 | -} | ||
| 195 | - | ||
| 196 | -int CreateOppInGraph(DataType inDtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs, | ||
| 197 | - std::vector<Operator>& outputs, Graph& graph) | ||
| 198 | -{ | ||
| 199 | - Status ret = SUCCESS; | ||
| 200 | - // 自定义代码:添加单算子定义到图中 | ||
| 201 | - auto add1 = op::ReluV2("add1"); | ||
| 202 | - std::vector<int64_t> xShape = {32, 4, 4, 4}; | ||
| 203 | - ADD_INPUT(1, x, inDtype, xShape, 2); | ||
| 204 | - | ||
| 205 | - ADD_OUTPUT(1, y, inDtype, xShape); | ||
| 206 | - | ||
| 207 | - outputs.push_back(add1); | ||
| 208 | - // 添加完毕 | ||
| 209 | - return SUCCESS; | ||
| 210 | -} | ||
| 211 | - | ||
| 212 | -int main(int argc, char* argv[]) | ||
| 213 | -{ | ||
| 214 | - const char* graph_name = "tc_ge_irrun_test"; | ||
| 215 | - Graph graph(graph_name); | ||
| 216 | - std::vector<ge::Tensor> input; | ||
| 217 | - | ||
| 218 | - printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str()); | ||
| 219 | - std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}}; | ||
| 220 | - Status ret = ge::GEInitialize(global_options); | ||
| 221 | - if (ret != SUCCESS) { | ||
| 222 | - printf("%s - INFO - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str()); | ||
| 223 | - return FAILED; | ||
| 224 | - } | ||
| 225 | - printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str()); | ||
| 226 | - | ||
| 227 | - std::vector<Operator> inputs{}; | ||
| 228 | - std::vector<Operator> outputs{}; | ||
| 229 | - | ||
| 230 | - std::cout << argv[1] << std::endl; | ||
| 231 | - char* endptr; | ||
| 232 | - //修改类型 | ||
| 233 | - DataType inDtype = DT_FLOAT; | ||
| 234 | - | ||
| 235 | - std::cout << inDtype << std::endl; | ||
| 236 | - | ||
| 237 | - ret = CreateOppInGraph(inDtype, input, inputs, outputs, graph); | ||
| 238 | - if (ret != SUCCESS) { | ||
| 239 | - printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 240 | - return FAILED; | ||
| 241 | - } | ||
| 242 | - | ||
| 243 | - if (!inputs.empty() && !outputs.empty()) { | ||
| 244 | - graph.SetInputs(inputs).SetOutputs(outputs); | ||
| 245 | - } | ||
| 246 | - | ||
| 247 | - std::map<AscendString, AscendString> build_options = { | ||
| 248 | - | ||
| 249 | - }; | ||
| 250 | - printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str()); | ||
| 251 | - ge::Session* session = new Session(build_options); | ||
| 252 | - | ||
| 253 | - if (session == nullptr) { | ||
| 254 | - printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 255 | - return FAILED; | ||
| 256 | - } | ||
| 257 | - printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str()); | ||
| 258 | - printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str()); | ||
| 259 | - | ||
| 260 | - std::map<AscendString, AscendString> graph_options = { | ||
| 261 | - | ||
| 262 | - }; | ||
| 263 | - uint32_t graph_id = 0; | ||
| 264 | - ret = session->AddGraph(graph_id, graph, graph_options); | ||
| 265 | - | ||
| 266 | - printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str()); | ||
| 267 | - printf("%s - INFO - [XIR]: dump graph to txt\n", GetTime().c_str()); | ||
| 268 | - std::string file_path = "./dump"; | ||
| 269 | - aclgrphDumpGraph(graph, file_path.c_str(), file_path.length()); | ||
| 270 | - printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str()); | ||
| 271 | - std::vector<ge::Tensor> output; | ||
| 272 | - ret = session->RunGraph(graph_id, input, output); | ||
| 273 | - if (ret != SUCCESS) { | ||
| 274 | - printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str()); | ||
| 275 | - delete session; | ||
| 276 | - GEFinalize(); | ||
| 277 | - return FAILED; | ||
| 278 | - } | ||
| 279 | - printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str()); | ||
| 280 | - | ||
| 281 | - int input_num = input.size(); | ||
| 282 | - for (int i = 0; i < input_num; i++) { | ||
| 283 | - std::cout << "input " << i << " dtype : " << input[i].GetTensorDesc().GetDataType() << std::endl; | ||
| 284 | - string input_file = "./tc_ge_irrun_test_0008_npu_input_" + std::to_string(i) + ".bin"; | ||
| 285 | - uint8_t* input_data_i = input[i].GetData(); | ||
| 286 | - int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize(); | ||
| 287 | - std::cout << "this is " << i << "th input, input shape size =" << input_shape << std::endl; | ||
| 288 | - uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType()); | ||
| 289 | - WriteDataToFile((const char*)input_file.c_str(), data_size, input_data_i); | ||
| 290 | - } | ||
| 291 | - | ||
| 292 | - int output_num = output.size(); | ||
| 293 | - for (int i = 0; i < output_num; i++) { | ||
| 294 | - std::cout << "output " << i << " dtype : " << output[i].GetTensorDesc().GetDataType() << std::endl; | ||
| 295 | - string output_file = "./tc_ge_irrun_test_0008_npu_output_" + std::to_string(i) + ".bin"; | ||
| 296 | - uint8_t* output_data_i = output[i].GetData(); | ||
| 297 | - int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize(); | ||
| 298 | - std::cout << "this is " << i << "th output, output shape size =" << output_shape << std::endl; | ||
| 299 | - uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType()); | ||
| 300 | - WriteDataToFile((const char*)output_file.c_str(), data_size, output_data_i); | ||
| 301 | - //新加3行打印 | ||
| 302 | - float* result = (float*)output_data_i; | ||
| 303 | - // int32_t* result = (int32_t*)output_data_i; | ||
| 304 | - for (int64_t j = 0; j < 8; j++) { | ||
| 305 | - LOG_PRINT("result[%ld] is: %f\n", j, result[j]); | ||
| 306 | - // LOG_PRINT("result[%ld] is: %d\n", j, result[j]); | ||
| 307 | - } | ||
| 308 | - } | ||
| 309 | - | ||
| 310 | - ge::AscendString error_msg = ge::GEGetErrorMsgV2(); | ||
| 311 | - std::string error_str(error_msg.GetString()); | ||
| 312 | - std::cout << "Error message: " << error_str << std::endl; | ||
| 313 | - ge::AscendString warning_msg = ge::GEGetWarningMsgV2(); | ||
| 314 | - std::string warning_str(warning_msg.GetString()); | ||
| 315 | - std::cout << "Warning message: " << warning_str << std::endl; | ||
| 316 | - printf("%s - INFO - [XIR]: Precision is ok\n", GetTime().c_str()); | ||
| 317 | - printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str()); | ||
| 318 | - delete session; | ||
| 319 | - ret = ge::GEFinalize(); | ||
| 320 | - if (ret != SUCCESS) { | ||
| 321 | - printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str()); | ||
| 322 | - return FAILED; | ||
| 323 | - } | ||
| 324 | - printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str()); | ||
| 325 | - return SUCCESS; | ||
| 326 | -} | ||
| @@ -0,0 +1,326 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include "aclnn_add_relu.h" | ||
| 12 | +#include "level0/add.h" | ||
| 13 | +#include "level0/axpy.h" | ||
| 14 | +#include "relu_v2.h" | ||
| 15 | +#include "aclnn_kernels/common/op_error_check.h" | ||
| 16 | +#include "aclnn_kernels/cast.h" | ||
| 17 | +#include "aclnn_kernels/contiguous.h" | ||
| 18 | +#include "level0/mul.h" | ||
| 19 | +#include "level0/logical_and.h" | ||
| 20 | +#include "level0/logical_or.h" | ||
| 21 | +#include "aclnn_kernels/common/op_error_check.h" | ||
| 22 | +#include "opdev/common_types.h" | ||
| 23 | +#include "aclnn/aclnn_base.h" | ||
| 24 | +#include "opdev/data_type_utils.h" | ||
| 25 | +#include "opdev/format_utils.h" | ||
| 26 | +#include "opdev/op_dfx.h" | ||
| 27 | +#include "opdev/op_executor.h" | ||
| 28 | +#include "opdev/op_log.h" | ||
| 29 | +#include "opdev/shape_utils.h" | ||
| 30 | +#include "opdev/tensor_view_utils.h" | ||
| 31 | +#include "opdev/platform.h" | ||
| 32 | + | ||
| 33 | +using namespace op; | ||
| 34 | +#ifdef __cplusplus | ||
| 35 | +extern "C" { | ||
| 36 | +#endif | ||
| 37 | + | ||
| 38 | +/* AddRelu 算子的完整计算流程如下: | ||
| 39 | + * self other | ||
| 40 | + * | | | ||
| 41 | + * \ / | ||
| 42 | + * Contiguous(workspace_0) Contiguous(workspace_2) | ||
| 43 | + * \ / | ||
| 44 | + * Cast(workspace_1) Cast(workspace_3) | ||
| 45 | + * \ / | ||
| 46 | + * Add(workspace_4) | ||
| 47 | + * | | ||
| 48 | + * Cast(workspace_5) | ||
| 49 | + * | | ||
| 50 | + * Relu(workspace_6) | ||
| 51 | + * | | ||
| 52 | + * ViewCopy | ||
| 53 | + * | | ||
| 54 | + * result | ||
| 55 | + */ | ||
| 56 | + | ||
| 57 | +static constexpr size_t MAX_DIM_LEN = 8; | ||
| 58 | + | ||
| 59 | +// 根据API定义,需要列出所能支持的所有dtype | ||
| 60 | +static const std::initializer_list<op::DataType> AXPY_DTYPE_SUPPORT_LIST = { | ||
| 61 | + op::DataType::DT_FLOAT, op::DataType::DT_INT32, op::DataType::DT_FLOAT16}; | ||
| 62 | + | ||
| 63 | +static const std::initializer_list<op::DataType> DTYPE_SUPPORT_LIST_WITHOUT_BF16 = { | ||
| 64 | + op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_INT8, op::DataType::DT_UINT8, | ||
| 65 | + op::DataType::DT_INT16, op::DataType::DT_INT32, op::DataType::DT_INT64}; | ||
| 66 | + | ||
| 67 | +static const std::initializer_list<op::DataType> DTYPE_SUPPORT_LIST_WITH_BF16 = { | ||
| 68 | + op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_BF16, op::DataType::DT_INT8, | ||
| 69 | + op::DataType::DT_UINT8, op::DataType::DT_INT16, op::DataType::DT_INT32, op::DataType::DT_INT64}; | ||
| 70 | + | ||
| 71 | +static const std::initializer_list<op::DataType> FP_DTYPE_SUPPORT_LIST = {op::DataType::DT_FLOAT, op::DataType::DT_BF16, | ||
| 72 | + op::DataType::DT_FLOAT16}; | ||
| 73 | + | ||
| 74 | +static bool CheckNotNull(const aclTensor* self, const aclTensor* other, const aclScalar* alpha, const aclTensor* out) | ||
| 75 | +{ | ||
| 76 | + OP_CHECK_NULL(self, return false); | ||
| 77 | + OP_CHECK_NULL(other, return false); | ||
| 78 | + OP_CHECK_NULL(alpha, return false); | ||
| 79 | + OP_CHECK_NULL(out, return false); | ||
| 80 | + return true; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +static inline const std::initializer_list<op::DataType>& GetDtypeSupportListBySocVersion() | ||
| 84 | +{ | ||
| 85 | + auto curArch = GetCurrentPlatformInfo().GetCurNpuArch(); | ||
| 86 | + if (curArch == NpuArch::DAV_2201 || curArch == NpuArch::DAV_3510) { | ||
| 87 | + return DTYPE_SUPPORT_LIST_WITH_BF16; | ||
| 88 | + } else { | ||
| 89 | + return DTYPE_SUPPORT_LIST_WITHOUT_BF16; | ||
| 90 | + } | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +static void CheckFormat(const aclTensor* self, const aclTensor* other, const aclTensor* out) | ||
| 94 | +{ | ||
| 95 | + OP_CHECK_NO_RETURN(self->GetStorageFormat() != Format::FORMAT_FRACTAL_NZ, | ||
| 96 | + OP_LOGW("Format of self gets [%s], this format mat lead to precision failure", | ||
| 97 | + op::ToString(Format::FORMAT_FRACTAL_NZ).GetString())); | ||
| 98 | + OP_CHECK_NO_RETURN(other->GetStorageFormat() != Format::FORMAT_FRACTAL_NZ, | ||
| 99 | + OP_LOGW("Format of other gets [%s], this format mat lead to precision failure", | ||
| 100 | + op::ToString(Format::FORMAT_FRACTAL_NZ).GetString())); | ||
| 101 | + OP_CHECK_NO_RETURN(out->GetStorageFormat() != Format::FORMAT_FRACTAL_NZ, | ||
| 102 | + OP_LOGW("Format of out gets [%s], this format mat lead to precision failure", | ||
| 103 | + op::ToString(Format::FORMAT_FRACTAL_NZ).GetString())); | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +static bool CheckPromoteType(const op::DataType selfDtype, const op::DataType otherDtype, const aclScalar* alpha, | ||
| 107 | + const op::DataType outDtype, op::DataType promoteType) | ||
| 108 | +{ | ||
| 109 | + // 检查self和other能否做数据类型推导 | ||
| 110 | + if (promoteType == DataType::DT_UNDEFINED) { | ||
| 111 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Self dtype %s and other dtype %s can not promote dtype.", | ||
| 112 | + op::ToString(selfDtype).GetString(), op::ToString(otherDtype).GetString()); | ||
| 113 | + return false; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + // 检查alpha能否转换为推导后的数据类型 | ||
| 117 | + if (promoteType == op::DataType::DT_BOOL) { | ||
| 118 | + OP_CHECK( | ||
| 119 | + IsIntegralType(DataType(alpha->GetDataType()), true), | ||
| 120 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Alpha dtype %s can't be cast to the promote dtype %s.", | ||
| 121 | + op::ToString(DataType(alpha->GetDataType())).GetString(), op::ToString(promoteType).GetString()), | ||
| 122 | + return false); | ||
| 123 | + } else if (!CanCast(DataType(alpha->GetDataType()), promoteType)) { | ||
| 124 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Alpha dtype %s can't be cast to the promote dtype %s.", | ||
| 125 | + op::ToString(DataType(alpha->GetDataType())).GetString(), op::ToString(promoteType).GetString()); | ||
| 126 | + return false; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + // 检查推导后的数据类型能否转换为输出的数据类型 | ||
| 130 | + if (!CanCast(promoteType, outDtype)) { | ||
| 131 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Promote dtype %s can't be cast to the desired output type %s.", | ||
| 132 | + op::ToString(promoteType).GetString(), op::ToString(outDtype).GetString()); | ||
| 133 | + return false; | ||
| 134 | + } | ||
| 135 | + return true; | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +static bool CheckShape(const aclTensor* self, const aclTensor* other, const aclTensor* y) | ||
| 139 | +{ | ||
| 140 | + OP_CHECK_MAX_DIM(self, MAX_DIM_LEN, return false); | ||
| 141 | + OP_CHECK_MAX_DIM(other, MAX_DIM_LEN, return false); | ||
| 142 | + | ||
| 143 | + op::Shape broadcastShape; | ||
| 144 | + OP_CHECK_BROADCAST_AND_INFER_SHAPE(self, other, broadcastShape, return false); | ||
| 145 | + | ||
| 146 | + if (broadcastShape != y->GetViewShape()) { | ||
| 147 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Shape of out should be %s, but current is %s.", | ||
| 148 | + op::ToString(broadcastShape).GetString(), op::ToString(y->GetViewShape()).GetString()); | ||
| 149 | + return false; | ||
| 150 | + } | ||
| 151 | + return true; | ||
| 152 | +} | ||
| 153 | + | ||
| 154 | +static aclnnStatus CheckParams(const aclTensor* self, const aclTensor* other, const aclScalar* alpha, | ||
| 155 | + const aclTensor* y) | ||
| 156 | +{ | ||
| 157 | + // 1. 检查参数是否为空指针 | ||
| 158 | + CHECK_RET(CheckNotNull(self, other, alpha, y), ACLNN_ERR_PARAM_NULLPTR); | ||
| 159 | + | ||
| 160 | + // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验 | ||
| 161 | + const std::initializer_list<op::DataType> dtypeSupportList = GetDtypeSupportListBySocVersion(); | ||
| 162 | + // 检查self的数据类型是否在add算子的支持列表内 | ||
| 163 | + OP_CHECK_DTYPE_NOT_SUPPORT(self, dtypeSupportList, return ACLNN_ERR_PARAM_INVALID); | ||
| 164 | + // 检查other的数据类型是否在add算子的支持列表内 | ||
| 165 | + OP_CHECK_DTYPE_NOT_SUPPORT(other, dtypeSupportList, return ACLNN_ERR_PARAM_INVALID); | ||
| 166 | + | ||
| 167 | + // 3. 检查self和other能否做数据类型推导以及推导的数据类型能否转换为输出数据类型 | ||
| 168 | + op::DataType promoteType = op::PromoteType(self->GetDataType(), other->GetDataType()); | ||
| 169 | + CHECK_RET(CheckPromoteType(self->GetDataType(), other->GetDataType(), alpha, y->GetDataType(), promoteType), | ||
| 170 | + ACLNN_ERR_PARAM_INVALID); | ||
| 171 | + | ||
| 172 | + // 4. 检查双输入是否能broadcast | ||
| 173 | + CHECK_RET(CheckShape(self, other, y), ACLNN_ERR_PARAM_INVALID); | ||
| 174 | + | ||
| 175 | + // 5. 检查format | ||
| 176 | + CheckFormat(self, other, y); | ||
| 177 | + | ||
| 178 | + return ACLNN_SUCCESS; | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +static bool IsSupportAxpy(const DataType promoteType) { return CheckType(promoteType, AXPY_DTYPE_SUPPORT_LIST); } | ||
| 182 | + | ||
| 183 | +static bool IsFpDtype(const DataType promoteType) { return CheckType(promoteType, FP_DTYPE_SUPPORT_LIST); } | ||
| 184 | + | ||
| 185 | +inline static bool isAddMixDtypeSupport(const aclTensor* self, const aclTensor* other) | ||
| 186 | +{ | ||
| 187 | + return (self->GetDataType() == DataType::DT_FLOAT16 && other->GetDataType() == DataType::DT_FLOAT) || | ||
| 188 | + (self->GetDataType() == DataType::DT_FLOAT && other->GetDataType() == DataType::DT_FLOAT16) || | ||
| 189 | + (self->GetDataType() == DataType::DT_BF16 && other->GetDataType() == DataType::DT_FLOAT) || | ||
| 190 | + (self->GetDataType() == DataType::DT_FLOAT && other->GetDataType() == DataType::DT_BF16); | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +aclnnStatus aclnnAddReluGetWorkspaceSize(const aclTensor* self, const aclTensor* other, aclScalar* alpha, | ||
| 194 | + aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor) | ||
| 195 | +{ | ||
| 196 | + L2_DFX_PHASE_1(aclnnAddRelu, DFX_IN(self, other, alpha), DFX_OUT(out)); | ||
| 197 | + // 固定写法,创建OpExecutor | ||
| 198 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 199 | + CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR); | ||
| 200 | + | ||
| 201 | + // 固定写法,参数检查 | ||
| 202 | + auto ret = CheckParams(self, other, alpha, out); | ||
| 203 | + CHECK_RET(ret == ACLNN_SUCCESS, ret); | ||
| 204 | + | ||
| 205 | + // add算子的空tensor在kernel中支持,对标竞品根据算子实际情况补充 | ||
| 206 | + if (self->IsEmpty() || other->IsEmpty()) { | ||
| 207 | + // 根据实际支持情况补充 | ||
| 208 | + *workspaceSize = 0; | ||
| 209 | + uniqueExecutor.ReleaseTo(executor); | ||
| 210 | + return ACLNN_SUCCESS; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + // 固定写法,将输入self转换成连续的tensor | ||
| 214 | + auto selfContiguous = l0op::Contiguous(self, uniqueExecutor.get()); | ||
| 215 | + CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 216 | + | ||
| 217 | + // 固定写法,将输入other转换成连续的tensor | ||
| 218 | + auto otherContiguous = l0op::Contiguous(other, uniqueExecutor.get()); | ||
| 219 | + CHECK_RET(otherContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 220 | + | ||
| 221 | + // 申请add的输出tensor | ||
| 222 | + const aclTensor* addOpOut = nullptr; | ||
| 223 | + // 判断输入是否符合kernel支持的混合输入类型 | ||
| 224 | + bool isMixDataType = isAddMixDtypeSupport(self, other); | ||
| 225 | + if (isMixDataType && !(alpha->ToFloat() > 1 || alpha->ToFloat() < 1)) { | ||
| 226 | + // 无需调用Cast,直接调用L0带混合数据类型的kernel | ||
| 227 | + addOpOut = l0op::Add(selfContiguous, otherContiguous, uniqueExecutor.get()); | ||
| 228 | + } else { | ||
| 229 | + // 对self和other两个输入做隐式数据类型转换,根据具体算子语义按需调用 | ||
| 230 | + auto promoteType = op::PromoteType(self->GetDataType(), other->GetDataType()); | ||
| 231 | + promoteType = IsFpDtype(promoteType) ? DataType::DT_FLOAT : promoteType; | ||
| 232 | + | ||
| 233 | + // 将输入self的数据类型转换成隐式数据类型,根据具体算子语义按需调用 | ||
| 234 | + auto selfCasted = l0op::Cast(selfContiguous, promoteType, uniqueExecutor.get()); | ||
| 235 | + CHECK_RET(selfCasted != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 236 | + | ||
| 237 | + // 将输入other的数据类型转换成隐式数据类型,根据具体算子语义按需调用 | ||
| 238 | + auto otherCasted = l0op::Cast(otherContiguous, promoteType, uniqueExecutor.get()); | ||
| 239 | + CHECK_RET(otherCasted != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 240 | + | ||
| 241 | + // 进行非混合输入类型的Add计算分支判断 | ||
| 242 | + if (!(alpha->ToFloat() > 1 || alpha->ToFloat() < 1)) { | ||
| 243 | + addOpOut = l0op::Add(selfCasted, otherCasted, uniqueExecutor.get()); | ||
| 244 | + } else if (IsSupportAxpy(promoteType)) { | ||
| 245 | + addOpOut = l0op::Axpy(selfCasted, otherCasted, alpha->ToFloat(), uniqueExecutor.get()); | ||
| 246 | + } else { | ||
| 247 | + const auto alphaTensor = uniqueExecutor.get()->ConvertToTensor(alpha, promoteType); | ||
| 248 | + const auto otherRes = l0op::Mul(otherCasted, alphaTensor, uniqueExecutor.get()); | ||
| 249 | + addOpOut = l0op::Add(selfCasted, otherRes, uniqueExecutor.get()); | ||
| 250 | + } | ||
| 251 | + } | ||
| 252 | + CHECK_RET(addOpOut != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 253 | + | ||
| 254 | + // 如果out的数据类型是int16,则转成int32进行relu计算 | ||
| 255 | + const aclTensor* addOutCasted = nullptr; | ||
| 256 | + if (addOpOut->GetDataType() == DataType::DT_INT16) { | ||
| 257 | + addOutCasted = l0op::Cast(addOpOut, DataType::DT_INT32, uniqueExecutor.get()); | ||
| 258 | + } else { | ||
| 259 | + addOutCasted = addOpOut; | ||
| 260 | + } | ||
| 261 | + CHECK_RET(addOutCasted != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 262 | + | ||
| 263 | + // 如果addOutCasted不是UINT8类型,需要调用relu计算 | ||
| 264 | + const aclTensor* reluRes = nullptr; | ||
| 265 | + if (addOutCasted->GetDataType() != op::DataType::DT_UINT8) { | ||
| 266 | + // 调用relu进行计算 | ||
| 267 | + reluRes = l0op::ReluV2(addOutCasted, uniqueExecutor.get()); | ||
| 268 | + } else { | ||
| 269 | + reluRes = addOutCasted; | ||
| 270 | + } | ||
| 271 | + CHECK_RET(reluRes != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 272 | + | ||
| 273 | + // reluRes数据类型cast回out | ||
| 274 | + auto outCasted = l0op::Cast(reluRes, out->GetDataType(), uniqueExecutor.get()); | ||
| 275 | + | ||
| 276 | + // 固定写法,将计算结果outCasted拷贝到输出out上,out可能是非连续的tensor | ||
| 277 | + auto viewCopyResult = l0op::ViewCopy(outCasted, out, uniqueExecutor.get()); | ||
| 278 | + CHECK_RET(viewCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 279 | + | ||
| 280 | + // 固定写法,获取计算过程中需要使用的workspace大小 | ||
| 281 | + *workspaceSize = uniqueExecutor->GetWorkspaceSize(); | ||
| 282 | + uniqueExecutor.ReleaseTo(executor); // 需要把 uniqueExecutor持有executor转移给executor | ||
| 283 | + return ACLNN_SUCCESS; | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +aclnnStatus aclnnAddRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream) | ||
| 287 | +{ | ||
| 288 | + L2_DFX_PHASE_2(aclnnAddRelu); | ||
| 289 | + // 固定写法,调用框架能力,完成计算 | ||
| 290 | + return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); | ||
| 291 | +} | ||
| 292 | + | ||
| 293 | +static inline aclnnStatus CheckInplace(const aclTensor* selfRef, const aclTensor* other) | ||
| 294 | +{ | ||
| 295 | + OP_CHECK_NULL(selfRef, return ACLNN_ERR_PARAM_NULLPTR); | ||
| 296 | + OP_CHECK_NULL(other, return ACLNN_ERR_PARAM_NULLPTR); | ||
| 297 | + | ||
| 298 | + op::Shape broadcastShape; | ||
| 299 | + OP_CHECK_BROADCAST_AND_INFER_SHAPE(selfRef, other, broadcastShape, return ACLNN_ERR_PARAM_INVALID); | ||
| 300 | + | ||
| 301 | + OP_CHECK(selfRef->GetViewShape() == broadcastShape, | ||
| 302 | + OP_LOGE(ACLNN_ERR_PARAM_NULLPTR, "Expected shape of selfRef should be %s, but got %s.", | ||
| 303 | + op::ToString(broadcastShape).GetString(), op::ToString(selfRef->GetViewShape()).GetString()), | ||
| 304 | + return ACLNN_ERR_PARAM_INVALID); | ||
| 305 | + return ACLNN_SUCCESS; | ||
| 306 | +} | ||
| 307 | + | ||
| 308 | +aclnnStatus aclnnInplaceAddReluGetWorkspaceSize(aclTensor* selfRef, const aclTensor* other, aclScalar* alpha, | ||
| 309 | + uint64_t* workspaceSize, aclOpExecutor** executor) | ||
| 310 | +{ | ||
| 311 | + auto ret = CheckInplace(selfRef, other); | ||
| 312 | + CHECK_RET(ret == ACLNN_SUCCESS, ret); | ||
| 313 | + | ||
| 314 | + return aclnnAddReluGetWorkspaceSize(selfRef, other, alpha, selfRef, workspaceSize, executor); | ||
| 315 | +} | ||
| 316 | + | ||
| 317 | +aclnnStatus aclnnInplaceAddRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream) | ||
| 318 | +{ | ||
| 319 | + L2_DFX_PHASE_2(aclnnInplaceAddRelu); | ||
| 320 | + // 固定写法,调用框架能力,完成计算 | ||
| 321 | + return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); | ||
| 322 | +} | ||
| 323 | + | ||
| 324 | +#ifdef __cplusplus | ||
| 325 | +} | ||
| 326 | +#endif | ||
| @@ -0,0 +1,93 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | +#ifndef OP_API_INC_ADD_RELU_H_ | ||
| 11 | +#define OP_API_INC_ADD_RELU_H_ | ||
| 12 | + | ||
| 13 | +#include "aclnn/aclnn_base.h" | ||
| 14 | +#include "aclnn_util.h" | ||
| 15 | + | ||
| 16 | +#ifdef __cplusplus | ||
| 17 | +extern "C" { | ||
| 18 | +#endif | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * @brief aclnnAddRelu的第一段接口,根据具体的计算流程,计算workspace大小。 | ||
| 22 | + * @domain aclnn_math | ||
| 23 | + * | ||
| 24 | + * 算子功能:完成加法计算后,对张量结果进行处理:大于0则不变,小于0则修改为0。 | ||
| 25 | + * | ||
| 26 | + * @param [in] self: npu | ||
| 27 | + * device侧的aclTensor,数据类型支持整型,浮点类型,且数据类型需要与other构成互相推导关系,shape需要与other满足broadcast关系。 | ||
| 28 | + * 支持非连续的Tensor,数据格式支持ND,且数据格式需要与other一致。 | ||
| 29 | + * @param [in] other: npu | ||
| 30 | + * device侧的aclTensor,数据类型支持整型,浮点类型,且数据类型需要与self构成互相推导关系,shape需要与self满足broadcast关系。 | ||
| 31 | + * 支持非连续的Tensor,数据格式支持ND,且数据格式需要与self一致。 | ||
| 32 | + * @param [in] alpha: host侧的aclScalar,数据类型需要可转换成self与other推导后的数据类型。 | ||
| 33 | + * @param [in] out: npu | ||
| 34 | + * device侧的aclTensor,数据类型支持整型,浮点类型,且数据类型需要是self与other推导之后可转换的数据类型,shape需要是self与other | ||
| 35 | + * broadcast之后的shape,数据格式支持ND,且数据格式需要与self一致。 | ||
| 36 | + * @param [out] workspaceSize: 返回用户需要在npu device侧申请的workspace大小。 | ||
| 37 | + * @param [out] executor: 返回op执行器,包含算子计算流程。 | ||
| 38 | + * @return aclnnStatus: 返回状态码。 | ||
| 39 | + */ | ||
| 40 | +ACLNN_API aclnnStatus aclnnAddReluGetWorkspaceSize(const aclTensor* self, const aclTensor* other, aclScalar* alpha, | ||
| 41 | + aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor); | ||
| 42 | + | ||
| 43 | +/** | ||
| 44 | + * @brief aclnnAdd的第二段接口,用于执行计算。 | ||
| 45 | + * | ||
| 46 | + * @param [in] workspace: 在npu device侧申请的workspace内存起址。 | ||
| 47 | + * @param [in] workspace_size: 在npu device侧申请的workspace大小,由第一段接口aclnnAddGetWorkspaceSize获取。 | ||
| 48 | + * @param [in] executor: op执行器,包含了算子计算流程。 | ||
| 49 | + * @param [in] stream: acl stream流。 | ||
| 50 | + * @return aclnnStatus: 返回状态码。 | ||
| 51 | + */ | ||
| 52 | +ACLNN_API aclnnStatus aclnnAddRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, | ||
| 53 | + aclrtStream stream); | ||
| 54 | + | ||
| 55 | +/** | ||
| 56 | + * @brief aclnnInplaceAddRelu的第一段接口,根据具体的计算流程,计算workspace大小。 | ||
| 57 | + * @domain aclnn_math | ||
| 58 | + * | ||
| 59 | + * 算子功能:完成加法计算后,对张量结果进行处理:大于0则不变,小于0则修改为0。 | ||
| 60 | + * | ||
| 61 | + * @param [in] selfRef: npu | ||
| 62 | + * device侧的aclTensor,数据类型支持整型,浮点类型,且数据类型需要与other构成互相推导关系,shape需要与other满足broadcast关系。 | ||
| 63 | + * 支持非连续的Tensor,数据格式支持ND,且数据格式需要与other一致。 | ||
| 64 | + * @param [in] other: npu | ||
| 65 | + * device侧的aclTensor,数据类型支持整型,浮点类型,且数据类型需要与self构成互相推导关系,shape需要与self满足broadcast关系。 | ||
| 66 | + * 支持非连续的Tensor,数据格式支持ND,且数据格式需要与self一致。 | ||
| 67 | + * @param [in] alpha: host侧的aclScalar,数据类型需要可转换成self与other推导后的数据类型。 | ||
| 68 | + * device侧的aclTensor,数据类型支持整型,浮点类型,且数据类型需要是self与other推导之后可转换的数据类型,shape需要是self与other | ||
| 69 | + * broadcast之后的shape,数据格式支持ND,且数据格式需要与self一致。 | ||
| 70 | + * @param [out] workspaceSize: 返回用户需要在npu device侧申请的workspace大小。 | ||
| 71 | + * @param [out] executor: 返回op执行器,包含算子计算流程。 | ||
| 72 | + * @return aclnnStatus: 返回状态码。 | ||
| 73 | + */ | ||
| 74 | +ACLNN_API aclnnStatus aclnnInplaceAddReluGetWorkspaceSize(aclTensor* selfRef, const aclTensor* other, aclScalar* alpha, | ||
| 75 | + uint64_t* workspaceSize, aclOpExecutor** executor); | ||
| 76 | + | ||
| 77 | +/** | ||
| 78 | + * @brief aclnnAdd的第二段接口,用于执行计算。 | ||
| 79 | + * | ||
| 80 | + * @param [in] workspace: 在npu device侧申请的workspace内存起址。 | ||
| 81 | + * @param [in] workspace_size: 在npu device侧申请的workspace大小,由第一段接口aclnnAddGetWorkspaceSize获取。 | ||
| 82 | + * @param [in] executor: op执行器,包含了算子计算流程。 | ||
| 83 | + * @param [in] stream: acl stream流。 | ||
| 84 | + * @return aclnnStatus: 返回状态码。 | ||
| 85 | + */ | ||
| 86 | +ACLNN_API aclnnStatus aclnnInplaceAddRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, | ||
| 87 | + aclrtStream stream); | ||
| 88 | + | ||
| 89 | +#ifdef __cplusplus | ||
| 90 | +} | ||
| 91 | +#endif | ||
| 92 | + | ||
| 93 | +#endif // OP_API_INC_ADD_RELU_H_ | ||
| @@ -0,0 +1,157 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include "aclnn_relu.h" | ||
| 12 | +#include "aclnn_kernels/common/op_error_check.h" | ||
| 13 | +#include "aclnn_kernels/contiguous.h" | ||
| 14 | +#include "op_api/aclnn_util.h" | ||
| 15 | +#include "opdev/make_op_executor.h" | ||
| 16 | +#include "opdev/op_dfx.h" | ||
| 17 | +#include "opdev/op_executor.h" | ||
| 18 | +#include "relu_v2.h" | ||
| 19 | + | ||
| 20 | +using namespace op; | ||
| 21 | + | ||
| 22 | +#ifdef __cplusplus | ||
| 23 | +extern "C" { | ||
| 24 | +#endif | ||
| 25 | + | ||
| 26 | +constexpr size_t MAX_DIM_LEN = 8; | ||
| 27 | + | ||
| 28 | +static const std::initializer_list<op::DataType> ASCEND910_DTYPE_SUPPORT_LIST = { | ||
| 29 | + op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_INT8, op::DataType::DT_UINT8, | ||
| 30 | + op::DataType::DT_INT16, op::DataType::DT_INT32, op::DataType::DT_INT64}; | ||
| 31 | +static const std::initializer_list<op::DataType> ASCEND910B_DTYPE_SUPPORT_LIST = { | ||
| 32 | + op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_BF16, op::DataType::DT_INT8, | ||
| 33 | + op::DataType::DT_UINT8, op::DataType::DT_INT16, op::DataType::DT_INT32, op::DataType::DT_INT64}; | ||
| 34 | + | ||
| 35 | +static inline const std::initializer_list<op::DataType>& GetDtypeSupportList() | ||
| 36 | +{ | ||
| 37 | + if (GetCurrentPlatformInfo().GetSocVersion() >= SocVersion::ASCEND910B && | ||
| 38 | + GetCurrentPlatformInfo().GetSocVersion() <= SocVersion::ASCEND910E) { | ||
| 39 | + return ASCEND910B_DTYPE_SUPPORT_LIST; | ||
| 40 | + } | ||
| 41 | + if (Ops::NN::AclnnUtil::IsRegbase()) { | ||
| 42 | + return ASCEND910B_DTYPE_SUPPORT_LIST; | ||
| 43 | + } | ||
| 44 | + return ASCEND910_DTYPE_SUPPORT_LIST; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +static bool CheckNotNull(const aclTensor* self, const aclTensor* out) | ||
| 48 | +{ | ||
| 49 | + OP_CHECK_NULL(self, return false); | ||
| 50 | + OP_CHECK_NULL(out, return false); | ||
| 51 | + return true; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +static bool CheckDtypeValid(const aclTensor* self, const aclTensor* out) | ||
| 55 | +{ | ||
| 56 | + auto supportList = GetDtypeSupportList(); | ||
| 57 | + OP_CHECK_DTYPE_NOT_SUPPORT(self, supportList, return false); | ||
| 58 | + OP_CHECK_DTYPE_NOT_SUPPORT(out, supportList, return false); | ||
| 59 | + OP_CHECK_DTYPE_NOT_MATCH(self, out->GetDataType(), return false); | ||
| 60 | + return true; | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +static bool CheckShape(const aclTensor* self, const aclTensor* out) | ||
| 64 | +{ | ||
| 65 | + OP_CHECK_SHAPE_NOT_EQUAL(self, out, return false); | ||
| 66 | + OP_CHECK_MAX_DIM(self, MAX_DIM_LEN, return false); | ||
| 67 | + OP_CHECK_MAX_DIM(out, MAX_DIM_LEN, return false); | ||
| 68 | + return true; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +static aclnnStatus CheckParams(const aclTensor* self, const aclTensor* out) | ||
| 72 | +{ | ||
| 73 | + CHECK_RET(CheckNotNull(self, out), ACLNN_ERR_PARAM_NULLPTR); | ||
| 74 | + CHECK_RET(CheckDtypeValid(self, out), ACLNN_ERR_PARAM_INVALID); | ||
| 75 | + CHECK_RET(CheckShape(self, out), ACLNN_ERR_PARAM_INVALID); | ||
| 76 | + return ACLNN_SUCCESS; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +static aclnnStatus CheckInplaceParams(const aclTensor* self) | ||
| 80 | +{ | ||
| 81 | + OP_CHECK_NULL(self, return ACLNN_ERR_PARAM_NULLPTR); | ||
| 82 | + auto supportList = GetDtypeSupportList(); | ||
| 83 | + OP_CHECK_DTYPE_NOT_SUPPORT(self, supportList, return ACLNN_ERR_PARAM_INVALID); | ||
| 84 | + OP_CHECK_MAX_DIM(self, MAX_DIM_LEN, return ACLNN_ERR_PARAM_INVALID); | ||
| 85 | + return ACLNN_SUCCESS; | ||
| 86 | +} | ||
| 87 | + | ||
| 88 | +static aclnnStatus ExecReluGetWorkspaceSize(const aclTensor* self, const aclTensor* out, uint64_t* workspaceSize, | ||
| 89 | + aclOpExecutor** executor) | ||
| 90 | +{ | ||
| 91 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 92 | + CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR); | ||
| 93 | + | ||
| 94 | + auto ret = CheckParams(self, out); | ||
| 95 | + CHECK_RET(ret == ACLNN_SUCCESS, ret); | ||
| 96 | + | ||
| 97 | + if (self->IsEmpty()) { | ||
| 98 | + *workspaceSize = 0; | ||
| 99 | + uniqueExecutor.ReleaseTo(executor); | ||
| 100 | + return ACLNN_SUCCESS; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + auto selfContiguous = l0op::Contiguous(self, uniqueExecutor.get()); | ||
| 104 | + CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 105 | + | ||
| 106 | + // UINT8 全为非负数,ReLU 等价于恒等变换,不需走 relu 计算(kernel 也不支持 uint8), | ||
| 107 | + // 直接 ViewCopy 输出即可。 | ||
| 108 | + const aclTensor* reluOpOut = nullptr; | ||
| 109 | + if (selfContiguous->GetDataType() == op::DataType::DT_UINT8) { | ||
| 110 | + reluOpOut = selfContiguous; | ||
| 111 | + } else { | ||
| 112 | + reluOpOut = l0op::ReluV2(selfContiguous, uniqueExecutor.get()); | ||
| 113 | + } | ||
| 114 | + CHECK_RET(reluOpOut != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 115 | + | ||
| 116 | + auto viewCopyResult = l0op::ViewCopy(reluOpOut, out, uniqueExecutor.get()); | ||
| 117 | + CHECK_RET(viewCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 118 | + | ||
| 119 | + *workspaceSize = uniqueExecutor->GetWorkspaceSize(); | ||
| 120 | + uniqueExecutor.ReleaseTo(executor); | ||
| 121 | + return ACLNN_SUCCESS; | ||
| 122 | +} | ||
| 123 | + | ||
| 124 | +aclnnStatus aclnnReluGetWorkspaceSize(const aclTensor* self, const aclTensor* out, uint64_t* workspaceSize, | ||
| 125 | + aclOpExecutor** executor) | ||
| 126 | +{ | ||
| 127 | + OP_CHECK_COMM_INPUT(workspaceSize, executor); | ||
| 128 | + L2_DFX_PHASE_1(aclnnRelu, DFX_IN(self), DFX_OUT(out)); | ||
| 129 | + return ExecReluGetWorkspaceSize(self, out, workspaceSize, executor); | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +aclnnStatus aclnnInplaceReluGetWorkspaceSize(aclTensor* selfRef, uint64_t* workspaceSize, aclOpExecutor** executor) | ||
| 133 | +{ | ||
| 134 | + OP_CHECK_COMM_INPUT(workspaceSize, executor); | ||
| 135 | + L2_DFX_PHASE_1(aclnnInplaceRelu, DFX_IN(selfRef), DFX_OUT(selfRef)); | ||
| 136 | + | ||
| 137 | + auto ret = CheckInplaceParams(selfRef); | ||
| 138 | + CHECK_RET(ret == ACLNN_SUCCESS, ret); | ||
| 139 | + | ||
| 140 | + return ExecReluGetWorkspaceSize(selfRef, selfRef, workspaceSize, executor); | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +aclnnStatus aclnnRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, const aclrtStream stream) | ||
| 144 | +{ | ||
| 145 | + L2_DFX_PHASE_2(aclnnRelu); | ||
| 146 | + return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +aclnnStatus aclnnInplaceRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, const aclrtStream stream) | ||
| 150 | +{ | ||
| 151 | + L2_DFX_PHASE_2(aclnnInplaceRelu); | ||
| 152 | + return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | +#ifdef __cplusplus | ||
| 156 | +} | ||
| 157 | +#endif | ||
| @@ -0,0 +1,37 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#ifndef ACLNN_RELU_H_ | ||
| 12 | +#define ACLNN_RELU_H_ | ||
| 13 | + | ||
| 14 | +#include "aclnn/aclnn_base.h" | ||
| 15 | +#include "aclnn_util.h" | ||
| 16 | + | ||
| 17 | +#ifdef __cplusplus | ||
| 18 | +extern "C" { | ||
| 19 | +#endif | ||
| 20 | + | ||
| 21 | +ACLNN_API aclnnStatus aclnnReluGetWorkspaceSize(const aclTensor* self, const aclTensor* out, uint64_t* workspaceSize, | ||
| 22 | + aclOpExecutor** executor); | ||
| 23 | + | ||
| 24 | +ACLNN_API aclnnStatus aclnnRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, | ||
| 25 | + const aclrtStream stream); | ||
| 26 | + | ||
| 27 | +ACLNN_API aclnnStatus aclnnInplaceReluGetWorkspaceSize(aclTensor* selfRef, uint64_t* workspaceSize, | ||
| 28 | + aclOpExecutor** executor); | ||
| 29 | + | ||
| 30 | +ACLNN_API aclnnStatus aclnnInplaceRelu(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, | ||
| 31 | + const aclrtStream stream); | ||
| 32 | + | ||
| 33 | +#ifdef __cplusplus | ||
| 34 | +} | ||
| 35 | +#endif | ||
| 36 | + | ||
| 37 | +#endif | ||
| @@ -0,0 +1,37 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include "relu_v2.h" | ||
| 12 | +#include "aclnn_kernels/common/op_error_check.h" | ||
| 13 | +#include "opdev/make_op_executor.h" | ||
| 14 | +#include "opdev/op_def.h" | ||
| 15 | +#include "opdev/op_dfx.h" | ||
| 16 | +#include "opdev/op_executor.h" | ||
| 17 | +#include "opdev/op_log.h" | ||
| 18 | + | ||
| 19 | +using namespace op; | ||
| 20 | + | ||
| 21 | +namespace l0op { | ||
| 22 | + | ||
| 23 | +OP_TYPE_REGISTER(ReluV2); | ||
| 24 | + | ||
| 25 | +const aclTensor* ReluV2(const aclTensor* self, aclOpExecutor* executor) | ||
| 26 | +{ | ||
| 27 | + L0_DFX(ReluV2, self); | ||
| 28 | + auto reluOut = executor->AllocTensor(self->GetStorageShape(), self->GetDataType(), self->GetStorageFormat()); | ||
| 29 | + CHECK_RET(reluOut != nullptr, nullptr); | ||
| 30 | + | ||
| 31 | + auto ret = ADD_TO_LAUNCHER_LIST_AICORE(ReluV2, OP_INPUT(self), OP_OUTPUT(reluOut)); | ||
| 32 | + OP_CHECK(ret == ACLNN_SUCCESS, OP_LOGE(ACLNN_ERR_INNER_NULLPTR, "ReluV2 ADD_TO_LAUNCHER_LIST_AICORE failed."), | ||
| 33 | + return nullptr); | ||
| 34 | + return reluOut; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +} // namespace l0op | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#ifndef OP_API_OP_API_COMMON_INC_LEVEL0_OP_RELU_V2_H_ | ||
| 12 | +#define OP_API_OP_API_COMMON_INC_LEVEL0_OP_RELU_V2_H_ | ||
| 13 | + | ||
| 14 | +#include "opdev/make_op_executor.h" | ||
| 15 | +#include "opdev/op_executor.h" | ||
| 16 | + | ||
| 17 | +namespace l0op { | ||
| 18 | +const aclTensor* ReluV2(const aclTensor* self, aclOpExecutor* executor); | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +#endif | ||
| @@ -8,4 +8,5 @@ | |||
| 8 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ---------------------------------------------------------------------------- | 9 | # ---------------------------------------------------------------------------- |
| 10 | 10 | ||
| 11 | -add_graph_plugin_sources() | 11 | +message(STATUS "=== Debug: start ops.activation.relu.graph_plugin.CMakeLists.txt ") |
| 12 | +add_graph_plugin_sources() | ||
| @@ -1,48 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * This file is part of the OpenBOAT project at Harbin Institute of Technology (HIT) | ||
| 3 | - * and is contributed to the CANN Open Software. | ||
| 4 | - * | ||
| 5 | - * Copyright (c) 2025 AISS Group, Harbin Institute of Technology (HIT). | ||
| 6 | - * All Rights Reserved. | ||
| 7 | - * | ||
| 8 | - * Authors (accounts): | ||
| 9 | - | ||
| 10 | - * - Tu Yuanhang <@TuYHAAAAAA> | ||
| 11 | - * - Su Tonghua <@sutonghua> | ||
| 12 | - * | ||
| 13 | - * This program is free software: you can redistribute it and/or modify it. | ||
| 14 | - * Licensed under the CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 15 | - * You may not use this file except in compliance with the License. | ||
| 16 | - * See the LICENSE file at the root of the repository for the full text of the License. | ||
| 17 | - * | ||
| 18 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, | ||
| 19 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 20 | - */ | ||
| 21 | - | ||
| 22 | -/*! | ||
| 23 | - * \file relu_v2_graph_infer.cpp | ||
| 24 | - * \brief relu_v2 operater graph infer resource | ||
| 25 | - */ | ||
| 26 | -#include "register/op_impl_registry.h" | ||
| 27 | -#include "log/log.h" | ||
| 28 | - | ||
| 29 | -namespace ops { | ||
| 30 | -using namespace ge; | ||
| 31 | - | ||
| 32 | -static constexpr int64_t IDX_0 = 0; | ||
| 33 | - | ||
| 34 | -static ge::graphStatus InferDataTypeReluV2(gert::InferDataTypeContext* context) | ||
| 35 | -{ | ||
| 36 | - OP_LOGD(context->GetNodeName(), "Begin to do InferDataTypeReluV2"); | ||
| 37 | - | ||
| 38 | - // 设置输出的dtype Relu算子逻辑是一个数和0求最大值 | ||
| 39 | - ge::DataType sizeDtype = context->GetInputDataType(IDX_0); | ||
| 40 | - context->SetOutputDataType(IDX_0, sizeDtype); | ||
| 41 | - | ||
| 42 | - OP_LOGD(context->GetNodeName(), "End to do InferDataTypeReluV2"); | ||
| 43 | - return GRAPH_SUCCESS; | ||
| 44 | -} | ||
| 45 | - | ||
| 46 | -IMPL_OP(ReluV2).InferDataType(InferDataTypeReluV2); | ||
| 47 | - | ||
| 48 | -}; // namespace ops | ||
Rexperimental/activation/relu_v2/op_graph/fusion_pass/CMakeLists.txt→experimental/activation/relu_v2/tests/CMakeLists.txt+13-6
Rexperimental/activation/relu_v2/op_host/CMakeLists.txt→experimental/activation/relu_v2/tests/ut/op_api/CMakeLists.txt+10-8
此空文件需要删除