系统信息
描述当前行为
tensorflow lite gpu委托文档提供了一个示例代码,可在android上高效运行tflite推理,并在egl上下文中借助opengl和SSBO避免CPU_GPU内存复制。 但是,这种方法似乎并没有带来任何性能提升。 该文档提到了一种方法-在这种情况下用于运行推理的方法-'interpreter.runInference(null,outputArray)'。此方法与基本运行方法相同,即解释器.run(inputTensor ,outputTensor)。 (当前api中似乎没有方法叫做'interpreter.runInference'。)实验性gpu委托api当前是否支持建议的方法(即直接从opengl ssbo访问输入图像以运行推理)?如何确保模型从GPU内存中的该SSBO接收输入?
*预期行为*
使用opengl ssbo的tflite推理应该比基本的gpu委托推理要快,后者每次将数据从cpu复制到gpu。
其他信息/日志
我们在android studio中测量了'tflite.run'方法的时间。输入采用推荐的ByteBuffer格式。
错误:无法解析方法runInference(null,?)
@ anilsathyan7
感谢您试用GPU委托。
您是否可以提供更多时间方面的信息,即前后多少毫秒?
您正在使用哪种网络? 具体来说,是否支持所有操作?
您是否编写了自定义着色器代码以将相机纹理复制到SSBO中,还是只是自己将CPU内存转储到SSBO中? 如果是前者,则说明您做的不错,而且速度会更快。 如果是后者,它只会变慢。
模型:类似于官方的TF-Lite细分模型(模型推断图作为图像附加).gpu委托似乎不支持最后三个附加节点,输入图像大小为129 * 129。
电话:OnePlus 3,GPU:Adreno 530
时间:
CPU推断:60-70毫秒
GPU推断:40-50毫秒
GPU推断(SSBO):80-90毫秒
即执行“ interpreter.run()”方法的时间。
这是我们用来将相机纹理复制到SSBO的方法:-
//Initialise SSBO
public int[] initializeShaderBuffer(){
android.opengl.EGLContext eglContext = eglGetCurrentContext();
int[] id = new int[1];
GLES31.glGenBuffers(id.length, id, 0);
GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, id[0]);
GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, mWidth * mHeight, null, GLES31.GL_STREAM_COPY);
GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);// unbind
return id;
}
int inputSsboId = initializeShaderBuffer()[0];
//After that every time a frame is available OR in onDraFrame(), call
fillSsboWithCameraImageTexture(inputSsboId,data);
//(Note: Data is Nothing but Camera Frame ByteBuffer)
// Fill Ssbo With CameraImageTexture
private int fillSsboWithCameraImageTexture(int inputSsboId,ByteBuffer cameraFramme) {
GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, mWidth * mHeight, cameraFramme, GLES31.GL_STREAM_COPY);
return inputSsboId;
}
相同的“ Interpreter.run()”方法能否处理来自CPU和SSBO的正常输入? 还是在这种情况下还有其他选项/功能可用于运行推理?
@ anilsathyan7
对于延迟的回复表示歉意。 出于某种原因,我刚刚在收件箱中输入了此内容> _ <
快速提问:您的代码:
不必一定是
GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, 3 * mWidth * mHeight, null, GLES31.GL_STREAM_COPY);
?
另外,您是否有资格制作形状为1x129x129x4的输入SSBO? 然后,您可以消除其中一个隐藏的内存。
从您共享的图中(顺便说一句,很好的可视化;对此表示赞赏),确实看起来一切都会处理到最后一个ResizeBilinear。 就其形状而言,它的形状也不算太差(129x129x2),它具有太多的通道等。因此,我希望不会出现任何速度下降的情况。
您在ModifyGraphWithDelegate
之前正确呼叫BindGlBufferToTensor
ModifyGraphWithDelegate
吗? 可以共享将纹理转换为SSBO的着色器代码吗? 我正在做类似的事情:
#version 310 es layout(local_size_x = 16, local_size_y = 16) in; layout(binding = 0) uniform sampler2D input_texture; layout(std430) buffer; layout(binding = 1) buffer Output { float elements[]; } output_data; void main() { ivec2 gid = ivec2(gl_GlobalInvocationID.xy); if (gid.x >= 224 || gid.y >= 224) return; vec3 pixel = texelFetch(input_texture, gid, 0).xyz; int linear_index = 3 * (gid.y * 224 + gid.x); output_data.elements[linear_index + 0] = pixel.x; output_data.elements[linear_index + 1] = pixel.y; output_data.elements[linear_index + 2] = pixel.z; }
用于MobileNet。 可能不直接适用,但您大致了解这个主意...
尚未正式宣布,但是供参考:GPU代码现在可以在以下位置看到:
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/gpu
如果您需要代码以更好地了解情况,那么会发生什么。
嗨@impjdi ,
您可以只使用ssbo共享样本分类应用程序,还是至少使用与opengl相关的代码?
我们根据您的输入使用了以下着色器代码,但是遇到一些与着色器版本有关的错误,我们无法解决opengl初学者的问题。
#version 310 es
layout(local_size_x = 16, local_size_y = 16) in;
layout(binding = 0) uniform sampler2D u_Texture0;
layout(std430) buffer;
layout(binding = 1) buffer Output { float elements[]; } output_data;
void main() {
ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
if (gid.x >= 257 || gid.y >= 257) return;
vec3 pixel = texelFetch(u_Texture0, gid, 0).xyz;
int linear_index = 3 * (gid.y * 257 + gid.x);
output_data.elements[linear_index + 0] = pixel.x;
output_data.elements[linear_index + 1] = pixel.y;
output_data.elements[linear_index + 2] = pixel.z;
}
mTextureUniformHandle0 = GLES31.glGetUniformLocation(mProgramHandle,
"u_Texture0");
// Set the active texture0 unit to texture unit 0.
GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
// Bind the texture to this unit.
GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mTextureDataHandle0);
// Tell the texture uniform sampler to use this texture in the shader by
// binding to texture unit 0.
GLES31.glUniform1i(mTextureUniformHandle0, 0);
public int[] initializeShaderBuffer(){
android.opengl.EGLContext eglContext = eglGetCurrentContext();
int[] id = new int[1];
GLES31.glGenBuffers(id.length, id, 0);
GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, id[0]);
GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, 257*257*3*4, null, GLES31.GL_STREAM_COPY);
GLES31.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER,1,id[0]);
GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);// unbind
return id;
}
@ anilsathyan7
我本周休假,办公室网络访问受限,很可能会忘记这一点。 你能下个星期再推我一下吗?
当然了porygon ...😉
嗨@impjdi ,
您可以为我们解决ssbo tflite的问题吗? 我们无法在android中使用ssbo来运行tflite推理。您能否仅使用ssbo或至少与opengl相关的代码共享示例分类应用程序?在这种情况下,我们可以期望提高多少速度?
嗨@impjdi ,
我将第二次请求演示SSBO推理的演示。
也许我应该打开一个单独的问题...我们正在尝试在我们的应用程序中与tflite GPUDelegate一起使用GLSurfaceView。 我们的渲染器可以正常工作,直到调用interpreter.modifyGraphWithDelegate(delegate);
,从而导致黑屏。 没有产生glErrors。 即使查看了新发布的GPU委托源,也很难理解对以上行进行注释/取消注释会如何改变行为。
一个可行的示例可能会清除问题...
谢谢!
@ anilsathyan7
呵呵,我早先错过了porygon部分:)
下面是C ++,但在Java中也应该类似。
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, /*your gl texture that has the image*/);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, /*your ssbo*/, 0, /*size in bytes*/);
glUseProgram(/*the program above*/);
glDispatchCompute(width / 16, height / 16, 1); // these are work group sizes
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // unbind
glBindTexture(GL_TEXTURE_2D, 0); // unbind
@ktgordon
嗯,唯一的官方示例代码是TF存储库中的TFLite演示应用程序。 由于Android应用程序不仅包含单个Java文件,还包含许多其他内容,除非我用这些文件启动一个全新的git repo,否则这将很困难。 不幸的是,最重要的是,我不是真正的移动应用程序开发人员。 我在没有相机的情况下在Android C ++中完成了大部分工作。 我将看看是否可以编写一个C ++二进制文件,使它可以在单个C ++文件中完成所有这些工作= /除了讨论之外...
modifyGraphWithDelegate
挂起听起来像是您在其他地方遇到了问题。 请确保您的TfLiteGpuDelegateBindBufferToTensor
之前被调用modifyGraphWithDelegate
,并且您的SSBO已创建。 带有modifyGraphWithDelegate
的程序的流程如下:
Interpreter.modifyGraphWithDelegate
(Java)
Interpreter::ModifyGraphWithDelegate
(C ++)
tflite::gpu::gl::(anonymous)::DelegatePrepare
(C ++)
tflite::gpu::gl::(anonymous)::Delegate::Prepare
(C ++)
您可能可以追溯导致挂起的原因。
@ anilsathyan7
事情解决了吗? 这个问题可以解决吗?
代码工作正常; 但是我们无法使用ssbo作为输入来获得正确的输出。输出似乎是黑色的(即输出全为零)。我们无法确保数据已正确复制到ssbo中或tensorflow是否正确访问了数据; 即使它没有错误运行,似乎也无法在android中调试和查看着色器代码(GLSL)。
随附的是包含当我们尝试将SSBO与tflite模型一起使用时的错误的日志文件。
该代码可在带有Adreno-GPU的Mobiles上正常运行,没有任何错误,但看不到任何输出。 但是,在配备Mali-GPU的手机中,甚至在模型出现之前就存在一些问题。
这些错误在Mali设备之间有所不同,而在Adreno Devices中无法看到输出。
以下测试中使用的设备是:
马里(错误记录附有问题:mali-gpu-ssbo-errorlog.txt)
_三星A8 + _
_荣誉发挥_
_Moto C plus_
Adreno (附带错误日志:adreno-gpu-ssbo-errorlog.txt)
_Poco F1_
@impjdi您可以看一下。如果您可以与我们分享有效的应用程序代码以供参考,那会更好。
@impjdi SSBO上的任何更新?
嗨@impjdi ,
我将第二次请求演示SSBO推理的演示。也许我应该打开一个单独的问题...我们正在尝试在我们的应用程序中与tflite GPUDelegate一起使用GLSurfaceView。 我们的渲染器可以正常工作,直到调用
interpreter.modifyGraphWithDelegate(delegate);
,从而导致黑屏。 没有产生glErrors。 即使查看了新发布的GPU委托源,也很难理解对以上行进行注释/取消注释会如何改变行为。一个可行的示例可能会清除问题...
谢谢!
@ktgordon您是否找到解决此问题的方法/解决方法? 我遇到了完全相同的问题。 调用ModifyGraphWithDelegate()后,所有glDraw调用均以黑色显示。 甚至不需要将SSBO缓冲区关联到TFLite张量。 这很奇怪。 还要更深入地看。
我们确实找到了解决方法。 我假设您正在使用Java API,并通过引入gpu委托implementation 'org.tensorflow:tensorflow-lite:0.0.1-gpu-experimental'
我认为正在发生的事情是ModifyGraphWithDelegate()修改了当前上下文,因此我们的显示表面不再是当前的……如果我们可以访问原始状态变量,这不是问题。 但是,由于我们最初尝试使用GLSurfaceView,所以我们无法访问任何这些变量。 实际上,ModifyGraphWithDelegate更改了我们无法恢复的gl状态。
从GLSurfaceView切换到TextureView给了我们更多的控制权,但代价是更加复杂。 我们创建了一个虚拟上下文,初始化了我们的解释器,并调用了ModifyGraphWithDelegate(),然后使用虚拟上下文创建了一个新的共享上下文。 这样,我们可以使显示表面成为当前电流并对其进行渲染。
通过重用Grafika的代码来管理egl上下文。
无论如何,这使我们通过了黑屏问题。
基于TFLite演示(使用TextureView),我所做的正是您在这里所说的。 主要有以下几种:
modifyGraphWithDelegate()
。eglMakeCurrent
将eglContext,eglSurface,eglDisplay设置为当前值使用glDrawArrays
绘制的结果为黑色。 有趣的是,如果按顺序交换了步骤1和步骤2,则一切正常。
还引用了Grafika代码。
接下来将尝试设置虚拟上下文...
@ktgordon刚开始工作! 实际上,虚拟共享上下文是使其起作用的关键。 我猜GLES上下文设置/切换可能比人们想象的要复杂得多。
@ anilsathyan7我基于TFLite演示,这是TFLite GPU委托页面提供的主要示例项目。 此示例项目使用TextureView
。 不知道SSBO是否适用于其他曲面类型。 我猜想应该是eglCreateWindowSurface()
接受SurfaceView
, SurfaceTexture
, SurfaceHolder
或Surface
,根据Android eglSurface doc 。 您链接中的GLTextureView扩展了SurfaceTexture,也应该可以正常工作。
性能提升非常明显。 我正在尝试448x448的图片。 (尝试放大图像以扩大复印时间)。 在Snapdragon 808上,不使用SSBO / Image2D复制着色器所花费的时间约为900毫秒。使用复制着色器,时间缩短为<20毫秒!
@gnsmrky您可以共享您的回购信息,这样对于每个人来说,开始使用ssbo可能都是一件更好的事情。
@gnsmrky您可以共享您的回购信息,这样对于每个人来说,开始使用ssbo可能都是一件更好的事情。
@SanthoshRajendiran试图找到时间这样做。 该代码现在非常混乱并且不可读。 我将在获得空闲周期后立即将其清理干净。
@gnsmrky @impjdi关于
@gnsmrky非常感谢您的努力。 当您在此处添加示例代码时,请告诉我们。
@SanthoshRajendiran @ soham24计划在周末发布该回购协议。 仍在做一些调整。 :)
San
我在最近的几次会议上都提出了这个要求。 该示例将添加到TFLite演示应用程序中,但是我有一些截止日期,所以要等到它才花几个月的时间:(
@santhoshRajendiran @ soham24 @impjdi
我只是在tensorflow-lite-ssbo Android分类器demo上放置了GPU
和mobilenet v1 float
可以看到copy time
,将帧复制到SSBO所需的时间。
代码仍然很粗糙。 但是应该以在TFLite GPU代表中开始在SSBO周围开始为目的。
在我的LG G4(Android M,Snapdragon 808)上,复制224x224像素缓冲区所需的时间大大减少。 从180ms〜200ms(Java ByteBuffer putFloat()
复制),降至1ms(shader + SSBO)。 由于LG G4是一部相对较旧的手机(现已超过5年),因此在新手机上节省的时间可能不那么重要。 但是,实际上,如果G4可以在<1毫秒内完成帧复制,那么无疑任何其他Android手机都可以做得更好。 :)
基本上它是做什么的:
eglContext
)。gpuContext
)。Interpreter.run()
时切换到上下文B。注意:我没有创建单独的线程来简化过程。 通常,上下文A和B应该在2个单独的线程中,因此eglMakeCurrent()在一个线程中仅被调用一次。
没有时间编写自述文件。 只是看看提交。 应该很简单找出其中的内容。 希望这有助于阐明有关TFLite + GPU委托+ SSBO的一些信息。
让我知道是否对你们有用...
@gnsmrky恭喜,并感谢您在SSBO上所做的出色工作。 我们在某些手机中试用了该应用程序。 下面讨论了各种电话上的工作方法:
1)Oneplus 3-模型运行时间约为40毫秒,与没有SSBO时相同。 在所有情况下,复制时间约为0或1
2)Poco F1-模型运行时间约为25ms,但是我们无法从应用程序中获取实际输出。
3)Samsung A8 +,Honor Play-应用程序因链接错误而崩溃,提示工作组调用的最大次数。 我们将工作组的大小修改为8,获得了5ms的模型运行时间,但无法从模型中获得正确的输出。
@gnsmrky非常感谢。 实施后,我会通知您。
@gnsmrky太好了。 非常感谢! 您是否尝试过deeplab细分模型?
@gnsmrky恭喜,并感谢您在SSBO上所做的出色工作。 我们在某些手机中试用了该应用程序。 下面讨论了各种电话上的工作方法:
- Oneplus 3-模型运行时间约为40毫秒,与没有SSBO时相同。 在所有情况下,复制时间约为0或1
因此,在这些手机中,OnePlus 3只能正常工作并具有正确的输出吗? 让我看看我是否可以握住Snapdragon 845手机。
@gnsmrky太好了。 非常感谢! 您是否尝试过deeplab细分模型?
@junhwanjang我还没有尝试过deeplab。 但是我确实尝试将输出SSBO与其他模型一起使用,该模型也可以正常工作。 您知道Deeplab是否可以与GPU Delegate完全兼容吗?
@SanthoshRajendiran我刚刚更新了存储库。 似乎计算着色器在某些设备上需要真实的显示表面。 我向资产添加了1dp x 1dp视图,以将其与gles曲面关联。 您可以在手机上再次尝试更新的回购吗?
这是最新的提交。
顺便说一句,凸轮-> SSBO副本不考虑从updateTexImage()
转换。 您可能需要将手机逆时针放置(即手机底部指向右侧),以得出正确的推断结果。
@gnsmrky感谢您的更新。 使用POCO F1(Adreno 630,Snapdragon 845)时,输出速度现在约为20-30ms,复制时间约为0-1ms。
问题仍然存在于Mali GPU设备(在Honor Play上测试)
下面随附的是Honor Play的错误日志:
@SanthoshRajendiran您是否尝试过将Mali设备的工作组设置为8,甚至4? 这是您应将16
更改8
或4
。
计算着色器中的local_size @ L1092
glDispatchCompute @ L1162
@gnsmrky我们尝试在Samsung A8 +
E / Android运行时:致命异常:CameraBackground
流程:android.example.com.tflitecamerademo,PID:23378
java.lang.IllegalArgumentException:内部错误:无法在给定的解释器上运行:GPU委托不支持下一步操作:
挤压:不支持操作。
前29个操作将在GPU上运行,其余2个操作将在CPU上运行。TfLiteGpuDelegate调用:[GL_OUT_OF_MEMORY]:没有足够的内存来执行命令。节点号31(TfLiteGpuDelegate)调用失败。
at org.tensorflow.lite.NativeInterpreterWrapper.run(Native Method)
at org.tensorflow.lite.NativeInterpreterWrapper.run(NativeInterpreterWrapper.java:149)
at org.tensorflow.lite.Interpreter.runForMultipleInputsOutputs(Interpreter.java:275)
at org.tensorflow.lite.Interpreter.run(Interpreter.java:249)
at com.example.android.tflitecamerademo.ImageClassifierFloatMobileNet.runInference(ImageClassifierFloatMobileNet.java:101)
at com.example.android.tflitecamerademo.ImageClassifier.classifyFrameSSBO(ImageClassifier.java:167)
at com.example.android.tflitecamerademo.Camera2BasicFragment.classifyFrameSSBO(Camera2BasicFragment.java:967)
at com.example.android.tflitecamerademo.Camera2BasicFragment.access$1200(Camera2BasicFragment.java:91)
at com.example.android.tflitecamerademo.Camera2BasicFragment$8.run(Camera2BasicFragment.java:785)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:65)
I / Process:正在发送信号。 PID:23378 SIG:9
@gnsmrky默认情况下,在诸如deeplab之类的模型(无法完全在GPU中运行的模型)中,从GPU到CPU的GPU委托会发生回退。 SSBO中的这种行为是否会改变?如果数据回落到CPU,我们如何获取数据?
@gnsmrky谢谢。 在低端设备上,这就像魅力一样。
一个问题,确实是我们必须逆时针旋转手机。 我可以在着色器中添加旋转逻辑吗?
引用链接: https :
@gnsmrky如果我想从tflite模型获取关于SSBO的图像输出,您能否深入了解应用程序代码中必须进行哪些更改。
@gnsmrky我们尝试在Samsung A8 +
@SanthoshRajendiran我刚刚做了一些调整就更新了回购协议。 应该大大降低内存需求。
8
作为工作组大小。您看到的SQUEEZE
错误可能是由于创建SSBO缓冲区时失败。 您是否按原样运行仓库?
让我知道更新后的仓库是否适合您。
@gnsmrky默认情况下,在诸如deeplab之类的模型(无法完全在GPU中运行的模型)中,从GPU到CPU的GPU委托会发生回退。 SSBO中的这种行为是否会改变?如果数据回落到CPU,我们如何获取数据?
@SanthoshRajendiran存储库中的SSBO仅用于输入缓冲区。 输出缓冲区没有任何变化。 因此,获取输出数据的代码应与使用CPU的方式相同(即ByteBuffer)。
我尚未接触过deeplab。 您知道哪个操作导致CPU回退吗?
@gnsmrky谢谢。 在低端设备上,这就像魅力一样。
一个问题,确实是我们必须逆时针旋转手机。 我可以在着色器中添加旋转逻辑吗?
引用链接: https :
@ soham24当您将常规的glViewPort,glDraw等与相应的顶点片段着色器一起使用时,将发生转换。 存储库中的SSBO代码是一个简单的内存浮点副本,不涉及任何顶点/片段着色器。 如果我们按浮动进行转换,则很可能会减慢速度。
最好的方法是将相机纹理“绘制”到具有所需变换的另一个纹理,然后执行纹理-> SSBO复制。 这将需要一些努力。 需要花更多的时间来做。
@gnsmrky如果我想从tflite模型获取关于SSBO的图像输出,您能否深入了解应用程序代码中必须进行哪些更改。
@SanthoshRajendiran您想对图像输出做什么? 创建一个SSBO并将其绑定到TFLite GPU委托就像创建一个SSBO并调用bindGlBufferToTensor()
到输出张量getOutputTensor()
一样容易,如GPU Delegate文档中所述。
@gnsmrky谢谢。 在低端设备上,这就像魅力一样。
一个问题,确实是我们必须逆时针旋转手机。 我可以在着色器中添加旋转逻辑吗?
引用链接: https :@ soham24当您将常规的glViewPort,glDraw等与相应的顶点片段着色器一起使用时,将发生转换。 存储库中的SSBO代码是一个简单的内存浮点副本,不涉及任何顶点/片段着色器。 如果我们按浮动进行转换,则很可能会减慢速度。
最好的方法是将相机纹理“绘制”到具有所需变换的另一个纹理,然后执行纹理-> SSBO复制。 这将需要一些努力。 需要花更多的时间来做。
谢谢@gnsmrky 。 如果您用所需的转换更新样本,那就太好了。
@gnsmrky我们发现了不支持Squeeze操作的问题。 这是因为默认情况下,Squeeze操作在Mali设备上的GPU中不起作用(已通过基准测试工具验证)。 希望,我们为此将打开一个单独的问题,或者因为@impjdi与该线程链接,他将处理该问题。除此之外,回购按原样工作...在我们的情况下,我们正在处理一个完整的GPU支持的模型并获得要在表面上渲染的图像输出,因此,我们也将继续使用SSBO输出。
@ SanthoshRajendiran我有一个疑问。 您是否在将输入大小纹理传递给tflite之前调整其大小?
op将被调整大小。 您如何直接通过纹理渲染它?
@ soham24正在调整大小的模型的输入,以确保模型正在运行。.我们将模型的输出调整为需要渲染的所需大小。
@ soham24正在调整大小的模型的输入,以确保模型正在运行。.我们将模型的输出调整为需要渲染的所需大小。
@SanthoshRajendiran我也听起来很奇怪。 我要说的是,如果SSBO的大小不正确,则GPU代表将说SQUEEZE存在问题,即使不是这种情况。
谢谢@gnsmrky 。 如果您用所需的转换更新样本,那就太好了。
进行中,尽管进度很慢...
在该应用程序的当前版本中,它是使用EGL Surface开发的。 我们尝试使用GL Surface View,但无法正常工作。 是否可以做一些工作来使ssbo输出直接在GL Surface View上呈现?
@gnsmrky我们尝试弄清Output SSBO,但我们无法正确执行。.您能告诉我们进行更改以使其正常工作所需的确切位置吗?
基本上,我们进行了这些修改。
1)通过按照tflite gpu文档设置setAllowBufferHandleOutput(true)来初始化tflite实例。
2)使用gpuDelegate.bindGlBufferToTensor(outputTensor,outputSsboId)将绑定的缓冲区输出输出到模型SSBO。
3)在移动屏幕上呈现输出。
您可以检查SSBO输出是否在您的情况下工作。。或者以前做过的一些更改(例如旋转屏幕)或现在也需要进行某些更改才能在屏幕上可视化输出。
因此,我附加了用于测试输出SSBO的tflite,其中我们什么也没做,只是使用ResizeBilinear操作将图像从197调整为257。
您可以检查SSBO输出是否在您的情况下工作。。或者以前做过的一些更改(例如旋转屏幕)或现在也需要进行某些更改才能在屏幕上可视化输出。
@SanthoshRajendiran我在这里发布的仓库中没有对输出SSBO做任何事情。 但是我输出SSBO确实有效。 因此,可能是您的着色器代码中的某些内容将数据从SSBO移动到纹理缓冲区以在屏幕上绘制。
我建议的是尝试一种不会改变任何形状的操作。 sqrt
op为例,这是一个不会改变张量形状的一元op。 填写可预测的值,例如100
,结果应为10
。 从一开始,这就是我处理输入/输出SSBO的方式。
我遇到的大多数问题不是在代码的TFLite GPU委托部分上,而是在Android的OpenGL ES上。 只需逐一剖析代码即可使其从SSBO正常运行到屏幕。
希望这可以帮助...
顺便说一句,尽量不要将非线性调整大小与双线性调整大小一起使用。 尝试像2
这样的比例因子。 因此, 157
大小将调整为314
。 这可能会帮助...
您好, @gnsmrky :
我在两个不同的设备中测试您的代码,它似乎只是随机使用GPU。 大多数时候,在GPU模式下,它什么都不做。 我尝试了更少的工作组(8或4),但没有任何区别...
您是否知道为什么会这样?
提前致谢。
我在两个不同的设备中测试您的代码,它似乎只是随机使用GPU。 大多数时候,在GPU模式下,它什么都不做。 我尝试了更少的工作组(8或4),但没有任何区别...
@jsolves您能详细说明吗? 您是说相机-> SSBO不起作用,还是GPU委托? 您如何观察它是否有效?
我希望我能告诉你更多。 但是应用中的每种模式都可以正常运行,直到运行GPU。 大多数情况下,将所有内容归类为0%或接近0%,并且设备的GPU使用率不会提高。 只有在少数情况下,gpu分类才能正常进行(并且gpu利用率相应地会提高)。
我尝试了其他“ gpu应用程序”,它们按预期工作。 我不知道如何确定问题是Camera-> SSBO或GPU委托还是与着色器有关的问题。 您知道什么我可以尝试查看问题是否是其中之一吗?
感谢您的回答。
我尝试了其他“ gpu应用程序”,它们按预期工作。 我不知道如何确定问题是Camera-> SSBO或GPU委托还是与着色器有关的问题。 您知道什么我可以尝试查看问题是否是其中之一吗?
@jsolves您绝对可以尝试的是原始Tensorflow Lite Android存储库,该存储库已支持GPU。 我的SSBO存储库仅添加相机->基于此存储库的SSBO。 您可以看到TFLite Android存储库中的GPU是否具有更快的推理时间。
啊,对不起,这个问题我有点累了。 是的,GPU Delegate可在原始存储库和我自己的自定义应用程序中正常工作。 它提供比CPU推理更快的推理时间。
那么问题出在相机-> SSBO部分中吗?
那么问题出在相机-> SSBO部分中吗?
@jsolves SSBO的主要目的是减少从相机到TFLite的输入SSBO的像素复制时间。 GPU推理时间完全不会受到影响。
在GPU模式下运行应用程序时,您是否看到“复制时间”?
另外,您如何检查GPU利用率? GPU利用率低时,您是否会获得预期的推理输出?
是的我知道。 在GPU(带有SSBO)中,复制时间非常短(0-2),但是大多数时候没有正确的分类(随机值或全0)。
在设备配置中,有一个类似“显示gpu利用率”的选项,并且在应用正常运行(与GPU配合)的几次情况下,gpu指示灯会升高。
这就像是摄像头不总是进入SSBO或有一些初始化麻烦。 但是我的Android-Fu不够强大... :(
@jsolves当我使用基本的3通道输入模型测试gpu推理时,我无法获得正确的结果。
但是,当我将3通道模型更改为伪4通道输入(使用新的Input和strided_slice ops)时,最终得到正确的结果:)
https://www.tensorflow.org/lite/performance/gpu_advanced#tips_and_tricks
有趣的。 如何制作“假4通道”,在每个像素中将“假” alpha设置为1?
提前致谢。
input_shape = (224, 224, 4)
inputs = Input(input_shape, dtype=np.float32)
x = Lambda(lambda x: x[:, :, :, :3])(inputs)
model_pre = Model(inputs, x)
model_pre.summary()
sess_fake = K.get_session()
graph_def_fake = sess_fake.graph_def
nodes_fake = [n for n in graph_def_fake.node]
我将模型转换如下。
我认为https://mediapipe.dev可以做到这一点。
@ soham24我经历了mediapipe,但不了解它是如何工作的。 Mediapipe团队提供的tflite具有TFLite-GPU不支持的操作,甚至它们都不是张量流操作。 谁能提供有关如何训练基于Mediapipe架构的细分模型的建议。
@SanthoshRajendiran甚至我也试图通过查看mediapipe代码来弄清楚管道。
如果tf的人帮助我们,那么IT将会很棒
@santhoshRajendiran @ soham24
是的,MediaPipe可能会使用GPU委托的所有功能,并且是一个不错的起点(我几年前曾在MediaPipe上工作过:D)。 我同意GPU路径并不是超级容易阅读,但仍然是一个不错的起点。 如果首先查看TfLiteInferenceCalculator
,将看到大量的RunInGlContext
东西,这确保了您保持在相同的GL上下文中。 然后,它真正要做的就是复制输入SSBO,运行推断并复制输出SSBO。 我认为仍有改进的空间,这将很快发生。 好吧,这是我接下来三个月的菜板:P
对于细分模型,您需要检入MediaPipe github页面并对其进行ping操作。
我们可以对此进行更新吗?
嗯,您能详细说明一下您希望进行的更新吗? 您是否要我们浏览另一个开源软件?
我试图像@gnsmrky那样将我的自定义tflite模型与android中的
(顺便说一句,最新的tflite似乎不支持bindGlBufferToTensor,但是官方的tflite gpu委托文档仍然在使用SSBO时引入bindGlBufferToTensor。)
无论如何,我已经从https://github.com/gnsmrky/tensorflow-lite-ssbo构建了tensorflow,并设法通过SSBO运行图像分类演示。 即使与没有SSBO的CPU版本和官方GPU版本相比,结果显示不同,它也至少可以正常工作-它具有预测值,并且复制时间减少了。
但是当我将提供的mobilenet模型更改为我的自定义模型时(我甚至只尝试了一个简单的添加操作模型),看起来工作正常,但输出全为零,或者有时会产生错误,Tensor不会绑定到缓冲区句柄,具体取决于所使用的模型。
由于我尝试使用与原始演示相同的224x224x3输入的模型,并且除了模型路径之外没有进行任何更改,因此我想知道在更改或制作模型时是否还需要进行其他修改。
以下是我尝试过的一些简单模型的示例。 (由Netron可视化)
如果TensorFlow提供带有最新tflite的官方SSBO演示,那就太好了。
tensorflow-lite-ssbo / tensorflow / lite / java / demo / app / src / main / java / com / example / android / tflitecamerademo / ImageClassifier。 java:212 :错误:找不到符号
gpuDelegate.bindGlBufferToTensor(inputTensor,inputSsboId);
^
符号:方法bindGlBufferToTensor(Tensor,int)
位置:类型为GpuDelegate的变量gpuDelegate
@jmhodges @gnsmrky
我不在Java领域工作,因此我不知道正在使用哪个委托Java API,但是bindGlBufferToTensor在已弃用的GL委托中被重命名,并在新的GPU委托中被删除。 签出//tf/lite/delegates/gpu/gl_delegate
& //tf/lite/delegates/gpu/gpu_delegate
。
@impjdi @jmhodges @gnsmrky
我的模型输入像素值是浮动的,范围为0.0-1.0(1.0 / 255),可以使用ssbo吗?
如何将ssbo buf转储到cpu进行评估?
您正在寻找glMapBufferRange
为什么在glDispatchCompute调用后transformedData打印出零值
哪里错了?
如果有更好的方法,我需要检查copyCamtextToSsbo之后的ssbo值吗?
@impjdi @svenstaro @bmabey
对Java ByteBuffer
和FloatBuffer
不太熟悉,但是在开始从内存位置读取之前,您是否错过了glFinish
?
@impjdi @svenstaro @ktgordon @SanthoshRajendiran @gnsmrky
您可以将FloatBuffer视为c ++中的float *指针(缓冲区)
我已经尝试过glFinish但结果相同
但是,如果我添加以下代码:
GLES31.glBufferData(GL_SHADER_STORAGE_BUFFER,ssboSize,ssboData,GL_STREAM_COPY);
为什么我可以通过glMapBufferRange获得ssboData内容?
我要评估out_data.elements内容是否正确? 派遣通勤后。
我用谷歌搜索了两天,但没有找到解决方案
GLES31.glBufferData(GL_SHADER_STORAGE_BUFFER,ssboSize,ssboData,GL_STREAM_COPY);
为什么我可以通过glMapBufferRange获得ssboData内容?
不是在谈论“为什么”部分,但是如果您可以访问ssboData
您的问题是否就解决
我还记得,我在网络上找不到足够的示例来取得合理的进展。 由于您正在询问纯OpenGLES计算着色器问题,因此您现在要询问的内容似乎对TFLite GPU支持略有超出范围。 我建议在Khronos论坛上提问和/或遵循TFLIte GPU和MediaPipe中的代码路径; 这两个框架大量使用SSBO和纹理。 我确定您会在其中找到用例。
@impjdi @svenstaro @ktgordon @SanthoshRajendiran @gnsmrky
我是opengl es的新手。
我已经查看了MediaPipe和Tflite GPU尝试解决它,但是失败了
我很好奇如何在Android中调试计算着色器
网络上关于ssbo的资料很少
该代码由https://github.com/gnsmrky/tensorflow-lite-ssbo提供
对不起,我的英语不好
别再强调我了。
@svenstaro非常抱歉打扰您
@impjdi
我终于找到了为什么glmapbufferrange返回全零的原因。
GL_OES_EGL_image_external_essl3无法在某些Android设备上使用
https://community.arm.com/developer/tools-software/graphics/f/discussions/9432/is-extension-gl_oes_egl_image_external_essl3-not-working-properly-in-compute-shader-on-mali-g71-gpu
啊,谢谢你的更新和分享!
我遵循了GPU委托的android官方文档,也陷入了bindBuffer步骤。
我不在Java领域工作,因此我不知道正在使用哪个委托Java API,但是bindGlBufferToTensor在已弃用的GL委托中被重命名,并在新的GPU委托中被删除。 签出
//tf/lite/delegates/gpu/gl_delegate
&//tf/lite/delegates/gpu/gpu_delegate
。
我签出了当前的主服务器,没有gpu_delegate(.cc?),只有gpu_delegate_jni(.cc)。 你是那个意思吗
无论如何,我发现TfLiteGpuDelegateBindBufferToTensor似乎是库的导出符号,我们可以获取委托的本机句柄,因此我们可以直接从Java调用该方法。
抱歉,最后一个文件应该是//tf/lite/delegates/gpu/delegate.cc
。 我们在内部尝试使用bindBuffer
(不使用委托API,但直接使用GPU内部函数),并且发现新API有点破损,因此无法与新API一起使用。 有人正在解决这些问题。 现在,如果您想使用bindBuffer
,我想您仍然会使用旧的API,即gl_delegate
。
@impjdi感谢您的更新。 这是否意味着SSBO路由当前仅可用于C绑定或根本不可用?
我尚未检查Java,但是如果Java已迁移到新的API(delegate.cc),则您的评估是正确的。
对于C ++,仅在v1(gl_delegate.cc)中可用,而在v2(delegate.cc)中不可用。
@impjdi是否解决了v2委托中的SSBO bindBuffer问题?
当前的计划是在委托v2中不支持bindBuffer。
@impjdi我们将图像帧保存在GPU内存中。 我们是否应该将其移至CPU只是为了开始推理,然后又将其移至GPU? 在许多情况下,花时间进行此操作会浪费gpu推理的好处。
@impjdi您是否可以共享有关为何委托v2不支持bindBuffer的任何信息? 我相信它可以消除memcpy动作,从而改善gpu端到端推理时间。 tflite团队会遇到一些无法解决的问题,还是仅由产品要求来决定?
移动GPU推断有许多高级用法,对于每种GPU委托,GPU委托都需要诸如bindBuffer
类的辅助函数,因为它不适合委托框架。 通过辅助功能或选项添加了对扩展用法的大量支持后,我们认为组合增长不再可维护,即使在GPU委托(OpenCL,OpenGL,Metal等)中,其外观也不一致。 请注意,我们必须使用Java API对其进行包装。 由于大多数用户都希望GPU委托只是一种快速的黑箱加速器,因此我们最终决定委托API将保持简洁。 对于支持简化的GPU执行管道的高级用法,我们仍将提供示例代码,例如MediaPipe的TfLiteInferenceCalculator
。 请注意,它尚不存在,因为它仍使用v1委托,因此可以访问bindBuffer
。
@impjdi此信息很有帮助。 另一个问题是MediaPipe委托v2集成何时发布? 谢谢。
有人在努力:)
是否有人设法将缓冲区与v2委托绑定?
在我看来,mediapipe已经在使用它,请参见mediapipe / tflite_gpu_runner.h 。 该运行器用在impjdi提到的use_advanced_gpu_api_
标志下的计算器中。 它代替了解释器/委托流程,而是使用低级组件。
对于那些想在不维护自己的解释器的情况下拥有SSBO实用程序的人来说,这是非常不友好的,但是更深入地讲,绑定逻辑位于mediapipe / tflite_gpu_runner.cc中,只需调用InferenceRunner::SetInputObject
。
v2委托人自己拥有InferenceRunner
因此对v2委托人的一个小补丁可能会添加所需的SetInputObject
(或输出)调用。 但是我还没有测试,设置此刻对我来说很困难。
@impjdi ,任何指导性的话在这里都会有所帮助。 这个对吗? 我们可以简单地使用InferenceRunner :: SetInputObject调用修补v2委托,然后调用它而不是v1 bindBuffer吗? 我认为我走的路不对,但是我确实认为,如果我们能够获得补丁文件并在此处共享,它将对社区非常有用。
@ natario1我认为@impjdi解释了bindBuffer
API不适合v2委托设计。 v1和v2委托之间的主要区别是v2同时支持OpenCL和OpenGL后端,而v1仅支持OpenGL。 这将影响Tflite处理数据所有权交换的方式。 而且,市场上的许多设备并不完全支持OpenCL-OpenGL互操作性。 我也尝试在MediaPipe中使用use_advanced_gpu_api_
标志,当我打开应用程序时会崩溃。 因此,我认为v2代理支持bindBuffer
功能不是一个简单的补丁。 如果您需要此功能,我认为最简单的解决方案是坚持使用opengl后端的mediapipe。
感谢您的评论@ brucechou1983 。 对我来说,一个更简单的解决方案是坚持使用v1委托,但是老实说,它似乎并没有像mediapipe运行程序那样做任何复杂的事情,除了在准备时调用InferenceRunner::SetInputObject
和InferenceRunner::SetInputObjectDef
。 我知道它可能还没有准备好,因为它处于标记之下。
v2委托也执行相同的object / objectdef调用,但是不同之处在于,它使用ObjectType::CPU_MEMORY
而不是像mediapipe那样使用ObjectType::OPENGL_SSBO
。
我不知道Android对OpenCL的支持是什么,但是OpenGL可以正常工作,因此我们可以在v2委托选项中有一个标志,告诉委托不要尝试OpenCL并使用OpenGL。 我认为,TF团队可以添加一些内容来简化v1-v2的过渡,因为使用v1的用户可能会设置SSBO。
@ natario1如果仅需要使用OpenGL的标志,尽管已经处于试验阶段,但它已经TFLITE_GPU_EXPERIMENTAL_FLAGS_GL_ONLY
。
但是,当您需要在200美元的手机上运行实时(>> 30fps)语义分段和/或运行面部网格时,在tflite运行时中选择合适的GPU后端以有效执行实际上并不是一个小问题。 我确实看到了对某些MALI gpu设备使用OpenCL的价值。 invoke()
执行速度比OpenGL ES快2到3倍。 尽管我必须将数据复制到张量/从张量复制,但总体性能还是更好的。 我认为tflite团队正在尝试将v2委托设计为通用/任意IoT设备/易于使用的黑箱加速器,同时为MediaPipe等其他框架创建接口以针对特定用途进行优化,例如在移动设备/台式机上简化GPU执行。
@ natario1我看到你在那里做了作业,很好
您可能已经注意到,但是TFLite正在为各种加速器或API添加一堆委托。 他们每个人都具有自定义的帮助程序功能并没有帮助使用,但是对于希望使用TFLite GPU委托作为魔术盒进行GPU加速推理的99%的用户来说,这更加令人困惑。 因此,我们做出的最终决定是使TFLite GPU代表尽可能简单,但为想要做真正高性能的高级用户留出空间。
提供TFLite GPU和MediaPipe的团队是姐妹团队,共享一位经理。 话虽如此,TFLite GPU不会破坏MediaPIpe,这是一个保证。 从这个意义上讲,更深入地使用MediaPipe的高级内部API(例如InferenceRunner::SetInputObject
是安全的。 当然,因为它不是公共API,而是高级的内部API,所以可能会发生API更改,使您有时不时遇到麻烦,但是您将始终拥有MediaPipe的参考实现。
我了解@impjdi的情况。 您会考虑类似V2Delegate::GetInferenceRunner()
吗? 这样我们就可以调用 InferenceRunner::SetInputObject
或代表外部的其他任何内容。
您说SetInput/OutputObject
和SetInput/OutputObjectDef
API是“高级的”,并且它们在某种程度上是合理的,但同时,将张量绑定到“某物”是很有意义的,必须指定其数据布局,大小,对象类型等。 就BindGlBufferToTensor
,它们实际上是非常优雅且易于理解的,从我的角度来看,这只是在引擎盖下做了一些我无法真正把握的魔术。
这些API也将隐藏在GetInferenceRunner()API的后面,您可以将其记录为“自担风险”功能,并保持黑匣子表面清洁。 我认为这种方法确实可以像您所说的那样“让房间开着”。 (也许为您做的工作不仅仅是为推理运行者添加getter,但您明白了—能够从外部控制委托对象)
除此之外,我将在本周末尝试使用这些低级API,以查看是否能够使v2正常工作。 感谢您的帮助!
编辑:在度过了一个周末之后,我意识到这个建议是不可能的,但是我希望您可以考虑像我最终所做的那样,这很干净,并且使委托标头保持不变。
@impjdi关于如何解决此错误的任何建议? BHWC> BHWC4转换似乎是一个问题,但是我不知道如何解决。 它发生在ToTensorConverter中。
E/tflite:
TfLiteGpuDelegate Invoke: Missing output in converter
Node number 1 (TfLiteGpuDelegateV2) failed to invoke.
我创建对象def和张量对象,如下所示:
// object def
tflite::gpu::ObjectDef object_def;
object_def.data_type = tflite::gpu::DataType::FLOAT32;
object_def.data_layout = tflite::gpu::DataLayout::BHWC;
object_def.object_type = tflite::gpu::ObjectType::OPENGL_SSBO;
object_def.user_provided = true;
// tensor object
tflite::gpu::OpenGlBuffer tensor_object;
tensor_object.id = ssbo;
然后将两者都传递给ModifyGraphWithDelegate
之前的委托人。 它们已正确传递给推理运行器和运行器构建器,但是我收到该转换器错误。
TF版本为2.2.0,我使用的模型非常简单,拍摄了400x400x1的图像并计算平均强度,返回一个浮点数。 我正在尝试仅将SSBO对象用于输入。
另外,我正在运行OpenGL后端,我的手机上没有OpenCL。
许多小时后,我认为我遇到了一个仍在2.2.0中存在的错误,但已通过以下提交在master中修复: https : https://github.com / tensorflow / tensorflow / commit / dffe6a0e810f4c3d9968ddb56fd58c8f405eb846
简而言之,对于那些感兴趣的人,我正在使用具有1个颜色通道(而不是4个颜色通道)的BHWC的事实,要求gl引擎执行一次转换和这种转换(在https://github.com/tensorflow/之前) tensorflow / commit / 4000a5c75cdbe49d77bcac93a7f21070a31c4cce和https://github.com/tensorflow/tensorflow/commit/dffe6a0e810f4c3d9968ddb56fd58c8f405eb846)已完全损坏,因为user_provided
/ flow / tensor硬编码为true blob / v2.2.0 / tensorflow / lite / delegates / gpu / gl / api2.cc#L595),但是当user_provided
为true时,引擎不会费心创建输出GL缓冲区(https:// github .com / tensorflow / tensorflow / blob / v2.2.0 / tensorflow / lite / delegates / gpu / gl / api2.cc#L199-L202),因此无法进行C-> C4转换。
通过将https://github.com/tensorflow/tensorflow/commit/4000a5c75cdbe49d77bcac93a7f21070a31c4cce和https://github.com/tensorflow/tensorflow/commit/dffe6a0e810f4c3d9968ddb56fd58c8f405eb846插入到v2。使用v2委托执行SSBO I / O。 这些提交已经很老了,所以我希望他们可以将其提交到下一个版本中。
这些是我必须进行的更改以公开必需的API: https :
最有用的评论
尚未正式宣布,但是供参考:GPU代码现在可以在以下位置看到:
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/gpu
如果您需要代码以更好地了解情况,那么会发生什么。