【问题标题】:How do I get probability/confidence as output for a CNN using keras in python?如何在 python 中使用 keras 获得概率/置信度作为 CNN 的输出?
【发布时间】:2019-02-04 10:00:30
【问题描述】:

所以,我是深度学习的新手,我开始使用 Keras 的 CNN 模型的猫和狗数据集。

在我的代码中,我无法将概率作为classifier.predictclassifier.predict_proba 的输出。我只是得到[[0,1]][[1,0]] 的输出。我尝试了几张图片。

但我正在寻找类似 @​​987654326@、[[0.89,0.11]] 的东西

我尝试将损失函数从 binary_crossentropy 更改为 categorical_crossentropy

我尝试将输出层的激活函数从sigmoid 更改为softmax

我还尝试将flow_from_directory 中的class_modebinary 更改为categorical

我想我的数据类型可能有问题,因为输出数组的类型是 float32。但即使这是错误,我也不知道如何改变它。

我找不到哪里出错了。请澄清/帮助。谢谢。

为什么我需要概率?

在我的另一个项目中,我会将图像拆分为“n”个较小的部分。然后,我将分别对“n”个片段使用分类器,并找到概率最大的一个片段。为此,我不会使用猫和狗的数据集。它用于 bin-picking,该数据集也将二进制输出为“YES”或“NO”。也欢迎对此提出任何建议。谢谢。

