端侧计算性能提升的思考

前言

随着计算机算力的提升及数据爆炸式的增长,人工智能开始运用在各方各面。算力的提升得益于GPU的良好的发展。以目标检测为例,输入的图像能够在多层的特征提取的操作后获取一个输入图像中感兴趣物体的分类得分以及表示物体的bbox。而每层输入特征图与卷积核的运算原理就是矩阵的运算。而这更加适用于GPU来进行运算。

其次,人们常说的挖矿,说十年前要是能买几个比特币现在是不是发达了,无可厚非,确实是发达了。区块链技术因比特币而火。所以,到底什么是挖矿,日常生活中的讨论也没听见几个解释是自己认同的,或者说产生共鸣的。
我阐述一下:挖矿换成书面语言就是记账,在POW共识机制下利用工作量证明机制来达成共识的过程,以计算机语言可以理解为就是做hash运算来得到某一预先设定特性的hash值,而这个预先设定的特性就是矿池的难度。由于比特币的总量恒定,所以现在越来越难挖,各种矿主出现,工厂似的矿机矿池,也就是GPU集群。

上述AI与区块链的计算都需要做大量的科学运算,所以,无论我们在做实验还是在挖矿操作,都会需要说越多的机器(GPU)堆在一起越好,效果那是肯定的,GPU本来就擅于数据的并行计算,多个GPU的效果带来的计算效率那就是就是杠杠的。

但你是否有一些感悟,随着互联网的发展或者说用户对软件的体验的不断提高,又或者说软件架构的不断升级,在进行一些集中式的AI算法处理貌似已经不太合适。无论从哪些方面都感觉不太合适了。

举个例子,之前在某厂待的时候,主要做视频的的智能裁剪及视频数据的上下游分发,算法侧主要是CV、NLP等,日均耗费40万RMB在支持算法的机子上。貌似某些小型算法其实可以部署在端侧进行,在用户无感知的情况下能够节约成本,同时这种端侧的处理更加贴近用户,拥有用户的最直观的特征。而不是通过一层一层协议包装后的数据,即使可能也不会有太大的变化
端侧部署的方式相比云端部署带来的好处是显而易见的:
1.实时性高,端侧处理可节省数据的网络传输时间。
2.节省资源,充分利用端侧算力和存储空间。
3.隐私性好,产生数据到消费数据都在端侧完成,避免传输引起的隐私泄露风险。
但端侧的算力确实是一大瓶颈,即使是做一些简单的运算也会有一些不好的体验,这里可以看看我开发的浏览器挖矿demo以及浏览器端跑posenet的实例,虽然做了一些人性化的处理,但是集中在端侧的算力计算使得用户的体验不是那么的好。

GPU为什么适合大量科学(重复)运算

设计之初,CPU与GPU就被设计为了解决不同问题的不同角色,CPU是我们计算机的核心,是调度者,其不单单用于运算操作,主要设计目标是低延迟。其中含有强大而少量的算术逻辑单元ALU和容量较大的缓存cache。而GPU目前主要的应用场景是:图像渲染、视频解码、深度学习、科学计算等,最适合多数据流单指令流的计算,主要设计目标是高带宽。其中含有大量算术逻辑单元ALU。但cache较小。
而算术逻辑单元ALU是能实现多组算术运算和逻辑运算的组合逻辑电路。当需要对大量的数据做同样的事情时,GPU就变得更加合适,当需要对同一数据做很多事情时,CPU就显得更加合适了。
CPU与GPU架构对比简图

端侧的局限性在哪儿

其实主要矛盾点就是在于端侧的算力问题,计算性能瓶颈,无法有大量的GPU支撑,这是最大的局限性。要在端侧进行大量的运算,需要端侧具有较好的语言运行计算性能。以JS为编程语言的端侧为例,以JavaScript为基础编程语言来做科学运算。总所周知,JS是一门动态,弱类型,解释性语言,那不具有编译器么?不是不需要编译,而是运行时的编译。对JS的运行需要一个JS引擎,最常用的就是V8。从开始运行JS代码。V8引擎会解析码源并将其转化成抽象语法树(AST),通过AST解释器(interpreter)会进一步地生成字节码,然后运行。

解释器启动和执行是很快的。因为不需要等待整个编译的过程就可以完成代码执行。从第一行就开始翻译,依次地执行了。那么对于web软件或者说平台,能够更快的去执行部分代码,让用户看着见是更重要的事情。但是对一些重复性的代码,解释器需要一遍一遍的去进行翻译,就会导致代码的运行效率下降,性能就降低了。而我们以上所述算力就是用在了大量重复的计算中,这就显得JS比较局限。相反,这个时候就可以体现出编译型语言的优势了,这类语言的执行可能需花费比较长的时间在对整个码源进行编译,生成可在机器上执行的代码,但由于事先编译好了,在编译过程中就对代码进行了优化,所以对于重复性工作来说不需要额外的花费。性能就会更好。

当然,我上面所说的V8对JS的解析过程只是一个粗略的阐述,V8是对整个JS执行过程有这各种各样的优化的,业界的各大厂为了提升性能给出了定制的引擎优化方案,例如【JUST IN TIME】通过在解释器中加入一个分析步骤,对代码的运行的情况做一个分析,记录代码运行次数,如何运行等信息。并进行状态标记来进行代码优化,提升执行效率与性能。

端侧AI应用

我简单的理解端侧AI是将AI能力结合需求放在客户端(app,web,H5)进行算法预测的过程。我觉得这是一个必然的趋势,例如:轻量级的CNN模型MobileNetV2。
pic

