跳到主要内容

我们在多个代表实际应用的典型数据集上,对向量编解码器(vector codec)进行了对比评测。

所有测试的步骤都一样:我们通过index_factory生成一个编解码器,然后用100万个具有代表性的向量进行训练。接着,我们对以下三点进行评估:

  • 重构误差(reconstruction error):在另一组100万个独立的向量上,先编码、再解码,计算平均L2距离(非平方)。注意部分编解码器(比如ITQ)无法合理进行重构。
  • 对称相似度搜索准确率(symmetric similarity search accuracy):即“1-最近邻召回率@1”。在1万个向量上,先进行编码/解码处理,再在之前那100万个也已编码/解码的向量中做最近邻搜索。反映了编解码器对向量区分能力的破坏程度。对于二值编码器,我们用汉明距离评测。
  • 非对称相似度搜索准确率(asymmetric similarity search accuracy):和上面类似,但查询向量不进行编码。模拟临时查询向量和已编码数据库向量对比的实际场景。

评测结果以表格(按码长升序排列)和对称检索准确率的曲线图方式展示。所选择的编解码器覆盖了主流的基线算法。优化调整可能还能进一步提升部分方法的性能。

备注

本组实验尚未包含现阶段内存效率最佳的“加法量化(Additive quantization)”方案。请参考additive quantizers wiki获取相关结果。

SIFT1M

SIFT1M数据集为学术界经典案例:包含100万个128维SIFT向量。每个向量以字节(byte)形式存储,因此编码长度超过128字节没有意义。

SIFT1M 编解码器准确率曲线

以下表格展示了最有代表性的一组实验数据:

编解码器(factory key)码长
code size
编解码器大小
codec size
重构误差
recons error
对称准确率@1
sym recall @ 1
非对称准确率@1
asym recall @ 1
解码耗时(秒)
decode time
ITQ64,LSH848.7 k-0.051--
OPQ8_48,PQ8872.2 k308.20.1410.2200.23
PCAR24,ZnLattice1x54_6877.3 k3640.1010.1450.20
OPQ8_48,PQ8x1010216 k301.50.2150.3020.25
OPQ8_48,PQ8x1212792 k297.10.2820.3530.27
Pad128,ITQ128,LSH16129 k-0.129--
OPQ16_64,PQ161696.2 k138.80.3070.4120.23
OPQ16_64,PQ16x1020288 k125.90.4280.5040.28
OPQ16_64,PQ16x12241.03 M118.70.5230.5670.34
Pad256,ITQ256,LSH32514 k-0.223--
PCAR64,SQ43297.9 k121.20.4810.5400.22
PCAR96,ZnLattice4x54_632114 k98.180.4680.5720.60
OPQ32_128,IVF16384,PQ32348.19 M61.860.6120.6660.14
OPQ32_128,PQ32x1040576 k56.20.6490.7180.57
OPQ32_128,Residual2x14,PQ32x10448.56 M45.340.7270.7640.11
OPQ32_128,Residual2x14,PQ32x125210.1 M36.20.7890.8090.11
OPQ32_128,Residual2x14,PQ32x146016.1 M29.550.8350.8500.14
SQ4641,10542.190.7400.7800.03
OPQ64_256,PQ64x10801.13 M17.320.8780.8961.04
SQ6961,1059.9040.9280.9420.06
OPQ64_256,PQ64x12964.13 M10.120.9220.9331.25
PCAR128,SQ8128131 k3.2010.9680.9770.38
SQ81281,1052.4680.9760.9790.04
SQfp162568100.9920.9920.03
备注

如果表格中为“nan”,表示在该算法下该项目不适用(比如ITQ无法合理重构)。解码耗时单位为解码100万个向量所需秒数(48线程)。

主要观察点:

  • ITQ64,LSH是极为传统的二值哈希方法,所有配置下均被产品量化(Product Quantizer, PQ)及标量量化(Scalar Quantizer, SQ)方法超越。
  • PQ相关方法(及其结合有旋转预处理的OPQ变体)在相似度检索中表现突出。不过OPQ需要在编解码器中额外存储旋转矩阵,因此会增大模型体积。
  • 对于同一PQ类型(例如PQ16),提升每个量化器(quantizer)位数通常能在码长增加不大的情况下大幅提高准确率。
  • 残差编码(Residual codec)比PQ稍好,但编码速度慢,且训练数据需求更大。
  • SQ8理论应有100%准确,但受到量化误差(quantization artifact)影响而未达到。
  • OPQ和PCA矩阵对于大规模数据集占用空间较大。尤其PCA矩阵会存两份(原始特征值也保留)。对输入维度为d的PCA,可从编解码器体积中减去d*d*4字节。
  • 格点量化(lattice quantizer)优于ITQ,但不及标量量化,部分原因可能是参数未针对短向量进一步优化。

Resnet50

该数据集为resnet50网络平均池化层输出的2048维向量,来源见low-shot-with-diffusion

