跳到主要内容

8.边缘部署

6.1 部署硬件GPU/FPGA/ASIC

​ 随着人工智能的发展,21世纪开始,对算力的需求也越来越高。人工智能的体系分为基础层,技术层和应用层,其中最底层的就是基础层的算法处理芯片,需要使用它来提高最基础的算力,传统通用CPU处理器算力不足,主要来源于GPU/FPGA/ASIC等AI芯片所提供的算力,下面我们就针对这三种不同的AI芯片进行讨论。

6.1.1 图形处理单元GPU

​ **图形处理单元(GPU)**其实是从中央处理器(CPU)演变而来的,原本是专为3D图形渲染的并行计算而设计的。在计算机早期,CPU是需要负责图形应用程序所需要的计算的,例如渲染2D和3D图像,动画视频等,但随着图形密集型应用程序的增多,给CPU带来了很多压力,导致整个计算机的性能下降,为了帮助CPU减轻压力,把图像相关的应用程序转移出来,所以GPU就应运而生,专门用于快速并行的执行图形相关的计算。

​ GPU通常包括多个处理器,每个处理器有一个共享内存,外加多个处理器和对应的寄存器,支持大规模并行处理,每个内核都专注于高效计算。CPU可以认为是整个系统的监工,协调通用的计算任务,而GPU执行的是更专业的任务(通常为数学任务)。CPU和GPU的架构简图如下所示:

image-20240109170331571

注意:越靠近核心的缓存速度越快

​ 在一些嵌入式设备中也有独立的GPU,也可以流畅的渲染3D图形和视频,例如手机,机顶盒。广告机等设备,GPU可以快速的在显示屏上呈现内容。现代GPU已经适应比最初设计的图形任务范围更广的任务,因为目前GPU比过去更具有编程性,目前GPU还能用于机器学习/训练深度学习神经网络/图像识别/视频游戏/视频编辑内容创造等工作。下面我们来展示GPU是如何工作的,为什么GPU可以加速图形和神经网络任务?

​ 在学习GPU如何工作前,我们需要知道并行计算是什么?并行计算是一种计算类型,其中特定的计算被分解成可以同时执行的独立的较小的计算,最后将计算结果重新组合或者同步。也就是说将原来一个比较大的运算任务分解成多个任务进行运算,任务的数量取决于核心的数,在硬件核心上的单元就是GPU中的处理器单元,在GPU中通常有数千个核心进行运算。

image=

如果计算可以支持并行计算的任务,我们就可以使用并行编程方法和GPU加速我们的计算。

下面我们以GPU渲染3D模型为例,3D模型可以可以由许多小三角形组成,如下图所示:

