Configuración de la cuantificación de vectores y el almacenamiento reducido para vectores más pequeños en Azure AI Search

Importante

Estas características se encuentran en versión preliminar pública en las Condiciones de uso complementarias. La API REST 2024-03-01-Preview proporciona los nuevos tipos de datos, propiedades de compresión de vectores y la propiedad stored.

En este artículo se describen la cuantificación de vectores y otras técnicas para comprimir índices vectoriales en Azure AI Search.

Evaluación de las opciones

Como primer paso, revise las opciones para reducir la cantidad de almacenamiento que usan los campos vectoriales. Estas opciones se excluyen mutuamente.

Se recomienda la cuantificación escalar porque comprime el tamaño del vector en memoria y en el disco con un esfuerzo mínimo, y esto tiende a proporcionar la mayor ventaja en la mayoría de los escenarios. Los tipos estrechos (excepto Float16) requieren un esfuerzo especial para fabricarse y stored ahorra almacenamiento, que no es tan costoso como la memoria.

Enfoque Por qué usar esta opción
Asignación de tipos de datos primitivos más pequeños a campos vectoriales Los tipos de datos estrechos, como Float16, Int16 y Int8, consumen menos espacio en memoria y en disco, pero debe tener un modelo de inserción que genera vectores en un formato de datos estrecho. O bien, si tiene lógica de cuantificación personalizada que genera datos pequeños. Un tercer caso de uso que requiere menos esfuerzo es la redifusión de incrustaciones nativas Float32 producidas por la mayoría de los modelos a Float16.
Eliminación del almacenamiento opcional de vectores recuperables Los vectores devueltos en una respuesta de consulta se almacenan por separado de los vectores utilizados durante la ejecución de la consulta. Si no necesita devolver vectores, puede desactivar el almacenamiento recuperable, lo que reduce el almacenamiento total por campo hasta un 50 %.
Adición de cuantificación escalar Use la cuantificación escalar integrada para comprimir incrustaciones nativas de Float32 en Int8. Esta opción reduce el almacenamiento en memoria y en el disco sin degradar el rendimiento de las consultas. Los tipos de datos más pequeños, como Int8, generan índices vectoriales que están menos enriquecidos con contenido que los que tienen incrustaciones de Float32. Para compensar la pérdida de información, la compresión integrada incluye opciones para el procesamiento posterior a consultas mediante incrustaciones sin comprimir y sobremuestreo para devolver resultados más relevantes. La reclasificación y el sobremuestreo son características específicas de la cuantificación escalar incorporada de campos Float32 o Float16 y no se pueden usar en incrustaciones que se sometan a una cuantificación personalizada.

Todas estas opciones se definen en un índice vacío. Para implementar cualquiera de ellas, use Azure Portal, API REST 2024-03-01-preview o un paquete beta del SDK de Azure.

Una vez definido el índice, puede cargar e indexar documentos como paso independiente.

Opción 1: Asignar tipos de datos estrechos a campos vectoriales

Los campos vectoriales almacenan incrustaciones de vectores, que se representan como una matriz de números. Al especificar un tipo de campo, se especifica el tipo de datos primitivo subyacente que se usa para contener cada número dentro de estas matrices. El tipo de datos afecta a la cantidad de espacio que ocupa cada número.

Con las API en versión preliminar, puede asignar tipos de datos primitivos estrechos para reducir los requisitos de almacenamiento de los campos vectoriales.

  1. Revise los tipos de datos de los campos vectoriales:

    • Número de punto flotante de 32 bits Collection(Edm.Single) (valor predeterminado)
    • Número de punto flotante de 16 bits Collection(Edm.Half)
    • Collection(Edm.Int16) Entero de 16 bits con signo
    • Collection(Edm.SByte) Entero de 8 bits con signo

    Nota:

    Actualmente no se admiten tipos de datos binarios.

  2. Elija un tipo de datos válido para la salida del modelo de inserción o para los vectores que se sometan a la cuantificación personalizada.

    La mayoría de los modelos de inserción generan números de punto flotante de 32 bits, pero si aplica la cuantificación personalizada, la salida podría ser Int16 o Int8. Ahora puede definir campos vectoriales que acepten el formato más pequeño.

    Los modelos de inserción de texto tienen un formato de salida nativo de Float32, que se asigna a Collection(Edm.Single) en Azure AI Search. No se puede asignar esa salida a Int8 porque la conversión de float a int está prohibida. Sin embargo, puede convertir de Float32 a Float16 (o Collection(Edm.Half)) y es una manera fácil de usar tipos de datos estrechos sin trabajo adicional.

    En la tabla siguiente se proporcionan vínculos a varios modelos de inserción que usan los tipos de datos estrechos.

    Modelo de inserción Salida nativa Tipos válidos en Azure AI Search
    text-embedding-ada-002 Float32 Collection(Edm.Single) o Collection(Edm.Half)
    text-embedding-3-small Float32 Collection(Edm.Single) o Collection(Edm.Half)
    text-embedding-3-large Float32 Collection(Edm.Single) o Collection(Edm.Half)
    Modelos de inserción de Cohere V3 con int8 embedding_type Int8 Collection(Edm.SByte)
  3. Asegúrese de comprender los inconvenientes de un tipo de datos estrecho. Collection(Edm.Half) tiene menos información, lo que da como resultado una resolución menor. Si los datos son homogéneos o densos, la pérdida de detalles o matices adicionales podría dar lugar a resultados inaceptables en el momento de la consulta, ya que hay menos detalles que se pueden usar para distinguir los vectores cercanos.

  4. Defina y compile el índice. Puede usar Azure Portal, 2024-03-01-previewo un paquete beta del SDK de Azure para este paso.

  5. Comprobar los resultados. Suponiendo que el campo vectorial está marcado como recuperable, use el Explorador de búsqueda o la API REST para comprobar que el contenido del campo coincida con el tipo de datos. Asegúrese de usar la versión de API correcta de 2024-03-01-preview para la consulta; de lo contrario, no se mostrarán las nuevas propiedades.