Resnet50 编解码器准确率曲线
编解码器(factory key)码长
code size
编解码器大小
codec size
重构误差
recons error
对称准确率@1
sym recall @ 1
非对称准确率@1
asym recall @ 1
编码耗时(秒)
encode time
解码耗时(秒)
decode time
ITQ64,LSH8536 k-0.028-42.41-
OPQ8_48,PQ88432 k11.140.0490.08618.951.91
PCAR24,ZnLattice1x54_6816.2 M12.670.0450.06018.931.21
OPQ8_48,PQ8x1010576 k10.890.0820.12923.431.95
OPQ24_96,PQ1212864 k10.290.0710.12914.530.94
OPQ8_48,PQ8x12121.13 M10.80.1240.17140.860.79
Pad128,ITQ128,LSH161.07 M-0.069-41.59-
RR128,LSHt161.00 M-0.056-18.27-
OPQ16_64,PQ1616576 k10.140.1610.21413.930.89
OPQ16_64,PQ16x1020768 k9.9040.2350.27815.740.86
OPQ16_64,PQ16x12241.5 M9.7790.2840.31621.720.92
OPQ16_64,PQ16x14284.5 M9.7170.3180.34245.720.92
Pad256,ITQ256,LSH322.26 M-0.125-43.74-
PCAR96,ZnLattice4x54_63216.8 M8.840.3610.40822.241.20
PCAR64,SQ43216.5 M9.960.2550.29114.650.84
OPQ32_128,IVF16384,PQ32349.13 M7.7830.4190.48623.320.86
OPQ32_128,PQ32x10401.5 M7.7730.4400.49629.701.37
OPQ32_128,Residual2x14,PQ32x10449.5 M7.5710.5270.56946.011.00
OPQ32_128,PQ32x12483 M7.5660.5160.55432.231.22
OPQ32_128,Residual2x14,PQ32x125211 M7.4720.5820.60957.470.91
OPQ32_128,Residual2x14,PQ32x146017 M7.4150.6030.61595.270.71
OPQ64_256,PQ64642.25 M5.8010.5400.60917.501.47
PCAR128,SQ46417 M7.7630.4570.51514.181.03
OPQ64_256,PQ64x10803 M5.3670.6300.69128.461.87
OPQ64_256,PQ64x12966 M5.1340.7160.75647.761.93
OPQ128_512,PQ1281284.5 M4.1590.7130.75219.184.18
PCAR128,SQ812817 M7.4040.6420.64715.391.03
PCAR384,ZnLattice16x54_612819 M4.6880.6790.73719.052.75
OPQ128_512,PQ128x101606 M3.7690.7810.81129.753.30
OPQ128_512,PQ128x1219212 M3.5640.8290.85176.594.11
OPQ128_512,PQ128x1422436 M3.4280.8540.873309.209.02
PCAR256,SQ825618 M4.8610.8460.85038.031.40
PCAR1024,Residual2x14,PQ25626089 M3.60.7090.76960.214.64
PCAR1024,Residual2x14,PQ256x12388104 M2.5290.8630.890181.394.76
PCAR512,SQ851220 M3.2330.9190.92118.144.00
PCAR1024,PQ512x1276840 M2.010.9530.955192.4813.30
SQ4102416.1 k3.5340.7250.76050.480.57
SQ8204816.1 k0.21620.9800.98216.800.58
SQfp164096810.0044930.9940.99415.670.53

主要观察点:

  • ITQ在高维情况下一样表现不佳
  • 对于高维场景,PQ系列光是模型体积就达到100MB以上,编码开销也很高
  • 标量量化(SQ)在高维情况下非常有吸引力,因为无需存储庞大模型
  • 残差编码(Residual codec)精度略高于SQ
  • 格点量化(lattice quantizer)在低码长(up to 32 bits)时能媲美OPQ系列,训练耗时低但编码解码非常慢

重构误差曲线

如下图为重构误差比较。可以看到召回率和重构误差高度相关:误差越低检索效果越好。

Resnet50 重构误差结果

句子嵌入(Sentence Embeddings)

本数据集来源于LASER toolkit,包含1024维的德语句子向量。

德语句子嵌入 编解码器准确率曲线
编解码器(factory key)码长
code size
编解码器大小
codec size
重构误差
recons error
对称准确率@1
sym recall @ 1
非对称准确率@1
asym recall @ 1
编码耗时(秒)
encode time
解码耗时(秒)
decode time
ITQ64,LSH8276 k-0.025-43.36-
OPQ8_48,PQ88240 k0.044360.0340.0629.931.82
PCAR24,ZnLattice1x54_684.1 M0.045150.0300.0389.561.75
OPQ8_48,PQ8x1010384 k0.044050.0520.08013.590.47
OPQ24_96,PQ1212480 k0.043370.0540.1017.580.63
OPQ8_48,PQ8x1212960 k0.043840.0700.09033.320.47
Pad128,ITQ128,LSH16580 k-0.063-32.96-
OPQ16_64,PQ1616320 k0.043180.0980.12713.100.52
OPQ16_64,PQ16x1020512 k0.042920.1260.14310.930.65
OPQ16_64,PQ16x12241.25 M0.042780.1410.15715.560.66
OPQ24_96,PQ2424480 k0.042030.1550.20240.630.59
OPQ16_64,PQ16x14284.25 M0.04270.1510.160102.270.59
Pad256,ITQ256,LSH321.25 M-0.121-33.70-
OPQ32_128,PQ3232640 k0.041110.2060.25518.770.83
PCAR64,SQ4324.26 M0.043230.0900.11616.190.51

