PQ 乘积量化:如何用 8 字节近似表示一个 128 维向量

当向量数量达到百万级,检索系统首先遇到的困难往往是内存。一个 128 维
float32 向量需要 512 字节;一百万个向量,仅原始数值就约占 512
MB,还没有计算 ID、索引和元数据。

乘积量化(Product
Quantization,PQ)用多个小码本近似表示高维向量,在存储成本、距离计算成本与检索精度之间做取舍。

从一个大问题拆成多个小问题

假设向量维度 D=128,将它切成 M=8 段,每段 16
维。针对训练样本的每一段,分别训练一个含 K=256 个聚类中心的 K-means
模型。

原向量:x = [x₁, x₂, …, x₈]
第 i 段的码本:Cᵢ = {cᵢ,₀, cᵢ,₁, …, cᵢ,₂₅₅}
编码:aᵢ = argminⱼ ‖xᵢ − cᵢ,ⱼ‖²
最终编码:[a₁, a₂, …, a₈]

每个编号只需要 8 bit,因此一个向量的编码是 8 字节,相比原来的 512
字节,编码部分缩小到 1/64。这里不包括共享码本、ID 和索引结构的开销。

注意:K-means 是在训练向量集合上进行的,不是拿一个向量的 8
个片段互相聚类。每个子空间有自己的码本,整套码本可以被所有数据库向量复用。

为什么叫“乘积”量化

8 个子空间各有 256 种选择,组合起来可以表示 256⁸
种重构结果。整体码本相当于各子码本的笛卡尔积,而实际只需存储 8
组中心。

以 float32 为例,共享码本数值占用约为:

M × K × (D/M) × 4 = 8 × 256 × 16 × 4 = 131072 字节

这种组合方式避免了显式学习和存储一个极大的完整码本,但也引入了分块假设与量化误差。

压缩以后怎样检索

常见方法是不压缩查询向量 q,只压缩数据库向量
x。这称为非对称距离计算(ADC)。

对一个查询,先计算每个子向量到对应码本所有中心的距离,生成查找表:

T[i, j] = ‖qᵢ − cᵢ,ⱼ‖²
近似距离 d(q, x) = Σᵢ T[i, aᵢ]

查找表针对当前查询构建一次。之后,每个候选向量只需要 8
次查表与累加,不必重新计算 128
个维度上的距离。上式对应平方欧氏距离;不能不加区分地把它当成所有相似度的计算公式。

PQ 的收益和代价

选择 可能收益 需要付出的代价
增大 M,固定每段编码位数 通常减小重构误差 编码变长,查表次数增加
增大每段中心数 K 量化划分更细 训练、码本和查询表成本提高
使用更短的编码 降低内存与带宽压力 近邻排序可能受量化误差影响
结合候选筛选索引 减少需要扫描的编码数量 候选筛选本身也可能漏召回

PQ 负责压缩表示,并不自动消除全库扫描。IVF-PQ
等方案会先筛选候选区域,再在区域内计算压缩距离。即使把向量“解码”回聚类中心,也只是恢复近似值,无法还原原始浮点数。

实际选择参数时,应在相同数据集、查询集和硬件上同时观察
Recall@k、延迟与内存,不能仅凭压缩比判断方案更好。

自测:为什么数据库中有一百万个向量,不需要保存一百万套码本?因为码本按子空间训练并共享,每个向量只保存中心编号。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