Para comprobar el tamaño del índice vectorial, use Azure Portal o 2024-03-01-preview.

Nota:

El tipo de datos del campo se usa para crear la estructura de datos física. Si desea cambiar un tipo de datos más adelante, quite y recompile el índice o cree un segundo campo con la nueva definición.

Opción 2: Establecer la propiedad stored para quitar el almacenamiento recuperable

La propiedad stored es un nuevo booleano en una definición de campo vectorial que determina si el almacenamiento se asigna para el contenido del campo vectorial recuperable. Si no necesita contenido vectorial en una respuesta de consulta, puede guardar hasta el 50 % de almacenamiento por campo estableciendo stored en false.

Dado que los vectores no son legibles por el usuario, normalmente se omiten en una respuesta de consulta que se representa en una página de búsqueda. Sin embargo, si usa vectores en el procesamiento de bajada, como pasar los resultados de la consulta a un modelo o proceso que consuma contenido vectorial, deberá mantener stored establecido en true y elegir una técnica diferente para minimizar el tamaño del vector.

En el ejemplo siguiente se muestra la colección de campos de un índice de búsqueda. Establezca stored en false para quitar permanentemente el almacenamiento recuperable para el campo vectorial.

PUT https://[service-name].search.windows.net/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" 
         } 
       ] 
     } 

Puntos clave:

  • Esto solo se aplica a los campos vectoriales.

  • Afecta al almacenamiento en disco, no a la memoria y no tiene ningún efecto en las consultas. La ejecución de consultas usa un índice vectorial independiente que no se ve afectado por la propiedad stored.

  • La propiedad stored se establece durante la creación del índice en los campos vectoriales y es irreversible. Si más adelante quiere recuperar contenido, deberá quitar y recompilar el índice, o bien crear y cargar un nuevo campo que tenga la nueva atribución.

  • Los valores predeterminados son stored establecidos en true y retrievable establecidos en false. En una configuración predeterminada, se almacena una copia recuperable, pero no se devuelve automáticamente en los resultados. Cuando stored es true, puede alternar retrievable entre true y false en cualquier momento sin tener que volver a generar un índice. Cuando stored es false, retrievable debe ser false y no se puede cambiar.

Opción 3: Configurar la cuantificación escalar

Se recomienda la cuantificación escalar incorporada porque reduce los requisitos de memoria y almacenamiento en disco, y agrega reclasificación y sobremuestreo para compensar los efectos de un índice más pequeño. La cuantificación escalar integrada se puede aplicar a los campos vectoriales que contienen datos Float32 o Float16.

Para usar la compresión vectorial integrada:

  • Agregue vectorSearch.compressions a un índice de búsqueda. El algoritmo de compresión admitido en esta versión preliminar es la cuantificación escalar.
  • Establezca propiedades opcionales para mitigar los efectos de la indexación perdida. Tanto rerankWithOriginalVectors como defaultOversampling proporcionan optimizaciones durante la ejecución de consultas.
  • Agregue vectorSearch.profiles.compression a un nuevo perfil de vector.
  • Asigne el nuevo perfil de vector a un nuevo campo vectorial.

Adición de la configuración de compresión y establecimiento de propiedades opcionales

En una definición de índice creada con la API REST 2024-03-01-preview, agregue una sección compressions. Use el siguiente valor JSON como plantilla.

