如何在TF2中将ImageDataGenerator与TensorFlow数据集结合使用?



我有一个TF数据集来对猫和狗进行分类:

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)

在示例中,他们使用了一些带有映射函数的图像增强。我想知道这是否也可以用漂亮的ImageDataGenerator类来完成,如下所示:

from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_image_generator = ImageDataGenerator(rescale=1./255) # Generator for our training data
train_data_gen = train_image_generator.flow_from_directory(batch_size=batch_size,
directory=train_dir,
shuffle=True,
target_size=(IMG_HEIGHT, IMG_WIDTH),
class_mode='binary')

我面临的问题是我只能看到 3 种使用ImageDataGenerator的方法:熊猫数据帧、numpy 数组和图像目录。 有没有办法也使用Tensorflow数据集并结合这些方法?

是的,是的,但这有点棘手。
KerasImageDataGenerator适用于numpy.array而不是tf.Tensor,因此我们必须使用 Tensorflow 的numpy_function。这将使我们能够对tf.data.Dataset内容执行操作,就像它是 numpy 数组一样。

首先,让我们声明我们将在数据集上.map的函数(假设您的数据集由图像、标签对组成(:

# We will take 1 original image and create 5 augmented images:
HOW_MANY_TO_AUGMENT = 5
def augment(image, label):
# Create generator and fit it to an image
img_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
img_gen.fit(image)
# We want to keep original image and label
img_results = [(image/255.).astype(np.float32)] 
label_results = [label]
# Perform augmentation and keep the labels
augmented_images = [next(img_gen.flow(image)) for _ in range(HOW_MANY_TO_AUGMENT)]
labels = [label for _ in range(HOW_MANY_TO_AUGMENT)]
# Append augmented data and labels to original data
img_results.extend(augmented_images)
label_results.extend(labels)
return img_results, label_results

现在,为了在tf.data.Dataset中使用此函数,我们必须声明一个numpy_function

def py_augment(image, label):
func = tf.numpy_function(augment, [image, label], [tf.float32, tf.int32])
return func

py_augment可以像以下方式安全使用:

augmented_dataset_ds = image_label_dataset.map(py_augment)

数据集中的image部分现在处于形状状态(HOW_MANY_TO_AUGMENT, image_height, image_width, channels). 要将其转换为简单的(1, image_height, image_width, channels)您可以简单地使用unbatch

unbatched_augmented_dataset_ds = augmented_dataset_ds.unbatch()

所以整个部分看起来像这样:

HOW_MANY_TO_AUGMENT = 5
def augment(image, label):
# Create generator and fit it to an image
img_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
img_gen.fit(image)
# We want to keep original image and label
img_results = [(image/255.).astype(np.float32)] 
label_results = [label]
# Perform augmentation and keep the labels
augmented_images = [next(img_gen.flow(image)) for _ in range(HOW_MANY_TO_AUGMENT)]
labels = [label for _ in range(HOW_MANY_TO_AUGMENT)]
# Append augmented data and labels to original data
img_results.extend(augmented_images)
label_results.extend(labels)
return img_results, label_results
def py_augment(image, label):
func = tf.numpy_function(augment, [image, label], [tf.float32, tf.int32])
return func
unbatched_augmented_dataset_ds = augmented_dataset_ds.map(py_augment).unbatch()
# Iterate over the dataset for preview:
for image, label in unbatched_augmented_dataset_ds:
...

一个想法是你可以创建一个生成器包装函数,该函数使用 tfds 数据集加载批量大小的倍数。然后将这些图像,标签传递给ImageDataGenerator的流方法,该方法将以所需的批量大小生成增强数据。

例如:

def tfds_imgen(ds, imgen, batch_size, batches_per):
for images, labels in ds:
flow_ = imgen.flow(images, labels, batch_size=batch_size)
for _ in range(batches_per):
yield next(flow_)
raw_train_ds = tfds.load(
'cats_vs_dogs', split='train',
batch_size=SOME_MULTIPLE_OF_32,
as_supervised=True)
imgen = ImageDataGenerator(...)
train_ds = tfds_imgen(
raw_train_ds.as_numpy_iterator(), imgen,
batch_size=32, batches_per=SOME_MULTIPLE_OF_32 // 32)

一种方法是通过 keras 预处理层添加数据增强,使增强成为模型的一部分(见这里:https://www.tensorflow.org/tutorials/images/data_augmentation#data_augmentation_2(。

文档中的示例:

data_augmentation = tf.keras.Sequential([
layers.RandomFlip("horizontal_and_vertical"),
layers.RandomRotation(0.2),
])

最新更新