Как применить увеличение данных в TensorFlow 2.0 после tfds.load ()

Я следую этому руководству.

Он показывает, как загружать наборы данных из новых наборов данных TensorFlow, используя метод tfds.load():

import tensorflow_datasets as tfds    
SPLIT_WEIGHTS = (8, 1, 1)
splits = tfds.Split.TRAIN.subsplit(weighted=SPLIT_WEIGHTS)

(raw_train, raw_validation, raw_test), metadata = tfds.load(
    'cats_vs_dogs', split=list(splits),
    with_info=True, as_supervised=True)

Следующие шаги показывают, как применить функцию к каждому элементу в наборе данных с помощью метода карты:

def format_example(image, label):
    image = tf.cast(image, tf.float32)
    image = image / 255.0
    # Resize the image if required
    image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))
    return image, label

train = raw_train.map(format_example)
validation = raw_validation.map(format_example)
test = raw_test.map(format_example)

Затем для доступа к элементам мы можем использовать:

for features in ds_train.take(1):
  image, label = features["image"], features["label"]

OR

for example in tfds.as_numpy(train_ds):
  numpy_images, numpy_labels = example["image"], example["label"]

Однако в руководстве ничего не говорится об увеличении данных. Я хочу использовать увеличение данных в реальном времени, подобное тому, которое имеет класс ImageDataGenerator от Keras. Я пробовал использовать:

if np.random.rand() > 0.5:
    image = tf.image.flip_left_right(image)

и другие аналогичные функции увеличения в format_example(), но как я могу убедиться, что он выполняет увеличение в реальном времени, а не заменяет исходное изображение в наборе данных?

Я мог бы преобразовать полный набор данных в массив Numpy, передав batch_size=-1 в tfds.load(), а затем используя tfds.as_numpy(), но это загрузило бы все изображения в память, которая не нужна. Я смогу использовать train = train.prefetch(tf.data.experimental.AUTOTUNE), чтобы загрузить достаточно данных для следующего цикла обучения.


person himanshurawlani    schedule 13.03.2019    source источник
comment
Вы также можете увидеть этот ответ, в нем представлены данные после дополнений, чтобы вы могли быть еще более уверены < / b> это работает (и в любом случае пример более убедителен).   -  person Szymon Maszke    schedule 19.04.2019


Ответы (1)


Вы подходите к проблеме с неверного направления.

Сначала загрузите данные, используя, например, tfds.load, cifar10 (для простоты мы будем использовать разбиения по умолчанию TRAIN и TEST):

import tensorflow_datasets as tfds

dataloader = tfds.load("cifar10", as_supervised=True)
train, test = dataloader["train"], dataloader["test"]

(вы можете использовать пользовательские tfds.Split объекты для создания наборов данных проверки или других, см. документацию)

train и test являются tf.data.Dataset объектами, поэтому вы можете использовать map, apply, batch и аналогичные функции для каждого из них.

Ниже приведен пример, в котором я буду (используя tf.image в основном):

  • преобразовать каждое изображение в tf.float64 в диапазоне 0-1 (не используйте этот дурацкий фрагмент из официальных документов, это гарантирует правильный формат изображения)
  • cache() результатов, так как их можно использовать повторно после каждого repeat
  • произвольно переворачивать left_to_right каждое изображение
  • произвольно изменить контраст изображения
  • перемешать данные и пакет
  • ВАЖНО: повторите все шаги, когда набор данных исчерпан. Это означает, что через одну эпоху все вышеупомянутые преобразования применяются снова (кроме тех, которые были кэшированы).

Вот код, выполняющий вышеуказанное (вы можете изменить lambdas на функторы или функции):

train = train.map(
    lambda image, label: (tf.image.convert_image_dtype(image, tf.float32), label)
).cache().map(
    lambda image, label: (tf.image.random_flip_left_right(image), label)
).map(
    lambda image, label: (tf.image.random_contrast(image, lower=0.0, upper=1.0), label)
).shuffle(
    100
).batch(
    64
).repeat()

