Python Keras CNN预测输出仅在一个数字范围内进行预测

Python Keras CNN预测输出仅在一个数字范围内进行预测,python,keras,deep-learning,regression,Python,Keras,Deep Learning,Regression,我正在尝试使用CNN根据3D医学大脑图像的评估分数进行预测,但是我收到的准确度分数在一个数字范围内(例如:有7个可能的测试分数:1、1.5、2、2.5、3、4、5,输出仅给出1-1.5范围内的预测) 我已经对图像进行了大小调整、标准化,并将其分为训练集(66个IMG)、测试集(22个IMG)和验证集(22个IMG)。由于图像太少,我添加了一个自定义的3D图像增强(来自github),因此图像总数增加到原来的10倍 我尝试过在我的网络中更改大多数(如果不是全部的话)参数(批量大小、优化器、学习率、

我正在尝试使用CNN根据3D医学大脑图像的评估分数进行预测,但是我收到的准确度分数在一个数字范围内(例如:有7个可能的测试分数:1、1.5、2、2.5、3、4、5,输出仅给出1-1.5范围内的预测)

我已经对图像进行了大小调整、标准化,并将其分为训练集(66个IMG)、测试集(22个IMG)和验证集(22个IMG)。由于图像太少,我添加了一个自定义的3D图像增强(来自github),因此图像总数增加到原来的10倍

我尝试过在我的网络中更改大多数(如果不是全部的话)参数(批量大小、优化器、学习率、简单/复杂的神经网络、激活、丢失等),但都无济于事。我也在网上寻找类似的问题,希望有人有同样的问题并解决了

下面是我正在使用的示例图像:

此图像的大小为(96,96,96),其数组值的条带为(在对其进行规格化后):

经过预处理步骤后,我将其输入CNN模型:

batch_size = 3

model = Sequential()

model.add(Conv3D(32, [3, 3, 3], padding='same', activation='relu',
                 input_shape=input_size))
model.add(Conv3D(32, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))

model.add(Conv3D(64, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(64, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))
model.add(Dropout(0.5))

model.add(Conv3D(128, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(128, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(128, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))

model.add(Conv3D(256, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(256, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(256, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))
model.add(Dropout(0.5))

model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation='linear'))

opt = optimizers.Adam(lr=1e-6)
model.compile(loss='mean_squared_logarithmic_error', optimizer=opt, metrics=['accuracy'])

train_datagen = customImageDataGenerator(shear_range=0.2,
                                         zoom_range=0.2,
                                         horizontal_flip=True)

val_datagen = customImageDataGenerator()

test_datagen = customImageDataGenerator()



training_set = train_datagen.flow(x_train, y_train, batch_size=batch_size, shuffle=True)

validation_set = val_datagen.flow(x_val, y_val, batch_size=batch_size, shuffle=False)

testing_set = test_datagen.flow(x_test, y_test, batch_size=batch_size, shuffle=False)



earlystop = EarlyStopping(monitor='val_loss', patience=30)

history = model.fit(
                    training_set,
                    steps_per_epoch = len(x_train)//batch_size,
                    epochs = 50,
                    #callbacks = [earlystop],
                    validation_data = validation_set,
                    validation_steps = len(x_val)//batch_size
                    )
我创建了一个自定义精度检查,以可视化输出:

Predicted score: [1.8405123] True score: 3.0
Predicted score: [1.4033222] True score: 3.0
Predicted score: [1.4690828] True score: 1.0
Predicted score: [1.5127727] True score: 3.0
Predicted score: [1.6159409] True score: 1.0
Predicted score: [1.4333361] True score: 1.5
Predicted score: [1.7470968] True score: 3.0
Predicted score: [1.2196972] True score: 1.5
Predicted score: [1.5940914] True score: 4.0
Predicted score: [1.4052064] True score: 1.0
Predicted score: [1.5127727] True score: 1.0
Predicted score: [1.4584785] True score: 1.0
Predicted score: [1.7860543] True score: 3.0
Predicted score: [1.4752649] True score: 2.5
Predicted score: [1.8568267] True score: 1.0
Predicted score: [1.4793051] True score: 3.0
Predicted score: [1.395096] True score: 2.5
Predicted score: [1.6011616] True score: 4.0
Predicted score: [1.9094267] True score: 1.0
Predicted score: [1.6322718] True score: 1.0
Predicted score: [1.7284409] True score: 4.0
Predicted score: [1.5262214] True score: 1.5
Out: 0.09090909090909091
如您所见,预测值在1-2范围内,即使测试分数在2.5、3、4和5范围内

print(y_pred.min(), y_pred.max())
1.2196972 1.9094267
最后,以下是我的图表:

正如你所看到的,损失减少得很漂亮,但是准确度在中途冻结了,我不确定原因可能是什么


很抱歉发了这么长的帖子,但如果有任何答案,我将不胜感激,谢谢

有几件事可能有助于提高模型的准确性

  • 在每个Conv3D层后添加BatchNomalization,提高了收敛性
  • 尝试将分数调整到一个范围[0,1]。当您有足够的数据时,这通常不是问题,但如果您的数据集很小,则可能会成为问题。这还需要在最后一层中激活
    softmax
  • 0.5的下降可能有点极端。试着在每次Conv3D之后添加一个较小的退出。可以使用以下包装器方便地将其与命题1)组合:

  • 希望这至少有助于改进一点。

    Ahh,感谢您的回复!对于#2,由于分数是从1到5,我是否应该将它们全部除以5以将它们标为[0,1]?对于#3,包装器到底是什么?它如何比我的格式更好?对不起,我对深度学习还不太熟悉,也没有那么渊博。也许你可以给我一些资源,因为我自己找不到。谢谢你的第一个问题,最好是-1,然后是/4,所以它严格地介于0和1之间。包装器只会让东西变短。这是一件好事,因为您可以使用它实现更复杂的块,例如跳过连接。查看tensorflow指南。另外,尝试更高的学习率,从
    1e-3
    开始,因为
    1e-6
    似乎太小。您好,我已经尝试了您提出的建议,但它们无法解决问题。添加batchnormalization增加了输出范围,但损失值停滞不前。较高的学习率给出了-500的不准确输出值。由于输出仍然在特定范围内,而不是在整个范围内,因此对分数进行缩放并没有多大改善。辍学率的下降使我的图表有点过拟合。我没有尝试过包装器技术,因为我觉得学习和实现它需要相当长的时间,而没有一定程度的工作保证,我也遇到了同样的问题。你解决问题了吗?
    print(y_pred.min(), y_pred.max())
    1.2196972 1.9094267
    
    import tensorflow as tf
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Layer, Conv3D, BatchNormalization, Dropout, InputLayer
    
    
    class ConvBlock(Layer):
      def __init__(self, filters=32, kernel_size = [3, 3, 3], 
                   padding='same', activation='relu', dropout=0.1):
        super(ConvBlock, self).__init__()
        self.conv = Conv3D(filters=filters, 
                           kernel_size=kernel_size, 
                           activation=activation, 
                           padding=padding)
        self.norm = BatchNormalization()
        self.dropout = Dropout(dropout)
    
      def call(self, input, training=False):
        x = self.conv(input)
        x = self.norm(x)
        x = self.dropout(x, training=training)
        return x
      
      
    model = Sequential()
    
    model.add(InputLayer((96, 96, 96, 1)))
    model.add(ConvBlock())
    
    model.summary()