在Android端实现基于OPENGL ES 的深度学习前向传播框架

github项目地址

首先感谢夕阳叹大神提供的思路,大家先可以去https://blog.csdn.net/jxt1234and2010/article/details/71056736看看,基本把实现的流程都说了一遍,我照着思路实现了一下,同时参考了一下CnnDroid

这个项目断断续续写了快4个月了,最近忙起来了,可能没什么时间完善了,先用blog记录一下思路,要有机会再完善了。

目前整个项目只实现了卷积,池化,全连接,concat,flat(和tensorflow的flat逻辑不一样),softmax,卷积部分实现了常规卷积,GEMM卷积(mat4级别的),winograd卷积。整个项目没能达到夕阳叹大神实现版本的效率,能力有限也不知道怎么优化了,希望能有OpenGL的大神能review下我写的shader,是不是实现上有问题,感激不尽。

大致的benchmark,个人时间有限就只与NCNN对比了一下运行squeezenet

ncnn没时间编译了,直接用的ncnn-mobile

cpu ncnn(4线程) mine
高通660 60ms 70ms
高通710 - 35ms
高通835 - 40ms

测试标准都是除去前10次后,然后前向运行100次耗时取均值。测试手机为小米note3,注意不同rom对opengl效率有影响,最好用最新的开发版或正式版。

基本实现流程:

1.输入层:

输入层使用RGBA16F格式的 GL_TEXTURE_2D_ARRAY 存储,纹理深度为1,纹理宽高同输入矩阵的宽高维度,通常输入矩阵的channel为1或者3,所以将输入矩阵传入纹理时,需要对其不足的通道补零。

2.卷积层

卷积层的输出纹理为RGBA16F的 GL_TEXTURE_2D_ARRAY,纹理深度为输出 ceil(channel/4),纹理高宽同输出高宽维度。

卷积层的kernel也使用纹理存储,纹理深度同输入纹理。最开始我是按照夕阳叹的思路用的ssbo,但是效率很慢,原因未知。换成纹理后效率有所提升。就我测试,基本运算有一半以上的耗时花在了从纹理读取数据上了,这部分不知道有没有优化空间。

kernel的维度为  n x (kernel_area + 1)x d。 n为kernel的数量,kernel_area 为kernel的截面积,d为输入纹理的深度,因为kernel的channel需要与输入channel相同。每一个kernel均存储为纹理上的1行,纹理每行的最后一列的第一个值用于存储改行kernel的bias。

常规卷积的逻辑为每个计算器计算1个输出,所以计算器座标同输出座标。

GEMM卷积为mat4级别的,所以一个计算器会同时计算4个输出值。

winograd卷积的kernel纹理时存储GgGt矩阵,存储逻辑同上。winograd实现时是将输出转变为nxn个2x2的输出,所以一个计算器也会计算4个输出值

3.池化层

池化层的输出纹理为RGBA16F的 GL_TEXTURE_2D_ARRAY,纹理深度为输出 ceil(channel/4),纹理高宽同输出高宽维度。

池化层的计算器座标与输出纹理一一对应,每个座标的计算器只进行对应座标的池化运算。

4.concat层

没有判断输入channel是否为4对齐,现在就实现了2个输入,并且输入channel均为4对齐的情况。通用的concat有时间再补上吧。

5.全连接层

全连接为了直接接卷积或池化的输出,输出纹理的格式设置为 1 x 1 x d, d为全连接层的神经元数量,输出纹理的深度就为ceil(d/4)。同样每个神经元的kernel也用纹理的1行存储,最后一列用于存储bias。

6.flat层

这层主要是为了方便读取最终结果,opengl通过framebuffer读取数据时,只能读取一个深度纹理上的数据。所以通过flat将纹理所有深度上的数据,移动到一个深度的纹理上。

7.softmax层

没什么东西了,直接实现的softmax公式。

 

目前在ARM Mail GPU上还有bug,cifa10的10分类模型能跑,squeezeNet就输出0,原因还没找到,手边也没有这种GPU的手机,应该也没机会修复了。

顺便记录一下ARM opengl编程遇到的一点小坑:

1.arm 下 opengles 的计算器localsize 最大值为128,而高通的为1024

2.arm 下shader定义image时必须设置精度(也许也可以直接在全局设置,我没试),而高通不需要

layout(binding = 0, rgba16f) readonly uniform highp image2DArray input_image;

纹理精度设置为highp或lowp,效率没变化。

3.shader的shared变量空间比高通的小(具体多少没查到,也没手机试),高通的手机为1000 个 float。

 

里面包括一个cifar10 10分类和squeezeNet 1000分类的模型。

cifar10的权重提取自CnnDroid

squeezenet的权重提取自squeezenet

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章