Как сделать пакетный внутренний продукт в Tensorflow?
-
16-10-2019 - |
Вопрос
У меня есть два тензора a:[batch_size, dim]
b:[batch_size, dim]
Анкет Я хочу сделать внутренний продукт для каждой пары в партии, генерируя c:[batch_size, 1]
, куда c[i,0]=a[i,:].T*b[i,:]
. Анкет Как?
Решение
Там нет родного .dot_product
метод Тем не менее, точечный продукт между двумя векторами-это просто умножение элемента, поэтому работает следующий пример:
import tensorflow as tf
# Arbitrarity, we'll use placeholders and allow batch size to vary,
# but fix vector dimensions.
# You can change this as you see fit
a = tf.placeholder(tf.float32, shape=(None, 3))
b = tf.placeholder(tf.float32, shape=(None, 3))
c = tf.reduce_sum( tf.multiply( a, b ), 1, keep_dims=True )
with tf.Session() as session:
print( c.eval(
feed_dict={ a: [[1,2,3],[4,5,6]], b: [[2,3,4],[5,6,7]] }
) )
Вывод:
[[ 20.]
[ 92.]]
Другие советы
Еще один вариант, который стоит проверить, - это [tf.einsum][1]
- это, по сути, упрощенная версия Эйнштейн нотация.
Следуя примерам Нила и Дамкара:
import tensorflow as tf
a = tf.placeholder(tf.float32, shape=(None, 3))
b = tf.placeholder(tf.float32, shape=(None, 3))
c = tf.einsum('ij,ij->i', a, b)
with tf.Session() as session:
print( c.eval(
feed_dict={ a: [[1,2,3],[4,5,6]], b: [[2,3,4],[5,6,7]] }
) )
Первый аргумент einsum
это уравнение, представляющее оси, которые будут умножены и суммированы. Основные правила для уравнения:
- Входные тензоры описываются с помощью запятой, разделенной строкой измерений.
- Повторные метки указывают, что соответствующие размеры будут умножены
- Выходной тензор описан другой строкой измерений, представляющих соответствующие входы (или продукты)
- Метки, которые отсутствуют в выходной строке, суммируются
В нашем случае, ij,ij->i
означает, что наши входные данные будут 2 матрица равной формы (i,j)
, и наш выход будет вектором формы (i,)
.
Как только вы получите его, вы обнаружите, что einsum
обобщает огромное количество других операций:
X = [[1, 2]]
Y = [[3, 4], [5, 6]]
einsum('ab->ba', X) == [[1],[2]] # transpose
einsum('ab->a', X) == [3] # sum over last dimension
einsum('ab->', X) == 3 # sum over both dimensions
einsum('ab,bc->ac', X, Y) == [[13,16]] # matrix multiply
einsum('ab,bc->abc', X, Y) == [[[3,4],[10,12]]] # multiply and broadcast
К сожалению, einsum
Получите симпатичный ударный удар по сравнению с ручным Multiply+снизить. Там, где производительность имеет решающее значение, я определенно рекомендую придерживаться решения Нила.
Принимая диагональ tf.tensordot Также делает то, что вы хотите, если вы устанавливаете ось на например,
[[1], [1]]
Я адаптировал пример Нила Слейтера:
import tensorflow as tf
# Arbitrarity, we'll use placeholders and allow batch size to vary,
# but fix vector dimensions.
# You can change this as you see fit
a = tf.placeholder(tf.float32, shape=(None, 3))
b = tf.placeholder(tf.float32, shape=(None, 3))
c = tf.diag_part(tf.tensordot( a, b, axes=[[1],[1]]))
with tf.Session() as session:
print( c.eval(
feed_dict={ a: [[1,2,3],[4,5,6]], b: [[2,3,4],[5,6,7]] }
) )
который теперь также дает:
[ 20. 92.]
Это может быть неоптимальным для больших матриц (см. Обсуждение здесь)