tf.map_fn
Преобразует 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
)
Используется в блокнотах
| Используется в руководствах | Используется в учебных материалах |
|---|---|
См. также tf.scan.
map_fn извлекает elems по оси 0, получая последовательность элементов; вызывает fn для преобразования каждого элемента; затем снова объединяет преобразованные значения в тензор.
Функции отображения с одним тензором на входе и выходе
Если 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); для преобразования каждого кортежа (или структуры) соответствующих срезов изelemsиспользуетсяfn. Например, если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.
Немедленное выполнение
При немедленном выполнении 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код Python, не относящийся к TensorFlow, который может быть написан в вашей функции, выполняться не будет. Подробнее см. в разделеtf.function. Рекомендуется отлаживать код безtf.function, а затем включать его, чтобы повысить производительность за счёт параллельного выполненияmap_fn.
| Аргументы | |
|---|---|
fn | Вызываемый объект, который нужно выполнить. Он принимает один аргумент, структура которого (возможно, вложенная) совпадает со структурой elems. Его выходные данные должны иметь ту же структуру, что и fn_output_signature, если она указана; в противном случае структура должна совпадать со структурой elems. |
elems | Тензор или последовательность тензоров (возможно, вложенная), каждый из которых будет разделён по первому измерению. fn будет применена к вложенной последовательности полученных срезов. elems может включать нерегулярные и разреженные тензоры. elems должен содержать как минимум один тензор. |
dtype | Устарело: эквивалентно fn_output_signature. |
parallel_iterations | (необязательно) Количество итераций, которые разрешено выполнять параллельно. При построении графа значение по умолчанию — 10. При немедленном выполнении значение по умолчанию — 1. |
back_prop | (необязательно) Устарело: вместо этого рекомендуется использовать tf.stop_gradient. Значение 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])>) |
© 2022 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 4.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/api_docs/python/tf/map_fn