在 Azure AI 搜索中配置向量量化并减少较小向量的存储

重要

根据补充使用条款,这些功能以公共预览版提供。 2024-03-01-Preview REST API 提供了新的数据类型、向量压缩属性和 stored 属性。

本文介绍用于在 Azure AI 搜索中压缩向量索引的向量量化和其他技术。

评估选项

第一步,检查用于减少向量字段使用的存储量的选项。 这些选项并不互斥,因此可以将多个选项一起使用。

建议使用标量量化,因为它是大多数情况下最有效的选择。 窄类型(Float16 除外)需要特意创建,stored 可以节省存储空间,而存储空间不像内存那么昂贵。

方法 为什么使用此选项
将较小的基元数据类型分配给向量字段 窄数据类型(例如 Float16Int16Int8)消耗的内存和磁盘空间较少。 如果嵌入模型以窄数据格式输出向量,则此选项是可行的。 或者,如果你有输出小数据的自定义量化逻辑,此选项也可行。 一个更常见的用例是将大多数模型生成的本机 Float32 嵌入重新转换为 Float16
消除可检索向量的可选存储 查询响应中返回的向量与查询执行期间使用的向量分开存储。 如果不需要返回向量,则可以关闭可检索存储,从而将每个字段的总体存储减少高达 50%。
添加标量量化 使用内置标量量化将本机 Float32 嵌入压缩为 Int8。 此选项可以减少内存和磁盘上的存储,而不会降低查询性能。 Int8 等较小的数据类型生成的向量索引的内容不如 Float32 嵌入的向量索引丰富。 为了弥补信息丢失,内置压缩包括使用未压缩嵌入和过采样进行查询后处理的选项,以返回更相关的结果。 重新排序和过采样是 Float32Float16 字段内置标量量化的特定功能,不能用于经过自定义量化的嵌入。

所有这些选项都是在空索引上定义的。 若要实施其中任何一项,请使用 Azure 门户、2024-03-01-preview REST API 或 beta Azure SDK 包。

定义索引后,可以单独加载文档和索引。

选项 1:将窄数据类型分配给向量字段

向量字段存储向量嵌入,向量嵌入表示为数字数组。 指定字段类型时,将指定用于保存这些数组中每个数字的基础基元数据类型。 数据类型会影响每个数字占用的空间大小。

使用预览 API,可以分配窄基元数据类型以减少向量字段所需的存储空间。

  1. 查看向量字段的数据类型

    • Collection(Edm.Single) 32 位浮点(默认)
    • Collection(Edm.Half) 16 位浮点
    • Collection(Edm.Int16) 16 位带符号整数
    • Collection(Edm.SByte) 8 位带符号整数

    注意

    目前不支持二进制数据类型。

  2. 选择对嵌入模型的输出或进行自定义量化的向量有效的数据类型。

    大多数嵌入模型输出 32 位浮点数,但如果应用自定义量化,则输出可能是 Int16Int8。 现在可以定义接受较小格式的向量字段。

    文本嵌入模型的本机输出格式为 Float32,它映射到 Azure AI 搜索中的 Collection(Edm.Single)。 无法将该输出映射到 Int8,因为禁止从 float 转换为 int。 但是,可以从 Float32 转换为 Float16(或 Collection(Edm.Half)),这是使用窄数据类型的简单方法,无需执行额外工作。

    下表提供了几个使用窄数据类型的嵌入模型的链接。

    嵌入模型 本机输出 Azure AI 搜索中的有效类型
    text-embedding-ada-002 Float32 Collection(Edm.Single)Collection(Edm.Half)
    text-embedding-3-small Float32 Collection(Edm.Single)Collection(Edm.Half)
    text-embedding-3-large Float32 Collection(Edm.Single)Collection(Edm.Half)
    具有 int8 embedding_type 的 Cohere V3 嵌入模型 Int8 Collection(Edm.SByte)
  3. 确保了解狭窄数据类型的利弊。 Collection(Edm.Half) 的信息较少,因此分辨率较低。 如果数据是同质或密集的,则丢失额外的细节或细微差别可能会导致查询时出现不可接受的结果,因为可用于区分附近向量的细节较少。

  4. 定义并生成索引。 可以使用 Azure 门户、2024-03-01-preview 或测试版 Azure SDK 包执行此步骤。

  5. 检查结果。 假设向量字段标记为可检索,请使用搜索资源管理器REST API 验证字段内容是否与数据类型匹配。 请务必使用正确的 2024-03-01-preview API 版本进行查询,否则不会显示新属性。

