Spec-Zone.ru › TensorFlow 2.4

tf.map_fn

Просмотреть исходный код на GitHub

Преобразует elems путём применения fn к каждому элементу, не уложенному на оси 0. (устаревшие аргументы)

tf.map_fn(
    fn, elems, dtype=None, parallel_iterations=None, back_prop=True,
    swap_memory=False, infer_shape=True, name=None, fn_output_signature=None
)
Предупреждение: НЕКОТОРЫЕ АРГУМЕНТЫ УСТАРЕЛИ: (dtype). Они будут удалены в будущей версии. Инструкции по обновлению: Используйте fn_output_signature вместо этого

См. также tf.scan.

map_fn извлекает elems по оси 0, чтобы получить последовательность элементов; вызывает fn для преобразования каждого элемента; и затем складывает преобразованные значения обратно.

Функции сопоставления с входными и выходными данными типа Single-Tensor

Если elems является единственным тензором, и сигнатура fn составляет tf.Tensor->tf.Tensor, тогда map_fn(fn, elems) эквивалентно tf.stack([fn(elem) for elem in tf.unstack(elems)]). Например:

tf.map_fn(fn=lambda t: tf.range(t, t + 3), elems=tf.constant([3, 5, 2]))
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=
  array([[3, 4, 5],
         [5, 6, 7],
         [2, 3, 4]], dtype=int32)>

map_fn(fn, elems).shape = [elems.shape[0]] + fn(elems[0]).shape.

Функции сопоставления с входными и выходными данными с множественной арностью

map_fn также поддерживает функции с входными и выходными данными с множественной арностью:

  • Если elems является кортежем (или вложенной структурой) тензоров, то все эти тензоры должны иметь одинаковый размер внешнего измерения (num_elems); и fn используется для преобразования каждого кортежа (или структуры) соответствующих срезов из elems. Например, если elems является кортежем (t1, t2, t3), тогда fn используется для преобразования каждого кортежа срезов (t1[i], t2[i], t3[i]) (где 0 <= i < num_elems).

  • Если fn возвращает кортеж (или вложенную структуру) тензоров, то результат формируется путём укладки соответствующих элементов из этих структур.

Указание выходной сигнатуры fn

Если сигнатуры ввода и вывода fn отличаются, то выходная сигнатура должна быть указана с помощью fn_output_signature. (Сигнатуры ввода и вывода отличаются, если их структуры, типы данных или типы тензоров не совпадают). Например:

tf.map_fn(fn=tf.strings.length,  # input & output have different dtypes
          elems=tf.constant(["hello", "moon"]),
          fn_output_signature=tf.int32)
<tf.Tensor: shape=(2,), dtype=int32, numpy=array([5, 4], dtype=int32)>
tf.map_fn(fn=tf.strings.join,  # input & output have different structures
          elems=[tf.constant(['The', 'A']), tf.constant(['Dog', 'Cat'])],
          fn_output_signature=tf.string)
<tf.Tensor: shape=(2,), dtype=string,
 numpy=array([b'TheDog', b'ACat'], dtype=object)>

fn_output_signature можно указать любым из следующих способов:

  • Тип данных tf.DType или tf.TensorSpec (для описания tf.Tensor)
  • tf.RaggedTensorSpec (для описания tf.RaggedTensor)
  • tf.SparseTensorSpec (для описания tf.sparse.SparseTensor)
  • Кортеж, список или словарь (возможно, вложенный), содержащие вышеупомянутые типы.

Разреженные тензоры

map_fn поддерживает tf.RaggedTensor входные и выходные данные. В частности:

  • Если elems является RaggedTensor, то fn будет вызываться с каждой строкой этого разреженного тензора.

    • Если у elems есть только одно разреженное измерение, то значения, передаваемые в fn будут tf.Tensor.
    • Если у elems есть несколько разреженных измерений, то значения, передаваемые в fn будут tf.RaggedTensor с одним менее разреженным измерением.
  • Если результат map_fn должен быть RaggedTensor, то используйте tf.RaggedTensorSpec для указания fn_output_signature.

    • Если fn возвращает tf.Tensor с различными размерами, то используйте tf.RaggedTensorSpec с ragged_rank=0 для объединения их в один разреженный тензор (который будет иметь ragged_rank=1).
    • Если fn возвращает tf.RaggedTensor, то используйте tf.RaggedTensorSpec с тем же ragged_rank.