"compressions": [

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

Puntos clave:

  • kind se debe establecer en scalarQuantization. Este es el único método de cuantificación admitido en este momento.

  • rerankWithOriginalVectors usa los vectores originales sin comprimir para recalcular la similitud y volver a generar los resultados principales devueltos por la consulta de búsqueda inicial. Los vectores sin comprimir existen en el índice de búsqueda aunque stored sea false. Esta propiedad es opcional. El valor predeterminado es true.

  • defaultOversampling considera un conjunto más amplio de resultados potenciales para compensar la reducción de la información de la cuantificación. La fórmula para los posibles resultados consta de la k en la consulta, con un multiplicador de sobremuestreo. Por ejemplo, si la consulta especifica una k de 5 y el sobremuestreo es 20, la consulta solicita eficazmente 100 documentos para su uso en la reedición, y utiliza el vector sin comprimir original para ese propósito. Solo se devuelven los mejores k resultados reclasificados. Esta propiedad es opcional. El valor predeterminado es 4.

  • quantizedDataType se debe establecer en int8. Este es el único tipo de datos primitivo que se admite en este momento. Esta propiedad es opcional. El valor predeterminado es int8.

Adición de una configuración de compresión a un perfil de vector

La cuantificación escalar se especifica como una propiedad en un nuevo perfil de vector. La creación de un nuevo perfil de vector es necesaria para crear índices comprimidos en memoria.

Dentro del perfil, debe usar el algoritmo de mundos pequeños jerárquicos navegables (HNSW). La cuantificación integrada no se admite con KNN exhaustiva.

  1. Cree un perfil de vector y agregue una propiedad de compresión.

    "profiles": [
       {
          "name": "my-vector-profile",
          "compression": "my-scalar-quantization", 
          "algorithm": "my-hnsw-vector-config-1",
          "vectorizer": null
       }
     ]
    
  2. Asigne un perfil de vector a un nuevo campo vectorial. La cuantificación escalar reduce el contenido a Int8, así que asegúrese de que el contenido sea Float32 o Float16.

    En Azure AI Search, los equivalentes de Entity Data Model (EDM) de los tipos Float32 y Float16 son Collection(Edm.Single) y Collection(Edm.Half), respectivamente.

    {
       "name": "DescriptionVector",
       "type": "Collection(Edm.Single)",
       "searchable": true,
       "retrievable": true,
       "dimensions": 1536,
       "vectorSearchProfile": "my-vector-profile"
    }
    
  3. Cargue el índice mediante indexadores para la indexación de modelos de extracción o API para la indexación de modelos de inserción.

La cuantificación escalar reduce la resolución de cada número dentro de cada inserción de vectores. En lugar de describir cada número como un número de punto flotante de 32 bits, usa un entero de 8 bits. Identifica un rango de números (normalmente percentil 99 mínimo y máximo) y los divide en un número finito de niveles o rangos, asignando a cada contenedor un identificador. En la cuantificación escalar de 8 bits, hay 2^8 o 256 rangos posibles.

Cada componente del vector se asigna al valor representativo más cercano dentro de este conjunto de niveles de cuantificación en un proceso similar a redondear un número real al entero más cercano. En el vector cuantificado de 8 bits, el número de identificador se sitúa en lugar del valor original. Después de la cuantificación, cada vector se representa mediante una matriz de identificadores para los contenedores a los que pertenecen sus componentes. Estos vectores cuantificados requieren muchos menos bits para almacenarse en comparación con el vector original, lo que reduce los requisitos de almacenamiento y la huella de memoria.

Índice de ejemplo con vectorCompression, tipos de datos y propiedad almacenada

Este es un ejemplo compuesto de un índice de búsqueda que especifica tipos de datos estrechos, almacenamiento reducido y compresión vectorial.

  • "HotelNameVector" proporciona un ejemplo de tipo de datos estrecho, redifusión de los valores originales Float32 a Float16, expresado como Collection(Edm.Half) en el índice de búsqueda.
  • "HotelNameVector" también se ha stored establecido en false. Las incrustaciones adicionales que se usan en una respuesta de consulta no se almacenan. Cuando stored es false, retrievable también debe ser false.
  • "DescriptionVector" proporciona un ejemplo de compresión vectorial. La compresión vectorial se define en el índice, al que se hace referencia en un perfil y, a continuación, se asigna a un campo vectorial. "DescriptionVector" también se ha stored establecido en false.
### 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
        },
        {
            "name": "DescriptionVector",
            "type": "Collection(Edm.Single)",
            "searchable": true,
            "retrievable": false,
            "dimensions": 1536,
            "stored": false,
            "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" }
                    ]
                }
            }
        ]
    }
}

Consulta de un campo vectorial cuantificado mediante el sobremuestreo

La sintaxis de consulta de este ejemplo se aplica a los campos vectoriales mediante la cuantificación escalar integrada. De forma predeterminada, los campos vectoriales que usan la cuantificación escalar también usan rerankWithOriginalVectors y defaultOversampling para mitigar los efectos de un índice vectorial más pequeño. Esos valores se especifican en el índice de búsqueda.

En la consulta, puede invalidar el valor predeterminado de sobremuestreo. Por ejemplo, si defaultOversampling es 10,0, puede cambiarlo a otra cosa en la solicitud de consulta.

Puede establecer el parámetro de sobremuestreo aunque el índice no tenga explícitamente una definición rerankWithOriginalVectors o defaultOversampling. Proporcionar oversampling en tiempo de consulta invalida la configuración de índice para esa consulta y ejecuta la consulta con un valor efectivo rerankWithOriginalVectors como true.

POST https://[service-name].search.windows.net/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   
            }
      ]    
    }

Puntos clave:

  • Se aplica a campos vectoriales que se someten a compresión vectorial, según la asignación del perfil vectorial.

  • Invalida el valor defaultOversampling o introduce el sobremuestreo en el momento de la consulta, incluso aunque en la configuración de compresión del índice no se especificaran opciones de sobremuestreo o reclasificación.

Consulte también