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

夕阳叹 夕阳叹     2022-08-30     363

关键词:

基于OpenGL ES的深度学习框架编写

背景与工程定位

背景

项目组基于深度学习实现了视频风格化和人像抠图的功能,但这是在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版本的效率就有足够优势了。

比如实时抠人像这个case:
ImageDivide
对每一帧相机预览产生的数据,系统将其映射为opengl 的一个external texture,然后需要 计算出一个 mask texture,与原先的texture作混合,显示出来。如果mask texture 的计算在cpu上进行,则需要每帧先把 graphicbuffer 的数据拷贝出来,计算出mask后上传到 mask texture 去,产生一来一回两次额外拷贝。

通用

本工程需要支持 caffe 产出的模型文件,支持常见的网络如lenet、ResNet等等。这个工作量包括编写相应层的算子,设计网络结构,解析caffe模型的参数等。
所幸的是,目前在移动端做好深度学习的预测就足够了,相比于兼顾训练的结构至少省去2/3的工作量。

工程实现

方案选型

GPU加速的API

GPGPU

使用GPU加速有如下一些方案:
CUDA、OpenCL、OpenGL(ES)、RenderScript、Metal
CUDA只适用到NVIDIA的GPU,Metal只适用于apple系列,这两个对android设备而言基本不用考虑。
对于OpenCL,虽然有不少移动GPU已经支持,比如 Arm 的 mali 系列(T628之后),且有相应的支持库。但是,一方面由于Android在系统层面上没有支持,没有相应的系统API,兼容性还是比较差,另一方面,OpenCL 操作完成后的内存传到OpenGL还是需要同步一下,会影响效率。
RenderScript 这个坑比较多,文档极少,而且会有跟OpenCL一样的需要跟OpenGL同步的问题,不做考虑。
最后就只剩下 OpenGL ES,为了开发方便,用 Computer shader 实现,尽管会有一定的兼容性牺牲(Android 5.1 及以上,GPU支持openGLES 3.1),但考虑到下面两点是值得的:
1、走渲染管线去实现通用计算,编程复杂且容易出错,调优也很麻烦。有 computer shader之后,编程就跟opencl、metal类似,这些工作量可以大幅降低,大大加快开发。
2、支持OpenGLES 3.1版本的GPU一般都是相对较新的,性能不会太差,能够实现加速的目的。

运算的分配

CNNdroid中仅用GPU加速卷积层的运算,其他还是由CPU+多线程执行。以前我们在早期作gpu加速的预研时,也有过类似的尝试,但是数据传输和同步的性能消耗远大于协同计算带来的性能提升。因此这个工程中,网络中的计算全部由GPU完成,避免数据在CPU和GPU之间反复传输或同步。

另外,GPU驱动在申请内存(分配纹理所需要内存空间)的时间消耗在移动设备端是不可忽略的,因此,不能在运算过程中临时创建纹理或其他Buffer,必须事先分配好。

优化注意点

1、向量化运算
预测时,我们输入神经网络的数据可表示为 whd 的三维数据。我们将输入数据用一个RGBA32F格式的3D纹理存维,由于每一个像素有4个数值,得到的纹理大小是 whceil(d4)
对于卷积层和内积层,我们把参数存储为mat4的数组,然后其计算就完全是vec4级的向量化运算。

2、合适的localsize设计
与OpenCL不一样,computer shader 必须手动指定 workgroup 的大小,并且指定运行的 workgroup 数量。这两组维度,都是越大越好。
local size 一般而言越大越好,但 computer shader 所需要的寄存器越多,local size 的最大值就越小,考虑到最耗时的卷积shader所能使用的local size 一般也就 64,保守起见都定为64(8乘8)。
不能对齐的情况在shader中处理,比如下面的代码:

void main()
{
    ivec3 pos = ivec3(gl_GlobalInvocationID);
    if (pos.x < MAX_WIDTH && pos.y < MAX_HEIGHT)
    {
        /*Do something*/
    }
}

3、适当地合并/去除layer
如正则层可以直接和上一层合并(末尾加个max处理就行),dropout层可以直接丢弃。
合并可以提升性能(不过不会太多),但最重要的是减少了中间内存。

框架设计

分为两个子模块,引擎模块在客户端上运行,工具模块用来转换caffe的模型文件。
Structure

引擎模块

