1. 向量数据库中的PQ算法概述
在当今大数据和人工智能时代,向量检索已经成为许多应用的核心技术。从推荐系统到图像搜索,再到自然语言处理,高效处理高维向量数据是提升系统性能的关键。Product Quantization(乘积量化,简称PQ)算法作为一种经典的向量压缩和近似搜索技术,因其出色的性能表现,已成为Faiss、Milvus等主流向量数据库的标配算法。
我第一次接触PQ算法是在处理一个千万级图像特征检索项目时。当时我们的服务器内存根本无法容纳所有原始向量,正是PQ算法帮助我们实现了64:1的压缩比,让整个系统得以在有限资源下运行。这种将高维空间分解为多个低维子空间分别处理的思路,不仅解决了存储问题,还大幅提升了搜索效率。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. PQ算法核心原理
2.1 基本思想与数学基础
PQ算法的核心思想可以用"分而治之"来概括。面对高维向量空间的处理难题,PQ算法采用了一种巧妙的分解策略:
-
向量分割:将原始的D维向量均匀分割成M个连续的子向量,每个子向量的维度为D/M。例如,一个128维向量分割成8个子向量,每个子向量16维。
-
子空间量化:为每个子空间训练一个独立的码本(codebook),通常使用K-means聚类算法生成k个聚类中心。这些聚类中心就是该子空间的"代表向量"。
-
编码存储:用最近的聚类中心索引替代原始子向量值,实现压缩存储。例如,每个子向量用1字节(256个可能值)表示,相比原始浮点存储大幅节省空间。
从数学角度看,PQ算法实际上是将原始高维空间R^D分解为M个子空间的笛卡尔积:
R^D ≈ R^(D/M) × R^(D/M) × ... × R^(D/M)
这种分解使得我们可以在每个低维子空间中独立进行量化操作,大大降低了问题的复杂度。
2.2 为什么称为"乘积"量化
"乘积"一词来源于数学中的笛卡尔积概念。PQ算法将原始向量空间视为多个子空间的乘积空间,量化过程就是在每个子空间独立进行量化操作的"乘积"。
具体来说,如果我们有M个子空间,每个子空间有k个聚类中心,那么理论上可以表示k^M种不同的组合。这就是"乘积"的威力——通过组合低维空间的量化结果,我们实际上获得了指数级的表示能力。
3. PQ算法实现细节
3.1 训练阶段详解
训练阶段是PQ算法的准备环节,目的是为每个子空间生成码本。以下是具体步骤:
-
数据准备:收集足够数量的训练样本(通常数万到数百万个向量),这些样本应该与实际应用场景中的数据分布相似。
-
向量分割:将每个训练样本分割成M个子向量。例如,对于128维向量和M=8,每个子向量16维。
-
子空间聚类:对每个子空间的所有子向量分别运行K-means算法:
python复制# 伪代码示例 codebooks = [] for m in range(M): sub_vectors = [v[m*d_sub:(m+1)*d_sub] for v in train_vectors] kmeans = KMeans(n_clusters=k) kmeans.fit(sub_vectors) codebooks.append(kmeans.cluster_centers_) -
码本存储:保存所有子空间的聚类中心,形成码本集合。每个码本通常包含256个聚类中心(可用1字节索引表示)。
在实际应用中,训练阶段通常是一次性开销。一旦码本训练完成,可以重复用于编码和搜索阶段。
3.2 编码阶段实现
编码阶段将原始高维向量转换
