Python 计算TensorFlow中两个输入集合的每对之间的成对距离
我有两个收藏。一个由k维中的m1点和另一个k维中的m2点组成。我需要计算两个集合的每对之间的成对距离 基本上有两个矩阵Am1,k和Bm2,k我需要得到一个矩阵Cm1,m2Python 计算TensorFlow中两个输入集合的每对之间的成对距离,python,tensorflow,Python,Tensorflow,我有两个收藏。一个由k维中的m1点和另一个k维中的m2点组成。我需要计算两个集合的每对之间的成对距离 基本上有两个矩阵Am1,k和Bm2,k我需要得到一个矩阵Cm1,m2 在scipy中,我可以通过使用和选择许多距离度量中的一个来轻松实现这一点,在TF中,我也可以在循环中实现这一点,但我不知道如何通过矩阵操作实现这一点,即使对于欧氏距离也是如此。几个小时后,我终于找到了如何在Tensorflow中实现这一点。我的解决方案只适用于欧氏距离,而且非常冗长。我也没有数学证明(只是大量手工操作,我希望更
在scipy中,我可以通过使用和选择许多距离度量中的一个来轻松实现这一点,在TF中,我也可以在循环中实现这一点,但我不知道如何通过矩阵操作实现这一点,即使对于欧氏距离也是如此。几个小时后,我终于找到了如何在Tensorflow中实现这一点。我的解决方案只适用于欧氏距离,而且非常冗长。我也没有数学证明(只是大量手工操作,我希望更加严格):
这将适用于任意维数的张量(即包含(…,N,d)向量)。请注意,它不是在集合之间(即不象
scipy.space.distance.cdist
),而是在单个向量批中(即象scipy.space.distance.pdist
)
你在找吗?@ParagS.Chandakkar谢谢,但不是。当A和B相同时,这个问题解决了问题。基本上这是我问题的一部分,因为他们计算一个集合中每对之间的成对距离。在这种解决方案中,如果你用
b[j]
替换a[j]
,我想你会得到你想要的,或者我遗漏了什么?唯一需要注意的是,您必须制作大小相同的A
和B
。你可以用较少的行对矩阵进行零填充,然后从结果中丢弃行。@ParagS.Chandakkar我非常怀疑我能做到这一点。即使可以,填充也不理想,因为一个矩阵可以有1000x5,另一个矩阵可以有10x5。用零填充另一个可能不是最好的做法。顺便说一句,看起来我已经找到了怎么做。我的数学目前还不严谨,所以我想验证几分钟。这里有另一个版本:@YaroslavBulatov,我想它会崩溃。一个组中元素之间的距离。我错了吗?啊,说得好。你可以通过将两个矩阵连接成(m1+m2),d形状,然后去掉cdist的对角块,得到cdist的pdist,它的形状是m1,m2,但是我想这比你的approach@YaroslavBulatov顺便提一下你知道如何计算其他指标吗?cosine
和correlation
可以用线性代数表示,因此类似的方法,不确定其他指标。对于一般情况,您可能可以执行以下操作:@function.Defun
定义f(i,j)以计算示例i和示例j之间的度量,然后对所有(i,j)对进行tf.map\u fn
,并重塑结果。就我个人而言,我可能只是使用scipy,然后将结果反馈到tensorflow中
import tensorflow as tf
import numpy as np
from scipy.spatial.distance import cdist
M1, M2, K = 3, 4, 2
# Scipy calculation
a = np.random.rand(M1, K).astype(np.float32)
b = np.random.rand(M2, K).astype(np.float32)
print cdist(a, b, 'euclidean'), '\n'
# TF calculation
A = tf.Variable(a)
B = tf.Variable(b)
p1 = tf.matmul(
tf.expand_dims(tf.reduce_sum(tf.square(A), 1), 1),
tf.ones(shape=(1, M2))
)
p2 = tf.transpose(tf.matmul(
tf.reshape(tf.reduce_sum(tf.square(B), 1), shape=[-1, 1]),
tf.ones(shape=(M1, 1)),
transpose_b=True
))
res = tf.sqrt(tf.add(p1, p2) - 2 * tf.matmul(A, B, transpose_b=True))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print sess.run(res)
import tensorflow as tf
import string
def pdist(arr):
"""Pairwise Euclidean distances between vectors contained at the back of tensors.
Uses expansion: (x - y)^T (x - y) = x^Tx - 2x^Ty + y^Ty
:param arr: (..., N, d) tensor
:returns: (..., N, N) tensor of pairwise distances between vectors in the second-to-last dim.
:rtype: tf.Tensor
"""
shape = tuple(arr.get_shape().as_list())
rank_ = len(shape)
N, d = shape[-2:]
# Build a prefix from the array without the indices we'll use later.
pref = string.ascii_lowercase[:rank_ - 2]
# Outer product of points (..., N, N)
xxT = tf.einsum('{0}ni,{0}mi->{0}nm'.format(pref), arr, arr)
# Inner product of points. (..., N)
xTx = tf.einsum('{0}ni,{0}ni->{0}n'.format(pref), arr, arr)
# (..., N, N) inner products tiled.
xTx_tile = tf.tile(xTx[..., None], (1,) * (rank_ - 1) + (N,))
# Build the permuter. (sigh, no tf.swapaxes yet)
permute = list(range(rank_))
permute[-2], permute[-1] = permute[-1], permute[-2]
# dists = (x^Tx - 2x^Ty + y^Tx)^(1/2). Note the axis swapping is necessary to 'pair' x^Tx and y^Ty
return tf.sqrt(xTx_tile - 2 * xxT + tf.transpose(xTx_tile, permute))