# Example: RaggedTensor input
rt = tf.ragged.constant([[1, 2, 3], [], [4, 5], [6]])
tf.map_fn(tf.reduce_sum, rt, fn_output_signature=tf.int32)
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([6, 0, 9, 6], dtype=int32)>
# Example: RaggedTensor output
elems = tf.constant([3, 5, 0, 2])
tf.map_fn(tf.range, elems,
          fn_output_signature=tf.RaggedTensorSpec(shape=[None],
                                                  dtype=tf.int32))
<tf.RaggedTensor [[0, 1, 2], [0, 1, 2, 3, 4], [], [0, 1]]>
Примечание: map_fn следует использовать только в том случае, если вам нужно отобразить функцию по строкам RaggedTensor. Если вы хотите отобразить функцию по отдельным значениям, то следует использовать:
  • tf.ragged.map_flat_values(fn, rt) (если fn выражается как операция TensorFlow)
  • rt.with_flat_values(map_fn(fn, rt.flat_values)) (в противном случае)

Например:

rt = tf.ragged.constant([[1, 2, 3], [], [4, 5], [6]])
tf.ragged.map_flat_values(lambda x: x + 2, rt)
<tf.RaggedTensor [[3, 4, 5], [], [6, 7], [8]]>

Разреженные тензоры

map_fn поддерживает tf.sparse.SparseTensor входные и выходные данные. В частности:

  • Если elems является SparseTensor, тогда fn будет вызываться с каждой строкой этого разреженного тензора. В частности, значение, передаваемое в fn будет tf.sparse.SparseTensor с одним меньшим измерением, чем elems.

  • Если результат map_fn должен быть SparseTensor, то используйте tf.SparseTensorSpec для указания fn_output_signature. Отдельные SparseTensor возвращаемые fn будут уложены в единый SparseTensor с одним дополнительным измерением.

# Example: SparseTensor input
st = tf.sparse.SparseTensor([[0, 0], [2, 0], [2, 1]], [2, 3, 4], [4, 4])
tf.map_fn(tf.sparse.reduce_sum, st, fn_output_signature=tf.int32)
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([2, 0, 7, 0], dtype=int32)>
# Example: SparseTensor output
tf.sparse.to_dense(
    tf.map_fn(tf.sparse.eye, tf.constant([2, 3]),
              fn_output_signature=tf.SparseTensorSpec(None, tf.float32)))
<tf.Tensor: shape=(2, 3, 3), dtype=float32, numpy=
  array([[[1., 0., 0.],
          [0., 1., 0.],
          [0., 0., 0.]],
         [[1., 0., 0.],
          [0., 1., 0.],
          [0., 0., 1.]]], dtype=float32)>
Примечание: map_fn следует использовать только в том случае, если вам нужно отобразить функцию по строкам SparseTensor. Если вы хотите отобразить функцию по ненулевым значениям, то следует использовать:
  • Если функция выражается как операция TensorFlow, используйте:

    tf.sparse.SparseTensor(st.indices, fn(st.values), st.dense_shape)
    
  • В противном случае, используйте:

    tf.sparse.SparseTensor(st.indices, tf.map_fn(fn, st.values),
                           st.dense_shape)
    

map_fn против векторизованных операций

map_fn применит операции, используемые fn к каждому элементу elems, что приведёт к O(elems.shape[0]) общим операциям. Это несколько смягчается тем фактом, что map_fn может обрабатывать элементы параллельно. Однако преобразование, выраженное с помощью map_fn обычно менее эффективно, чем эквивалентное преобразование, выраженное с использованием векторизованных операций.

map_fn обычно следует использовать только в том случае, если выполняется одно из следующих условий:

  • Трудно или дорого выразить желаемое преобразование с помощью векторизованных операций.
  • fn создаёт большие промежуточные значения, поэтому эквивалентное векторизованное преобразование потребует слишком много памяти.
  • Обработка элементов параллельно более эффективна, чем эквивалентное векторизованное преобразование.
  • Эффективность преобразования не критически важна, и использование map_fn более читабельно.

Например, пример, приведенный выше, отображающий fn=lambda t: tf.range(t, t + 3) по elems может быть переписан более эффективно с помощью векторизованных операций:

