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} 1−∥x∥⋅∥y∥xTy
- 欧氏距离(的平方): ∥ x − y ∥ 2 2 \parallel x-y\parallel_2^2 ∥x−y∥22
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}
∥x−y∥22=i=1∑n(xi−yi)2=i=1∑nxi2−2i=1∑nxiyi+i=1∑nyi2=xTx−2xTy+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=A−2XTX+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.]])