GPU从架构上算术逻辑单元的数量要远远多于Cache(缓存)和Control(控制器),由此导致其只适用于计算密集与数据并行的运算程序。
所谓计算密集指:数值计算的比例要远大于内存操作,因此内存访问的延时可以被计算掩盖,对缓存的需求较低;
数据并行则是说:大任务可以拆解为执行相同指令的小任务,因此对复杂流程控制的需求较低。
AI机器学习正是这样的“运算程序”:将一个复杂问题拆解为众多的简单问题,一次性输入海量用于计算的参数。对简单问题解决的顺序性要求不高,最后输出整体结果即可。
NVIDIA的业务范畴数据中心 游戏 专业可视化 汽车 OEM和其他。
但云端(数据中心)和端侧(手机、智能汽车等移动端)场景中, AI芯片的运算方式有着本质性的差别。
首先,云端处理大批量一次性到达的累积数据(扩大批处理量,batch size),车端芯片则需要处理流数据,随着行驶(时间)陆续到来的数据;
第二,云端处理可以“等”数据“够了”再开始处理,车端则需要实时完成计算,尽可能得降低延迟,更勿论几秒钟的“等待”;
第三:在云端,任务本身是限定在虚拟世界,无需考虑与现实世界的交互。在车端则身处现实世界,每一个任务都需要考虑交互性。
此外,功耗和成本在车端AI芯片的考量中也占据更重的分量。
可见,云端AI芯片更侧重于数据吞吐量和支持多种AI任务的要求,车端的AI芯片则须保证很高的计算能效和实时性要求,能够实现端侧推断,以及低功耗、低延迟甚至低成本的要求。
但目前,英伟达端侧芯片的核心GPU架构仍是云端架构。
CUDA核在每个GPU时钟中最多可以执行1个单精度乘法累加运算,适用于参数一致的AI模型深度学习以及高精度的高性能计算。
但对于AI模型来说,模型参数的权重各有不同,如果全部对标当中的高精度进行运算,则时间长且内存消耗大;而如果都降维到低精度参数,则输出的结果误差较大。
张量核就可以做到混合精度:每1个GPU时钟执行1个矩阵乘法累加运算,输入矩阵是 FB16,乘法结果和累加器是FB32矩阵。
混合精度虽然在一定程度上牺牲了训练的精度,但可以减少内存的占用,以及缩短模型的训练时间。
在扩充适应多样计算需求的算子同时,英伟达也在不断扩充算子所能支持的浮点精度。
CUDA核在最主流的FP32基础上,先后增加了对FP64、INT32 的计算能力;张量核则可支持FP16、INT8/INT4/Binary、TF32、 BF16、 FP64等多种数据精度的支持。
host端如何调cuda kernel ?
CUDA 程序中采用 <<<>>>语法糖发射的接口,这个三尖号语法在编译时会被替换为 Runtime API 的 cudaLaunchKernel 函数,运行时会进一步调用 Driver API 的 cuLaunchKernel 函数。
从物理世界来看,芯片架构就是在方寸之间(目前主流车规级量产芯片尺寸40nm-5nm)做文章:如何在有限的空间内排布算子、存储器以及之间的通信线路,不同的计算需求将导致不同的阵列方式。
对于NV GPU来说,端侧以实时推理为第一要务的深度学习任务外,还需要考虑云端的训练和高性能计算等更多的任务,通用性计算与混合精度矩阵计算需求并重,仍需在方寸之间为CUDA核留下不少的位置。
相比通用型架构,自动驾驶专用架构在设计的时候会充分考虑到目标应用场景的特色,采用更高效适用的计算核以及组合模式,从而实现计算效率的提升,更好地满足目标应用场景的计算需求。
围绕提升MAC阵列的利用效率,地平线自主研发的BPU(嵌入式人工智能处理器,Brain Processing Unit,大脑处理器)架构采用大规模异构计算、高灵活大并发数据桥和脉动张量计算核三大核心技术打造适应端侧自动驾驶需求的矩阵运算。
主要面向batchsize=1、DDR节省和对使用depthwise的卷积神经网络进行优化,契合自动驾驶场景特征和高能效比。
batchsize是指神经网络一次批量处理的样本数目。一次批处理的样本数目越多,那么就有潜在的更多并行计算/加速的可能。在云端场景下,有海量的数据需要处理,GPU以及其他一些云端AI芯片在架构设计上就会充分考虑batchsize大(一次批处理样本多)的特性来设计,从而提高硬件效率。
深度可分离卷积/深层卷积(depthwise separable convolution)代替普通的卷积,形成小规模/轻量化模型,如SqueezeNet、MobileNet、ShuffleNet等
自动驾驶和其他一些端侧场景,数据上按固定的时间依次到达的,比如摄像头的帧率是30FPS,那么相当于每隔33ms就会有一张图达到,这时候就需要立即处理,尽早搞明白周围的状况而对车辆做出必要的控制。
本质上,自动驾驶面临的就是一个batchsize=1的问题(来一张图就要马上处理,而不能多等几张图一起处理),特斯拉的FSD chip发布会也强调了其架构设计面向batchsize=1优化。
但这些高扩展性和丰富性,对自动驾驶AI来说是否是必要的?
2018年,英伟达发布了采用Volta架构GPU的Soc(系统级芯片)Xavier,可执行高级别自动驾驶任务。按照英伟达的定义,XAVIER是专门为机器人和边缘计算而设计的计算平台,采用台积电的12nm工艺。
相比之下,特斯拉FSD采用三星14nm工艺,且算力上Xavier只有FSD的一半。但从面积上,XAVIER却比FSD要大一些。
背后便是应用于云端场景的架构,与完全对标一个品牌需求的车端架构,在芯片布局上的不同。
直观来看,Xavier集成的Volta GPU,提供了512个CUDA核和64个张量核。相比之下,FSD中负责通用浮点计算的GPU面积远小于其MAC阵列NPU。
从需求出发,FSD芯片上只需运行特斯拉的自动驾驶AI,因此完全对标深度学习需求的MAC阵列占据更多的片上位置。
DSP 上有两块 data ram(简称 dram),每一块 data ram 又分为两个宽为 512bit 的 bank。同时,DSP 上有两个 Load/Store 单元,Load/Store 模块访问 data ram 的带宽都是 512bit,所以理论上的访存带宽是 1024bit/cycle,而独立于 Load/Store的SuperGather模块是为了支持 DSP 上高效的 gather/scatter 操作。另外,可以看到 DSP 还有一个 dma 模块,该模块用于片外空间和 dram 之间的数据传输。
为了充分利用算力和访存能力,Cadence DSP 支持了 SIMD(Single Instruction, Multiple Data) 和 VLIW(Very Long Insruction Word) 两种特性。
SIMD 支持 64lanes * 8bit 或 32lanes * 16bit 等总位宽为 512bit 的向量访存和向量计算。向量化指令,可以实现向量化访存和向量化计算,即单个指令一次处理多个数据;
高通叫 HVX 扩展,ARM叫 NEON 扩展
随着计算场景的复杂化,许多高性能DSP的SIMD的计算位宽已经从128 bits升级到1024 bits
由于SIMD一次需要处理多个数据,所以针对一些场景,也加入了一些新指令
科学计算中存在很多复数的计算,相邻两位分别是实数和虚数,很多DSP有相应的交织读取指令,单独load实部或者虚部的数据到寄存器,为了提高大数据量的吞吐,部分向量load指令在结束后会完成地址的自加,不需要增加指令去计算新地址和计算指令配套,也需要有向量化的类型转换指令,该功能中有时会合并到一些特殊的load指令中,举个例子就是,16位数据load到32位数据的地址上,类型转换功能包含在该load指令中。
VLIW 是一种谋求指令级并行 (ILP, instruction level parallelism) 的技术。VLIW 可以将多个指令打包后在一起同时发射,从而获取指令级的并行度。与超标量、乱序执行等其他 ILP 技术不同的是,VLIW 的并行指令排布是在编译期就确定好的,而不需要 CPU 进行复杂的运行时调度。VLIW 使得 DSP 处理器在不需要大幅增加硬件复杂度的情况下,就可以获取 ILP 的加速收益。 如果遇到前后指令相关依赖的情况,就不能把这些指令放到一个指令包中,这种情况下指令包的指令不是满载的。许多厂商为了提高IPC,会对这种情况做相应的优化;如下图是高通hexagon的优化思路,可以将流水线上数据冲突的指令放在一个指令包上。
Cadence DSP 是哈弗架构,其指令和数据独立编址,具体的编址规格由 LSP(Linker Support Package) 决定,而用户可以通过名为 memmap.xmm 的内存配置文件来定义和修改 LSP。
host端如何调DSP 算子 ?
从 CPU 侧发起调用,通过 rpc 协议调起 DSP 侧提供的服务,将 CPU 侧程序称为 rpc_host,而 DSP 侧程序称为 rpc_dsp。rpc_dsp 负责起一个线程监听来自 rpc_host 的 message,并从 message 解析出需要进行的动作,并在执行完该动作后回复 rpc_host 一个 message。需要预先将 rpc_dsp 编译成可执行程序,再将可执行程序 dump 成 bin 文件,这里称为 dsp_bin(包含 iram.bin 和 sram.bin)。而 CPU 侧负责准备算子调用的所有输入,并装载编译好的 dsp_bin 到 DSP 的 dram 中(前文介绍 LSP 的部分有说明应该如何进行内存映射),同时把 rpc_dsp 侧的监听线程 run 起来,最后 rpc_host 发起 rpc 调用并等待 rpc 返回。
需要说明一点,CPU 和 DSP 之间一般会使用 IPCM(核间通信模块)实现对一段 ddr 地址空间的共享。但是 DSP 直接访问这段 ddr 的延迟是远大于访问 dram 的延迟,所以对于算子执行过程中需要频繁访问的 ddr 数据,一般是先使用 dma 将其搬运到 dram 上,算子执行结束后,计算的输出再通过 dma 搬回到 ddr。根据DMA的异步特性,可以将计算和内存拷贝 overlap 起来。
TCM
与ARM的A系列芯片一样,cadence dsp 和 hexagon dsp 中都有紧耦合内存( TCM ),core从 TCM 中拿到数据的周期和 L1 cache 一致,通常会将需要多次访问的数据放到 DTCM ,多次使用的指令放到 ITCM,提高运行速度,类似于GPU中的shared memory 和 constant memory,这些地址的分配通过ld脚本中的地址设置和 attribute 关键字去分配。
https://aijishu.com/a/1060000000257512
https://en.wikipedia.org/wiki/Tesla_Autopilot_hardware
https://developer.nvidia.com/zh-cn/blog/gpudirect-storage/