elems = tf.constant([3, 5, 2])
tf.range(3) + tf.expand_dims(elems, 1)
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=
  array([[3, 4, 5],
         [5, 6, 7],
         [2, 3, 4]], dtype=int32)>

В некоторых случаях tf.vectorized_map может использоваться для автоматического преобразования функции в эквивалент векторизованной операции.

Выполнение в режиме Eager

При выполнении в режиме Eager, map_fn не выполняется параллельно, даже если parallel_iterations установлено в значение > 1. Вы по-прежнему можете получить преимущества от параллельного выполнения функции, используя декоратор tf.function:

fn=lambda t: tf.range(t, t + 3)
@tf.function
def func(elems):
  return tf.map_fn(fn, elems, parallel_iterations=3)
func(tf.constant([3, 5, 2]))
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=
  array([[3, 4, 5],
         [5, 6, 7],
         [2, 3, 4]], dtype=int32)>
Примечание: если вы используете декоратор tf.function, любой не относящийся к TensorFlow фрагмент Python-кода, который вы могли написать в своей функции, не будет выполнен. Подробнее см. tf.function. Рекомендуется отлаживать без tf.function, но переключаться на него, чтобы получить преимущества от параллельного выполнения map_fn.
Аргументы
fn Выполняемый вызов. Он принимает один аргумент, который будет иметь ту же (возможно, вложенную) структуру, что и elems. Его вывод должен иметь ту же структуру, что и fn_output_signature если она задана; в противном случае он должен иметь ту же структуру, что и elems.
elems Массив или (возможно, вложенная) последовательность массивов, каждый из которых будет разложен по первому измерению. fn будет применено к вложенной последовательности получившихся срезов. elems может содержать разреженные и разбросанные массивы. elems должен состоять как минимум из одного массива.
dtype Устаревшее: эквивалентно fn_output_signature.
parallel_iterations (необязательно) Количество итераций, разрешенных для выполнения параллельно. При построении графа значение по умолчанию равно 10. При выполнении в режиме eager значение по умолчанию установлено в 1.
back_prop (необязательно) Устаревшее: используйте вместо этого tf.stop_gradient. False отключает поддержку обратного распространения.
swap_memory (необязательно) True разрешает обмен памятью между GPU и CPU.
infer_shape (необязательно) False отключает тесты на согласованность форм вывода.
name (необязательно) Префикс имени для возвращаемых массивов.
fn_output_signature Подпись результата fn. Должна быть указана, если подписи входных и выходных данных fn различаются (то есть если их структуры, типы данных или типы массивов не совпадают). fn_output_signature может быть задана любым из следующих способов:
  • Тип tf.DType или tf.TensorSpec (для описания tf.Tensor)
  • Тип tf.RaggedTensorSpec (для описания tf.RaggedTensor)
  • Тип tf.SparseTensorSpec (для описания tf.sparse.SparseTensor)
  • Кортеж, список или словарь (возможно, вложенный), содержащий указанные выше типы.
Возвращаемые значения
Массив или (возможно, вложенная) последовательность массивов. Каждый массив содержит результат применения fn к массивам, разложенным из elems по первому измерению, от первого до последнего. Результат может включать разреженные и разбросанные массивы.
Исключения
TypeError если fn не является вызываемым, или структура результата fn и fn_output_signature не совпадают.
ValueError если длины результата fn и fn_output_signature не совпадают, или если elems не содержит ни одного массива.

Примеры:

elems = np.array([1, 2, 3, 4, 5, 6])
tf.map_fn(lambda x: x * x, elems)
<tf.Tensor: shape=(6,), dtype=int64, numpy=array([ 1,  4,  9, 16, 25, 36])>
elems = (np.array([1, 2, 3]), np.array([-1, 1, -1]))
tf.map_fn(lambda x: x[0] * x[1], elems, fn_output_signature=tf.int64)
<tf.Tensor: shape=(3,), dtype=int64, numpy=array([-1,  2, -3])>
elems = np.array([1, 2, 3])
tf.map_fn(lambda x: (x, -x), elems,
         fn_output_signature=(tf.int64, tf.int64))
(<tf.Tensor: shape=(3,), dtype=int64, numpy=array([1, 2, 3])>,
 <tf.Tensor: shape=(3,), dtype=int64, numpy=array([-1, -2, -3])>)

© 2020 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 3.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/versions/r2.4/api_docs/python/tf/map_fn

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API