Такой tf.data.Dataset можно передать непосредственно методам Кераса fit, evaluate и predict.

Проверка того, что это действительно так работает

Я вижу, вы очень подозрительно относитесь к моему объяснению, давайте рассмотрим пример:

1. Получите небольшой набор данных.

Вот один из способов взять один элемент, который, по общему признанию, нечитабелен и не интуитивно понятен, но вас это должно устроить, если вы сделаете что-нибудь с Tensorflow:

# Horrible API is horrible
element = tfds.load(
    # Take one percent of test and take 1 element from it
    "cifar10",
    as_supervised=True,
    split=tfds.Split.TEST.subsplit(tfds.percent[:1]),
).take(1)

2. Повторите данные и проверьте, совпадают ли они:

Используя Tensorflow 2.0, можно обойтись без глупых обходных путей (почти):

element = element.repeat(2)
# You can iterate through tf.data.Dataset now, finally...
images = [image[0] for image in element]
print(f"Are the same: {tf.reduce_all(tf.equal(images[0], images[1]))}")

И это неудивительно:

Are the same: True

3. Проверяйте, отличаются ли данные после каждого повтора со случайным увеличением.

Ниже фрагмент repeats одиночный элемент 5 раз и проверки, которые равны, а какие разные.

element = (
    tfds.load(
        # Take one percent of test and take 1 element
        "cifar10",
        as_supervised=True,
        split=tfds.Split.TEST.subsplit(tfds.percent[:1]),
    )
    .take(1)
    .map(lambda image, label: (tf.image.random_flip_left_right(image), label))
    .repeat(5)
)

images = [image[0] for image in element]

for i in range(len(images)):
    for j in range(i, len(images)):
        print(
            f"{i} same as {j}: {tf.reduce_all(tf.equal(images[i], images[j]))}"
        )

Вывод (в моем случае каждый запуск был бы другим):

0 same as 0: True
0 same as 1: False
0 same as 2: True
0 same as 3: False
0 same as 4: False
1 same as 1: True
1 same as 2: False
1 same as 3: True
1 same as 4: True
2 same as 2: True
2 same as 3: False
2 same as 4: False
3 same as 3: True
3 same as 4: True
4 same as 4: True

Вы также можете преобразовать каждое из этих изображений в numpy и сами увидеть изображения, используя _ 34_, matplotlib.pyplot.imshow или другие альтернативы.

Еще один пример визуализации пополнения данных в реальном времени

Этот ответ предоставляет более полное и удобочитаемое представление об увеличении данных с использованием Tensorboard и MNIST, возможно, вы захотите проверить это (да Бесстыдный штекер, но полезный наверное).

person Szymon Maszke    schedule 09.04.2019
comment
Из документации функции карты здесь: Это преобразование применяется map_func к каждому элементу этого набора данных и возвращает новый набор данных, содержащий преобразованные элементы, в том же порядке, в каком они появились во входных данных. - person himanshurawlani; 13.04.2019
comment
Это действительно так. Отметьте ВАЖНО: часть, которую я добавил только что. По сути, каждое увеличение применяется к каждой части данных (один элемент в этом случае может быть пакетным, если перед ним использовался batch(), так должно быть быстрее) на лету и возвращается с дополнением или без него (если оно случайное). Когда tf.data.Dataset исчерпано и repeat используется (чтобы тренироваться для нескольких эпох / бесконечно), все операции повторяются, за исключением тех, которые мы кэшировали во время первого прохода. Устраняет путаницу? - person Szymon Maszke; 13.04.2019
comment
Итак, как я могу убедиться, что все операции повторяются, когда я использую repeat? - person himanshurawlani; 14.04.2019
comment
Я вижу, ты не очень веришь в tensorflow, я могу это понять. Я добавил пример, в котором сравниваются изображения до и после random_flip_left_right. При желании вы можете сделать свои собственные более обширные тесты таким образом. - person Szymon Maszke; 14.04.2019
comment
Спасибо за пример! После этапа проверки все становится намного яснее. - person himanshurawlani; 15.04.2019