• 参考:《昇腾AI处理器架构与编程——深入理解CANN技术原理及应用》

昇腾 AI 处理器

背景

  • 为了满足当今飞速发展的深度神经网络对芯片算力的需求, 华为公司于 2018 年推出了昇腾系列 AI 处理器 (NPU, Neural-Network Processing Units), 可以对整型数 (INT8、INT4) 或浮点数 (FP16) 提供强大高效的乘加计算力
  • 由于昇腾 AI 处理器具有强大的算力并且在硬件体系结构上对于深度神经网络进行了特殊的优化, 从而使之能以极高的效率完成目前主流深度神经网络的前向计算, 因此在智能终端等领域拥有广阔的应用前景

主要的架构组成部件

  • 昇腾 AI 处理器本质上是一个片上系统, 主要可以应用在与图像、视频、语音、文字处理相关的场景。其主要的架构组成部件包括特制的计算单元、大容量的存储单元和相应的控制单元
    • Multi-Core (AI CPU + Control CPU): 昇腾 AI 处理器集成了多个 CPU 核心, 每个核心都有独立的 L1 和 L2 Cache, 所有核心共享一个片上 L3 Cache
      • 集成的 CPU 核心按照功能可以划分为专用于控制处理器整体运行的控制 CPU 和专用于承担非矩阵类复杂计算的 AI CPU。两类任务占用的 CPU 核数可由软件根据系统实际运行情况动态分配
    • AI Core: 除了 CPU 之外,该处理器真正的算力担当是采用了达芬奇架构的 AI Core。这些 AI Core 通过特别设计的架构和电路实现了高通量、大算力和低功耗, 特别适合处理深度学习中神经网络必需的常用计算, 如矩阵相乘等
      • 8 MB 片上 L2 Cache: 针对深度神经网络参数量大、中间值多的特点, 该处理器还特意为 AI 计算引擎配备了片上 L2 缓冲区, 用来将大量需要复用的中间数据缓存在片上,进而提供高带宽、低延迟、高效率的数据交换和访问,同时也有助于降低系统整体功耗
    • 任务调度器 (Task Scheduler, TS): 实现计算任务在 AI Core 上的高效分配和调度的专用 CPU。该 CPU 专门服务于 AI Core 和 AI CPU, 而不承担任何其他的事务和工作
    • 数字视觉预处理模块 (HW) (Digital Vision Pre-Processing, DVPP): 视频和图像数据在进入昇腾 AI 处理器的计算引擎处理之前, 需要生成满足处理要求的输入格式、分辨率等, 因此需要调用数字视觉预处理模块进行预处理以实现格式和精度转换等要求 (对应于每一种不同的功能都会设计一个相应的硬件电路模块来完成计算工作)
      • 视频编解码: 视频解码 (Video Decoder,VDEC)、视频编码 (Video Encoder,VENC) (支持 4K 分辨率)
      • 图像编解码: JPEG 编解码 (JPEG Decoder/Encoder, JPEGD/E)、PNG 解码 (PNG Decoder, PNGD)
      • 图像预处理 可以完成对输入图像的上/下采样、裁剪、色调转换等多种功能

AI 计算引擎 = AI Core + AI CPU

在这里插入图片描述

可扩展性

  • DDR/HBM 接口: 处理器可以采用 LPDDR4 高速主存控制器接口, 价格较低。目前主流片上系统处理器的主存一般由 DDR (Double Data Rate,双倍速率内存) 或 HBM (High Bandwidth Memory, 高带宽存储器) 构成, 用来存放大量的数据
  • PCIe 总线接口: 当该处理器作为计算服务器的加速卡使用时,会通过 PCIe 总线接口和服务器其他单元实现数据互换
    • 由于采用了模块化的设计,可以很方便地通过叠加模块的方法提高后续芯片的计算力。各个模块间通过基于 CHI 协议的片上环形总线相连, 实现模块间的数据连接通路并保证数据的共享和一致性
  • 其他通用的外设接口模块包括 USB、磁盘、网卡、GPIO、I2C 和电源管理接口等

达芬奇架构 (DaVinci Architecture)

Domain Specific Architecture, DSA (特定域架构)

  • 达芬奇架构基于 ARM 架构,是华为自研的面向 AI 计算特征的全新计算架构
    • 不同于传统的支持通用计算的 CPU 和 GPU, 也不同于专用于某种特定算法的专用芯片 ASIC, 达芬奇架构本质上是为了适应某个特定领域中的常见应用和算法