若要检查向量索引大小,请使用 Azure 门户或 2024-03-01-preview

注意

字段的数据类型用于创建物理数据结构。 如果以后想要更改数据类型,请删除并重建索引,或者使用新定义创建第二个字段。

选项 2:设置 stored 属性以删除可检索存储

stored 属性是向量字段定义上的一个新布尔值,用于确定是否为可检索的向量字段内容分配存储空间。 如果查询响应中不需要向量内容,则可以通过将 stored 设置为 false 来为每个字段节省最多 50% 的存储空间。

由于人工无法读取向量,因此在搜索页面上呈现的查询响应中通常会省略它们。 但是,如果在下游处理中使用向量,例如将查询结果传递到使用向量内容的模型或进程,则应将 stored 设置保持为 true 并选择不同的技术来最小化向量大小。

下示例显示搜索索引的字段集合。 将 stored 设置为 false 以永久删除向量字段的可检索存储。

PUT https://[service-name].search.azure.cn/indexes/[index-name]?api-version=2024-03-01-preview  
   Content-Type: application/json  
   api-key: [admin key]  

     { 
       "name": "myindex", 
       "fields": [ 
         { 
           "name": "myvector", 
           "type": "Collection(Edm.Single)", 
           "retrievable": false, 
           "stored": false, 
           "dimensions": 1536, 
           "vectorSearchProfile": "vectorProfile" 
         } 
       ] 
     } 

要点

  • 仅适用于向量字段

  • 影响磁盘上的存储,而不是内存,并且对查询没有影响。 查询执行使用不受 stored 属性影响的单独向量索引。

  • stored 属性是在向量字段上创建索引期间设置的,并且是不可逆的。 如果以后想要检索内容,则必须删除并重建索引,或者创建并加载具有新属性的新字段。

  • 默认情况下,stored 设置为 true,retrievable 设置为 false。 在默认配置中,会存储可检索的副本,但不会在结果中自动返回。 当 stored 为 true 时,可以随时在 true 和 false 之间切换可检索 retrievable,而无需重建索引。 当 stored 为 false 时,retrievable 也必须为 false 并且不能更改。

选项 3:配置标量量化

建议使用内置标量量化,因为它可以降低对内存和磁盘存储的需求,并且增加重新排名和过采样以抵消较小索引的影响。 内置标量量化可应用于包含 Float32Float16 数据的向量字段。

若要使用内置向量压缩,请执行以下操作:

  • vectorSearch.compressions 添加到搜索索引。 此预览版支持的压缩算法是标量量化。
  • 设置可选属性以减轻有损索引的影响。 rerankWithOriginalVectorsdefaultOversampling 都会在查询执行期间提供优化。
  • vectorSearch.profiles.compression 添加到新的向量配置文件。
  • 将新的向量配置文件分配给新的向量字段。

添加压缩设置并设置可选属性

在使用 2024-03-01-preview REST API 创建的索引定义中,添加 compressions 节。 使用以下 JSON 作为模板。

"compressions": [

      {  
        "name": "my-scalar-quantization",  
        "kind": "scalarQuantization",  
        "rerankWithOriginalVectors": true,  (optional)
        "defaultOversampling": 10.0,  (optional)
        "scalarQuantizationParameters": {  (optional)
             "quantizedDataType": "int8",  (optional)
        }
      }  
   ]

