始终从TensorFlow Lite模型获得0预测值

3
我用以下代码训练并保存了一个模型。
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import tensorflow as tf
from tensorflow.python.keras.optimizer_v2.rmsprop import RMSprop

train_data_gen = ImageDataGenerator(rescale=1 / 255)
validation_data_gen = ImageDataGenerator(rescale=1 / 255)

# Flow training images in batches of 120 using train_data_gen generator
train_generator = train_data_gen.flow_from_directory(
    'datasets/train/',
    classes=['bad', 'good'],
    target_size=(200, 200),
    batch_size=120,
    class_mode='binary')

validation_generator = validation_data_gen.flow_from_directory(
    'datasets/valid/',
    classes=['bad', 'good'],
    target_size=(200, 200),
    batch_size=19,
    class_mode='binary',
    shuffle=False)

model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(16, (3, 3), activation='relu', input_shape=(200, 200, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),

    tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),

    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),

    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),

    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(),
    # 512 neuron hidden layer
    tf.keras.layers.Dense(512, activation='relu'),
    # Only 1 output neuron. It will contain a value from 0-1
    # where 0 for 1 class ('bad') and 1 for the other ('good')
    tf.keras.layers.Dense(1, activation='sigmoid')])

model.compile(loss='binary_crossentropy',
              optimizer=RMSprop(lr=0.001),
              metrics='accuracy')

model.fit(train_generator,
          steps_per_epoch=10,
          epochs=25,
          verbose=1,
          validation_data=validation_generator,
          validation_steps=8)

print("Evaluating the model :")
model.evaluate(validation_generator)

print("Predicting :")

validation_generator.reset()
predictions = model.predict(validation_generator, verbose=1)
print(predictions)

model.save("models/saved")

然后使用以下方法将此模型转换为tflite

import tensorflow as tf


def saved_model_to_tflite(model_path, quantize):
    converter = tf.lite.TFLiteConverter.from_saved_model(model_path)
    model_saving_path = "models/converted/model.tflite"
    if quantize:
        converter.optimizations = [tf.lite.Optimize.DEFAULT]
        model_saving_path = "models/converted/model-quantized.tflite"
    tflite_model = converter.convert()
    with open(model_saving_path, 'wb') as f:
        f.write(tflite_model)

然后使用单个图像对模型进行测试。

import tensorflow as tf


def run_tflite_model(tflite_file, test_image):

    interpreter = tf.lite.Interpreter(model_path=str(tflite_file))
    interpreter.allocate_tensors()
    print(interpreter.get_input_details())
    input_details = interpreter.get_input_details()[0]
    output_details = interpreter.get_output_details()[0]

    interpreter.set_tensor(input_details["index"], test_image)
    interpreter.invoke()
    output = interpreter.get_tensor(output_details["index"])[0]

    prediction = output.argmax()

    return prediction

main.py

if __name__ == '__main__':


    converted_model = "models/converted/model.tflite"
    bad_image_path = "datasets/experiment/bad/b.png"
    good_image_path = "datasets/experiment/good/g.png"
    img = io.imread(bad_image_path)
    resized = resize(img, (200, 200)).astype('float32')
    test_image = np.expand_dims(resized, axis=0)
    prediction = run_tflite_model(converted_model, test_image)
    print(prediction)

尽管我输入的图像不同,但模型始终给出预测值为0。这里出了什么问题?

在检查 TensorFlow Lite 模型的有效性之前,我建议先验证给定的 TF 模型是否正常工作。这将有助于发现根本原因。 - Jae sung Chung
我使用验证测试对其进行了测试,如您在代码中所见,该模型的准确率达到了90%以上。 - user158
@JaesungChung实际上这是我第二次看到:https://stackoverflow.com/questions/67058625/tensorflow-prediction-always-zero,在那里我始终得到0,似乎tflite转换过程存在问题? - user158
1个回答

2

在将图像传递给tflite模型之前,您忘记对其进行归一化处理。

resized = resize(img, (200, 200)).astype('float32')
resized = resized / 255.
test_image = np.expand_dims(resized, axis=0)
prediction = run_tflite_model(converted_model, test_image)

编辑:

你正在执行一个二元分类任务而不是多类别分类任务,所以你不需要在输出数组中取最大值,因为它只会产生一个处于0到1范围内的单一值。如果这个值大于或等于0.5,那么你可以将结果解释为正例,否则解释为负例。

import tensorflow as tf

def run_tflite_model(tflite_file, test_image):
    interpreter = tf.lite.Interpreter(model_path=str(tflite_file))
    interpreter.allocate_tensors()
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()
    interpreter.set_tensor(input_details[0]["index"], test_image)
    interpreter.invoke()
    predictions = interpreter.get_tensor(output_details[0]["index"])
    return 1 if predictions >= 0.5 else 0 # 1 = good, 0 = bad

尽管已经进行了更改,仍然得到0。 - user158
它对于好的情况是[0.54478854],对于坏的情况是[0.53851837]。 - user158
你正在执行二元分类而不是多类分类,因此在仅产生0到1范围内的单个值时,取最大值没有意义。我已更新答案以反映这一点。 - yudhiesh
抱歉伙计,现在我总是得到1,尽管图像很糟糕。 - user158
@user158,结果更与实际使用的模型以及训练和验证的结果相关。因此,我建议您另外提一个问题来讨论它。 - yudhiesh
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接