AI Core (达芬奇架构)

  • 昇腾 AI 处理器的计算核心主要由 AI Core 构成, 负责执行标量向量张量相关的计算密集型算子。AI Core 采用了达芬奇架构
    • 计算部件: 矩阵计算单元 (Cube Unit)、向量计算单元 (Vector Unit) 和标量计算单元 (Scalar Unit)
      • 这三种计算单元分别对应了张量、向量和标量三种常见的计算模式, 形成了三条独立的执行流水线, 在系统软件的统一调度下互相配合达到优化的计算效率
    • 片上缓冲区: 这些存储资源和相关联的计算资源相连,或者和总线接口单元 (Bus Interface Unit, BIU) 相连,从而可以获得外部总线上的数据;具体来说,片上缓冲区包括:
      • 用来放置整体图像特征数据、网络参数以及中间结果的输入缓冲区 (Input Buffer, IB) 和输出缓冲区(Output Buffer, OB)
      • 提供一些临时变量的高速寄存器单元, 这些寄存器单元位于各个计算单元中
    • 存储转换单元 (Memory Transfer Unit, MTE): 设置于输入缓冲区之后, 主要的目的是为了以极高的效率实现数据格式的转换
      • 例如卷积操作中为了加速卷积运算,需要用 Img2Col 函数将卷积操作转化为矩阵乘积操作。存储转换单元将 Img2Col 函数固化在了硬件电路中, 极大地提升了 AI Core 的执行效率, 从而能够实现不间断的卷积计算 (与之相对的,GPU 是以软件来实现 Img2Col 函数的,因此效率不如 AI Core)
    • 控制单元: 主要包括系统控制模块、标量指令处理队列、指令发射模块、矩阵运算队列、向量运算队列、存储转换队列和事件同步模块
      • 系统控制模块负责指挥和协调 AI Core 的整体运行模式、配置参数和实现功耗控制等
      • 标量指令处理队列主要实现控制指令的译码
      • 指令发射模块: 指令被译码后,就会通过指令发射模块顺次发射出去。根据指令的不同类型, 指令将会分别发送到矩阵运算队列向量运算队列存储转换队列 (标量指令会驻留在标量指令处理队列中进行后续执行)
        • 四条独立的流水线:矩阵运算队列、向量运算队列和存储转换队列三个队列中的指令依据 FIFO 的方式分别输出到矩阵计算单元、向量计算单元和存储转换单元进行相应的计算。最终形成了标量、向量、张量、存储转换四条独立的流水线, 可以并行执行以提高指令执行效率
      • 事件同步模块: 如果指令执行过程中出现依赖关系或者有强制的时间先后顺序要求,则可以通过事件同步模块来调整和维护指令的执行顺序
        • 事件同步模块完全由软件控制, 在软件编写的过程中可以通过插入同步符的方式来指定每一条流水线的执行时序从而达到调整指令执行顺序的目的
  • 在 AI Core 中,存储单元为各个计算单元提供被转置过并符合要求的数据, 计算单元返回运算的结果给存储单元, 控制单元为计算单元和存储单元提供指令控制, 三者相互协调合作完成计算任务
    在这里插入图片描述

计算单元

  • 计算单元是AI Core中提供强大算力的核心单元,相当于AI Core的主力军。AI Core计算单元主要包含矩阵计算单元向量计算单元标量计算单元累加器。矩阵计算单元和累加器主要完成与矩阵相关的运算,向量计算单元负责执行向量运算,标量计算单元主要负责各类型的标量数据运算和程序的流程控制
    在这里插入图片描述

矩阵计算单元

矩阵乘法

  • 由于常见的深度神经网络算法中大量的使用了矩阵计算, 达芬奇架构中特意对矩阵计算进行了深度的优化并定制了相应的矩阵计算单元来支持高吞吐量的矩阵处理
    在这里插入图片描述
CPU vs. GPU vs. Ascend

CPU 中计算矩阵乘法

  • 在传统 CPU 中计算矩阵乘法的典型代码如下. 该程序需要用到 3 个循环进行一次完整的矩阵相乘计算, 如果在一个单发射的 CPU 上执行至少需要 M × K × N M ×K ×N M×K×N 个时钟周期才能完成, 当矩阵非常庞大时执行过程极为耗时
    • 例如要实现一个 16 × 16 16×16 16×16 矩阵与另一个 16 × 16 16×16 16×16 矩阵的乘法, 至少需要 1 6 3 \boldsymbol {16^3} 163 个时钟周期
for(int m = 0; m < M; m++)
	for(int n = 0; n < N; n++)
		for(int k = 0; k < K; k++)
			C[m][n] += A[m][k] * B[k][n];