要点

  • kind 必须设置为 scalarQuantization。 这是目前唯一支持的量化方法。

  • rerankWithOriginalVectors 使用原始的未压缩向量来重新计算相似性,并对初始搜索查询返回的顶部结果进行重新排名。 即使 stored 为 false,未压缩的向量也存在于搜索索引中。 此属性是可选的。 默认值为 true。

  • defaultOversampling 将考虑更广泛的潜在结果,以抵消量化导致的信息减少。 潜在结果的公式由查询中的 k 和过采样乘数组成。 例如,如果查询指定 k 为 5,并且过采样为 20,则查询实际上会请求 100 个文档用于重新排序,并为此使用原始未压缩向量。 仅返回前 k 个重新排序的结果。 此属性是可选的。 默认值为 4。

  • quantizedDataType 必须设置为 int8。 这是目前唯一支持的基元数据类型。 此属性是可选的。 默认值为 int8

将压缩设置添加到向量配置文件

标量量化被指定为新的向量配置文件中的属性。 要在内存中构建压缩索引,必须创建新的向量配置文件。

在配置文件中,必须使用分层可导航小世界 (HNSW) 算法。 详尽的 KNN 不支持内置量化。

  1. 创建新的向量配置文件并添加压缩属性。

    "profiles": [
       {
          "name": "my-vector-profile",
          "compression": "my-scalar-quantization", 
          "algorithm": "my-hnsw-vector-config-1",
          "vectorizer": null
       }
     ]
    
  2. 将向量配置文件分配给的向量字段。 标量量化会将内容减少为 Int8,因此请确保你的内容是 Float32Float16

    在 Azure AI 搜索中,Float32Float16 类型的实体数据模型 (EDM) 等效项分别是 Collection(Edm.Single)Collection(Edm.Half)

    {
       "name": "DescriptionVector",
       "type": "Collection(Edm.Single)",
       "searchable": true,
       "retrievable": true,
       "dimensions": 1536,
       "vectorSearchProfile": "my-vector-profile"
    }
    
  3. 使用用于拉取模型索引的索引器或用于推送模型索引的 API 加载索引

标量量化降低了每个向量嵌入中每个数字的分辨率。 它没有将每个数字描述为 32 位浮点数,而是使用 8 位整数。 它标识一系列数字(通常是第 99 个百分位数的最小值和最大值),将它们划分为有限数量的级别或容器,并为每个容器分配一个标识符。 在 8 位标量量化中,有 2^8 或 256 个可能的 bin。

向量的每个分量都被映射到这组量化级别内最接近的代表值,其过程类似于将实数舍入到最接近的整数。 在量化的 8 位向量中,标识符号代替原始值。 量化后,每个向量都由其分量所属的 bin 的标识符数组表示。 与原始向量相比,这些量化向量需要存储的位数要少得多,从而减少所需存储和内存占用。

使用 vectorCompression、数据类型和 stored 属性的示例索引

以下是搜索索引的 JSON 示例,该索引指定 Float32 字段上的 vectorCompression、第二个向量字段上的 Float16 数据类型以及设置为 false 的 stored 属性。 它是此预览中的向量压缩和存储功能的组合。

### Create a new index
POST {{baseUrl}}/indexes?api-version=2024-03-01-preview  HTTP/1.1
    Content-Type: application/json
    api-key: {{apiKey}}

