Как сделать пакетный внутренний продукт в Tensorflow?

datascience.stackexchange https://datascience.stackexchange.com/questions/15032

  •  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 это уравнение, представляющее оси, которые будут умножены и суммированы. Основные правила для уравнения:

  1. Входные тензоры описываются с помощью запятой, разделенной строкой измерений.
  2. Повторные метки указывают, что соответствующие размеры будут умножены
  3. Выходной тензор описан другой строкой измерений, представляющих соответствующие входы (или продукты)
  4. Метки, которые отсутствуют в выходной строке, суммируются

В нашем случае, 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.]

Это может быть неоптимальным для больших матриц (см. Обсуждение здесь)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с datascience.stackexchange
scroll top