GPU 中计算矩阵乘法

  • GPU 采用通用矩阵乘法 (GEMM) 的方法来实现矩阵乘法
    • 例如要实现一个 16 × 16 16×16 16×16 矩阵与另一个 16 × 16 16×16 16×16 矩阵的乘法, 需要安排 256 个并行的线程, 并且每一个线程都可以独立计算完成结果矩阵中的一个输出点。假设每一个线程在一个时钟周期内可以完成一次乘加运算, 则 GPU 完成整个矩阵计算需要 16 个时钟周期, 这个延时是传统 GPU 无法避免的瓶颈

Ascend 中计算矩阵乘法

  • AI Core 针对矩阵乘法运算做了深度的优化。达芬奇架构在 AI Core 中特意设计了矩阵计算单元作为昇腾 AI 处理器的核心计算模块, 意图高效解决矩阵计算的瓶颈问题
    • 矩阵计算单元提供强大的并行乘加计算能力, 使得 AI Core 能够高速处理矩阵计算问题。通过精巧设计的定制电路和极致的后端优化手段, 矩阵计算单元可以用一条指令完成两个 16 × 16 16×16 16×16 矩阵的相乘运算 (标记为 16^3, 也是 Cube 这一名称的来历), 等同于在极短时间内进行了 1 6 3 = 4096 16^3=4096 163=4096 个乘加运算
    • 也就是说,昇腾 AI 处理器要实现一个 16 × 16 16×16 16×16 矩阵与另一个 16 × 16 16×16 16×16 矩阵的乘法, 只需要 1 个时钟周期
改变矩阵的存储方式来提升矩阵计算的效率

C = A × B C=A× B C=A×B

  • 在 CPU 计算过程中, 矩阵 A A A 是按照行的方式进行扫描, 矩阵 B B B 以列的方式进行扫描。而内存读取的方式是具有极强的数据局部性特征的, 考虑 Row-Major 的矩阵存储方式 (即无论矩阵 A A A 还是矩阵 B B B 都会按照行的方式进行存放), 当读取内存中某个数时会打开内存中相应的一整行并且把同一行中所有的数都读取出来。这种内存的读取方式对矩阵 A A A 是非常高效的,但是对于矩阵 B B B 的读取却显得非常不友好, 因为代码中矩阵 B B B 是需要一列一列读取的
    • 为此需要将矩阵 B B B 的存储方式转成按列存储 (Column-Major), 这样才能够符合内存读取的高效率模式
  • 因此, 在矩阵计算中往往通过改变某个矩阵的存储方式来提升矩阵计算的效率
矩阵计算单元 (矩阵乘法)
  • 矩阵计算单元在完成 C = A × B C=A ×B C=A×B 的矩阵运算时,会事先将矩阵 A A A 按行存放在输入缓冲区中, 同时将矩阵 B B B 按列存放在输入缓冲区中, 通过矩阵计算单元计算后得到的结果矩阵 C C C 按行存放在输出缓冲区中
  • 在矩阵相乘运算中, 矩阵 C C C 的第一元素由矩阵 A A A 的第一行的 16 个元素和矩阵 B B B 的第一列的 16 个元素由矩阵计算单元子电路进行 16 次乘法和 15 次加法运算得出。矩阵计算单元中共有 256 个矩阵计算子电路, 可以由一条指令并行完成矩阵 C C C 的 256 个元素计算
    在这里插入图片描述

由于达芬奇架构采用了固定的 16 × 16 16×16 16×16 大小的矩阵计算单元, 所以在处理规模较小的网络时, 容易造成矩阵计算单元算力难以发挥、硬件资源利用率低下的问题


操作数类型

  • 除了支持 FP16 类型的运算,矩阵计算单元也可以支持诸如 INT8 等更低精度类型的输入数据。程序员可以根据深度神经网络对于精度的要求来适当调整矩阵计算单元的运算精度,从而可以获得更加出色的性能
    • 对于 INT8, 矩阵计算单元可以一次完成一个 16 × 32 16×32 16×32 矩阵与一个 32 × 16 32×16 32×16 的矩阵相乘运算
    • 矩阵计算单元还同时支持 UINT8U2 数据类型计算。在 U2 数据类型下, 只支持对两比特 U2 类型权重的计算。由于现代轻量级神经网络权重为两比特的情况比较普遍,所以在计算中先将 U2 权重数据转换成 FP16 或者 INT8 后再进行计算
