Как использовать parallel_interleave в TensorFlow - PullRequest
0 голосов
/ 26 апреля 2018

Я читаю код в TensorFlow репозиторий репо . Следующий фрагмент кода является частью, которая создает набор данных TensorFlow из файлов TFRecord:

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))

Я не знаю, что написать в? место. Map_func в parallel_interleave () - это __init __ () класса tf.data.TFRecordDataset для файлов 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 must return a Dataset` object". Я также пытался использовать tf.data.Dataset, но в выводе говорится, что Dataset - это абстрактный класс, который нельзя помещать туда.

Кто-нибудь может помочь этому? Большое спасибо.

1 Ответ

0 голосов
/ 05 июня 2018

parallel_interleave полезно, когда у вас есть преобразование, которое преобразует каждый элемент набора данных source в несколько элементов в набор данных destination . Я не уверен, почему они используют его в репозитории для репозиториев таким образом, когда они могли просто использовать 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 из второго каталога также будут доступны (также с 3-го, 4-го и т.д.). Кроме того, результирующий набор данных будет содержать чередующиеся блоки каждой метки, например, 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 для метки. Это также место, где вы можете сделать все преобразования на изображении. Здесь я делаю изменение размера и базовую предварительную обработку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...