我想将CNN模型的具体预测更改为概率

时间:2020-11-07 17:24:38

标签: python tensorflow keras deep-learning neural-network

我训练了一个模型来将图片分类为两种不同的类型。一切正常 很好,但是我的模型只能进行特定的预测(在我的情况下为1或0),但是我很想拥有一个更像概率的预测(例如90%1和10%0)。 我现在应该更改的代码部分在哪里?到底是S型函数决定了它的1还是0?帮助会很好。预先感谢。

import numpy as np
from keras.callbacks import TensorBoard
from keras import regularizers
from keras.models import Sequential
from keras.layers import Activation, Dropout, Flatten, Dense, Conv2D, MaxPooling2D
from keras.optimizers import Adam
from keras.metrics import categorical_crossentropy
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
from keras.layers.normalization import BatchNormalization

from utils import DataGenerator, PATH

train_path = 'Dataset/train'
valid_path = 'Dataset/valid'
test_path = 'Dataset/test'

model = Sequential()
model.add(Conv2D(16, (3, 3), input_shape=(640, 640, 1), padding='same', activation='relu',
                 kernel_regularizer=regularizers.l2(1e-4),
                 bias_regularizer=regularizers.l2(1e-4)))
model.add(MaxPooling2D(pool_size=(4, 4)))

model.add(Conv2D(32, (3, 3), activation='relu',
                 kernel_regularizer=regularizers.l2(1e-4),
                 bias_regularizer=regularizers.l2(1e-4)))
model.add(MaxPooling2D(pool_size=(5, 5)))

model.add(Conv2D(64, (3, 3), activation='relu',
                 kernel_regularizer=regularizers.l2(1e-4),
                 bias_regularizer=regularizers.l2(1e-4)))
model.add(MaxPooling2D(pool_size=(6, 6)))

model.add(Flatten())
model.add(Dense(64, activation='relu',
                kernel_regularizer=regularizers.l2(1e-4),
                bias_regularizer=regularizers.l2(1e-4)))
model.add(Dropout(0.3))
model.add(Dense(1, activation='sigmoid',
                kernel_regularizer=regularizers.l2(1e-4),
                bias_regularizer=regularizers.l2(1e-4)))
print(model.summary())

model.compile(loss='binary_crossentropy', optimizer=Adam(lr=1e-3), metrics=['accuracy'])

epochs = 50
batch_size = 16

datagen = DataGenerator()
datagen.load_data()

model.fit_generator(datagen.flow(batch_size=batch_size), epochs=epochs, validation_data=datagen.get_validation_data(),
                    callbacks=[TensorBoard(log_dir=PATH+'/tensorboard')])

#model.save_weights('first_try.h5')
model.save('second_try')

如果我尝试在模型中获得这样的图片:

path = 'train/clean/picturenumber2'  
def prepare(filepath):   
  IMG_SIZE = 640    
  img_array = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE)    
  new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))   
  return new_array.reshape(-1, IMG_SIZE, IMG_SIZE, 1) 

model = tf.keras.models.load_model('second_try') 
prediction = model.predict(prepare(path))
print(prediction)

我只得到这样的输出:[[1.]]另外,如果我将其放入包含多张图片的列表中。该预测本身似乎是有效的。

1 个答案:

答案 0 :(得分:2)

简短答案: 将最后一层的 Sigmoid 激活功能更改为 softmax

为什么?

因为S形输出范围是0.0到1.0,所以要对此输出进行有意义的解释,请选择一个适当的阈值,在该阈值之上代表正类别,而在其下方则代表负类别。(对于二进制分类问题)

即使softmax具有相同的输出范围,但不同之处在于它的输出在该here上具有更多的归一化类概率,因此,如果您的模型在任何给定的输入上输出0.99,则可以可以解释为该模型具有99.0%的信心为正类,而0.1%的信心为负类。

更新: 正如@amin所建议的那样,如果您需要归一化的概率,则应该进行更多的更改以使其起作用。

  1. 修改数据生成器以输出2个类/标签,而不是一个。

  2. 将最后一个密集层从1个节点更改为2个节点。