Модель Keras - Unet Image Segmentation

Я пытаюсь воссоздать UNet с использованием API модели Keras, я собрал изображения ячеек и его сегментированную версию, и я пытаюсь обучить модель с ее помощью. При этом я мог загрузить другую ячейку и получить сегментированную версию изображения в качестве прогноза.

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)

Если бы кто-нибудь мог сказать мне, что я сделал не так, каким должен быть код, или указать мне правильное направление, я был бы очень признателен.

Спасибо!


person user3233991    schedule 05.12.2017    source источник


Ответы (3)


Я думаю, что Керас ожидает «последний канал», пока вы передаете изображения в «режиме первого канала».

Есть разные способы изменить этот параметр, см. Здесь: https://keras.io/backend/

person lorenzori    schedule 29.12.2017

Вам нужно изменить форму входных данных так, как ожидает 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)
person Naomi Fridman    schedule 12.11.2019

Я знаю, что вопрос довольно старый, но я все же хочу отдать ему свои 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
person pratsbhatt    schedule 04.07.2020