我正在阅读 TensorFlow 中的代码 benchmarks repo .以下代码是从 TFRecord 文件创建 TensorFlow 数据集的部分:
ds = tf.data.TFRecordDataset.list_files(tfrecord_file_names)
ds = ds.apply(interleave_ops.parallel_interleave(tf.data.TFRecordDataset, cycle_length=10))
我正在尝试更改此代码以直接从 JPEG 图像文件创建数据集:
ds = tf.data.Dataset.from_tensor_slices(jpeg_file_names)
ds = ds.apply(interleave_ops.parallel_interleave(?, cycle_length=10))
我不知道该写什么?地方。 parallel_interleave() 中的 map_func 是 tf.data.TFRecordDataset 类的 __init__() 对于 TFRecord 文件,但是我不知道对于 JPEG 文件要写什么。
我们不需要在这里做任何转换。因为我们将压缩两个数据集,然后再进行转换。代码如下:
counter = tf.data.Dataset.range(batch_size)
ds = tf.data.Dataset.zip((ds, counter))
ds = ds.apply( \
batching.map_and_batch( \
map_func=preprocess_fn, \
batch_size=batch_size, \
num_parallel_batches=num_splits))
因为我们不需要在 ?地方,我尝试使用一个空的 map_func,但出现错误“map_func必须返回一个
Dataset` 对象”。我也尝试过使用 tf.data.Dataset,但输出显示 Dataset 是一个不允许放在那里的抽象类。
有人可以帮忙吗?非常感谢。
最佳答案
parallel_interleave
当您有一个将源 数据集的每个元素转换为多个元素到目标 数据集的转换时非常有用。我不确定他们为什么在基准 repo 中使用它,而他们本可以使用 map
并行调用。
这是我建议使用 parallel_interleave
的方式用于从多个目录读取图像,每个目录包含一个类:
classes = sorted(glob(directory + '/*/')) # final slash selects directories only
num_classes = len(classes)
labels = np.arange(num_classes, dtype=np.int32)
dirs = DS.from_tensor_slices((classes, labels)) # 1
files = dirs.apply(tf.contrib.data.parallel_interleave(
get_files, cycle_length=num_classes, block_length=4, # 2
sloppy=False)) # False is important ! Otherwise it mixes labels
files = files.cache()
imgs = files.map(read_decode, num_parallel_calls=20)\. # 3
.apply(tf.contrib.data.shuffle_and_repeat(100))\
.batch(batch_size)\
.prefetch(5)
分为三个步骤。首先,我们获取目录列表及其标签 (#1
)。
然后,我们将这些映射到文件数据集。但是如果我们做一个简单的 .flatmap()
, 我们将以标签 0
的所有文件结束, 然后是标签 1
的所有文件, 然后 2
等等...然后我们需要非常大的洗牌缓冲区来获得有意义的洗牌。
因此,我们改为应用 parallel_interleave
(#2
)。这是 get_files()
:
def get_files(dir_path, label):
globbed = tf.string_join([dir_path, '*.jpg'])
files = tf.matching_files(globbed)
num_files = tf.shape(files)[0] # in the directory
labels = tf.tile([label], [num_files, ]) # expand label to all files
return DS.from_tensor_slices((files, labels))
使用 parallel_interleave
确保 list_files
每个目录的并行运行,所以到第一个 block_length
文件从第一个目录开始列出,第一个 block_length
第二个目录中的文件也将可用(也可以从第三个、第四个等)。此外,生成的数据集将包含每个标签的交错 block ,例如1 1 1 1 2 2 2 2 3 3 3 3 3 1 1 1 1 ...
(对于 3 个类和 block_length=4
)
最后,我们从文件列表 (#3
) 中读取图像。这是 read_and_decode()
:
def read_decode(path, label):
img = tf.image.decode_image(tf.read_file(path), channels=3)
img = tf.image.resize_bilinear(tf.expand_dims(img, axis=0), target_size)
img = tf.squeeze(img, 0)
img = preprocess_fct(img) # should work with Tensors !
label = tf.one_hot(label, num_classes)
img = tf.Print(img, [path, label], 'Read_decode')
return (img, label)
此函数采用图像路径及其标签,并为每个路径返回一个张量:路径的图像张量和标签的 one_hot 编码。这也是您可以对图像进行所有转换的地方。在这里,我会调整大小和进行基本的预处理。
关于python - 如何在 TensorFlow 中使用 parallel_interleave,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50046505/