【问题标题】:Compute the pairwise distance between each pair of the two collections of inputs in TensorFlow计算 TensorFlow 中两个输入集合的每对之间的成对距离
【发布时间】:2017-05-08 03:00:28
【问题描述】:

我有两个系列。一个由 m1k 维度的点和另一个 m2 点组成k 个维度中的点。我需要计算两个集合中每对之间的成对距离。

基本上有两个矩阵Am1、kBm2 , k 我需要得到一个矩阵Cm1, m2 .

我可以通过使用distance.sdist 轻松地在 scipy 中执行此操作并选择许多距离度量之一,我也可以在 TF 中循环执行此操作,但我什至无法弄清楚如何使用矩阵操作来执行此操作欧几里得距离。

【问题讨论】:

  • 您在寻找this吗?
  • @ParagS.Chandakkar 谢谢你,但没有。当 A 和 B 相同时,该问题解决了问题。基本上这是我的问题的部分案例,因为他们计算了一个集合中每一对之间的成对距离。
  • 在那个解决方案中,如果你用b[j] 替换a[j],我想你会得到你想要的,还是我错过了什么?唯一需要注意的是,您必须使 AB 大小相同。您可以通过用较少的行数对矩阵进行零填充,然后从结果中丢弃这些行。
  • @ParagS.Chandakkar 我非常怀疑我能做到这一点。即使我可以填充也不理想,因为一个矩阵可以有 1000x5,另一个可以有 10x5。用零填充另一个可能不是最好的事情。顺便说一句,看起来我已经找到了方法。我的数学目前不严谨,所以我想验证一下。

标签: python tensorflow


【解决方案1】:

这将适用于任意维度的张量(即包含 (..., N, d) 向量)。请注意,它不在集合之间(即不像scipy.spatial.distance.cdist),而是在一组向量中(即像scipy.spatial.distance.pdist

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

【讨论】:

  • 您的解决方案对我来说很好,只是我有时会从计算中得到 NaN。 sqrt 下的值变为负数。我将 (K, N, N) 维数组传递给函数。
【解决方案2】:

几个小时后,我终于找到了如何在 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)

【讨论】:

  • @YaroslavBulatov 我认为它可以计算pdist。一组元素之间的距离。我错了吗?
  • 啊,好点子。您可以通过将两个矩阵连接成 (m1+m2),d 形状并采用形状为 m1,m2 的 cdist 的非对角块来从 cdist 中取出 pdist,但我想这比您的方法更昂贵
  • @YaroslavBulatov btw,你知道如何计算其他指标吗?
  • cosinecorrelation 可以用线性代数表示,所以类似的方法,不确定其他方法。对于一般情况,也许您可​​以执行以下操作:@function.Defun 定义了计算示例 i 和示例 j 之间的度量的 f(i,j),然后对所有 (i,j) 对执行 tf.map_fn 并重塑结果。就个人而言,虽然我可能只使用 scipy,然后将结果反馈到 tensorflow
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 2012-07-04
  • 2018-06-05
  • 2023-02-01
  • 2021-12-10
相关资源
最近更新 更多