1、数据层
Image 为一个RGBA32F格式的2D Array纹理,SSBO为一种vbo,
全称为GL_SHADER_STORAGE_BUFFER,用于存储自定义类型的数据(主要就是卷积层和内积层的参数)。
Program 为 着色器链接而成的 opengl program,NetInfo 由 proto 定义,用于规定网络结构。
在 shader 中,image 和 SSBO 示例如下:

layout(rgba32f, binding = 0) writeonly uniform highp image2DArray uOutput;//Image
layout(rgba32f, binding = 1) readonly uniform highp image2DArray uInput;//Image
layout(binding = 2) readonly buffer kernel {
    mat4 values[];
} uKernel;//SSBO

2、算子层
包括各类layer的实现,如卷积,正则,内积(全连接),Softmax等。
每一个layer要负责申请自己的输出内存(image)。

3、结构层
根据 NetInfo 的信息,创建各类算子并构成DAG(有向无环图),执行运算并输出结果。

下图是lenet的dag示例:
Lenet

工具模块

包括一个结构转换器、参数初始化和拷贝工具。拷贝工具是比较容易出错的,因为卷积层和内积层的参数需要补零对齐及重排。

性能与效果

跟开源的 caffe-android-lib 对比
https://github.com/sh1r0/caffe-android-lib

库大小

caffe-android-lib 11M
DeeplearningOGL 440K
全自主开发的,毫无疑问要小很多很多。

运行效率

Oppo R9 (MT6755, GPU: Mali-T860)上的测试结果:
连续运行十次,去除第一次的结果(移动设备上一般都是动态调频的,第一次跑的时候CPU/GPU的频率还没调起来,会比较慢)。
Lenet 网络:
caffe-android-lib:5.0~5.2ms(线程设为4)
DeeplearningOGL:3.6-3.8 ms

较CPU版本(包含了neon与多线程优化)提升了 50%左右的效率,已经大大超出预期了,在GPU更好的机器上(如mate8上)表现会更佳。
相比于 CNNdroid 更是好很多了。

人像抠图的场景很流畅,且不需要隔帧计算。

基于opengl编写一个简易的2d渲染框架02——搭建opengl环境

由于没有使用GLFW库,接下来得费一番功夫。阅读这篇文章前请看一下这个网页:https://learnopengl-cn.github.io/01%20Getting%20started/02%20Creating%20a%20window/ 以下,我摘取了一点片段 Windows上的OpenGL库  如果你是Windows平台,opengl32.l... 查看详情

基于opengl编写一个简易的2d渲染框架-04绘制图片

阅读文章前需要了解的知识,纹理:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/   过程简述:利用FreeImage库加载图像数据,再创建OpenGL纹理,通过Canvas2D画布绘制,最后又Renderer渲染器渲染   本来想用soil库... 查看详情

开篇词:基于java的深度学习框架及其生态圈

随着深度学习在语音、图像、自然语言等领域取得了广泛的成功,越来越多的企业、高校和科研单位开始投入大量的资源研发AI项目。同时,为了方便广大研发人员快速开发深度学习应用,专注于算法应用本身,避免重复造轮子... 查看详情