Link 获取 Github 中的代码。

    #Building the CNN
    
    from keras.models import Sequential
    from keras.layers import Convolution2D
    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(Convolution2D(filters=32,kernel_size=[3,3],input_shape=(64,64,3),activation='relu'))
    
    #Step 2 - Pooling
    classifier.add(MaxPooling2D(pool_size=(2,2),strides=2))
    
    #Adding another Convolutional Layer for better accuracy
    #classifier.add(Convolution2D(filters=32,kernel_size=[3,3],activation='relu'))
    #classifier.add(MaxPooling2D(pool_size=(2,2),strides=2))
    
    #Step 3 - Flattening
    classifier.add(Flatten()) 
    
    #Step 4 - Fully Connected Layers
    classifier.add(Dense(units= 64, activation='relu'))
    classifier.add(Dense(units= 2, activation='softmax'))
    
    
    #Compiling the CNN
    classifier.compile(optimizer='adam',loss = 'categorical_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='categorical')
    
    test_set = test_datagen.flow_from_directory('dataset/test_set',
                                                target_size=(64,64),
                                                batch_size=32,
                                                class_mode='categorical')
    
    classifier.fit_generator(training_set,
                        steps_per_epoch=250,
                        epochs=3,                       #Just for time being I've kept very few epochs.
                        validation_data=test_set,
                        validation_steps=62)
    
    
    #Making new Predictions
    import numpy as np
    from keras.preprocessing import image
    
    test_image_luna=image.load_img('dataset/single/SkilletLuna.JPG',target_size=(64,64))
    test_image2=image.img_to_array(test_image_luna)
    test_image2=np.expand_dims(test_image2,axis=0)
    luna=classifier.predict_proba(test_image2)

In [11]: luna
    ...: 
Out[11]: array([[0., 1.]], dtype=float32)

【问题讨论】:

  • 您检查过预测的准确性吗? NN 至少学到了什么吗?
  • 是的,它确实学会了。它在 1 个 epoch 内有 50% 的准确率。 25 个 epoch 的准确率达到 80%。它分类没有问题,唯一的事情是它应该给我一些至少一些图像的十进制值(当我使用classifer.predict时)并且它没有,这让我很困扰。 @markuscosinus

标签: python tensorflow keras neural-network conv-neural-network


【解决方案1】:

我想我发现了错误。您正在使用 ImageDataGenerator 重新调整您的训练和测试数据。但是在测试单个图像时您并没有这样做。 试试这个:

# Making new Predictions
import numpy as np
from keras.preprocessing import image

test_image_luna = image.load_img('D:\\NR\\data\\live2013\\caps.bmp', target_size=(64,64))
test_image2 = image.img_to_array(test_image_luna)/255.
test_image2 = np.expand_dims(test_image2, axis=0)
luna = classifier.predict_proba(test_image2)

高输入值导致非常高的输出值。由于您使用的是 softmax 激活,因此这些值会导致非常接近 0 和 1 的预测。

【讨论】:

    【解决方案2】:

    我正在寻找类似 [[0.4,0.6]]、[[0.89,0.11]]

    classifier.predict 是您应该用来获取概率的方法。考虑以下提示,您能否再次检查?

    构建二元分类器有两种方式:

    1. 具有一个输出神经元sigmoid激活的NN。输出 a 被解释为第 1 类的概率,因此第 2 类的概率为 1-a
    2. 具有两个输出神经元的NN使用softmax激活。然后将每个神经元解释为一个类别的概率。

    两者都是有效的选项,但既然你在做 2. 你应该使用 softmax 激活。

    我尝试将损失函数从 binary_crossentropy 更改为 categorical_crossentropy。

    这应该没什么区别,基本上是一样的公式。

    我认为我的数据类型可能有问题,因为 输出数组是 float32。但即使那是错误,我也不会 知道如何改变它。

    这也不是错误的原因,因为类型 float32 适合概率输出。

    【讨论】:

    • 是的,我同意分类器.predict 应该给出一个概率,但不知何故,它使用上面的代码将自身四舍五入为 0 或 1。另外,我尝试将 1 个输出神经元用于 sigmoid,2 个用于 softmax,两者的结果都是 0 或 1 的舍入输出。我认为分类器没有那么自信。此外,为了解决这个问题,我什至尝试运行更少的时期(如 1 或 3)来获得小数的概率,但它只给出 0 或 1。
    【解决方案3】:

    predict() 或 predict_generator() 都可以。

    import numpy as np
    from keras.preprocessing import image
    
    test_image_luna=image.load_img('dataset/single/SkilletLuna.JPG',target_size=(64,64))
    test_image2=image.img_to_array(test_image_luna)
    test_image2=np.expand_dims(test_image2,axis=0)
    luna=classifier.predict(test_image2)
    
    print(luna)
    

    如果您想要“n”个图像(或您的情况下的“n”个图像子集)的预测概率,您可以尝试 predict_generator():

    from keras.preprocessing.image import ImageDataGenerator
    
    test_datagen=ImageDataGenerator(rescale=1./255)
    test_set = test_datagen.flow_from_directory('dataset/test_set',
                                                 target_size=(64,64),
                                                 batch_size=32,
                                                 class_mode='categorical')
    
    predicted_probabilities = classifier.predict_generator(test_set)
    print(predicted_probabilities)
    

    使用以下以四舍五入到小数点后 2 位的百分比打印:

    print(np.round(luna*100,2))
    print(np.round(predicted_probabilities*100,2))
    

    让我知道这是否适合你!

    【讨论】:

    • 感谢 predict_generator 同时预测 n 个图像。是的,我同意 classifier.predict 应该可以工作,但不知何故,它使用上面的代码将自身四舍五入为 0 或 1。另外,我尝试将 1 个输出神经元用于 sigmoid,2 个用于 softmax,两者的结果都是 0 或 1 的舍入输出。我认为分类器没有那么自信。此外,为了解决这个问题,我什至尝试运行更少的时期(如 1 或 3)来获得小数的概率,但它只给出 0 或 1。
    • 您可以在代码顶部包含以下内容:np.set_printoptions(precision=3, suppress=False)。我认为这是一个数组格式问题。 Softmax 函数和 epoch 看起来不错!
    • 是的,这是一个数组格式问题,我没有重新调整单个测试数据的数组。
    • @Snitch30 你是怎么解决这个问题的?我也面临同样的问题。
    猜你喜欢
    • 2023-04-05
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 2021-03-04
    • 2018-06-21
    • 1970-01-01
    相关资源
    最近更新 更多