昇腾AI创新大赛训练营
14:00-14:30 基础知识-理论课
一、CANN 、达芬奇架构和算子
1.AI Core逻辑架构
达芬奇架构包含三部分:
1)计算类:矩阵计算单元(两个矩阵扔进去相乘)、向量计算单元、标量计算单元
2)控制类:整个计算过程提供了指令控制
3)存储类: 存储单元和数据通路构成了存储系统
AI core是昇腾AI处理器的核心
计算单元包括Vector计算单元、Cube计算单元等
2.计算单元
包含:
1)Scalar计算单元
2)Cube计算单元
异步指令流、同步信号流、计算数据流
数据从AI core并行计算有六条流水线
3.什么是算子-算子在神经网络中的定义
算子对应数学含义:
1)一个函数空间到另一个函数空间的映射,比如微分算子,不定积分算子
常见算子,Relu算子,Sigmoid算子
(计算机不能精确表达根号二,因为精度不够)
算子基本概念-总览
● 算子名称 用于标志网络中的某个算子- Conv1,Conv2
● 算子类型
● 数据容器
4.张量
Tensor用于存储算子输入数据和输出数据的容器,TensorDesc是对输入数据与输出数据的描述。
tensor的shape:(4,20,20,3)
长宽都是20,4张图片,像素点由红、绿、蓝三颜色组成,即数据排布格式
深度学习中,多维数据通过多维数组存储,比如卷积网络中特征图(Feature Map)通常用四维张量来表示
遍历一般是高维到低维进行的
基本概念-轴
轴(Axis):代表张量中维度的下标
shape是(5,6),axis=0表示张量中的第一维
二、实践(昇腾Ascend C快速入门)
指导:
更改ip地址:
远程登陆
实验截图:
1.连接板子
2.查看网络连接:
3.检查ip地址是否修改成功:
4.连接Mobaterm
14:30-16:00 矢量计算-理论课
1.什么是Ascend C算子
什么场景需要开发自定义算子?
一般场景下无需自己开发算子,但若是以下场景,开发者需要考虑自定义算子开发
推理场景,将第三方框架模型使用ATC工具转换为适用昇腾适配器
Device模块
Device负责指定计算运行的真实设备,包含aclrtSetDevice、arlrtResetDevice、aclrtGetDevice、aclrtGetRunMode等众多运行时接口用于进行device管理。
2.如何编写核函数
核函数是Ascend C算子设备侧的一种扩展
编写:使用变量类型限定符
规则或建议:核函数必须有void返回类型
核函数的调用:是C/C++函数调用语句的一种扩展:<<<...>>>
kernel_name<<<blockDim<<blockDim,12ctrl, srteam>>>(argument list);
blockDim
:规定核函数将会在几个核上执行
12ctrl:
保留参数,暂时设置为固定值nullptr
stream
:
编程模型—SPMD模型
Ascend C算子编程是SPMD的编程,将需要处理的数据拆分并在多个计算核心上运行;多个AI core 共享相同的指令代码
编程用到Vector_in和Vector_out
3.采用标准C++用法,基于类库API进行编程
基础API
高级API
Ascend C匹配用户开发习惯,采用标准C++语法和一组类库API进行编程
C++运算符重载
整个tensor参与计算:dst=src1+src2
tensor前n个数据计算:Add(dst,src1,src2,n)
tensor高维切分计算:Add(dst,src1,src2,mask,repeatTimes,{dataBlockStride,....}
高级API
编程范式–TPIPE并行计算
Programming Paradigm
Ascend
4.典型的计算范式
这里向我们展示了示例代码:
namespace ops {
class AddCustom : public OpDef {
public:
explicit AddCustom(const char* name) : OpDef(name)
{
// Add算子的第一个输入
this->Input("x")
.ParamType(REQUIRED) // 代表输入必选
.DataType({ ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32 }) // 输入支持的数据类型
.Format({ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND }) // 输入支持的数据格式
.UnknownShapeFormat({ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND }); // 未知Shape情况下的Format的默认值
// Add算子的第二个输入
this->Input("y")
.ParamType(REQUIRED)
.DataType({ ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32 })
.Format({ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND })
.UnknownShapeFormat({ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND });
this->Output("z")
.ParamType(REQUIRED)
.DataType({ ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32 })
.Format({ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND })
.UnknownShapeFormat({ ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND });
// 关联InferShape函数
this->SetInferShape(ge::InferShape);
// 关联Tiling函数
this->AICore()
.SetTiling(optiling::TilingFunc);
// 注册算子支持的AI处理器型号,请替换为实际支持的AI处理器型号
this->AICore().AddConfig("ascendxxx");
}
};
// 结束算子注册
OP_ADD(AddCustom);
} // namespace ops
基本的向量编程范式:CopyIn,CopyOut,Compute
基本的矩阵编程范式
复杂的矢量、矩阵编程范式
计算并行流动起来,实行流水任务,矢量编程任务间通信和同步,矢量中任务间通信与同步
执行加队列是因为,Enque本身是堵塞的,有一个Enque完成,vector才能启动;做同步是用队列实现
开发流程
算子分析
核函数定义
在add_custom核函数的实现中实例化KernelAdd算子类,调用Init()函数完成内存初始化
根据编程范式,输入输出队列
Init()函数实现
Process函数实现
创建local—copyin阶段
x+y=z compute阶段
–copyout阶段
c++,申请之后就要释放,(比如app越用越卡,爆了)
以上是关于内存的处理。
16:00-17:00 实践
cd ~/samples/operator/AddCustomSample/KernelLaunch/
cp -r AddKernelInvocationNeo/ test
cd test/
bash run.sh -r cpu -v Ascend310P1
观察结果
用MobaXTerm左侧的文件栏打开~/samples/operator/AddCustomSample/KernelLaunch/test/scripts/gen_data.py
修改其中代码:
input_x = np.random.uniform(1,10,[8,2048]).astype(np.float16)
golden = np.sinh(input_x).astype(np.float16)
保存
再打开add_custom.cpp
修改其中compute()函数,把“Add(xxxxxxxxxxxxxxxxx)”那一行注释掉,改成sinh的计算逻辑,用xLocal当输入,zLocal当输出,改完后保存。
测试方式:
bash run.sh -r cpu -v Ascend310P1
输出“test pass”即为修改成功。
感悟:
来到华为南京研究所,不仅感受到浓厚的科研氛围,舒适的办公环境,更是在短短几节课就收益良多,对Ascend算子有了初步的理解,并亲手连接板子进行实践,在老师的指导下进行测试,过程中虽然遇到了一些困难,最后却都能独立完成,我十分激动,对计算机知识也更加有兴趣,集训营第一天我就收获满满,期待明天的旅程,同时也坚定了自己以后做华为的一份子的决心!