累加器单元 (偏置计算)
  • 在有关矩阵的处理上, 通常在进行完一次矩阵乘法后还需要和上一次的结果进行累加, 以实现类似 C = A × B + C C=A×B+C C=A×B+C 的运算。矩阵计算单元的设计也考虑到了这种情况, 为此专门在矩阵计算单元后面增加了一组累加器单元, 可以实现将上一次的中间结果与当前的结果相累加, 总共累加的次数可以由软件控制, 并在累加完成之后将最终结果写入输出缓冲区
    • 例如在卷积计算过程中, 累加器可以完成加偏置的累加计算
大小超过 16 × 16 16\times16 16×16 的矩阵乘法
  • 矩阵计算单元可以快速完成 16 × 16 16×16 16×16 的矩阵相乘。但当超过 16 × 16 16×16 16×16 大小的矩阵利用该单元进行计算时, 则需要事先按照特定的数据格式进行矩阵的存储, 并在计算的过程中以特定的分块方式进行数据的读取
    • 如下图所示, 矩阵 A A A 展示的切割和排序方式称作 “大 Z 小 Z”, 直观地看就是矩阵 A A A 的各个分块之间按照行的顺序排序,称为 “大 Z” 方式; 而每个块的内部数据也是按照行的方式排列, 称为 “小 Z” 方式
    • 与之形成对比的是矩阵 B B B 的各个分块之间按照行排序,而每个块的内部按照列排序, 称为 “大 Z 小 N” 的排序方式
    • 按照矩阵计算的一般法则,昇腾 AI 处理器内部专用电路可以实现将如此排列的 A A A B B B 矩阵相乘之后得到结果矩阵 C C C, 而矩阵 C C C 将会呈现出各个分块之间按照列排序,而每个块内部按照行排序的格式,称为 “大 N 小 Z” 的排列方式
      在这里插入图片描述
分块平铺处理 (Tiling)
  • 受限于片上缓存的容量, 当一次难以装下整个矩阵 B B B 时, 可以将矩阵 B B B 进行分块,划分成为 b 0 \boldsymbol b_0 b0 b 1 \boldsymbol b_1 b1 b 2 \boldsymbol b_2 b2 b 3 \boldsymbol b_3 b3 等多个子矩阵。而每一个子矩阵的大小都可以适合一次性存储到芯片上的缓存中并与矩阵 A A A 进行计算从而得到结果子矩阵
    • 例如 A B = A [ b 1 b 2 . . . b n ] = [ A b 1 A b 2 . . . A b n ] AB=A\begin{bmatrix}\boldsymbol b_1&\boldsymbol b_2&...&\boldsymbol b_n\end{bmatrix}=\begin{bmatrix}A\boldsymbol b_1&A\boldsymbol b_2&...&A\boldsymbol b_n\end{bmatrix} AB=A[b1b2...bn]=[Ab1Ab2...Abn],每一次都读入 B B B 的一个子矩阵 b i \boldsymbol b_i bi 并计算 A b i A\boldsymbol b_i Abi
      • 这样做的目的是充分利用数据的局部性原理, 尽可能地把缓存中的子矩阵数据重复使用完毕并得到所有相关的子矩阵结果后, 再读入新的子矩阵, 开始新的周期。如此往复, 可以依次将所有的子矩阵都一一搬运到缓存中, 完成整个矩阵计算的全过程, 最终得到结果矩阵 C C C
    • 再例如,若矩阵 A A A B B B 都不能一次读入片上缓存,则如下图所示, 可将矩阵 A A A 和矩阵 B B B 都等分成同样大小的块, 每一块都可以是一个 16 × 16 16×16 16×16 的子矩阵, 排不满的地方可以通过补零实现。首先求 C 1 C_1 C1 结果子矩阵, 需要分两步计算: 第一步将 A 1 A_1 A1 B 1 B_1 B1 搬移到矩阵计算单元中,并算出 A 1 × B 1 A_1×B_1 A1×B1 的中间结果; 第二步将 A 2 A_2 A2 B 2 B_2 B2 搬移到矩阵计算单元中, 再次计算 A 2 × B 2 A_2×B_2 A2×B2, 并把计算结果累加到上一次 A 1 × B 1 A_1×B_1 A1×B1 的中间结果, 这样才完成结果子矩阵 C 1 C_1 C1 的计算, 之后将 C 1 C_1 C1 写入输出缓冲区。由于输出缓冲区容量也有限, 所以需要尽快将 C 1 C_1 C1 子矩阵写入内存中,便于留出空间接收下一个结果子矩阵 C 2 C_2 C2。同理,以此类推可以完成整个大规模矩阵乘法的运算
      • 上述计算方式是最基本的分块矩阵计算方式,没有复用数据。在昇腾 AI 处理器的实际计算过程中, 会在一定程度上复用矩阵 A A A 和矩阵 B B B 的分块矩阵
        在这里插入图片描述

  • 矩阵分块的优点是充分利用了缓存的容量, 并最大程度利用了数据计算过程中的局部性特征, 可以高效地实现大规模的矩阵乘法计算

