【问题标题】:Keras model.predict only returns one figure for binary classification taskKeras model.predict 对于二元分类任务只返回一个数字
【发布时间】:2021-07-28 00:04:37
【问题描述】:

我已经按照这条指令“https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html”用 Keras 训练了一个二元分类任务。

但是,model.predict 只返回一个数字,例如 [[0.6343]]。 我认为它应该返回两个数字,例如 [[0.6343, 0.1245]],其中每个数字代表每个类别的概率。

我正在使用 2.2.4 版的 Keras 和 1.13.1 版的 Tensorflow。

这是我的代码。

from keras.models import Sequential
from keras.layers import Activation, Dense, Dropout, Flatten, Conv2D, MaxPooling2D
from keras.utils import np_utils
from sklearn.datasets import fetch_mldata
from keras.datasets import mnist
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import tensorflowjs as tfjs


##############
# Train model
##############

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=(96, 128, 3), data_format="channels_last"))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(128, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])


################################
# Read image data from directory
################################

batch_size = 16

# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    rescale=1./255,
    shear_range=0.2,
    fill_mode='wrap',
    zoom_range=0.2,
    horizontal_flip=True,
    vertical_flip=True
)

# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1./255)

# this is a generator that will read pictures found in
# subfolers of 'data/train', and indefinitely generate
# batches of augmented image data
train_generator = train_datagen.flow_from_directory(
        'dataset/train',  # this is the target directory
        target_size=(96, 128),  # all images will be resized to 150x150
        batch_size=batch_size,
        class_mode='binary')  # since we use binary_crossentropy loss, we need binary labels

# this is a similar generator, for validation data
validation_generator = test_datagen.flow_from_directory(
        'dataset/validation',
        target_size=(96, 128),
        batch_size=batch_size,
        class_mode='binary')


##############
# Fit model
##############

model.fit_generator(
        train_generator,
        steps_per_epoch=2000 // batch_size,
        epochs=30,
        validation_data=validation_generator,
        validation_steps=800 // batch_size)
model.save('model.h5')  # always save your weights after training or during training
tfjs.converters.save_keras_model(model, './')


##############
# Predict class
##############

img = load_img('./dataset/validation/dog/image001.png')

if (img.size == (96, 128)):
    img = img.rotate(90, expand=True)

x = img_to_array(img)  # this is a Numpy array with shape (3, 150, 150)
x = x / 255
x = x.reshape((1,) + x.shape)  # this is a Numpy array with shape (1, 3, 150, 150)

model.predict(x, batch_size=None, verbose=0, steps=None)

我应该如何修复代码以生成我期望的结果(两个数字)?

【问题讨论】:

  • 对于二元交叉熵损失,只有一个概率输出,因为另一个概率只是1-p,所以不需要同时输出两个概率。
  • 您在具有 1 个节点的输出层上使用 sigmoid。这意味着您将获得单个输出值(可能是某个类存在的可能性),并且可以很好地作为逻辑回归函数进行二元分类。但是,如果您正在寻找概率分布,那么您需要在输出层上使用 2 个节点和 softmax 激活函数。这将为每个预测提供 2 个输出,其中包含两个类别的概率分数。

标签: python tensorflow keras deep-learning


【解决方案1】:

感谢 Matias 和 amityadav,我解决了这个问题。 我不得不做出以下改变。

  1. 使用“categorical_crossentropy”损失
  2. 使用“softmax”进行最终激活
  3. 将“2”赋给最终的 Dense 函数
  4. 对 flow_from_directory 的 class_mode 使用“分类”

我的最终代码如下所示

from keras.models import Sequential
from keras.layers import Activation, Dense, Dropout, Flatten, Conv2D, MaxPooling2D
from keras.utils import np_utils
from sklearn.datasets import fetch_mldata
from keras.datasets import mnist
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import tensorflowjs as tfjs


##############
# Train model
##############

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=(96, 128, 3), data_format="channels_last"))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(128, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Dense(2))
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])


################################
# Read image data from directory
################################

batch_size = 16

# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    rescale=1./255,
    shear_range=0.2,
    fill_mode='wrap',
    zoom_range=0.2,
    horizontal_flip=True,
    vertical_flip=True
)

# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1./255)

# this is a generator that will read pictures found in
# subfolers of 'data/train', and indefinitely generate
# batches of augmented image data
train_generator = train_datagen.flow_from_directory(
        'dataset/train',  # this is the target directory
        target_size=(96, 128),  # all images will be resized to 150x150
        batch_size=batch_size,
        class_mode='categorical')  # since we use binary_crossentropy loss, we need binary labels

# this is a similar generator, for validation data
validation_generator = test_datagen.flow_from_directory(
        'dataset/validation',
        target_size=(96, 128),
        batch_size=batch_size,
        class_mode='categorical')


##############
# Fit model
##############

model.fit_generator(
        train_generator,
        steps_per_epoch=2000 // batch_size,
        epochs=30,
        validation_data=validation_generator,
        validation_steps=800 // batch_size)
model.save('model.h5')  # always save your weights after training or during training
tfjs.converters.save_keras_model(model, './')


##############
# Predict class
##############

img = load_img('./dataset/validation/dog/image001.png')

if (img.size == (96, 128)):
    img = img.rotate(90, expand=True)

x = img_to_array(img)  # this is a Numpy array with shape (3, 150, 150)
x = x / 255
x = x.reshape((1,) + x.shape)  # this is a Numpy array with shape (1, 3, 150, 150)

model.predict(x, batch_size=None, verbose=0, steps=None)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-15
    • 2019-12-08
    • 1970-01-01
    • 2019-09-12
    • 2018-09-04
    • 1970-01-01
    相关资源
    最近更新 更多