【问题标题】:java.nio.BufferOverflowException run-time error when running TensorFlow model in Android?在 Android 中运行 TensorFlow 模型时出现 java.nio.BufferOverflowException 运行时错误?
【发布时间】:2018-02-05 13:47:36
【问题描述】:

出于某种原因,每当我增加输入图像大小以在 android 中进行推理(用于图像分类)时,我都会收到此错误:

 Process: com.example.android.androidevaluateimagenet, PID: 31064
 java.nio.BufferOverflowException
     at java.nio.FloatBuffer.put(FloatBuffer.java:444)
     at org.tensorflow.Tensor.writeTo(Tensor.java:390)
     at org.tensorflow.contrib.android.TensorFlowInferenceInterface.fetch(TensorFlowInferenceInterface.java:338)
     at org.tensorflow.contrib.android.TensorFlowInferenceInterface.fetch(TensorFlowInferenceInterface.java:301)
     at com.example.android.androidevaluateimagenet.TensorFlowImageClassifier.recognizeImage(TensorFlowImageClassifier.java:148)
     at com.example.android.androidevaluateimagenet.MainActivity.getInferenceTime(MainActivity.java:240)
     at com.example.android.androidevaluateimagenet.MainActivity$2.onClick(MainActivity.java:318)
     at android.view.View.performClick(View.java:4763)
     at android.view.View$PerformClick.run(View.java:19821)
     at android.os.Handler.handleCallback(Handler.java:739)
     at android.os.Handler.dispatchMessage(Handler.java:95)
     at android.os.Looper.loop(Looper.java:135)
     at android.app.ActivityThread.main(ActivityThread.java:5272)
     at java.lang.reflect.Method.invoke(Native Method)
     at java.lang.reflect.Method.invoke(Method.java:372)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)                                                                      at com.example.android.androidevaluateimagenet.MainActivity$2.onClick(MainActivity.java:318)
                                                                                                 at android.view.View.performClick(View.java:4763)
                                                                                                 at android.view.View$PerformClick.run(View.java:19821)
                                                                                                 at android.os.Handler.handleCallback(Handler.java:739)
                                                                                                 at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                                 at android.os.Looper.loop(Looper.java:135)
                                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5272)
                                                                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                                                                 at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909)
                                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)

我不太确定为什么。对于低于我使用的输入图像尺寸,模型运行良好。此外,该问题仅对我正在使用的一种模型而言是唯一的。我也尝试过更小和更大(2 倍大)的模型,它们工作得非常好。只是这个模型给了我这个问题,但我无法根据产生的错误确定这个模型到底有什么问题。

具体的错误堆栈跟踪:

TensorFlowImageClassifier.java:

    inferenceInterface.fetch(outputName, outputs);

TensorFlowInferenceInterace.java:

public void fetch(String var1, float[] var2) {
    this.fetch(var1, FloatBuffer.wrap(var2));
}

张量.java:

public void writeTo(FloatBuffer var1) {
    if(this.dtype != DataType.FLOAT) {
        throw incompatibleBuffer(var1, this.dtype);
    } else {
        ByteBuffer var2 = this.buffer();
        var1.put(var2.asFloatBuffer());
    }
}

FloatBuffer.java:

public FloatBuffer put(FloatBuffer src) {
    if (src == this)
        throw new IllegalArgumentException();
    int n = src.remaining();
    if (n > remaining())
        throw new BufferOverflowException();
    for (int i = 0; i < n; i++)
        put(src.get());
    return this;
}

【问题讨论】:

  • 我已经看到了这个帖子,但我认为这不是问题的原因。 (缓冲区是在库内部分配的,我无法控制它)。此外,我运行了一个更大的模型,并且尺寸没有超过。
  • 尝试通过 Runtime.getRuntime().gc() 清除位图缓存; System.gc();
  • 试过了还是不行,还是一样的错误。

标签: java android machine-learning tensorflow computer-vision


【解决方案1】:

离开堆栈跟踪和错误消息,似乎抱怨提供给fetch 的float[] 数组的长度小于模型生成的输出大小。因此,您需要调整代码以向fetch 提供大小更合适的数组。

不幸的是,TensorFlowInferenceInterface 类没有公共方法来访问获取的张量的实际形状。如果您是从源代码构建,则可以通过在类中添加以下内容来实现:

public long[] fetchShape(String outputName) {
  return getTensor(outputName).shape();
}

(这可能是对项目的良好贡献)。

希望对您有所帮助。

【讨论】:

  • 不幸的是,我需要的容量是相当固定的,我不太确定在代码中的哪个位置可以进一步降低内存需求。我认为问题与模型实现有关,因为我使用了一个更大的模型,它消耗了大约 3 倍的内存,但在移动设备上运行它没有问题。有没有办法检查大部分内存来自模型的位置?
【解决方案2】:

问题肯定如https://stackoverflow.com/users/6708503/ash所描述的那样

使用此日志输出查看张量输出的形状:

Log.i(TAG, "This is the output tensor shape of my .pb file in asset folder" + 
inferenceInterface.graph().operation(outputNames[i]).output(0).shape());

希望这将有助于跟踪调试过程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 2017-08-21
    相关资源
    最近更新 更多