向量计算单元

  • AI Core 中的向量计算单元主要负责完成和向量相关的运算, 能够实现向量和标量, 或双向量之间的计算, 功能覆盖各种基本和多种定制的计算类型, 主要包括 FP32、FP16、INT32 和 INT8 等数据类型的计算
    • 所有这些操作都可以通过软件配合相应的向量单元指令来实现
    • 对向量计算单元而言, 输入的数据可以不连续, 这取决于输入数据的寻址模式: 向量计算单元支持的寻址模式包括了向量连续寻址固定间隔寻址; 在特殊情形下,对于地址不规律的向量,向量计算单元也提供了向量地址寄存器寻址来实现向量的不规则寻址
      在这里插入图片描述

  • 如下图所示,向量计算单元可以作为矩阵计算单元和输出缓冲区之间的数据通路和桥梁:
    • 矩阵运算完成后的结果在向输出缓冲区传递的过程中,向量计算单元可以顺便完成在深度神经网络尤其是卷积神经网络计算中常用的 ReLU 激活函数、池化等功能并实现数据格式的转换
    • 经过向量计算单元处理后的数据可以被写回到输出缓冲区或者矩阵计算单元中, 以等待下一次运算
    • 向量计算单元提供了丰富的计算功能,也可以实现很多特殊的计算函数, 从而和矩阵计算单元形成功能互补, 全面完善了 AI Core 对非矩阵类型数据计算的能力
      在这里插入图片描述

标量计算单元

  • 标量计算单元负责完成 AI Core 中与标量相关的运算。它相当于一个微型 CPU, 控制整个 AI Core 的运行:
    • 标量计算单元可以对程序中的循环进行控制, 可以实现分支判断, 其结果可以通过在事件同步模块中插入同步符的方式来控制 AI Core 中其他功能性单元的执行流程
    • 它还为矩阵计算单元或向量计算单元提供数据地址和相关参数的计算, 并且能够实现基本的算术运算。其他复杂度较高的标量运算则由专门的 AI CPU 通过算子完成
  • 在标量计算单元周围配备了多个通用寄存器 (General Purpose Register, GPR) 和专用寄存器 (Special Purpose Register, SPR)
    • 通用寄存器可以用于变量或地址的寄存, 为算术逻辑运算提供源操作数和存储中间计算结果
    • 专用寄存器的设计是为了支持指令集中一些指令的特殊功能, 一般不可以直接访问, 只有部分可以通过指令读写。软件可以通过监视这些专用寄存器来控制和改变 AI Core 的运行状态和模式
      • AI Core 中具有代表性的专用寄存器包括 CoreID (用于标识不同的 AI Core), VA (向量地址寄存器) 以及 STATUS (AI Core 运行状态寄存器) 等

存储系统

  • 众所周知, 几乎所有的深度学习算法都是数据密集型的应用。对于昇腾 AI 处理器来说, 合理设计数据存储和传输结构对于系统的最终运行性能至关重要。不合理的设计往往成为系统性能瓶颈, 从而白白浪费片上海量的计算资源
  • AI Core 的片上存储单元和相应的数据通路构成了存储系统。AI Core 通过各种类型的分布式缓冲区之间的相互配合, 为深度神经网络计算提供了大容量和及时的数据供应, 高效适配计算单元的强大算力, 为整体计算性能消除了数据流传输的瓶颈, 综合提升了 AI Core 的整体计算性能, 从而支撑了深度学习计算中所需要的大规模、高并发数据的快速有效提取和传输
    • 与谷歌 TPU 设计中的统一缓冲区设计理念相类似, AI Core 采用了大容量的片上缓冲区设计, 通过增大的片上缓存数据量来减少数据从片外存储系统搬运到 AI Core 中的频次, 从而可以降低数据搬运过程中所产生的功耗, 有效控制了整体计算的能耗
    • 达芬奇架构通过存储转换单元中内置的定制电路, 在进行数据传输的同时, 就可以实现诸如 Img2Col 或者其他类型的格式转化操作, 不仅节省了格式转换过程中的消耗, 同时也节省了数据转换的指令开销。这种能将数据在传输的同时进行转换的指令称为随路指令。硬件单元对随路指令的支持为程序设计提供了便捷性