3D mesh-triangles with different resolution (3D Modelling for... | Download  Scientific Diagram

你可以想象一下,如果想让这个兔子像视频一样变得能动,那么就需要为每个小三角形的三个角的坐标值进行计算,假设每个角都使用X,Y,Z坐标来表示,如下图所示制作三角形来组成模型就需要制作三个顶点的坐标值,当然如果你的模型是由一个个正方形组成亦是如此,可能是由四个顶点组成。我们这一小节主要针对三角形构成的模型进行讨论,三角形的三个顶点可以在各个三角形之间共享,那么如果你的模型有1000个三角形,那么可能就不需要3000个顶点来组成模型。

image= ​ 回到我们的一开始说的,如果我们需要让这个兔子动起来,我们就需要将这一个个三角形进行平移/旋转/缩放等操作,这些操作统称为变换。

在现实3D图形中,使用数学的方式表达XYZ坐标的最佳方式就是使用向量的方式进行表达,如果想对向量进行变换操作,最简单的方式就是使用矩阵运算的方式,将原来的坐标乘一个3*3的矩阵,例如:

[XYZ][Sx000Sy000Sz]=[XSxYSyZSz]\left[\begin{matrix} X \\ Y \\ Z \\ \end{matrix} \right] * \left[\begin{matrix} S_x & 0 & 0 \\ 0 & S_y & 0 \\ 0 & 0 & S_z \\ \end{matrix} \right] = \left[\begin{matrix} X*S_x \\ Y*S_y \\ Z*S_z \\ \end{matrix} \right]

你可以看到矩阵的每行都有不同的属性值,你只需要使用特定的预先定义好的矩阵进行相乘后即可对这个小三角形进行平移/缩放/旋转等操作,所以要使得能很轻易的让那么多个小三角形进行变换,那么GPU需要十分擅长矩阵运算,并且支持大量的矩阵运算。

image-20240119112106644

从上图中,我们看到我们需要将这些矩阵数据加载到内存中,加载后,GPU会同时访问内存并运输大量的矩阵块数据。核心在处理当前矩阵块数据时,它从系统内存中获取了更多的块,所以GPU永远不会空闲。GPU获取了一块矩阵块后会交给GPU计算完成完成还需要使用着色器对每个小三角形都填充颜色,当然这个由GPU渲染器来完成的。

image-20240112111131687

​ 如果对于是大矩阵的运算,GPU则会取一部分一部分的取出大矩阵的数据进行计算,我们就以两个大矩阵相乘的例子来看GPU是如何进行计算优化的。假设存在两个4*4的矩阵A和B,将矩阵A和矩阵B相乘,乘积结果使用C进行保存。如下所示:

image-20240112150428598

​ 我们可以将这个4*4矩阵分块,拆分成2*2的块矩阵,那么乘积结果C就等于两个2*2的块矩阵相乘,最终计算出矩阵块的乘积结果。我们就重点来看C矩阵是如何在GPU上实现并行计算的。我们就3个核心的GPU为例,如下图所示:

image-20240112164709464

​ 我们先来计算C11的块矩阵元素,我们可以将子矩阵块A11,B11从L2缓存中取出,放到L1缓存中,SM-1核心对获取的数据进行运算,将乘积结果放到共享内存SMEM中,将A12和A21从L2缓存中取出,放到L1缓存中,SM核心对获取的数据进行运算,将乘积结果放到共享内存中。最后从共享内存中取出两个乘积结果进行求和就可以得出完整C11。同时我们可以使用其他SM核心并行的计算这些子矩阵块,最终计算完矩阵中的不同的块矩阵的数据,从而得到整个C矩阵的数据。

​ 我们用更多的内存带宽将数据块从系统内存提取到GPU中的缓存中,使用多处理器来并行的处理。那么对于大矩阵块的乘法,我们就需要知道一些超参数,也就是我们怎么每次取的块大小是多少?需要使用多少个核心进行处理,以及使用哪一个核心进行处理?

image-20240112170049703

​ CUDA就可以负责确定这些超参数,同时如果我们需要使用GPU对我们的矩阵运算进行加速,使用CUDA即可完成。

CUDA是 NVIDIA 专为图形处理单元 (GPU) 上的通用计算开发的并行计算平台和编程模型。借助 CUDA,开发者能够利用 GPU 的强大性能显著加速计算应用。

在经 GPU 加速的应用中,工作负载的串行部分在 CPU 上运行,且 CPU 已针对单线程性能进行优化,而应用的计算密集型部分则以并行方式在数千个 GPU 核心上运行。使用 CUDA 时,开发者使用主流语言(如 C、C++、Fortran、Python 和 MATLAB)进行编程,并通过扩展程序以几个基本关键字的形式来表示并行性。

那么回到我们的问题为什么在深度学习中我们经常需要使用GPU设备呢?

因为在神经网络中进行的许多计算可以很轻易的分解为多个彼此独立的较小计算任务。例如我们前面学习的卷积运算:

0_zADmyHH92LZPdnmj

我们通过前面学习的卷积过程就可以知道,我们每次运算都是独立于其他计算的,所以我们可以发现每次卷积计算都不会依赖其他计算的结果,因此所有这些独立的卷积计算都可以在GPU上并行的运算,并且整个输出通道可以在整个计算完成后生成,所以我们就可以使用并行计算方法在GPU上加速卷积运算。

image-20240109191628601

6.1.2 现场可编程门阵列FPGA

​ 现场可编程门阵列 (FPGA) 是一种半导体集成电路,它基于通过可编程 互连 连接的可配置逻辑块 (CLB) 矩阵。FPGA 可以在制造后根据所需的应用或功能要求进行重新编程。FPGA中芯片的逻辑单元是可以通过编程的方式改变,同时逻辑单元的连接也是可以改变的。

FPGA的基本结构包括可编程输入输出单元,可配置逻辑块,数字时钟管理模块,嵌入式块RAM,布线资源,内嵌专用硬核,底层内嵌功能单元。编程语言有VHDL/Verilog等。

​ 下面我以一个简单的神经网络为例,带大家来看FPGA上是如何加速神经网络的,如下图所示:

image=

下面根据这个神经网络中来设计一个逻辑电路,那么我们先编写一个框图,展示神经网络的参数,如下所示

image=

可以看到我们主要是实现隐藏层和输出层的四个神经元,那么我们来看如果FPGA中如何实现单个神经元的逻辑电路如下所示:

image=

对于一个神经元,我们有三个输入信号x_1,x_2,x_3,输入信号的的权重w_1,w_2,w_3,对它们两个进行相乘;将乘积结果相加起来,并且加上偏置值。将最终的输入信号和传入ROM中,我们在ROM(只读存储器)中存储了sigmoid激活函数,经过ROM中的激活函数处理后输出最终的值。我们就根据原来的神经元模型在FPGA上使用VHDL设计对应的逻辑电路。那么对于神经网络,FPGA的逻辑电路就可以设计成这样,我们将神经网络的结构映射成硬件的结构。如下图所示:

image=

下面我们来看一下FPGA的优缺点。

优点:

  • 加速深度学习推理: FPGA可以通过硬件加速深度学习推理任务,提高模型的性能和效率。深度学习模型通常需要大量的计算资源,FPGA的并行计算能力使其成为加速推理任务的理想选择。

  • **灵活性和可编程性:**FPGA具有可编程性,允许用户根据特定需求设计和实现定制化的硬件加速器。这种灵活性使得FPGA适用于各种不同的人工智能应用,包括图像识别、语音处理和自然语言处理等。

  • 低功耗: 相对于传统的通用处理器,FPGA通常具有较低的功耗。这对于在嵌入式系统和移动设备等资源受限的环境中使用人工智能技术是非常重要的。

  • 实时处理: FPGA可以提供实时性能,适用于需要即时响应的应用,如自动驾驶、智能摄像头和物联网设备等。

  • 加速算法和模型优化: 利用FPGA的并行性和硬件加速能力,可以对人工智能算法和模型进行优化,加速训练和推理过程,提高整体性能。

缺点:

  • 复杂性: FPGA的设计和编程相对复杂,需要专业的硬件设计和编程技能。

  • 成本: FPGA通常相对昂贵,尤其是高性能和大规模的FPGA。这可能成为一些项目和应用采用FPGA的障碍,尤其是在预算受限的情况下。

  • 功耗波动: 虽然相对于某些通用处理器,FPGA具有较低的功耗,但在某些情况下,由于FPGA的可编程性和灵活性,其功耗可能难以精确估计,导致功耗波动。

  • 相对固定的硬件资源: FPGA的硬件资源是有限的,并且通常是相对固定的。这可能导致在处理某些大规模或复杂的人工智能任务时,资源不足的问题。

  • **编译使用:**工具链的质量参差不齐,一次编译的时间较长。

6.1.3 专用集成电路ASIC

​ 专用集成电路是为特定任务或应用定制设计的集成电路 (IC)。与FPGA板不同,FPGA板在制造后可以进行编程以满足各种用例要求,而ASIC设计是在设计过程的早期进行定制的,以满足特定需求。两种主要的ASIC设计方法是门阵列和全定制。ASIC由IC设计人员根据特定的电路需求,设计专用的逻辑电路,在设计完成后生成设计网表,交给芯片制造厂家流片。在流片之后,内部逻辑电路就固定了,芯片的功能也就固定的。通常ASIC芯片可用于通信(通信芯片)/汽车电子(电机芯片)/航天航空(导航/飞行控制芯片)等。

​ 在深度学习领域,ASIC专门针对深度学习任务的集成电路被称为硬件加速器,可提高深度神经网络的推理和训练速度,并在相同时间内降低功耗。深度学习ASIC的电路结构和功能经过专门优化,以满足深度学习任务的计算需求。这种硬件优化可以提供高度并行计算、特定网络架构的支持以及其他深度学习运算的硬件加速。

​ ASIC中最有标志性的就是Google TPU,它是由谷歌设计的专用硬件加速器,用于机器学习和深度学习任务。TPU的设计目标是提供高性能和高效能的硬件,以加速谷歌云平台上的机器学习工作负载。并且其对TensorFlow框架具有很好的兼容性,使得在TensorFlow上训练和部署模型时能够充分发挥TPU的性能优势。

目前国内外在做ASIC的厂商有:国外的谷歌/英伟达/英特尔/AMD等,国内的华为/全志/瑞芯微/地平线/寒武纪/嘉楠/比特大陆/芯原等。

​ 在深度学习的ASIC设计中,一些硬件加速器采用了类似于脉动阵列(systolic array)的结构,以实现高度并行的计算。它就是利用多个小型计算核心并行执行矩阵乘法等操作,以提高性能。对于这种ASIC的计算单元主要是由计算单元PE阵列组成,通常以规则的二维或三维排列,形成一个紧凑的网格结构。这有助于实现高度的并行计算。如下图所示:

image=

下面我以一个两个矩阵相乘的例子来看,脉动阵列是如何对矩阵运算进行加速的。

C=AB=[a11a12a13a21a22a23a31a32a33][b11b12b13b21b22b23b31b32b33]C11=a11b11+a12b21+a13b31C12=a11b12+a12b22+a13b32C13=a11b13+a12b23+a13b33...C33=a31b13+a32b32+a33b33C=AB=[c11c12c13c21c22c23c31c32c33]C=A*B= \left[\begin{matrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \\ \end{matrix} \right] * \left[\begin{matrix} b_{11} & b_{12} & b_{13}\\ b_{21} & b_{22} & b_{23} \\ b_{31} & b_{32} & b_{33} \\ \end{matrix} \right] \\ C_{11}= a_{11}* b_{11} + a_{12}*b_{21} + a_{13}*b_{31}\\ C_{12}= a_{11}* b_{12} + a_{12}*b_{22} + a_{13}*b_{32}\\ C_{13}= a_{11}* b_{13} + a_{12}*b_{23} + a_{13}*b_{33}\\ ...\\ C_{33}= a_{31}* b_{13} + a_{32}*b_{32} + a_{33}*b_{33}\\ C=A*B=\left[\begin{matrix} c_{11} & c_{12} & c_{13}\\ c_{21} & c_{22} & c_{23} \\ c_{31} & c_{32} & c_{33} \\ \end{matrix} \right]

我们先来看我们如果需要进行两个矩阵乘法,需要进行多少次运算,可以看到我们求出一个矩阵C中的一个元素c11需要进行5次乘法和加法运算,矩阵C中总共有9个元素需要求,那么总共需要45次运算。那么如果使用ASIC芯片,并且使用脉动阵列中的计算单元来看一下是如何优化矩阵乘法。如下图所示:

image-20240115172200704

image=

​ 下面我们对上图中的展示上图中脉动阵列的计算流程进行说明:

  • 将A矩阵放在计算单元PE阵列中,将B矩阵放在输入的位置。

  • 将输入数据往右移一列,将矩阵B的数据传入计算单元PE阵列中,与计算单元中的元素作乘法运算。

  • 将输入数据再往右移一列,再次进行矩阵乘法运算。将上一次计算的结果往下移一行,对计算单元的元素进行加法计算。

  • 重复将数据往右移计算乘积结果,往下移计算加法结果,直到将所有数据计算完成。

我们可以看到如果使用脉动阵列的方式进行矩阵乘法运算,我们可以快速减少计算步骤和所需时间。我们经过上述方法可以将整个输出矩阵C的结果放到输出里面了。可以看到我们的矩阵A的尺寸和脉动阵列的尺寸是一致的,才能保证进行乘法运算的结果正常运算,那么对于一般的矩阵乘法(尺寸可能和阵列不一致),可以通过分块或者填充来匹配阵列的尺寸大小。

对于sigmod/RELU等激活函数,脉动阵列无法实现的功能,可以使用其他硬件单元来实现。

6.2 嵌入式模型部署

从零到最后嵌入式模型部署流程是准备数据集、数据预处理、数据标注、选择算法、训练、调整参数、生成模型、边缘部署。

①准备数据集包括文本数据、图像数据、音频数据等,图像数据中有包括数字数据集、人脸数据集、人形数据集、道路数据集等。

②数据预处理,主要是为了检查、修正、删除在数据集中不适用于模型的数据。常见的方法是:特征缩放、缺失值处理、异常值处理、数据转换等。

③数据标注,对于图像数据,对目标物体进行画框,导出其在图像中的位置。对于音频数据,对时间轴上标注出音标或者特定词等。

④选择算法,我们需要根据数据集来选择算法如:文本的检测算法、分类算法等;图像的目标检测算法、人脸检测算法、人形检测算法等,音频的语音识别算法、语音合成算法等。

⑤训练后生成模型,评估模型后修改模型或参数,直至模型达到最优的效果。

⑥模型部署,使用AI芯片中的神经网络处理单元进行模型的推理。

6.3 嵌入式AI芯片

目前主流的嵌入式AI芯片做法都是将AI模块嵌入到定制的SOC中,允许芯片架构针对特定的计算应用进行优化。一般都是多个核心放在单个SOC上,现实中很多AI芯片的做法都是多核异构,即采用多个核心,且不同架构。

嘉楠公司的K510含有三核 RISC-V 处理器和KPU通用神经网络引擎;

全志公司的V853含有Arm Cortex-A7@1GHz 、E907@600MHz和NPU神经网络处理器;

英伟达公司的jetson nano含有四核Arm Cortex-A57主核、28核Maxwell架构GPU图形处理单元;

下图为嘉楠K510芯片架构图,可以从红框中为该芯片为CPU+ASIC架构。

image=

下图为全志V853芯片架构图,可以从红框中为该芯片为CPU+ASIC架构。

image=

6.4 边缘部署流程

边缘部署的流程包括模型转换量化压缩打包封装

6.4.1 模型转换

模型转换是由于我们训练和推理的设备不一致,用于连接不同框架的模型。由于目前许多开源算法都要自己的模型格式,主流的做法是将原本的模型转换成onnx或Caffe的格式,再转换成AI芯片所要求的格式。

例如对于yolov5目标检测算法,嘉楠公司的K510的模型格式转换流程为:pt->onnx->kmodel

全志公司的V853芯片的模型格式转换流程为:pt->onnx->nbg

英伟达公司的jetson nano的模型格式转换流程为:pt->onnx->tensorRT

其中pt格式是pytorch的模型格式,onnx格式是开放神经网络交换格式,用于表达深度学习的模型标准,可使模型在不同框架之间进行转移。Kmodel格式是嘉楠公司的KPU所用的文件格式。nbg为芯原公司的NPU所用的文件格式。 tensorRT为英伟达公司所用的文件格式。

image-20231208153014570

6.4.2 量化压缩

为了缩小模型,我们常使用量化压缩,它是由于在卷积神经网络中为了追求更好的精度,常会采用浮点float-32,这导致参数量、计算量、占用内存都会变得很大,为了减小模型存储和内存占用、压缩参数、提高速度使得可以部署到资源较少的嵌入式设备中,需要转换成int整型。

image=

减小了模型所占用到的资源,模型的精度也会下降,但如果要使量化后的模型可以落地使用就需要将量化后的精度损失降低到可接受范围内,同时还需要保证部署后的速度、资源占用率和能耗。

image=

非对称模式是不以0为中心点,以所有参数的中间值为中心点,将整个模型中的所有参数等比例映射到0-255范围内。

对称模式是以0为中心点,将整个模型中的所有参数等比例映射到0-255范围内。

参考资料:神经网络量化白皮书

6.4.3 打包封装

打包封装是指将模型文件、模型的前处理后处理模型推理等打包供嵌入式设备中的应用程序使用。

在了解前处理和后处理之前,我们来回顾一下模型的输入内容和输出内容。

image=

模型的输入是以声音/图像/文本,进行模型推理后,输出的数据也是由模型本身确定的输出的数据内容,输出内容可以是函数的参数、tensor特征向量、格式化文本。

6.4.4 端侧推理

前处理是指由于模型的输入是由模型本身确定的,有些会以多维矩阵(Tensor)的数据作为输入,但嵌入式设备采集的数据一般为图像格式音频格式文本格式等,如果想将数据推入模型中进行推理需要根据模型的输入要求,将采集数据的格式转换为多维矩阵,或不进行处理直接将数据输入模型。

②模型推理是`指将转换后的多维矩阵在转换成特定格式的模型上运行,输出的多维矩阵可以满足精度、性能等需求。例如英伟达公司的jetson nano转换后的模型使用TensorRT引擎进行推理;嘉楠公司的K510转换后的模型使用nncase框架进行推理。全志公司的V853转换后的模型使用芯原VIPLite引擎进行推理。

后处理是指将推理后的处理结果(参数/多维矩阵/格式化文本)进行处理或者解码,转化为嵌入式设备输出给外设的图像特征、音频特征或文本特征等。

image-20240122114752401