---
title: 入门示例
description: "本节以一个简单的Add算子为例，带您快速熟悉TIK算子的编写流程。"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/others/tbeaicpudevg/atlasopdev_10_0048.html
sourcePath: /source/zh/canncommercial/900/others/tbeaicpudevg/atlasopdev_10_0048.html
indexId: c715fbb2b06197ab5166ef494eb01acb6190c3a46453225fb4778c79c28959a373
---
# 入门示例

#### 目标

本节以一个简单的Add算子为例，带您快速熟悉TIK算子的编写流程。

本样例中，定义Add算子的两个输入的shape都为(128,)，数据类型为float16，运行目标为AI处理器的AI Core。


#### 算子分析

算子分析阶段，需要明确算子的数学表达式，输入/输出，调度流程设计，算子的实现函数名称等。

1. Add算子的数学表达式为：

```
y=x1+x2
```


  计算过程是：将两个输入参数相加，得到最终结果y并将其返回。

2. 明确输入和输出。

  - Add算子有两个输入一个输出。
  - 本样例中算子的输入支持的数据类型为float16，算子输出的数据类型与输入数据类型相同。
  - 本样例中，算子输入支持的shape为(128,)，输出shape与输入shape相同。
  - 算子输入支持的format为：NCHW,NC1HWC0,NHWC,ND。
    TIK算子开发方式对format不敏感，算子实现过程中不需要过多关注format。

3. Add算子的Schedule流程设计。

  a. 定义数据，分别在AI Core外部存储与内部存储中定义数据。
  b. 数据搬运，将外部存储中的数据搬运到AI Core内部存储的Unified Buffer中。由于输入数据的shape为(128,)，数据类型为float16，所以128*2=256Byte，远小于Unified Buffer的大小（例如Ascend310，Unified Buffer为256KB），所以执行一次搬运即可。
  c. 执行计算。
    调用双目矢量计算接口vec_add执行加法计算。

    由于Vector Unit一次最多可计算256Byte的数据，此样例数据为256Byte，所以让所有的Vector计算单元参与计算，执行一次计算即可。

4. 明确算子实现文件名称、算子实现函数名称以及算子的类型（OpType）。

  - 算子类型需要采用大驼峰的命名方式，即采用大写字符区分不同的语义。
  - 算子实现文件名称和算子定义函数名称，可选用以下任意一种命名规则：

    - 用户自定义，此时需要在      TBE算子信息库
中配置opFile.value与opInterface.value。
    - 不配置      TBE算子信息库
中的opFile.value与opInterface.value，FE会将OpType按照如下方式进行转换后进行算子文件名和算子函数名的匹配。
      转换规则如下：
      - 首字符的大写字符转换为小写字符。
        例如：Abc -> abc

      - 小写字符后的大写字符转换为下划线+小写字符。
        例如：AbcDef -> abc_def

      - 紧跟数字以及大写字符后的大写字符，作为同一语义字符串，查找此字符串后的第一个小写字符，并将此小写字符的前一个大写字符转换为下划线+小写字符，其余大写字符转换为小写字符。若此字符串后不存在小写字符，则直接将此字符串中的大写字符转换为小写字符。
        例如：ABCDef -> abc_def；Abc2DEf -> abc2d_ef；Abc2DEF -> abc2def；ABC2dEF -> abc2d_ef。


因此本例中，算子类型定义为AddTik；算子的实现文件名称及实现函数名称定义为add_tik。
通过以上分析，得到Add算子的设计规格如下：

**表1 Add算子设计规格**

| 算子类型（OpType） | AddTik | AddTik | AddTik | AddTik |
| --- | --- | --- | --- | --- |
| 算子输入 | name：x1 | shape： (128,) | data type： float16 | format： NCHW,NC1HWC0, NHWC,ND |
| 算子输入 | name：x2 | shape： (128,) | data type： float16 | format： NCHW,NC1HWC0, NHWC,ND |
| 算子输出 | name：y | shape： (128,) | data type： float16 | format： NCHW,NC1HWC0, NHWC,ND |
| TIK计算接口 | vec\_add | vec\_add | vec\_add | vec\_add |
| 实现函数名称 | add\_tik | add\_tik | add\_tik | add\_tik |


#### 算子代码实现

下面以此AddTik算子为例描述TIK程序的编写步骤：

