【问题标题】:Keras model - Unet Image SegmentationKeras 模型 - Unet 图像分割
【发布时间】:2018-05-18 15:39:33
【问题描述】:

我正在尝试使用 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 个 epoch,但相反,它会抛出以下错误:

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)

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

谢谢!

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

      【解决方案2】:

      您需要将输入数据重塑为 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)
      

      【讨论】:

        【解决方案3】:

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

        有不同的方法可以改变这个设置,请参考这个:https://keras.io/backend/

        【讨论】:

          猜你喜欢
          • 2018-10-15
          • 2020-04-08
          • 2021-02-26
          • 2019-01-31
          • 2021-11-02
          • 2023-04-01
          • 2020-10-12
          • 2020-05-03
          • 2018-07-25
          相关资源
          最近更新 更多