标量量化的介绍
大多数嵌入模型输出向量值。虽然这提供了最高保真度,但考虑到向量中实际重要的信息,这是一种浪费。在给定的数据集内,嵌入永远不需要每个单独维度上的所有 20 亿个选项。对于更高维度的向量(例如 386 维及更高),尤其如此。量化允许以有损的方式对向量进行编码,从而略微降低保真度,但节省了巨大的空间。
理解标量量化中的桶
标量量化获取每个向量维度并将其分桶到某种更小的数据类型中。在本文档的其余部分,我们将假设将值量化为。要准确地分桶值,并不像将浮点数四舍五入到最接近的整数那么简单。许多模型输出的向量在范围上具有连续的维度。因此,两个不同的向量值 0.123 和 0.321 都可能向下舍入为 0。最终,一个向量在中仅使用其 255 个可用桶中的 2 个,从而丢失了过多的信息。
图 1:量化目标的说明,将从到的连续值分桶成离散的值。
数值转换背后的数学原理并不复杂。由于我们可以计算浮点范围的最小值和最大值,因此我们可以使用最小-最大归一化,然后线性地移动这些值。
图 2:在 和 之间转换的方程式。请注意,这些是失真转换,而非精确转换。在以下示例中,我们仅使用 int8 内的正值。这与 Lucene 的实现相一致。
统计量在标量量化中的作用
分位数是分布的一部分,它包含一定百分比的值。例如,我们的浮点数的 可能位于 之间,而不是 的真实最小值和最大值。小于 -0.75 和大于 0.86 的任何值都被认为是异常值。如果在尝试量化结果时包含异常值,则最常见的值将拥有更少的可用区间。而区间越少可能意味着精度越低,从而导致信息丢失越多。
图 3: 置信区间 和各个分位数值的示意图。 的所有值都落在 范围内。
这一切都很好,但现在我们知道了如何量化值,我们如何实际计算两个量化向量之间的距离?它是否像常规的 点积 一样简单?
代数在标量量化中的作用
我们仍然缺少一个至关重要的部分,如何计算两个量化向量之间的距离。虽然在本文中我们还没有回避数学,但我们即将进行更多数学运算。是时候拿出你的铅笔,并尝试回忆起 多项式 和基本代数。
对于 点积 和 余弦相似度 的基本要求是能够将浮点数相乘并将结果相加。我们已经知道如何在 和 值之间进行转换,那么使用我们的转换,乘法是什么样子的呢?
然后我们可以展开这个乘法,为了简化,我们将用 代替 。
更有趣的是,这个等式中只有一部分需要同时使用两个值。然而,点积不仅仅是两个浮点数的乘积,而是向量每个维度上所有浮点数的乘积。有了向量维度数 ,以下所有内容都可以在查询时和存储时预先计算。
仅仅是 ,并且可以存储为单个浮点数。
和
可以预先计算并存储为单个浮点数。
所有这些
点积计算唯一需要的就是 ,并结合一些预先计算的值与结果。
确保量化的准确性
那么,这到底是如何保证准确的呢?量化不是会丢失信息吗?是的,确实会,但量化利用了一个事实,即我们并不需要所有信息。对于学习到的嵌入模型,各个维度的分布通常没有 长尾分布。这意味着它们是局部化的并且相当一致。此外,通过量化引入的每个维度的误差是独立的。也就是说,对于我们常见的向量运算(如点积),误差会抵消。
结论
哇,内容真是太多了。但现在您已经很好地理解了量化的技术优势、背后的数学原理以及如何在考虑线性变换的情况下计算向量之间的距离。接下来,让我们看看如何在 Lucene 中实现这一点,以及在那里的一些独特挑战和优势。