文章目录
Abstract
本文介绍了一种基于乘积量化的近似最近邻 (ANN) 搜索方法,主要思想是将一个向量空间分解为多个低维子空间的笛卡尔积,然后分别量化每个子空间。最终输入向量由包含其子空间量化索引的短编码表示。进而可以从它们的编码来估计两个原始向量的欧式距离。非对称版本的 pq 量化距离提高了计算精度,因为这种方法可以计算向量和代码之间的近似距离。
最终的实验结果表明,本文中提出的方法用来搜索最近邻是非常有效的,尤其是在待排索引文件系统中。实验利用 SIFT 和 GIFT 特征作为搜索特征得到很好的准确性,且表现比目前三种最新方法要好。该方法的可扩展性在 20 亿个向量数据集上得到了验证。
Introduction
计算高维向量之间的欧氏距离是许多需求的基本要求。然而由于维度的关系,最近邻搜索的计算代价往往是十分高昂的。对于 N 维的欧式空间
R
D
\mathbb{R}^D
RD,问题是在一个有
n
n
n 个向量的有限集合
Y
⊂
R
D
\mathcal{Y}\subset\ \mathbb{R}^D
Y⊂ RD 中找到元素
N
N
(
x
)
\mathrm{NN}(x)
NN(x),以最小化到查询向量(query vector)的距离:
N
N
(
x
)
=
arg
min
y
∈
Y
d
(
x
,
y
)
\mathrm{NN}(x)=\mathop{\arg\min}_{y\in\mathcal{Y}}d(x,y)
NN(x)=argminy∈Yd(x,y)
目前已经提出了击中多维索引方法,如非常流行的 KD-tree 或其他分支定界方法都是用来减少搜索时间。然而,事实证明,对于高维特征来说,这种方法并不比暴力穷举计算距离更有效,后者的复杂度为
O
(
n
D
)
\mathcal{O}(nD)
O(nD)。
目前有大量文献都对上述问题进行优化来提升 ANN 检索的效果。这些算法的思想都是仅仅找到近似最近邻而非概率为 1 的 NN(x)。同时尽管也产生了其它的距离度量方法,但大多数都是致力于研究欧氏距离。因此在本文中,我们考虑了与许多应用相关的欧氏距离。在这方面,目前最流行的 ANN 检索方法是 欧式局部敏感哈希(E2LSH) 方法,它在有限的假设下为搜索质量提供了理论保证,且已经成功应用于局部描述子和 3D 目标索引。然而,对于真实数据,利用向量分布的启发式方法要比 LSH 方法表现更好。这些方法包括随机 KD-trees 和分层 k-means 方法,二者都在 FLANN 选择算法中进行了实现。
通常基于搜索质量和效率之间的权衡来比较 ANN 算法,但是,这种权衡(trade-off) 并没有考虑索引结构的内存要求。像在 E2LSH 的情况下,内存使用量甚至可能会高于原始向量,此外,E2LSH 和 FLANN 都需要根据精确的 L2 距离来进行最后的重排(re-rank) 操作,如果访问速度很重要,则这会要求将索引向量存储在主内存中。上述约束严重限制了这些算法可以处理的向量数据量。知道最近,相关研究人员才提出限制内存使用的方法,对于涉及大量数据的问题,这是一个关键标准。在大规模场景识别中,需要对数百万到数十亿的图像进行索引。在文献[17]中,Torralba 等人用单个全局 GIST 描述子来表示一个图像,该描述子被映射到一个短的二进制编码。在无监督的情况下,学习该映射,使得由汉明距离定义的嵌入空间中的邻域反映了原始特征的欧式空间中的邻域。然后就可以根据编码之间的汉明距离,通过最近邻搜索来近似欧氏距离的最近邻。在文献 [19] 中,谱哈希(SH) 的表现优于受限玻尔兹曼机,boost 以及 LSH 生成的二进制编码。类似的,Jegou 等人的汉明 (Hamming) 嵌入方法使用二进制签名来细化 BOF 图像搜索框架中的量化 SIFT 或 GIFT 描述符。
本文使用了量化方法来构造原始向量的短编码,目标是使用向量到聚类中心的距离来估计原始向量之间的距离,也就是不对查询向量进行量化,而仅对数据库中的向量进行量化。这个操作减少了量化噪声,进而提升了搜索的质量。为了获取精确的距离,必须对量化误差加以限制。因此,聚类中心的总数 k k k 应足够大,例如,对于 64 bits 的编码, k = 2 64 k=2^{64} k=264。而这也就引发了有关如何学习码本和设定向量的几个问题。首先,学习这样的量化器所需要的样本数量是巨大的,即 k k k 倍。其次,算法本身的复杂度也令人望而却步。最终,地球上医用的计算机内存都不足以存储表示聚类中心的浮点值。
分层的 k-means 算法可以提高学习阶段和相应的分配过程的效率,但是上述限制仍然适用,特别是在内存使用和学习集的大小方面。标量量化是另一种选择,但是他们在内存和重构误差之间的权衡方面提供了较差的量化错误属性。晶格量化器 (lattice quantizers) 为均匀的矢量分布提供了更好的量化属性,但是现实中的向量很少能够满足这一条件。实际上,在索引任务重,这些量化器的性能明显比 k-means 要查。在本文中,我们主要关注的是乘积量化器,据我们所知,这种半结构化的量化器在最近邻搜索方法中从未被考虑过。
本文提出的方法优点是双重的,首先,候选的距离数量明显高于汉明嵌入方法,因为这些技术中使用的汉明空间只允许几个不同的距离。其次,作为本文种方法的副产品,我们获取到了预期平方距离的估计值,这是进行 ϵ \epsilon ϵ 半径搜索或使用 Lowe 距离比准则所必须的。使用汉明空间的目的是有效地计算距离,但是需要注意的是,计算汉明距离的最快方法之一是查表。而本文中的方法使用了类似数量的查找表,从而获取了和计算汉明距离相当的效率。
查询向量与所有编码的详尽比较对于非常大的数据集是不现实的,因此,本文引入了一个改进的倒排索引文件结构来快速访问最相关的向量。一个粗略(coarse) 量化器用于实现此反向文件结构,其中与簇(索引)对应的向量存储在相关联的列表中。列表中的向量是由乘积量化计算得到的短编码表示,这里使用的是编码对于剧烈中心的残差矢量。
乘积量化在局部 SIFT 和全局 GIST 描述符上得到了相应验证。与现有技术相比表明,本文中的方法要优于现有的技术方法,特别是谱哈希,汉明嵌入和 FLANN。
本文的组织结构如下。第二节介绍了量化概念以及提出的乘积量化器,第三节介绍了用于 N N \mathrm{NN} NN 搜索的方法,第四节介绍了避免穷举搜索的结构。第五届对我们的方法的参数进行了评估,并与现有的技术进行了比较。
Background: Quantization, Product Quantizer
有关向量量化有大量文献,详细可以参考文献[24]。在本节中,进介绍本文其余部分中使用到的一些符号和概念。
A. Vector quantization
量化是信息论中一个被广泛研究的破坏性的过程,它的目标是减少表示空间的技术,特别是当输入是实值的时候。在形式上,量化器是将 D \mathrm{D} D 维向量 x ∈ R D x\in\mathbb{R}^D x∈RD 映射到向量 q ( x ) ∈ C = { c i ; i ∈ I } q(x)\in\mathcal{C}=\{c_i;i\in\mathcal{I}\} q(x)∈C={ci;i∈I} 的函数 q q q。其中,索引集假定为是有限的: I = 0 , . . . , k − 1 \mathcal{I}=0,...,k-1 I=0,...,k−1。重构值(reproduction) c i c_i ci 称为聚类中心,重构值 C \mathcal{C} C 的集合是大小为 k k k 的码本。
映射到指定索引
i
i
i 的向量集合称为 (Voronoi) 单元(cell),定义如下:
V
i
≜
{
x
∈
R
D
:
q
(
x
)
=
c
i
}
\mathcal{V}_i\triangleq\left\{x\in\mathbb{R}^{\mathrm{D}}:q(x)=c_i\right\}
Vi≜{x∈RD:q(x)=ci}
量化器的
k
k
k 个单元形成
R
D
\mathbb{R}^D
RD 的一个分区(partition)。根据定义,位于相同单元
V
i
\mathcal{V}_i
Vi 中的所有向量都由相同的聚类中心
c
i
c_i
ci 进行重构。一个量化器的质量通常有输入向量
x
x
x 与它的重构值
q
(
x
)
q(x)
q(x) 之间的均方误差来衡量:
M
S
E
(
q
)
=
E
X
[
d
(
q
(
x
)
,
x
)
2
]
=
∫
p
(
x
)
d
(
q
(
x
)
,
x
)
2
d
x
\mathrm{MSE}(q)=\mathbb{E}_{X}\left[d(q(x),x)^2\right]=\int{p(x)d(q(x),x)^2dx}
MSE(q)=EX[d(q(x),x)2]=∫p(x)d(q(x),x)2dx
其中
d
(
x
,
y
)
=
∣
∣
x
−
y
∣
∣
d(x,y)=||x-y||
d(x,y)=∣∣x−y∣∣ 表示向量
x
x
x 和
y
y
y 之间的欧氏距离,
p
(
x
)
p(x)
p(x) 是随机变量
X
X
X 的概率分布函数。对于任意概率分布函数,改用蒙卡特罗抽样法对上述公式 3 进行数值计算,作为大量样本集上
∣
∣
q
(
x
)
−
x
∣
∣
2
||q(x)-x||^2
∣∣q(x)−x∣∣2 的平均值。
为了使量化器是最优的,它必须满足 Lloyd 最优条件,首先,根据欧氏距离将向量
x
x
x 量化为距离其最近的码本中的聚类中心:
q
(
x
)
=
arg
min
c
i
∈
C
d
(
x
,
c
i
)
q(x)=\mathop{\arg\min}_{c_i\in\mathcal{C}}d(x,c_i)
q(x)=argminci∈Cd(x,ci)
因此,这些单元格被超平面分隔。第二个 Lloyd 条件是重构后的向量值必须是
V
o
r
o
n
o
i
Voronoi
Voronoi 单元中所有向量的期望值:
c
i
=
E
X
[
x
∣
i
]
=
∫
V
i
p
(
x
)
x
d
x
c_i=\mathbb{E}_{X}[x|i]=\int_{\mathcal{V}_i}p(x)xdx
ci=EX[x∣i]=∫Vip(x)xdx
Lloyd 量化器对应于 k-means 聚类算法,它通过迭代地将训练集的向量赋值到聚类中心店,并根据赋值的向量重新估计这些中心店,从而找到一个接近最优的 code book。在下文中,我们假设两个 Lloyd 条件均成立,因为我们学习量化器使用的是 k-means 聚类。但是需要注意的是,k-means 只是在量化误差方面找到了局部最优。
下面将要使用的另一个量是用相应的聚类中心
c
i
c_i
ci 重构单元格(cell)
V
i
\mathcal{V}_i
Vi 的向量时,计算得到的均方失真
ξ
(
q
,
c
i
)
\xi(q,c_i)
ξ(q,ci)。用
p
i
=
P
(
q
(
x
)
=
c
i
)
p_i=\mathbb{P}\left(q(x)=c_i\right)
pi=P(q(x)=ci) 表示将一个向量分配给聚类中心
c
i
c_i
ci 的概率,计算公式为:
ξ
(
q
,
c
i
)
=
1
p
i
∫
V
i
d
(
x
,
q
(
x
)
)
2
p
(
x
)
d
x
\xi(q,c_i)=\frac{1}{p_i}\int_{\mathcal{V}_i}{d\left(x,q(x)\right)^2p(x)}dx
ξ(q,ci)=pi1∫Vid(x,q(x))2p(x)dx
可以看出
M
S
E
\mathrm{MSE}
MSE 可以由上面公式导出:
M
S
E
(
q
)
=
∑
i
∈
I
p
i
ξ
(
q
,
c
i
)
\mathrm{MSE}(q)=\sum_{i\in\mathcal{I}}p_i\xi(q,c_i)
MSE(q)=i∈I∑piξ(q,ci)
在不进行任何进一步处理(熵编码)的情况下,存储上述索引值的内存的成本为
⌈
l
o
g
2
k
⌉
\lceil log_2k\rceil
⌈log2k⌉ bits。因此,由于量化器产生的编码都是存储在二进制存储器中,所以对于
k
k
k 使用 2 的幂数值是比较方便的。
B.Product quantizers
让我们考虑一个 128 维的向量,如 SIFT 描述符。用其产生 64 bits 的编码,原向量每个分量"仅"为 0.5 bits,但却会产生 k = 2 64 k=2^{64} k=264 个聚类中心。也正因为如此,Lloyd’s 算法甚至是 HKM 算法都无法使用,因为所需样本的数量和量化器学习的复杂度都是 k k k 的几倍,甚至不可能存储代表 k 个聚类中心的 D × k D\times k D×k 个浮点值。
乘积量化是解决上述问题的有效方法。这是源码编码中的一种常见技术,它允许选择要联合量化的分量数(例如,可以使用强大的 Leech 晶格来对 24 个分量组进行量化)。输入向量
x
x
x 被分为
m
m
m 个不同的子向量
u
j
,
1
≤
j
≤
m
u_j,1\leq j\leq m
uj,1≤j≤m,其中,每个子向量的维度是
D
∗
=
D
/
m
D^*=D/m
D∗=D/m,其中,
D
D
D 是
m
m
m 的整数倍。之后使用
m
m
m 个量化器分别对子空间进行量化。对于给定的向量
x
x
x,有如下变化:
x
1
,
.
.
.
,
x
D
∗
⏟
u
1
(
x
)
,
.
.
.
,
x
D
−
D
∗
+
1
,
.
.
.
,
x
D
⏟
u
m
(
x
)
→
q
1
(
u
1
(
x
)
)
,
.
.
.
,
q
m
(
u
m
(
x
)
)
\underbrace{x_1,...,x_{D^*}}_{u_1(x)},...,\underbrace{x_{D-D^*+1},...,x_{D}}_{u_m(x)}\rightarrow q_1(u_1(x)),...,q_m(u_m(x))
u1(x)
x1,...,xD∗,...,um(x)
xD−D∗+1,...,xD→q1(u1(x)),...,qm(um(x))
其中
q
j
q_j
qj 是第
j
j
j 个子向量的低复杂度的量化器。通过子量化器
q
j
q_j
qj,我们将索引集
I
j
\mathcal{I}_j
Ij、码本
C
j
\mathcal{C}_j
Cj 以及重构值
c
j
,
i
c_{j,i}
cj,i 相关联起来。乘积量化器的重构值由乘积索引集
I
=
I
1
×
.
.
.
×
I
m
\mathcal{I}=\mathcal I_1\times ...\times \mathcal{I}_m
I=I1×...×Im 的元素标识。因此将码本定义为笛卡尔乘积:
C
=
C
1
×
.
.
.
×
C
m
\mathcal{C}=\mathcal{C}_1\times...\times\mathcal{C}_m
C=C1×...×Cm
同时,该集合的聚类中心就是由
m
m
m 个子量化器的聚类中心串联起来所得。从这里开始,我们假定所有的子量化器都有相同的有限个
k
∗
k^*
k∗ 个重构值(聚类中心),在这种前提下,聚类中心的总数由下面公式给出:
k
=
(
k
∗
)
m
k=(k^*)^m
k=(k∗)m
需要注意的是,在极限情况下,即
m
=
D
m=D
m=D,向量
x
x
x 的所有分量都会被单独进行量化,此时乘积量化也就变成了一个标量量化器,其中,原始向量中的每个值相关的量化函数可能不同。
乘积量化器的优势是由几个小的聚类中心集产生一个大的聚类中心集——与子量化器相关的聚类中心集。在使用 Lloyd 算法学习子量化器是,使用的向量数量有限,但是在某种程度上,码本仍然能够适应数据分布来表示原始特征。学习量化器的复杂度是使用维度为 D D D 的 k k k 个聚类中心点进行 k − m e a n s k-means k−means 算法复杂度的 m 倍。
显式地直接存储码本 C \mathcal{C} C 的效率不高,相反的,我们存储所有子量化器的 m × k ∗ m\times k^* m×k∗ 个聚类中心,也就是 m D ∗ k = k ∗ D mD^*k=k*D mD∗k=k∗D 个浮点值。量化原始向量中的一个元素需要 k ∗ D k^*D k∗D 次浮点运算。表 1 总结了与 k-means、HKM 相关资源的需求。可以看出,乘积量显然是唯一一个可以再为较大的 k k k 值建立索引的量化器。
为了在选择常数
k
∗
k^*
k∗ 时能够提供良好的量化特性,每个子向量之间应该有一个能够比较的平均的量(on average, a comparable energy)。确保这一特性的一种方法是在量化之前将向量乘以一个随机正交矩阵,但是,对于大多数向量类型来说,这并不是必须的,而且也不建议这样做。因为连续的分量通常通过构造相互关联,并且可以用相同的子量化器更好地将他们进行量化。由于子空间之间是正交的,因此与乘积量化器相关的平方误差为:
M
S
E
(
q
)
=
∑
j
M
S
E
(
q
j
)
\mathrm{MSE}(q)=\sum_{j}\mathrm{MSE}(q_j)
MSE(q)=j∑MSE(qj)
其中
M
S
E
(
q
j
)
\mathrm{MSE}(q_j)
MSE(qj) 是子量化器
q
j
q_j
qj 相关的平方误差,图1显示了不同
(
m
,
k
∗
)
(m,k^*)
(m,k∗) 组合的
M
S
E
\mathrm{MSE}
MSE 与编码长度的关系,如果
k
∗
k^*
k∗ 是 2 的整数次幂,则编码长度为
l
=
m
l
o
g
2
k
∗
l=m\mathrm{log}_2k^*
l=mlog2k∗。这些曲线是根据一组 128 维 SIFT 特征得到的,更详细的信息可以参考第四节。从图中可以看出,对于固定数量的 bits 数,最好是使用少量的带有多个子聚类中心的子量化器要比使用多个带有少量子聚类中心的子量化器更好。也就是
m
m
m 较小,
k
∗
k^*
k∗ 较大能够有较好的效果。在极限情况,当
m
=
1
m=1
m=1 时,乘积量化将退化为常规的 k-mean 聚类量化。
从表 1 中可以看出, k ∗ k^* k∗ 的增大会导致量化器的计算量随之增大。它们还增加了存储聚类中( k ∗ ∗ D k^**D k∗∗D 个浮点值)的内存使用量,如果聚类中心查找表不能使用 (fit) 高速缓存,则会进一步降低效率。在 m = 1 m=1 m=1 的其工况下,我们不能使用多于 16 bits 来保证这个量化过程成本可控,通常 k ∗ = 256 , m = 8 k^*=256,m=8 k∗=256,m=8 是一个合理的选择。
对上述量化部分进行总结:
- 设数据集有 K K K 个类别,每个样本都是以一个 向量 (vector) 的形式表示,维数为 d d d,将每个样本向量分成 m m m 组;
- 将所有向量的某组分量作为数据集,采用 k-means 算法得到 k ∗ k^* k∗ 个聚类中心,然后运行 m m m 次 k-means 算法,则每组都会产生 k ∗ k^* k∗ 个聚类中心,该组聚类中心记为一个集合;
- 将上述得到的 m m m 个集合做笛卡尔积,从而得到整个数据集的聚类中心。
笛卡尔积:
笛卡尔乘积是指在数学中,两个集合 X 和 Y 的笛卡尔积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能 有序对 的其中一个成员。
from itertools import product for x,y,z in product(['a','b','c'],['d','e'],['m','n']): print(x,y,z)
上述输出为: a d m a d n a e m a e n b d m b d n b e m b e n c d m c d n c e m c e n
Searching with Quantization
最近邻搜索取决于查询向量 (query vector) 和数据库中向量之间的距离,或等效的平方距离。本节介绍的方法是根据向量的量化指标,根据相应的编码技术对向量量化结果进行比较。本节首先解释如何使用乘积量化器来计算距离,然后给出了该距离下的误差统计界限,并给出了平方欧式距离的精确估计。图 2 给出了两种情况的示意:
A. Computing distance using quantized codes
设一个查询向量 (query vector) 为 x x x,数据集内一个向量为 y y y,我们提出了两种方法来计算这两个向量的欧氏距离的估计值,即对称式计算 (SDC) 和非对称式计算 (ADC)。
symmetric distance computation(SDC):
向量
x
x
x 和
y
y
y 都使用其相应的聚类中心代替,即
q
(
x
)
,
q
(
y
)
q(x),q(y)
q(x),q(y)。原始向量间的距离
d
(
x
,
y
)
d(x,y)
d(x,y) 采用公式
d
^
(
x
,
y
)
≜
d
(
q
(
x
)
,
q
(
y
)
)
\hat{d}(x,y)\triangleq d(q(x),q(y))
d^(x,y)≜d(q(x),q(y)) 来计算,该计算方法可以使用乘积量化有效获得:
d
^
(
x
,
y
)
=
d
(
q
(
x
)
,
q
(
y
)
)
=
∑
j
d
(
q
j
(
x
)
,
q
j
(
y
)
)
2
\hat d(x,y)=d(q(x),q(y))=\sqrt{\sum_j{d(q_j(x),q_j(y))^2}}
d^(x,y)=d(q(x),q(y))=j∑d(qj(x),qj(y))2
其中,距离
d
(
c
j
,
i
,
c
j
,
i
i
)
2
d(c_{j,i},c_{j,i^i})^2
d(cj,i,cj,ii)2 可以从第
j
j
j 个子量化器查表获得,每个子量化器的查找表均包含所有的聚类中心对
(
i
,
i
′
)
(i,i^{'})
(i,i′) 之间的平方距离,即共
(
k
∗
)
2
(k^*)^2
(k∗)2 个距离值。
Asymmetric distance compution(ADC):
数据集中的向量
y
y
y 使用相应的聚类中心代替,即
q
(
y
)
q(y)
q(y),但查询向量 (query vector) 则不进行编码操作,原始向量之间的距离
d
(
x
,
y
)
d(x,y)
d(x,y) 采用公式
d
~
(
x
,
y
)
≜
d
(
x
,
q
(
y
)
)
\tilde{d}(x,y)\triangleq d(x,q(y))
d~(x,y)≜d(x,q(y)) 来计算,具体如下所示:
d
~
(
x
,
y
)
=
d
(
x
,
q
(
y
)
)
=
∑
j
d
(
u
j
(
x
)
,
q
j
(
u
j
(
y
)
)
)
2
\tilde{d}(x,y)=d(x,q(y))=\sqrt{\sum_j{d(u_j(x),q_j(u_j(y)))^2}}
d~(x,y)=d(x,q(y))=j∑d(uj(x),qj(uj(y)))2
其中,平方距离
d
(
u
j
(
x
)
,
c
j
,
i
)
2
,
j
=
1...
m
,
i
=
1...
k
∗
d(u_j(x),c_{j,i})^2,j=1...m,i=1...k^*
d(uj(x),cj,i)2,j=1...m,i=1...k∗ 在搜索操作之前进行计算。其中,
u
j
(
x
)
u_j(x)
uj(x) 表示查询向量
x
x
x 的第
j
j
j 个分量。
对于最近邻搜索,实际中并不计算平方根操作,因为平方根函数单调递增,所以平方距离会产生相同的向量排序结果。
对于两种距离的说明:
- SDC:
- 为了提高计算速度,一般会在检索前提前算好 d ( c j , i , c j , i ′ ) d(c_{j,i},c_{j,i^{'}}) d(cj,i,cj,i′),然后在检索时就是进行查表,以 O ( 1 ) \mathcal{O}(1) O(1) 的复杂度计算出结果;
- d ^ ( x , y ) \hat d(x,y) d^(x,y) 是 d ( x , y ) d(x,y) d(x,y) 的近似计算,一般会先用相似计算方法选出 top N 近邻,然后再做 rerank 以拿到最终的近邻排序结果。
- ADC:
- 为了提高计算速度,一般会在检索前提前算好 d ( u j ( x ) , c j , i ) 2 , j = 1... m , i = 1... k ∗ d(u_j(x),c_{j,i})^2,j=1...m,i=1...k^* d(uj(x),cj,i)2,j=1...m,i=1...k∗,然后在检索时就是查表,以 O ( 1 ) \mathcal{O}(1) O(1) 的复杂度查出结果;
- d ~ ( x , y ) \tilde{d}(x,y) d~(x,y) 也是 d ( x , y ) d(x,y) d(x,y) 的近似计算,与 SDC 类似,一般会先用相思计算方法选出 top N 近邻,然后再做 rerank 以拿到最终的近邻排序结果。
表二总结了在共有 n = ∣ Y ∣ n=|\mathcal{Y}| n=∣Y∣ 个向量的数据集 Y \mathcal{Y} Y 总搜索向量 x x x 的 k k k 个最近邻时实际的不同步骤的复杂性。可以看出,SDC 和 ADC 查询的准备成本是相同的,且与数据集大小 n n n 无关。当 n n n 很大时,最耗时的运算是公式 12 和公式 13 中的求和运算。该表中给出的是当所有元素被任意排序且 n > > k n>>k n>>k 时搜索最小的 k k k 个元素的计算复杂度。
SDC 对 ADC 的唯一优势是可以炼制与查询相关的内存使用,因为 SDC 的查询向量是编码后的结果。但这在大多数情况下是无关紧要的,因此这里推荐使用非对称距离进行计算,它使用了相近的复杂度却有更小的损失,在本节的其他部分,我们将会重点介绍 ADC。
B. Analysis of the distance error
在这一小节将分析使用 d ~ ( x , y ) \tilde{d}(x,y) d~(x,y) 距离代替 d ( x , y ) d(x,y) d(x,y) 距离带来的误差。下面的分析并不依赖于乘积量化器才能适用,而是对于所有满足在第二节中的公式 4 和公式 5 的 Lloyd 最优性条件的量化器。
本着用于重构编码的均方误差标准的思想,通过下面的均方距离误差 (MSDE) 来计算距离的误差:
M
S
D
E
(
q
)
≜
∬
(
d
(
x
,
y
)
−
d
~
(
x
,
y
)
)
2
p
(
x
)
d
x
p
(
y
)
d
y
\mathrm{MSDE}(q)\triangleq\iint{\left(d(x,y)-\tilde{d}(x,y)\right)^2p(x)dx\ p(y)dy}
MSDE(q)≜∬(d(x,y)−d~(x,y))2p(x)dx p(y)dy
由三角不等式可知:
d
(
x
,
q
(
y
)
)
−
d
(
y
,
q
(
y
)
)
≤
d
(
x
,
y
)
≤
d
(
x
,
q
(
y
)
)
+
d
(
y
,
q
(
y
)
)
d\left(x,q(y)\right)-d\left(y,q(y)\right)\leq d(x,y)\leq d\left(x,q(y)\right)+d\left(y,q(y)\right)
d(x,q(y))−d(y,q(y))≤d(x,y)≤d(x,q(y))+d(y,q(y))
并且可以等效如下:
(
d
(
x
,
y
)
−
d
(
x
,
q
(
y
)
)
)
2
≤
d
(
y
,
q
(
y
)
)
2
{\left(d(x,y)-d\left(x,q(y)\right)\right)}^2\leq d\left(y,q(y)\right)^2
(d(x,y)−d(x,q(y)))2≤d(y,q(y))2
结合公式 16 和公式 14,可以得到如下结论:
M
S
D
E
(
q
)
≤
∫
p
(
x
)
(
∫
d
(
y
,
q
(
y
)
)
2
p
(
y
)
d
y
)
d
x
\mathrm{MSDE}(q)\leq\int{p(x)\left(\int{d\left(y,q(y)\right)^2p(y)dy}\right)dx}
MSDE(q)≤∫p(x)(∫d(y,q(y))2p(y)dy)dx
KaTeX parse error: Undefined control sequence: \ at position 69: … \ \ \ \ \ \ \ \̲ ̲
其中, M S E ( q ) \mathrm{MSE}(q) MSE(q) 是公式 3 中的量化器 q q q 的均方误差。上述不等式对于任何量化器都成立,而这也就表明我们的方法中估算的距离误差在统计意义上是受与量化器相关的 M S E \mathrm{MSE} MSE。对于对称距离来说,类似的推导表明统计意义上的误差上界是 2 × M S E ( q ) 2\times \mathrm{MSE}(q) 2×MSE(q)。因此,最小化量化误差是有意义的,因为这个标准提供了估算的距离误差的上界。如果对排序最高的向量执行精确的距离计算 (如 LSH中所做的工作),则可以使用量化误差 (而不是选择任意一组元素) 作为标准,动态地选择应用后处理的向量集。
If an exact distance calculation is performed on the highest ranked vectors, as done in LSH [7], the quantization error can be used (instead of selecting an arbitrary set of elements) as a criterion to dynamically select the set of vectors on which the post-processing should be applied.
C.Estimator of the squared distance
如本小节后面所示,使用估计值 d ^ \hat d d^ 或 d ~ \tilde{d} d~ 会导致估计的特征描述子之间的平均距离降低。图 3 显示了查询包含 1000 个 SIFT 向量的数据集中的 某个 SIFT 向量时的距离。它将真实距离用公式 12 和 13 计算的估计值进行比较。我们可以清楚地看到这些距离估计上的偏差,不出意料地,对称版本的距离计算 (SDC) 有更大的偏差。
One can clearly see the bias on these distance estimators. Unsurprisingly, the symmetric version is more sensitive to this bias.
此后,我们计算平方距离的期望值以此来抵消上述偏差。在使用乘积量化的情况下,从子量化器索引 q j ( u j ( y ) ) , j = 1... m q_j\left(u_j(y)\right),j=1...m qj(uj(y)),j=1...m 中得到给定向量 y y y 的近似 q ( y ) q(y) q(y)。量化索引也就指示出了向量 y y y 位于哪个单元格 V i \mathcal{V}_i Vi 内。然后,我们可以计算出 x x x 与一个随机变量 Y Y Y 之间的期望距离的平方 e ~ ( x , q ( y ) ) \tilde e(x,q(y)) e~(x,q(y)),这在我们的非对称距离计算方法中是完全已知的,其中随机变量 Y Y Y 服从 q ( Y ) = q ( y ) = c i q(Y)=q(y)=c_i q(Y)=q(y)=ci ,它表示关于 y y y 知道它的量化指标后所有假设情况。
We can then compute the expected squared distance e ~ ( x , q ( y ) ) \tilde e(x,q(y)) e~(x,q(y)) between x x x, which is fully known in our asymmetric distance computation method, and a random variable $ Y$ , subject to q ( Y ) = q ( y ) = c i q(Y ) = q(y) = c_i q(Y)=q(y)=ci, which represents all the hypothesis on y y y knowing its quantization index.
e ~ ( x , y ) ≜ E Y [ ( x − Y ) 2 ∣ q ( Y ) = c i ] \tilde e(x,y)\triangleq\mathbb E_Y\left[(x-Y)^2|q(Y)=c_i\right] e~(x,y)≜EY[(x−Y)2∣q(Y)=ci]
= ∫ V i ( x − y ) 2 p ( y ∣ i ) d y \ \ \ =\int _{\mathcal{V}_i}(x-y)^2p(y|i)dy =∫Vi(x−y)2p(y∣i)dy
= 1 p i ∫ V i ( x − c i + c i − y ) 2 p ( y ) d y \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\frac{1}{p_i}\int _{\mathcal{V}_i}(x-c_i+c_i-y)^2p(y)dy =pi1∫Vi(x−ci+ci−y)2p(y)dy
利用公式 5 的 Lloyd 条件,推导出平方表达式,并加以观察:
∫
V
i
(
y
−
c
i
)
p
(
y
)
d
y
=
0
\int _{\mathcal{V}_i}(y-c_i)p(y)dy=0
∫Vi(y−ci)p(y)dy=0
从而公式 21 可以简化为:
e
~
(
x
,
y
)
=
(
x
−
q
(
y
)
)
2
+
∫
V
i
(
x
−
y
)
2
p
(
y
∣
q
(
y
)
=
c
i
)
d
y
\tilde{e}(x,y)=(x-q(y))^2+\int _{\mathcal{V}_i}(x-y)^2p(y|q(y)=c_i)dy
e~(x,y)=(x−q(y))2+∫Vi(x−y)2p(y∣q(y)=ci)dy
KaTeX parse error: Undefined control sequence: \ at position 76: … \ \ \ \ \ \ \ \̲ ̲
其中偏差 ξ ( q , q ( y ) ) \xi(q,q(y)) ξ(q,q(y)) 与 y y y 以及其量化后的重构值相关。
对乘积量化应用公式 24,计算向量
x
x
x 和向量
y
y
y 之间的期望距离的平方,我们仅知道量化索引
q
j
(
u
j
(
y
)
)
q_j(u_j(y))
qj(uj(y)),包括将公式 13 修正为:
e
~
(
x
,
y
)
=
d
~
(
x
,
y
)
2
+
∑
j
ξ
j
(
y
)
\tilde{e}(x,y)=\tilde d(x,y)^2+\sum_j{\xi_j(y)}
e~(x,y)=d~(x,y)2+j∑ξj(y)
其中后面的校正项,也就是平均误差:
ξ
j
(
y
)
≜
ξ
(
q
j
,
q
j
(
u
j
(
y
)
)
)
\xi_j(y)\triangleq\xi(q_j,q_j(u_j(y)))
ξj(y)≜ξ(qj,qj(uj(y)))
使用第
j
j
j 个子量化器来将
u
j
(
y
)
u_j(y)
uj(y) 量化为
q
j
(
y
)
q_j(y)
qj(y),这个过程可以通过对
I
j
\mathcal{I}_j
Ij 查表得到。
上述结果同样能够应用到对称距离,也就是将公式中的
x
x
x 和
y
y
y 都使用乘积量化进行编码,对于对称距离来说,我们能够得到如下的结论:
e
~
(
x
,
y
)
=
d
^
(
x
,
y
)
2
+
∑
j
ξ
j
(
x
)
+
∑
j
′
ξ
j
′
(
x
)
\tilde{e}(x,y)=\hat d(x,y)^2+\sum_j{\xi_j(x)}+\sum_{j'}{\xi_{j'}(x)}
e~(x,y)=d^(x,y)2+j∑ξj(x)+j′∑ξj′(x)
Discussion:
图 4 给出了真实距离与公式 13 和公式 25 估计的真实距离之差的概率分布函数。图中的结论已经在大量的 SIFT 描述子上进行了实验。修正后的公式 13 的距离估计偏差明显变小。然而,我们注意到,在这种情况下,校正的偏差会导致估计量的方差变大,这是统计中常见的现象。此外,对于最近邻,修正项可能高于方程 13 的测度,这也就意味着我们会对那些索引稀少的向量进行了乘法。但需要注意的是,修正项与非对称版本中的搜索查询无关。
在我们的实验中,挂插到校正版本的距离平均返回的结果较差,因此,我们提倡将公式 13 用于最近邻搜索。仅当我们对距离本身感兴趣时,校正后的距离版本才有意义。
Non Exhaustive Search
使用乘积量化器的近似最近邻搜索的速度很快(每个距离计算仅需要 m m m 次加法运算),同时显著降低了存储特征描述子的内存需求。然而,搜索是详尽的。该方法在图像全局描述的上下文保持尺度可变,但是,如果每个图像都是由一组本地描述符进行描述,则无法进行彻底的搜索,因为我们需要索引数是一个描述符并执行多个查询。
Nevertheless, the search is exhaustive. The method remains scalable in the context of a global image description [17], [19]. However, if each image is described by a set of local descriptors, an exhaustive search is prohibitive, as we need to index billions of descriptors and to perform multiple queries [20].
为了避免穷举搜索,我们将倒排索引文件系统与非对称距离计算 (IVFADC) 结合在一起。也就是反向文件量化特征描述子,然后将图像索引存储在相应的列表中,具体可以参考图 5 中的”粗量化“ (coarse quantizer) 步骤。这个操作可以快速访问一小部分图像索引,并且被证明在大规模搜索中也可以成功。我们首先为每个描述符添加了一小段编码,而不是仅存储图像索引。在这里,我们用乘积量化器对向量以及其对应的聚类中心之间的差进行编码,如图 5 所示。这种方法为每个特征描述子添加仅几个 bits 的代价,大大加快了搜索速度。此外,由于对餐差进行编码比对向量本身编码更为精确,因此这种策略会稍微提高搜索精度。
A. Coarse quantizer,locally defined product quantizer
与 “Video-Google” 中的方法类似,使用 k-means 学习到一个码本,从而得到一个量化器 q c q_c qc,在下文中称为粗量化器。对于 SIFT 特征描述子来说,与 q c q_c qc 相关的聚类中心的数量 k ’ k’ k’ 通常取 1000 ∼ 1 000 000 1000\sim 1\ 000\ 000 1000∼1 000 000 之间,这与第三节中乘积量化器所使用的聚类中心数目相比小很多。
除了上面的粗量化阶段外,我们还采用了与文献 [20] 中应用的策略类似的方法,也就是通过乘积量化器获得的编码对原始向量进行更为细化的表示。但同时为了应用到上面的粗量化所提供的信息,即与向量
y
y
y 相关联的聚类中心
q
c
(
y
)
q_c(y)
qc(y) ,下面使用乘积量化
q
p
q_p
qp对残差向量进行编码:
r
(
y
)
=
y
−
q
c
(
y
)
r(y)=y-q_c(y)
r(y)=y−qc(y)
上式对应于 Voronoi 单元格中的偏移。与原始向量相比,残差向量的值通常偏小,向量近似为:
y
¨
≜
q
c
(
y
)
+
q
p
(
y
−
q
c
(
y
)
)
\ddot{y}\triangleq q_c(y)+q_p(y-q_c(y))
y¨≜qc(y)+qp(y−qc(y))
即通过一组
(
q
c
(
y
)
,
q
p
(
y
−
q
c
(
y
)
)
)
(q_c(y),q_p(y-q_c(y)))
(qc(y),qp(y−qc(y))) 来表示。与二进制表示类似,粗略量化器提供最高有效位,乘积量化器编码对应的是最低有效位。
对于查询向量
x
x
x 和数据集向量
y
y
y 之间的距离
d
(
x
,
y
)
d(x,y)
d(x,y) 的估计值为
x
x
x 与
y
¨
\ddot y
y¨ 之间的距离
d
¨
(
x
,
y
)
\ddot{d}(x,y)
d¨(x,y) 表示:
d
¨
(
x
,
y
)
=
d
(
x
,
y
¨
)
=
d
(
x
−
q
c
(
y
)
,
q
p
(
y
−
q
c
(
y
)
)
)
\ddot d(x,y)=d(x,\ddot y)=d\bigg(x-q_c(y),q_p\big(y-q_c(y)\big)\bigg)
d¨(x,y)=d(x,y¨)=d(x−qc(y),qp(y−qc(y)))
我们使用
q
p
j
q_{p_j}
qpj 来表示第
j
j
j 个子量化器,我们使用下面的分解表达式来有效地计算该估计量:
d
¨
(
x
,
y
)
2
=
∑
j
d
(
u
j
(
x
−
q
c
(
y
)
)
,
q
p
j
(
u
j
(
y
−
q
c
(
y
)
)
)
)
\ddot d(x,y)^2=\sum_{j}{d\bigg(u_j(x-q_c(y)),q_{p_j}\big(u_j(y-q_c(y))\big)\bigg)}
d¨(x,y)2=j∑d(uj(x−qc(y)),qpj(uj(y−qc(y))))
与计算
A
D
C
\mathrm{ADC}
ADC 的方法类似,对于每个子量化器
q
p
j
q_{p_j}
qpj,残差向量分量
u
j
(
x
−
q
c
(
y
)
)
u_j\big(x-q_c(y)\big)
uj(x−qc(y)) 和相应的分量聚类中心
c
j
,
i
c_{j,i}
cj,i 之间的距离都进行了提前计算和存储。
乘积量化器是对从一个训练集中收集的一组残差向量进行学习的。尽管通过粗量化器将向量量化为不停的索引,但是所得到的残差向量仍然用于学习唯一的乘积量化器。我们假设当残差的分布在所有 Voronoi 细胞上都被边缘化时,相同的乘积量化器是准确的。对于每个 Voronoi 单元,学习和使用不同的乘积量化器组成的方法可能会得到较差的结果。然而,这在计算上将会是非常昂贵的,并且将需要存储 k ′ k' k′ 个乘积量化码本,即共 k ′ × d × k ∗ k'\times d\times k^* k′×d×k∗ 个浮点值,这对于常数 k ′ k' k′ ,内存通常是很难存储下的。
B. Indexing structure
我们使用粗量化器将一个倒排索引文件实现为一个列表 L 1 . . . L k ′ \mathcal{L_1...L_{k^{'}}} L1...Lk′。如果 Y \mathcal{Y} Y 是要索引的向量数据集,则与量化器 q c q_c qc 的聚类中心 c i c_i ci 关联的列表 L i \mathcal{L}_i Li 存储在集合 { y ∈ Y : q c ( y ) = c i } \{y\in\mathcal{Y}:q_c(y)=c_i\} {y∈Y:qc(y)=ci} 中。
在倒排列表 L i L_i Li 中,与 y y y 对应的条目包含向量标识符和编码后的残差 q p ( r ( y ) ) q_p(r(y)) qp(r(y)):
其中,标识符字段是由于倒排文件结构造成的开销,且根据要存储的向量性质,标识符不一定是唯一的。例如,要用局部描述符描述图像,图像标识符可以替换向量标识符,即,同一图像的所有向量具有相同的标识符,因此,一个 20bits 的字段足以从包含 100w 个的数据集中识别出一张图像。同时,可以使用索引压缩进一步降低这个存储成本,这可以根据参数将存储标识符的平均成本下降到大约 8 位。需要注意的是,一些图像的集合信息也可以插入到该条目中,如文献 20 和 27 中所使用的方法。
C. Searching algorithm
倒排文件系统是我们方法中的非穷举版本的关键,当搜索向量 x x x 的最近邻时,倒排文件会提供一个 Y \mathcal{Y} Y 的自检,并据此来估计距离:只扫描 q c ( x ) q_c(x) qc(x) 对应的倒排列表 L i \mathcal{L}_i Li。
然而, x x x 和它的最近邻通常并不会量化到相同的聚类中心,而是量化到附近的聚类中心。为了解决这个问题,我们使用了文献 [29] 中的多重分配的方法。查询向量 x x x 被分给 w w w 个索引,而不是只有一个,对应 q c q_c qc 的码本中 x x x 的 w w w 近邻,这回扫描所有对应的倒排表。多重分配方法不适用于数据库向量,因为这会增加内存使用量。图 5 给出了如何为数据库建立索引并进行搜索。
索引 向量 y y y 的步骤如下:
- 将 y y y 量化为 q c ( y ) q_c(y) qc(y);
- 计算残差 r ( y ) = y − q c ( y ) r(y)=y-q_c(y) r(y)=y−qc(y);
- 将 r ( y ) r(y) r(y) 量化为 q p ( r ( y ) ) q_p(r(y)) qp(r(y)),对于乘积量化器,等效于将 q j ( u j ( y ) ) q_j(u_j(y)) qj(uj(y)) 分配给 u j ( y ) u_j(y) uj(y),其中, j = 1... m j=1...m j=1...m;
- 给对应于 q c ( y ) q_c(y) qc(y) 的倒排列表中添加一个新的条目,它包含向量(或图像)标识符和二进制编码(乘积量化器的索引);
搜索 查询向量 x x x 的最近邻步骤:
-
将向量 x x x 量化到其在码本 q c q_c qc 中的最近的 w w w 个近邻
为了便于说明,在接下来的两个步骤中,我们仅用 r ( x ) r(x) r(x) 表示与这 w w w 个指定的相关的残差。下面两个步骤适用于所有 w w w 的分配。
-
对于每个子量化器 j j j 和它的聚类中心 c j , i c_{j,i} cj,i,计算平方距离 d ( u j ( r ( x ) ) , c j , i ) 2 d(u_j(r(x)),c_{j,i})^2 d(uj(r(x)),cj,i)2;
-
计算 r ( x ) r(x) r(x) 与反向链表的所有索引向量之间的平方距离。李永前一步周计算的子向量到聚类中心的距离,这包括对 m m m 个查找值求和,具体参见公式 31 31 31;
-
根据估计的距离,选择向量 x x x 的 K K K 个最近邻,这是通过维护一个固定容量的最大堆结构有效地实现的,该结构存储了迄今为止所见到的 K K K 个最小值。在每次计算距离之后,只有当此标识符的距离小于最大堆中的最大距离时,才会将其添加到结构中。
上述步骤中仅步骤 3 依赖于数据库的大小。与 A D C ADC ADC 方法相比,将向量 x x x 量化为 q c ( x ) q_c(x) qc(x) 的附加步骤在于计算 D D D 维向量之间的 k ′ k' k′ 个距离。假设反向链表是平衡的,则必须解析大约 n × w / k ′ n\times w/k' n×w/k′ 个条目。因此,上面这种搜索将会比 ADC 方法快得多,如下一节所示。