赞
踩
人工智能(Artificial intelligence)的迅速发展正在改变世界。以深度学习(Deep learning)为驱动力和代表的第三波AI浪潮,正在变革和赋能金融、制造、农业、交通、医疗、零售、教育等众多行业,同时也极大地影响着我们每个人的生活。当前,在移动设备上各种新的AI应用场景正在不断涌现。大量新的需求对端上的智能能力提出了新的挑战,也带来了新的机遇。今天,得益于AI技术的巨大突破与进步,我们可以与设备像人一样通过语音、手势等方式沟通,扫一下人脸即可确定身份进行支付,穿戴式设备可分析健康状况并给出建议,系统可以根据用户的使用习惯自动优化,汽车会检测识别周围环境给出指引或者自动驾驶。这样的应用还有许许多多。所有这些,背后都离不开AI的助力。
过去几年将智能计算放于云上的方式被广泛采用,即智能强依赖云端。这几年随着移动设备硬件能力飞速提升及智能需求井喷,边缘计算开始兴起。机器学习模型在服务器上训练好后可以被部署到端设备上,执行过程不依赖云端,从而很大程度地改善了用户体验。在不侵犯隐私的前提下,使用过程中产生的数据又可以帮助改善模型的效果,最终构成一个良性的智能闭环。总得来说,端上智能具有以下优点:
也正是由于边缘智能计算具备这些优点,使它成为业界的热点。但是,在带来机遇的同时,它也带来了巨大的挑战。这些挑战主要来源于边缘设备的资源限制,如计算速度、存储与功耗等。
在过去几年里,深度学习在视觉、自然语言处理、语音识别、推荐、智能控制等领域获得了许多重大的突破,并在很多的专项上超越了人类水平。我们知道,深度学习有三大基石:数据、算法和算力。大数据的兴起为AI提供了契机,深度学习的主要优势之一就是能基于大量数据进行学习。算法则提供了处理数据和从数据中进行学习的有效方法。而要对大量数据和复杂的网络进行计算,需要强大算力的支撑。而某种意义上来说它们之间有一些互补关系。如随着近几年AutoML的火热,人们发现让机器搜索网络架构可以找到比人工设计更优的方案。Google的大神Jeff Dean(对,就是编译器从不给他警告,只有他给编译器警告的那位)就曾经表示:未来谷歌可能会用100倍的计算能力,取代机器学习专业知识。换句话说,如果拥有足够的算力,可以替代很大部分算法设计。
这就引出一个问题,多少的算力是足够的?这个问题估计谁也没法给出一个准确的答案,但我们可以通过一些数据侧面感受下。OpenAI发布的分析表明:自2012年,也就是深度学习爆发以来,人工智能训练任务中使用的算力呈指数级增长,其目前速度为每3.5个月翻一倍。相比之下,摩尔定律中芯片性能翻倍的速度是18个月。2012年来人们对于算力的需求增长了超过30万倍。另外,随之而来的能耗和成本问题也不容小视。据美国马萨诸塞大学研究人员表示,通过神经网络自动架构搜索训练一个Transformer网络,碳排放180吨,相当于把三辆汽车从全新用到报废。当然,这里是训练时所需的算力,移动端上因为大多只需要推理,其算力需求会小得多。我们以比较热门的自动驾驶来举例。自动驾驶汽车为了完成周围环境的感知,需要处理从camera、radar、LIDAR等一系列传感器来的数据。Intel CEO Brian Krzanich曾在一次大会keynote中称:估计到2020年,一辆自动驾驶车每天大约会产生4TB的数据。而这些数据很多是需要实时处理的。要处理如此大量的数据,其算力需求可想可知。Imagination汽车市场总监Bryce Johnstone表示:自动驾驶级别每升高一级,对计算力的需求至少增长十倍。第五级全自动驾驶,可能需要500TOPS以上计算力。而作为“低配版”自动驾驶的ADAS,根据功能的不同,也需要10到100+GFLOPS的计算力。
这几年,机器学习学术研究空前繁荣。Jeff Dean就曾发推给出数据:根据对arXiv上论文的统计,到2018年底,平均每天产生100篇。难怪有种论文读不过来的感觉。。。然而,与学术界遍地开花的一派繁荣景象相比,工业界落地难的尴尬境地困扰着不少业内人士。不少AI产品停留在PPT和概念演示阶段,然后,就没有然后了。。。其中最大的阻碍之一就是端上的计算资源有限,难以支持多样的、实时的AI相关计算任务。
以深度神经网络(DNN)为代表的AI计算任务,本质上是推动了边缘设备计算模式的转变。传统的移动端基本以I/O密集任务为主,偶尔来个计算密集任务可能用户就会觉得发烫,是不是哪里出问题了。而DNN的推理一次就动不动几十亿次运算,而且还是周期性高频率运行,外加系统中可能还有多个DNN同时运行,这传统的玩法根本扛不住。因此,我们的核心问题是算法需求与边缘硬件算力之间的矛盾。而且这个矛盾很可能会长期存在。就像之前的Andy and Bill’s Law,即便算力大幅度提升,市场会出现更多的场景需求,更高的准确率要求把这些增长的算力吃掉。注意算力还与存储、能耗等资源密切相关,因此在移动端性能优化的目标除了耗时外,还包括内存占用及功耗等等。
要解决上一节提到的问题,缓解算法需求与移动端算力的矛盾,业界有几个基本思路:
下面分别就这几个思路稍作展开。
以DNN为代表的现代流行机器学习模型在端上的大量应用带来了计算模式的变化。DNN中的典型计算(如矩阵乘加)普遍有逻辑简单,计算量大,且反复计算的特点。这种计算模式的变化推动了芯片的发展与变化。目前主要的挑战来自两个方面:
针对以上挑战,业界进行了各种尝试来克服。我们知道,神经网络的执行很多时候就是在做矩阵计算。既然是非常耗时的特殊计算,那最好的方式就是用专门的硬件(就像编解码芯片),从而达到高性能、低功耗。这种为专门目的而设计的集成电路被称为ASIC。FPGA与ASIC类似,也是用硬件实现软件算法。只是它是一种“半成品”,可以自定义。这几年,各种神经网络芯片可以说是一个接一个,层出不穷。一时间,各种"xPU"横空出世。貌似26个字母都快用完了。。。
本质上,它们大多是为了解决上面提到的根本问题。对于摩尔定律的放缓或者失效,一个自然的路子就是通过并行来提速。CPU经历了从单核到双核再到多核的发展历程,然而毕竟作为通用处理器由于硬件设计上的一些限制无法堆太多核。将并行计算推向大规模的先行者是Nvidia,早在2006年,Nvidia推出了CUDA,非常明智地将之前专用于图形领域的GPU推向通用计算领域,摇身变为GPGPU。2012年,以绝对优势获得ImageNet冠军的AlexNet正是用了CUDA来加速训练。Nvidia随着之后兴起的深度学习浪潮进入了一条快车道,其硬件与软件生态已成为服务器端的绝对主流和标配。与CPU不同,GPU拥有数以千计的核心,能同时做并行任务中的操作。这样其整体性能就可以不受单个核心频率的限制。其局限是只适用于规则的可并行计算任务,对于DNN中的矩阵乘加就非常适合,因此,在深度学习的任务中,GPU的吞吐量可以比CPU高出一个数量级。
然而,GPU毕竟设计之初不是为神经网络专用的,它仍是一个通用处理器。虽比CPU更专用了,但硬件设计仍需考虑一定的通用性,因此也不能做得太激进。 这就给了ASIC进一步的发展空间。ASIC因为是专用的,因此可以针对性地进行硬件设计,从而达到极致的能效。与GPU相比,用于神经网络的ASIC芯片的显著特点是一般会有更多的计算单元(如TPU包含65536个8位MAC矩阵乘法单元)。但是,像之前提到的,只考虑计算速度是不够的,很多时候瓶颈在于访存。很多时候我们谈算力指标言必FLOPS,其实这个指标很容易让人误解,似乎只需FLOPS到了一切都妥妥的了。其实由于访存速率的限制很多时候硬件算力只能发挥出一部分甚至是10%不到。在Roofline模型中,由计算平台的算力和带宽上限决定的"roofline"将整个区域分为两个部分-memory bound和compute bound。根据模型在图中的位置可以判断它的瓶颈在哪里。我们发现不少模型,尤其是像MobileNet等轻量级的模型由于计算密度较低大多会落入memory bound区域。也就是说,这种情况下硬件计算速度再快也白瞎。针对访存这块,神经网络芯片一般会在设计上做针对性的优化,比如更大的片上内存(如TPU的有28M)。另外,像有David Patterson(图灵奖获得者)背书的Google出品的TPU为了更大幅度缓解冯·诺依曼瓶颈,让脉动阵列架构重回到舞台。在这种架构下,每次执行乘法运算时,结果会被直接传递给后面的乘法器,并进行求和。在整个过程中,无需访问内存。去除这些访存开销,还会有额外好处,即功耗的降低。我们知道与计算相比,访存才是功耗大户。通过这种方式可以有效提高能效比。
以上只是举些小例子,其它各种神经网络的ASIC也是各显神通,用足了各种优化来克服传统计算方式的缺点。虽然目前这条路子仍然是绝对的主流,但人们同时也开始探索新型的计算形式和计算硬件用于神经网络计算,如:
尽管经过科学家们的不懈努力,这些新型的计算方式和硬件的价值已初现端倪,但目前仍主要处在研究阶段。要将它们落地并大规模应用,还需要克服很多困难。而一旦它们技术成熟,那将会是革命性的。
很多时候,程序执行符合80/20法则。即80%的时间在跑20%的代码(当然,这里的数是虚指)。对于神经网络来说也不例外。如对于视觉任务中典型的CNN,通常卷积与全连接层会占到总计算量的80%~90%甚至更高。另外像在语音、自然语言理解领域常用的RNN中大量存在LSTM和GRU层,它们本质上也是做矩阵计算。因此很多时候大家做性能优化会focus在矩阵计算上。
抛开实现谈优化意义不大,或者说油水不多。只有考虑与平台硬件结合的深度优化,才能充分挖掘潜在的性能。因此,在计算实现中,需要考虑硬件特性和能力。例如处理器对于不同类型指令性能差异(如大多计算硬件上乘法比加法更耗时和耗能)和存储器层次结构(每一级的延时和能耗都可能相差数量级)。考虑到平台相关的硬件加速能力还有CPU的并行指令、GPU的并行编程等等。
最简单的方法当然是按公式来计算,称为直接法。全连接层其实就是矩阵和向量乘,不用多说。卷积层的定义稍稍复杂一些。为简单先不考虑stride,dilation等特殊卷积,且卷积核size宽高相等。记输入为 X X X,其维度为 N × C i × H i × W i N \times C_i \times H_i \times W_i N×Ci×Hi×Wi,卷积核为 W W W,其维度 C o × C i × K × K C_o \times C_i \times K \times K Co×Ci×K×K,输出为 Y Y Y,维度为 N × C o × H o × W o N \times C_o \times H_o \times W_o N×Co×Ho×Wo,则对输出张量中的每个元素,计算公式为:
Y n , c , x , y = ∑ m = 0 C i − 1 ∑ u = 0 K − 1 ∑ v = 0 K − 1 X n , m , x + u , y + v W c , m , u , v Y_{n,c,x,y} = \sum_{m=0}^{C_i - 1} \sum_{u=0}^{K - 1} \sum_{v=0}^{K - 1} X_{n, m, x+u, y+v} W_{c, m, u, v} Yn,c,x,y=m=0∑Ci−1u=0∑K−1v=0∑K−1Xn,m,x+u,y+vWc,m,u,v
算法复杂度为 O ( N C i C o H o W o K 2 ) O(N C_i C_o H_o W_o K^2) O(NCiCoHoWoK2)。其优点简单粗暴,且几乎无需额外的内存开销。其缺点也是显而易见的,就是效率会比较低。现代计算库一般都会使用一系列的计算实现优化,几个比较典型的如:
我们可以看到,就像其它很多计算任务一样,没有一种实现方法是万能的。因此,用时需要根据实际情况来。实际使用中还会有不少坑,如有些方法可能对精度有较大影响,而有些是基于一些硬件特性假设的。因此,如果你尝试了一种看起来非常牛X的计算优化,结果却不尽如人意,不要伤心,不要难过,很可能只是不满足该算法的某些隐式假设。为了避免人肉挑选之苦,业界也有尝试通过自动化的方法来为神经网络中每个卷积选取最合适的实现算法。
还有一类优化是并行优化。对于矩阵乘加这样天然可并行的计算,不并行白不并行。常用的手段有几类:
再次回到访存优化的话题。无论是CPU还是GPU,都存在存储器层次结构(memory hierarchy)的概念。对于这个层次结构中的每两个层级之间,其速率都可能有数量级的差异。为了让计算尽可能少地访问内存,就需要让程序尽可能cache friendly。做得好和不好有时性能会是成倍的差异。在NN计算优化中,针对访存的优化很多。举两个常见且效果明显的典型例子:
在过去的几年里,服务器市场基本是Nvidia GPU的天下。尽管近几年它也受到了来自TPU等各方面的压力,但总体来说,对于服务器端异构多元化程度没那么大。而与之不同的是,在移动端,不仅硬件种类多,而且同一类硬件差异也大。CPU有ARM和x86的,GPU有Adreno、Mali、Vivante等(虽说有像OpenCL这样的接口标准,但和CUDA不同,毕竟是多厂商各有各的实现,良莠不齐。而且很多厂商还会有私有扩展)。各类芯片如CPU、GPU、FPGA、DSP、ASIC不仅能力各异,算力也有数量级的差异,能效甚至有几个数量级之差。当然,理想情况下,如果ASIC一统江湖,在性能、成本、算子支持等方面都完爆、吊打和摩擦其它芯片,那事情倒简单一些。但这毕竟还需要些时间。因此,当前如何在AI时代充分挖掘和利用这些异构硬件的计算能力就成了一个很有趣的问题。
要解决问题,首先是问题的定义与描述。绝大多数计算任务可以被抽象成计算图,或者更具体地,有向无环图(DAG)。如一个DNN就是一个典型的DAG,一个场景中pipeline的各个节点也可以抽象成一个DAG。如在监控场景,一般摄像头数据进来先做预处理,再进行物体检测,同时可能还会做光流。物体检测结果会送去做细分类(如车牌识别,车型识别,行人ID识别等),另外还会拿来做跟踪。形式化地,计算图记为 G = ( V , E , w , c ) G=(V, E, w, c) G=(V,E,w,c)。节点 V = v 1 , . . . , v n V=v_1, ..., v_n V=v1,...,vn为操作,边 E = e 1 , . . . , e m E=e_1, ..., e_m E=e1,...,em表示操作间的依赖关系。 w i ∈ R w_i \in \mathbb{R} wi∈R对应边上对应的通信代价。 c i ∈ R c_i \in \mathbb{R} ci∈R对应节点上的计算代价。目标是使某个指定的性能指标最小(如整个计算图执行完的时间)。对于异构调度来说,同时还需要满足一些约束。这些约束包括但不限于:有些硬件只能执行整型计算,某些硬件只能支持或者加速某些特定算子,某几个算子需要放在同一设备上跑等等。
显然,这本质上是一个调度问题,而调度问题古而有之。因此,类似的问题也一定被前人研究过。对于一般的调度问题,可以描述为RCPS(Resource-constrained project scheduling)问题。RCPS问题的一种特例为MS(Machine scheduling)问题。MS问题的一种重要特例为JSS(Job shop scheduling)问题。在该问题中,一坨job需要调度到一堆机器上。每个job包含一个或多个必须按序执行的操作。而每个操作必须在指定机器上完成。目标是找到每台机器上的操作序列使得某个性能指标(如makespan)最小。基于JSS问题衍生出非常多的变体和扩展。其中与本节关注问题比较相切的是FJSS(Flexible job shop scheduling)问题。它将操作与机器的绑定关系解除了,即一个操作可以在多台机器上执行。这意味我们还需要确定操作与机器的对应关系,于是调度就分为两个子问题:machine assignment和local scheduling。遗憾的是,无论是对于JSS问题还是它的扩展,亦或是子问题,都是NP-hard的。也就是说,至少在目前的人类文明水平下,无法在多项式时间复杂度下找到最优解。
那么问题来了,怎么解呢?业界大体有这么几类方式:
要进行异构调度,还需要有软件框架。这个框架需要有runtime来进行模型解析、优化、调度、执行等任务,还需要能接入各种硬件加速方案以供调度。硬件加速组件需要用HAL进行抽象封装,这样就可以将runtime与HAL加速实现解耦,让第三方加速方案方便地接入。业界的典型例子如Google的Android NN runtime。自Android 8.1以来,厂商可以通过NN HAL接口接入runtime被其调度。另一个例子如Microsoft的ONNXRuntime。它通过ExecutionProvider接口接入多种加速后端。但是,它们目前的分图和调度方案都是基于比较简单的规则,基本原则是哪个快就让哪个跑。这样的贪心策略注定无法得到全局更优的解。虽然通过异构调度我们可以得到一些性能上的好处,但仍有不少的挑战亟待我们解决。如:
模型的容量(Capacity)即其能拟合复杂函数的能力,简单来说即其表达能力。这是个非常抽象的概念,我们很难用具体的测度衡量它。但很多时候,从统计意义上来说,模型参数越多,capacity相对更大(虽然也不绝对)。它像是一把双刃剑。更强的表达能力当然是我们想要的。然后同时它可能也会让网络更难训练,且计算量更大。从2012年深度学习火热起来的几年里,学界的主流方向就是奔着更高的准确率刷榜,ImageNet就像奥运会百米赛跑一样,记录一次次被刷新。但与此同时,网络也变得越来越重,越来越复杂。而实际使用中,尤其是移动端往往难以运行这样重量级的网络。人们看到这样的问题,于是一系列轻量级的网络应运而生。当然,各个子领域基本都会有针对性的轻量化工作。由于这个topic涉及内容很多,而且网上这方面的介绍多如牛毛。这里篇幅有限,只拿几个经典的通用主干网络简单走一下。另外因一些网络有多个版本,所以这里我想按年份来排:
众所周知,机器学习分为训练和推理两个阶段。在这两个阶段中,计算任务是有差别的。一方面,一些算子在训练时需要,而在推理时是不需要的(或者形式不一样)。另外模型中的计算图可以作很多简化和优化(如冗余计算消除,内存布局优化,Operator fusion等)。因此我们在将训练好的模型部署前会对模型进行一些图优化和转化;另一方面,业界普遍认为模型过参数化(Over-parameterization)和高精度对训练有好处,而在推理时并不必要。这样的假设支持我们可以在不严重影响准确率的前提下对模型进行简化。这样的好处是多方面的。不仅减少了延时,也降低了功耗。同时还减少了内存占用,内存占用的减少还会提高cache利用率,甚至可能原来需要放在DRAM中的模型现在可以塞进SRAM中,从而又进一步提高性能、降低功耗。另外,更小的模型还利于应用更新或者OTA升级。可谓好处多多,一举多得。
深度学习自爆发后朝着更高、更强目标狂奔几年后,比较明显的轻量化之风大约兴起于2015年左右。除了轻量化网络结构设计之外,另一个重要的分支就是模型压缩。当时,韩松等人的deep compression相关工作有着标志性的影响。它通过结合多种压缩方法,将网络模型size压缩了几十倍,性能获得成倍的提升。这让大家意识到当时的DNN模型中可榨油水如此之多。另外,因深度学习领域工作获得图灵奖的三位大神Geoffrey Hinton, Yann LeCun和Yoshua Bengio在该领域也早有布局,做了先驱和奠基性的工作,如Hinton的知识蒸馏,Bengio在量化模型训练方法上的研究及二值化网络BinaryConnect,和LeCun用于网络参数裁剪的OBD方法以及低轶分解方面的工作。
在文章的末尾,我想简单聊下个人以为的,对于未来发展趋势和方向的,一些不成熟的看法。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。