昇腾架构及编程模型解读-I
计算单元是AI Core中提供强大算力的核心单元,相当于AI Core的主力军,主要包括:Cube Unit(矩阵计算单元)、Vector Unit(向量计算单元)和Scalar Unit(标量计算单元),完成AI Core中不同类型的数据计算。Ascend C编程范式把算子内部的处理程序,分成多个流水任务(Stage),以张量(Tensor)为数据载体,以队列(Queue)进行任务之间的通信与同
一、昇腾系列产品
昇腾910和昇腾310
昇腾310:主要面向端侧设备和边缘计算场景,具有低功耗、高效能的特点。它主要用于推理任务,有较高能效比。
昇腾910:针对数据中心和云计算场景设计,具有高性能的人工智能处理能力。其采用了先进的7nm工艺制程,集成了数千个处理核心,支持深度学习、推理推断等多种人工智能计算任务。其浮点运算性能高达256TFLOPS,支持FP16、INT8、INT4等多种精度,半精度(FP16)算力达到320 TFLOPS,整数精度(INT8)算力达到640 TOPS。昇腾910已被广泛应用于自动驾驶、AI一体机以及能源、金融、公共、交通、电信、制造、教育等行业。
二、达芬奇架构
1. 计算单元
计算单元是AI Core中提供强大算力的核心单元,相当于AI Core的主力军,主要包括:Cube Unit(矩阵计算单元)、Vector Unit(向量计算单元)和Scalar Unit(标量计算单元),完成AI Core中不同类型的数据计算。
2. 存储单元
- MTE: AI Core上有多个MTE(Memory Transfer Engine,存储转换引擎),包括MTE1、MTE2、MTE3。MTE是数据搬运单元,负责AI Core内部数据在不同Buffer之间的数据读写管理和格式转换的操作,比如填充(padding)、转置(transpose)、3D图像转2D矩阵(Img2Col)等
- BIU:BIU (Bus Interface Unit,总线接口单元),是AI Core的“大门”,负责AI Core与总线交互。BIU是AI Core从外部(L2缓冲区/双倍速率内存DDR/高速宽带内存HBM)读取数据以及往外写数据的出入口,负责把AI Core的读写请求转换为总线上的请求并完成协议交互等工作。
- L1 Buffer :L1缓冲区,通用内部存储,是AI Core内比较大的一块数据中转区,可暂存AI Core中需要反复使用的一些数据从而减少从总线读写的次数。某些MTE的数据格式转换功能,要求源数据必须位于L1 Buffer,例如3D图像转2D矩阵(Img2Col)操作。
- GPR通用寄存器(General-Purpose Register),标量计算的输入和输出。应用开发工程师不需要具体关注这些寄存器。由系统内部实现封装,程序访问Scalar Buffer并执行标量计算的时候,系统内部自动实现Scalar Buffer和GPR之间的同步。
- SPR专用寄存器(Special-Purpose Register),AI Core的一组配置寄存器。通过修改SPR的内容可以修改AI Core的部分计算行为。
三、昇腾编程模型
Ascend C编程范式把算子内部的处理程序,分成多个流水任务(Stage),以张量(Tensor)为数据载体,以队列(Queue)进行任务之间的通信与同步,以内存管理模块(Pipe)管理任务间的通信内存。
1. 流水任务
矢量算子编程范式把算子的实现流程分为3个基本任务:CopyIn,Compute,CopyOut,其中,CopyIn负责数据搬入操作,Compute负责矢量计算操作,CopyOut负责数据搬出操作。
2. 任务间通信和同步
不同的流水任务之间存在数据依赖,需要进行数据传递。Ascend C中使用Queue队列完成任务之间的数据通信和同步,Queue提供了EnQue、DeQue等基础API。Queue队列管理NPU上不同层级的物理内存时,用一种抽象的逻辑位置(QuePosition)来表达各个级别的存储(Storage Scope),代替了片上物理存储的概念,开发者无需感知硬件架构。矢量编程中Queue类型(逻辑位置)包括:VECIN、VECOUT。Ascend C使用GlobalTensor和LocalTensor作为数据的基本操作单元,它是各种指令API直接调用的对象,也是数据的载体。LocalTensor用于存放AI Core中Local Memory(内部存储)的数据。GlobalTensor用来存放Global Memory(外部存储)的全局数据。
矢量编程中的任务间通信和同步
矢量编程主要分为CopyIn、Compute、CopyOut三个任务:
- CopyIn任务中将输入数据从GlobalTensor搬运至LocalTensor后,需要使用EnQue将LocalTensor放入VECIN的Queue中
- Compute任务等待VECIN的Queue中LocalTensor出队之后才可以进行矢量计算,计算完成后使用EnQue将计算结果LocalTensor放入到VECOUT的Queue中
- CopyOut任务等待VECOUT的Queue中LocalTensor出队,再将其拷贝到GlobalTensor
矩阵编程:矩阵编程主要分为CopyIn,Split,Compute,Aggregate,CopyOut这5个任务。任务间进行数据传递时会使用到的逻辑位置示意图如下:
矩阵编程中的任务间通信和同步
3. 内存管理
任务间数据传递使用到的内存统一由内存管理模块Pipe进行管理。Pipe作为片上内存管理者,通过InitBuffer接口对外提供Queue内存初始化功能,开发者可以通过该接口为指定的Queue分配内存。Queue队列内存初始化完成后,需要使用内存时,通过调用AllocTensor来为LocalTensor分配内存给Tensor,当创建的LocalTensor完成相关计算无需再使用时,再调用FreeTensor来回收LocalTensor的内存。
内存管理示意图
4. 算子实现
CopyIn任务:将Global Memory上的输入Tensor xGm和yGm搬运至Local Memory,分别存储在xLocal, yLocal
Compute任务:对xLocal, yLocal执行加法操作,计算结果存储在zLocal中
CopyOut任务:将输出数据从zLocal搬运至Global Memory上的输出Tensor zGm中
CopyIn,Compute任务间通过VECIN队列inQueueX,inQueueY进行通信和同步
Compute,CopyOut任务间通过VECOUT队列outQueueZ进行通信和同步
pipe内存管理对象对任务间交互使用到的内存、临时变量使用到的内存统一进行管理
矢量Add算子开发流程
四、小结
从上面的开发流程来看,由于昇腾加速卡架构较为复杂,加速单元部件众多,算子开发流程较为复杂。其编程模型与使用C/C++语言的CPU编程模型和使用CUDA/OpenCL等的GPGPU编程模型差异较大。即使开发一个简单的矢量Add算子也需要大量的工作,而要取得比较好的性能又需要对架构非常了解其针对性进行大量优化,开发难度很大。
更多推荐
所有评论(0)