首页 > 解决方案 > Android:与相同模型的 Python 相比,TFLite 给出了错误的预测

问题描述

我正在创建一个需要运行 tensorflow 图像分类模型的 Android 应用程序。我在 Python 中创建了以下简单模型:

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=(28, 28, 2)))
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dense(13, activation="softmax"))

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

在这里,输入是通过以下方式从图像创建的:

img = Image.open("img1.png").convert("LA").resize((28, 28))
input = np.reshape(np.asarray(img), (1, 28, 28, 2))

模型的准确性非常好。我将模型保存为以下tflite格式:

conv = tf.lite.TFLiteConverter.from_keras_model(model)
tfmodel = conv.convert()
open("mymodel.tflite", "wb").write(tfmodel)

现在,我想在 Android 中使用这个模型。我正在使用 Android Studio 4.1。我tfliteFile > New > Others > TFLite. 我通过以下方式启动了 TF 模型:

Mymodel model = Mymodel.newInstance(context);

我有一个要测试的位图。为了向模型发送输入,我需要从该位图创建一个形状为 (1, 28, 28, 2) 的数组,并使用该数组创建一个 ByteBuffer 对象。我这样做的方式如下:

public static float[][][][] getBMPArray(Bitmap bmpTile) {
    int width = bmpTile.getWidth();
    float[][][][] bmpArray = new float[1][width][width][2];
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < width; j++) {
            float pixelVal = (float)(Color.red(bmpTile.getPixel(j, i)) * 299
                    + Color.green(bmpTile.getPixel(j, i)) * 587
                    + Color.blue(bmpTile.getPixel(j, i)) * 114) / 1000;
            bmpArray[0][i][j][0] = pixelVal / 255;
            bmpArray[0][i][j][1] = 1;
        }
    }
    return bmpArray;
}

public static ByteBuffer bmpByteBuffer(Bitmap bmp) {
    int width = bmp.getWidth();
    float[][][][] bmpArray = getBMPArray(bmp);
    ByteBuffer bmpByteBuf = ByteBuffer.allocate(1 * 28 * 28 * 2 * 4);;
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < width; j++) {
            bmpByteBuf.putFloat(bmpArray[0][i][j][0]);
            bmpByteBuf.putFloat(bmpArray[0][i][j][1]);
        }
    }
    return bmpByteBuf;
}

我通过以下方式将输入发送到模型:

ByteBuffer bmpByteBuf = bmpByteBuffer(bmp);
TensorBuffer inputFeature0 = TensorBuffer.createFixedSize(new int[]{1, 28, 28, 2}, DataType.FLOAT32);
inputFeature0.loadBuffer(bmpByteBuf);

然后我以以下方式创建输出:

Mymodel.Outputs outputs = model.process(inputFeature0);
TensorBuffer outputFeature0 = outputs.getOutputFeature0AsTensorBuffer();
float[] predLabels = outputFeature0.getFloatArray();

我已经检查了两个不同的图像,通过模型在 Python 和 Android 中运行它们,但 Python 总是给出正确的结果(这是预期的),但 Android 给类提供了错误的概率。以下是 Python 和 Android 针对相同图像和相同模型的输出(Python 给出了正确答案):

Python: array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)
Android: predLabels = {float[13]@9684} [NaN for every output]

我认为问题来了可能是因为我没有在 Android 中正确解析图像数据。有人可以在这方面帮助我。谢谢!

标签: javapythonandroidtensorflowimage-classification

解决方案


推荐阅读