Разница между tf.data.Dataset.map () и tf.data.Dataset.apply ()

После недавнего обновления до версии 1.4 Tensorflow включил tf.data в ядро ​​библиотеки. Одна «важная новая функция», описанная в примечаниях к выпуску версии 1.4 это tf.data.Dataset.apply(), который является «методом применения пользовательских функций преобразования. ". Чем это отличается от уже существующего tf.data.Dataset.map()?


person GPhilo    schedule 03.11.2017    source источник


Ответы (4)


Разница в том, что map будет выполнять одну функцию для каждого элемента Dataset отдельно, тогда как apply будет выполнять одну функцию для всего Dataset одновременно (например, _ 5_, приведенный в качестве примера в документации).

Аргумент apply - это функция, которая принимает Dataset и возвращает Dataset, когда аргумент map - это функция, которая принимает один элемент и возвращает один преобразованный элемент.

person Sunreef    schedule 03.11.2017
comment
... Мне было интересно, где была документация по новым функциям для использования с apply. И теперь я вижу, что функции находятся в tf. ** contrib **. Data, а API набора данных был перемещен в tf.data, где я и искал. - person GPhilo; 03.11.2017
comment
Боюсь, я до сих пор не понимаю разницы в практическом плане. map используется для преобразования значений в наборе данных, а apply работает с самим набором данных ... так что apply также может заменить map? - person GPhilo; 03.11.2017
comment
apply используется, когда нужно рассмотреть сразу несколько элементов. Например, если вы хотите создать набор данных со средними значениями пяти последовательных элементов в вашем наборе данных, вы не сможете сделать это с map - person Sunreef; 03.11.2017
comment
Я понимаю! Хорошо, теперь это имеет смысл. Итак, если я понял это правильно, apply может полностью заменить map (потому что, если у него есть доступ ко всем элементам, он также может иметь доступ к ним по одному, как map), но писать функции для apply не так просто, как писать функции которые работают с самими значениями, поэтому мы можем оставить map по практическим соображениям. Имеет ли это смысл? - person GPhilo; 03.11.2017
comment
Я так понимаю, да. Если вы хотите заменить map вызовом apply, тогда ваша функция внутри apply в любом случае должна будет выполнять эквивалент map. - person Sunreef; 03.11.2017

Ответ Sunreef абсолютно правильный. Возможно, вам все еще интересно, почему мы представили Dataset.apply() < / a>, и я подумал, что могу предложить некоторую предысторию.

tf.data API имеет набор основных преобразований, таких как Dataset.map() и Dataset.filter(), которые, как правило, полезны для широкого диапазона наборов данных, вряд ли изменятся и реализованы в виде методов для объекта tf.data.Dataset. В частности, на них распространяются те же гарантии обратной совместимости, что и на другие основные API в TensorFlow.

Однако основной подход немного ограничен. Нам также нужна свобода экспериментировать с новыми преобразованиями перед добавлением их в ядро, а также позволить другим разработчикам библиотек создавать свои собственные преобразования, которые можно использовать повторно. Поэтому в TensorFlow 1.4 мы выделили набор настраиваемых преобразований, которые находятся в tf.contrib.data. В число пользовательских преобразований входят некоторые, обладающие очень специфической функциональностью (например, tf.contrib.data.sloppy_interleave() ), и кое-где, где API все еще находится в разработке (например, _8 _). Первоначально мы реализовали эти пользовательские преобразования как функции от Dataset до Dataset, что отрицательно сказалось на синтаксическом потоке конвейера. Например:

dataset = tf.data.TFRecordDataset(...).map(...)

# Method chaining breaks when we apply a custom transformation.
dataset = custom_transformation(dataset, x, y, z)

dataset = dataset.shuffle(...).repeat(...).batch(...)

Поскольку это казалось обычным шаблоном, мы добавили Dataset.apply() как способ связать основные и пользовательские преобразования в один конвейер:

dataset = (tf.data.TFRecordDataset(...)
           .map(...)
           .apply(custom_transformation(x, y, z))
           .shuffle(...)
           .repeat(...)
           .batch(...))

Это второстепенная функция в общей схеме вещей, но, надеюсь, она помогает сделать tf.data программы более легкими для чтения и библиотеку легче расширять.

person mrry    schedule 03.11.2017
comment
Спасибо!! Это именно то, что я надеялся понять, и то, что мне не хватало, чтобы полностью понять новый интерфейс. Я оставлю ответ @Sunreef помеченным как ответ, но на самом деле два ответа дополняют друг друга. - person GPhilo; 03.11.2017
comment
@mrry, как выполняются map и apply, выполняются ли они для размера пакета каждый раз, когда вы можете следующий элемент итератора, или применяются ко всему набору данных после инициализации графика? Причина, по которой я спрашиваю, заключается в том, что загрузка набора данных, такого как imagenet, может занять намного больше времени, если применяется к каждому пакету, который раз и навсегда для всего набора данных - person Eliethesaiyan; 31.05.2018
comment
@Eliethesaiyan Большинство преобразований в tf.data не имеют состояния и являются потоковыми, что означает, что они могут немедленно возвращать результаты и потреблять мало памяти при работе с большими наборами данных, которые могут не умещаться в памяти. Это означает, что если у вас есть Dataset.repeat() после этих преобразований, они будут выполняться при каждом проходе через данные. Если вы хотите избежать этого, добавьте Dataset.cache() после преобразований, которые вы хотите выполнить один раз. - person mrry; 31.05.2018
comment
@mrry, не могли бы вы предоставить привет мир реализации custom_transformation? - person Marsellus Wallace; 30.11.2018

У меня недостаточно репутации для комментариев, но я просто хотел указать, что вы действительно можете использовать карту для применения к нескольким элементам в наборе данных, вопреки комментариям @sunreef к его собственному посту.

Согласно документации, карта принимает в качестве аргумента

map_func: функция, отображающая вложенную структуру тензоров (имеющую формы и типы, определенные в self.output_shapes и self.output_types) другой вложенной структуре тензоров.

output_shapes определяются набором данных и могут быть изменены с помощью функций API, таких как batch. Так, например, вы можете выполнить пакетную нормализацию, используя только dataset.batch и .map с:

dataset = dataset ...
dataset.batch(batch_size)
dataset.map(normalize_fn)

Похоже, что основная полезность apply() - это когда вы действительно хотите выполнить преобразование всего набора данных.

person zephyrus    schedule 03.11.2017
comment
Ваш вариант использования действительно может быть построен с комбинацией пакета и карты, но карта по-прежнему работает с отдельными значениями набора данных, которые она вызывала (которые в данном случае, конечно, являются пакетами). Apply является более общим, потому что он позволяет, например, иметь пакеты переменной длины, переупорядочивать, группировать и т. Д. @ Sunreef пример group_by_window не может быть воспроизведен с помощью map () (обратите внимание, что это не преобразование, которое нужно обрабатывается для всего набора данных, так как окна могут быть построены постепенно) - person GPhilo; 04.11.2017
comment
Я согласен - опять же, это был больше комментарий, адресованный людям, плохо знакомым с datasetAPI, которые могут не знать, как элемент на самом деле является динамической концепцией, в зависимости от того, как вы определяете набор данных. Это интуитивно понятно, как только вы это понимаете, но мне потребовалось несколько секунд. - person zephyrus; 04.11.2017

Просто аргумент transformation_func из apply() Dataset; аргумент map_func из map() element

person 武状元    schedule 17.04.2021