99% 的验证准确率但 0% 的预测结果(UNET 架构)

数据挖掘 神经网络 训练 预言 准确性
2021-10-11 23:41:13

我正在调试用于识别眼睛图像中角膜反射的 UNET 架构的结果。虽然我获得了超过 99% 的训练准确度和非常高(超过 99%)的验证准确度,但当我自己运行验证图像时,我从模型预测中得到的只是空白图像。当我使用具有完全相同参数的相同架构进行训练时,我会再次获得高精度数字,但在预测中再次运行验证集会产生很好的结果。这是我遇到问题、验证和预测结果不匹配的数据集的示例输出:


Train on 326 samples, validate on 140 samples
Epoch 1/1
277s - loss: 0.1961 - dice_coef: 0.0012 - acc: 0.9834 - val_loss: 0.0338 - val_dice_coef: 4.8418e-11 - val_acc: 0.9979
326/326 [==============================] - 79s     

这是我的代码:

#-------------------------------------------------------
# Define UNET model
#-------------------------------------------------------
print("Compiling UNET Model.....")

def dice_coef(y_true, y_pred):
    y_true_f = K.flatten(y_true)
    y_pred_f = K.flatten(y_pred)
    intersection = K.sum(y_true_f * y_pred_f)
    coef = (2. * intersection + K.epsilon()) / (K.sum(y_true_f) + K.sum(y_pred_f) + K.epsilon())
    return coef

x_data = x_data[:,:,:,np.newaxis]
y_data = y_data[:,:,:,np.newaxis]
x_train, x_val, y_train, y_val = train_test_split(x_data, y_data, test_size = 0.3)

input_layer = Input(shape=x_train.shape[1:])
c1 = Conv2D(filters=8, kernel_size=(3,3), activation='relu', padding='same')(input_layer)

l = MaxPool2D(strides=(2,2))(c1)
c2 = Conv2D(filters=16, kernel_size=(3,3), activation='relu', padding='same')(l)

l = MaxPool2D(strides=(2,2))(c2)
c3 = Conv2D(filters=32, kernel_size=(3,3), activation='relu', padding='same')(l)

l = MaxPool2D(strides=(2,2))(c3)
c4 = Conv2D(filters=32, kernel_size=(1,1), activation='relu', padding='same')(l)

l = concatenate([UpSampling2D(size=(2,2))(c4), c3], axis=-1)
l = Conv2D(filters=32, kernel_size=(2,2), activation='relu', padding='same')(l)

l = concatenate([UpSampling2D(size=(2,2))(l), c2], axis=-1)
l = Conv2D(filters=24, kernel_size=(2,2), activation='relu', padding='same')(l)

l = concatenate([UpSampling2D(size=(2,2))(l), c1], axis=-1)
l = Conv2D(filters=16, kernel_size=(2,2), activation='relu', padding='same')(l)

l = Conv2D(filters=64, kernel_size=(1,1), activation='relu')(l)
l = Dropout(0.5)(l)

output_layer = Conv2D(filters=1, kernel_size=(1,1), activation='sigmoid')(l)

model = Model(input_layer, output_layer)

model.compile(optimizer=Adam(1e-4), loss='binary_crossentropy', metrics=[dice_coef, 'acc'])


#-------------------------------------------------------
# Train UNET MOdel
#-------------------------------------------------------
if train_opt:
    print("Training UNET Model.....")
    weight_saver = ModelCheckpoint(weights_file, monitor='val_dice_coef', save_best_only=True, save_weights_only=True)
    annealer = LearningRateScheduler(lambda x: 1e-3 * 0.8 ** x)
    hist = model.fit(x_train, y_train, batch_size = 8, validation_data = (x_val, y_val), epochs=1, verbose=2, callbacks = [weight_saver, annealer])
    model.evaluate(x_train, y_train)

非常感谢你的帮助!

1个回答

没有“不匹配”的准确性。您的问题是您有一个图像分割问题,其中 99% 的像素应该为零。因此,获得 99% 的准确率非常容易。仅预测空白输出图像的模型的得分与您的网络迄今为止的得分大致相同。您的准确性指标没有意义。

低 Dice 系数得分让您更好地了解正在发生的事情。这仅涵盖正例匹配,并且好的分数将接近 1.0。低分表明网络没有专注于正确获取正像素。相反,网络已经学会在任何地方预测接近于零,因为这可以很好地将损失度量最小化为第一个近似值。

如何解决问题?

首先,停止报告准确性。这个指标会误导您,您需要找到另一个指标,以便您可以公平地评估您的模型。由于您已经拥有 Dice,因此您可以放弃准确性并改用 Dice。或者,您可以使用加权准确度,与每类训练数据中的平均像素数成反比。查看Keras 指标选项,您可能希望为此添加另一个自定义指标。您已经使用该dice_coef功能完成了此操作,因此这应该不是问题。

其次,训练你的网络更长时间。您的示例只有一个时代。根据您有多少训练示例,这对于图像处理网络来说可能太低了。尝试以几何级数增加数字 - 3, 10, 30, 100, 300, 1000 - 使用新指标查看训练期间是否有任何改进。

您还可以尝试更改成本函数以对其进行加权以支持正像素。Keras的fit 函数为此目的有一个 class_weight 参数,您可以将其设置为class_weight = {0:1, 1:20}