如何从 tflite 模型输出形状 [1, 28, 28,1] 的数组作为 android 中的图像

Posted

技术标签:

【中文标题】如何从 tflite 模型输出形状 [1, 28, 28,1] 的数组作为 android 中的图像【英文标题】:How to output array of shape [ 1, 28, 28,1] from a tflite model as image in android 【发布时间】:2020-10-01 22:55:51 【问题描述】:

我有一个保存的tflite模型,其输入输出详情如下:

    输入 :['name': 'dense_4_input', 'index': 0, 'shape': array([ 1, 100], dtype=int32), 'shape_signature ': array([ 1, 100], dtype=int32), 'dtype': , 'quantization': (0.0, 0), 'quantization_parameters': 'scales': array([], dtype=float32), ' zero_points': array([], dtype=int32), 'quantized_dimension': 0, 'sparsity_parameters': ]

    输出 : ['name': 'Identity', 'index': 22, 'shape': array([ 1, 28, 28, 1], dtype=int32 ), 'shape_signature': array([ 1, 28, 28, 1], dtype=int32), 'dtype': , 'quantization': (0.0, 0), 'quantization_parameters': 'scales': array([ ], dtype=float32), 'zero_points': array([], dtype=int32), 'quantized_dimension': 0, 'sparsity_parameters': ]

如何在使用 Java 和 Tensorflow 解释器的 android 应用上将输出显示为图像?

【问题讨论】:

【参考方案1】:
import android.content.res.AssetManager
import android.graphics.Bitmap
import android.util.Log
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.Tensor
import java.io.FileInputStream
import java.lang.StringBuilder
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.channels.FileChannel

class ImgPredictor(val assetManager: AssetManager, modelFilename: String) 
    private var tflite: Interpreter

    private var input: ByteBuffer
    private var output: ByteBuffer

    init 
        val tfliteOptions = Interpreter.Options()

        val fd = assetManager.openFd(modelFilename)
        val inputStream = FileInputStream(fd.fileDescriptor)
        val fileChannel: FileChannel = inputStream.channel
        val startOffset: Long = fd.startOffset
        val declaredLength: Long = fd.declaredLength
        val mbb = fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength)
        tflite = Interpreter(mbb, tfliteOptions)
        Log.i("ImgPredictor", "interpreter: $tflite.detail()")
        input = ByteBuffer.allocate(100 * Int.SIZE_BYTES)
        input.order(ByteOrder.nativeOrder())

        output = ByteBuffer.allocate(1 * 28 * 28 * 1 * Int.SIZE_BYTES)
        output.order(ByteOrder.nativeOrder())
    

    fun predict(data: IntArray): Bitmap 
        val startTs = System.currentTimeMillis();

        input.clear()
        output.clear()

        input.rewind()
        for (i in 0 until 100) 
            input.putInt(data[i])
        
        tflite.run(input, output)
        val bitmap = Bitmap.createBitmap(28, 28, Bitmap.Config.ARGB_8888);
        // vector is your int[] of ARGB
        bitmap.copyPixelsFromBuffer(output)
        return bitmap
    


fun Tensor.detail(): String 
    return "[shape: $this.shape().toList() dataType: $this.dataType(), bytes: $this.numBytes()]"


fun Interpreter.detail(): String 
    val sb = StringBuilder("interpreter: \n")
    sb.append("input:  \n")
    for (i in 0 until this.inputTensorCount) 
        sb.append("    ").append(this.getInputTensor(i).detail()).append("\n")
    
    sb.append(", \n")

    sb.append("output:  \n")
    for (i in 0 until this.outputTensorCount) 
        sb.append("    ").append(this.getOutputTensor(i).detail()).append("\n")
    
    sb.append("")
    return sb.toString()

您可以在此处查看官方教程以获取更多详细信息: Example of object-detection interpreter. 但这里有几点你应该注意: 1. 尽量保持implementation 'org.tensorflow:tensorflow-lite:x.x.x'与您的PC相同的版本,因为某些操作可能无法在较低版本中运行。 2. 使用一些细节函数来打印解释器的输入/输出。 3.检查输入输出数据缓冲顺序endian。

【讨论】:

以上代码抛出运行时异常:“Buffer not large enough for pixels” 尽量保持你的代码顺利通过代码。确保你输出的 int32 是 RGBA 格式的数据,你可以调试它。

以上是关于如何从 tflite 模型输出形状 [1, 28, 28,1] 的数组作为 android 中的图像的主要内容,如果未能解决你的问题,请参考以下文章

在android中运行TFLite模型[字节缓冲区的大小和形状不匹配]

如何在脚本中加载 tflite 模型?

处理来自 YOLOv5 TFlite 的输出数据

如何在图像分类上快速运行 tflite 模型

如何知道 Tensorflow Lite 模型的输入/输出特征信息?

如何从特定层获取输出张量?