Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

tf.map_fn

Wersja TensorFlow 1 Wyświetl źródło na GitHub

Przekształca elems , stosując fn do każdego elementu spiętrzonego na osi 0. (przestarzałe argumenty)

Używany w notebookach

Używany w przewodniku Używany w samouczkach

Zobacz także tf.scan .

map_fn rozpakowuje elems na osi 0 w celu uzyskania sekwencji elementów; wywołuje fn aby przekształcić każdy element; a następnie układa przekształcone wartości z powrotem.

Funkcje mapowania z wejściami i wyjściami z jednym tensorem

Jeśli elems jest pojedynczym tensorem, a sygnatura fn to tf.Tensor->tf.Tensor , to map_fn(fn, elems) jest równoważne tf.stack([fn(elem) for elem in tf.unstack(elems)]) . Na przykład:

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 .

Funkcje mapowania z wielowarstwowymi wejściami i wyjściami

map_fn obsługuje również funkcje z wielowarstwowymi wejściami i wyjściami:

  • Jeśli elems jest krotką (lub zagnieżdżoną strukturą) tensorów, to wszystkie te tensory muszą mieć ten sam rozmiar wymiaru zewnętrznego ( num_elems ); a fn służy do przekształcania każdej krotki (lub struktury) odpowiednich wycinków z elems . Np. Jeśli elems jest krotką (t1, t2, t3) , to fn jest używany do przekształcenia każdej krotki wycinków (t1[i], t2[i], t3[i]) (gdzie 0 <= i < num_elems ) .

  • Jeśli fn zwraca krotkę (lub zagnieżdżoną strukturę) tensorów, to wynik jest tworzony przez ułożenie w stos odpowiednich elementów z tych struktur.

Określanie sygnatury wyjściowej fn

Jeśli sygnatury wejściowe i wyjściowe fn są różne, to sygnaturę wyjściową należy określić za pomocą funkcji fn_output_signature . (Sygnatury wejściowe i wyjściowe różnią się, jeśli ich struktury, typy dtypów lub typy tensorów nie są zgodne). Na przykład:

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 można określić za pomocą dowolnego z poniższych:

RaggedTensors

map_fn obsługuje wejścia i wyjścia tf.RaggedTensor . W szczególności:

  • Jeśli elems jest RaggedTensor , to fn zostanie wywołane z każdym wierszem tego poszarpanego tensora.

    • Jeśli elems ma tylko jeden wymiar nierówny, to wartości przekazane do fn będą tf.Tensor s.
    • Jeśli elems ma wiele poszarpanych wymiarów, wówczas wartości przekazane do fn będą miały wartość tf.RaggedTensor s o jeden mniej poszarpany wymiar.
  • Jeśli wynik map_fn powinien być RaggedTensor , użyj tf.RaggedTensorSpec aby określić fn_output_signature .

# 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]]>

Na przykład:

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

SparseTensors

map_fn obsługuje wejścia i wyjścia tf.sparse.SparseTensor . W szczególności:

  • Jeśli elems jest SparseTensor , to fn zostanie wywołane z każdym wierszem tego rzadkiego tensora. W szczególności wartość przekazana do fn będzie tf.sparse.SparseTensor z jednym wymiarem mniej niż elems .

  • Jeśli wynik map_fn powinien być SparseTensor , użyj tf.SparseTensorSpec aby określić fn_output_signature . Pojedyncze SparseTensor zwrócone przez fn zostaną umieszczone w jednym SparseTensor o jeszcze jednym wymiarze.

# 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)>
  • Jeśli funkcja jest wyrażalna jako operacje TensorFlow, użyj:
 tf.sparse.SparseTensor(st.indices, fn(st.values), st.dense_shape)
 
  • W przeciwnym razie użyj:
 tf.sparse.SparseTensor(st.indices, tf.map_fn(fn, st.values),
                       st.dense_shape)
 

map_fn a operacje wektoryzowane

map_fn zastosuje operacje używane przez fn do każdego elementu elems , co elems w elems O(elems.shape[0]) operacji. Jest to nieco złagodzone przez fakt, że map_fn może przetwarzać elementy równolegle. Jednak transformacja wyrażona za pomocą map_fn jest zwykle mniej wydajna niż równoważna transformacja wyrażona za pomocą operacji wektoryzowanych.

map_fn powinno być zwykle używane tylko wtedy, gdy spełniony jest jeden z poniższych warunków:

  • Wyrażenie żądanej transformacji za pomocą operacji wektoryzowanych jest trudne lub kosztowne.
  • fn tworzy duże wartości pośrednie, więc równoważna transformacja wektoryzowana zajęłaby zbyt dużo pamięci.
  • Równoległe przetwarzanie elementów jest bardziej wydajne niż równoważna transformacja wektoryzowana.
  • Wydajność transformacji nie jest krytyczna, a użycie map_fn jest bardziej czytelne.

Na przykład podany powyżej przykład, w którym odwzorowuje fn=lambda t: tf.range(t, t + 3) różnych elems można przepisać wydajniej, używając elems wektoryzowanych:

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

W niektórych przypadkach tf.vectorized_map może służyć do automatycznej konwersji funkcji na wektoryzowany ekwiwalent.

Chętna egzekucja

Podczas gorączkowego wykonywania map_fn nie jest wykonywana równolegle, nawet jeśli parallel_iterations ma wartość> 1. Nadal można uzyskać korzyści wydajnościowe wynikające z równoległego uruc