【问题标题】:How to interpret results returned by model.predict?如何解释 model.predict 返回的结果?
【发布时间】:2020-05-02 09:05:54
【问题描述】:

我正在尝试制作一个可以识别图片中是否有猫的神经网络。我在 tensorflow 网站上找到了this tutorial,并试图使其适应我的问题。本教程是对猫和狗进行分类,但由于我只想检测猫,所以我将类别更改为猫和非猫。

对于非猫,我下载了一个随机图像数据集。

我在教程中的代码中添加了两个生成器:

test_data_gen = test_image_generator.flow_from_directory(batch_size=batch_size,
                                                               directory=test_dir,
                                                               target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                               class_mode='binary')

pred_data_gen = pred_image_generator.flow_from_directory(batch_size=batch_size,
                                                                 directory=pred_dir,
                                                                 target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                                 class_mode='binary')

然后像这样测试模型:

print('\n# Evaluate on test data')
results = model.evaluate_generator(test_data_gen)
print('test loss, test acc:', results)

print('\n# Generate predictions')
predictions = model.predict(pred_data_gen)
print(len(predictions))
print(predictions)

这是输出:

# Evaluate on test data
test loss, test acc: [0.45212748232815003, 0.9324082]
# Generate predictions for custom samples
256
[[ -8.023465  ]
 [ -7.781438  ]
 [ 50.281197  ]
 [-10.172492  ]
 [ -5.1096087 ]
 [ 43.0299    ]
 [ 21.416649  ]
 ...
 [-10.866359  ]
 [-14.797473  ]
 [ 84.72212   ]
 [ 23.712345  ]
 [ -6.4916744 ]
 [-18.384903  ]
 [ 33.10642   ]]

测试准确率很高,但我不知道这些结果意味着什么。我认为它们应该在 0 和 1 之间,但它们甚至有负值。我应该如何解释这些结果?

编辑:

这是我的模型(在最后一层添加 sigmoid 激活函数之前):

model = Sequential([
    Conv2D(16, 3, padding='same', activation='relu', input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
    MaxPooling2D(),
    Conv2D(32, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Conv2D(64, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Flatten(),
    Dense(512, activation='relu'),
    Dense(1)
])

我把最后一层改成Dense(1, activation='sigmoid'),输出如下:

# Evaluate on test data
test loss, test acc: [0.714477022488912, 0.5949367]

# Generate predictions for custom samples
256
[[1.]
 [1.]
 [1.]
 ...
 [1.]
 [1.]
 [1.]]

所有预测值都是 1,即使测试集中只有一半的图像是猫。

EDIT2:

这是我编译和拟合模型的方法:

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

model.summary()

history = model.fit_generator(
    train_data_gen,
    steps_per_epoch=total_train // batch_size,
    epochs=epochs,
    validation_data=val_data_gen,
    validation_steps=total_val // batch_size
)

【问题讨论】:

  • 尝试在最后一层应用 Dense(1, activation='sigmoid')
  • 请分享您的型号代码
  • @CodePope 已编辑帖子。
  • 你能粘贴完整的代码,尤其是你编译和适合的位吗?
  • @LukaszTracewski 添加了更多代码。

标签: python python-3.x tensorflow machine-learning keras


【解决方案1】:

您模型中的最后一层是具有单个神经元的Dense 层。由于没有向它传递任何参数,因此默认情况下它具有线性激活。用户@Code Pope 表示这是一个“失败”(Tensorflow 文档中的错误?)。不是,代码非常好。

您的损失函数计算二元交叉熵,它可以轻松地与线性激活一起使用。事实上,计算 sigmoid 只是一点额外的,不需要。 ANN 将为一个类输出负值,为另一类输出正值。它们没有标准化,而是所谓的logits - 这就是你在损失函数中说from_logits=True的原因。

如何获得预测:

from sklearn.metrics import accuracy_score

images, actual = next(train_data_gen)
predictions = model.predict(images)
predictions = (predictions > 0).flatten()
accuracy_score(results, pred)

【讨论】:

    【解决方案2】:

    您需要使用 sigmoid 函数将输出缩放到 [0, 1]

    https://www.tensorflow.org/api_docs/python/tf/math/sigmoid

    【讨论】:

    • 谢谢!我改了最后一层Dense(1, activation='sigmoid'),现在所有的预测值都是1.。知道我可能做错了什么吗?
    • 如果你改变最后一层 Dense(1, activation='sigmoid') 来预测它很好,但是当你再次训练一个新的时你必须小心,因为这条线 tf.keras.losses.BinaryCrossentropy(from_logits =True),这意味着您从 Dense(activation=None) 计算损失,您必须将其更改为 False。但是,我不建议将这种方法用于高级 ML 项目,因为在计算损失之前应用 sigmoid 会损失一些重要的数字。
    【解决方案3】:

    在您链接的示例中(here,有故障。在最后一个Dense 层中,必须有一个 sigmoid 函数的值介于 0 和 1 之间。原始示例来自书 @987654324 @来自 Francois Chollet,示例来自第 5.2 章。示例可在 github 上获得,我建议您使用它:here。 我已经使用了该示例,并且效果很好。您编辑的模型看起来不错,但我不确定您是否为图像创建了正确的文件夹结构,因此也为您的ImageDataGenerator 创建了正确的文件夹结构。我已经训练了模型,然后加载了一个图像来预测:

    from keras.preprocessing import image
    from keras.applications.vgg16 import preprocess_input, decode_predictions
    import numpy as np
    img_path = '/Users/CodePope/Downloads/catsdogs/cats_and_dogs_smalla/test/dogs/dog.1500.jpg'
    img = image.load_img(img_path, target_size=(150,150))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x /=255.
    model.predict(x)
    

    结果如下:

    array([[0.8290838]], dtype=float32)
    

    看起来不错,因为 0 代表猫,1 代表狗。 对于猫图像,我们有:

    from keras.preprocessing import image
    from keras.applications.vgg16 import preprocess_input, decode_predictions
    import numpy as np
    img_path = '/Users/CodePope/Downloads/catsdogs/cats_and_dogs_smalla/test/cats/cat.1500.jpg'
    img = image.load_img(img_path, target_size=(150,150))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x /=255.
    model.predict(x)
    

    结果:

    array([[0.15701984]], dtype=float32)
    

    尽管我刚刚对模型进行了五个 epoch 的训练,验证准确度为 0.67。

    【讨论】:

    • 我检查并正确加载了图像。 @Thananchai 写的怎么样?我应该将tf.keras.losses.BinaryCrossentropy(from_logits=True) 更改为tf.keras.losses.BinaryCrossentropy(from_logits=False) 吗?
    • @WojtekWencel 如果使用 sigmoid 激活函数,则无需将 from_logits 设置为 True
    • 这不是真的,最后一层不必有“sigmoid”。线性激活效果很好,你只需要知道如何解释最后一层(然后就是一个分数)。
    • @Tracewski,标准化你的图像然后有一个线性输出函数在间隔(-infinity,infinity)中输出是没有意义的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 2014-07-10
    • 2017-05-02
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多