基于opengl编写一个简易的2d渲染框架-13使用例子

 这是重构渲染器的最后一部分了,将会给出一个demo,测试模板测试、裁剪测试、半透明排序等等: 上图是本次demo的效果图,中间的绿色图形展现的是模板测试。 模板测试voidinit(Pass*&p1,Pass*&p2){p1=newPass;p2=newPass;... 查看详情

深度学习-pytorch框架实战系列

...-PyTorch框架实战系列PyTorch是一个开源的Python机器学习库,基于Torch,用于自然语言处理等应用程序。2017年1月,由Facebook人工智能研究院(FAIR)基于Torch推出了PyTorch。它是一个基于Python的可续计算包,提供两个高级功能:1、具有... 查看详情

基于opengl编写一个简易的2d渲染框架-09重构渲染器-shader

  Shader只是进行一些简单的封装,主要功能:    1、编译着色程序    2、绑定Uniform数据    3、根据着色程序的顶点属性传递顶点数据到GPU   着色程序的编译GLuintShader::createShaderProgram(constchar*vsname,constchar*p... 查看详情

基于opengl编写一个简易的2d渲染框架-05渲染文本

阅读文章前需要了解的知识:文本渲染 https://learnopengl-cn.github.io/06%20In%20Practice/02%20Text%20Rendering/ 简要步骤:获取要绘制的字符的Unicode码,使用FreeType库获取对应的位图数据,添加到字符表中(后面同样的字符可以再表中... 查看详情

基于opengl编写一个简易的2d渲染框架-12重构渲染器-blockallocator

 BlockAllocator的内存管理情况可以用下图表示   整体思路是,先分配一大块内存Chunk,然后将Chunk分割成小块Block。由于Block是链表的一个结点,所以可以通过链表的形式把未使用的Block连接起来,并保存到pFreeLists中。当... 查看详情

基于opengl编写一个简易的2d渲染框架-07鼠标事件和键盘事件

这次为程序添加鼠标事件和键盘事件   当检测到鼠标事件和键盘事件的信息时,捕获其信息并将信息传送到需要信息的对象处理。为此,需要一个可以分派信息的对象,这个对象能够正确的把信息交到正确的对象。 实... 查看详情

开篇词:基于java的深度学习框架及其生态圈

...NTK(Microsoft)、PaddlePaddle(百度)等。以上框架基本都是基于Python或者C/C++开发的。而且很多基于Python的科学计算库,如Numpy、Pandas等都可以直接参与数据的建模,非常快捷高效。然而,对于很多IT企业及政府网站,大量的应用都... 查看详情

基于opengl编写一个简易的2d渲染框架-08重构渲染器-整体架构

  事实上,前面编写的渲染器Renderer非常简陋,虽然能够进行一些简单的渲染,但是它并不能满足我们的要求。  当渲染粒子系统时,需要开启混合模式,但渲染其他顶点时却不需要开启混合模式。所以同时渲染粒子系统和... 查看详情

基于opengl编写一个简易的2d渲染框架-11重构渲染器-renderer

 假如要渲染一个纯色矩形在窗口上,应该怎么做?先确定顶点的格式,一个顶点应该包含位置信息vec3以及颜色信息vec4,所以顶点的结构体定义可以这样:structVertex{Vec3position;Vec4color;};然后填充矩形四个顶点是数据信息:Verte... 查看详情

用户增长——快手的基于深度学习框架的集成⽣存分析软件kwaisurvival(代码片段)

...rvival,上手试了试:KwaiSurvival是快⼿DA⾃主开发的基于深度学习框架的集成⽣存分析软件,帮助使⽤者在Python编程环境下⾼效地使⽤⽣存分析模型实现⼤规模的数据分析地址:https://github.com/kwaiDA/KwaiSurvival本篇主要... 查看详情

生存分析——快手的基于深度学习框架的集成⽣存分析软件kwaisurvival(代码片段)

...rvival,上手试了试:KwaiSurvival是快⼿DA⾃主开发的基于深度学习框架的集成⽣存分析软件,帮助使⽤者在Python编程环境下⾼效地使⽤⽣存分析模型实现⼤规模的数据分析地址:https://github.com/kwaiDA/KwaiSurvival本篇主要... 查看详情

深度学习框架太抽象?其实不外乎这五大核心组件

...习框架都包含以下五个核心组件: 1.张量(Tensor)2.基于张量的各种操作3.计算图(ComputationGraph)4.自动微分(AutomaticDifferentiation)工具5.BLAS、cuBLAS、cuDNN等拓展包 1.张量(Tensor) 张量是所有深度学习框架中最核心的... 查看详情

基于nvidiagpus的深度学习训练新优化

基于NVIDIAGPUs的深度学习训练新优化NewOptimizationsToAccelerateDeepLearningTrainingonNVIDIAGPUs不同行业采用人工智能的速度取决于最大化数据科学家的生产力。NVIDIA每月都会发布优化的NGC容器,为深度学习框架和库提高性能,帮助科学家最... 查看详情

深度学习框架keras安装

...ngzhuochenfu/article/details/51187603 前提:Keras是Python语言中基于原始深度学习框架Tensorflow或Theano的封装框架。如果准备使用Keras首先必须准备安装Tensorflow或Theano,我安装的是TensorFlowCPU版本。 在cmd窗 查看详情

人脸识别---基于深度学习和稀疏表达的人脸识别算法

介绍基于深度学习和稀疏表达的人脸识别算法1利用VGGFace提取人脸特征2PCA对人脸特征进行降维3稀疏表达的人脸匹配Code1介绍本文将介绍一种基于深度学习和稀疏表达的人脸识别算法。首先,利用深度学习框架(VGGFace)提取人脸特征... 查看详情