【问题标题】:Correct way of doing data augmentation in TensorFlow with the dataset api?使用数据集 api 在 TensorFlow 中进行数据增强的正确方法?
【发布时间】:2017-12-12 20:48:09
【问题描述】:

所以,我一直在使用 TensorFlow 数据集 API 来加载图像和分割掩码(用于语义分割项目),我希望能够生成批量图像和掩码,每个图像都有随机经历了亮度变化,对比度变化,裁剪,饱和度变化等预处理功能的任意组合。所以,我批次中的第一张图像可能没有预处理,第二张可能有饱和度变化,第三张可能有亮度和饱和度和很快。

我尝试了以下方法:

import tensorflow as tf
from tensorflow.contrib.data import Dataset, Iterator
import random


def _resize_image(image, mask):
    image = tf.image.resize_bicubic(image, [480, 640], True)
    mask = tf.image.resize_bicubic(mask, [480, 640], True)
    return image, mask

def _corrupt_contrast(image, mask):
    image = tf.image.random_contrast(image, 0, 5)
    return image, mask


def _corrupt_saturation(image, mask):
    image = tf.image.random_saturation(image, 0, 5)
    return image, mask


def _corrupt_brightness(image, mask):
    image = tf.image.random_brightness(image, 5)
    return image, mask


def _random_crop(image, mask):
    seed = random.random()
    image = tf.random_crop(image, [240, 320, 3], seed=seed)
    mask = tf.random_crop(mask, [240, 320, 1], seed=seed)
    return image, mask


def _flip_image_horizontally(image, mask):
    seed = random.random()
    image = tf.image.random_flip_left_right(image, seed=seed)
    mask = tf.image.random_flip_left_right(mask, seed=seed)

    return image, mask


def _flip_image_vertically(image, mask):
    seed = random.random()
    image = tf.image.random_flip_up_down(image, seed=seed)
    mask = tf.image.random_flip_up_down(mask, seed=seed)

    return image, mask


def _normalize_data(image, mask):
    image = tf.cast(image, tf.float32)
    image = image / 255.0

    mask = tf.cast(mask, tf.float32)
    mask = mask / 255.0

    return image, mask


def _parse_data(image_paths, mask_paths):
    image_content = tf.read_file(image_paths)
    mask_content = tf.read_file(mask_paths)

    images = tf.image.decode_png(image_content, channels=3)
    masks = tf.image.decode_png(mask_content, channels=1)

    return images, masks


def data_batch(image_paths, mask_paths, params, batch_size=4, num_threads=2):
    # Convert lists of paths to tensors for tensorflow
    images_name_tensor = tf.constant(image_paths)
    mask_name_tensor = tf.constant(mask_paths)

    # Create dataset out of the 2 files:
    data = Dataset.from_tensor_slices(
        (images_name_tensor, mask_name_tensor))

    # Parse images and labels
    data = data.map(
        _parse_data, num_threads=num_threads, output_buffer_size=6 * batch_size)

    # Normalize images and masks for vals. between 0 and 1
    data = data.map(_normalize_data, num_threads=num_threads, output_buffer_size=6 * batch_size)

    if params['crop'] and not random.randint(0, 1):
        data = data.map(_random_crop, num_threads=num_threads,
                    output_buffer_size=6 * batch_size)

    if params['brightness'] and not random.randint(0, 1):
        data = data.map(_corrupt_brightness, num_threads=num_threads,
                    output_buffer_size=6 * batch_size)

    if params['contrast'] and not random.randint(0, 1):
        data = data.map(_corrupt_contrast, num_threads=num_threads,
                    output_buffer_size=6 * batch_size)

    if params['saturation'] and not random.randint(0, 1):
        data = data.map(_corrupt_saturation, num_threads=num_threads,
                    output_buffer_size=6 * batch_size)

    if params['flip_horizontally'] and not random.randint(0, 1):
        data = data.map(_flip_image_horizontally,
                    num_threads=num_threads, output_buffer_size=6 * batch_size)

    if params['flip_vertically'] and not random.randint(0, 1):
        data = data.map(_flip_image_vertically, num_threads=num_threads,
                    output_buffer_size=6 * batch_size)

    # Shuffle the data queue
    data = data.shuffle(len(image_paths))

    # Create a batch of data
    data = data.batch(batch_size)

    data = data.map(_resize_image, num_threads=num_threads,
                    output_buffer_size=6 * batch_size)

    # Create iterator
    iterator = Iterator.from_structure(data.output_types, data.output_shapes)

    # Next element Op
    next_element = iterator.get_next()

    # Data set init. op
    init_op = iterator.make_initializer(data)

    return next_element, init_op

但是由此返回的所有批次都应用了相同的转换,而不是不同的组合,我的猜测是 random.randint 仍然存在,并且实际上并没有为每个批次运行,如果是这样,我该如何解决这个问题想要的结果? 有关我打算如何使用它的示例(我觉得这与问题无关,但人们可能仍然想知道)可以找到here

【问题讨论】:

  • random_crop 设置seed 参数是否保证imagemask 以相同(一致)的方式裁剪?
  • @RohanSaxena 至少在理论上应该,但我注意到,在 GPU 上运行此代码时,有时它们没有以相同的方式裁剪,可能是因为一些多线程问题,我现在更喜欢先将两个张量沿深度连接,然后裁剪它们,然后再次沿深度解包。这可确保两者都在相同的空间维度上进行裁剪。

标签: python-3.x tensorflow tensorflow-datasets


【解决方案1】:

所以问题确实是带有 if 语句的控制流带有 Python 变量,并且只在创建图形时执行一次,为了做我想做的事情,我必须定义一个包含布尔值的占位符是否应用函数的值(并在每次迭代中输入一个新的布尔张量以更改增强),并且控制流由 tf.cond 处理。如果有人感兴趣,我将新代码推送到我在上述问题中发布的 GitHub 链接。

【讨论】:

  • 您也可以使用介于 0 和 1 之间的 tf.random_uniform 并使用阈值在图中随机化。
  • 那么当您在_flip_left_right 中执行tf.image.random_flip_left_right(image, seed=self.seed) 时,您多久更换一次种子?在更改种子之前,您不会对所有图像再次进行相同的翻转吗?
  • 另外,使用图级种子的人可能对github.com/tensorflow/tensorflow/issues/35682感兴趣
  • 添加到我的第一条评论:这与我想象的完全不同。显然,tf.random.uniform((),0,1,seed=1); tf.random.uniform((),0,1,seed=1)tf.random.set_seed(1); tf.random.uniform((),0,1); tf.random.uniform((),0,1) 不同:前者返回两个不同的数字,后者返回两个相同的数字。但如果是这样,你如何确保cond_crop_imagecond_crop_mask 是相同的?对我来说,看起来好像可以裁剪图像,而与此同时,可能没有裁剪蒙版。
  • 其实你是对的,我遇到了错误裁剪的问题。现在我要做的是沿深度连接图像和蒙版。裁剪这个新张量,然后沿深度解包以取回图像和蒙版。这种方式不需要同步,因为只有一个作物命令作物两者。我只是没有更新我在上面链接中发布的代码。
猜你喜欢
  • 2023-03-22
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 2020-10-14
  • 1970-01-01
  • 2021-01-14
  • 1970-01-01
  • 2018-10-21
相关资源
最近更新 更多