首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >使用byte类型节省向量空间

使用byte类型节省向量空间

原创
作者头像
点火三周
发布2023-07-04 08:52:09
发布2023-07-04 08:52:09
2.1K0
举报

Elasticsearch 在 8.6 中引入了一种新型向量!该向量具有 8 位整数维度,其中每个维度的范围为 -128, 127。这比当前具有 32 位浮点维度的向量小 4 倍,这可以节省大量空间。

您现在可以开始为这些较小的 8 位向量建立索引,方法是在mapping中将element_type 参数设为__byte,类似于下面的示例。

代码语言:javascript
复制
{
    "mappings": {
        "properties": {
            "my_vector": {
                "type": "dense_vector",
                "element_type": "byte",
                "dims": 3,
                "index": true,
                "similarity": "dot_product"
            }
        }
    }
}

但是,如果现有向量的维度不适合这种较小的类型怎么办?然后我们可以使用量化 (quantize) 过程使它们适合,通常只损失很小的精度!

机器学习和数据分析中,向量通常用于表示数据点。但有时这些向量的维度可能不适合所需的类型,这可能会导致存储和处理问题。这就是量化过程的作用。

量化涉及减少用于表示向量每个维度的位数。这可以通过将值四舍五入到可以用较小类型表示的最近可能值来实现。虽然这可能导致小量的精度损失,但它可以极大地提高效率并减少存储要求。

量化通常用于图像和音频压缩等应用程序,其中需要高效地处理和存储大量数据。通过使用量化,我们可以减小这些文件的大小,同时仍然保持合理的质量水平。同样的,如果在基准测试下,我们能看到精度损失很少,该技术则同样对文本向量的压缩有效。

总的来说,量化是优化机器学习和其他应用程序中数据存储和处理的强大工具。它使我们能够更有效地处理更大的数据集,而不会牺牲太多准确性或质量。

让我们量化一下

让我们从定义量化开始。量化是获取较大值集并将其映射到较小值集的过程。更具体地说,在我们的例子中,这将获取 32 位浮点数的范围,并将其映射到向量中每个维度的 8 位整数的范围。(这不应与降维混淆,这是一个不同的主题。这只是减小现有维度的值范围。) 

这引出了另外两个问题。我们的 32 位浮点向量的实际范围是多少?我们应该使用什么函数来进行映射?根据用例的不同,答案也有很大差异。

例如,最简单的量化形式之一是获取归一化 32 位向量的维度,并将它们线性映射到 8 位向量的整个维度范围。使用 Python,这将类似于以下内容:

代码语言:javascript
复制
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)。

现在,让我们看一下使用以下设置从实际示例获得的测试指标:

  1. 所有数据均使用云中的 Elasticsearch 和两个 gcp.data.highcpu.1 64GB 节点收集
  2. 数据收集自NQ 数据集(自然问题),由 Google 构建,用于 BEIR
  3. 嵌入模型是sentence-transformers/all-MiniLM-L6-v2
  4. 使用前面的示例 Python 片段将量化生成 8 位整数向量应用于从数据收集的 32 位浮点向量

然后,我们根据此设置收集结果,奇迹发生了:

类别

kNN 响应时间中值

准确响应时间中值

召回@100

NDCG@10

索引总大小(1p、1r)

byte

32毫秒

1072毫秒

0.79

0.38

5.8GB

float

36毫秒

1530毫秒

0.79

0.38

16.4GB

% 减少

11%

30%

0%

0%

64%

我们的结果看起来棒极了。让我们逐一分解。

  • kNN 响应时间中值:此响应时间是使用针对我们的示例数据集的近似 kNN 搜索来收集的。这种类型的搜索使用 Lucene 的 HNSW 图作为支持数据结构。我们发现byte的响应时间比float的响应时间增加了 11%。
  • 精确响应时间中值:此响应时间是使用精确 kNN 搜索针对我们的示例数据集收集的。这种类型的搜索使用脚本来迭代数据集中的每个向量,并将返回最佳的结果。我们看到响应时间减少了 30% 的巨大改进!
  • Recall@100:这向我们显示最相关的结果是否包含在前 100 个中。这对于显示我们的量化函数是否运行良好非常重要。我们可以看到字节与浮点的数字是相同的,这意味着即使在量化之后,字节的相关性也与浮点的相关性一样好。
  • @NDCG@10:这向我们展示了前 10 个结果的质量有多好。这是评估我们的量化函数是否运行良好的另一个重要指标。再一次,字节与浮点之间的数字是相同的,因此我们可以放心,即使在量化之后,我们的结果仍然一样好。
  • 总索引大小(1p,1r):这是用于具有单个分区和单个副本的向量索引的总索引大小。对于此指标,我们禁用了_source,我们建议将其用于所有向量字段,其中摄取的向量数据未经修改,因此不会存储两次。我们发现索引总大小大幅减少了 64%!由于包括图形连接在内的 HNSW 数据结构的额外开销,这并没有完全达到字节和浮点之间的 4 倍差异,但它仍然是相当大的尺寸减小。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 让我们量化一下
  • 现实世界中的一些实际数据
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档