存储单元

  • AI Core 中的存储单元由存储控制单元、缓冲区和寄存器组成:
    • 存储控制单元
      • 通过总线接口可以直接读写 AI Core 之外的更低层级的 L2 缓存, 并且也可以直通到 DDR 或 HBM, 从而可以直接读写内存。总线接口在这个过程中可以将 AI Core 内部发出的读写请求转换为符合总线要求的外部读写请求, 并完成协议的交互和转换等工作
      • 输入数据从总线接口读入后就会经由存储转换单元进行处理。存储转换单元作为 AI Core 内部数据通路的传输控制器, 负责 AI Core 内部数据在不同缓冲区之间的读写管理, 以及完成一系列的格式转换操作, 如补零、Img2Col、转置、解压缩等。存储转换单元还可以控制 AI Core 内部的输入缓冲区, 从而实现局部数据的缓存
    • 缓冲区包括了用于暂存原始图像特征数据的输入缓冲区, 以及处于中心的输出缓冲区来暂存各种形式的中间数据和输出数据
      • 输入缓冲区: 在深度神经网络计算中, 由于输入图像特征数据通道众多且数据量庞大, 往往会采用输入缓冲区来暂时保留需要频繁重复使用的数据, 以达到节省功耗、提高性能的效果。当输入缓冲区被用来暂存使用率较高的数据时, 就不需要每次通过总线接口到 AI Core 的外部读取, 从而在减少总线上数据访问频次的同时也降低了总线上产生拥堵的风险。另外, 当存储转换单元进行数据的格式转换操作时, 会产生巨大的带宽需求, 达芬奇架构要求源数据必须被存放于输入缓冲区中, 才能够进行格式转换, 而输入缓冲控制器负责控制数据流入输入缓冲区中。输入缓冲区的存在有利于将大量用于矩阵计算的数据一次性地搬移到 AI Core 内部, 同时利用固化的硬件大幅提升了数据格式转换的速度, 避免了矩阵计算单元的阻塞, 消除了由于数据转换过程缓慢而带来的性能瓶颈
      • 输出缓冲区: 在神经网络中往往可以把每层计算的中间结果放在输出缓冲区中, 从而在进入下一层计算时方便地获取数据。由于通过总线读取数据的带宽低、延迟大, 通过充分利用输出缓冲区就可以大大提升计算效率
    • AI Core 中的各类寄存器资源主要是标量计算单元在使用。同时,在矩阵计算单元还包含有直接提供数据的寄存器, 提供当前正在进行计算的大小为 16 × 16 16×16 16×16左、右输入矩阵。在矩阵计算单元之后,累加器也含有结果寄存器, 用于缓存当前计算的大小为 16 × 16 16×16 16×16 的结果矩阵。在累加器配合下可以不断地累积前次矩阵计算的结果,这在卷积神经网络的计算过程中极为常见。在软件的控制下, 当累积的次数达到要求后, 结果寄存器中的结果可以被一次性地传输到输出缓冲区中
      在这里插入图片描述
  • 所有的缓冲区和寄存器的读写都可以通过底层软件显式地控制,有经验的程序员可以通过巧妙的编程方式来防止存储单元中出现读写冲突而影响流水线的进程。对于类似卷积和矩阵这样规律性强的计算模式,高度优化的程序可以实现全程无阻塞的流水线执行

数据通路

  • 数据通路指的是 AI Core 在完成一个计算任务时, 数据在 AI Core 中的流通路径

  • 下图展示了达芬奇架构中一个 AI Core 内完整的数据传输路径。这其中包含了 DDR 或 HBM 及 L2 缓冲区, 这些都属于 AI Core 核外的数据存储系统。图中其他各类型的数据缓冲区都属于核内存储系统
    在这里插入图片描述
    • 核外存储系统中的数据可以通过 LOAD 指令被直接搬运到矩阵计算单元中进行计算, 输出的结果会被保存在输出缓冲区中。除了直接将数据通过 LOAD 指令发送到矩阵计算单元中,核外存储系统中的数据也可以通过 LOAD 指令先行传入输入缓冲区, 再通过其他指令传输到矩阵计算单元中。这样做的好处是利用大容量的输入缓冲区来暂存需要被矩阵计算单元反复使用的数据
    • 矩阵计算单元和输出缓冲区之间是可以相互传输数据的。由于矩阵计算单元容量较小, 部分矩阵运算结果可以写入输出缓冲区中, 从而提供充裕的空间容纳后续的矩阵计算。当然也可以将输出缓冲区中的数据再次搬回矩阵计算单元作为后续计算的输入。输出缓冲区和向量计算单元、标量计算单元以及核外存储系统之间都有一条独立的双向数据通路。输出缓冲区中的数据可以通过专用寄存器或通用寄存器进出标量计算单元
    • 值得注意的是, AI Core 中的所有数据如果需要向外部传输,都必须经过输出缓冲区, 才能够被写回到核外存储系统中。在 AI Core 中并没有一条从输入缓冲区直接写入输出缓冲区的数据通路。因此输出缓冲区作为 AI Core 数据流出的闸口, 能够统一地控制和协调所有核内数据的输出
      • 例如输入缓冲区中的图像特征数据如果需要被输出到系统内存中, 则需要先经过矩阵计算单元处理后存入输出缓冲区中, 最终从输出缓冲区写回到核外存储系统中

