nabsabraham / focal-tversky-unet

This repo contains the code for our paper "A novel focal Tversky loss function and improved Attention U-Net for lesion segmentation" accepted at IEEE ISBI 2019.
357 stars 72 forks source link

General Code review on 3D model #8

Closed DecentMakeover closed 5 years ago

DecentMakeover commented 5 years ago

Hi sorry to bother you with this but my model is not learning at all the loss stays the same after every epoch -0.3370

This is the model

def unet(input_shape=(128, 128, 128), optimizer=Adam, initial_learning_rate=5e-4, loss_function=weighted_dice_coefficient_loss):

inputs = Input(shape=input_shape)
conv1 = UnetConv3D(inputs, 32, is_batchnorm=False, name='conv1')
pool1 = MaxPooling3D(pool_size=(2, 2,2 ))(conv1)

conv2 = UnetConv3D(pool1, 64, is_batchnorm=False, name='conv2')
pool2 = MaxPooling3D(pool_size=(2, 2,2 ))(conv2)

conv3 = UnetConv3D(pool2, 128, is_batchnorm=False, name='conv3')
pool3 = MaxPooling3D(pool_size=(2, 2,2 ))(conv3)

conv4 = UnetConv3D(pool3, 256, is_batchnorm=False, name='conv4')
pool4 = MaxPooling3D(pool_size=(2, 2,2 ))(conv4)

conv5 = Conv3D(512, (3, 3, 3), activation='relu', kernel_initializer=kinit, padding='same', data_format = 'channels_first')(pool4)
conv5 = Conv3D(512, (3, 3, 3), activation='relu', kernel_initializer=kinit, padding='same', data_format = 'channels_first')(conv5)

up6 = concatenate([Conv3DTranspose(256, (2, 2,2 ), strides=(2, 2,2 ), kernel_initializer=kinit, padding='same', data_format = 'channels_first')(conv5), conv4], axis=1)
conv6 = Conv3D(256, (3, 3, 3), activation='relu', padding='same', data_format = 'channels_first')(up6)
conv6 = Conv3D(256, (3, 3, 3), activation='relu', padding='same', data_format = 'channels_first')(conv6)

up7 = concatenate([Conv3DTranspose(128, (2, 2,2 ), strides=(2, 2,2 ), padding='same', data_format = 'channels_first')(conv6), conv3], axis=1)
conv7 = Conv3D(128, (3, 3, 3), activation='relu', kernel_initializer=kinit, padding='same', data_format = 'channels_first')(up7)
conv7 = Conv3D(128, (3, 3, 3), activation='relu', kernel_initializer=kinit, padding='same', data_format = 'channels_first')(conv7)

up8 = concatenate([Conv3DTranspose(64, (2, 2,2 ), strides=(2,2,2 ), kernel_initializer=kinit, padding='same', data_format = 'channels_first')(conv7), conv2], axis=1)
conv8 = Conv3D(64, (3, 3, 3), activation='relu', kernel_initializer=kinit, padding='same', data_format = 'channels_first')(up8)

up9    = concatenate([Conv3DTranspose(32, (2, 2,2 ), strides=(2, 2,2 ), kernel_initializer=kinit, padding='same', data_format = 'channels_first')(conv8), conv1], axis=1)
conv9  = Conv3D(32, (3, 3, 3), activation='relu',  kernel_initializer=kinit, padding='same', data_format = 'channels_first')(up9)
conv9  = Conv3D(32, (3, 3, 3), activation='relu', kernel_initializer=kinit, padding='same', data_format = 'channels_first')(conv9)
conv10 = Conv3D(3, (1, 1, 1), activation='relu', kernel_initializer=kinit,padding = 'same', name='final', data_format = 'channels_first')(conv9)

activation_name = 'sigmoid'
activation_block = Activation(activation_name)(conv10)
model = Model(inputs=[inputs], outputs=[activation_block])
model.compile(optimizer=optimizer(), loss=loss_function)
return model

And this is the helper function

def UnetConv3D(input, outdim, is_batchnorm, name):
x = Conv3D(outdim, (3, 3, 3), strides=(1, 1, 1), kernel_initializer=kinit, padding="same", name=name+'_1', data_format = 'channels_first')(input)
if is_batchnorm:
    x =BatchNormalization(name=name + '_1_bn')(x)
x = Activation('relu',name=name + '_1_act')(x)

x = Conv3D(outdim, (3, 3, 3), strides=(1, 1, 1), kernel_initializer=kinit, padding="same", name=name+'_2', data_format = 'channels_first')(x)
if is_batchnorm:
    x = BatchNormalization(name=name + '_2_bn')(x)
x = Activation('relu', name=name + '_2_act')(x)
return x

And this is the loss function

def weighted_dice_coefficient(y_true, y_pred, axis=(-3, -2, -1), smooth=0.00001):
"""
Weighted dice coefficient. Default axis assumes a "channels first" data structure
:param smooth:
:param y_true:
:param y_pred:
:param axis:
:return:
"""
return K.mean(2. * (K.sum(y_true * y_pred,
                          axis=axis) + smooth/2)/(K.sum(y_true,
                                                        axis=axis) + K.sum(y_pred,
                                                                           axis=axis) + smooth)

My input is (128,128,128), am i doing an obvious mistake? Please let me know if more info needed.

quqixun commented 5 years ago

conv10 = Conv3D(3, (1, 1, 1), activation='relu', kernel_initializer=kinit,padding = 'same', name='final', data_format = 'channels_first')(conv9) activation_name = 'sigmoid' activation_block = Activation(activation_name)(conv10)

Your output has 3 channels, you may apply 'softmax' to compute probability for each class.

DecentMakeover commented 5 years ago

Hi @quqixun ,Thanks for the reply Changing activation from sigmoid to softmax does not work.

nabsabraham commented 5 years ago

Hi @DecentMakeover, did you find a solution? I actually haven't tried 3D but will run your code sometime this week to see if I can debug

DecentMakeover commented 5 years ago

Hey , that’s okay , I have moved on from this now.

On 02-Aug-2019, at 8:47 PM, Nabila Abraham notifications@github.com<mailto:notifications@github.com> wrote:

Hi @DecentMakeoverhttps://github.com/DecentMakeover, did you find a solution? I actually haven't tried 3D but will run your code sometime this week to see if I can debug

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/nabsabraham/focal-tversky-unet/issues/8?email_source=notifications&email_token=AGD5QF6FNVOPVJ63T2ECWOTQCRFXXA5CNFSM4H2WVJTKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3OBJEQ#issuecomment-517739666, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AGD5QF3BB2AXHKLEJCUZ3XDQCRFXXANCNFSM4H2WVJTA.