python - 使用 keras 训练时出现奇怪的结果
问题描述
我正在尝试使用带有 tensorflow 的 keras 在braTS18数据集(带有 nifiti 图像的医学数据)上训练一个unet模型。但是我得到了非常奇怪的结果:
如您所见,准确率从 96% 开始,在第三个 epoch 达到 99%。此外,验证损失也不会降低。训练后的模型也没有预测到任何东西。
我以不同的方式拆分数据(20% 训练 60% 验证,或 60% 训练 20% 验证)但没有用。我认为问题可能出在我的模型或数据生成器上。以下是代码:
网络模型
def unet_model(filters=16, dropout=0.1, batch_normalize=True):
# Build U-Net model
inputs = Input((img_height, img_width, img_channels), name='main_input')
s = Lambda(lambda x: x / 255) (inputs)
c1 = Conv2D(filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c1') (s)
c1 = Dropout(0.1) (c1)
c1 = Conv2D(filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c1_d') (c1)
p1 = MaxPooling2D((2, 2)) (c1)
c2 = Conv2D(2*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c2') (p1)
c2 = Dropout(0.1) (c2)
c2 = Conv2D(2*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c2_d') (c2)
p2 = MaxPooling2D((2, 2)) (c2)
c3 = Conv2D(4*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c3') (p2)
c3 = Dropout(0.2) (c3)
c3 = Conv2D(4*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c3_d') (c3)
p3 = MaxPooling2D((2, 2)) (c3)
c4 = Conv2D(8*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c4') (p3)
c4 = Dropout(0.2) (c4)
c4 = Conv2D(8*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c4_d') (c4)
p4 = MaxPooling2D(pool_size=(2, 2)) (c4)
c5 = Conv2D(16*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c5') (p4)
c5 = Dropout(0.3) (c5)
c5 = Conv2D(16*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c5_d') (c5)
u6 = Conv2DTranspose(8*filters, (2, 2), strides=(2, 2), padding='same', name = 'u6') (c5)
u6 = concatenate([u6, c4])
c6 = Conv2D(8*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c6') (u6)
c6 = Dropout(0.2) (c6)
c6 = Conv2D(8*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c6_d') (c6)
u7 = Conv2DTranspose(4*filters, (2, 2), strides=(2, 2), padding='same', name = 'u7') (c6)
u7 = concatenate([u7, c3])
c7 = Conv2D(4*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c7') (u7)
c7 = Dropout(0.2) (c7)
c7 = Conv2D(4*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c7_d') (c7)
u8 = Conv2DTranspose(2*filters, (2, 2), strides=(2, 2), padding='same', name = 'u8') (c7)
u8 = concatenate([u8, c2])
c8 = Conv2D(2*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c8') (u8)
c8 = Dropout(0.1) (c8)
c8 = Conv2D(2*filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c8_d') (c8)
u9 = Conv2DTranspose(filters, (2, 2), strides=(2, 2), padding='same', name = 'u9') (c8)
u9 = concatenate([u9, c1], axis=3)
c9 = Conv2D(filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c9') (u9)
c9 = Dropout(0.1) (c9)
c9 = Conv2D(filters, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same', name = 'c9_d') (c9)
outputs = Conv2D(1, (1, 1), activation='sigmoid', name = 'output') (c9)
adam = optimizers.Adam(lr=lr, beta_1=beta1, decay=lr_decay, amsgrad=False)
model = Model(inputs=[inputs], outputs=[outputs])
model.compile(optimizer=adam, loss='binary_crossentropy', metrics=['accuracy',dice,jaccard])
plot_model(model, to_file=os.path.join(save_dir +"model.png"))
if os.path.exists(os.path.join(save_dir +"model.txt")):
os.remove(os.path.join(save_dir +"model.txt"))
with open(os.path.join(save_dir +"model.txt"),'w') as fh:
model.summary(positions=[.3, .55, .67, 1.], print_fn=lambda x: fh.write(x + '\n'))
model.summary()
return model
这是数据生成器的代码:
def generate_data(X_data, Y_data, batch_size):
samples_per_epoch = total_folders
number_of_batches = samples_per_epoch/batch_size
counter=0
while True:
X_batch = X_data[batch_size*counter:batch_size*(counter+1)]
Y_batch = Y_data[batch_size*counter:batch_size*(counter+1)]
counter += 1
yield X_batch, Y_batch
if counter >= number_of_batches:
counter = 0
...
in the main function
...
if __name__ == "__main__":
callbacks = [
EarlyStopping(patience=1000, verbose=1),
ReduceLROnPlateau(factor=0.1, patience=3, min_lr=0.00001, verbose=1),
ModelCheckpoint(save_dir + 'model.{epoch:02d}-{val_loss:.2f}.h5', verbose=1, save_best_only=True, save_weights_only=True)
]
model = unet_model(filters=16, dropout=0.05, batch_normalize=True)
H = model.fit_generator(generate_data(X_train,Y_train,batch_size),
epochs= epochs,
steps_per_epoch = total_folders/batch_size,
validation_data=generate_data(X_test,Y_test,batch_size*2),
callbacks=callbacks,
validation_steps= total_folders/batch_size*2)
我在这里做错了什么?
解决方案
我相信你的问题是你的损失函数/指标。如果大多数患者没有任何肿瘤,并且准确度或 jaccard 距离同样考虑这两个类别,则您的模型将通过简单地说一切都是 backgorund/healthy 来返回高准确度值和低 jaccard 指数值。您可以通过实现始终返回背景类标签并将其与当前结果进行比较的自定义损失来检查这一点。要解决您的问题,请实施类似 jaccard 距离的方法,以降低背景的权重。可以在此处找到可能比准确性更合适的不同指标的概述。
另外,也许我不了解数据集,但您不应该分割不同种类的肿瘤,因此使用分类而不是二元分类吗?
推荐阅读
- reactjs - 单选按钮在选择选项时自动选择其他选项
- windows - 将 Atlassian Bamboo 安装为“内部服务器错误”后出现错误
- linux-kernel - Buildroot:如何修改自定义板的设备树?
- mysql - GCP 上 Cloud SQL 的漏洞
- java - 尝试从 SQLite 数据库加载图像路径时出错
- facebook - 访问 Facebook 广告经理帐户时,我会因错误“FB internal Thrift over HTTP”而退出
- java - 无法解析符号“扫描仪”Java
- javascript - 如何在浏览器中显示解码的 JSON 数据
- wordpress - 创建用户时 Wordpress 上的 ACF 问题
- c# - 有没有更优雅的方法从 TimeSpan 中删除秒?