pytorch和Numpy 的广播机制高效计算矩阵之间两两距离
示例:
import torch def pairwise_distance_broadcast(X, Y=None): """ 使用广播机制计算两两欧几里得距离。 参数: X: 第一个张量,形状为 (m, d),表示 m 个 d 维向量。 Y: 第二个张量(可选),形状为 (n, d)。如果为 None,则计算 X 内部的两两距离。 返回: 距离矩阵,形状为 (m, n)。 """ if Y is None: Y = X # 扩展维度以支持广播 X_expanded = X.unsqueeze(1) # 形状为 (m, 1, d) Y_expanded = Y.unsqueeze(0) # 形状为 (1, n, d) # 计算两两距离 distance_matrix = torch.sqrt(torch.sum((X_expanded - Y_expanded) ** 2, dim=2)) # 形状为 (m, n) return distance_matrix # 示例 X = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=torch.float32) Y = torch.tensor([[7.0, 8.0], [9.0, 10.0]], dtype=torch.float32) # 计算 X 和 Y 之间的两两距离 distances = pairwise_distance_broadcast(X, Y) print("X 和 Y 之间的两两距离:") print(distances) # 计算 X 内部的两两距离 internal_distances = pairwise_distance_broadcast(X) print("X 内部的两两距离:") print(internal_distances)
示例:
'''求三维空间中两组点之间的两两距离''' import numpy as np # 第一组点,假设有四个点,位置如下 a = np.array([[ 0, 0, 0], [10,10,10], [20,20,20], [30,30,30]]) # 第二组点,假设有两个点,位置如下 b = np.array([[ 0, 0, 0], [10,10,10]]) # 计算距离 c = a[:, None, :] - b # 用None扩展维度,使其shape变为(4, 1, 3),b的shape是(2, 3), # 然后两个数组相减,此时会用到广播机制。 c的shape:(4, 2, 3) dist = np.sqrt(np.sum(c * c, axis=-1)) print(dist) # 输出如下: # [[ 0. 17.32050808] # [17.32050808 0. ] # [34.64101615 17.32050808] # [51.96152423 34.64101615]]
广播机制的规则可参考:nupmy broadcast (广播)
======================================================================
以下是旧内容:
利用numpy可以很方便的计算两个二维数组之间的距离。二维数组之间的距离定义为:X的维度为(m, c),Y的维度为(n,c),Z为X到Y的距离数组,维度为(m,n)。且Z[0,0]是X[0]到Y[0]的距离。Z(a,b)为X[a]到Y[b]的距离。
例如: 计算 m*2 的矩阵与 n * 2 的矩阵中,m*2 的每一行到 n*2 的两两之间欧氏距离。
''' L2 = sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2) ''' import numpy as np # ============= 方法一:不用循环 ==================== def L2_dist_1(cloud1, cloud2): m, n = len(cloud1), len(cloud2) cloud1 = np.repeat(cloud1, n, axis=0) cloud1 = np.reshape(cloud1, (m, n, -1)) dist = np.sqrt(np.sum((cloud1 - cloud2)**2, axis=2)) return dist # ============= 方法二:用一重循环 ================== def L2_dist_2(cloud1, cloud2): m, n = len(cloud1), len(cloud2) dist = np.zeros((m, n), dtype=np.float) for i in range(m): dist[i, :] = np.sqrt(np.sum((cloud1[i, :] - cloud2)**2, axis=1)) return dist # ============= 方法二:用两重循环 ================== def L2_dist_3(cloud1, cloud2): m, n = len(cloud1), len(cloud2) dist = np.zeros((m, n), dtype=np.float) for i in range(m): for j in range(n): dist[i, j] = np.sqrt(np.sum((cloud1[i, :] - cloud2[j, :])**2, axis=0)) return dist if __name__ == '__main__': a = np.array([[ 0, 0, 0], [10,10,10], [20,20,20], [30,30,30]]) b = np.array([[ 0, 0, 0], [10,10,10]]) print('不用循环:\n', L2_dist_1(a, b)) print('用一重循环:\n', L2_dist_2(a, b)) print('用两重循环:\n', L2_dist_3(a, b))
程序运行结果: