diff --git a/atvc/README.md b/atvc/README.md
index 854dd6e79268b6a29ee4b18cbb36937bd9dfa8b8..93037269b547bca59c105af9fc743ca5881e8bc3 100644
--- a/atvc/README.md
+++ b/atvc/README.md
@@ -1,35 +1,35 @@
# ATVC
-ATVC(AscendC Template for Vector Compute)是一个用AscendC API搭建的C++模板头文件集合,旨在帮助用户快速开发AscendC典型Vector算子。它将AscendC Vector算子开发流程中的计算实现解耦成可自定义的模块, 内部封装实现了kernel数据搬入搬出等底层通用操作及通用tiling计算,实现了高效的算子开发模式。
-相比传统AscendC算子开发方式,利用ATVC搭建的Vector算子可做到开发效率提升3-5倍。用户只需选择匹配的模板并完成核心计算逻辑就完成算子kernel侧开发,atvc还内置了每个模板库对应的通用tiling计算实现,可省去用户手写tiling的开发量就能达到不错的性能表现,极大提升算子开发效率。
+ATVC(Ascend C Template for Vector Compute)是一个用Ascend C API搭建的C++模板头文件集合,旨在帮助用户快速开发Ascend C典型Vector算子。它将Ascend C Vector算子开发流程中的计算实现解耦成可自定义的模块, 内部封装实现了kernel数据搬入搬出等底层通用操作及通用tiling计算,实现了高效的算子开发模式。
+相比传统Ascend C算子开发方式,利用ATVC搭建的Vector算子可做到开发效率提升3-5倍。用户只需选择匹配的模板并完成核心计算逻辑就完成算子kernel侧开发,atvc还内置了每个模板库对应的通用tiling计算实现,可省去用户手写tiling的开发量就能达到不错的性能表现,极大提升算子开发效率。
-
+
-请参阅[快速入门](./docs/1_quick_start.md)以快速了解ATVC的Add算子搭建流程。
-请参阅[开发者文档](./docs/2_developer_guide.md)以获取ATVC框架各模板与API的使用细节,完成自定义EleWise类算子以及Reduce类算子开发。
+请参阅[快速入门](./docs/01_quick_start.md)以快速了解ATVC的Add算子搭建流程。
+请参阅[开发者文档](./docs/02_developer_guide.md)以获取ATVC框架各模板与API的使用细节,完成自定义Elementwise类算子以及Reduce类算子开发。
# 环境要求
- 硬件型号支持
-Atlas 800I A2推理服务器/Atlas A2训练服务器
+Atlas 800I A2推理服务器
- 配套软件
CANN开发套件包Ascend-cann-toolkit\_\\_linux\-\.run,并设置相关环境变量
cmake >= 3.16.0
# 工程目录
-ATVC工程结构可归纳成以下主要组件,更详细的文件结构介绍请参阅[Code Organization](./docs/code_organization.md):
+ATVC工程结构可归纳成以下主要组件,更详细的文件结构介绍请参阅[Code Organization](./docs/03_code_organization.md):
```
├── docs // 文档介绍
-├── examples // ATVC使用样例
-├── include // ATVC提供的头文件集合,用户使用前需将其置入其他工程的包含路径下
+├── examples // ATVC使用样例
+├── include // ATVC提供的头文件集合,用户使用前需将其置入其他工程的包含路径下
├── tests // 测试模块相关代码
-└── ReadME.md // overview
+└── README.md // 综述
```
# 快速上手
-快速执行example用例,更详细的流程请参阅[快速入门](./docs/1_quick_start.md)。
+快速执行example用例,更详细的流程请参阅[快速入门](./docs/01_quick_start.md)。
- 下载ATVC代码
```bash
@@ -68,21 +68,22 @@ Accuracy verification passed.
# 已支持的模版
| Vector模版类型 |
| ------------------------------------------------------------ |
-| Ele-wise模板 |
+| Elementwise模板 |
| Reduce模板 |
| Broadcast模板 |
# 样例介绍
| 样例名 | 描述 | 类型|
| ------------------------------------------------------------ | ------------------------------------------------------------ |------------------------------------------------------------ |
-| [add](./examples/add/add.cpp) | 使用ATVC的Ele-wise模板实现Add算子以及调用样例 | 直调算子 |
-| [sinh_custom](./examples/sinh_custom/sinh_custom.cpp) | 临时Tensor参与计算的自定义Ele-wise类算子以及调用样例 | 直调算子 |
-| [add_with_scalar](./examples/add_with_scalar/add_with_scalar.cpp) | 输入带标量的自定义Ele-wise类算子以及调用样例 | 直调算子 |
+| [add](./examples/add/add.cpp) | 使用ATVC的Elementwise模板实现Add算子以及调用样例 | 直调算子 |
+| [sinh_custom](./examples/sinh_custom/sinh_custom.cpp) | 临时Tensor参与计算的自定义Elementwise类算子以及调用样例 | 直调算子 |
+| [add_with_scalar](./examples/add_with_scalar/add_with_scalar.cpp) | 输入带标量的自定义Elementwise类算子以及调用样例 | 直调算子 |
| [reduce_sum](./examples/reduce_sum/reduce_sum.cpp) | 使用ATVC的Reduce模板实现自定义ReduceSum算子以及调用样例 | 直调算子 |
| [broadcast_to](./examples/broadcast_to/broadcast_to.cpp) | 使用ATVC的Broadcast模板实现自定义BroadcastTo算子以及调用样例 | 直调算子 |
-| [ops_aclnn](./examples/aclnn) | 使用ATVC基于自定义工程算子的实现以及调用样例 | 自定义工程算子 |
-| [ops_pytorch](./examples/pytorch) | 使用ATVC基于[pytorch](https://gitee.com/ascend/pytorch)算子的实现以及调用样例 | pytorch算子 |
+| [tanh_grad](./examples/tanh_grad/tanh_grad.cpp) | 使用Tiling超参进行算子性能调优的ElementWise类算子调用样例 | 直调算子 |
+| [ops_aclnn](./examples/ops_aclnn) | 使用ATVC基于自定义工程算子的实现以及调用样例 | 自定义工程算子 |
+| [ops_pytorch](./examples/ops_pytorch) | 使用ATVC基于[pytorch](https://gitee.com/ascend/pytorch)算子的实现以及调用样例 | pytorch算子 |
-更多算子类型介绍和如何选取模板参见参阅[快速入门](./docs/1_quick_start.md),其中add、sinh_custom、add_with_scalar、reduce_sum、broadcast_to是ATVC的直调样例,ops_aclnn为基于ATVC对接aclnn工程的算子目录,ops_pytorch为基于ATVC对接pytorch工程的算子目录。其中,ops_aclnn和ops_pytorch样例需要进入到example路径下按照README.md描述执行。
+更多算子类型介绍和如何选取模板参见参阅[快速入门](./docs/1_quick_start.md),其中add、sinh_custom、add_with_scalar、reduce_sum、broadcast_to、tanh_grad是ATVC的直调样例,ops_aclnn为基于ATVC对接aclnn工程的算子目录,ops_pytorch为基于ATVC对接pytorch工程的算子目录。其中,ops_aclnn和ops_pytorch样例需要进入到example路径下按照README.md描述执行。
@@ -90,7 +91,7 @@ Accuracy verification passed.
| 算子模板 | 数据类型 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
-| Ele-wise | int32_t、float |
+| Elementwise | int32_t、float |
| Reduce | int32_t、float |
| Broadcast | int32_t、float |
diff --git a/atvc/docs/1_quick_start.md b/atvc/docs/01_quick_start.md
similarity index 66%
rename from atvc/docs/1_quick_start.md
rename to atvc/docs/01_quick_start.md
index 3c5c469b49f1b6048ff53f5b6d4f9637a2273b22..51c24a860f7cf3a2edd3113d526045d6843be990 100644
--- a/atvc/docs/1_quick_start.md
+++ b/atvc/docs/01_quick_start.md
@@ -1,9 +1,8 @@
# 快速入门
这篇文档帮助你体验ATVC开发Add算子的整个流程。
-快速上手的完整代码请参阅[atvc/examples/add](../examples/add/add.cpp)。
# 环境要求
-ATVC 对软硬件运行环境有如下要求:
+ATVC对软硬件运行环境有如下要求:
- 硬件型号
Atlas 800I A2推理服务器
- 软件要求
@@ -33,17 +32,16 @@ git clone https://gitee.com/ascend/ascendc-api-adv.git
# 使用ATVC开发Add算子
-本示例将展示如何基于ATVC提供的模板以及接口快速搭建Add算子,示例内展示了ATVC框架下区别于传统AscendC Add的实现代码。
-
+本示例将展示如何基于ATVC提供的模板以及接口快速搭建Add算子,示例内展示了ATVC框架下区别于传统Ascend C Add的实现代码。
## 定义算子描述
首先通过ATVC提供的[ATVC::OpTraits](../include/common/atvc_opdef.h)模板结构体来描述Add算子的输入输出信息,定义如下:
```cpp
// Add算子中有两个输入,一个输出。类型均为float
-using ADD_OPTRAITS = ATVC::OpTraits, ATVC::OpOutputs>;
+using ADD_OPTRAITS = ATVC::OpTraits, ATVC::OpOutputs>;
```
## 实现算子计算逻辑
-用户需要通过AscendC API来搭建Add算子的核心计算逻辑,在ATVC框架中,这类算子的核心计算逻辑是通过定义一个结构体的仿函数来实现。它需要`ATVC::OpTraits`作为固定模板参数,并重载`operator()`来被提供的Kernel层算子模板类调用。
+用户需要通过Ascend C API来搭建Add算子的核心计算逻辑,在ATVC框架中,这类算子的核心计算逻辑是通过定义一个结构体的仿函数来实现。它需要`ATVC::OpTraits`作为固定模板参数,并重载`operator()`来被提供的Kernel层算子模板类调用。
Add算子的计算仿函数定义如下:
```cpp
#include "atvc.h" // 包含所有atvc模板api的总入口头文件
@@ -61,7 +59,7 @@ struct AddComputeFunc {
template
// 重载operator,提供给算子模板类调用
__aicore__ inline void operator()(AscendC::LocalTensor a, AscendC::LocalTensor b, AscendC::LocalTensor c) {
- AscendC::Add(c, a, b, c.GetSize()); // 开发调用AscendC Api自行实现计算逻辑, 通过c.GetSize()获取单次计算的元素数量
+ AscendC::Add(c, a, b, c.GetSize()); // 开发调用AscendC API自行实现计算逻辑, 通过c.GetSize()获取单次计算的元素数量
}
};
```
@@ -80,13 +78,13 @@ template
* a Device上的gm地址,指向Add算子第一个输入
* b Device上的gm地址,指向Add算子第二个输入
* c Device上的gm地址,指向Add算子第一个输出
- * param Device上的gm地址,指向运行态ATVC::EleWiseParam数据
+ * param 指向运行态ATVC::EleWiseParam数据
*/
-__global__ __aicore__ void AddCustom(GM_ADDR a, GM_ADDR b, GM_ADDR c, GM_ADDR param)
+__global__ __aicore__ void AddCustom(GM_ADDR a, GM_ADDR b, GM_ADDR c, ATVC::EleWiseParam param)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);
auto op = ATVC::Kernel::EleWiseOpTemplate>(); // 将AddComputeFunc仿函数作为模板参数传入,实例化EleWiseOpTemplate模板类
- op.Run(a, b, c, param); // 按照输入、输出、param的顺序传入Run函数,实现GM->GM的数据计算
+ op.Run(a, b, c, ¶m); // 按照输入、输出、param的顺序传入Run函数,实现GM->GM的数据计算
}
```
@@ -99,49 +97,48 @@ ATVC::ElewiseParam param;
// totalCnt描述EleWise单输入的元素个数
int32_t totalCnt = 1024;
// ADD_OPTRAITS为ADD算子描述原型,根据算子输入输出个数和实际元素数量计算出Tiling数据后填入param中
-if (!ATVC::Host::CalcEleWiseTiling(eleNum, param)) {
+if (!ATVC::Host::CalcEleWiseTiling(totalCnt, param)) {
printf("Elewise tiling error.\n");
return -1;
};
-//
-// 调用aclrtMemcpy接口拷贝Host侧数据到Device侧
-// aclrtMemcpy(paramDevice, sizeof(param), reinterpret_cast(¶m), sizeof(param), ACL_MEMCPY_HOST_TO_DEVICE)
-//
uint32_t blockNum = param.tilingData.blockNum;
// 调用核函数
+// aDevice Device上的gm地址,指向Add算子第一个输入
+// bDevice Device上的gm地址,指向Add算子第二个输入
+// cDevice Device上的gm地址,指向Add算子第一个输出
+// param Device上的gm地址,指向运行态ATVC::EleWiseParam数据
AddCustom<<>>(aDevice, bDevice, cDevice, paramDevice);
```
## 算子编译&执行
完成算子代码编写后,调用以下命令编译代码并执行:
```bash
-$ cd ./atvc/tests/
-$ bash run_test.sh add
-...
-Generate golden data successfully.
-...
-Accuracy verification passed.
+cd ./atvc/tests/
+bash run_test.sh add
```
其他样例执行命令如下:
```bash
-$ bash run_test.sh sinh_custom # 执行sinh_custom样例
-$ bash run_test.sh reduce_sum # 执行reduce_sum样例
-$ bash run_test.sh add_with_scalar # 执行add_with_scalar样例
-$ bash run_test.sh broadcast_to # 执行broadcast样例
+bash run_test.sh sinh_custom # 执行sinh_custom样例
+bash run_test.sh reduce_sum # 执行reduce_sum样例
+bash run_test.sh add_with_scalar # 执行add_with_scalar样例
+bash run_test.sh broadcast_to # 执行broadcast样例
```
## 完整样例
完整代码样例请参照[examples/add/add.cpp](../examples/add/add.cpp)
# 模板选择
-用户根据待开发的Vector算子定义特征,选择匹配的模板及其配套的tiling算法,若自定义算子不在当前模板库的范围内,建议使用基本AscnedC API 手写算子。
-## Ele-wise类算子
-Ele-wise类算子通常是指对张量进行元素级别的操作的函数或方法,包括但不限于加、减、乘、除及指数、对数、三角函数等数学函数。这类算子的特点是会逐元素进行计算操作,而不会改变输入数据的形状。常见的ELe-wise算子有Add、Sub、Exp、Log、Sin、Sqrt等。
+用户根据待开发的Vector算子定义特征,选择以下三种匹配的模板及其配套的tiling算法,若自定义算子不在当前模板库的范围内,建议使用基本Ascend C API 手写算子。
+## Elementwise类算子
+Elementwise类算子通常是指对张量进行元素级别的操作的函数或方法,包括但不限于加、减、乘、除及指数、对数、三角函数等数学函数。这类算子的特点是会逐元素进行计算操作,而不会改变输入数据的形状。常见的Elementwise算子有Add、Sub、Exp、Log、Sin、Sqrt等。
## Reduce类算子
Reduce类算子通常是指对张量中的元素进行归约操作的算子,通常用来求和、求平均值等操作,可指定某几个维度进行归约计算,也可以将所有元素归约计算为一个标量。常见的Reduce类算子有ReduceSum(求和)、ReduceMean(求平均值)、ReduceProdcut(累乘)、ReduceMax(求最大值)、ReduceMin(求最小值)、ReduceAny(or操作)、ReduceAll(and操作)。
## Broadcast
-Broadcast算子是指完成广播操作,用于处理不同形状的张量间的运算。
-例如tensorA的shape是(1,5),tensorB的shape是(3,5),若要实现tensorC = tensorA + tensorB,实际上需要将TensorA广播为shape(3,5),再进行tensorA和tensorB的相加操作。广播的过程,实际上就是将原数据在某个维度上进行复制扩展。
+Broadcast 算子用于在张量形状不一致时实现张量间的逐元素运算。
+设张量 A 的 shape 为 (1, 5),张量 B 的 shape 为 (3, 5)。为完成 C = A + B,首先需依据广播规则将 A 由 (1, 5) 扩展至 (3, 5)。该过程通过在长度为 1 的维度上复制数据,使两个张量的形状对齐,从而支持逐元素相加运算。
+
+# Copyright
+Copyright (c) 2025 Huawei Technologies Co., Ltd.
\ No newline at end of file
diff --git a/atvc/docs/2_developer_guide.md b/atvc/docs/02_developer_guide.md
similarity index 72%
rename from atvc/docs/2_developer_guide.md
rename to atvc/docs/02_developer_guide.md
index c236bd991ca57a6d0eeb9c3dbf3ac16bb9aa81c3..e494ebad5e79cb59f229104ded1df5ace0d121da 100644
--- a/atvc/docs/2_developer_guide.md
+++ b/atvc/docs/02_developer_guide.md
@@ -1,20 +1,20 @@
# 1 架构设计
ATVC将Vector算子开发流程中的可定制化模块抽象出了Host层和Kernel层,它们的基本概念如下:
-- Host层:在CPU Host侧执行,提供Tiling计算&策略分派的API,它根据实际数据场景帮助用户计算出较优的数据搬运等运行态参数
-- Kernel层:它是利用AscendC API搭建出的一系列Vector算子模板类,屏蔽了算子开发中用户无需感知的数据搬入搬出以及资源申请等固定模块,并将核心计算模块开放给用户定义。
+- Host层:在CPU Host侧执行,提供Tiling计算&策略分派的API,它根据实际数据场景帮助用户计算出较优的数据搬运等运行态参数。
+- Kernel层:它是利用Ascend C API搭建出的一系列Vector算子模板类,屏蔽了算子开发中用户无需感知的数据搬入搬出以及资源申请等固定模块,并将核心计算模块开放给用户定义。
-
+
基于如上分层结构,ATVC中一个核函数的实现与调用的关系如下图所示(ATVC框架提供的模板及接口用黄色表示;支持开发自定义的模块用蓝色表示):
-
+
## 1.1 公共数据结构
-我们将对ATVC核函数定义以及调用涉及的三个公共数据概念:算子原型的编译态参数`OpTraits`, Tiling计算的运行态参数`Param`, 模板策略的编译态参数`Policy` 分别进行介绍:
+我们将对ATVC核函数定义以及调用涉及的三个公共数据概念:算子原型的编译态参数`OpTraits`, Tiling计算的运行态参数`Param`, 模板策略的编译态参数`Policy` 分别进行介绍。
### 1.1.1 OpTraits
-ATVC框架参考C++模板元编程的`stl::type_list`实现,推出了`ATVC::OpInputs`、`ATVC::OpOutputs`、`ATVC::OpTemps`的模板结构体分别用于描述算子的计算输入、计算输出、计算过程的临时资源,支持C++基础类型作为不定长模板参数传入。它们三者组成了覆盖了整个ATVC框架编译态参数`OpTraits`。`ATVC::OpTraits`的完整数据定义如下
+ATVC框架参考C++模板元编程的`type_list`实现,推出了`ATVC::OpInputs`、`ATVC::OpOutputs`、`ATVC::OpTemps`的模板结构体分别用于描述算子的计算输入、计算输出、计算过程的临时资源,支持C++基础类型作为不定长模板参数传入。它们三者组成了整个ATVC框架编译态参数`OpTraits`。`ATVC::OpTraits`的完整数据定义如下
```cpp
// atvc_opdef.h
namespace ATVC {
@@ -25,23 +25,23 @@ enum class ParamType {
TEMP, // 临时计算资源
};
-template
+template
struct ParamTypes{
using types = ATVC::TypeList;
static constexpr ParamType usage = paramType_;
};
-template
+template
using OpInputs = ParamTypes;
-template
+template
using OpOutputs = ParamTypes;
-template
+template
using OpTemps = ParamTypes;
// OpTraits的结构体定义,TempTypeList默认为空
-template>
+template >
struct OpTraits {
using In = InTypeList;
using Out = OutTypeList;
@@ -64,7 +64,7 @@ using AddOpTraits = ATVC::OpTraits; // Add算
### 1.1.2 Param
ATVC框架提供了`ATVC::EleWiseParam`、`ATVC::ReduceParam`、`ATVC::BroadcastParam` 三个结构体来描述算子内部调度的Tiling数据和其他资源变量。Param 作为Host侧Tiling API的输出,它将传入ATVC框架的Kernel层算子模板,并在运行时指导算子内部模块完成数据的循环搬运与调度计算。
-以下为ElementWise类算子的`ATVC::EleWiseParam`参与计算的伪代码,详细使用流程请参考本文档的 2.1.5 Host层API:
+以下为ElementWise类算子的`ATVC::EleWiseParam`参与计算的伪代码,详细使用流程请参考本文档的 [2.1.5 Host层API](#215-host层api):
```cpp
// 声明运行态参数param
ATVC::ElewiseParam param;
@@ -93,48 +93,48 @@ ATVC::Host::CalcReduceTiling(..., &policy, ¶m);
// ReduceAdapter根据policy具体值将动态参数转为静态模板参数,并传入核函数
if (policy.patternId == 1 && policy.loopCnt == 2 && policy.loopInnerCnt == 3) {
- constexpr ATVC::ReducePolicy selectedPolicy = {1, 2, 3};
+ constexpr ATVC::ReducePolicy selectedPolicy = {1, 2, 3};
ReduceKernel<<<...>>>(...);
}
// 自定义的ReduceKernel核函数内部调用了ReduceOpTemplate算子模板类, 该模板类内部实现了Policy对应的各种计算场景
-template
-__global__ __aicore__ ReduceKernel(GM_ADDR x, GM_ADDR y, GM_ADDR paramDevice) {
+template
+__global__ __aicore__ ReduceKernel(GM_ADDR x, GM_ADDR y, ATVC::ReduceParam param) {
auto op = ATVC::Kernel::ReduceOpTemplate(); // 实例化算子Kernel模板, Policy作为模板参数传入
- op.Run(x, y, paramDevice); // param作为运行态参数传入
+ op.Run(x, y, ¶m); // param作为运行态参数传入
}
```
# 2 利用ATVC完成算子开发
-## 2.1 element-wise算子开发
-ATVC框架提供的element-wise算子模块之间的交互如下(ATVC框架提供的模板及接口用黄色表示;开发自定义的模块用蓝色表示):
-
+## 2.1 Elementwise算子开发
+ATVC框架提供的Elementwise算子模块之间的交互如下(ATVC框架提供的模板及接口用黄色表示;开发自定义的模块用蓝色表示):
+
-不同计算原理的element-wise算子在Kernel内部的数据搬运模块并无区别,因此EleWise的数据交互不涉及Policy的不同Kernel模板实现。
+不同计算原理的Elementwise算子在Kernel内部的数据搬运模块并无区别,因此Elementwise的数据交互不涉及Policy的不同Kernel模板实现。
### 2.1.1 Components
-根据element-wise算子在框架内部的交互场景,ATVC提供如下的接口以及模板类帮助开发搭建自定义AscendC的ElementWise算子:
-
-自定义element-wise算子需按照以下顺序完成模块之间的组装:
+根据Elementwise算子在框架内部的交互场景,ATVC提供如下的接口以及模板类帮助开发搭建自定义Ascend C的ElementWise算子:
+
+自定义Elementwise算子需按照以下顺序完成模块之间的组装:
1. 定义计算模板
-2. 将计算模板类传入`Kernel`层算子模板完成核函数功能实现;
+2. 将计算模板类传入Kernel层算子模板完成核函数功能实现;
3. 定义Kernel层算子入口API,内部实例化计算模板类;
-下面将以Sinh算子 $y = \frac{\exp(x) - \exp(-x)}{2}$ 的实现为样例,按照组成Kernel的顺序介绍element-wise算子开发的流程。
+下面将以Sinh算子 $y = \frac{\exp(x) - \exp(-x)}{2}$ 的实现为样例,按照组成Kernel的顺序介绍Elementwise算子开发的流程。
### 2.1.2 计算模板
-计算模板是用户必须在element-wise 算子实现过程中完成的一类特殊模板类的定义。模板类无需关注数据如何从GM搬运到UB,只需重载`operator()`的公有接口,并在该仿函数内部实现AscendC::LocalTensor之间的计算逻辑。在Kernel层的组装阶段,计算模板将作为模板参数传入`ATVC::Kernel::EleWiseOpTemplate`,并在数据计算阶段被调用。下方为计算模板实现Sinh计算逻辑的代码样例:
+计算模板是用户必须在Elementwise 算子实现过程中完成的一类特殊模板类的定义。模板类无需关注数据如何从GM搬运到UB,只需重载`operator()`的公有接口,并在该仿函数内部实现`AscendC::LocalTensor`之间的计算逻辑。在Kernel层的组装阶段,计算模板将作为模板参数传入`ATVC::Kernel::EleWiseOpTemplate`,并在数据计算阶段被调用。下方为计算模板实现Sinh计算逻辑的代码样例:
```cpp
#include "atvc.h" // 包含所有模板及API的总入口头文件
// 传入编译态参数ATVC::OpTraits
-template
+template
// 开发自定义函数名/类名
struct SinhComputeFunc {
// DataType模板参数,根据实际数据类型个数填写
- template
+ template
// 重载operator公有接口,提供给Kernel::EleWiseOpTemplate调用
__aicore__ inline void operator()(AscendC::LocalTensor x, AscendC::LocalTensor y, AscendC::LocalTensor tempBuffer1, AscendC::LocalTensor tempBuffer2) {
// 开发调用AscendC API自行实现计算仿函数
@@ -153,10 +153,10 @@ struct SinhComputeFunc {
3. 开发定义的`operator()`仿函数的输入参数类型支持`AscendC::LocalTensor`以及C++其他基础数据类型。形式参数需按照`ATVC::OpInputs<>`,`ATVC::OpOutputs<>`, `ATVC::OpTemps<>`声明的顺序填入,其他标量参数放在最后,根据用户计算场景按需传入。
-### 2.1.3 内置EleWise算子模板
+### 2.1.3 内置Elementwise算子模板
`ATVC::Kernel::EleWiseOpTemplate`为ATVC框架提供的内置ElementWise基本算子类,它实现了一套算子数据的搬运搬出、资源分配和释放的算子流程。它需要计算模板类作为模板参数传入来完成实例化。核函数通过调用它完成整套计算逻辑:1. 资源初始化; 2.将数据从GM搬运至UB; 3.按`OpTraits`的输入、输出、临时资源描述、其他标量的顺序传入计算模板类的仿函数完成数据的基块计算; 4.将结果从UB搬出至GM。
-下方为`ATVC::Kernel::EleWiseOpTemplate`模板类的外部接口介绍,完整模板类定义请参考`atvc/include/elewise/elewise_op_template.h`。
+下方为`ATVC::Kernel::EleWiseOpTemplate`模板类的外部接口介绍,完整模板类定义请参考[`atvc/include/elewise/elewise_op_template.h`](../include/elewise/elewise_op_template.h)。
```cpp
// 开发定义的计算模板类
template
@@ -166,13 +166,13 @@ public:
// 按照输入、输出、EleWiseParam、其他标量的顺序传入
// 内部根据EleWiseParam进行数据调度并调用EleWiseOpTemplate完成计算后搬出到GM
- template
+ template
__aicore__ inline void Run(Args&&... args) {
//
// 完成变长参数的解析和数据调度计算
//
}
-}
+};
```
@@ -187,20 +187,20 @@ using SinhOpTraits = ATVC::OpTraits, ATVC::OpOutputs> elewiseTemplate;
// 调用EleWiseOpTemplate的Run接口传入输入x, 输出y,Host::CalcEleWiseTiling API的输出param
-elewiseTemplate.Run(x, y, param);
+elewiseTemplate.Run(x, y, ¶m);
}
```
### 2.1.4 核函数定义
-在element-wise开发流程中,用户需要自行定义核函数接口。核函数内部可依赖`ATVC::Kernel::EleWiseOpTemplate`完成功能实现。
+在Elementwise开发流程中,用户需要自行定义核函数接口。核函数内部可依赖`ATVC::Kernel::EleWiseOpTemplate`完成功能实现。
基于`2.1.2`和`2.1.3`的样例代码,Kernel层的自定义核函数代码样例如下:
```cpp
#include "atvc.h"
// 2.1.2 章节中的SinhComputeFunc 定义
-// template
+// template
// struct SinhComputeFunc {
// ...
// }
@@ -208,21 +208,21 @@ using SinhOpTraits = ATVC::OpTraits, ATVC::OpOutputs
-__global__ __aicore__ void SinhCustom(GM_ADDR x, GM_ADDR y, GM_ADDR param)
+template
+__global__ __aicore__ void SinhCustom(GM_ADDR x, GM_ADDR y, ATVC::EleWiseParam param)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); // 控制算子执行时只启动Vector核
auto op = ATVC::Kernel::EleWiseOpTemplate>();
- op.Run(x, y, param); // 按照输入、输出、param的顺序传入Run函数中;OpTraits内部的ATVC::OpTemps将由EleWiseOpTemplate内部申请资源,开发无需关注
+ op.Run(x, y, ¶m); // 按照输入、输出、param的顺序传入Run函数中;OpTraits内部的ATVC::OpTemps将由EleWiseOpTemplate内部申请资源,开发无需关注
}
```
-利用ATVC框架开发element-wise算子的过程中,Kernel层的核函数定义必须遵从以下约束:
+利用ATVC框架开发Elementwise算子的过程中,Kernel层的核函数定义必须遵从以下约束:
1. 核函数必须预留一个GM_ADDR类型的形参用于传入`ATVC::EleWiseParam`运行态参数;
2. 核函数内部必须加入`KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);`这段代码标注算子执行时只启动Vector核;
@@ -231,24 +231,24 @@ __global__ __aicore__ void SinhCustom(GM_ADDR x, GM_ADDR y, GM_ADDR param)
```cpp
using SinhOpTraits = ATVC::OpTraits, ATVC::OpOutputs, ATVC::OpTemps>;
-extern "C" __global__ __aicore__ void SinhCustom(GM_ADDR x, GM_ADDR y, GM_ADDR param)
+extern "C" __global__ __aicore__ void SinhCustom(GM_ADDR x, GM_ADDR y, ATVC::EleWiseParam param)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); // 控制算子执行时只启动Vector核
auto op = ATVC::Kernel::EleWiseOpTemplate>(); // 模板参数传入固定的SinhOpTraits
- op.Run(x, y, param);
+ op.Run(x, y, ¶m);
}
```
### 2.1.5 Host层API
-ATVC的Host层提供了element-wise算子的通用Tiling算法API `ATVC::Host::CalcEleWiseTiling`,它根据算子计算原型`ATVC::OpTraits`以及数据大小计算出包含`ATVC::EleWiseTilingData`的运行态参数`ATVC::EleWiseParam`。`ATVC::EleWiseParam`在运行时将参与模板算子数据搬运从而实现较优计算。
`ATVC::EleWiseTilingData`和`ATVC::EleWiseParam`的数据结构定义如下:
+ATVC的Host层提供了Elementwise算子的通用Tiling算法API `ATVC::Host::CalcEleWiseTiling`,它根据算子计算原型`ATVC::OpTraits`以及数据大小计算出包含`ATVC::EleWiseTilingData`的运行态参数`ATVC::EleWiseParam`。`ATVC::EleWiseParam`在运行时将参与模板算子数据搬运从而实现较优计算。
`ATVC::EleWiseTilingData`和`ATVC::EleWiseParam`的数据结构定义如下:
```cpp
namespace ATVC{
struct EleWiseTilingData {
uint32_t tailBlockCnt; // 需要额外执行一次循环的核的数量
- uint32_t tailElemCnt; // 尾块元素数量
- uint32_t numPerBlock; // 每个核需计算的总元素数量
- uint32_t tiledCnt; // 每次搬入搬出的元素个数
- uint32_t blockNum; // 执行核数
+ uint32_t tailElemCnt; // 尾块元素数量
+ uint32_t numPerBlock; // 每个核需计算的总元素数量
+ uint32_t tiledCnt; // 每次搬入搬出的元素个数
+ uint32_t blockNum; // 执行核数
};
struct EleWiseParam {
@@ -300,23 +300,15 @@ if (!ATVC::Host::CalcEleWiseTiling(eleNum, param)) {
通过ATVC框架实现的完整SinhCustom算子定义&调用[代码](../examples/sinh_custom/sinh_custom.cpp)如下:
```cpp
-/**
- * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
- *
- * This file is a part of the CANN Open Software.
- * Licensed under CANN Open Software License Agreement Version 1.0 (the "License").
- * Please refer to the License for details. You may not use this file except in compliance with the License.
- * 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.
- * See LICENSE in the root of the software repository for the full text of the License.
- */
-
#include
#include
#include
+#include
+#include
#include
#include "acl/acl.h"
-#include "atvc.h"
+#include "elewise/elewise_host.h"
+#include "elewise/elewise_device.h"
#define CHECK_ACL(x) \
do { \
@@ -331,12 +323,12 @@ static constexpr float REL_TOL = 1e-3f;
static constexpr float ABS_TOL = 1e-5f;
// 判断两个浮点数是否足够接近
-bool IsClose(float a, float b) {
+bool IsClose(float a, float b)
+{
const float eps = 1e-40f; // 防止分母为零
float diff = std::abs(a - b);
return (diff <= ABS_TOL) || (diff <= REL_TOL * std::max(std::abs(a), std::abs(b) + eps));
}
-}
// 描述算子的输入输出以及临时计算资源
using SinhOpTraits = ATVC::OpTraits, ATVC::OpOutputs, ATVC::OpTemps>;
@@ -348,30 +340,76 @@ struct SinhComputeFunc {
// DataType模板参数,根据实际数据类型个数填写
template
// 重载operator公有接口,提供给`ATVC::Kernel::EleWiseOpTemplate`调用
- __aicore__ inline void operator()(AscendC::LocalTensor x, AscendC::LocalTensor y, AscendC::LocalTensor tempBuffer1, AscendC::LocalTensor tempBuffer2) {
+ __aicore__ inline void operator()(AscendC::LocalTensor x,
+ AscendC::LocalTensor y,
+ AscendC::LocalTensor tempBuffer1,
+ AscendC::LocalTensor tempBuffer2)
+ {
// 开发调用AscendC Api自行实现计算仿函数
uint32_t tiledCnt = y.GetSize(); // 进行单次基块计算的元素个数
AscendC::Muls(tempBuffer1, x, static_cast(-1), tiledCnt); // tempBuffer1 = -1 * x
AscendC::Exp(tempBuffer1, tempBuffer1, tiledCnt); // tempbuffer1 = exp(-x)
AscendC::Exp(tempBuffer2, x, tiledCnt); // tempbuffer2 = exp(x)
AscendC::Sub(y, tempBuffer2, tempBuffer1, tiledCnt); // y = exp(x) - exp(-x)
- AscendC::Muls(y, y, static_cast(0.5), tiledCnt); // y = (e^(x) - e^(-x)) / 2
+ AscendC::Muls(y, y, static_cast(0.5), tiledCnt); // y = (e^(x) - e^(-x)) / 2
}
};
+void InitializeData(int32_t eleNum, std::vector &inputX, std::vector &golden)
+{
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_real_distribution dis(1.0f, 10.0f);
+
+ for (int i = 0; i < eleNum; ++i) {
+ inputX[i] = dis(gen);
+ golden[i] = std::sinh(inputX[i]);
+ }
+}
+
+bool VerifyResults(const std::vector &golden, const std::vector &output)
+{
+ for (int32_t i = 0; i < golden.size(); i++) {
+ if (!IsClose(golden[i], output[i])) {
+ printf("Accuracy verification failed! The expected value of element "
+ "in index [%d] is %f, but actual value is %f.\n",
+ i,
+ golden[i],
+ output[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+void InitializeACL(aclrtContext &context, aclrtStream &stream, int32_t deviceId)
+{
+ CHECK_ACL(aclInit(nullptr));
+ CHECK_ACL(aclrtSetDevice(deviceId));
+ CHECK_ACL(aclrtCreateContext(&context, deviceId));
+ CHECK_ACL(aclrtCreateStream(&stream));
+}
+
+void CleanACL(aclrtStream &stream, int32_t deviceId)
+{
+ CHECK_ACL(aclrtDestroyStream(stream));
+ CHECK_ACL(aclrtResetDevice(deviceId));
+ CHECK_ACL(aclFinalize());
+}
+}
/*
* 该函数为SinhCustom算子核函数入口
- * x Device上的gm地址,指向Add算子第一个输入
- * y Device上的gm地址,指向Add算子第一个输出
- * param Device上的gm地址,指向运行态ATVC::EleWiseParam数据
+ * x Device上的gm地址,指向SinhCustom算子第一个输入
+ * y Device上的gm地址,指向SinhCustom算子第一个输出
+ * param 指向运行态ATVC::EleWiseParam数据
*/
template
-__global__ __aicore__ void SinhCustom(GM_ADDR x, GM_ADDR y, GM_ADDR param)
+__global__ __aicore__ void SinhCustom(GM_ADDR x, GM_ADDR y, ATVC::EleWiseParam param)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); // 控制算子执行时只启动Vector核
auto op = ATVC::Kernel::EleWiseOpTemplate>();
- op.Run(x, y, param); // 按照输入、输出、param的顺序传入Run函数中;OpTraits内部的ATVC::OpTemps将由EleWiseOpTemplate内部申请资源,开发无需关注
+ op.Run(x, y, ¶m); // 按照输入、输出、param的顺序传入Run函数中;OpTraits内部的ATVC::OpTemps将由EleWiseOpTemplate内部申请资源,开发无需关注
}
int main()
@@ -380,18 +418,11 @@ int main()
int32_t eleNum = 8 * 2048;
size_t inputByteSize = static_cast(eleNum) * sizeof(float);
size_t outputByteSize = static_cast(eleNum) * sizeof(float);
-
- std::random_device rd;
- std::mt19937 gen(rd());
- std::uniform_real_distribution dis(1.0f, 10.0f);
std::vector inputX(eleNum);
std::vector golden(eleNum);
+ InitializeData(eleNum, inputX, golden);
- for (int i = 0; i < eleNum; ++i) {
- inputX[i] = (dis(gen));
- golden[i] = std::sinh(inputX[i]);
- }
ATVC::EleWiseParam param;
// 计算输入为8*2048个float元素的sinh算子的运行态参数param
@@ -400,19 +431,15 @@ int main()
return -1;
};
// 初始化Acl资源与数据
- CHECK_ACL(aclInit(nullptr));
aclrtContext context;
- int32_t deviceId = 0;
- CHECK_ACL(aclrtSetDevice(deviceId));
- CHECK_ACL(aclrtCreateContext(&context, deviceId));
aclrtStream stream = nullptr;
- CHECK_ACL(aclrtCreateStream(&stream));
+ int32_t deviceId = 0;
+ InitializeACL(context, stream, deviceId);
uint8_t *yHost;
uint8_t *xDevice;
uint8_t *yDevice;
uint8_t *paramDevice;
-
CHECK_ACL(aclrtMalloc((void **)&xDevice, inputByteSize, ACL_MEM_MALLOC_HUGE_FIRST));
CHECK_ACL(aclrtMemcpy(xDevice, inputByteSize, inputX.data(), inputByteSize, ACL_MEMCPY_HOST_TO_DEVICE));
@@ -422,8 +449,10 @@ int main()
// 将tiling计算的运行时参数EleWiseParam param传到Device侧
auto elementParamSize = sizeof(param);
CHECK_ACL(aclrtMalloc((void**)¶mDevice, elementParamSize, ACL_MEM_MALLOC_HUGE_FIRST));
- CHECK_ACL(aclrtMemcpy(paramDevice, elementParamSize, reinterpret_cast(¶m), elementParamSize, ACL_MEMCPY_HOST_TO_DEVICE));
-
+ CHECK_ACL(aclrtMemcpy(paramDevice, elementParamSize,
+ reinterpret_cast(¶m), elementParamSize,
+ ACL_MEMCPY_HOST_TO_DEVICE));
+
// 调用自定义的Kernel API, <<<>>>的BlockNum参数可通过param的TilingData获取
SinhCustom<<>>(xDevice, yDevice, paramDevice);
@@ -437,15 +466,10 @@ int main()
CHECK_ACL(aclrtFree(paramDevice));
CHECK_ACL(aclrtFreeHost(yHost));
- CHECK_ACL(aclrtDestroyStream(stream));
- CHECK_ACL(aclrtResetDevice(deviceId));
- CHECK_ACL(aclFinalize());
+ CleanACL(stream, deviceId);
- for (int32_t i = 0; i < eleNum; i++) {
- if (!IsClose(golden[i], outputY[i])) {
- printf("Accuracy verification failed! The expected value of element in index [%d] is %f, but actual value is %f.\n", i, golden[i], outputY[i]);
- return -1;
- }
+ if (!VerifyResults(golden, outputY)) {
+ return -1;
}
printf("Accuracy verification passed.\n");
return 0;
@@ -454,12 +478,12 @@ int main()
## 2.2 Reduce算子开发
ATVC框架提供的Reduce算子模板类的模块之间的交互如下(ATVC框架提供的模板及接口用黄色表示;开发自定义的模块用蓝色表示):
-
+
Reduce模板算子内部根据计算的数据大小、shape、Reduce axis轴完成了不同计算调度的代码实现,ATVC将各种计算调度场景抽象为`ATVC::ReducePolicy`。在算子调用阶段,分派策略API可根据Tiling API计算出的`ATVC::ReducePolicy`转化为编译态参数,结合计算模板来实例化`ATVC::Kernel::ReduceOpTemplate`算子模板类。
### 2.2.1 Components
根据Reduce算子在框架内部的交互场景,ATVC提供如下的接口以及模板类帮助开发搭建自定义Reduce算子:
-
+
自定义Reduce算子需按照以下顺序完成模块之间的组装:
1. 自定义计算模板/使用框架内置计算模板
2. 将计算模板传入`Kernel`层模板算子完成核函数功能实现;
@@ -478,7 +502,7 @@ Reduce类的计算模板涉及多核之间的数据结果同步以及核内分
#include "common/kernel_utils.h"
#include "reduce/common/patterns.h"
-#include "reduce/reduce_utils/reduce_block_aux_util.h"
+#include "reduce/utils/reduce_block_aux_util.h"
namespace ATVC {
@@ -520,17 +544,17 @@ public:
```
Reduce计算模板类将在数据计算阶段被`ReduceOpTemplate`算子模板调用,因此Reduce计算模板类的实现必须遵从以下约束:
-- 该模板类在实例化时固定传入ATVC::OpTraits类型的结构体作为模板参数,如` ATVC::OpTraits,ATVC::OpOutputs`。
+- 该模板类在实例化时固定传入ATVC::OpTraits类型的结构体作为模板参数,如`ATVC::OpTraits,ATVC::OpOutputs`。
- 开发必须完成以下公有API的内部实现:
- 1. 计算单数据基块的Reduce结果 \_\_aicore\_\_ inline void Compute(...)
- 2. 计算单UB内不同数据基块的计算结果 \_\_aicore\_\_ inline void UpdateCache(...);
- 3. 计算多核之间&同一核内的多次UB结果 \_\_aicore\_\_ inline void ReduceBetweenUB(...)
- 4. 返回非对齐场景不参与计算的尾部数据的填充值 \_\_aicore\_\_ inline U GetPaddingValue()
+ 1. 计算单数据基块的Reduce结果 `\_\_aicore\_\_ inline void Compute(...)`
+ 2. 计算单UB内不同数据基块的计算结果 `\_\_aicore\_\_ inline void UpdateCache(...)`
+ 3. 计算多核之间&同一核内的多次UB结果 `\_\_aicore\_\_ inline void ReduceBetweenUB(...)`
+ 4. 返回非对齐场景不参与计算的尾部数据的填充值 `\_\_aicore\_\_ inline U GetPaddingValue()`
### 2.2.3 内置Reduce算子模板
`ATVC::Kernel::ReduceOpTemplate`是一套基本的Reduce算子类,它实现了一套算子数据的搬运搬出、资源分配和释放的流程。Kernel层的算子模板需要计算模板类作为模板参数传入来完成实例化。在调用阶段,算子类将按照固定参数顺序调用计算模板类的对应接口,完成数据的计算。
-相比EleWise算子模板不同的是,ReduceOpTemplate内置了不同场景的Reduce实现,并在编译时通过`ATVC::ReducePolicy`类型的结构体来实现实例化。ReduceOpTemplate内部将根据模板参数决定数据将由哪类具体的模板实例计算。`ATVC::ReducePolicy`的数据定义如下:
+相比Elementwise算子模板不同的是,ReduceOpTemplate内置了不同场景的Reduce实现,并在编译时通过`ATVC::ReducePolicy`类型的结构体来实现实例化。ReduceOpTemplate内部将根据模板参数决定数据将由哪类具体的模板实例计算。`ATVC::ReducePolicy`的数据定义如下:
```cpp
struct ReducePolicy {
@@ -542,21 +566,20 @@ struct ReducePolicy {
下方为`ATVC::Kernel::ReduceOpTemplate`模板类的外部接口介绍,完整模板类定义请参考`atvc/include/reduce/reduce_op_template.h`。
```cpp
-template
+template
class ReduceOpTemplate {
public:
__aicore__ inline ReduceOpTemplate(){};
// 按照输入、输出、EleWiseParam、其他标量的顺序传入
// 内部根据EleWiseParam进行数据调度并调用ReduceOpTemplate完成计算后搬出到GM
- template
- __aicore__ inline void Run(GM_ADDR x, GM_ADDR y, GM_ADDR param) {
+ template
+ __aicore__ inline void Run(GM_ADDR x, GM_ADDR y, ATVC::ReduceParam* param) {
//
// Reduce类算子Run接口按输入、输出、运行态参数param顺序传入
//
}
-}
+};
```
@@ -566,13 +589,13 @@ public:
// ReduceSum算子的描述:一个输入,一个输出,类型均为float
using ReduceOpTraits = ATVC::OpTraits, ATVC::OpOutputs>;
-template
-__global__ __aicore__ void ReduceCustom(GM_ADDR x, GM_ADDR y, GM_ADDR reduceParam)
+template
+__global__ __aicore__ void ReduceCustom(GM_ADDR x, GM_ADDR y, ATVC::ReduceParam reduceParam)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_MIX_AIV_1_0); // 使用了多核控制指令,设置算子执行时只启动Vector核
// 将计算模板类模板定义作为模板参数传入, Policy由Host层的策略分派API给出
auto op = ATVC::Kernel::ReduceOpTemplate, Policy>();
- op.Run(x, y, reduceParam);
+ op.Run(x, y, &reduceParam);
}
```
@@ -587,16 +610,16 @@ using ReduceOpTraits = ATVC::OpTraits, ATVC::OpOutputs
-__global__ __aicore__ void ReduceSumCustom(GM_ADDR x, GM_ADDR y, GM_ADDR param)
+template
+__global__ __aicore__ void ReduceSumCustom(GM_ADDR x, GM_ADDR y, ATVC::ReduceParam param)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_MIX_AIV); // 使用了多核控制指令,设置算子执行时只启动Vector核
auto op = ATVC::Kernel::ReduceOpTemplate, SelectPolicy>();
- op.Run(x, y, param);
+ op.Run(x, y, ¶m);
}
```
@@ -604,7 +627,7 @@ __global__ __aicore__ void ReduceSumCustom(GM_ADDR x, GM_ADDR y, GM_ADDR param)
Reduce算子开发场景下,核函数定义必须遵从以下约束:
1. 核函数须预留一个GM_ADDR类型的形参用于传入`ATVC::ReduceParam`运行态参数;
2. 核函数须加入`KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_MIX_AIV_1_0);`这段代码显示标注算子类型;
-3. 核函数须实例化`ATVC::Kernel::ReduceOpTemplate`变量并调用它的`Run(GM_ADDR x, GM_ADDR y, GM_ADDR param)`接口来实现数据的调度运算;
+3. 核函数须实例化`ATVC::Kernel::ReduceOpTemplate`变量并调用它的`Run(GM_ADDR x, GM_ADDR y, ATVC::ReduceParam* param)`接口来实现数据的调度运算;
### 2.2.5 Host层API
@@ -693,33 +716,28 @@ static constexpr ATVC::ReducePolicy REDUCE_POLICY3 { ATVC::AR_PATTERN::AR, ATVC:
// ReduceOpAdapter函数定义
// 负责Reduce类算子的调度,选择对应的Policy最佳策略并执行Kernel函数
-template
+template
void ReduceOpAdapter(uint8_t* x, uint8_t* y, ATVC::ReduceParam ¶m, ATVC::ReducePolicy &policy, aclrtStream& stream)
{
// 申请临时空间workspace,并将其与ReduceTilingData一同传到Device侧
- uint8_t *paramDevice;
uint8_t *workspaceDevice;
CHECK_ACL(aclrtMalloc((void **)&workspaceDevice, param.workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST));
param.workspaceAddr = reinterpret_cast(workspaceDevice);
- auto reduceParamSize = sizeof(param);
- CHECK_ACL(aclrtMalloc((void**)¶mDevice, reduceParamSize, ACL_MEM_MALLOC_HUGE_FIRST));
- CHECK_ACL(aclrtMemcpy(paramDevice, reduceParamSize, reinterpret_cast(¶m), reduceParamSize, ACL_MEMCPY_HOST_TO_DEVICE));
// 将tiling api计算出的ReducePolicy转化为编译态参数并实例化相应的核函数
if (policy == ATVC::REDUCE_POLICY0) {
- ReduceCustom<<>>(x, y, paramDevice);
+ ReduceCustom<<>>(x, y, param);
}else if (policy == ATVC::REDUCE_POLICY1) {
- ReduceCustom<<>>(x, y, paramDevice);
+ ReduceCustom<<>>(x, y, param);
} else if (policy == ATVC::REDUCE_POLICY2) {
- ReduceCustom<<>>(x, y, paramDevice);
+ ReduceCustom<<>>(x, y, param);
} else if (policy == ATVC::REDUCE_POLICY3) {
- ReduceCustom<<>>(x, y, paramDevice);
+ ReduceCustom<<>>(x, y, param);
} else {
printf("[ERROR] Cannot find any matched policy.\n");
}
// 流同步后释放申请的param内存
CHECK_ACL(aclrtSynchronizeStream(stream));
CHECK_ACL(aclrtFree(workspaceDevice));
- CHECK_ACL(aclrtFree(paramDevice));
}
using ReduceOpTraits = ATVC::OpTraits, ATVC::OpOutputs>;
@@ -747,25 +765,17 @@ using ReduceOpTraits = ATVC::OpTraits, ATVC::OpOutputs
#include
#include
+#include
+#include
#include
#include "acl/acl.h"
-#include "atvc.h"
+#include "reduce/reduce_host.h"
+#include "reduce/reduce_device.h"
#define CHECK_ACL(x) \
do { \
@@ -780,29 +790,45 @@ static constexpr float REL_TOL = 1e-3f;
static constexpr float ABS_TOL = 1e-5f;
// 判断两个浮点数是否足够接近
-bool IsClose(float a, float b) {
+bool IsClose(float a, float b)
+{
const float eps = 1e-40f; // 防止分母为零
float diff = std::abs(a - b);
return (diff <= ABS_TOL) || (diff <= REL_TOL * std::max(std::abs(a), std::abs(b) + eps));
}
-}
// ReduceSum算子的描述:一个输入,一个输出,类型均为float
using ReduceOpTraits = ATVC::OpTraits, ATVC::OpOutputs>;
+bool VerifyResults(const std::vector &golden, const std::vector &output)
+{
+ for (int32_t i = 0; i < golden.size(); i++) {
+ if (!IsClose(golden[i], output[i])) {
+ printf("Accuracy verification failed! The expected value of element "
+ "in index [%d] is %f, but actual value is %f.\n",
+ i,
+ golden[i],
+ output[i]);
+ return false;
+ }
+ }
+ return true;
+}
+}
+
/*
* 该函数为ReduceCustom算子核函数入口
- * x Device上的gm地址,指向Add算子第一个输入
- * y Device上的gm地址,指向Add算子第一个输出
- * reduceParam Device上的gm地址,指向运行态ATVC::ReduceParam数据
+ * x Device上的gm地址,指向ReduceCustom算子第一个输入
+ * y Device上的gm地址,指向ReduceCustom算子第一个输出
+ * reduceParam 指向运行态ATVC::ReduceParam数据
*/
template
-__global__ __aicore__ void ReduceCustom(GM_ADDR x, GM_ADDR y, GM_ADDR reduceParam)
+__global__ __aicore__ void ReduceCustom(GM_ADDR x, GM_ADDR y, ATVC::ReduceParam reduceParam)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_MIX_AIV_1_0); // 使用了多核控制指令,设置算子执行时只启动Vector核
// 将计算模板类模板定义作为模板参数传入,Policy由Host层的策略分派API给出
auto op = ATVC::Kernel::ReduceOpTemplate, Policy>();
- op.Run(x, y, reduceParam);
+ op.Run(x, y, &reduceParam);
}
// 负责Reduce类算子的调度,选择对应的Policy最佳策略并执行Kernel函数
@@ -816,11 +842,13 @@ void ReduceOpAdapter(uint8_t* x, uint8_t* y, ATVC::ReduceParam ¶m, ATVC::Red
param.workspaceAddr = reinterpret_cast(workspaceDevice);
auto reduceParamSize = sizeof(param);
CHECK_ACL(aclrtMalloc((void**)¶mDevice, reduceParamSize, ACL_MEM_MALLOC_HUGE_FIRST));
- CHECK_ACL(aclrtMemcpy(paramDevice, reduceParamSize, reinterpret_cast(¶m), reduceParamSize, ACL_MEMCPY_HOST_TO_DEVICE));
+ CHECK_ACL(aclrtMemcpy(paramDevice, reduceParamSize,
+ reinterpret_cast(¶m), reduceParamSize,
+ ACL_MEMCPY_HOST_TO_DEVICE));
// 将tiling api计算出的ReducePolicy转化为编译态参数并实例化相应的核函数
if (policy == ATVC::REDUCE_POLICY0) {
ReduceCustom<<>>(x, y, paramDevice);
- }else if (policy == ATVC::REDUCE_POLICY1) {
+ } else if (policy == ATVC::REDUCE_POLICY1) {
ReduceCustom<<>>(x, y, paramDevice);
} else if (policy == ATVC::REDUCE_POLICY2) {
ReduceCustom<<>>(x, y, paramDevice);
@@ -862,6 +890,8 @@ void ReduceOpAdapter(uint8_t* x, uint8_t* y, ATVC::ReduceParam ¶m, ATVC::Red
ReduceCustom<<>>(x, y, paramDevice);
} else if (policy == ATVC::REDUCE_POLICY21) {
ReduceCustom<<>>(x, y, paramDevice);
+ } else if (policy == ATVC::REDUCE_POLICY22) {
+ ReduceCustom<<>>(x, y, paramDevice);
} else {
printf("[ERROR] Cannot find any matched policy.\n");
}
@@ -881,7 +911,7 @@ int32_t main(int32_t argc, char* argv[])
std::vector shape{8, 1024}; // 测试输入shape
std::vector inputX(eleNum, 1.0f);
std::vector golden(outEleNum, 8.0f);
-
+ printf("Generate golden data successfully.\n");
// 初始化Acl资源
CHECK_ACL(aclInit(nullptr));
aclrtContext context;
@@ -904,7 +934,7 @@ int32_t main(int32_t argc, char* argv[])
ATVC::ReducePolicy policy = {-1, -1, -1}; // Reduce运行态参数,负责映射最适合的Reduce模板实现
// Host侧调用Tiling API完成相关运行态参数的运算
if (!ATVC::Host::CalcReduceTiling(shape, dim, &policy, ¶m)) {
- printf("Reduce tiling error.");
+ printf("Reduce tiling error.\n");
return -1;
};
@@ -924,12 +954,10 @@ int32_t main(int32_t argc, char* argv[])
CHECK_ACL(aclrtResetDevice(deviceId));
CHECK_ACL(aclFinalize());
- for (int32_t i = 0; i < outEleNum; i++) {
- if (!IsClose(golden[i], outputY[i])) {
- printf("Accuracy verification failed! The expected value of element in index [%d] is %f, but actual value is %f.\n", i, golden[i], outputY[i]);
- return -1;
- }
+ if (!VerifyResults(golden, outputY)) {
+ return -1;
}
+
printf("Accuracy verification passed.\n");
return 0;
}
@@ -937,11 +965,11 @@ int32_t main(int32_t argc, char* argv[])
## 2.3 Broadcast算子开发
ATVC框架提供的Broadcast算子模板类的模块之间的交互如下(ATVC框架提供的模板及接口用黄色表示;开发自定义的模块用蓝色表示):
-
+
Broadcast模板算子内部根据数据类型、输入/输出shape完成某个轴上数据扩充的功能,ATVC将各种计算调度场景抽象为`ATVC::BroadcastPolicy`。在算子调用阶段,分派策略API可根据Tiling API计算出的`ATVC::BroadcastPolicy`转化为编译态参数,结合计算模板来实例化`ATVC::Kernel::BroadcastOpTemplate`算子模板类。
### 2.3.1 Components
根据Broadcast算子在框架内部的交互场景,ATVC提供如下的接口以及模板类帮助开发搭建自定义Broadcast算子:
-
+
自定义Broadcast算子需按照以下顺序完成模块之间的组装:
1. 自定义计算模板/使用框架内置计算模板
2. 将计算模板传入`Kernel`层模板算子完成核函数功能实现;
@@ -959,7 +987,7 @@ Broadcast计算模板是指Broadcast类算子在UB上实现将A轴的数据复
#include "broadcast/common/broadcast_common.h"
namespace ATVC {
-template
+template
class BroadcastCompute {
public:
using inputDTypeList = typename OpTraits::In::types;
@@ -988,7 +1016,7 @@ Broadcast计算模板类将在数据计算阶段被`BroadcastOpTemplate`算子
* AB场景的计算:输入`src`是一个shape为(dimA, 1)的Tensor,需要将数据扩充到`dst`上,dst的shape是(dimA, dimB);
* BA场景的计算:输入`src`是一个shape为(1, dimA)的Tensor,需要将src数据扩充到`dst`上,dst的shape是(dimB, dimA);
-- 该模板类在实例化时固定传入ATVC::OpTraits类型的结构体作为模板参数,如` ATVC::OpTraits,ATVC::OpOutputs`。
+- 该模板类在实例化时固定传入`ATVC::OpTraits`类型的结构体作为模板参数,如` ATVC::OpTraits,ATVC::OpOutputs`。
### 2.3.3 内置Broadcast算子模板
`ATVC::Kernel::BroadcastOpTemplate`是一套基本的Broadcast算子类,它实现了一套算子数据的搬运搬出、资源分配和释放的流程。Kernel层的算子模板需要计算模板类作为模板参数传入来完成实例化。在调用阶段,Broadcast算子模板将按照固定参数顺序调用计算模板类的`Compute`接口,完成数据的计算。
@@ -1003,12 +1031,12 @@ struct BroadcastPolicy {
};
```
-下方为`ATVC::Kernel::BroadcastOpTemplate`模板类的外部接口介绍,完整模板类定义请参考`atvc/include/broadcast/broadcast_op_template.h`。
+下方为`ATVC::Kernel::BroadcastOpTemplate`模板类的外部接口介绍,完整模板类定义请参考[`atvc/include/broadcast/broadcast_op_template.h`](../include/broadcast/broadcast_op_template.h)。
```cpp
#ifndef ATVC_BROADCAST_OP_TEMPLATE_H
#define ATVC_BROADCAST_OP_TEMPLATE_H
#include "common/const_def.h"
-#include "broadcast/broadcast_utils/broadcast_buf_pool.h"
+#include "broadcast/utils/broadcast_buf_pool.h"
namespace ATVC {
namespace Kernel {
template
@@ -1023,14 +1051,14 @@ public:
@param dst: 输出数据的gm指针
@broadcastParam: broadcast的动态参数,包含tiling data, workspace等
*/
- __aicore__ inline void Run(GM_ADDR src, GM_ADDR dst, GM_ADDR broadcastParam)
+ __aicore__ inline void Run(GM_ADDR src, GM_ADDR dst, ATVC::BroadcastParam* broadcastParam)
{
this->Init(src, dst, broadcastParam);
this->Process();
}
- AscendC::GlobalTensor srcGlobal;
- AscendC::GlobalTensor dstGlobal;
+ AscendC::GlobalTensor srcGlobal_;
+ AscendC::GlobalTensor dstGlobal_;
BroadcastCompute compute_;
__gm__ BroadcastParam *param_;
};
@@ -1046,14 +1074,13 @@ public:
// BroadcastTo算子的描述:一个输入,一个输出,类型均为float
using BroadcastOpTraits = ATVC::OpTraits, ATVC::OpOutputs>;
-template
-__global__ __aicore__ void BroadcastCustom(GM_ADDR x, GM_ADDR y, GM_ADDR broadcastParam)
+template
+__global__ __aicore__ void BroadcastCustom(GM_ADDR x, GM_ADDR y, ATVC::BroadcastParam broadcastParam)
{
- AscendC::printf("BroadcastCustom\n");
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); // 设置算子执行时只启动Vector核
// 将计算模板类模板定义作为模板参数传入,Policy由Host层的策略分派API给出
auto op = ATVC::Kernel::BroadcastOpTemplate, Policy>();
- op.Run(x, y, broadcastParam);
+ op.Run(x, y, &broadcastParam);
}
```
@@ -1069,18 +1096,17 @@ using BroadcastOpTraits = ATVC::OpTraits, ATVC::OpOutputs
/*
* 该函数为BroadcastCustom算子核函数入口
- * x Device上的gm地址,指向Add算子第一个输入
- * y Device上的gm地址,指向Add算子第一个输出
- * broadcastParam Device上的gm地址,指向运行态ATVC::BroadcastParam数据
+ * x Device上的gm地址,指向BroadcastTo算子第一个输入
+ * y Device上的gm地址,指向BroadcastTo算子第一个输出
+ * broadcastParam 指向运行态ATVC::BroadcastParam数据
*/
-template
-__global__ __aicore__ void BroadcastCustom(GM_ADDR x, GM_ADDR y, GM_ADDR broadcastParam)
+template
+__global__ __aicore__ void BroadcastCustom(GM_ADDR x, GM_ADDR y, ATVC::BroadcastParam broadcastParam)
{
- AscendC::printf("BroadcastCustom\n");
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); // 设置算子执行时只启动Vector核
// 将计算模板类模板定义作为模板参数传入,Policy由Host层的策略分派API给出
auto op = ATVC::Kernel::BroadcastOpTemplate, Policy>();
- op.Run(x, y, broadcastParam);
+ op.Run(x, y, &broadcastParam);
}
```
@@ -1088,7 +1114,7 @@ __global__ __aicore__ void BroadcastCustom(GM_ADDR x, GM_ADDR y, GM_ADDR broadca
Broadcast算子开发场景下,核函数定义必须遵从以下约束:
1. 核函数须预留一个GM_ADDR类型的形参用于传入`ATVC::BroadcastParam`运行态参数;
2. 核函数须加入`KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);`这段代码显示标注算子类型;
-3. 核函数须实例化`ATVC::Kernel::BroadcastOpTemplate`变量,实例化时需传入对应的计算实现模板类`ATVC::BroadcastCompute`,并调用它的`Run(GM_ADDR x, GM_ADDR y, GM_ADDR broadcastParam)`接口来实现数据的调度运算;
+3. 核函数须实例化`ATVC::Kernel::BroadcastOpTemplate`变量,实例化时需传入对应的计算实现模板类`ATVC::BroadcastCompute`,并调用它的`Run(GM_ADDR x, GM_ADDR y, ATVC::BroadcastParam* broadcastParam)`接口来实现数据的调度运算;
### 2.3.5 Host层API
#### 2.3.5.1 CalcBroadcastTiling
@@ -1128,7 +1154,7 @@ struct BroadcastParam {
```cpp
namespace ATVC {
namespace Host {
-template
+template
bool CalcBroadcastTiling(std::vector shapeIn, std::vector shapeOut, BroadcastPolicy* policy, BroadcastParam* param)
{
using inputDTypeList = typename OpTraits::In::types;
@@ -1170,7 +1196,7 @@ int32_t main(int32_t argc, char* argv[])
```cpp
// 负责Broadcast类算子的调度,选择对应的Policy最佳策略并执行Kernel函数
-template
+template
void BroadcastOpAdapter(uint8_t* x, uint8_t* y, ATVC::BroadcastParam ¶m, ATVC::BroadcastPolicy &policy, aclrtStream& stream)
{
// 申请临时空间workspace,并将其与BroadcastTilingData一同传到Device侧
@@ -1216,7 +1242,7 @@ int32_t main(int32_t argc, char* argv[])
### 2.3.6 完整样例
-通过ATVC框架实现的完整BroadcastCustom算子[样例代码](../examples/broadcast_to/broadcast_to.cpp)如下:
+通过ATVC框架实现的完整BroadcastCustom算子[样例代码](../examples/broadcast_to/broadcast_to.cpp)
```cpp
#include
#include
@@ -1252,23 +1278,22 @@ using BroadcastOpTraits = ATVC::OpTraits, ATVC::OpOutputs
/*
* 该函数为BroadcastCustom算子核函数入口
- * x Device上的gm地址,指向Add算子第一个输入
- * y Device上的gm地址,指向Add算子第一个输出
- * broadcastParam Device上的gm地址,指向运行态ATVC::BroadcastParam数据
+ * x Device上的gm地址,指向BroadcastTo算子第一个输入
+ * y Device上的gm地址,指向BroadcastTo算子第一个输出
+ * broadcastParam 指向运行态ATVC::BroadcastParam数据
*/
-template
-__global__ __aicore__ void BroadcastCustom(GM_ADDR x, GM_ADDR y, GM_ADDR broadcastParam)
+template
+__global__ __aicore__ void BroadcastCustom(GM_ADDR x, GM_ADDR y, ATVC::BroadcastParam broadcastParam)
{
- AscendC::printf("BroadcastCustom\n");
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); // 设置算子执行时只启动Vector核
// 将计算模板类模板定义作为模板参数传入,Policy由Host层的策略分派API给出
auto op = ATVC::Kernel::BroadcastOpTemplate, Policy>();
- op.Run(x, y, broadcastParam);
+ op.Run(x, y, &broadcastParam);
}
// 负责Broadcast类算子的调度,选择对应的Policy最佳策略并执行Kernel函数
-template
+template
void BroadcastOpAdapter(uint8_t* x, uint8_t* y, ATVC::BroadcastParam ¶m, ATVC::BroadcastPolicy &policy, aclrtStream& stream)
{
// 申请临时空间workspace,并将其与BroadcastTilingData一同传到Device侧
@@ -1355,4 +1380,210 @@ int32_t main(int32_t argc, char* argv[])
printf("Accuracy verification passed.\n");
return 0;
}
-```
\ No newline at end of file
+```
+
+# 3 ATVC的调试调优功能
+为了用户在使用ATVC进行算子开发时能快速进行精度调试和性能调优,ATVC支持多种调试调优能力。
+## 3.1 OpTraits校验接口
+用户可通过`DebugCheck()`接口校验不同模板的OpTraits功能, 接口在Host侧调用,无需额外的开关限制,接口定义如下:
+```cpp
+namespace ATVC {
+namespace Host {
+template
+bool DebugCheck()
+}
+}
+```
+其中,模板参数`OpTraits`是用户定义的待校验的输入输出描述信息, 模板参数`templateType`是校验规则分类的标识, 定义如下:
+```cpp
+enum class TemplateType {
+ ELE_WISE, // ElementWise模板的校验类型
+ REDUCE, // Reduce模板的校验类型
+ BROADCAST, // Broadcast模板的校验类型
+};
+```
+接口使用示例:
+```cpp
+using AddOpTraits = ATVC::OpTraits, ATVC::OpOutputs>;
+
+ATVC::Host::DebugCheck();
+```
+完整的DebugCheck调用接口样例可参考tanh_grad算子[样例代码](../examples/tanh_grad/tanh_grad.cpp)。
+## 3.2 使用调试调优模式运行算子
+样例执行脚本run_test.sh支持可选入参`--run-mode`进行不同调试调优运行模式的选择。
+当前支持`debug_print`和`profiling`两种模式。
+- `--run-mode=debug_print`:DFX信息打印模式,打开kernel侧的模板内置关键节点的信息打印和异常退出时的打印功能。
+- `--run-mode=profiling`:Profiling性能采集模式,运行时打开profiling性能数据采集功能。
+- 未设置`--run-mode`:默认模式,正常上板,无kernel侧的dfx信息打印, 未开启profiling性能采集功能。
+## 3.2.1 DFX信息打印模式
+通过运行run_test.sh脚本时加上可选参数`--run-mode=debug_print`打开本功能。
+DFX信息打印格式按照 [日志级别(`ERROR`/`INFO`)]:[`ATVC`][`Module`](可选:[`CopyIn`/`CopyOut`等])的标准进行打印。
+- 日志级别: ERROR是异常打印信息,INFO是模板内部重要信息打印
+- `ATVC`: 标识是ATVC模板库内置的DFX信息打印
+- `Module`: 标识是哪个模块的信息打印,例如:`EleWise`、 `Reduce`、`Broadcast`、`Common`等模块。
+- 可选子模块: 用于部分`Module`涉及多个子模块,可选择增加子模块信息,细化DFX信息。
+模板内部提供的DFX信息打印接口定义及使用样例如下所示, 对于普通算子开发用户,无需关注该接口,只有需要修改或者扩展开发模板功能的场景,可使用该接口。
+```cpp
+//接口定义
+namespace ATVC {
+namespace Kernel {
+template
+__aicore__ inline void DebugPrintf(__gm__ const char* fmt, Args&&... args);
+}
+}
+// 调用示例
+ATVC::Kernel::DebugPrintf("[ERROR]: [ATVC][EleWise] Input Count can not be 0!\n");
+ATVC::Kernel::DebugPrintf("[INFO]: [ATVC][EleWise][CopyIn] Offset is %u, copy count is %u.\n", curCoreStartCnt_ + offsetCnt_, calcCnt_);
+```
+
+## 3.2.2 开启Profiling性能调优功能
+通过运行run_test.sh脚本时加上可选参数`--run-mode=profiling`打开本功能。
+为了增加Profiling采集性能数据的稳定性,建议用户在开启profiling时,运行时重复多次调用kernel,可实现一次性采集多次上板的性能数据,消除抖动。
+```cpp
+TanhGrad<<>>(dyDevice, yDevice, zDevice, paramDevice);
+#if ATVC_DEBUG_MODE == 2 // ATVC_DEBUG_MODE == 2: open profiling
+ for (int32_t i = 0; i < 19; i++) { // 19: run kernel 1 + 19 times for profiling
+ TanhGrad<<>>(dyDevice, yDevice, zDevice, paramDevice);
+ }
+#endif
+```
+其中`ATVC_DEBUG_MODE`是`run-mode`在不同的模式下的内部宏定义的映射。`ATVC_DEBUG_MODE == 2`是`--run-mode=profiling`的内部映射,用户无需关注。
+
+## 3.3 Tiling超参调优
+### 3.3.1 ElementWise模板算子Tiling超参调优
+#### 3.3.1.1 ElementWise模板通用Tiling算法
+- 计算blockNum:计算blockNum = 总的元素量(totalCnt) / 单核数据量基线(singleCoreBaseLine), blockNum最小值为1, 最大值为平台提供的最大vectorCore值。
+- 计算达到UB上限的单核单输入元素个数值ubLimitCnt:UB上限内存大小 / 所有输入输出及temp单个元素的内存之和。
+- 计算tiledCnt:
+ - 计算每个核需要处理的数据元素量avgElePerBlock = totalCnt / blockNum;
+ - 根据avgElePerBlock所处的splitDataShape数据段,按照切分系数去切分基本块: tiledCnt = dataSplitFactor / dataSplitFactor
+ - tiledCnt调整: 不超上限ubLimitCnt, 不小于下限32,且最后的tiledCnt要做32元素对齐。
+#### 3.3.1.2 ElementWise TilingData定义
+ElementWise模板通用Tiling切分的数据结构为EleWiseTilingData,描述了核间切分和单核内切分的策略,其定义如下:
+```cpp
+namespace ATVC {
+struct EleWiseTilingData {
+ uint32_t tailBlockCnt; // 需要额外执行一次循环的核的数量
+ uint32_t tailElemCnt; // 尾块元素数量
+ uint32_t numPerBlock; // 每个核需计算的基本块个数
+ uint32_t tiledCnt; // 基本块元素个数
+ uint32_t blockNum; // 执行核数
+};
+}
+```
+
+#### 3.3.1.3 ElementWise Tiling超参调优
+当前提供的ElementWise模板内置通用Tiling可调超参如下所示:
+| Tiling超参名 | 数据类型 | 参数说明 | 调节范围 | 默认值 |
+| ----------- | -------------- | ----------- | ----------- |---|
+| singleCoreBaseLine | uint32_t | 单核数据量基线 | [256, 128 * 1024] | 512|
+| ubSizeLimitThreshold | float | UB内存使用上限,决定了basicBlock最大值 | [0.5, 0.96] | 0.95 |
+| splitDataShape | uint32_t[3]| 单核内数据量的3个分段节点,表示数据量分为4段| {node_0, node_1, node_2} | {1024, 32*1024, 64*1024}|
+| dataSplitFactor | uint32_t[4]| 单核内4个数据段的切分系数, 决定不同数据段的切分基本块的大小| {factor_0, factor_1, factor_2, factor_3} 均大于0 小于32| {4, 4, 8, 6}|
+| rsvLiveCnt | uint32_t| 预留的空间大小为rsvLiveCnt * (inputBuffer + outputBuffer)|[0, 1]| 0|
+
+对应的超参`EleWiseTilingHyperParam`数据结构定义如下:
+```cpp
+namespace ATVC {
+namespace Host {
+struct EleWiseTilingHyperParam {
+ uint32_t singleCoreBaseLine = 512; // 数据量基线:核内数据量超过基线就分多核直至满核, 设置范围: [256, 128 * 1024]
+ float ubSizeLimitThreshold = 0.95f; // UB内存使用上限,决定了basicBlock最大值
+ uint32_t nBufferNum = 2; // multi buffer 设置值为: [1, 2]
+ uint32_t splitDataShape[MAX_SHAPE_NODE] = {1024, 32 * 1024, 64 * 1024}; // 数据分段节点
+ uint32_t dataSplitFactor[MAX_SHAPE_NODE + 1] = {4, 4, 8, 6}; // 对应数据分段内的数据量的切分系数
+ uint32_t rsvLiveCnt = 0; // 额外的存活节点数,表示内部需要申请空间个数,可设置的范围为[0, 1]
+};
+}
+}
+```
+计算接口`CalcEleWiseTiling()`定义如下所示:
+```cpp
+namespace ATVC {
+namespace Host {
+template
+bool CalcEleWiseTiling(int32_t totalCnt, ATVC::EleWiseParam ¶m,
+ EleWiseTilingHyperParam hyperParam = EleWiseTilingHyperParam());
+}
+}
+```
+其中,可选参数`hyperParam`在未传入用户自定义超参时,使用`EleWiseTilingHyperParam`的默认值。
+若用户需要修改某个超参,调用示例如下所示:
+```cpp
+ // Add算子中有两个输入,一个输出。类型均为float
+ using AddOpTraits = ATVC::OpTraits, ATVC::OpOutputs>;
+ // totalCnt描述EleWise单输入的元素个数
+ int32_t eleNum = 8 * 1024;
+ // 声明运行态参数param
+ ATVC::EleWiseParam param;
+ ATVC::Host::EleWiseTilingHyperParam hyperParam;
+ hyperParam.singleCoreBaseLine = 1024;
+ if (!ATVC::Host::CalcEleWiseTiling(eleNum, param, hyperParam=hyperParam)) {
+ printf("[ERROR]: Calculate eleWise tiling failed.\n");
+ return -1;
+ };
+```
+### 3.3.2 Reduce模板算子Tiling超参调优
+#### 3.3.2.1 Reduce Tiling通用算法
+Reduce Tiling计算流程较为复杂,简化后的主要流程如下:
+
+#### 3.3.2.2 Reduce TilingData定义
+ATVC host 和kernel侧都会使用到的`ReduceTilingData`是Reduce的核间AR轴切分、单核内AR轴切分的策略,其定义如下:
+```cpp
+namespace ATVC {
+struct ReduceTilingData {
+ uint64_t factorACntPerCore; // 在每个核上不参与计算的非Reduce轴实际维度
+ uint64_t factorATotalCnt; // 不参与计算的非Reduce轴总维度
+ uint64_t ubFactorA; // 单UB内非Reduce轴的数据量
+ uint64_t factorRCntPerCore; // 在每个核上参与计算的Reduce轴实际维度
+ uint64_t factorRTotalCnt; // 参与计算的Reduce轴总维度
+ uint64_t ubFactorR; // 单UB内参与计算的Reduce轴维度
+ uint64_t groupR; // 切轴为R轴,该轴上切点外的R的相对数据量
+ uint64_t outSize; // 切轴外的AR数据总量
+ uint64_t basicBlock; // 基础数据块大小
+ int32_t coreNum; // 执行核数
+ float meanVar; // 预留信息,暂不使用
+ uint64_t shape[MAX_DIM]; // shape信息
+ uint64_t stride[MAX_DIM]; // 输入数据搬运步长
+ uint64_t dstStride[MAX_DIM]; // 输出数据搬运步长
+};
+}
+```
+#### 3.3.2.3 Reduce 超参调优
+可调参数如下所示:
+| Tiling超参名 | 数据类型 | 参数说明 | 调节范围 | 默认值 |
+| ----------- | -------------- | ----------- | ----------- |---|
+| basicBlock | uint32_t | Reduce 基本块内存大小 | 不能超过UB内存的1/3, 192K内存 建议在48K-54K之间设置 | 54 * 1024|
+| maxInnerA | uint32_t |AR切轴内A轴的最大数据量 | [128, 4096] | 128 |
+| balanceThreshHold | double| 多核均衡的阈值水平, 阈值越高,切分后每个核处理的数据量越均衡 | [0.85, 0.95]| 0.95 |
+
+对应的超参`ReduceTilingHyperParam`结构定义如下:
+```cpp
+namespace ATVC {
+namespace Host {
+struct ReduceTilingHyperParam {
+ uint32_t basicBlock = 48 * 1024; // 设置Reduce基本块内存大小, 一般不能超过内存的1/3, 建议在[48-54]之间设置
+ uint32_t maxInnerA = 128; // [128, 256]
+ double balanceThreshHold = 0.95; // 多核均衡的阈值水平 [0.8-0.95]
+};
+}
+}
+```
+Reduce Tiling的计算接口`CalcReduceTiling()`定义如下:
+```cpp
+namespace ATVC {
+namespace Host {
+template
+bool CalcReduceTiling(std::vector inputShape,
+ std::vector reduceDim,
+ ReducePolicy* policy,
+ ReduceParam* param,
+ ReduceTilingHyperParam hyperParam = ReduceTilingHyperParam());
+}
+}
+```
+其中,可选参数`hyperParam`在未传入用户自定义超参时,使用`ReduceTilingHyperParam`的默认值,若用户需要修改某个超参,可自定义`ReduceTilingHyperParam`后传入。
+
+# Copyright
+
+Copyright (c) 2025 Huawei Technologies Co., Ltd.
\ No newline at end of file
diff --git a/atvc/docs/code_organization.md b/atvc/docs/03_code_organization.md
similarity index 42%
rename from atvc/docs/code_organization.md
rename to atvc/docs/03_code_organization.md
index 58bd34d4de241e131263081eb5bcc0d85dab218c..47641b0cb98d098b19a918a1145b5d546ade92a2 100644
--- a/atvc/docs/code_organization.md
+++ b/atvc/docs/03_code_organization.md
@@ -8,40 +8,25 @@ include目录下的头文件是按照如下的文件层级进行组织。
```
include/
├── atvc.h // Vector模板编程入口头文件
-├── common // 不同模板公用api和C++基本类的拓展模板目录
-│ ├── atvc_opdef.h // ATVC模板算子数据类型描述
-│ ├── compile_info.h // 平台相关编译信息
-│ ├── const_def.h // 常量定义
-│ └── ...
-├── elewise // element_wise模板目录
-│ ├── common
-│ │ └── elewise_common.h // element_wise的公共数据定义
-│ ├── elewise_op_template.h // element_wise算子模板类
-│ └── elewise_host.h // element_wise算子host侧API
-├── broadcast // broadcast模板目录
-│ ├── common // broadcast模板各层公用文件目录
-│ │ ├── ...
-│ │ └── broadcast_common.h // broadcast的公共数据定义
-│ ├── broadcast_utils // broadcast模板辅助工具目录
-│ │ ├── ...
-│ │ └── broadcast_buf_pool.h // broadcast内存管理类
-│ ├── tiling // broadcast模板host层目录
-│ │ └── broadcast_tiling.h // broadcast tiling算法
-│ ├── broadcast_host.h // broadcast算子host侧API
-│ ├── broadcast_op_template.h // broadcast算子模板类
-│ └── broadcast_compute.h // broadcast计算模板
-└── reduce // reduce模板目录
- ├── common // reduce模板各层公用文件目录
- │ ├── ...
- │ └── reduce_common.h // reduce的公共数据定义
- ├── reduce_utils // reduce模板辅助工具目录
- │ ├── ...
- │ └── reduce_util.h // reduce计算辅助工具函数
- ├── tiling // reduce模板host层目录
- │ └── reduce_tiling.h // reduce tiling算法
- ├── reduce_host.h // reduce算子host侧API
- ├── reduce_op_template.h // reduce算子模板类
- └── reduce_sum.h // reduceSum计算模板
+├── common // 不同模板公用API和C++基本类的拓展模板目录
+├── elewise // Elementwise模板目录
+│ ├── common // Elementwise的公共数据定义
+│ ├── elewise_op_template.h // Elementwise算子模板类
+│ └── elewise_host.h // Elementwise算子host侧API
+├── broadcast // Broadcast模板目录
+│ ├── common // Broadcast模板各层公用文件目录
+│ ├── utils // Broadcast模板辅助工具目录
+│ ├── tiling // Broadcast模板host层目录
+│ ├── broadcast_host.h // Broadcast算子host侧API
+│ ├── broadcast_op_template.h // Broadcast算子模板类
+│ └── broadcast_compute.h // Broadcast计算模板
+└── reduce // Reduce模板目录
+ ├── common // Reduce模板各层公用文件目录
+ ├── utils // Reduce模板辅助工具目录
+ ├── tiling // Reduce模板host层目录
+ ├── reduce_host.h // Reduce算子host侧API
+ ├── reduce_op_template.h // Reduce算子模板类
+ └── reduce_sum.h // ReduceSum计算模板
```
## 2. examples
examples文件夹下提供了算子代码样例,包含算子实现的源码文件和测试用例配置和执行脚本。
@@ -50,7 +35,7 @@ examples
├── add // EleWise Add算子样例
│ ├── README.md
│ └── add.cpp
-├── add_with_scalar // EleWise + Scalar场景样例
+├── add_with_scalar // EleWise + Scalar算子样例
│ ├── README.md
│ └── add_with_scalar.cpp
├── broadcast_to // BroadcastTo算子样例
@@ -62,14 +47,21 @@ examples
└── sinh_custom // SinhCustom算子样例
├── README.md
└── sinh_custom.cpp
+└── tanh_grad // Tah_Grad算子样例
+ ├── README.md
+ └── tanh_grad.cpp
```
## 3. docs
docs文件夹下包含项目的所有文档。
```
doc/
-├── 1_quick_start.md // atvc快速上手指南
-├── 2_developer_guide.md // 开发指南
-├── code_organization.md // 目录结构说明
-└── data // 图片
-```
\ No newline at end of file
+├── 01_quick_start.md // ATVC快速上手指南
+├── 02_developer_guide.md // 开发指南
+├── 03_code_organization.md // 目录结构说明
+└── images // 图片
+```
+
+# Copyright
+
+Copyright (c) 2025 Huawei Technologies Co., Ltd.
\ No newline at end of file
diff --git a/atvc/docs/data/architecture.png b/atvc/docs/images/architecture.png
similarity index 100%
rename from atvc/docs/data/architecture.png
rename to atvc/docs/images/architecture.png
diff --git a/atvc/docs/data/atvc_user_case.png b/atvc/docs/images/atvc_user_case.png
similarity index 100%
rename from atvc/docs/data/atvc_user_case.png
rename to atvc/docs/images/atvc_user_case.png
diff --git a/atvc/docs/data/broadcast_components.png b/atvc/docs/images/broadcast_components.png
similarity index 100%
rename from atvc/docs/data/broadcast_components.png
rename to atvc/docs/images/broadcast_components.png
diff --git a/atvc/docs/data/broadcast_dataflow.png b/atvc/docs/images/broadcast_dataflow.png
similarity index 100%
rename from atvc/docs/data/broadcast_dataflow.png
rename to atvc/docs/images/broadcast_dataflow.png
diff --git a/atvc/docs/data/elewise_components.png b/atvc/docs/images/elewise_components.png
similarity index 100%
rename from atvc/docs/data/elewise_components.png
rename to atvc/docs/images/elewise_components.png
diff --git a/atvc/docs/data/elewise_dataflow.png b/atvc/docs/images/elewise_dataflow.png
similarity index 100%
rename from atvc/docs/data/elewise_dataflow.png
rename to atvc/docs/images/elewise_dataflow.png
diff --git a/atvc/docs/data/framework.png b/atvc/docs/images/framework.png
similarity index 100%
rename from atvc/docs/data/framework.png
rename to atvc/docs/images/framework.png
diff --git a/atvc/docs/data/reduce_components.png b/atvc/docs/images/reduce_components.png
similarity index 100%
rename from atvc/docs/data/reduce_components.png
rename to atvc/docs/images/reduce_components.png
diff --git a/atvc/docs/data/reduce_dataflow.png b/atvc/docs/images/reduce_dataflow.png
similarity index 100%
rename from atvc/docs/data/reduce_dataflow.png
rename to atvc/docs/images/reduce_dataflow.png
diff --git a/atvc/docs/images/reduce_tiling.png b/atvc/docs/images/reduce_tiling.png
new file mode 100644
index 0000000000000000000000000000000000000000..628694c0b699281016a49adadfe0f52bc296fe20
Binary files /dev/null and b/atvc/docs/images/reduce_tiling.png differ
diff --git a/atvc/examples/add/add.cpp b/atvc/examples/add/add.cpp
index f5a410a114299bbff4b620dd15bce57201812688..a3f1e65443f1c0bd3551f573f1cd49df4063fd9b 100644
--- a/atvc/examples/add/add.cpp
+++ b/atvc/examples/add/add.cpp
@@ -38,26 +38,6 @@ bool IsClose(float a, float b)
return (diff <= ABS_TOL) || (diff <= REL_TOL * std::max(std::abs(a), std::abs(b) + eps));
}
-// Add算子中有两个输入,一个输出。类型均为float
-using ADD_OPTRAITS = ATVC::OpTraits, ATVC::OpOutputs>;
-
-// 传入编译态参数ATVC::OpTraits
-template
-struct AddComputeFunc {
- /*
- 函数说明: c = a + b
- 参数说明:
- a : 参与运算的输入
- b : 参与运算的输入
- c : 参与运算的输出
- */
- template
- // 重载operator,提供给算子模板类调用
- __aicore__ inline void operator()(AscendC::LocalTensor a, AscendC::LocalTensor b, AscendC::LocalTensor c) {
- AscendC::Add(c, a, b, c.GetSize()); // 开发调用AscendC Api自行实现计算逻辑, 通过c.GetSize()获取单次计算的元素数量
- }
-};
-
void InitializeData(int32_t eleNum, std::vector &inputX, std::vector &inputY, std::vector &golden)
{
std::random_device rd;
@@ -75,7 +55,7 @@ bool VerifyResults(const std::vector &golden, const std::vector &o
{
for (int32_t i = 0; i < golden.size(); i++) {
if (!IsClose(golden[i], output[i])) {
- printf("Accuracy verification failed! The expected value of element "
+ printf("[ERROR]: Accuracy verification failed! The expected value of element "
"in index [%d] is %f, but actual value is %f.\n",
i,
golden[i],
@@ -94,21 +74,41 @@ void InitializeACL(aclrtContext &context, aclrtStream &stream, int32_t deviceId)
CHECK_ACL(aclrtCreateStream(&stream));
}
-void CleanACL(aclrtStream &stream, int32_t deviceId)
+void CleanACL(aclrtStream &stream, aclrtContext &context, int32_t deviceId)
{
CHECK_ACL(aclrtDestroyStream(stream));
+ CHECK_ACL(aclrtDestroyContext(context));
CHECK_ACL(aclrtResetDevice(deviceId));
CHECK_ACL(aclFinalize());
}
-void CleanUp(uint8_t *&zHost, uint8_t *&xDevice, uint8_t *&yDevice, uint8_t *&zDevice, uint8_t *¶mDevice)
+void CleanUp(uint8_t *&zHost, uint8_t *&xDevice, uint8_t *&yDevice, uint8_t *&zDevice)
{
CHECK_ACL(aclrtFree(xDevice));
CHECK_ACL(aclrtFree(yDevice));
CHECK_ACL(aclrtFree(zDevice));
- CHECK_ACL(aclrtFree(paramDevice));
CHECK_ACL(aclrtFreeHost(zHost));
}
+
+// Add算子中有两个输入,一个输出。类型均为float
+using AddOpTraits = ATVC::OpTraits, ATVC::OpOutputs>;
+
+// 传入编译态参数ATVC::OpTraits
+template
+struct AddComputeFunc {
+ /*
+ 函数说明: c = a + b
+ 参数说明:
+ a : 参与运算的输入
+ b : 参与运算的输入
+ c : 参与运算的输出
+ */
+ template
+ // 重载operator,提供给算子模板类调用
+ __aicore__ inline void operator()(AscendC::LocalTensor a, AscendC::LocalTensor b, AscendC::LocalTensor c) {
+ AscendC::Add(c, a, b, c.GetSize()); // 开发调用AscendC Api自行实现计算逻辑, 通过c.GetSize()获取单次计算的元素数量
+ }
+};
}
template
@@ -117,18 +117,22 @@ template
* a Device上的gm地址,指向Add算子第一个输入
* b Device上的gm地址,指向Add算子第二个输入
* c Device上的gm地址,指向Add算子第一个输出
- * param Device上的gm地址,指向运行态ATVC::EleWiseParam数据
+ * param 指向运行态ATVC::EleWiseParam数据
*/
-__global__ __aicore__ void AddCustom(GM_ADDR a, GM_ADDR b, GM_ADDR c, GM_ADDR param)
+__global__ __aicore__ void AddCustom(GM_ADDR a, GM_ADDR b, GM_ADDR c, ATVC::EleWiseParam param)
{
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);
// 将AddComputeFunc仿函数作为模板参数传入,实例化EleWiseOpTemplate模板类
auto op = ATVC::Kernel::EleWiseOpTemplate>();
- op.Run(a, b, c, param); // 按照输入、输出、param的顺序传入Run函数,实现GM->GM的数据计算
+ op.Run(a, b, c, ¶m); // 按照输入、输出、param的顺序传入Run函数,实现GM->GM的数据计算
}
int main()
{
+ if (!ATVC::Host::DebugCheck()) {
+ printf("[ERROR]: Element wise OpTraits check failed.\n");
+ return -1;
+ }
// totalCnt描述EleWise单输入的元素个数
int32_t eleNum = 8 * 1024;
size_t inputByteSize = static_cast(eleNum) * sizeof(float);
@@ -145,8 +149,8 @@ int main()
InitializeACL(context, stream, deviceId);
ATVC::EleWiseParam param;
- if (!ATVC::Host::CalcEleWiseTiling(eleNum, param)) {
- printf("Elewise tiling error.\n");
+ if (!ATVC::Host::CalcEleWiseTiling(eleNum, param)) {
+ printf("[ERROR]: Calculate Element wise tiling Failed.\n");
return -1;
};
auto elementParamSize = sizeof(param);
@@ -155,33 +159,29 @@ int main()
uint8_t *xDevice;
uint8_t *yDevice;
uint8_t *zDevice;
- uint8_t *paramDevice;
CHECK_ACL(aclrtMallocHost((void **)&zHost, outputByteSize));
CHECK_ACL(aclrtMalloc((void **)&xDevice, inputByteSize, ACL_MEM_MALLOC_HUGE_FIRST));
CHECK_ACL(aclrtMalloc((void **)&yDevice, inputByteSize, ACL_MEM_MALLOC_HUGE_FIRST));
CHECK_ACL(aclrtMalloc((void **)&zDevice, outputByteSize, ACL_MEM_MALLOC_HUGE_FIRST));
- CHECK_ACL(aclrtMalloc((void **)¶mDevice, elementParamSize, ACL_MEM_MALLOC_HUGE_FIRST));
CHECK_ACL(aclrtMemcpy(xDevice, inputByteSize, inputX.data(), inputByteSize, ACL_MEMCPY_HOST_TO_DEVICE));
- CHECK_ACL(aclrtMemcpy(yDevice, inputByteSize, inputY.data(), inputByteSize, ACL_MEMCPY_HOST_TO_DEVICE));
- CHECK_ACL(aclrtMemcpy(paramDevice, elementParamSize, reinterpret_cast(¶m),
- elementParamSize, ACL_MEMCPY_HOST_TO_DEVICE));
+ CHECK_ACL(aclrtMemcpy(yDevice, inputByteSize, inputY.data(), inputByteSize, ACL_MEMCPY_HOST_TO_DEVICE));
uint32_t blockNum = param.tilingData.blockNum;
- // 调用核函数
- AddCustom<<>>(xDevice, yDevice, zDevice, paramDevice);
+ // 调用核函数
+ AddCustom<<>>(xDevice, yDevice, zDevice, param);
CHECK_ACL(aclrtSynchronizeStream(stream));
CHECK_ACL(aclrtMemcpy(zHost, outputByteSize, zDevice, outputByteSize, ACL_MEMCPY_DEVICE_TO_HOST));
std::vector outputZ(reinterpret_cast(zHost), reinterpret_cast(zHost) + eleNum);
- CleanUp(zHost, xDevice, yDevice, zDevice, paramDevice);
- CleanACL(stream, deviceId);
+ CleanUp(zHost, xDevice, yDevice, zDevice);
+ CleanACL(stream, context, deviceId);
if (!VerifyResults(golden, outputZ)) {
return -1;
}
- printf("Accuracy verification passed.\n");
+ printf("[INFO]: Accuracy verification passed.\n");
return 0;
}
\ No newline at end of file
diff --git a/atvc/examples/add_with_broadcast/README.md b/atvc/examples/add_with_broadcast/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f49500d66f3d7b495549cdb9d09bb3530860e097
--- /dev/null
+++ b/atvc/examples/add_with_broadcast/README.md
@@ -0,0 +1,47 @@
+
+
+## 概述
+
+本样例介绍了利用ATVC实现带广播的Add单算子并完成功能验证
+
+
+## 样例支持产品型号:
+- Atlas A2训练系列产品
+
+## 目录结构
+
+| 文件名 | 描述 |
+| ------------------------------------------------------------ | ------------------------------------------------------------ |
+| [add_with_broadcast.cpp](./add_with_broadcast.cpp) | Add算子代码实现以及调用样例 |
+
+## 算子描述
+
+Add算子数学计算公式:$z = x + y$
+
+Add算子规格:
+
+