Reputation: 51
The task I am dealing with is multiclass segmentation (0-3 classes on each image). I had a working U-Net model and could train on small dataset just fine, then I augmented the dataset and now I have almost 15k 512x512 grayscale images. I've naturally encountered an issue with not having enough HW resources (RAM, GPU), so I decided to switch to google colab and to go with ImageDataGenerator. I've encountered this issue not being able to solve so far.
InvalidArgumentError: Conv2DSlowBackpropInput: Size of out_backprop doesn't match computed: actual = 16, computed = 32 spatial_dim: 2 input: 64 filter: 2 output: 16 stride: 2 dilation: 1 [[node model/conv2d_transpose_1/conv2d_transpose (defined at /usr/local/lib/python3.7/dist-packages/keras/backend.py:5360) ]] [Op:__inference_train_function_3151]
The only explanation for me is I am not using the generator well. I've structured the data as:
path_to_dataset
│
└───images_dir
│ │
│ └─── images_subdir
│ │ img1.png
│ │ img2.png
│ │ ...
│
└───masks_dir
│ │
│ └─── masks_subdir
│ │ img1.png
│ │ img2.png
│ │ ...
The subdirectories are there to only make ImageDataGenerator work.
data_gen_args = dict(rescale=1./255,)
image_datagen = ImageDataGenerator(**data_gen_args)
mask_datagen = ImageDataGenerator(**data_gen_args)
# image_datagen.fit(images)
# mask_datagen.fit(masks)
# Provide the same seed and keyword arguments to the fit and flow methods
seed = 1
image_generator = image_datagen.flow_from_directory(
'/content/drive/MyDrive/DP/preprocess_images/images/final_ds/orig_folder/',
batch_size=16,
class_mode=None,
# color_mode='grayscale',
seed=seed)
mask_generator = mask_datagen.flow_from_directory(
'/content/drive/MyDrive/DP/preprocess_images/images/final_ds/seg_greyscale_folder/',
batch_size=16,
class_mode=None,
# color_mode='grayscale',
seed=seed)
# combine generators into one which yields image and masks
train_generator = zip(image_generator, mask_generator)
callbacks = [
ModelCheckpoint('unet_512.h5', verbose=1, save_best_only=True),
EarlyStopping(patience=5, monitor='val_loss'),
TensorBoard(log_dir='logs_unet512')
]
history = model.fit(train_generator,
verbose=1,
epochs=50,
callbacks=callbacks,
# class_weight=class_weights,
shuffle=False)
I didn't deal with creating data generator for validation data so far, since I'm not even able to make this part work.
And for the curious ones, here's the model.
# IMG_HEIGHT=512, IMG_WIDTH=512, IMG_CHANNELS=1
inputs = Input((IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS))
s = inputs
# Contraction path
c1 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(s)
c1 = Dropout(0.1)(c1)
c1 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c1)
p1 = MaxPooling2D((2, 2))(c1)
c2 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p1)
c2 = Dropout(0.1)(c2)
c2 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c2)
p2 = MaxPooling2D((2, 2))(c2)
c3 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p2)
c3 = Dropout(0.2)(c3)
c3 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c3)
p3 = MaxPooling2D((2, 2))(c3)
c4 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p3)
c4 = Dropout(0.2)(c4)
c4 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c4)
p4 = MaxPooling2D(pool_size=(2, 2))(c4)
c5 = Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p4)
c5 = Dropout(0.3)(c5)
c5 = Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c5)
# Expansive path
u6 = Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(c5)
u6 = concatenate([u6, c4])
c6 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u6)
c6 = Dropout(0.2)(c6)
c6 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c6)
u7 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(c6)
u7 = concatenate([u7, c3])
c7 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u7)
c7 = Dropout(0.2)(c7)
c7 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c7)
u8 = Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(c7)
u8 = concatenate([u8, c2])
c8 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u8)
c8 = Dropout(0.1)(c8)
c8 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c8)
u9 = Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same')(c8)
u9 = concatenate([u9, c1], axis=3)
c9 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u9)
c9 = Dropout(0.1)(c9)
c9 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c9)
# n_classes=4
outputs = Conv2D(n_classes, (1, 1), activation='softmax')(c9)
model = Model(inputs=[inputs], outputs=[outputs])
Edit: also planning to get the number of filters up, so far I'm running the model that worked before on my personal laptop
Upvotes: 2
Views: 779
Reputation: 51
I didn't find a way to make it work with keras built in implementations, however custom generator does the trick. Seems like most of the tasks are handled very well, but multiclass semantic segmentation will be added, hopefully, some day
Upvotes: 0