通过 Tensorflow 进行的图像分类给出了完全相同的预测
Image classification through Tensorflow gives the exact same prediction
耐心等待我解释一下。
我有一个 Android 应用程序,它使用 OpenCV 将 YUV420 图像转换为位图并将其传输到解释器。问题是,每次我 运行 它,我都会得到完全相同的 class 预测,具有与我指向的内容无关的完全相同的置信度值。
...
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
...
现在,在您提到我的模型训练不足之前,我已经在 Tensorflow Codelab-2 中提供的 TFLite 示例中测试了完全相同的 .tflite
文件。它可以正常工作,并以 90%+ 的准确率识别我的所有 4 个 classes。此外,我使用了一个 label_image.py
脚本来测试 .pb
文件,我的 .tflite
是从该文件派生的,它可以正常工作。我已经在每个 class 的近 5000 多张图像上训练了模型。由于它适用于其他应用程序,我猜模型没有问题,但我的实现没有问题。虽然我就是不能确定它。
以下代码用于从图像字节创建垫子:
//Retrieve the camera Image from ARCore
val cameraImage = frame.acquireCameraImage()
val cameraPlaneY = cameraImage.planes[0].buffer
val cameraPlaneUV = cameraImage.planes[1].buffer
// Create a new Mat with OpenCV. One for each plane - Y and UV
val y_mat = Mat(cameraImage.height, cameraImage.width, CvType.CV_8UC1, cameraPlaneY)
val uv_mat = Mat(cameraImage.height / 2, cameraImage.width / 2, CvType.CV_8UC2, cameraPlaneUV)
var mat224 = Mat()
var cvFrameRGBA = Mat()
// Retrieve an RGBA frame from the produced YUV
Imgproc.cvtColorTwoPlane(y_mat, uv_mat, cvFrameRGBA, Imgproc.COLOR_YUV2BGRA_NV21)
// I've tried the following in the above line
// Imgproc.COLOR_YUV2RGBA_NV12
// Imgproc.COLOR_YUV2RGBA_NV21
// Imgproc.COLOR_YUV2BGRA_NV12
// Imgproc.COLOR_YUV2BGRA_NV21
以下代码用于将图像数据添加到 ByteBuffer 中:
// imageFrame is a Mat object created from OpenCV by processing a YUV420 image received from ARCore
override fun setImageFrame(imageFrame: Mat) {
...
// Convert mat224 into a float array that can be sent to Tensorflow
val rgbBytes: ByteBuffer = ByteBuffer.allocate(1 * 4 * 224 * 224 * 3)
rgbBytes.order(ByteOrder.nativeOrder())
val frameBitmap = Bitmap.createBitmap(imageFrame.cols(), imageFrame.rows(), Bitmap.Config.ARGB_8888, true)
// convert Mat to Bitmap
Utils.matToBitmap(imageFrame, frameBitmap, true)
frameBitmap.getPixels(intValues, 0, frameBitmap.width, 0, 0, frameBitmap.width, frameBitmap.height)
// Iterate over all pixels and retrieve information of RGB channels
intValues.forEach { packedPixel ->
rgbBytes.putFloat((((packedPixel shr 16) and 0xFF) - 128) / 128.0f)
rgbBytes.putFloat((((packedPixel shr 8) and 0xFF) - 128) / 128.0f)
rgbBytes.putFloat(((packedPixel and 0xFF) - 128) / 128.0f)
}
}
.......
private var labelProb: Array<FloatArray>? = null
.......
// and classify
labelProb?.let { interpreter?.run(rgbBytes, it) }
.......
我检查了从 Mat 转换而来的位图。它尽可能地表现得最好。
有什么想法吗?
更新一个
我稍微更改了 setImageFrame
方法的实现以匹配实现 here。既然它对他有用,我希望它也对我有用。还是不行。
override fun setImageFrame(imageFrame: Mat) {
// Reset the rgb bytes buffer
rgbBytes.rewind()
// Iterate over all pixels and retrieve information of RGB channels only
for(rows in 0 until imageFrame.rows())
for(cols in 0 until imageFrame.cols()) {
val imageData = imageFrame.get(rows, cols)
// Type of Mat is 24
// Channels is 4
// Depth is 0
rgbBytes.putFloat(imageData[0].toFloat())
rgbBytes.putFloat(imageData[1].toFloat())
rgbBytes.putFloat(imageData[2].toFloat())
}
}
更新二
怀疑我的浮动模型,我将其更改为预构建的 MobileNet Quant 模型以消除可能性。问题依然存在于此。
...
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
...
好的。所以4天后,我终于解决了这个问题。问题是 ByteBuffer
是如何启动的。我在做 :
private var rgbBytes: ByteBuffer = ByteBuffer.allocate(1 * 4 * 224 * 224 * 3)
而不是我应该做的:
private val rgbBytes: ByteBuffer = ByteBuffer.allocateDirect(1 * 4 * 224 * 224 * 3)
我试图了解 ByteBuffer.allocate()
和 ByteBuffer.allocateDirect()
here 之间的区别,但无济于事。
如果有人能回答另外两个问题,我会很高兴:
- 为什么 Tensorflow 需要直接字节缓冲区而不是非直接缓冲区?
- 简述Direct和Non Direct ByteBuffer的区别是什么?
耐心等待我解释一下。
我有一个 Android 应用程序,它使用 OpenCV 将 YUV420 图像转换为位图并将其传输到解释器。问题是,每次我 运行 它,我都会得到完全相同的 class 预测,具有与我指向的内容无关的完全相同的置信度值。
...
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
Recognitions : [macbook pro: 0.95353276, cello gripper: 0.023749515].
...
现在,在您提到我的模型训练不足之前,我已经在 Tensorflow Codelab-2 中提供的 TFLite 示例中测试了完全相同的 .tflite
文件。它可以正常工作,并以 90%+ 的准确率识别我的所有 4 个 classes。此外,我使用了一个 label_image.py
脚本来测试 .pb
文件,我的 .tflite
是从该文件派生的,它可以正常工作。我已经在每个 class 的近 5000 多张图像上训练了模型。由于它适用于其他应用程序,我猜模型没有问题,但我的实现没有问题。虽然我就是不能确定它。
以下代码用于从图像字节创建垫子:
//Retrieve the camera Image from ARCore
val cameraImage = frame.acquireCameraImage()
val cameraPlaneY = cameraImage.planes[0].buffer
val cameraPlaneUV = cameraImage.planes[1].buffer
// Create a new Mat with OpenCV. One for each plane - Y and UV
val y_mat = Mat(cameraImage.height, cameraImage.width, CvType.CV_8UC1, cameraPlaneY)
val uv_mat = Mat(cameraImage.height / 2, cameraImage.width / 2, CvType.CV_8UC2, cameraPlaneUV)
var mat224 = Mat()
var cvFrameRGBA = Mat()
// Retrieve an RGBA frame from the produced YUV
Imgproc.cvtColorTwoPlane(y_mat, uv_mat, cvFrameRGBA, Imgproc.COLOR_YUV2BGRA_NV21)
// I've tried the following in the above line
// Imgproc.COLOR_YUV2RGBA_NV12
// Imgproc.COLOR_YUV2RGBA_NV21
// Imgproc.COLOR_YUV2BGRA_NV12
// Imgproc.COLOR_YUV2BGRA_NV21
以下代码用于将图像数据添加到 ByteBuffer 中:
// imageFrame is a Mat object created from OpenCV by processing a YUV420 image received from ARCore
override fun setImageFrame(imageFrame: Mat) {
...
// Convert mat224 into a float array that can be sent to Tensorflow
val rgbBytes: ByteBuffer = ByteBuffer.allocate(1 * 4 * 224 * 224 * 3)
rgbBytes.order(ByteOrder.nativeOrder())
val frameBitmap = Bitmap.createBitmap(imageFrame.cols(), imageFrame.rows(), Bitmap.Config.ARGB_8888, true)
// convert Mat to Bitmap
Utils.matToBitmap(imageFrame, frameBitmap, true)
frameBitmap.getPixels(intValues, 0, frameBitmap.width, 0, 0, frameBitmap.width, frameBitmap.height)
// Iterate over all pixels and retrieve information of RGB channels
intValues.forEach { packedPixel ->
rgbBytes.putFloat((((packedPixel shr 16) and 0xFF) - 128) / 128.0f)
rgbBytes.putFloat((((packedPixel shr 8) and 0xFF) - 128) / 128.0f)
rgbBytes.putFloat(((packedPixel and 0xFF) - 128) / 128.0f)
}
}
.......
private var labelProb: Array<FloatArray>? = null
.......
// and classify
labelProb?.let { interpreter?.run(rgbBytes, it) }
.......
我检查了从 Mat 转换而来的位图。它尽可能地表现得最好。
有什么想法吗?
更新一个
我稍微更改了 setImageFrame
方法的实现以匹配实现 here。既然它对他有用,我希望它也对我有用。还是不行。
override fun setImageFrame(imageFrame: Mat) {
// Reset the rgb bytes buffer
rgbBytes.rewind()
// Iterate over all pixels and retrieve information of RGB channels only
for(rows in 0 until imageFrame.rows())
for(cols in 0 until imageFrame.cols()) {
val imageData = imageFrame.get(rows, cols)
// Type of Mat is 24
// Channels is 4
// Depth is 0
rgbBytes.putFloat(imageData[0].toFloat())
rgbBytes.putFloat(imageData[1].toFloat())
rgbBytes.putFloat(imageData[2].toFloat())
}
}
更新二
怀疑我的浮动模型,我将其更改为预构建的 MobileNet Quant 模型以消除可能性。问题依然存在于此。
...
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
Recognitions : [candle: 18.0, otterhound: 15.0, syringe: 13.0, English foxhound: 11.0]
...
好的。所以4天后,我终于解决了这个问题。问题是 ByteBuffer
是如何启动的。我在做 :
private var rgbBytes: ByteBuffer = ByteBuffer.allocate(1 * 4 * 224 * 224 * 3)
而不是我应该做的:
private val rgbBytes: ByteBuffer = ByteBuffer.allocateDirect(1 * 4 * 224 * 224 * 3)
我试图了解 ByteBuffer.allocate()
和 ByteBuffer.allocateDirect()
here 之间的区别,但无济于事。
如果有人能回答另外两个问题,我会很高兴:
- 为什么 Tensorflow 需要直接字节缓冲区而不是非直接缓冲区?
- 简述Direct和Non Direct ByteBuffer的区别是什么?