多进单出的数据通路

  • 达芬奇架构数据通路的特点是多进单出, 数据流入 AI Core 可以通过多条数据通路, 可以从外部直接流入矩阵计算单元、输入缓冲区和输出缓冲区中的任何一个, 流入路径的方式比较灵活, 在软件的控制下由不同数据流水线分别进行管理。而数据输出则必须通过输出缓冲区,最终才能输出到核外存储系统中。这样设计的理由主要是考虑到了深度神经网络计算的特征
    • AI Core 中设计多个输入数据通路的好处是对输入数据流的限制少, 能够为计算源源不断地输送源数据:神经网络在计算过程中, 往往输入的数据种类繁多并且数量巨大, 比如多个通道、多个卷积核的权重和偏置值以及多个通道的特征值等,而 AI Core 中对应这些数据的存储单元可以相对独立且固定, 可以通过并行输入的方式来提高数据流入的效率, 满足海量计算的需求
    • 与此相反, 深度神经网络计算将多种输入数据处理完成后往往只生成输出特征矩阵, 数据种类相对单一。根据神经网络输出数据的特点, 在AI Core中设计了单输出的数据通路, 一方面节约了芯片硬件资源; 另一方面可以统一管理输出数据, 将数据输出的控制硬件降到最低

  • 综上所述, 达芬奇架构中的各个存储单元之间的数据通路以及多进单出的核内外数据交换机制是在深入研究了以卷积神经网络为代表的主流深度学习算法后开发出来的, 目的是在保障数据良好的流动性前提下, 减少芯片成本、提升计算性能、降低控制复杂度

控制单元

  • 在达芬奇架构下, 控制单元为整个计算过程提供了指令控制, 相当于 AI Core 的司令部, 负责整个 AI Core 的运行。控制单元的主要组成部分为系统控制模块指令缓存标量指令处理队列指令发射模块矩阵运算队列向量运算队列存储转换队列事件同步模块
    在这里插入图片描述

指令缓存

  • 在指令执行过程中,可以提前预取后续指令, 并一次读入多条指令进入缓存, 提升指令执行效率。多条指令从系统内存通过总线接口进入到 AI Core 的指令缓存中并等待后续硬件快速自动解码或运算

标量指令处理队列指令发射模块

  • 指令被解码后便会被导入标量队列中, 实现地址解码与运算控制。这些指令包括矩阵计算指令、向量计算指令以及存储转换指令等。在进入指令发射模块之前, 所有指令都作为普通标量指令被逐条顺次处理。标量队列将这些指令的地址和参数解码配置好后, 由指令发射模块根据指令的类型分别发送到对应的指令执行队列中, 而标量指令会驻留在标量指令处理队列中进行后续执行

矩阵运算队列向量运算队列存储转换队列

  • 指令执行队列由矩阵运算队列向量运算队列存储转换队列组成。矩阵计算指令进入矩阵运算队列, 向量计算指令进入向量运算队, 存储转换指令进入存储转换队列, 同一个指令执行队列中的指令是按照进入队列的顺序进行执行的, 不同指令执行队列之间可以并行执行, 通过多个指令执行队列的并行执行可以提升整体执行效率。当指令执行队列中的指令到达队列头部时就进入真正的指令执行环节, 并被分发到相应的执行单元中, 如矩阵计算指令会发送到矩阵计算单元, 存储转换指令会发送到存储转换单元

