跳转到主要内容
Chroma 集合具有一个 configuration(配置),它决定了嵌入索引的构建和使用方式。我们为这些索引配置使用了默认值,对于大多数开箱即用的用例,这些默认值应该能提供出色的性能。 您在集合中选择使用的 嵌入函数 也会影响其索引构建,并包含在配置中。 创建集合时,您可以根据不同的数据、精度和性能要求自定义这些索引配置值。某些查询时的配置也可以在集合创建后使用 .modify 函数进行自定义。

HNSW 索引配置

在单节点 Chroma 集合中,我们使用 HNSW(分层导航小世界)索引来执行近似最近邻 (ANN) 搜索。
HNSW (Hierarchical Navigable Small World) 索引是一种基于图的数据结构,专为高维向量空间中高效的近似最近邻搜索而设计。它的工作原理是构建一个多层图,其中每一层都包含数据集的一个子集,越高层越稀疏,作为快速导航的“高速公路”。该算法在每一层建立附近点之间的连接,创建“小世界”属性,从而实现高效的搜索复杂度。在搜索过程中,算法从顶层开始,在嵌入空间中向查询点导航,然后逐层向下移动,在每个级别细化搜索,直到找到最终的最近邻。
HNSW 索引参数包括
  • space 定义了嵌入空间的距离函数,从而定义了相似性的定义方式。默认值为 l2(平方 L2 范数),其他可能的值包括 cosine(余弦相似度)和 ip(内积)。
距离参数方程式直观理解
平方 L2l2d=(AiBi)2d = \sum\left(A_i-B_i\right)^2测量向量之间的绝对几何距离,适用于需要真实空间接近度的情况。
内积ipd=1.0(Ai×Bi)d = 1.0 - \sum\left(A_i \times B_i\right)侧重于向量的对齐和幅值,常用于推荐系统,其中较大的值表示更强的偏好。
余弦相似度cosined=1.0(Ai×Bi)(Ai2)(Bi2)d = 1.0 - \frac{\sum\left(A_i \times B_i\right)}{\sqrt{\sum\left(A_i^2\right)} \cdot \sqrt{\sum\left(B_i^2\right)}}仅测量向量之间的角度(忽略幅值),使其成为文本嵌入或关注方向而非规模的情况的理想选择。
您应确保所选的 space 受到集合嵌入函数的支持。每个 Chroma 嵌入函数都会指定其默认空间和支持的空间列表。
  • ef_construction 决定了索引创建期间用于选择邻居的候选列表大小。较高的值会以更多的内存和时间为代价提高索引质量,而较低的值会以降低精度为代价加快构建速度。默认值为 100
  • ef_search 决定了搜索最近邻时使用的动态候选列表大小。较高的值通过探索更多潜在邻居来提高召回率和准确性,但会增加查询时间和计算成本,而较低的值会导致更快但准确性较低的搜索。默认值为 100。此字段可在创建后修改。
  • max_neighbors 是图中的每个节点在索引构建期间可以拥有的最大邻居数(连接数)。较高的值会导致更稠密的图,从而在搜索期间获得更好的召回率和准确性,但会增加内存使用和构建时间。较低的值会创建更稀疏的图,减少内存使用和构建时间,但代价是搜索准确性和召回率较低。默认值为 16
  • num_threads 指定在索引构建或搜索操作期间使用的线程数。默认值为 multiprocessing.cpu_count()(可用 CPU 核心数)。此字段可在创建后修改。
  • batch_size 控制索引操作期间每个批次处理的向量数量。默认值为 100。此字段可在创建后修改。
  • sync_threshold 确定何时将索引与持久存储同步。默认值为 1000。此字段可在创建后修改。
  • resize_factor 控制索引在需要调整大小时增长的幅度。默认值为 1.2。此字段可在创建后修改。
例如,这里我们创建了一个具有自定义 spaceef_construction 值的集合
collection = client.create_collection(
    name="my-collection",
    embedding_function=OpenAIEmbeddingFunction(model_name="text-embedding-3-small"),
    configuration={
        "hnsw": {
            "space": "cosine",
            "ef_construction": 200
        }
    }
)

微调 HNSW 参数

在近似最近邻搜索的语境下,召回率是指检索到了多少真正的最近邻。增加 ef_search 通常会提高召回率,但会减慢查询速度。类似地,增加 ef_construction 会提高召回率,但会增加创建索引时的内存使用量和运行时间。为 HNSW 参数选择正确的值取决于您的数据、嵌入函数以及对召回率和性能的要求。您可能需要尝试不同的构建和搜索值,以找到满足您要求的值。例如,对于一个包含 50,000 个 2048 维嵌入的数据集,生成的嵌入如下
embeddings = np.random.randn(50000, 2048).astype(np.float32).tolist()
我们设置了两个 Chroma 集合
  • 第一个配置为 ef_search: 10。当使用该集合中的特定嵌入(id = 1)进行查询时,查询耗时 0.00529 秒,我们得到的嵌入距离为
[3629.019775390625, 3666.576904296875, 3684.57080078125]
  • 第二个集合配置为 ef_search: 100ef_construction: 1000。执行相同的查询时,这次耗时 0.00753 秒(慢了约 42%),但其距离测量的结果更好
[0.0, 3620.593994140625, 3623.275390625]
在此示例中,当使用测试嵌入 (id=1) 进行查询时,第一个集合未能找到该嵌入本身,尽管它就在集合中(它本应作为距离为 0.0 的结果出现)。第二个集合虽然稍慢,但成功找到了查询嵌入本身(通过 0.0 的距离显示),并返回了总体更接近的邻居,证明了其以性能为代价换取了更好的准确性。

嵌入函数配置

创建集合时选择的嵌入函数及其初始化参数将保留在集合配置中。这使我们能够在不同客户端使用该集合时正确地重新构建它。 您可以将嵌入函数作为“create”方法的参数设置,或直接在配置中设置:
安装 openaicohere 软件包
pip install openai cohere
使用嵌入函数和自定义配置创建集合
import os
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction, CohereEmbeddingFunction

# Using the `embedding_function` argument
openai_collection = client.create_collection(
    name="my_openai_collection",
    embedding_function=OpenAIEmbeddingFunction(
        model_name="text-embedding-3-small"
    ),
    configuration={"hnsw": {"space": "cosine"}}
)

# Setting `embedding_function` in the collection's `configuration`
cohere_collection = client.get_or_create_collection(
    name="my_cohere_collection",
    configuration={
        "embedding_function": CohereEmbeddingFunction(
            model_name="embed-english-light-v2.0",
            truncate="NONE"
        ),
        "hnsw": {"space": "cosine"}
    }
)
注意: 许多嵌入函数需要 API 密钥才能与第三方嵌入提供商进行交互。Chroma 嵌入函数将自动查找用于存储提供商 API 密钥的标准环境变量。例如,如果设置了 OPENAI_API_KEY 环境变量,Chroma 的 OpenAIEmbeddingFunction 会将其 api_key 参数设置为该值。如果您的 API 密钥存储在具有非标准名称的环境变量中,您可以通过设置 api_key_env_var 参数来配置您的嵌入函数以使用自定义环境变量。为了使嵌入函数正常运行,您必须在每个使用该集合的环境中设置此变量。
cohere_ef = CohereEmbeddingFunction(
    api_key_env_var="MY_CUSTOM_COHERE_API_KEY",
    model_name="embed-english-light-v2.0",
    truncate="NONE",
)