【问题标题】:TensorFlow Binary Image Classification: Predict Probability of each class for each image in data setTensorFlow 二值图像分类:预测数据集中每个图像的每个类别的概率
【发布时间】:2020-11-17 02:57:45
【问题描述】:

我正在构建一个用于二值图像分类的 TensorFlow 模型。我有两个标签“好”和“坏” 我希望模型应该为数据集中的每个图像输出,该图像是好是坏以及概率是多少

例如,如果我提交 1.jpg 并假设它是“好”图像。那么模型应该以 100% 的概率预测 1.jpg 为好,以 0% 的概率预测为坏。

到目前为止,我已经能够想出以下内容

model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(input_shape, input_shape, 3)),
  tf.keras.layers.MaxPool2D(2,2),
  #
  tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
  tf.keras.layers.MaxPool2D(2,2),
  #
  tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
  tf.keras.layers.MaxPool2D(2,2),
  ##
  tf.keras.layers.Flatten(),
  ##
  tf.keras.layers.Dense(512, activation='relu'),
  ##
  tf.keras.layers.Dense(1, activation='sigmoid')
])

上述模型的输出形状是 1 x 1。但我认为这不符合我的目的。

我是这样编译模型的

 model.compile(loss='binary_crossentropy',
          optimizer=RMSprop(lr=0.001),
          metrics=['accuracy'])
 model_fit = model.fit(train_dataset,
                  steps_per_epoch=3,
                  epochs=30,
                  validation_data=validation_dataset)

非常感谢任何帮助。

【问题讨论】:

  • 你是如何编译模型的?
  • 我投票结束这个问题,因为它不是一个问题。

标签: python tensorflow image-processing classification


【解决方案1】:

如果有人正在寻找答案,下面是用于模型生成的 python 代码

这里需要注意的一些点是

  1. 输入图像形状为 360x360x3
  2. 最后一层的激活函数是“softmax”而不是“sigmoid
  3. 损失函数是“sparse_categorical_crossentropy”而不是“binary_crossentropy
  4. 输出的形状是 2 而不是 1

请注意 #2、#3 和 #4,即使我正在尝试提出一个用于二值图像分类的模型。我的最终目标是将此模型转换为 TensorFlow Lite 版本并在 Android 应用程序中使用 TensorFlow Lite 模型。

之前,当我使用“sigmoid”作为最后一层并使用“binary_crossentropy”作为损失函数时,最后一层的输出形状不能大于 1。

因此,当我在 Android 应用程序中使用从该 TensorFlow 模型生成的 Lite 模型时,我遇到了下面提到的错误

"找不到要标注的轴。要标注的有效轴应具有大小 大于 1"

通过 #2、#3 和 #4 中提到的更改,生成的 Lite 模型在 Android 中运行良好。

import tensorflow as tf
import matplotlib.pyplot as plt
import cv2
import os
import numpy as np
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing import image
from tensorflow.keras.optimizers import RMSprop


print("version")
print(tf.__version__)

train = ImageDataGenerator(rescale=1/255)
validation = ImageDataGenerator(rescale=1/255)

input_shape = 360
train_dataset = train.flow_from_directory('container_images/train/',
                                          target_size=(input_shape,input_shape),
                                          batch_size=3,
                                          classes=['good', 'bad'],
                                          class_mode='binary')

validation_dataset = train.flow_from_directory('container_images/validation/',
                                          target_size=(input_shape,input_shape),
                                          batch_size=3,
                                          classes=['good', 'bad'],
                                          class_mode='binary')

print(train_dataset.class_indices)
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(input_shape, input_shape, 3)),
    tf.keras.layers.MaxPool2D(2,2),
    #
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
    tf.keras.layers.MaxPool2D(2,2),
    #
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPool2D(2,2),
    ##
    tf.keras.layers.Flatten(),
    ##
    tf.keras.layers.Dense(512, activation='relu'),
    ##
    tf.keras.layers.Dense(2, activation='softmax')
])

model.compile(loss='sparse_categorical_crossentropy',
              optimizer=RMSprop(lr=0.001),
              metrics=['accuracy'])
model_fit = model.fit(train_dataset,
                      steps_per_epoch=3,
                      epochs=30,
                      validation_data=validation_dataset)

【讨论】:

    【解决方案2】:

    您不必让模型输出“好”和“坏”作为标签,相反,您可以分别输出每个标签的概率,换句话说,图像好的概率和形象不好。将最后一层的输出大小设为 2。因此,您的模型现在将输出一个二维向量,其中 [1.0, 0.0] 表示 100% 好,0% 坏,[0.0, 1.0] 表示 0% 好和100%的坏。使用二元交叉熵作为训练的损失函数。当然,您必须对训练数据进行类似的标记,因此如果您有一个好的训练示例,请将其标记为 [1.0, 0.0],因为您 100% 确定它是好的,如果您有一个不好的训练示例,请将其标记为[0.0, 1.0] 因为您也 100% 确定这是一个坏例子。

    我告诉你使用二元交叉熵作为损失函数的原因是,模型将学习输出二维向量输出分量的相反概率。因此,如果它是一个好图像,第一个分量会很高,而第二个分量会很低,反之亦然,如果它是一个坏图像。另外,经过训练,在进行预测时,您只取两者中最高的概率,如果较高的概率是第一个,那么它是一个“好”的图像,你只使用那个概率。

    【讨论】:

    • 我将最后一层的形状更改为 2 tf.keras.layers.Dense(2, activation='sigmoid') 但现在运行 python 程序时出现错误。 ValueError: logits 和 labels 必须具有相同的形状 ((None, 2) vs (None, 1))
    • 您使用的 tensorflow 版本是什么?我使用的是 2.2.0 版本,您的代码在将最后一层的大小更改为 2 后可以工作。
    • 感谢您的帮助。我做了一些更改以使其正常工作。我将损失函数更改为“sparse_categorical_crossentropy”,将最后一层的激活函数更改为“softmax”而不是“sigmoid”,并且按照建议,我将最后一个函数的输出大小更改为 2。
    猜你喜欢
    • 2018-04-19
    • 2020-05-22
    • 2019-11-14
    • 2020-04-03
    • 2020-07-11
    • 2016-10-01
    • 2020-03-05
    • 1970-01-01
    • 2019-08-05
    相关资源
    最近更新 更多