tf.compat.v1.map_fn
Преобразует elems путём применения fn к каждому элементу, не сложенному по оси 0. (устаревшие аргументы)
tf.compat.v1.map_fn(
fn, elems, dtype=None, parallel_iterations=None, back_prop=True,
swap_memory=False, infer_shape=True, name=None, fn_output_signature=None
)
См. также 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) - A
tf.RaggedTensorSpec(для описанияtf.RaggedTensor) - A
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.
| Args | |
|---|---|
fn | Вызываемый объект для выполнения. Он принимает один аргумент, который будет иметь ту же (возможно вложенную) структуру, что и elems. Его выходные данные должны иметь ту же структуру, что и fn_output_signature , если она предоставлена; в противном случае она должна иметь ту же структуру, что и elems. |
elems | Тензор или (возможно, вложенная) последовательность тензоров, каждый из которых будет извлечён вдоль своего первого измерения. fn будет применяться к вложенной последовательности полученных срезов. elems может включать разреженные и разметённые тензоры. elems должен содержать по крайней мере один тензор. |
dtype | Устарело: Эквивалентно fn_output_signature. |
parallel_iterations | (необязательно) Количество итераций, разрешённых для параллельного выполнения. При построении графа значение по умолчанию составляет 10. При выполнении в режиме eager значение по умолчанию устанавливается в 1. |
back_prop | (необязательно) False отключает поддержку обратного распространения. |
swap_memory | (необязательно) True включает обмен памятью между GPU и CPU. |
infer_shape | (необязательно) False отключает проверки согласованности форм выходных данных. |
name | (необязательно) Префикс имени для возвращаемых тензоров. |
fn_output_signature | Выходная подпись функции fn. Должна быть указана, если подписи ввода и вывода fn отличаются (т.е., если их структуры, типы данных или типы тензоров не совпадают). fn_output_signature можно указать любым из следующих способов:
|
| Возвращает | |
|---|---|
Тензор или (возможно, вложенная) последовательность тензоров. Каждый тензор складывает результаты применения 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/compat/v1/map_fn