我正在创建一个需要运行 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。我tflite
从File > 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 中正确解析图像数据。有人可以在这方面帮助我。谢谢!