Cannot train image segmentation model with UNet - python-3.x

My environment
Ubuntu 18.04
Python 3.6.8
Tensorflow 1.12.0
The problem
I made UNet to segment images by using Tensorflow. I refered the original paper, and I implemented the same structure except for the output channel number (used 3 but not 2). My model seems to work well, but the loss does not converge, it is like electrocardiogram ...
I used MSE as loss function, but some websites said that MSE does not valid in UNet, so I change to use dice loss. But still, it does not work. I suspect that the network structure is bad.
The codes
import tensorflow as tf
tf.reset_default_graph()
with tf.name_scope('input'):
X = tf.placeholder(tf.float32, shape=[None, 572, 572, 3], name='X')
y = tf.placeholder(tf.float32, shape=[None, 388, 388, 3], name='y')
# Encoding
with tf.name_scope('layer1'):
conv1 = tf.layers.conv2d(X, filters=64, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv1')
conv2 = tf.layers.conv2d(conv1, filters=64, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv2')
with tf.name_scope('layer2'):
pool1 = tf.nn.max_pool(conv2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='VALID', name='pool1')
conv3 = tf.layers.conv2d(pool1, filters=128, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv3')
conv4 = tf.layers.conv2d(conv3, filters=128, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv4')
with tf.name_scope('layer3'):
pool2 = tf.nn.max_pool(conv4, ksize=[1,2,2,1], strides=[1,2,2,1], padding='VALID', name='pool2')
conv5 = tf.layers.conv2d(pool2, filters=256, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv5')
conv6 = tf.layers.conv2d(conv5, filters=256, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv6')
with tf.name_scope('layer4'):
pool3 = tf.nn.max_pool(conv6, ksize=[1,2,2,1], strides=[1,2,2,1], padding='VALID', name='pool3')
conv7 = tf.layers.conv2d(pool3, filters=512, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv7')
conv8 = tf.layers.conv2d(conv7, filters=512, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv8')
with tf.name_scope('layer5'):
pool4 = tf.nn.max_pool(conv8, ksize=[1,2,2,1], strides=[1,2,2,1], padding='VALID', name='pool4')
conv9 = tf.layers.conv2d(pool4, filters=1024, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv9')
conv10 = tf.layers.conv2d(conv9, filters=1024, kernel_size=3, strides=1, activation=tf.nn.relu, name='conv10')
#Decoding
with tf.name_scope('layer6'):
up_conv1 = tf.layers.conv2d_transpose(conv10, filters=512, kernel_size=2, strides=2)
croped_conv8 = tf.image.central_crop(conv8, 7/8)
concat1 = tf.concat([croped_conv8, up_conv1], axis=-1)
conv11 = tf.layers.conv2d(concat1, filters=512, kernel_size=3, activation=tf.nn.relu, name='conv11')
conv12 = tf.layers.conv2d(conv11, filters=512, kernel_size=3, activation=tf.nn.relu, name='conv12')
with tf.name_scope('layer7'):
up_conv2 = tf.layers.conv2d_transpose(conv12, filters=256, kernel_size=2, strides=2)
croped_conv6 = tf.image.central_crop(conv6, 13/17)
concat2 = tf.concat([croped_conv6, up_conv2], axis=-1)
conv13 = tf.layers.conv2d(concat2, filters=256, kernel_size=3, activation=tf.nn.relu, name='conv13')
conv14 = tf.layers.conv2d(conv13, filters=256, kernel_size=3, activation=tf.nn.relu, name='conv14')
with tf.name_scope('layer8'):
up_conv3 = tf.layers.conv2d_transpose(conv14, filters=128, kernel_size=2, strides=2)
croped_conv4 = tf.image.central_crop(conv4, 5/7)
concat3 = tf.concat([croped_conv4, up_conv3], axis=-1)
conv15 = tf.layers.conv2d(concat3, filters=128, kernel_size=3, activation=tf.nn.relu, name='conv15')
conv16 = tf.layers.conv2d(conv15, filters=128, kernel_size=3, activation=tf.nn.relu, name='conv16')
with tf.name_scope('layer8'):
up_conv4 = tf.layers.conv2d_transpose(conv16, filters=64, kernel_size=2, strides=2)
croped_conv2 = tf.image.central_crop(conv2, 49/71)
concat4 = tf.concat([croped_conv2, up_conv4], axis=-1)
conv17 = tf.layers.conv2d(concat4, filters=64, kernel_size=3, activation=tf.nn.relu, name='conv17')
conv18 = tf.layers.conv2d(conv17, filters=64, kernel_size=3, activation=tf.nn.relu, name='conv18')
output = tf.layers.conv2d(conv18, filters=3, kernel_size=1, name='output')
with tf.name_scope('train'):
dice = 2 * tf.math.reduce_sum(output*y) / (tf.math.reduce_sum(output) + tf.math.reduce_sum(y) + 1)
loss = 1 - dice
optimizer = tf.train.AdamOptimizer()
training_op = optimizer.minimize(loss)
with tf.name_scope('save'):
saver = tf.train.Saver()
loss_sumary = tf.summary.scalar('ls', loss)
filewriter = tf.summary.FileWriter('./', tf.get_default_graph())

Related

TensorFlow: "NotImplementedError: When subclassing the `Model` class, you should implement a `call` method."

inside "PWCDCNet.py" I have defined the following ANN:
class Conv2D(tfk.layers.Layer):
def __init__(self, filters, kernel_size, strides, name=None, padding=1, dilation_rate=1):
super(Conv2D, self).__init__(name=name)
self.conv_out = tfk.layers.Conv2D(filters=filters,
kernel_size=kernel_size,
strides=strides,
padding='same',
kernel_initializer='he_normal',
dilation_rate=dilation_rate,
activation=tfk.layers.LeakyReLU(0.1))
def call(self, inputs):
return self.conv_out(inputs)
class DeConv2D(tfk.layers.Layer):
def __init__(self, filters, kernel_size=4, strides=2, name=None):
super(DeConv2D, self).__init__(name=name)
self.deconv_out = tfk.layers.Conv2DTranspose(filters=filters,
kernel_size=kernel_size,
strides=strides,
padding='same',
name=name)
def call(self, inputs):
return self.deconv_out(inputs)
def CostVolumn(c1, warp, search_range, name='cost_volumn'):
padded_lvl = tf.pad(warp, [[0, 0], [search_range, search_range], [search_range, search_range], [0, 0]])
_, h, w, _ = tf.unstack(tf.shape(c1))
max_offset = search_range * 2 + 1
cost_vol = []
for y in range(0, max_offset):
for x in range(0, max_offset):
slice = tf.slice(padded_lvl, [0, y, x, 0], [-1, h, w, -1])
cost = tf.reduce_mean(c1 * slice, axis=3, keepdims=True)
cost_vol.append(cost)
cost_vol = tf.concat(cost_vol, axis=3)
cost_vol = tf.nn.leaky_relu(cost_vol, alpha=0.1, name=name)
return cost_vol
class PredictFlow(tfk.layers.Layer):
def __init__(self, name=None):
super(PredictFlow, self).__init__()
self.conv_out = tfk.layers.Conv2D(filters=2,
kernel_size=3,
strides=1,
name=name,
padding='same')
def call(self, inputs):
return self.conv_out(inputs)
class PWCDCNet(tf.keras.Model):
def __init__(self, max_displacement=4):
super(PWCDCNet, self).__init__()
self.conv1a = Conv2D( 16, kernel_size=3, strides=2, name='conv1a')
self.conv1aa = Conv2D( 16, kernel_size=3, strides=1, name='conv1aa')
self.conv1b = Conv2D( 16, kernel_size=3, strides=1, name='conv1b')
self.conv2a = Conv2D( 32, kernel_size=3, strides=2, name='conv2a')
self.conv2aa = Conv2D( 32, kernel_size=3, strides=1, name='conv2aa')
self.conv2b = Conv2D( 32, kernel_size=3, strides=1, name='conv2b')
self.conv3a = Conv2D( 64, kernel_size=3, strides=2, name='conv3a')
self.conv3aa = Conv2D( 64, kernel_size=3, strides=1, name='conv3aa')
self.conv3b = Conv2D( 64, kernel_size=3, strides=1, name='conv3b')
self.conv4a = Conv2D( 96, kernel_size=3, strides=2, name='conv4a')
self.conv4aa = Conv2D( 96, kernel_size=3, strides=1, name='conv4aa')
self.conv4b = Conv2D( 96, kernel_size=3, strides=1, name='conv4b')
self.conv5a = Conv2D(128, kernel_size=3, strides=2, name='conv5a')
self.conv5aa = Conv2D(128, kernel_size=3, strides=1, name='conv5aa')
self.conv5b = Conv2D(128, kernel_size=3, strides=1, name='conv5b')
self.conv6aa = Conv2D(196, kernel_size=3, strides=2, name='conv6aa')
self.conv6a = Conv2D(196, kernel_size=3, strides=1, name='conv6a')
self.conv6b = Conv2D(196, kernel_size=3, strides=1, name='conv6b')
self.LeakyReLU = tfk.layers.LeakyReLU(0.1, name='LeakyReLU')
self.conv6_0 = Conv2D(128, kernel_size=3, strides=1, name='conv6_0')
self.conv6_1 = Conv2D(128, kernel_size=3, strides=1, name='conv6_1')
self.conv6_2 = Conv2D(96, kernel_size=3, strides=1, name='conv6_2')
self.conv6_3 = Conv2D(64, kernel_size=3, strides=1, name='conv6_3')
self.conv6_4 = Conv2D(32, kernel_size=3, strides=1, name='conv6_4')
self.deconv6 = DeConv2D(2, kernel_size=4, strides=2, name='deconv_6')
self.upfeat6 = DeConv2D(2, kernel_size=4, strides=2, name='upfeat_6')
self.conv5_0 = Conv2D(128, kernel_size=3, strides=1, name='conv5_0')
self.conv5_1 = Conv2D(128, kernel_size=3, strides=1, name='conv5_1')
self.conv5_2 = Conv2D(96, kernel_size=3, strides=1, name='conv5_2')
self.conv5_3 = Conv2D(64, kernel_size=3, strides=1, name='conv5_3')
self.conv5_4 = Conv2D(32, kernel_size=3, strides=1, name='conv5_4')
self.deconv5 = DeConv2D(2, kernel_size=4, strides=2, name='deconv_5')
self.upfeat5 = DeConv2D(2, kernel_size=4, strides=2, name='upfeat_5')
self.conv4_0 = Conv2D(128, kernel_size=3, strides=1, name='conv4_0')
self.conv4_1 = Conv2D(128, kernel_size=3, strides=1, name='conv4_1')
self.conv4_2 = Conv2D(96, kernel_size=3, strides=1, name='conv4_2')
self.conv4_3 = Conv2D(64, kernel_size=3, strides=1, name='conv4_3')
self.conv4_4 = Conv2D(32, kernel_size=3, strides=1, name='conv4_4')
self.deconv4 = DeConv2D(2, kernel_size=4, strides=2, name='deconv4')
self.upfeat4 = DeConv2D(2, kernel_size=4, strides=2, name='upfeat4')
self.conv3_0 = Conv2D(128, kernel_size=3, strides=1, name='conv3_0')
self.conv3_1 = Conv2D(128, kernel_size=3, strides=1, name='conv3_1')
self.conv3_2 = Conv2D(96, kernel_size=3, strides=1, name='conv3_2')
self.conv3_3 = Conv2D(64, kernel_size=3, strides=1, name='conv3_3')
self.conv3_4 = Conv2D(32, kernel_size=3, strides=1, name='conv3_4')
self.deconv3 = DeConv2D(2, kernel_size=4, strides=2, name='deconv3')
self.upfeat3 = DeConv2D(2, kernel_size=4, strides=2, name='upfeat3')
self.conv2_0 = Conv2D(128, kernel_size=3, strides=1, name='conv2_0')
self.conv2_1 = Conv2D(128, kernel_size=3, strides=1, name='conv2_1')
self.conv2_2 = Conv2D(96, kernel_size=3, strides=1, name='conv2_2')
self.conv2_3 = Conv2D(64, kernel_size=3, strides=1, name='conv2_3')
self.conv2_4 = Conv2D(32, kernel_size=3, strides=1, name='conv2_4')
self.deconv2 = DeConv2D(2, kernel_size=4, strides=2, name='deconv2')
self.dc_conv1 = Conv2D(128, kernel_size=3, strides=1, padding=1, dilation_rate=1, name='dc_conv1')
self.dc_conv2 = Conv2D(128, kernel_size=3, strides=1, padding=2, dilation_rate=2, name='dc_conv2')
self.dc_conv3 = Conv2D(128, kernel_size=3, strides=1, padding=4, dilation_rate=4, name='dc_conv3')
self.dc_conv4 = Conv2D(96, kernel_size=3, strides=1, padding=8, dilation_rate=8, name='dc_conv4')
self.dc_conv5 = Conv2D(64, kernel_size=3, strides=1, padding=16, dilation_rate=16, name='dc_conv5')
self.dc_conv6 = Conv2D(32, kernel_size=3, strides=1, padding=1, dilation_rate=1, name='dc_conv6')
self.predict_flow6 = PredictFlow(name='predict_flow6')
self.predict_flow5 = PredictFlow(name='predict_flow5')
self.predict_flow4 = PredictFlow(name='predict_flow4')
self.predict_flow3 = PredictFlow(name='predict_flow3')
self.predict_flow2 = PredictFlow(name='predict_flow2')
self.dc_conv7 = PredictFlow(name='dc_conv7')
def call(self, inputs):
im1 = inputs[:, :, :, :3]
im2 = inputs[:, :, :, 3:]
c11 = self.conv1b(self.conv1aa(self.conv1a(im1)))
c21 = self.conv1b(self.conv1aa(self.conv1a(im2)))
c12 = self.conv2b(self.conv2aa(self.conv2a(c11)))
c22 = self.conv2b(self.conv2aa(self.conv2a(c21)))
c13 = self.conv3b(self.conv3aa(self.conv3a(c12)))
c23 = self.conv3b(self.conv3aa(self.conv3a(c22)))
c14 = self.conv4b(self.conv4aa(self.conv4a(c13)))
c24 = self.conv4b(self.conv4aa(self.conv4a(c23)))
c15 = self.conv5b(self.conv5aa(self.conv5a(c14)))
c25 = self.conv5b(self.conv5aa(self.conv5a(c24)))
c16 = self.conv6b(self.conv6a(self.conv6aa(c15)))
c26 = self.conv6b(self.conv6a(self.conv6aa(c25)))
### 6th flow
corr6 = CostVolumn(c1=c16, warp=c26, search_range=4)
x = tf.concat([self.conv6_0(corr6), corr6], 3)
x = tf.concat([self.conv6_1(x), x], 3)
x = tf.concat([self.conv6_2(x), x], 3)
x = tf.concat([self.conv6_3(x), x], 3)
x = tf.concat([self.conv6_4(x), x], 3)
flow6 = self.predict_flow6(x)
up_flow6 = self.deconv6(flow6)
up_feat6 = self.upfeat6(x)
### 5th flow
warp5 = bilinear_warp(c25, up_flow6*0.625)
corr5 = CostVolumn(c1=c15, warp=warp5, search_range=4)
x = tf.concat([corr5, c15, up_flow6, up_feat6], 3)
x = tf.concat([self.conv5_0(x), x], 3)
x = tf.concat([self.conv5_1(x), x], 3)
x = tf.concat([self.conv5_2(x), x], 3)
x = tf.concat([self.conv5_3(x), x], 3)
x = tf.concat([self.conv5_4(x), x], 3)
flow5 = self.predict_flow5(x)
up_flow5 = self.deconv5(flow5)
up_feat5 = self.upfeat5(x)
### 4th flow
warp4 = bilinear_warp(c24, up_flow5*1.25)
corr4 = CostVolumn(c1=c14, warp=warp4, search_range=4)
x = tf.concat([corr4, c14, up_flow5, up_feat5], 3)
x = tf.concat([self.conv4_0(x), x], 3)
x = tf.concat([self.conv4_1(x), x], 3)
x = tf.concat([self.conv4_2(x), x], 3)
x = tf.concat([self.conv4_3(x), x], 3)
x = tf.concat([self.conv4_4(x), x], 3)
flow4 = self.predict_flow4(x)
up_flow4 = self.deconv4(flow4)
up_feat4 = self.upfeat4(x)
### 3rd flow
warp3 = bilinear_warp(c23, up_flow4*2.5)
corr3 = CostVolumn(c1=c13, warp=warp3, search_range=4)
x = tf.concat([corr3, c13, up_flow4, up_feat4], 3)
x = tf.concat([self.conv3_0(x), x], 3)
x = tf.concat([self.conv3_1(x), x], 3)
x = tf.concat([self.conv3_2(x), x], 3)
x = tf.concat([self.conv3_3(x), x], 3)
x = tf.concat([self.conv3_4(x), x], 3)
flow3 = self.predict_flow3(x)
up_flow3 = self.deconv3(flow3)
up_feat3 = self.upfeat3(x)
# 2nd flow
warp2 = bilinear_warp(c22, up_flow3*5.0)
corr2 = CostVolumn(c1=c12, warp=warp2, search_range=4)
x = tf.concat([corr2, c12, up_flow3, up_feat3], 3)
x = tf.concat([self.conv2_0(x), x], 3)
x = tf.concat([self.conv2_1(x), x], 3)
x = tf.concat([self.conv2_2(x), x], 3)
x = tf.concat([self.conv2_3(x), x], 3)
x = tf.concat([self.conv2_4(x), x], 3)
flow2 = self.predict_flow2(x)
x = self.dc_conv4(self.dc_conv3(self.dc_conv2(self.dc_conv1(x))))
flow2 = flow2 + self.dc_conv7(self.dc_conv6(self.dc_conv5(x)))
return flow2
This ANN gets imported into another file:
from PWCNet_tf2.PWCDCNet import PWCDCNet
PWC_model = tf.keras.Model(PWCDCNet())
checkpoint = tf.train.Checkpoint(PWC_model)
save_path = checkpoint.save('/some_directories/PWCNet_tf2/checkpoints/0001/tf_ckpt')
checkpoint.restore(save_path)
But if I try to:
output = PWC_model(input)
I get the error:
NotImplementedError: When subclassing the `Model` class, you should implement a `call` method.
I am wondering, as a call method is implemented for every Layer, but also for the ANN as a whole. Is the error due to the way I import the model?
Thanks to all of you in advance!
The error was that I called:
PWC_model = tf.keras.Model(PWCDCNet())
instead of:
PWC_model = PWCDCNet()

A `Concatenate` layer requires inputs with matching shapes except for the concat axis

I try to train Unet neural network from zhixuhao, I submit to the input of the image 512x512 but I get this error:
Traceback (most recent call last):
File "unet.py", line 168, in <module>
myunet.train()
File "unet.py", line 159, in train
model.fit(imgs_train, imgs_mask_train, batch_size=1, nb_epoch=10, verbose=1, shuffle=True, callbacks=[model_checkpoint])
File "C:\Users\mimozzza\AppData\Local\Programs\Python\Python37\lib\site-packages\keras\engine\training.py", line 952, in fit
batch_size=batch_size)
File "C:\Users\mimozzza\AppData\Local\Programs\Python\Python37\lib\site-packages\keras\engine\training.py", line 751, in _standardize_user_data
exception_prefix='input')
File "C:\Users\mimozzza\AppData\Local\Programs\Python\Python37\lib\site-packages\keras\engine\training_utils.py", line 138, in standardize_input_data
str(data_shape))
ValueError: Error when checking input: expected input_1 to have shape (256, 256, 3) but got array with shape (512, 512, 3)
Here is the code:
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs)
print ("conv1 shape:"),conv1.shape
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv1)
print ("conv1 shape:"),conv1.shape
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
print ("pool1 shape:"),pool1.shape
conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool1)
print ("conv2 shape:"),conv2.shape
conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv2)
print ("conv2 shape:"),conv2.shape
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
print ("pool2 shape:"),pool2.shape
conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool2)
print ("conv3 shape:"),conv3.shape
conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv3)
print ("conv3 shape:"),conv3.shape
pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
print ("pool3 shape:"),pool3.shape
conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool3)
conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv4)
drop4 = Dropout(0.5)(conv4)
pool4 = MaxPooling2D(pool_size=(2, 2))(drop4)
conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool4)
conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv5)
drop5 = Dropout(0.5)(conv5)
up6 = Conv2D(512, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(drop5))
merge6 = concatenate([drop4, up6], axis=3)
conv6 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge6)
conv6 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv6)
up7 = Conv2D(256, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv6))
merge7 = concatenate([conv3, up7], axis=3)
conv7 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge7)
conv7 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv7)
up8 = Conv2D(128, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv7))
merge8 = concatenate([conv2, up8], axis=3)
conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge8)
conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv8)
up9 = Conv2D(64, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv8))
merge9 = concatenate([conv1, up9], axis=3)
conv9 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge9)
conv9 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)
conv9 = Conv2D(2, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)
conv10 = Conv2D(1, 1, activation = 'sigmoid')(conv9)
model = Model(input = inputs, output = conv10)
model.compile(optimizer = Adam(lr = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy'])
return model
I looked at other discussions on this topic and realized that the error might be related to the resolution of the image, but my files are the same resolution that was supposed to be zhixuhao initially.
Tell me, what's the problem, and how can I fix it?
PS:
I use keras version 1.0.0, and also use the latest version of the code from GitHub, I use the version on October 24, 2017.
The problem is solved, in the code images were specified with a resolution of 256x256, although I tried to learn from the 512x512 images.

Imbalanced data for semantic segmentation in Keras?

I am new with keras and have been learning it for about 3 weeks now. I apologies if my question sounds a bit stupid.
I am currently doing semantic medical image segmentation of 512x512. I'm using UNet from this link https://github.com/zhixuhao/unet . Basically, I want to segment a brain from an image (so two-class segmentation, background vs foreground)
I have made a few modification of the network and I'm getting some results which i am happy with. But I think I can improve the segmentation results by imposing more weight on the foreground because the number of pixels of the brain is much smaller than the number of background pixels. In some cases the brain does not appear in the image especially those located in the bottom slices.
I don't know which part of the code I need to modify in https://github.com/zhixuhao/unet
I would really appreciate if anyone can help me with this. Thanks a lot in advance!
import numpy as np
import os
import skimage.io as io
import skimage.transform as trans
import numpy as np
from keras.models import *
from keras.layers import *
from keras.optimizers import *
from keras.callbacks import ModelCheckpoint, LearningRateScheduler
from keras import backend as keras
def unet(pretrained_weights=None, input_size=(256, 256, 1)):
inputs = Input(input_size)
conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(inputs)
conv1 = BatchNormalization()(conv1)
conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv1)
conv1 = BatchNormalization()(conv1)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool1)
conv2 = BatchNormalization()(conv2)
conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv2)
conv2 = BatchNormalization()(conv2)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool2)
conv3 = BatchNormalization()(conv3)
conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv3)
conv3 = BatchNormalization()(conv3)
pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool3)
conv4 = BatchNormalization()(conv4)
conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv4)
conv4 = BatchNormalization()(conv4)
drop4 = Dropout(0.5)(conv4)
pool4 = MaxPooling2D(pool_size=(2, 2))(drop4)
conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool4)
conv5 = BatchNormalization()(conv5)
conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv5)
conv5 = BatchNormalization()(conv5)
drop5 = Dropout(0.5)(conv5)
up6 = Conv2D(512, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
UpSampling2D(size=(2, 2))(drop5))
merge6 = concatenate([drop4, up6], axis=3)
conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge6)
conv6 = BatchNormalization()(conv6)
conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv6)
conv6 = BatchNormalization()(conv6)
up7 = Conv2D(256, 2, activation='relu', padding='same', kernel_initializer='he_normal')(UpSampling2D(size=(2, 2))(conv6))
merge7 = concatenate([conv3, up7], axis=3)
conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge7)
conv7 = BatchNormalization()(conv7)
conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv7)
conv7 = BatchNormalization()(conv7)
up8 = Conv2D(128, 2, activation='relu', padding='same', kernel_initializer='he_normal')(UpSampling2D(size=(2, 2))(conv7))
merge8 = concatenate([conv2, up8], axis=3)
conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge8)
conv8 = BatchNormalization()(conv8)
conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv8)
conv8 = BatchNormalization()(conv8)
up9 = Conv2D(64, 2, activation='relu', padding='same', kernel_initializer='he_normal')(UpSampling2D(size=(2, 2))(conv8))
merge9 = concatenate([conv1, up9], axis=3)
conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge9)
conv9 = BatchNormalization()(conv9)
conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv9)
conv9 = BatchNormalization()(conv9)
conv9 = Conv2D(2, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv9)
conv9 = BatchNormalization()(conv9)
conv10 = Conv2D(1, 1, activation='sigmoid')(conv9)
model = Model(input=inputs, output=conv10)
model.compile(optimizer=Adam(lr=1e-4), loss='binary_crossentropy', metrics=['accuracy'])
# model.summary()
if (pretrained_weights):
model.load_weights(pretrained_weights)
return model
Here's the main.py
from model2 import *
from data2 import *
from keras.models import load_model
class_weight= {0:0.10, 1:0.90}
myGene = trainGenerator(2,'data/brainTIF/trainNew','image','label',save_to_dir = None)
model = unet()
model_checkpoint = ModelCheckpoint('unet_brainTest_e10_s5.hdf5',
monitor='loss')
model.fit_generator(myGene,steps_per_epoch=5,epochs=10,callbacks = [model_checkpoint])
testGene = testGenerator("data/brainTIF/test3")
results = model.predict_generator(testGene,18,verbose=1)
saveResult("data/brainTIF/test_results3",results)
As an option for class_weight for binary classes, you can also handle imbalanced classes using Synthetic Oversampling Technique (SMOTE), increasing the size of the minority group:
from imblearn.over_sampling import SMOTE
sm = SMOTE()
x, y = sm.fit_sample(X_train, Y_train)