编解码器基准测试结果(下)

以下表格汇总了多种编码器(编解码器,Codec)在不同参数设置下的基准测试结果。每一行都代表一种组合的配置或量化方式,下方为详细参数解释。

方法(编码器组合)维度训练样本数误码率Top-1 精度Top-5 精度编码速度 (ms/样本)查询速度 (ms/样本)
PCAR96,ZnLattice4x54_6324.38 M0.041680.2010.2228.690.81
OPQ32_128,IVF16384,PQ32348.63 M0.040790.2420.27582.160.42
OPQ32_128,PQ32x10401 M0.040710.2580.28822.440.79
OPQ32_128,Residual2x14,PQ32x10449 M0.040550.2890.30534.870.41
OPQ32_128,PQ32x12482.5 M0.040520.2920.30791.290.89
OPQ32_128,Residual2x14,PQ32x146016.5 M0.040380.3150.32294.090.41
OPQ64_256,PQ64641.25 M0.038450.3630.42112.661.44
PCAR128,SQ4644.51 M0.041250.1890.23013.190.71
PCAR64,SQ8644.26 M0.042600.1660.16517.950.54
OPQ64_256,PQ64x10802 M0.037910.4350.469111.141.75
OPQ64_256,PQ64x12965 M0.037670.4730.498213.541.64
OPQ128_512,PQ1281282.5 M0.035500.5340.59916.703.06
PCAR384,ZnLattice16x54_61285.51 M0.036230.5540.59610.711.80
OPQ128_512,PQ128x101604 M0.034970.6300.66825.143.18
OPQ128_512,PQ128x1219210 M0.034670.6800.71368.923.09
OPQ128_512,PQ128x1422434 M0.034520.7110.729338.227.07
PCAR1024,PQ2562569.01 M0.010690.6460.700122.887.62
PCAR256,SQ82565.01 M0.037470.5280.52810.691.08
PCAR768,ZnLattice32x54_62567.01 M0.033140.7240.78012.763.42
PCAR1024,Residual2x14,PQ256x1238888 M0.0046120.8390.867208.753.67
PCAR1024,PQ5125129.01 M0.0033130.8810.90133.068.53
PCAR512,SQ85126.01 M0.034310.7680.76811.322.00
PCAR1024,PQ512x1276824 M0.0010030.9650.970227.6213.56
SQ676882730.0039240.8430.87222.250.47
SQ8102482730.00096230.9550.96518.180.27
SQfp162048811.041e-050.9990.99937.520.28

字段解释

  • 方法(编码器组合):指本行使用的特征变换/量化/编码组合。例如:OPQ32_128(正交乘积量化)、IVF16384(倒排文件,16384簇)、PQ32(32维乘积量化)、Residual2x14(残差编码),等。
  • 维度:数据经变换或编码后的特征维数。
  • 训练样本数:训练量化器时用到的数据量。
  • 误码率:量化重构数据和原数据的均方误差,越低表明编码质量越高。
  • Top-1/Top-5 精度:在最近邻检索中,正确结果分列 Top-1 和前五(Top-5)返回的准确率。
  • 编码速度(ms/样本):将一个样本转为量化编码所需的毫秒数。
  • 查询速度(ms/样本):用编码向量做一次检索的平均耗时(毫秒)。
备注

不同表项中,"OPQ" 表示正交乘积量化(Orthogonal Product Quantization),"PQ" 表示乘积量化(Product Quantization),"SQ" 表示缩减量化(Scalar Quantization),"ZnLattice" 表示点阵量化(Lattice Quantization);"Residual" 指多级残差编码;"PCAR" 则是主成分分析降维(Principal Component Analysis, PCA)。


基准测试结果观察

  • 虽然本数据集的维度低于 ResNet50 嵌入(embedding),但原始检索效果却更低,因此该场景的索引和压缩更加具有挑战性。
  • 残差类编解码器的编码时间消耗较大,在大规模场景下可能成为瓶颈。
  • 点阵量化(Lattice Quantization,ZnLattice)在本场景下表现非常出色,准确率基本优于相同维度下的传统乘积量化方法,有一定优势。
提示

针对此类低维特征和实际数据规模,综合考虑 Top-1/Top-5 精度、误码率和编码速度,在选型时推荐优先尝试 ZnLattice 及 OPQ+PQ 等组合。


相关代码与结果可复现性


注意事项

注意

部分复杂组合(如残差量化、多级 PQ)的编码速度较慢,仅适合对压缩精度有极高要求的应用场景。大规模生产环境建议权衡速度与精度后使用。


如需进一步了解各类量化器的工作原理或使用方式,请查阅相关章节或参考上述代码示例。