事件同步模块

  • 对于指令流水线之间可能出现的数据依赖, 达芬奇架构的解决方案是通过设置事件同步模块来统一协调各个流水线的进程。事件同步模块时刻控制每条流水线的执行状态, 并分析不同流水线的依赖关系,从而解决数据依赖和同步的问题。在达芬奇架构中, 无论是流水线内部的同步还是流水线之间的同步, 都是通过事件同步模块利用软件控制来实现的
    • 比如矩阵运算队列的当前指令需要依赖向量计算单元的结果, 在执行过程中, 事件同步控制模块会暂停矩阵运算队列执行流程, 要求其等待向量计算单元的结果。而当向量计算单元完成计算并输出结果后, 此时事件同步模块则通知矩阵运算队列需要的数据已经准备好, 可以继续执行。在事件同步模块准许放行之后矩阵运算队列才会发射当前指令
    • 如下图所示, 标量指令处理队列首先执行标量指令 0、1 和 2 三条标量指令, 由于向量运算队列中的指令 0 和存储转换队列中的指令 0 与标量指令 2 存在数据依赖性, 需要等到标量指令 2 完成(时刻 3)才能发射并启动。由于指令是被顺序发射的, 因此只能等到时刻 4 时才能发射并启动矩阵运算指令 0 和标量指令 3,这时 4 条指令流水线可以并行执行。直到标量指令处理队列中的 全局同步标量指令 7 生效后, 由事件同步模块对矩阵流水线、向量流水线和存储转换流水线进行全局同步控制, 需要等待矩阵运算指令 0、向量运算指令 1 和存储转换指令 1 都执行完成后, 事件同步模块才会允许标量流水线继续执行标量指令 8
      在这里插入图片描述

系统控制模块

  • 在控制单元中还存在一个系统控制模块。在 AI Core 运行之前,需要外部的任务调度器来控制和初始化 AI Core 的各种配置接口, 如指令信息、参数信息以及任务块信息等。这里的任务块是指 AI Core 中的最小的计算任务粒度
  • 在配置完成后, 系统控制模块会控制任务块的执行进程, 同时在任务块执行完成后, 系统控制模块会进行中断处理状态申报。如果在执行过程中出现了错误, 系统控制模块将会把执行的错误状态报告给任务调度器,进而反馈当前 AI Core 的状态信息给整个昇腾 AI 处理器系统

指令集 (ISA) 设计

  • 昇腾AI处理器的指令集设计介乎于精简指令集和复杂指令集之间,包括了标量指令向量指令矩阵指令控制指令
    • 标量指令类似于精简指令集, 而矩阵、向量和数据搬运指令类似于复杂指令集。昇腾 AI 处理器指令集结合精简指令集和复杂指令集两者的优势,在实现单指令功能简单和速度快的同时,对于内存的操作也比较灵活,搬运较大数据块时操作简单、效率较高

标量指令

  • 标量指令主要由标量计算单元执行, 主要的目的是为向量指令和矩阵指令配置地址以及控制寄存器, 并对程序执行流程进行控制。标量指令还负责输出缓冲区中数据的存储和加载, 以及进行一些简单的数据运算等
    在这里插入图片描述

向量指令

  • 向量指令由向量计算单元执行, 类似于传统的单指令多数据 (Single Instruction Multiple Data,SIMD) 指令, 每个向量指令可以完成多个操作数的同一类型运算, 可以直接操作输出缓冲区中的数据且不需要通过数据加载指令来操作向量寄存器中存储的数据
  • 向量指令支持的数据类型为 FP16、FP32 和 INT32。向量指令支持多次迭代执行, 也支持对带有间隔的向量直接进行运算
    在这里插入图片描述

矩阵指令

  • 矩阵指令由矩阵计算单元执行, 实现高效的矩阵相乘和累加操作 ( C = A × B + C C=A×B+C C=A×B+C)。在神经网络计算过程中,矩阵 A A A 通常代表输入特征矩阵, 矩阵 B B B 通常代表权重矩阵, 矩阵 C C C 为输出特征矩阵
  • 矩阵指令支持 INT8 和 FP16 类型的输入数据, 支持 INT32、FP16 和 FP32 类型的计算。目前最常用的矩阵指令为矩阵乘加指令 MMAD, 在矩阵计算中,系统会不断通过 MMAD 指令来实现矩阵的乘加操作,从而达到加速神经网络卷积计算的目的。其格式如下:
MMAD.type [Xd] [Xn] [Xm] [Xt]
  • 其中, [Xn], [Xm] 为指定输入矩阵 A A A 和矩阵 B B B 的起始地址, [Xd] 为指定输出矩阵 C C C 的起始地址。Xt 表示配置寄存器, 由三个参数组成, 分别为 M M M, K K K N N N, 用以表示矩阵 A A A B B B C C C 的大小
    在这里插入图片描述
Logo

昇腾万里,让智能无所不及

更多推荐