Error when checking target: expected conv2d_29 to have 4 dimensions, but got array with shape (1255, 12)

I would like to train a deep learning model, where input image shape is (224,224,3) . And I would like to feed them into a u-net model.
After training I get the error : Error when checking target: expected conv2d_29 to have 4 dimensions, but got array with shape (1255, 12)
I'm confused since I'm sure the image array and label has no issue. Is the issue within the model? How should I resolve this?
The model is as below:
#def unet(pretrained_weights = None, input_size = (224,224,3)):
concat_axis = 3
input_size= Input((224,224,3))
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(input_size)
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv1)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
#flat1 = Flatten()(pool1)
conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool1)
conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv2)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool2)
conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv3)
pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool3)
conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv4)
drop4 = Dropout(0.5)(conv4)
pool4 = MaxPooling2D(pool_size=(2, 2))(drop4)
conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool4)
conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv5)
drop5 = Dropout(0.5)(conv5)
up_conv5 = UpSampling2D(size=(2, 2), data_format="channels_last")(conv5)
ch, cw = get_crop_shape(conv4, up_conv5)
crop_conv4 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv4)
up6 = concatenate([up_conv5, crop_conv4], axis=concat_axis)
conv6 = Conv2D(256, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(up6)
conv6 = Conv2D(256, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(conv6)
up_conv6 = UpSampling2D(size=(2, 2), data_format="channels_last")(conv6)
ch, cw = get_crop_shape(conv3, up_conv6)
crop_conv3 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv3)
up7 = concatenate([up_conv6, crop_conv3], axis=concat_axis)
conv7 = Conv2D(128, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(up7)
conv7 = Conv2D(128, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(conv7)
up_conv7 = UpSampling2D(size=(2, 2), data_format="channels_last")(conv7)
ch, cw = get_crop_shape(conv2, up_conv7)
crop_conv2 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv2)
up8 = concatenate([up_conv7, crop_conv2], axis=concat_axis)
conv8 = Conv2D(64, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(up8)
conv8 = Conv2D(64, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(conv8)
up_conv8 = UpSampling2D(size=(2, 2), data_format="channels_last")(conv8)
ch, cw = get_crop_shape(conv1, up_conv8)
crop_conv1 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv1)
up9 = concatenate([up_conv8, crop_conv1], axis=concat_axis)
conv9 = Conv2D(32, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(up9)
conv9 = Conv2D(32, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(conv9)
model = Model(inputs = input_size, outputs = conv9)
Since the model output's layer is conv layer, the output shape has 4 dimensions(Batch_size, width, height, channels). But you are feeding an array of shape (1255, 12). If the target label has a shape of (Batch_size, num_features) then the last layer's output should have a shape of (None, 12) or (Batch_size, 12).
You have two options to deal with this situation.
Using dense layer after flattening the output of conv layer
Reshaping the output of conv layer to have the desired shape.
The choice depends on the problem you're dealing with. If the problem is classification, option one could be used to add softmax activation. With option 1 the modification to the code would be,
conv9 = Conv2D(32, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(conv9)
flatten1 = Flatten()(conv9)
dense1 = Dense(12, activation="softmax")(flatten1) # The choice of the activation depends on the problem you are dealing with.
model = Model(inputs = input_size, outputs = dense1)
With option 2, the modification would be
conv9 = Conv2D(32, (3, 3), padding="same", activation="relu", kernel_initializer = 'he_normal')(conv9)
reshape1 = Reshape((12,)(conv9) # The choice of the activation depends on the problem you are dealing with.
model = Model(inputs = input_size, outputs = reshape1)
N.B: When the Reshape layer is used to reshape tensor to (None, 12) shape be sure that the product of the output shape of the previous layer should be divisible by 12.

NoneType' object has no attribute '_inbound_nodes

hi I have been struggling to address this problem, while I cannot really figure it out. I will appreciate any suggestion for my peculiar situation. Thank you very much! My network structure is as following:
def get_unet(self):
inputs = Input((self.img_rows, self.img_cols, 1))
conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(inputs)
conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv1)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool1)
conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv2)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool2)
conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv3)
pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool3)
conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv4)
drop4 = Dropout(0.5)(conv4)
pool4 = MaxPooling2D(pool_size=(2, 2))(drop4)
conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool4)
conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv5)
drop5 = Dropout(0.5)(conv5)
up6 = Conv2D(512, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
UpSampling2D(size=(2, 2))(drop5))
print("drop4 shape",type(drop4),drop4.shape)
print("up6 shape",type(up6),up6.shape)
merge6=tf.concat([drop4, up6], axis=3)
print(merge6.shape)
conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge6)
conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv6)
up7 = Conv2D(256, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
UpSampling2D(size=(2, 2))(conv6))
print("conv3,up7",conv3.shape,up7.shape)
merge7 =tf.concat([conv3, up7],axis=3)
conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge7)
conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv7)
up8 = Conv2D(128, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
UpSampling2D(size=(2, 2))(conv7))
print("conv2,up8",conv2.shape,up8.shape)
merge8 = tf.concat([conv2, up8],axis=3)
conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge8)
conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv8)
up9 = Conv2D(64, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
UpSampling2D(size=(2, 2))(conv8))
print("conv1,up9",conv1.shape,up9.shape)
merge9 = tf.concat([conv1, up9], axis=3)
print("merge9 shape",merge9.shape)
conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge9)
conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv9)
conv9 = Conv2D(2, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv9)
conv10 = Conv2D(1, 1, activation='sigmoid')(conv9)
print("conv10 shape",conv10.shape)
print("inputs shape1,outputs conv10 shape2",inputs.shape,conv10.shape)
model = Model(inputs=inputs, outputs=conv10)
model.compile(optimizer=Adam(lr=1e-4), loss='binary_crossentropy', metrics=['accuracy'])
print('model compile')
return model
this is the error:
model = Model(inputs=inputs, outputs=conv10)
File "/usr/local/lib/python3.5/dist-packages/keras/legacy/interfaces.py", line 91, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 91, in __init__
self._init_graph_network(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 235, in _init_graph_network
self.inputs, self.outputs)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 1412, in _map_graph_network
tensor_index=tensor_index)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 1399, in build_map
node_index, tensor_index)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 1399, in build_map
node_index, tensor_index)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 1399, in build_map
node_index, tensor_index)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 1399, in build_map
node_index, tensor_index)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/network.py", line 1371, in build_map
node = layer._inbound_nodes[node_index]
AttributeError: 'NoneType' object has no attribute '_inbound_nodes'
Replace all your tf.concat() with keras.layers.concatenate(). That's causing the problem. Also, update your keras in case you haven't done it.

Resources