什么是前端智能推理引擎在前端智能推理引擎之前,我们先来说说什么是“端智能”。On-DeviceMachineLearning是指将机器学习的应用放在设备端。这里的“设备端”是相对于云服务而言的。可以是手机,也可以是IOT设备等。传统的机器学习,由于模型的大小和机器的计算能力,多在服务器端完成。比如AmazonAWS有“AmazonRekognitionService”,Google有“GoogleCloudVisionService”。随着以手机为代表的端侧设备计算能力的提升,以及模型设计本身的演进,体积更小、能力更强的模型逐渐可以部署到端上运行。与云端部署方式相比,APP端具有更直接的用户特性,具有以下优势:实时性高,端侧处理可以节省数据网络传输时间。节省资源,充分利用端侧计算能力和存储空间。隐私性好,从生成数据到消费数据都在端侧完成,避免了传输带来的隐私泄露风险。这些都是端到端智能化的优势,但不是万能的,还有一些局限性:设备资源有限,端侧算力和存储有限,大规模高强度连续计算无法执行。算法规模小,终端计算能力小,单个用户的数据无法在算法中最优。用户数据有限,端侧数据不适合长期保存,可用数据有限。同理,前端智能是指将机器学习应用放在前端(web、h5、小程序等)。那么,什么是前端智能推理引擎呢?如下图所示:前端智能推理引擎其实就是利用前端的计算能力来执行模型的东西。业界现有的前端推理引擎下面介绍三种常见的推理引擎tensorflow.js(以下简称tfjs)ONNX.jsWebDNN对于一个on-end推理引擎,最重要的是什么?当然是性能!性能越好,端上的应用场景就会越多。下面看一下这三种推理引擎的性能对比:(以下数据使用模型为MobileNetV2分类模型)cpu(js计算)可以看出,在纯JS环境下计算,需要1500多ms才做一分类。试想一下,如果一个摄像头需要对捕捉到的物体进行实时分类预测(比如预测捕捉到的物体是猫还是狗),那么每次预测需要1500ms,这样的性能是难以忍受的。WASM在WASM环境下,性能最好的ONNX.js达到了135ms的性能,也就是7fps左右,勉强可以用。tfjs是可怕的1501毫秒。这是因为onnx.js使用worker进行多线程加速,所以性能是最好的。WebGL(GPU)最后是GPU环境。可以看到tfjs和ONNXjs的性能已经达到了比较好的性能水平,而WebDNN的性能就比较差了。除了以上三种引擎外,目前国内还有百度的paddle.js和淘宝的mnn.js,这里不再赘述。当然,在选择合适的推理引擎时,除了性能之外,还有生态、引擎维护等一系列的考虑。综合来看,tfjs是目前市面上最适合的前端推理引擎。因为tfjs可以依托tensorflow强大的生态和谷歌官方团队的专职维护。相比之下,ONNX框架比较小众,ONNXjs也快一年没有维护了。WebDNN无论是性能还是生态都没有任何竞争力。前端的高性能计算方案其实从上一章就可以看出来。一般而言,基于WASM和WebGL的GPU计算更多用于前端的高性能计算。当然还有asm.js,这里不多说。WASMWASM大家都应该很熟悉,这里只是简单介绍一下:WebAssembly是一种运行在现代网络浏览器中并提供新的性能特性和效果的新型代码。它不是为手写代码而设计的,而是为C、C++和Rust等低级源语言提供高效的编译目标。对于web平台,这具有巨大的意义——它为客户端应用程序提供了一种以接近本机的速度在web平台上运行以多种语言编写的代码的方式;可能的。此外,您可以在不知道如何编写WebAssembly代码的情况下使用它。WebAssembly模块可以导入到Web应用程序(或Node.js)中,并公开WebAssembly函数以供JavaScript使用。JavaScript框架不仅可以使用WebAssembly获得巨大的性能优势和新特性,还可以让Web开发人员轻松使用各种功能。--《摘自MDNWebAssembly概念》WebGL是什么?WebGL不是用来做图形渲染的吗?不做3D?为什么要做高性能计算?可能有些同学听说过gpgpu.js库,它使用webgl进行通用计算。具体原理是什么?(为了能够继续阅读,请快速浏览这篇文章):《利用WebGL2 实现Web前端的GPU计算》。推理引擎的性能已经优化到极致。现在我们知道了前端的两种高性能计算方式,那么如果现有框架(tfjs、onnxjs)的性能不能满足我们的需求怎么办?我们如何进一步提高引擎的性能并在生产环境中实施?答案是:手撕源码,优化性能。是的,就是这么简单粗暴。下面以tfjs为例(其他框架原理相同),介绍一下如何使用不同的姿势来优化引擎性能。去年初,我们团队与谷歌的tfjs团队进行了深入交流。Google明确表示tfjs的发展方向主要以WASM计算为主,webgl计算不做新特性,专注于维护。但现阶段浏览器和小程序还没有完全支持WASM(如SIMD、Multi-Thread等),所以暂时无法在生产环境中实现WASM。所以现阶段,我们还是需要依赖webgl的计算能力。不好的是此时tfjs在移动端的webgl性能还是差强人意,尤其是在中低端机器上的性能根本不能满足我们的业务需求。没办法,只能硬着头皮进去优化引擎。因此引入以下内容进行webgl计算。为WebGL高性能计算优化n种姿势姿势一:计算矢量化计算矢量化是指利用glsl的vec2/vec4/matrix数据类型进行计算,因为对于GPU来说,最大的优势就是计算并行化,通过vectorDecomputing可以达到效果尽可能并行化。例如矩阵乘法:c=a1*b1+a2*b2+a3*b3+a4*b4;可以改为c=dot(vec4(a1,a2,a3,a4),vec4(b1,b2,b3,b4));矢量化还要配合内存布局的优化;姿势二:内存布局优化如果你看过上面的文章《利用WebGL2 实现Web前端的GPU计算》,你应该明白GPU中所有的数据存储都是通过Texture进行的,而Texture本身就是一个长n*宽m*channel(rgba)的东西4.什么如果我们要在里面存储一个3*224*224*150的四维矩阵呢?肯定会涉及到矩阵的编码,即将高维矩阵以一定的格式存储在具有特征形状的纹理中,而Texture的数据排列会影响计算过程中的读取和存储性能。比如我举个简单的例子:如果是常规的内存排列,一个计算需要按行或按列遍历一次矩阵,而GPU的缓存是tile类型,即n*n类型缓存。根据不同的芯片n不同。所以这种遍历方式会频繁的造成cachemiss,成为性能瓶颈。因此,我们需要通过内存布局来优化性能。类似下图:姿势三:图优化由于一个模型是由一个个operator组成的,而GPU中的每个operator都被设计成一个webgl程序,每次切换程序都会造成更多的性能损失。所以如果有办法减少模型中的程序数量,性能提升也是相当可观的。如下图所示:我们在图结构上融合一些可以融合的节点(nOP->1OP),基于新的计算节点实现一个新的OP。这样一来,OP的数量就大大减少了,进而减少了Program的数量,从而提高了推理性能。这种效果在低端手机上尤其明显。姿势四:混合精度计算以上所有计算都是基于常规浮点计算,即float32单精度浮点计算。那么,混合精度计算能否在GPU中实现呢?例如,float16、float32、uint8混合精度计算。答案是肯定的,在GPU中实现混合精度计算的价值在于增加GPU的带宽。由于webgl的纹理的每个像素包含rgba的四个通道,而每个通道最多32位,所以我们可以在32位中存储尽可能多的数据。如果精度是float16,那么可以存两个float16,带宽是之前的两倍。同样,uint8的带宽是前一个的四倍。这种性能提升是巨大的。再说上图:姿势n:……优化的方法有很多,这里就不一一列举了。引擎落地场景目前,基于我们深度优化的引擎,已经在蚂蚁集团、阿里经济体的多个应用场景落地。比较典型的就是文章开头演示的宠物识别,以及卡片识别、碎屏摄像头等场景。行业内有虚拟试妆小程序,之前比较流行。阅读本文的小伙伴们也可以脑洞大开,挖掘出更多更有趣的智能场景。未来展望随着市场模型的升级和引擎的深度优化,相信tfjs会在更多交互场景大放异彩,比如具备AI能力的前端游戏、AR、VR等场景。我们现在要做的是静下心来,站在巨人的肩膀上,继续打磨引擎,静待花开。
