当前位置: 首页 > 科技观察

基于OpenGLES的深度学习框架编写

时间:2023-03-17 22:56:26 科技观察

背景及工程定位后台项目组实现了基于深度学习的视频风格化和人像抠图功能,但是这个是跑在PC/服务器上的,现在需要移植到移动端,所以需要一个移动端深度学习的计算框架。同类型的库caffe-Android-lib应该是最方便集成的深度学习框架库了。据说tensorflow和mxnet也有对应的android库,由于时间原因暂未测试。CNNdroid,网址https://zhuanlan.zhihu.com/p/25259452,这是一个用renderscript优化的深度学习框架,但是从代码实现和实际测试结果来看,表现一般。工程定位实现了一个实时、小型、通用的深度学习预测框架。实时不同于PC或服务器。移动设备上的GPU不一定像CPU那么强大(多线程+neon/vfp),但在需要实时计算的场景(主要是相机预览和视频播放),往往是基于OpenGL的渲染环境。在实时情况下,深度学习框架的输入和输出都在GPU端。使用CPU进行计算,往往需要复制图像,然后上传到GPU端。因此,基于GPU的深度学习库可以等同于CPU版本。效率是足够的。对于相机预览产生的每一帧数据,系统将其映射到opengl的一个外部纹理,然后需要计算一个mask纹理,与原始纹理混合,显示出来。如果masktexture的计算是在cpu上进行的,那么每一帧都需要将graphicbuffer的数据拷贝出来,计算mask再上传到masktexture,导致多了一份或者两份。General本项目需要支持caffe生产的模型文件,支持lenet、ResNet等常见网络。这个工作量包括编写相应层的算子,设计网络结构,分析caffe模型的参数,etc.幸运的是,目前在移动端做深度学习预测就足够了,相比考虑训练的结构至少节省2/3的工作量。项目实现方案选择GPU加速使用GPU加速的API包括以下方案:CUDA、OpenCL、OpenGL(ES)、RenderScript、MetalCUDA只适用于NVIDIAGPU,Metal只适用于苹果系列,这两个适用于androiddevices的话基本不用考虑。对于OpenCL,虽然很多移动GPU已经支持了,比如Arm的mali系列(T628之后),也有相应的支持库。但是,一方面,由于Android在系统层面没有支持,没有相应的系统API,所以兼容性还是比较差。另一方面,OpenCL运算转移到OpenGL后的内存还需要同步,会影响效率。RenderScript坑多,文档少,和OpenCL一样需要和OpenGL同步的问题,所以不考虑。***只剩下OpenGLES。为了开发方便,用Computershader实现。虽然会牺牲一些兼容性(Android5.1及以上,GPU支持openGLES3.1),但值得考虑以下两点:1、走渲染管线实现通用计算,编程复杂且容易出错,而且调音也很麻烦。使用计算机着色器,编程类似于opencl和metal,可以大大减少工作量,大大加快开发速度。2、支持OpenGLES3.1的GPU一般都比较新,性能也不算太差,可以达到加速的目的。运算分配在CNNdroid中,只有GPU用于加速卷积层的运算,其余由CPU+多线程执行。我们在GPU加速的早期预研中也做过类似的尝试,但是数据传输和同步的性能消耗远大于协同计算带来的性能提升。因此,在这个项目中,网络中的计算全部由GPU来完成,以避免CPU和GPU之间的重复数据传输或同步。另外,GPU驱动申请内存(分配纹理所需的内存空间)所耗费的时间在移动设备端也不容忽视。因此,在计算过程中不能临时创建纹理或其他缓冲区,必须提前分配。优化注意点1.预测向量化计算时,我们输入神经网络的数据可以表示为w?h?d的三维数据。我们将输入数据存储在RGBA32F格式的3D纹理中。由于每个像素有4个值,因此生成的纹理大小为w?h?ceil(d4)。对于卷积层和内积层,我们将参数存储为mat4数组,然后计算完全是一个vec4级的向量化运算。2.适当的localsize设计不同于OpenCL。计算机着色器必须手动指定工作组的大小和要运行的工作组的数量。对于两组维度,越大越好。一般来说,localsize越大越好,但是计算机shader需要的寄存器越多,localsize的最大值越小。考虑到最耗时的卷积着色器可以使用的localsize一般为64,两者都设置为64(8乘以8)比较保守。不能对齐的情况在shader中处理,比如下面的代码:voidmain(){ivec3pos=ivec3(gl_GlobalInvocationID);if(pos.x