{
    "name": "hotels-vector-quickstart",
    "fields": [
        {
            "name": "HotelId", 
            "type": "Edm.String",
            "searchable": false, 
            "filterable": true, 
            "retrievable": true, 
            "sortable": false, 
            "facetable": false,
            "key": true
        },
        {
            "name": "HotelName", 
            "type": "Edm.String",
            "searchable": true, 
            "filterable": false, 
            "retrievable": true, 
            "sortable": true, 
            "facetable": false
        },
        {
            "name": "HotelNameVector",
            "type": "Collection(Edm.Half)",
            "searchable": true,
            "retrievable": false,
            "dimensions": 1536,
            "stored": false,
            "vectorSearchProfile": "my-vector-profile-no-compression"
        },
        {
            "name": "Description", 
            "type": "Edm.String",
            "searchable": true, 
            "filterable": false, 
            "retrievable": false, 
            "sortable": false, 
            "facetable": false,
            "stored": false,
        },
        {
            "name": "DescriptionVector",
            "type": "Collection(Edm.Single)",
            "searchable": true,
            "retrievable": true,
            "dimensions": 1536,
            "vectorSearchProfile": "my-vector-profile-with-compression"
        },
        {
            "name": "Category", 
            "type": "Edm.String",
            "searchable": true, 
            "filterable": true, 
            "retrievable": true, 
            "sortable": true, 
            "facetable": true
        },
        {
            "name": "Tags",
            "type": "Collection(Edm.String)",
            "searchable": true,
            "filterable": true,
            "retrievable": true,
            "sortable": false,
            "facetable": true
        },
        {
            "name": "Address", 
            "type": "Edm.ComplexType",
            "fields": [
                {
                    "name": "City", "type": "Edm.String",
                    "searchable": true, "filterable": true, "retrievable": true, "sortable": true, "facetable": true
                },
                {
                    "name": "StateProvince", "type": "Edm.String",
                    "searchable": true, "filterable": true, "retrievable": true, "sortable": true, "facetable": true
                }
            ]
        },
        {
            "name": "Location",
            "type": "Edm.GeographyPoint",
            "searchable": false, 
            "filterable": true, 
            "retrievable": true, 
            "sortable": true, 
            "facetable": false
        }
    ],
    "vectorSearch": {
        "compressions": [
          {  
            "name": "my-scalar-quantization",  
            "kind": "scalarQuantization",  
            "rerankWithOriginalVectors": true,  
            "defaultOversampling": 10.0,  
            "scalarQuantizationParameters": {  
              "quantizedDataType": "int8",
            }  
          }  
        ],  
        "algorithms": [
            {
                "name": "my-hnsw-vector-config-1",
                "kind": "hnsw",
                "hnswParameters": 
                {
                    "m": 4,
                    "efConstruction": 400,
                    "efSearch": 500,
                    "metric": "cosine"
                }
            },
            {
                "name": "my-hnsw-vector-config-2",
                "kind": "hnsw",
                "hnswParameters": 
                {
                    "m": 4,
                    "metric": "euclidean"
                }
            },
            {
                "name": "my-eknn-vector-config",
                "kind": "exhaustiveKnn",
                "exhaustiveKnnParameters": 
                {
                    "metric": "cosine"
                }
            }
        ],
        "profiles": [      
            {
                "name": "my-vector-profile-with-compression",
                "compression": "my-scalar-quantization", 
                "algorithm": "my-hnsw-vector-config-1",
                "vectorizer": null
            },
            {
                "name": "my-vector-profile-no-compression",
                "compression": null, 
                "algorithm": "my-eknn-vector-config",
                "vectorizer": null
            }
      ]
    },
    "semantic": {
        "configurations": [
            {
                "name": "my-semantic-config",
                "prioritizedFields": {
                    "titleField": {
                        "fieldName": "HotelName"
                    },
                    "prioritizedContentFields": [
                        { "fieldName": "Description" }
                    ],
                    "prioritizedKeywordsFields": [
                        { "fieldName": "Tags" }
                    ]
                }
            }
        ]
    }
}

使用过采样查询量化向量字段

此示例中的查询语法适用于使用内置标量量化的向量字段。 默认情况下,使用标量量化的向量字段还使用 rerankWithOriginalVectorsdefaultOversampling 来减轻较小向量索引的影响。 这些设置在搜索索引中指定

在查询中,可以替代过采样默认值。 例如,如果 defaultOversampling 为 10.0,可以在查询请求中将其更改为其他值。

即使索引没有显式 rerankWithOriginalVectorsdefaultOversampling 定义,也可以设置过采样参数。 在查询时提供过采样会替代该查询的索引设置,并将 oversampling 设置为 rerankWithOriginalVectors 来执行查询。

POST https://[service-name].search.azure.cn/indexes/[index-name]/docs/search?api-version=2024-03-01-Preview   
  Content-Type: application/json   
  api-key: [admin key]   

    {    
       "vectorQueries": [
            {    
                "kind": "vector",    
                "vector": [8, 2, 3, 4, 3, 5, 2, 1],    
                "fields": "myvector",
                "oversampling": 12.0,
                "k": 5   
            }
      ]    
    }

要点

  • 适用于根据向量配置文件分配进行矢量压缩的向量字段。

  • 即使索引的压缩配置未指定过采样或重新排名选项,也会在查询时替代 defaultOversampling 值或引入过采样。

另请参阅