数据增强图像数据生成器 Keras 语义分割

Posted

技术标签:

【中文标题】数据增强图像数据生成器 Keras 语义分割【英文标题】:Data Augmentation Image Data Generator Keras Semantic Segmentation 【发布时间】:2016-11-04 11:32:51 【问题描述】:

我正在使用 Keras 在一些图像数据上拟合全卷积网络以进行语义分割。但是,我遇到了一些过度拟合的问题。我没有那么多数据,我想做数据扩充。但是,由于我想做逐像素分类,我需要任何增强功能,如翻转、旋转和移位,以同时应用于特征图像和标签图像。理想情况下,我想使用 Keras ImageDataGenerator 进行即时转换。但是,据我所知,您无法对特征数据和标签数据进行等效转换。

有谁知道是否是这种情况,如果不是,有没有人有任何想法?否则,我将使用其他工具创建一个更大的数据集,然后一次性输入。

谢谢!

【问题讨论】:

我遇到了完全相同的问题,我也想到了ImageDataGenerator,但没有找到任何解决方案。所以我自己做了:-( 请问您最终在此过程中使用了什么工具来确保对特征和数据应用相同的转换? 您可以通过创建自己的批处理生成器来相对轻松地做到这一点,您可以在其中以相同的方式增加输入/输出,然后调用model.train_on_batch。确保自己打乱数据,因为这通常由 model.fit 处理。 我自己的 java 代码应用于批处理,或批处理 + 基本事实。 【参考方案1】:

有一些工作正在扩展 ImageDataGenerator 以使其更灵活地处理这些类型的情况(参见this issue on Github 中的示例)。

此外,正如 Mikael Rousson 在 cmets 中所提到的,您可以轻松地自己创建自己的 ImageDataGenerator 版本,同时利用它的许多内置函数来简化它。这是我用于图像去噪问题的示例代码,其中我使用随机裁剪 + 加性噪声来动态生成干净和嘈杂的图像对。您可以轻松地对其进行修改以添加其他类型的增强。之后,您可以使用Model.fit_generator 使用这些方法进行训练。

from keras.preprocessing.image import load_img, img_to_array, list_pictures

def random_crop(image, crop_size):
    height, width = image.shape[1:]
    dy, dx = crop_size
    if width < dx or height < dy:
        return None
    x = np.random.randint(0, width - dx + 1)
    y = np.random.randint(0, height - dy + 1)
    return image[:, y:(y+dy), x:(x+dx)]

def image_generator(list_of_files, crop_size, to_grayscale=True, scale=1, shift=0):
    while True:
        filename = np.random.choice(list_of_files)
        try:
            img = img_to_array(load_img(filename, to_grayscale))
        except:
            return
        cropped_img = random_crop(img, crop_size)
        if cropped_img is None:
            continue
        yield scale * cropped_img - shift
def corrupted_training_pair(images, sigma):
    for img in images:
        target = img
        if sigma > 0:
            source = img + np.random.normal(0, sigma, img.shape)/255.0
        else:
            source = img
        yield (source, target)
def group_by_batch(dataset, batch_size):
    while True:
        try:
            sources, targets = zip(*[next(dataset) for i in xrange(batch_size)])
            batch = (np.stack(sources), np.stack(targets))
            yield batch
        except:
            return
def load_dataset(directory, crop_size, sigma, batch_size):
    files = list_pictures(directory)
    generator = image_generator(files, crop_size, scale=1/255.0, shift=0.5)
    generator = corrupted_training_pair(generator, sigma)
    generator = group_by_batch(generator, batch_size)
    return generator

然后你可以像这样使用上面的:

train_set = load_dataset('images/train', (patch_height, patch_width), noise_sigma, batch_size)
val_set = load_dataset('images/val', (patch_height, patch_width), noise_sigma, batch_size)
model.fit_generator(train_set, samples_per_epoch=batch_size * 1000, nb_epoch=nb_epoch, validation_data=val_set, nb_val_samples=1000)

【讨论】:

在 Keras 中使用数据生成器时流函数有什么作用? 流函数用于从文件目录或numpy数组创建数据生成器。但是,这与这个问题或我的回答无关。我建议您针对您的确切问题打开一个新问题,而不是作为对不相关问题答案的评论。【参考方案2】:

是的,你可以。这是 Keras 文档中的一个示例。您将使用相同种子播种的两个生成器和 fit_generator 压缩在一起。 https://keras.io/preprocessing/image/

# we create two instances with the same arguments 
data_gen_args = dict(featurewise_center=True,
                     featurewise_std_normalization=True,
                     rotation_range=90.,
                     width_shift_range=0.1,
                     height_shift_range=0.1,
                     zoom_range=0.2) 
image_datagen = ImageDataGenerator(**data_gen_args) 
mask_datagen = ImageDataGenerator(**data_gen_args)

# Provide the same seed and keyword arguments to the fit and flow methods seed = 1 
image_datagen.fit(images, augment=True, seed=seed) 
mask_datagen.fit(masks, augment=True, seed=seed)

image_generator = image_datagen.flow_from_directory(
    'data/images',
    class_mode=None,
    seed=seed)

mask_generator = mask_datagen.flow_from_directory(
    'data/masks',
    class_mode=None,
    seed=seed)

# combine generators into one which yields image and masks 
train_generator = zip(image_generator, mask_generator)

model.fit_generator(
    train_generator,
    samples_per_epoch=2000,
    nb_epoch=50)

【讨论】:

当我尝试将它们压缩在一起时卡住了,你有什么想法吗? train_generator = zip(image_generator, mask_generator)内存限制或永无止境的执行 使用 itertools.izip() 代替,它会为您提供 zip() 的生成器版本 @Dennis 我有一个onehot mask encoding 函数,并希望将所有掩码转换为此编码。我如何/在哪里可以根据mask_generator 调用我的函数? flow_from_directory() 需要子目录代表每个类。只有当你的数据格式用这种方式。或者你必须在使用它之前进行格式化。 我不知道imagesmasks 应该是什么。我知道它们代表输入数据X 和目标数据Y,但我认为XY 正在从生成器中提取出来......嗯。

以上是关于数据增强图像数据生成器 Keras 语义分割的主要内容,如果未能解决你的问题,请参考以下文章

Keras中语义分割的不平衡数据?

语义分割中的数据增强Augmentor基本使用方法(全随机生成和对每张图片均进行一次增强)

图像预处理和数据增强应该如何用于语义分割?

Keras深度学习实战(18)——语义分割详解

Keras图像分割实战:数据整理分割自定义数据生成器模型训练

用于非图像数据格式的多任务学习的 keras 数据生成器