Python 用于U-Net图像分割的Keras图像生成器中的分割验证数据

Python 用于U-Net图像分割的Keras图像生成器中的分割验证数据,python,keras,image-segmentation,Python,Keras,Image Segmentation,我正在尝试训练一个用于图像分割的U-net网络 我克隆了这个存储库(),它有一个U-net的Keras实现 我的数据组织在存储库中的3个文件夹中: 列车/图像:包含原始图像 序列/标签:包含原始图像的遮罩 test/:包含新的原始图像,以查看网络在培训后的性能 我得到了一个可以分段的网络,但它在培训期间不使用验证数据 我希望有一个验证失败,并有一个回调停止培训时,验证失败没有改善 model_checkpoint = ModelCheckpoint('unet_master.hdf5', mon

我正在尝试训练一个用于图像分割的U-net网络

我克隆了这个存储库(),它有一个U-net的Keras实现

我的数据组织在存储库中的3个文件夹中:

列车/图像:包含原始图像

序列/标签:包含原始图像的遮罩

test/:包含新的原始图像,以查看网络在培训后的性能

我得到了一个可以分段的网络,但它在培训期间不使用验证数据

我希望有一个验证失败,并有一个回调停止培训时,验证失败没有改善

model_checkpoint = ModelCheckpoint('unet_master.hdf5', monitor='val_loss',verbose=1, save_best_only=True)
#earlystopping
earlystopping = EarlyStopping(monitor='val_loss', patience=10, verbose=0, mode='min')

callbacks_list = [model_checkpoint,earlystopping]

#load unet function
model=unet()

model.fit_generator(my_generator, validation_data=validation_generator, steps_per_epoch=1000,epochs=5,callbacks=callbacks_list)

my_generator是使用data.py文件中的函数trainGenerator和adjustData预先定义的(请参见末尾)

现在,我正在尝试生成Validation_生成器,但没有成功

我读过这期:

本教程:

但我没办法。 我的问题是理解在我的案例中什么是“数据”。是火车文件夹吗?为什么我必须有一个图像发生器和一个遮罩发生器

我已尝试为图像和遮罩创建一个生成器,并为验证创建另一个生成器,如下所示:

#added 0.3 validation_split to aug_dict
aug_dict = dict(rotation_range=0.2,
                    width_shift_range=0.05,
                    height_shift_range=0.05,
                    shear_range=0.05,
                    zoom_range=0.05,
                    horizontal_flip=True,
                    vertical_flip=True,
                    fill_mode='nearest',
               validation_split=0.3)


image_color_mode='grayscale'
target_size=(256,256)
batch_size=1
save_to_dir=None
seed=1
image_datagen = ImageDataGenerator(**aug_dict)
mask_datagen = ImageDataGenerator(**aug_dict)
validation_datagen = ImageDataGenerator(**aug_dict)


# i removed     class_mode = None, to have it running
image_generator = image_datagen.flow_from_directory(
    train_path,
    color_mode = image_color_mode,
    target_size = target_size,
    subset='training',
    batch_size = batch_size,
    save_to_dir = save_to_dir,
    seed = seed)

mask_generator = mask_datagen.flow_from_directory(
    mask_path,
    color_mode = image_color_mode,
    target_size = target_size,
    subset='training',
    batch_size = batch_size,
    save_to_dir = save_to_dir,
    seed = seed)

train_generator=zip(image_generator,mask_generator)

#function to run the adjustData function
def return_adjusted_generator(train_generator):
    for (img,mask) in train_generator:
        img,mask = adjustData(img,mask,flag_multi_class=False,num_class=2)
        yield (img,mask)
        
my_new_generator=return_adjusted_generator(train_generator)
        
validation_generator = validation_datagen.flow_from_directory(
    train_path,
    class_mode = None,
    color_mode = image_color_mode,
    target_size = target_size,
    subset='validation',
    batch_size = batch_size,
    save_to_dir = save_to_dir,
    seed = seed)
这将产生:

找到了164张属于2类的图片。 找到了164张属于2类的图片。 找到了68张属于2类的图片

然后我跑:

model_checkpoint = ModelCheckpoint('unet_master.hdf5', monitor='val_loss',verbose=1, save_best_only=True)
#added earlystopping
earlystopping = EarlyStopping(monitor='val_loss', patience=10, verbose=1, mode='min')

callbacks_list = [model_checkpoint, earlystopping]

model=unet()

model.fit_generator(my_new_generator, validation_data=validation_generator, steps_per_epoch=20,epochs=1,callbacks=callbacks_list)
我得到的错误是: ValueError:无法将输入数组从形状(256256,1)广播到形状(1)

我知道图像生成器和遮罩生成器是错误的,因为如果我在图像生成器中循环,我会看到图像和遮罩。但我不知道我做错了什么

非常感谢您对如何分割数据进行验证的任何帮助

多谢各位

使用的功能:

def adjustData(img,mask,flag_multi_class,num_class):
    if(flag_multi_class):
        img = img / 255
        mask = mask[:,:,:,0] if(len(mask.shape) == 4) else mask[:,:,0]
        new_mask = np.zeros(mask.shape + (num_class,))
        for i in range(num_class):
            #for one pixel in the image, find the class in mask and convert it into one-hot vector
            #index = np.where(mask == i)
            #index_mask = (index[0],index[1],index[2],np.zeros(len(index[0]),dtype = np.int64) + i) if (len(mask.shape) == 4) else (index[0],index[1],np.zeros(len(index[0]),dtype = np.int64) + i)
            #new_mask[index_mask] = 1
            new_mask[mask == i,i] = 1
        new_mask = np.reshape(new_mask,(new_mask.shape[0],new_mask.shape[1]*new_mask.shape[2],new_mask.shape[3])) if flag_multi_class else np.reshape(new_mask,(new_mask.shape[0]*new_mask.shape[1],new_mask.shape[2]))
        mask = new_mask
    elif(np.max(img) > 1):
        img = img / 255
        mask = mask /255
        mask[mask > 0.5] = 1
        mask[mask <= 0.5] = 0
    return (img,mask)



def trainGenerator(batch_size,train_path,image_folder,mask_folder,aug_dict,image_color_mode = "grayscale",
                    mask_color_mode = "grayscale",image_save_prefix  = "image",mask_save_prefix  = "mask",
                    flag_multi_class = False,num_class = 2,save_to_dir = None,target_size = (256,256),seed = 1):
    '''
    can generate image and mask at the same time
    use the same seed for image_datagen and mask_datagen to ensure the transformation for image and mask is the same
    if you want to visualize the results of generator, set save_to_dir = "your path"
    '''
    image_datagen = ImageDataGenerator(**aug_dict)
    mask_datagen = ImageDataGenerator(**aug_dict)
    image_generator = image_datagen.flow_from_directory(
        train_path,
        classes = [image_folder],
        class_mode = None,
        color_mode = image_color_mode,
        target_size = target_size,
        batch_size = batch_size,
        save_to_dir = save_to_dir,
        save_prefix  = image_save_prefix,
        seed = seed)
    mask_generator = mask_datagen.flow_from_directory(
        train_path,
        classes = [mask_folder],
        class_mode = None,
        color_mode = mask_color_mode,
        target_size = target_size,
        batch_size = batch_size,
        save_to_dir = save_to_dir,
        save_prefix  = mask_save_prefix,
        seed = seed)
    train_generator = zip(image_generator, mask_generator)
    for (img,mask) in train_generator:
        img,mask = adjustData(img,mask,flag_multi_class,num_class)
        yield (img,mask)

def adjustData(img、mask、flag\u multi\u class、num\u class):
如果(标记多类):
img=img/255
掩码=掩码[:,:,:,0]如果(len(mask.shape)==4)其他掩码[:,:,0]
新的掩码=np.0(mask.shape+(num\u类)
对于范围内的i(num_类):
#对于图像中的一个像素,在mask中找到类并将其转换为一个热向量
#索引=np,其中(掩码=i)
#索引掩码=(索引[0]、索引[1]、索引[2]、np.zeros(len(索引[0])、dtype=np.int64)+i如果(len(掩码形状)==4)其他(索引[0]、索引[1]、np.zeros(len(索引[0])、dtype=np int64)+i)
#新屏蔽[索引屏蔽]=1
新的屏蔽[mask==i,i]=1
new_mask=np.Reformate(new_mask,(new_mask.shape[0],new_mask.shape[1]*new_mask.shape[2],new_mask.shape[3])如果标记了multi_类,则为np.Reformate(new_mask,(new_mask.shape[0]*new_mask.shape[1],new_mask.shape[2]))
掩码=新的\u掩码
elif(np.max(img)>1):
img=img/255
掩码=掩码/255
遮罩[遮罩>0.5]=1
面具