【问题标题】:Pretrained keras model is returing the same result in android预训练的 keras 模型在 android 中返回相同的结果
【发布时间】:2019-05-26 13:40:15
【问题描述】:

我在 Keras 中创建了一个图像分类器,后来我将模型保存为 pb 格式以在 android 中使用它。

但是,在python代码中,它可以正确地对图像进行分类。但在 android 中,无论我提供什么图像作为输入,输出总是相同的。

这就是我训练模型的方式

rom keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense

# Initialising the CNN
classifier = Sequential()

# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))

# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))

# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))

# Step 3 - Flattening
classifier.add(Flatten())

# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))

# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])

# Part 2 - Fitting the CNN to the images

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale = 1./255,
                                   shear_range = 0.2,
                                   zoom_range = 0.2,
                                   horizontal_flip = True)

test_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory('dataset/training_set',
                                                 target_size = (64, 64),
                                                 batch_size = 32,
                                                 class_mode = 'binary')

test_set = test_datagen.flow_from_directory('dataset/test_set',
                                            target_size = (64, 64),
                                            batch_size = 32,
                                            class_mode = 'binary')

classifier.fit_generator(training_set,
                         steps_per_epoch = 8000,
                         epochs = 25,
                         validation_data = test_set,
                         validation_steps = 2000)
classifier.summary()
classifier.save('saved_model.h5')

后来我使用this将该keras模型(saved_model.h5)转换为tensorflow模型

这就是我转换位图浮点数组的方式

    public static float[] getPixels(Bitmap bitmap) {

        final int IMAGE_SIZE = 64;

        int[] intValues = new int[IMAGE_SIZE * IMAGE_SIZE];
        float[] floatValues = new float[IMAGE_SIZE * IMAGE_SIZE * 3];

        if (bitmap.getWidth() != IMAGE_SIZE || bitmap.getHeight() != IMAGE_SIZE) {
            // rescale the bitmap if needed
            bitmap = ThumbnailUtils.extractThumbnail(bitmap, IMAGE_SIZE, IMAGE_SIZE);
        }

        bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

        for (int i = 0; i < intValues.length; ++i) {
            final int val = intValues[i];
        // bitwise shifting - without our image is shaped [1, 64, 64, 1] but we need [1, 168, 168, 3]
            floatValues[i * 3 + 2] = Color.red(val) / 255.0f;
            floatValues[i * 3 + 1] = Color.green(val) / 255.0f;
            floatValues[i * 3] = Color.blue(val) / 255.0f;
        }
        return floatValues;
    }

后来,我尝试在android中使用tensorflow对图像进行分类,如下所示。

TensorFlowInferenceInterface tensorFlowInferenceInterface; 
tensorFlowInferenceInterface = new TensorFlowInferenceInterface(getAssets(),"model.pb");
float[] output = new float[2];
tensorFlowInferenceInterface.feed("conv2d_11_input",
                getPixels(bitmap), 1,64,64,3);
tensorFlowInferenceInterface.run(new String[]{"dense_12/Sigmoid"});
tensorFlowInferenceInterface.fetch("dense_12/Sigmoid",output);

我给output 的值是[1,0]

有什么我错过的吗?

【问题讨论】:

  • 您执行的预处理步骤是否与模型训练前的相同
  • 是的,我这样做了。我要分享我的代码吗?
  • 是的,但请尝试将其限制为仅相关部分,以便任何人都可以轻松检查它。
  • @today 我已经编辑了我的问题。你能看看吗?
  • 最初在玩 TensorFlowInferenceInterface 时,我遇到了类似的问题。但是切换到TensorFlow Lite后,我的问题就解决了。

标签: android tensorflow machine-learning keras deep-learning


【解决方案1】:

Color.red(int)Color.blue(int)Color.green(int) 返回的颜色分量是 [0, 255] 范围内的整数(请参阅 doc)。使用 Keras 的ImageDataGenerator 读取图像时也是如此。但是,正如我在 cmets 部分所述,在预测阶段,您需要执行与训练阶段相同的预处理步骤。您在训练中通过1./255 缩放图像像素(在ImageDataGenerator 中使用rescale = 1./255),因此,根据我提到的第一点,这也必须在预测中完成:

floatValues[i * 3 + 2] = Color.red(val) / 255.0;
floatValues[i * 3 + 1] = Color.green(val) / 255.0;
floatValues[i * 3] = Color.blue(val) / 255.0;

【讨论】:

  • 非常感谢您的回复。我已根据您的建议更改了代码,但结果仍然相同。我还根据您的建议编辑了我的问题。
  • @MithunSarkerShuvro 好吧,我不确定还有什么问题。我没有在 android 中使用过 TF,所以它返回 [1,0] 对我来说很奇怪,即两个值可能对应于具有 one 单位的 sigmoid 层输出的阈值和转换值。它似乎在内部进行了某种后处理,或者您可能已经以这种方式对其进行了配置。
  • 似乎我找到了一些东西,我只是用 255 来划分而不是 255.0 。现在我得到了一些不同的东西。对于猫图像,我得到了一些价值 [3.0000e,0],对于狗图像,我得到了 [4.000e,0]。我给出了完全不同的东西,我得到了类似 [1.0000e,0] 的东西,有什么逻辑吗,所以我可以说出我应该将哪只猫和哪只狗分类。仅供参考,我已经训练了我的模型,只是为了确定猫和狗。
  • @MithunSarkerShuvro 我不知道这些值对应什么。在正常情况下,例如在 python 中使用 Keras,sigmoid 返回范围 (0,1) 内的浮点值。所以我不知道如何将[3,0][4,0] 甚至[1,0] 解释为模型的输出,该模型具有一个sigmoid 层,其最后一层为一个单元。
猜你喜欢
  • 2019-04-27
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-20
  • 2018-04-15
  • 2017-06-05
相关资源
最近更新 更多