keras сегментация InvalidArgumentError: несовместимые формы: [32,256,256,3] против [32,256,256,4]

#python #tensorflow #keras #unity3d-unet #semantic-segmentation

#python #тензорный поток #keras #семантическая сегментация

Вопрос:

Я пытаюсь обучить UNET, чтобы обнаружить повреждения дороги после стихийного бедствия. Мои образы есть 256x256x3 , а маски есть 256x256x1 . Пиксели соответствуют 4 классам: 0 = фон, 1 = нет поврежденной дороги, 2 = поврежденная дорога и 3 = листва деревьев, мешающая обзору. Это выглядит примерно так — (на изображении видно только 3 класса):

пример кортежа

У меня есть эти изображения в папках со следующей структурой. У меня также есть данные проверки в той же структуре

 -- train images
   -- img
      -- 1.png
      -- 2.png
-- train masks
   -- img
      -- 1_mask.png
      -- 2_mask.png
 

Мои генераторы данных train и validation следующие

 image_data_gen = image.ImageDataGenerator(rotation_range = 40, horizontal_flip = True,
                                          vertical_flip = True, zoom_range = 0.2,
                                          shear_range = 0.2,width_shift_range = 0.2,
                                          height_shift_range = 0.2)
mask_data_gen = image.ImageDataGenerator(rotation_range = 40, horizontal_flip = True,
                                          vertical_flip = True, zoom_range = 0.2,
                                          shear_range = 0.2,width_shift_range = 0.2,
                                          height_shift_range = 0.2)
validimg_data_gen = image.ImageDataGenerator()
validmask_data_gen = image.ImageDataGenerator()


image_array_gen = image_data_gen.flow_from_directory(directory=train_images_path, class_mode = None,
                                   target_size = (256,256), seed = 909)
mask_array_gen = mask_data_gen.flow_from_directory(directory=train_segs_path, class_mode = None,
                                   target_size = (256,256), seed = 909)
valid_image_array_gen = validimg_data_gen.flow_from_directory(directory= val_images_path, class_mode = None,
                                   target_size = (256,256), seed = 909)
valid_mask_array_gen = validmask_data_gen.flow_from_directory(directory= val_segs_path, class_mode = None,
                                   target_size = (256,256), seed = 909)

# combine generators into one which yields image and masks
train_generator = zip(image_array_gen, mask_array_gen)
valid_generator = zip(valid_image_array_gen, valid_mask_array_gen)
 

Я понимаю, что, поскольку это проблема сегментации, class_mode должно быть None . Когда я запускаю указанную выше ячейку Found x images belonging to 1 classes. , появляется сообщение, где x — количество обучающих и проверочных изображений, которые у меня есть во вложенной папке «img». Я думаю, что ошибка может заключаться в том, что у меня есть мои данные во вложенных папках «img», и keras считает, что все изображения соответствуют классу img, когда на самом деле существует 4 класса пикселей. Но если я помещу свои данные в папки train images и train masks, я получу сообщение Found 0 images belonging to 0 classes.

Когда я пытаюсь обучить свою модель, results = model.fit_generator(train_generator, steps_per_epoch=int(train_samples/batch_size),epochs=30, validation_data=valid_generator,validation_steps=int(valid_samples/batch_size)) я получаю ошибку:

 InvalidArgumentError:  Incompatible shapes: [32,256,256,3] vs. [32,256,256,4]
     [[node gradient_tape/categorical_crossentropy/mul/BroadcastGradientArgs (defined at <ipython-input-120-22f04a70298f>:3) ]] [Op:__inference_train_function_19597]

Function call stack:
train_function
 

Код, который я использовал для определения модели, находится в конце этого вопроса. Обратите внимание, что если я изменю последний слой conv10 = Conv2D(1, 1, activation = 'softmax')(conv9) , ошибка исчезнет, и обучение будет выполнено без проблем. Также я думаю, что ошибка может заключаться в том, что у меня есть мои данные во вложенной папке img, но что я могу сделать, чтобы указать модель, в которой классы пикселей равны 4, без этой ошибки?

Модель

 def unet(pretrained_weights = None,input_size = (256,256,3)):
    inputs = Input(input_size)
    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))
    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(4, 1, activation = 'softmax')(conv9)
    
    model = Model(inputs = inputs, outputs = conv10)
    return(model)


model = unet() 
model.compile(optimizer='adam', loss='categorical_crossentropy' ,metrics=['categorical_accuracy'])
 

Ответ №1:

ваш train_images _path должен быть путем к каталогу, который содержит подкаталоги класса. То же самое для других каталогов, которые вы используете в потоке из каталога.Например, если у вас есть структура каталогов, как показано ниже, для классификации собак и кошек

  c:
  ---train_images
     ---img
        --- cats
        --- dogs
then in flow from directory your path would be
r'c:train_imagesimg'
 

поток из каталога создаст классы cats и dogs

Комментарии:

1. Я понимаю, что для классификации изображений именно так и должно быть сделано, однако я пытаюсь семантическую сегментацию, где все классы могут встречаться в любом изображении. Так что это не так просто, как иметь папку для кошек, а другую для собак, нужно классифицировать каждый пиксель как принадлежащий к тому или иному классу

2. ОК неправильно понял вопрос