Keras模型 - Unet图像分割

时间:2017-12-05 03:50:20

标签: python-3.x machine-learning computer-vision keras keras-layer

我正在尝试使用Keras模型API重新创建一个UNet,我收集了单元格的图像,以及它的分段版本,我正在尝试用它训练模型。在这样做时,我可以上传不同的单元格并获得图像的分段版本作为预测。

https://github.com/JamilGafur/Unet

from __future__ import print_function

from matplotlib import pyplot as plt
from keras import losses
import os
from keras.models import Model
from keras.layers import Input, concatenate, Conv2D, MaxPooling2D, Conv2DTranspose
from keras.optimizers import Adam
import cv2
import numpy as np
# training data 
image_location = "C:/Users/JamilG-Lenovo/Desktop/train/"
image = image_location+"image"
label = image_location +"label"


class train_data():

    def __init__(self, image, label):
        self.image = []
        self.label = []
        for file in os.listdir(image):
            if file.endswith(".tif"):
                self.image.append(cv2.imread(image+"/"+file,0))

        for file in os.listdir(label):
            if file.endswith(".tif"):
                #print(label+"/"+file)
                self.label.append(cv2.imread(label+"/"+file,0))

    def get_image(self):
        return np.array(self.image)

    def get_label(self):
        return np.array(self.label)



def get_unet(rows, cols):
    inputs = Input((rows, cols, 1))
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)

    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1)
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)

    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2)
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)
    pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)

    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool3)
    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)
    pool4 = MaxPooling2D(pool_size=(2, 2))(conv4)

    conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool4)
    conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv5)

    up6 = concatenate([Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(conv5), conv4], axis=3)
    conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(up6)
    conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv6)

    up7 = concatenate([Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(conv6), conv3], axis=3)
    conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(up7)
    conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv7)

    up8 = concatenate([Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(conv7), conv2], axis=3)
    conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(up8)
    conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv8)

    up9 = concatenate([Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(conv8), conv1], axis=3)
    conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(up9)
    conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv9)

    conv10 = Conv2D(1, (1, 1), activation='sigmoid')(conv9)

    model = Model(inputs=[inputs], outputs=[conv10])
    model.compile(optimizer=Adam(lr=1e-5), loss = losses.mean_squared_error)

    return model



def main():
    # load all the training images
    train_set = train_data(image, label)
    # get the training image
    train_images = train_set.get_image()
    # get the segmented image
    train_label = train_set.get_label()
    print("type of train_images" + str(type(train_images[0])))
    print("type of train_label" + str(type(train_label[0])))
    print('\n')
    print("shape of train_images" + str(train_images[0].shape))
    print("shape of train_label" + str(train_label[0].shape))


    plt.imshow(train_images[0], interpolation='nearest')
    plt.title("actual image")
    plt.show()

    plt.imshow(train_label[0], interpolation='nearest')
    plt.title("segmented image")
    plt.show()
    # create a UNet (512,512)
    unet = get_unet(train_label[0].shape[0],
                    train_label[0].shape[1])

    # look at the summary of the unet
    unet.summary()
    #-----------errors start here-----------------

    # fit the unet with the actual image, train_images
    # and the output, train_label
    unet.fit(train_images, train_label, batch_size=16, epochs=10)

main()

当我试图运行它时,我希望它适合超过10个时期,但相反,它会抛出以下错误:

File "C:\ProgramData\Anaconda3\lib\site-packages\keras\engine\training.py", 
line 144, in _standardize_input_data str(array.shape))

ValueError: Error when checking input: expected input_5 to have shape (None, 
512, 512, 1) but got array with shape (1, 30, 512, 512)

如果有人能告诉我我做错了什么,代码应该是什么,或者指出我正确的方向,我会非常感激。

谢谢!

3 个答案:

答案 0 :(得分:1)

我认为当您以“频道优先模式”传递图像时,Keras期待“频道最后”。

有多种方法可以更改此设置,请参阅:https://keras.io/backend/

答案 1 :(得分:0)

您需要按照keras期望的方式重塑输入数据:(图像数,行数,列数,1)

添加图像形状的打印输出,这样会更加清晰。

我认为这堂课很多余。只需使用功能,更易于调试。 也许您将图像整理到一个列表中,然后将其转换为数组时,将得到1作为零形状。

