zoukankan      html  css  js  c++  java
  • 算子算力计算

    1. 仅基于算力或者算子算法的公司成功率比较低,只有少数头部企业赢者通吃:反例寒武纪被华为抛弃,正例如英伟达也要持续观察,即便是正例,也要看到TESLA抛弃它做FSD,蔚来小鹏蠢蠢欲动想做自己的芯片
    2. 基于场景看比较容易成功,软硬结合护城河比较深:比如监控识别的海康大华,自动驾驶的Mobileye、可能成功的地平线。扫地机器人的科沃斯和石头科技,都是对细分场景理解深刻的。
    3.大数据的积累非常重要,自学习的基础:自动驾驶的路测数据;医院的CT片、案例等
    嵌入式AI框架Tengine的架构、算子定制和引擎推理

    本文主要分为以下几个部分:

    1、嵌入式AI面临的挑战和Tengine的解决方案

    2、Tengine架构解析

    3、Tengine API简介

    4、实践1:Tengine扩展,定制和添加算子

    5、实践2:Tengine在CPU/GPU/NPU/DLA上的推理

    Tengine是一个嵌入式AI计算框架,公司的一个核心产品,首先在算力层面做了许多工作,通过与国内众多芯片厂商建立深度合作关系,采用各种技术方案去充分发挥硬件的计算性能,所以,在全力打造一个AI的算力生态平台,希望通过Tengine,能够很方便的调用到底层芯片的算力。

    其次,提供一系列的产品和工具包,方便算法训练出来后,面对端侧落地时需要解决的各种问题,能够有一套标准且快速的方法去解决这些问题,加速整个AI产业的落地。这是一个目标,所以未来的Tengine会演化为一个AIoT的开发和部署平台,而不仅仅是一个推理框架。

    嵌入式AI面临的挑战和Tengine的解决方案

     目前,嵌入式AI存在哪些问题呢?首先,可以看到AI对日常生活的渗透变得越来越强烈,可以说AI如电力将无处不在,这个趋势的形成主要有两方面的原因,第一是端侧计算算力的提升,即CPU的演进和各种各样NPU的出现;第二是算法本身的进步,可以看到从最早的VGG到Inception v1、v2、v3再到EfficientNet,算法本身也在不断的轻量化,导致以前只能跑在服务器上的AI应用,现在可以在端侧运行。另一个问题是大家对于数据安全和隐私越来越关注,这也导致越来越多人希望AI计算能够在本地上运行,就尽量不在云端上运行。对于端侧AI,16年是元年,到现在为止还处于一个快速的爆发期。

    上面主要介绍前端的应用需求,那具体的产业链是什么情况呢?产业的情况目前是非常不友好的,第一体现在硬件的多样性,AIoT市场硬件的多样性是天然存在的,现在各种各样AI加速的IP出现导致多样化更严重。而且随着AI的进一步应用,以前认为不太可能跑AI的硬件,如MCU等,现在也可以跑一些AI的算法,所以整个硬件平台多样性越来越严重。

    第二体现在软件的多样性,现在有很多种训练框架,那训练框架训练出来的模型送入嵌入式平台,目前也是处于百花齐放的状态,各种各样的框架也很多,训练框架有的是原生的,也有第三方开发的。所以对于应用开发人员来说,怎样把一个算法落地到平台上,这中间的过程还是非常长的。

    以上是针对应用开发人员,那对算法开发人员,这也是一个很严重的问题。训练好的模型,要把它落地到一个算力有限的嵌入式平台,可能需要对模型做调整,把它的规模减小,还需要做量化及很多工作之后,才能实现落地。如果还想用嵌入式平台上的加速芯片,还需针对芯片做一些调整,可能有些算子不支持,需要做替换,或者定义上有差别。所以,整个的生态是非常不友好的。

    在这种多样性环境下,可以看到整个AI产业链工作效率非常低下。对于芯片公司,擅长做算力的提升,但发现如果只做芯片,做简单的驱动,很多的AI的开发者是没办法用起来的,所以它需要投入大量的资源去做上层的开发平台和开发环境,例如国内的华为公司,从芯片到ID环境到部署环境,整个一条产业链都做了

    算法和应用公司也发现如果不去完成底层硬件的适配,训练好的一个模型可能在训练时效果会非常好,真正落地到平台上时,要么性能特别慢,要么精度特别差。所以,需要亲自把模型适配并优化好,这样算法才能真正的应用与落地。觉得整个产业链分工非常不明确,效率低下,这也是去试图改进和解决的问题。

     算法和应用公司也发现如果不去完成底层硬件的适配,训练好的一个模型可能在训练时效果会非常好,真正落地到平台上时,要么性能特别慢,要么精度特别差。所以,需要亲自把模型适配并优化好,这样算法才能真正的应用与落地。觉得整个产业链分工非常不明确,效率低下,这也是去试图改进和解决的问题。

    1)开放,开放主要从两点去关注。第一是开源,因为希望有更多的人用Tengine,所以做一个开源的措施。第二是模块化,因为AI的整个软件和硬件都还在快速的发展,需要提供很好的方式去支持新出现的算法、模型以及硬件,所以以模块化的方式去构建整个软件。

    2)高效,因为在SOC平台算力永远是一个瓶颈,所以想让算法在平台上跑得快、跑得好,对它做优化是不可少的。而,主要从两个层面做优化,第一是在图的层面做优化,第二个是实现高性能的计算库,这个计算库是完全自主知识产权的。

    3)连接,首先是连接算法和芯片,不论算法或者芯片变化,都希望尽可能减少中间对接的成本。接着是,还需要考虑支持多个计算设备的情况,能把多个设备之间的调度和使用连接起来。这是Tengine作为一个推理框架赋能产业时,做的三件事情。

     Tengine怎么样助力AIoT的应用开发呢?上图展示的是一个标准算法落地的过程。最左边是算法训练,然后再通过Inference server对外提供server里的标准工作流程。当需要在SoC上去做时,第一件事是对模型做优化,然后对模型做量化,这时有可能会出现精度和速度的下降情况,还需要把原始的模型去做一些修改,这个过程可能会反复很多次,改完之后,可以把它放到某一个inference engine上,然后在芯片上跑起来。

    上面介绍的只是算法模型部分,真正的一个AI应用包含数据的记录和结果的输出。上面还可看到一个前处理、后处理的环节,不管是摄像头来的数据,还是传感器来的数据,都需要经过一定的前处理,再把数据送入推理引擎,推理引擎的结果也需做一定的后处理,才能够交给应用程序做进一步的分析和处理。在量化的过程中,有可能会造成一定的精度的损失,对一些精度要求比较高的场景,比如人脸或是支付场景,这种损失还需要尽量避免,所以还需要针对量化去做重训练。

    Tengine为了加速AIoT的落地过程,如上图蓝色框的内容,都是Tengine做一些工作的地方。针对常见的主流的训练框架,提供了一个量化重训练的工具包,对于前处理和后处理也提供了专门的算法库来加速。

    Tengine架构解析

    下面重点针对Tengine的推进引擎部分做简单介绍。主要分为以下几部分,首先是对整体架构的简单介绍,然后会介绍对训练框架的支持情况,因为这部分对于落地来说是最关键的,最后是计算图的执行,以及高性能计算库和配套工具。

     

    – Tengine产品架构

    Tengine产品架构如上图所示,最上面是API接口,对于API接口,进行了仔细的研究,因为,认为要去构建一个Tengine的AI应用生态,API的稳定性是第一位的,这样才能够保证整个生态能够持续发展。

    下面是模型的转换层,可以把各种各样主流的训练框架模型转换成Tengine的模型,然后再端上运行,接着,会提供一些配套的工具,包括图的编译、压缩、调优,以及进行仿真的一些工具,还提供了一些常用的算法库,包括前处理、后处理,以及面向一些特定领域的算法库。

    接着下面是真正的执行层,包括图的执行、NNIR,NNIR是Tengine的图的一个表示,包括内存优化、调度和加密都在这里实现。再下面是对操作系统的适配,Tengine 目前已经支持RTOS和Bare-Metal的场景,这些都是为了支持特别低端CPU去做的。在异构计算层,已经能够去支持CPU、GPU、MCU、NPU等,也会介绍在GPU和DLA上的用法。

    – 训练框架与OS适配

    对于训练框架,现在已经支持TensorFlow、PyTorch、MXNet等;对于主流操作系统,基本上Linux一系列都可以支持,还有RTOS也支持,后续还会把 IOS和Windows加上。

    – 模型转换方案

    模型转换方案本质上是把其它框架模型转换成Tengine的模型。有两个办法做模型转换,第一个是可以用Tengine提供的转换工具,自动转化。第二个需要用户自己去写一些代码,相当于可以用Python脚本把原模型的所有的参数和数据提出来,然后在通过Tengine接口去构建一个Tengine NNIR的图,最后再保存为Tengine的模型。所以,模型转换方案,与其它方案不太一样。第一步是先把所有的模型解析成Tengine的NNIR格式,第二步再保存成Tengine模型。理论上,Tengine NNIR可以直接去执行,也是没有问题的。所以,利用这个方法还可以做更多的事情。比如可以把Tengine NNIR保存为一个Caffe的模型,这样就把Tengine作为一个模型之间转换的工具。做一个好的模型转换工具很不容易,定义Tengine NNIR时,其实也踩过很多框架之间兼容性的坑,虽然市面上可以看到有各种各样的转化工具,其实都会有多多少少的坑在里面。

    – Tengine模型可视化工具

    Tengine模型转化完之后,需要关心下模型转化结果对不对?是不是符合预期?和开源社区的模型可视化工具软件Netron进行了合作,实现Netron对Tengine模型支持,如果下载最新版本的Netron,已经对Tengine有很好的支持。

     

     如上图所示的一个例子中,是SqueezeNet的最初的几层,第一个Convolution的属性,如上图右边所示,输入是一个data,然后有一个filter和一个bias。可以看到,因为Tengine实际上是对着图做一些优化,所以属性会多一个activation。activation为0表示是一个ReLU的activation,实际上是把Convolution和ReLU合并在一起。这个工具能很好的展示Tengine模型结束后模型转化的结果,也是个非常好用的工具。

    – 计算图执行

    对于计算图的执行,所有模型加载过来,不管是其它框架模型还是Tengine模型,都会转换成Tengine NNIR,这需要去屏蔽各种框架的差异,把兼容性做得非常好。得到Tengine NNIR后,要决定这些节点在哪个设备上执行,如果系统只有一个设备,问题比较容易解决。但当系统存在多个计算设备时,会遇到一些困难,第一个是两个计算设备可能特点会不一样,比如其中一个性能比较高,但有些算子不支持,另一个设备性能比较低,但算子支持程度会比较好。采取什么策略去做,切成多个,还是集中在一个上去算?这属于静态情况,若是动态情况就更复杂。

    假定设备A当前看起来很闲,但当准备把这个任务发给它时,可能会变得很繁忙。所以目前为止,一直没有特别好的解决方案。这里更接近于OpenVX的方案,OpenVX的方案实际上是所有计算设备需要按需求定一个优先级,得到一个计算图之后,计算图会按照优先级去询问底下设备,能不能支持这个节点。如果有一个设备响应了,这个节点就不会再分配给其它的设备。方案类似,不同点在于,会让计算图在所有的计算设备都看一遍,并不只是终结到某一个为止。

     

     通过这种方式,可以确定这个图的哪个节点在哪个设备上去算,确定完之后,根据设备分配的情况,把图切成多个不同的部分。上面的示意图是举的一个例子,实际上是切成4个部分,这4个部分图之间会有一定的依赖关系,有些图可以并行执行,有些图不能并行执行。假定黄色和蓝色是可以并行执行的,构成一个执行图,接下来把这个图调度到各个设备上去执行,可以看到黄色和蓝色的计算图,可以同时在两个设备上去跑,这是大概整个计算的一个过程。

    – 发挥硬件极致性能的计算

    真正在设备上跑时,还需要把算力尽可能发挥出来。对计算库做了大量的优化,花精力最多的是整个神经网络里面最耗时的一部分算子包括卷积,全连接层和池化。卷积根据参数的不同,也实现了各种不同的计算模式,比如基于GEMM、Direct和Winograd的,一般情况下,库的双向加速比可以达到175%,四线程可以达到300%,对于有些网络还会更好,四线程将近接近400%。

    对于优化,实际上是针对CPU的微架构做优化。在一个完整的网络运行的情况下,可以看到Convolution MAC利用率可达到70%,基本上是把硬件的性能给用尽了,对Arm的全系列产品都做了很好的适配。

    计算库不仅对FP32有很好的支持,对INT8也做了很好的优化,这样才能够充分发掘出硬件的算力,可以看到INT8比FP32基本上能提速50~90%。同时也注意到INT8还是会带来一些精度损失,计算库还支持混合精度计算的模式,对于精度损失大的层,可以采用FP32计算,其它可以采用INT8计算,这是一个能够同时兼顾精度和速度的方案。对于开源版本的FP32的性能,整个的效果是非常不错的,Squeezenet都不到60毫秒。

    – 量化重训练工具

    刚才提到INT8对于端侧推理,现在基本上是一个必选项。但INT8的精度的问题一直困扰大家,再看下现在主流的训练框架,除了TensorFlow有个TensorFlow.Net之外,其它的框架目前都没有非常完整的一个量化重训练方案。针对这个问题,做了一个量化重训练的工具,还针对NPU做了一些改进,因为NPU的芯片厂商对于训练并不是特别熟悉,所以,希望能够去改进在NPU上跑的量化精度,让更多的应用在NPU上去跑起来。

     如上图右边所示为量化重训练的结果,可以看到整个效果是非常不错的。特别是对于MxNet_MobileNet,重训练后的精度可以提高两个百分点。

    除了Tengine整个配套工具及量化重训练之外,对于前处理、后处理,也做了不少的工作,实际上有个HCL.Vision的模块,针对CV的应用做的一个计算库。这个计算库与其它CV计算库不同点,在于若硬件平台上有一些图像处理的加速,会去调用底层硬件平台接口来处理,若没有,会用做一个优化的CPU的实现,对外会提供一个统一的接口,这对于开发应用程序就非常方便了。在接口不变的情况下,在一个有硬件加速的平台上就能够获得硬件的加速。

    Tengine API简介

    下面进入Tengine API的部分,首先介绍下对API设计的想法,后面再介绍下目前API的一些应用。

    – 概述

    在刚开始做Tengine时,把API放在一个很重要的位置,同时也学习和参考业界一些优秀的软件方案以及框架。实际上主要参考了Android NN、OpenVX、TensorRT、TensorFlow、MXNet的接口设计原则和思路,最后更偏向于OpenVX。

    ,有两个原则,第一个是接口的定义和实现完全无关,这主要基于现在AI的软件和硬件还处于一个快速发展的情况下来考虑的。如果接口定义会绑定某些实现,会对代码重构或支持一些新的特性时,带来很大负担,所以把接口定义和实现完全抛开。

    第二个是要注重接口的稳定性和灵活性,稳定性对于所有的API都非常重要。为什么还特别强调灵活性?与上面类似,未来会怎么样,不是很清楚,所以要尽可能预留一些接口,去支持未来要出现的功能以及给应用程序对底层有更多的操控权,这样会更有利于Tengine应用生态的稳定性和长期发展性。

    对于硬件这块,一直考虑怎么样能够对Tengine支持的更好。在端侧跑一些训练的模型,可以看得见的趋势,所以接口也要去支持模型训练。从本质上来说,Tengine是连接算法和芯片,通过一个标准的接口把芯片的算力提供给应用。这对于实行和训练的方案,也是很有价值的。最后,看下结果,采用C的接口作为核心的API,然后基于C去封装一些更好用的API,比如C++ API或者Python API,这两个API目前已经实现了,规划中还有JS API和Java API,都会基于C API去做,这是整个API体系的一个想法。

    – 多芯片和软件后端支持

    在进入AIoT市场时,知道未来一定是有多种AI加速芯片和AI IP的出现,怎样让应用程序在不同的芯片或不同的AI加速IP之间迁移,工作量能更少。可以看下,方案是应用程序通过一次性的接口,就能够调到各种不同的算力。如上图最左边可以看到,在一个RK3288或树莓派Linux上去实现推理的一个用法,调用Tengine模型,右边第一行是一个MCU的平台,可能需要换一种新的模型就好,换为tiny模型,不再是Tengine的一个模型。如果是NPU,只需要把中间模型的格式给换一下,其它部分基本上都不需要去改动,这样不管是应用程序的维护,还是学习成本都会很低。

    基于,API会发现,对于现在的开发商降低很多复杂度。比如一个应用,希望既能在安卓上跑,又能在Linux上跑时,可以调Tengine接口,都能很好的调用到底层硬件的算力。在安卓下会更复杂,因为Google提出Android NN API的一个接口,在之前并没有这个接口,假定有一个应用程序,既想调用这个接口,没在Android NN的平台上,怎么办呢?

    实际上,可以用中间的方案,仍然调用Android NN API,但是通过重新实现Android NN Runtime让Tengine调底下的一个算力,这样可以保证用程序,不必担心在不同平台上需要去切换接口的问题。由上面的场景可以看到对底下的芯片公司价值最大,而芯片公司,只需对Tengine做试配之后,对于各种场景都能够很好的为应用程序提供一个算力的功能。

    – C++ API和Python API

    下面介绍下C++ API和Python API,这两个主要是为了快速简单去使用,所以会把C API里面很多的功能去掉。看一个典型的用法,分为4步,第一步是加载模型,第二步是设置输入数据,第三步是run,第4步是取一个接口。

    Python API与C++ API类似,只不过变成Python结构下也能调这些东西。

      C API相对来说,核心API会比较复杂,可以分为几大类,第一大类是Tengine的初始化,destroy,接下来是跟Tengine整个NNIR对应,Tengine里面有Graph的概念,有Node的概念,有Tensor的概念。这部分概念跟TensorFlow会更像些。对于Graph,包含Graph创建,Node的创建,所以通过Tengine接口,可以去创建一个图的,这也是为了支持模型转换及训练等功能区做的考虑。接下来还是图执行的接口,包括Prerun和Postrun,剩下都是一些杂项接口,比如,设置日志的重新项,可以去graph和节点绑定一个执行设备。

    下面介绍下用C API去做推理的典型过程,与刚才差不多,可能稍微麻烦一点就是需要主动调一个prerun的接口,prerun接口完成把计算图绑定一个设备的问题,以及在设备上分配给计算图做计算所需要资源的过程。接下来是去设Tensor的buffer,然后再去run。

    – C API创建图和节点

    首先是创建一个空的图,空的图代表什么都没有,不来自于任何的框架;接下来需要创建一个input节点,input节点需要创建两个东西,第一个是Node,第二个是Tensor,将Tensor设置为节点的output的Tensor,这一点的思路是和TensorFlow完全一致,所以会与TensorFlow会长得比较像一点;再接下来是创建一个Convolution节点,与上面的input节点类似,首先需要创建一个节点,并指定这个节点的op是一个Convolution;之后要创建这个节点输出的Tensor;再下面把输入的Tensor设好,比如说0、1、2,分别设定input_tensor、w_tensor和b_tensor,这三个就构成了这个节点;Convolution还有很多参数,比如kernel size,stride,padding怎么去设?提供了一个接口,可以直接设置节点的属性,可以通过程序直接设置。

    实践1:Tengine扩展,定制和添加算子

    前面已基本上介绍完接口,下面再结合具体的代码给看下,怎么样去扩展和定制算子。

    – Tengine算子kernel定制

    首先是算子kernel的定制,若Tengine里已经实现一个算子,但和目前实现的框架有差别时,需要一个更好的实现,或平台上有一个硬件可以对算子做加速,不希望用,已经做好的,有两种办法去解决,第一种是通过C API的custom kernel的接口做替换,但替换时需要指定哪个节点来做,这类接口学习成本可能会低些,不需要了解Tengine添加一个新算子的过程,只需要做计算。

    第二种情况是可以用Plugin的实现,通过一个外挂模块来把算子重新实现,只不过在注册时,把实现的优先级提高。这样做完之后,所有关于这个类型算子的实现,都会用算子来做。

    先介绍下用Tengine C API去做替换的方式,然后Plugin的方式会在后面一个例子中怎么去添加一个新算子。

     Tengine C API里有一个的custom kernel的接口,这个接口最关键的数据是custom_kernel_ops,定义了custom kernel需要实现内容,数据结构如上图所示,第一个是op,op是表明要去做一个convolution,还是要去做一个pooling,在接下来是两个parameter,一个kernel_param,一个kernel_param_size,是给算子去用的。然后三个最关键函数:prerun、run、postrun,传进去首先是ops,就是ops自身,接下来是input_tensor和output_tensor。其它的参数,需要在parameter里找出来。

    这个设置完之后,可以去调set_custom_kernel去替换设备上的实现。现在,可以去看下代码。

    http://oss.zhidx.com/uploads/2020/06/5ed9cb6be1a11_5ed9cb6bd6f9b_5ed9cb6bd6f54_1J.mp4

    – Tingine新算子的添加

    新算子的添加,对于推理框架也很重要,特别是针对Tensorflow的情况,由于Tensorflow算子既多又复杂,当遇到不支持算子时,推荐先用plugin的模式在Tingine Repo外实现。待测试稳定之后,再提交PR合入到Repo里。

    下面以Tensorflow新算子Ceil为例,一共有以下几件事情:第一是在Tengine NNIR中注册一个新的算子定义;第二是在Tengine Tensorflow Serializer中注册算子的模型加载;最后需要在Tengine Executor里面真正实现算子,可以看代码。

    http://oss.zhidx.com/uploads/2020/06/5eda07243f6ca_5eda07243b689_5eda07243b623_2.mp4

    实践2:Tengine在CPU/GPU/NPU/DLA上的推理

    下面看怎样做推理,选了一个MobilenetSSD来做,一共有三个例子,第一个是单独用一个是 CPU跑,第二个是CPU+GPU配合跑,第三是多设备跑的情况,可以看下MSSD的例子。前面在CPU、GPU下运行的情况,假定是一个NPU或一个DLA时,怎样能用起来?看一个演示:

    http://oss.zhidx.com/uploads/2020/06/5ed9ddf4a53b9_5ed9ddf4a0f98_5ed9ddf4a0f49_4.mp4

    由上面可以看出,调用NPU 是一件非常容易的事情,对于学习成本和应用开发速度都有很大的提升。



    人工智能芯片与自动驾驶
  • 相关阅读:
    List of the best open source software applications
    Owin对Asp.net Web的扩展
    NSwag给api加上说明
    'workspace' in VS Code
    unable to find valid certification path to requested target
    JMeter的下载以及安装使用
    exception disappear when forgot to await an async method
    Filter execute order in asp.net web api
    记录web api的request以及response(即写log)
    asp.net web api的源码
  • 原文地址:https://www.cnblogs.com/wujianming-110117/p/14835504.html
Copyright © 2011-2022 走看看