我们在进行算法训练的时候,我们会选择一个适合的算法层面的实现框架,例如pytorch,tensorflow,caffe等,选择的过程中往往伴随着源代码是否有无,社区是否完备,上手是否简单,编写是否容易等等等,但是不可忽略的一个重点是框架的性能。端侧(js)也有许多推理框架:
1.tensorflow.js
2.ONNX.js
3.WebDNN
4.paddle.js
5.mnn.js
但都是以JS为基础编程语言的实现,我上面所提的posenet的实例就是以TF.js实现的一个demo,显得捉襟见肘,如何提升端侧框架的执行效率和性能显得十分重要。

端侧算力提速

1.webworkers
The Web Workers specification defines an API for spawning background scripts in your web application. Web Workers allow you to do things like fire up long-running scripts to handle computationally intensive tasks, but without blocking the UI or other scripts to handle user interactions.

换成人话:WebWorkers是一个HTML5的新API,web开发者可以通过此API在后台运行一个脚本而不阻塞UI,可以用来做需要大量计算的事情,充分利用CPU多核。然后这里可以尝试下webworkers的实例!的真实效果。

webworkers的浏览器兼容情况如下:基本都已经支持了webworkers
webworkers

parallel是提供的一个对webworkers的一个封装,可以应用在node端也可以应用在浏览器端,其可以根据你的cpu的内核数分配线程数,然后利用map与reduce接口能够很方便的进行并行运算,加上日期函数就可以很方便的对比单线程与多线程处理同一个问题上不同的时间了。例如:计算从1加到100000000000000叭叭叭叭叭叭。

2.webGL gpu提速
熟悉openGL的人对webGL就很方便上手了,只是编程语言和api有一定区别,在网页层面提供了canvas绘图对象提供2d或者3d上下文来进行2维或3维图形的绘制,当然你也可以使用目前我觉得最方便的webGL库three.js来完成图形的绘制,具体的webGL的知识可以到网上查看文档。webGL最大的好处就是能够在内部实现机制调起GPU加速图形的绘制。这使得利用webGL做GPU加速运算成为了可能。

我们在进行图形绘制的时候,都是有许多像素点组成,每个像素的颜色可以有RGBA四个维度表示,每个维度范围为0-255,既8位 把RGBA表示成数值的话,那每个像素可以存32位,这就是前端使用gpu计算最为核心的一点,每个像素可以存储一个32位的值, 刚刚好就是一个int或者uint。这在之前做基于浏览器的挖矿demo BWCoin时,为了提速JS对hash值的运算就曾尝试过,但失败告终?,但也不妨成为我的经验值哈!过程就是你需要将做hash运算的方法过程,定制化实现webgl中以像素点为基本单位的计算方法。真烧脑,超纲了超纲了~

3.webassembly
终于说到主角了,哈哈哈,我其实就是想谈一谈wasm,最近对wasm进行了尝鲜,我觉得这真有可能格了JS的命,同样,我还是先给出wasm的浏览器支持情况:以及wasm的中文官网
pic

官网显示WebAssembly/wasm WebAssembly 或者 wasm 是一个可移植、体积小、加载快并且兼容 Web 的全新格式。是不是很牛,JS的执行效率不行,那就直接换掉,用C或者C++甚至汇编来加速端侧的计算效率。经过几天的尝试,我对wasm的理解是:WebAssembly 就是一项字节码标准,以字节码的形式依赖虚拟机在浏览器中运行。往底层了挖,就是对多种语言提供入口,经过LLVM将不同语言编译为.wasm,然后执行。
编译后的二进制代码无需经过解析和编译两个步骤,就无JS啦,在面对一些高计算量、对性能要求高的应用场景图像/视频解码、图像处理、3D等的优势就显现出来了。也就是说你duck不必再担心js的执行效率问题,用一些效率更高的底层语言来写你的端侧推理框架或者底层代码,性能会成倍增长。
pic

写下快速尝鲜示例吧:
1.wasm安装与Emscripten编译:前提是你已经安装了git、cmake、python。cmake可以通过brew安装

# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git

# Enter that directory
cd emsdk

# Fetch the latest version of the emsdk (not needed the first time you clone)
git pull

# Download and install the latest SDK tools.
./emsdk install latest

# Make the "latest" SDK "active" for the current user. (writes .emscripten file)
./emsdk activate latest

# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh
复制代码

2.编写C语言代码

#include <stdio.h>
int main(int argc, char ** argv) {
	printf("Hello, bowen!");
	return 0;
}

复制代码

3.执行wasm编译命令输出到html

emcc hello.c -s WASM=1 -o hello.html
复制代码

4.使用 emrun 命令来创建一个 http 协议的 web server 来展示我们编译后的文件

emrun --no_browser --port 8080 .
复制代码

5.浏览器中访问hello.html,查看控制台Hello bowen输出即为编译成功

当然,以上只是一个wasm的极速体验的例子,wasm的功能强大,有很多可做的方面,例如利用wasm重新定制播放器等。俺还在探索哈~?

总结

总结?看了上面的还需要我总结么?不需要,反正俺告诉你,端侧智能是一定的,必然的,你现在学习webgl来的及,学习webassembly来的及。??????????????????<( ̄︶ ̄)>

开个玩笑,还是要总结的,之前在infoq看见一篇文章的题目叫**“恕我直言,90% 的应用场景都不需要用WebAssembly”** 看见这篇文章的时候真是好想怼他, “恕我直言,卡住你的应用场景往往就那10%”。虽然他说的有理有据,但需要突破的总是那小百分之十,我承认就目前看来wasm的用处的确很少,但往往极致体验,需要突破的时候,卡住脖子的时候往往就是那少数没人做的工作。

其次,利用webGL或者wasm的能力在端侧进行算力的提升,性能的提升,的确是不错的选择,尤其是wasm。
pic

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享