矢量化计算样本集两两之间的欧氏距离

本文介绍如何使用矩阵操作批量计算样本集内的两两欧氏距离,通过将距离公式转化为内积形式,利用TensorFlow和PyTorch实现高效计算,并提供代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Notes

给定样本集 X = ( x ( 1 ) , … , x ( n ) ) X=(x^{(1)},\dots,x^{(n)}) X=(x(1),,x(n)),求它们两两之间的距离,即距离矩阵 D i j = d ( x ( i ) , x ( j ) ) D_{ij}=d(x^{(i)},x^{(j)}) Dij=d(x(i),x(j))
d ( ⋅ , ⋅ ) d(\cdot,\cdot) d(,) 表示某种距离,常用两种:

  • cosine 距离: 1 − x T y ∥ x ∥ ⋅ ∥ y ∥ 1-\frac{x^Ty}{\parallel x\parallel\cdot\parallel y\parallel} 1xyxTy
  • 欧氏距离(的平方): ∥ x − y ∥ 2 2 \parallel x-y\parallel_2^2 xy22

cosine 距离容易,l2_normalize 之后内积,或者直接用优化内积的方式代替。
但如果用欧氏距离,之前一直不知道怎么用矩阵操作求得距离矩阵。

Euclidean Distance

思路是将欧氏距离拆成内积表示
x = ( x 1 , … , x n ) x=(x_1,\dots,x_n) x=(x1,,xn) y = ( y 1 , … , y n ) y=(y_1,\dots,y_n) y=(y1,,yn),有
∥ x − y ∥ 2 2 = ∑ i = 1 n ( x i − y i ) 2 = ∑ i = 1 n x i 2 − 2 ∑ i = 1 n x i y i + ∑ i = 1 n y i 2 = x T x − 2 x T y + y T y = < x , x > − 2 < x , y > + < y , y > \begin{aligned} \parallel x-y\parallel_2^2 &=\sum_{i=1}^n(x_i-y_i)^2 \\ &=\sum_{i=1}^nx^2_i-2\sum_{i=1}^nx_iy_i+\sum_{i=1}^ny^2_i \\ &=x^Tx-2x^Ty+y^Ty \\ &=<x,x>-2<x,y>+<y,y> \end{aligned} xy22=i=1n(xiyi)2=i=1nxi22i=1nxiyi+i=1nyi2=xTx2xTy+yTy=<x,x>2<x,y>+<y,y>
以一个有两个样本的数据集 X 为例,即: D = [ < x ( 1 ) , x ( 1 ) > < x ( 1 ) , x ( 1 ) > < x ( 2 ) , x ( 2 ) > < x ( 2 ) , x ( 2 ) > ] − 2 [ < x ( 1 ) , x ( 1 ) > < x ( 1 ) , x ( 2 ) > < x ( 2 ) , x ( 1 ) > < x ( 2 ) , x ( 2 ) > ] + [ < x ( 1 ) , x ( 1 ) > < x ( 2 ) , x ( 2 ) > < x ( 1 ) , x ( 1 ) > < x ( 2 ) , x ( 2 ) > ] D = \left[\begin{matrix}<x^{(1)},x^{(1)}> & <x^{(1)},x^{(1)}> \\ <x^{(2)},x^{(2)}> & <x^{(2)},x^{(2)}>\end{matrix}\right] - \\ 2\left[\begin{matrix}<x^{(1)},x^{(1)}> & <x^{(1)},x^{(2)}> \\ <x^{(2)},x^{(1)}> & <x^{(2)},x^{(2)}>\end{matrix}\right] + \\ \left[\begin{matrix}<x^{(1)},x^{(1)}> & <x^{(2)},x^{(2)}> \\ <x^{(1)},x^{(1)}> & <x^{(2)},x^{(2)}>\end{matrix}\right] D=[<x(1),x(1)><x(2),x(2)><x(1),x(1)><x(2),x(2)>]2[<x(1),x(1)><x(2),x(1)><x(1),x(2)><x(2),x(2)>]+[<x(1),x(1)><x(1),x(1)><x(2),x(2)><x(2),x(2)>]
记作: D = A − 2 X T X + A T D=A-2X^TX+A^T D=A2XTX+AT,则 A 就是 X T X X^TX XTX 取对角线元组成列向量,再打横广播出一个 n × n n\times n n×n 矩阵。

Intra-batch

  • 这里只适用与一个样本集内部两两之间的欧氏距离(的平方)
import numpy as np
import tensorflow as tf

X = np.arange(12).reshape(3, 4)

with tf.Session() as sess:
    X = tf.constant(X, dtype='float32')
    print('数据集 X:', sess.run(X))
    xtx = tf.matmul(X, tf.transpose(X))  # 内积
    diag = tf.diag_part(xtx)  # 对角线元
    D = tf.expand_dims(diag, 1) - \
            2. * xtx + \
            tf.expand_dims(diag, 0)
    # D = tf.sqrt(D)  # 开根
    print('距离矩阵 D:', sess.run(D))
  • 输出
数据集 X: [[ 0.  1.  2.  3.]
 [ 4.  5.  6.  7.]
 [ 8.  9. 10. 11.]]
距离矩阵 D: [[  0.  64. 256.]
 [ 64.   0.  64.]
 [256.  64.   0.]]

Inter-batch

当希望求两个样本集 A 和 B 之间,各 A i A_i Ai B j B_j Bj 之间的欧氏距离,稍为改一下:

import torch

def euclidean(a, b, sqrt=False):
    aTa = torch.diag(torch.matmul(a, a.t()))
    bTb = torch.diag(torch.matmul(b, b.t()))
    aTb = torch.matmul(a, b.t())
    D = aTa.view(-1, 1) - 2.0 * aTb + bTb.view(1, -1)
    if sqrt:
        D = torch.sqrt(D)
    return D


A = torch.arange(6).reshape(3, 2)  # 3 个样本的 A
print("A:\n", A)
B = torch.tensor([[8, 9]])  # 1 个样本的 B
print("B:\n", B)

D = euclidean(A, B)
print("距离:\n", D)

输出:

A:
tensor([[0, 1],
        [2, 3],
        [4, 5]])
B:
tensor([[8, 9]])
距离:
tensor([[128.],
        [ 72.],
        [ 32.]])

References

  1. Tensorflow实现Triplet Loss
  2. MarkDown(LaTex) 数学公式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值