作者:Jack Conradson, Benjamin Trent
Elasticsearch 在 8.6 中引入了一种新型向量! 该向量具有 8 位整数维度,其中每个维度的范围为 [-128, 127]。 这比具有 32 位浮点维度的当前向量小 4 倍,这可以节省大量空间。
你现在可以通过将带有字节值的 element_type 参数添加到向量映射中来开始索引这些较小的 8 位向量,类似于下面的示例。
- {
- "mappings": {
- "properties": {
- "my_vector": {
- "type": "dense_vector",
- "element_type": "byte",
- "dims": 3,
- "index": true,
- "similarity": "dot_product"
- }
- }
- }
- }
但是,如果你现有的向量维度不适合这种较小的类型怎么办? 然后我们可以使用量化过程使它们适合,通常只有很小的精度损失!
让我们从定义量化开始。 量化是获取较大值集并将它们映射到较小值集的过程。 更具体地说,在我们的例子中,这将采用 32 位浮点数的范围并将其映射到向量中每个维度的 8 位整数的范围。 (这不应与降维混淆,后者是不同的主题。这只是缩小现有维度的值范围。)
这导致了另外两个问题。 我们的 32 位浮点向量的实际范围是多少? 我们应该使用什么功能来进行映射? 答案因用例而异。
例如,最简单的量化形式之一是采用归一化 32 位向量的维度并将它们线性映射到 8 位向量的整个维度范围。 使用 Python,这将类似于以下内容:
- import numpy as np
- import typing as t
-
- def quantize_embeddings(text_and_embeddings: t.List[t.Mapping[str, t.Any]]) -> t.List[t.Mapping[str, t.Any]]:
- quantized_embeddings = np.array([x['embedding'] for x in
- query_and_embeddings])
- quantized_embeddings = (quantized_embeddings * 128)
- quantized_embeddings = quantized_embeddings.clip(-128,
- 127).astype(int).tolist()
- return [dict(item, **{'embedding': embedding}) for (item,
- embedding) in zip(text_and_embeddings, quantized_embeddings)]
不过,这只是一个例子。 还有许多其他有用的量化函数。 对于你的特定用例,重要的是要评估哪种量化方法可以为您提供相对于空间缩减、相关性和召回率之间的权衡的最佳结果。
8 位向量和量化都很棒,但它们真的能减少实际用例中的空间吗? 答案是肯定的! 并且实质上。 这就是他们在不损害相关性和召回率的情况下继续提供良好结果的全部过程。 Elasticsearch 甚至拥有你使用我们的排名评估 API 自行进行评估所需的所有工具。
现在,让我们看一下使用以下设置从真实示例生成的一些数字:
然后我们让一些神奇的事情发生并根据这个设置收集结果:
category | Median kNN Response Time | Median Exact Response Time | Recall@100 | NDCG@10 | Total Index Size (1p, 1r) |
byte | 32ms | 1072ms | 0.79 | 0.38 | 5.8gb |
float | 36ms | 1530ms | 0.79 | 0.38 | 16.4gb |
% Reduction | 11% | 30% | 0% | 0% | 64% |
我们的结果看起来棒极了。 让我们逐一分解。
作为 8.6 的一部分,字节向量已准备就绪,我们鼓励你在 Elastic Cloud 中启动一个集群并尝试一下!