Тензор потока `map_fn` занимает много времени для выполнения - PullRequest
0 голосов
/ 08 марта 2020

Учитывая тензоры a формы (n, f) и b формы (m, f), я создал функцию для вычисления евклидовых расстояний между этими двумя тензорами

import tensorflow as tf

nr = tf.reduce_sum(tf.square(a), 1)
nw = tf.reduce_sum(tf.square(b), 1)

nr = tf.reshape(nr, [-1, 1])
nw = tf.reshape(nw, [1, -1])
res = nr - 2*tf.matmul(a, b, False, True) + nw
res = tf.argmin(res, axis=1)

Пока все хорошо, код работает немного быстро (я получил лучшую производительность с cKDTree, когда n= 1000, m=1600, f=4, но сейчас это не проблема). Я проверю производительность по сравнению с различными размерами входных данных позже.

В этом примере тензор b - это сплющенная версия тензора ранга 3. Я делаю это, чтобы иметь возможность оценить евклидовы расстояния, используя два тензора с одинаковым рангом (что проще). Но после оценки расстояний мне нужно знать, где в исходном тензоре находится каждый из ближайших элементов. Для этого я создал собственную лямбда-функцию fn для преобразования обратно в тензорные координаты ранга 3.

fn = lambda x: (x//N, x%N)
# This map takes a enormous amount of time
out = tf.map_fn(fn, res, dtype=(tf.int64, tf.int64))
return tf.stack(out, axis=1)

Но, к сожалению, для этого tf.map_fn требуется ОГРОМНОЕ время для запуска, около 300 мс .

Просто для сравнения, если я выполню np.apply_along_axis в наборе данных, который содержит точно те же данные (но массив numpy), объем отпечатка едва заметен, около 50 микросекунды против 300 мс эквивалентного тензорного потока.

Для этого mapping?

TF версии 2.1.0 есть лучшие подходы, и CUDA включен и работает.

Просто добавим немного времени

%timeit eucl_dist_tf_vecmap(R_tf, W_tf)
28.1 ms ± 128 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)


%timeit eucl_dist_tf_nomap(R_tf, W_tf)
2.07 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


%timeit eucl_dist_ckdtree_applyaxis(R, W)  
878 µs ± 2.34 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit eucl_dist_ckdtree_noapplyaxis(R, W)  
817 µs ± 51 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Первые два времени используют показанную здесь пользовательскую функцию: первое с vectorized_map, второе без vectorized_map и stack (накладные расходы на vectorized_map, протестировано.

И последние два раза являются реализациями, основанными на cKDTree Сципи. Первый использует np.apply_along_axis точно так же, как в векторизованной карте. Мы видим, что издержки намного меньше в массиве numpy.

1 Ответ

1 голос
/ 08 марта 2020

Вы можете попробовать tf.vectorized_map. https://www.tensorflow.org/api_docs/python/tf/vectorized_map

Если вам нужно изменить тип данных de, вы можете попробовать изменить значение parallel_iterations в параметрах map_fn, которое по умолчанию равно 1 в режиме ожидания.

...