1. Python模块导入。

```
from tbe import tik
import tbe.common.platform as tbe_platform
import numpy as np
```


  “tbe.tik”：提供了所有TIK相关的python函数，具体请参考CANN软件安装后文件存储路径的“python/site-packages/tbe/tik”。

2. 定义算子实现函数。

```
def add_tik():
```


  说明：本样例为了让大家对TIK有初步的认识，数据类型与形状都设置成了固定值，实际进行算子开发时，算子的数据是执行时才传入的，所以需要在算子实现函数定义时包含输入与输出数据基本信息，如TIK入口函数。

3. 设置AI处理器的版本，并指定运行目标。

```
# soc_version请设置为实际昇腾AI处理器的型号
tbe_platform.set_current_compile_soc_info(soc_version)
```


  “set_current_compile_soc_info”接口中的参数“core_type”用来指定核类型，默认值为“AiCore”，代表运行目标为AI Core。

4. 构建TIK DSL容器。

```
tik_instance = tik.Tik(disable_debug=False)
```


  因为此样例后续要进行功能调试，所以设置“disable_debug=False”使能调试开关。

5. 向TIK DSL容器中，插入TIK DSL语句。

  a. 在AI Core的外部存储和内部存储中定义输入数据、输出数据。

```
data_A = tik_instance.Tensor("float16", (128,), name="data_A", scope=tik.scope_gm)
data_B = tik_instance.Tensor("float16", (128,), name="data_B", scope=tik.scope_gm)
data_C = tik_instance.Tensor("float16", (128,), name="data_C", scope=tik.scope_gm)
data_A_ub = tik_instance.Tensor("float16", (128,), name="data_A_ub", scope=tik.scope_ubuf)
data_B_ub = tik_instance.Tensor("float16", (128,), name="data_B_ub", scope=tik.scope_ubuf)
data_C_ub = tik_instance.Tensor("float16", (128,), name="data_C_ub", scope=tik.scope_ubuf)
```


  b. 将外部存储中的数据搬入AI Core内部存储（比如Unified Buffer）中。

```
tik_instance.data_move(data_A_ub, data_A, 0, 1, 128*2 //32, 0, 0)
tik_instance.data_move(data_B_ub, data_B, 0, 1, 128*2 //32, 0, 0)
```


  c. 进行加法计算。

```
tik_instance.vec_add(128, data_C_ub[0], data_A_ub[0], data_B_ub[0], 1, 8, 8, 8)
```


  d. 将数据从AI Core内部存储中搬出到AI Core外部存储。

```
tik_instance.data_move(data_C, data_C_ub, 0, 1, 128*2 //32, 0, 0)
```


6. 将TIK DSL容器中的语句，编译成AI处理器可执行的代码，即算子的.o文件和算子描述.json文件。

```
tik_instance.BuildCCE(kernel_name="simple_add",inputs=[data_A,data_B],outputs=[data_C])
```

其中，

  - kernel_name：指明编译产生的二进制代码中的核函数名称。
  - inputs：存放程序的输入Tensor，为从外部存储中加载的数据，必须是Global Memory的存储类型。
  - outputs：存放程序的输出Tensor，对应计算后搬运到外部存储中的数据，必须是Global Memory的存储类型。
7. 返回TIK实例。

```
return tik_instance
```


#### 功能调试

1. 在算子实现文件下方添加功能调试代码，用于对算子实现进行验证。

```
if __name__ == "__main__":
# 调用TIK算子实现函数
tik_instance = add_tik()
# 初始化数据，为128个float16类型的数字1的一维矩阵
data = np.ones((128,), dtype=np.float16)
feed_dict = {"data_A": data, "data_B": data}
# 启动功能调试
data_C, = tik_instance.tikdb.start_debug(feed_dict=feed_dict, interactive=True)
# 打印输出数据
print(data_C)
```


2. 运行TIK Python程序。
  python3 add_tik.py

  输入data_A和data_B分别为128个float16类型的数字1的一维矩阵，展示的输出data_C如下所示：

```
[TIK]>c
[2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.
2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.
2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.
2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.
2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.
2. 2. 2. 2. 2. 2. 2. 2.]
```


  以上仅对大致编程过程进行展示，后续会对上述实例中各接口、各参数的含义进行详细描述。