image = []
label = []
for file in os.listdir(image):
    if file.endswith(".tif"):
        image.append(cv2.imread(image+"/"+file,0).reshape((row,col,1))

for file in os.listdir(label):
    if file.endswith(".tif"):
        label.append(cv2.imread(label+"/"+file,0)).reshape((row,col,1))

然后

unet.fit(images, label, batch_size=16, epochs=10)

答案 2 :(得分:-1)

我知道这个问题已经很老了,但是我仍然想给我2美分。 首先,我必须指出,您在此处指的体系结构不是U-Net。

U-Net从一个双卷积层开始,每个层都有64个过滤器。在上面的示例中,您的模型架构以32个过滤器大小开始。填充不应该是“相同的”,而应该是“有效的”,还有其他一些问题,例如在将收缩层的输出连接到扩展部分之前没有裁剪收缩层的输出。

您将需要具有以下输入层。

inputs = layers.Input(shape=(512, 512, 1))

您将必须以以下方式构建模型。

model.build(input_shape=(None, 1, 512, 512))

这意味着您将必须以上述方式调整输入方向。 您的Github链接无效,由于您使用变量代替了数字,因此我看不到图像的输入大小。这就是我的猜测。

如果您有兴趣了解实际U-net模型的外观,则可以查看以下代码。

def unet_model():
# declaring the input layer
# Input layer expects an RGB image, in the original paper the network consisted of only one channel.
inputs = layers.Input(shape=(572, 572, 3))
# first part of the U - contracting part
c0 = layers.Conv2D(64, activation='relu', kernel_size=3)(inputs)
c1 = layers.Conv2D(64, activation='relu', kernel_size=3)(c0)  # This layer for concatenating in the expansive part
c2 = layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2), padding='valid')(c1)

c3 = layers.Conv2D(128, activation='relu', kernel_size=3)(c2)
c4 = layers.Conv2D(128, activation='relu', kernel_size=3)(c3)  # This layer for concatenating in the expansive part
c5 = layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2), padding='valid')(c4)

c6 = layers.Conv2D(256, activation='relu', kernel_size=3)(c5)
c7 = layers.Conv2D(256, activation='relu', kernel_size=3)(c6)  # This layer for concatenating in the expansive part
c8 = layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2), padding='valid')(c7)

c9 = layers.Conv2D(512, activation='relu', kernel_size=3)(c8)
c10 = layers.Conv2D(512, activation='relu', kernel_size=3)(c9)  # This layer for concatenating in the expansive part
c11 = layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2), padding='valid')(c10)

c12 = layers.Conv2D(1024, activation='relu', kernel_size=3)(c11)
c13 = layers.Conv2D(1024, activation='relu', kernel_size=3, padding='valid')(c12)

# We will now start the second part of the U - expansive part
t01 = layers.Conv2DTranspose(512, kernel_size=2, strides=(2, 2), activation='relu')(c13)
crop01 = layers.Cropping2D(cropping=(4, 4))(c10)

concat01 = layers.concatenate([t01, crop01], axis=-1)

c14 = layers.Conv2D(512, activation='relu', kernel_size=3)(concat01)
c15 = layers.Conv2D(512, activation='relu', kernel_size=3)(c14)

t02 = layers.Conv2DTranspose(256, kernel_size=2, strides=(2, 2), activation='relu')(c15)
crop02 = layers.Cropping2D(cropping=(16, 16))(c7)

concat02 = layers.concatenate([t02, crop02], axis=-1)

c16 = layers.Conv2D(256, activation='relu', kernel_size=3)(concat02)
c17 = layers.Conv2D(256, activation='relu', kernel_size=3)(c16)

t03 = layers.Conv2DTranspose(128, kernel_size=2, strides=(2, 2), activation='relu')(c17)
crop03 = layers.Cropping2D(cropping=(40, 40))(c4)

concat03 = layers.concatenate([t03, crop03], axis=-1)

c18 = layers.Conv2D(128, activation='relu', kernel_size=3)(concat03)
c19 = layers.Conv2D(128, activation='relu', kernel_size=3)(c18)

t04 = layers.Conv2DTranspose(64, kernel_size=2, strides=(2, 2), activation='relu')(c19)
crop04 = layers.Cropping2D(cropping=(88, 88))(c1)

concat04 = layers.concatenate([t04, crop04], axis=-1)

c20 = layers.Conv2D(64, activation='relu', kernel_size=3)(concat04)
c21 = layers.Conv2D(64, activation='relu', kernel_size=3)(c20)

# This is based on our dataset. The output channels are 3, think of it as each pixel will be classified
# into three classes, but I have written 4 here, as I do padding with 0, so we end up have four classes.
outputs = layers.Conv2D(4, kernel_size=1)(c21)  

model = tf.keras.Model(inputs=inputs, outputs=outputs, name="u-netmodel")
return model