Compartir por


Reducir el tamaño del vector mediante la cuantización, tipos de datos reducidos y opciones de almacenamiento

En este artículo se explica cómo usar la cuantificación de vectores y otras técnicas para reducir el tamaño de vector en Azure AI Search. El índice de búsqueda especifica definiciones de campo vectorial, incluidas las propiedades de los tipos de datos almacenados y estrechos. La cuantificación también se especifica en el índice y se asigna al campo vectorial a través de su perfil de vector.

Estas características están disponibles con carácter general en la API REST 2024-07-01 y en los paquetes de Azure SDK destinados a esa versión. Un ejemplo al final de este artículo muestra las variaciones en el tamaño de vector para cada uno de los enfoques descritos en este artículo.

Evaluación de las opciones

Como primer paso, revise los tres enfoques para reducir la cantidad de almacenamiento utilizado por los campos vectoriales. Estos enfoques no son mutuamente excluyentes y se pueden combinar para reducir el tamaño máximo del vector.

Recomendamos la cuantización incorporada porque comprime el tamaño del vector en memoria y en disco con un esfuerzo mínimo, y eso tiende a proporcionar el mayor beneficio en la mayoría de los escenarios. Por el contrario, los tipos estrechos (excepto float16) requieren un esfuerzo especial para fabricarlos, y stored ahorran almacenamiento en disco, que no es tan caro como la memoria.

Enfoque Por qué usar esta opción
Adición de cuantificación escalar o binaria Use la cuantificación para comprimir incrustaciones float32 o float16 nativas en int8 (escalar) o Byte (binario). 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 o Byte, producen índices vectoriales menos ricos en contenido que aquellos con incrustaciones más grandes. 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. El reordenamiento y el sobremuestreo son características específicas de la cuantización incorporada de campos float32 o float16 y no pueden utilizarse en incrustaciones sometidas a una cuantización personalizada.
Asignación de tipos de datos primitivos más pequeños a campos vectoriales Los tipos de datos estrechos, como float16, int16, int8 y Byte (binario) consumen menos espacio en memoria y en disco, pero debe disponer de un modelo de incrustación que dé salida a los 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 refundición de las incrustaciones nativas float32 producidas por la mayoría de los modelos a float16. Consulte Índice de vectores binarios para obtener más información sobre los vectores binarios.
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 %.

Todas estas opciones se definen en un índice vacío. Para implementar cualquiera de ellos, use Azure Portal, las API REST o un paquete de Azure SDK destinado a esa versión de API.

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

Opción 1: Configurar la cuantificación

Se recomienda la cuantificación para reducir el tamaño del vector porque reduce los requisitos de almacenamiento de memoria y disco para las inserciones float16 y float32. Para desplazar los efectos de un índice más pequeño, puede agregar sobremuestreo y reectángulos sobre vectores sin comprimir.

La cuantificación se aplica a los campos vectoriales que reciben vectores de tipo float. En los ejemplos de este artículo, el tipo de datos del campo es Collection(Edm.Single) para incrustaciones entrantes float32, pero también se admite float16. Cuando los vectores se reciben en un campo con compresión configurada, el motor realiza automáticamente la cuantificación para reducir la superficie de los datos vectoriales en la memoria y en el disco.

Se admiten dos tipos de cuantificación:

  • La cuantificación escalar comprime los valores float en tipos de datos más estrechos. Ai Search admite actualmente int8, que es de 8 bits, lo que reduce el tamaño del índice vectorial cuatro veces.

  • La cuantificación binaria convierte los floats en bits binarios, que ocupa 1 bit. Esto da como resultado un tamaño de índice vectorial reducido hasta 28 veces menor.

Para usar la cuantificación integrada, siga estos pasos:

  • Uso de Create Index o Create Or Update Index para especificar la compresión de vectores
  • Agregue vectorSearch.compressions a un índice de búsqueda.
  • Agregue una scalarQuantization configuración o binaryQuantization y asígnele un nombre.
  • Establezca propiedades opcionales para mitigar los efectos de la indexación perdida.
  • Crear un nuevo perfil de vector que use la configuración con nombre
  • Creación de un nuevo campo de vector con el nuevo perfil de vector
  • Cargar el índice con datos float32 o float16 que se cuantifican durante la indexación con la configuración definida
  • Opcionalmente, consulte los datos cuantificados mediante el parámetro de sobremuestreo si desea invalidar el valor predeterminado.

Agregar "compresión" a un índice de búsqueda

En el ejemplo siguiente se muestra una definición de índice parcial con una colección de campos que incluye un campo vectorial y una sección vectorSearch.compressions.

En este ejemplo se incluyen scalarQuantization o binaryQuantization. Puede especificar tantas configuraciones de compresión como necesite y, a continuación, asignar las que desee a un perfil de vector.

POST https://[servicename].search.windows.net/indexes?api-version=2024-07-01

{
  "name": "my-index",
  "fields": [
    { "name": "Id", "type": "Edm.String", "key": true, "retrievable": true, "searchable": true, "filterable": true },
    { "name": "content", "type": "Edm.String", "retrievable": true, "searchable": true },
    { "name": "vectorContent", "type": "Collection(Edm.Single)", "retrievable": false, "searchable": true },
  ],
  "vectorSearch": {
        "profiles": [ ],
        "algorithms": [ ],
        "compressions": [
          {
            "name": "use-scalar",
            "kind": "scalarQuantization",
            "scalarQuantizationParameters": {
              "quantizedDataType": "int8"
            },
            "rerankWithOriginalVectors": true,
            "defaultOversampling": 10
          },
          {
            "name": "use-binary",
            "kind": "binaryQuantization",
            "rerankWithOriginalVectors": true,
            "defaultOversampling": 10
          }
        ]
    }
}

Puntos clave:

  • kind debe establecerse en scalarQuantization o binaryQuantization.

  • 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 es opcional y solo se aplica a la cuantificación escalar. Si lo agrega, debe establecerse en int8. Este es el único tipo de datos primitivo admitido para la cuantificación escalar en este momento. El valor predeterminado es int8.

Adición del algoritmo HNSW

Asegúrese de que el índice tiene el algoritmo Jerárquico de mundos pequeños navegables (HNSW). La cuantificación integrada no se admite con KNN exhaustiva.

"vectorSearch": {
    "profiles": [ ],
    "algorithms": [
      {
          "name": "use-hnsw",
          "kind": "hnsw",
          "hnswParameters": {
              "m": 4,
              "efConstruction": 400,
              "efSearch": 500,
              "metric": "cosine"
          }
      }
    ],
     "compressions": [ <see previous section>] 
}

Creación y asignación de un nuevo perfil de vector

Para usar una nueva configuración de cuantificación, debe crear un nuevo perfil de vector. La creación de un nuevo perfil de vector es necesaria para crear índices comprimidos en memoria. El nuevo perfil usa HNSW.

  1. En la misma definición de índice, cree un nuevo perfil de vector y agregue una propiedad de compresión y un algoritmo. Estos son dos perfiles, uno para cada enfoque de cuantificación.

    "vectorSearch": {
        "profiles": [
           {
              "name": "vector-profile-hnsw-scalar",
              "compression": "use-scalar", 
              "algorithm": "use-hnsw",
              "vectorizer": null
           },
           {
              "name": "vector-profile-hnsw-binary",
              "compression": "use-binary", 
              "algorithm": "use-hnsw",
              "vectorizer": null
           }
         ],
         "algorithms": [  <see previous section> ],
         "compressions": [ <see previous section> ] 
    }
    
  2. Asigne un perfil de vector a un nuevo campo vectorial. El tipo de datos del campo es float32 o float16.

    En Azure AI Search, los equivalentes en el Modelo de Datos de Entidades (EDM) de los tipos float32 y float16 son Collection(Edm.Single) y Collection(Edm.Half), respectivamente.

    {
       "name": "vectorContent",
       "type": "Collection(Edm.Single)",
       "searchable": true,
       "retrievable": true,
       "dimensions": 1536,
       "vectorSearchProfile": "vector-profile-hnsw-scalar",
    }
    
  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 coma flotante de 16 o 32 bits, utiliza un número 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.

La cuantificación binaria comprime vectores de alta dimensión mediante la representación de cada componente como un solo bit, ya sea 0 o 1. Este método reduce drásticamente la superficie de memoria y acelera las operaciones de comparación de vectores, que son cruciales para las tareas de búsqueda y recuperación. Las pruebas comparativas muestran una reducción del 96 % en el tamaño del índice vectorial.

Es especialmente eficaz para las incrustaciones con dimensiones mayores que 1024. Para dimensiones más pequeñas, se recomienda probar la calidad de la cuantificación binaria o probar escalar en su lugar. Además, hemos encontrado que BQ funciona muy bien cuando las incrustaciones se centran alrededor de cero. Los modelos de inserción más populares, como OpenAI, Cohere y Mistral, se centran alrededor de cero.

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

Una manera fácil de reducir el tamaño del vector es almacenar incrustaciones en un formato de datos más pequeño. La mayoría de los modelos de inserción generan números de punto flotante de 32 bits, pero si cuantifica los vectores, o si el modelo de inserción lo admite de forma nativa, la salida puede ser float16, int16 o int8, que es significativamente menor que float32. Puede acomodar estos tamaños de vector más pequeños asignando un tipo de datos estrecho a un campo vectorial. En el índice vectorial, los tipos de datos estrechos consumen menos almacenamiento.

  1. Revise los tipos de datos usados para los campos vectoriales para el uso recomendado:

    • Número de punto flotante de 32 bits Collection(Edm.Single) (valor predeterminado)
    • Collection(Edm.Half) Punto flotante de 16 bits (estrecho)
    • Collection(Edm.Int16) Entero con signo de 16 bits (estrecho)
    • Collection(Edm.SByte) Entero con signo de 8 bits (estrecho)
    • Collection(Edm.Byte) Entero sin signo de 8 bits (solo se permite con tipos de datos binarios empaquetados)
  2. En esa lista, determine qué tipo de datos es válido para la salida del modelo de inserción o para los vectores que se someten a la cuantificación personalizada.

    En la tabla siguiente se proporcionan vínculos a varios modelos de inserción que pueden usar un tipo de datos estrecho (Collection(Edm.Half)) sin cuantificación adicional. Puede convertir de float32 a float16 (mediante Collection(Edm.Half)) sin trabajo adicional.

    Modelo de inserción Salida nativa Asignación de este tipo 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)

    Se pueden usar otros tipos de datos estrechos si el modelo emite incrustaciones en el formato de datos más pequeño o si tiene una cuantificación personalizada que convierte vectores a un formato más pequeño.

  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, Crear o actualizar índice (API REST)o un paquete de Azure SDK 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.

    Para comprobar el tamaño del índice vectorial, use Azure Portal o get Statistics (API REST).

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 3: 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. Esta propiedad stored es true de forma predeterminada. Si no necesita contenido vectorial en una respuesta de consulta, puede guardar hasta el 50 % de almacenamiento por campo estableciendo stored en false.

Consideraciones para establecer stored en false:

  • Dado que los vectores no son legibles para las personas, puede omitirlos de los resultados enviados a los LLM en los escenarios RAG y de los resultados que se muestran en una página de búsqueda. No obstante, manténgalos, si usa vectores en un proceso de bajada que consume contenido vectorial.

  • Sin embargo, si la estrategia de indexación incluye actualizaciones parciales del documento, como "merge" o "mergeOrUpload" en un documento, tenga en cuenta que si stored se establece en false, los vectores del campo no almacenado se omitirán durante la combinación. En cada operación "merge" o "mergeOrUpload", debe proporcionar los campos vectoriales además de otros campos no vectoriales que esté actualizando, o el vector se eliminará.

Recuerde que la stored atribución es irreversible. Se establece durante la creación de índices en campos vectoriales cuando se crean estructuras de datos físicas. 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.

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/demo-index?api-version=2024-07-01 
   Content-Type: application/json  
   api-key: [admin key]  
 
     { 
       "name": "demo-index", 
       "fields": [ 
         { 
           "name": "vectorContent", 
           "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.

Ejemplo: técnicas de compresión vectorial

Este es el código de Python que muestra la cuantificación, los tipos de datos estrechos y el uso de la propiedad almacenada: Ejemplo de código: cuantificación de vectores y opciones de almacenamiento mediante Python.

Este código crea y compara el tamaño del índice de almacenamiento y vector para cada opción:

****************************************
Index Name: compressiontest-baseline
Storage Size: 21.3613MB
Vector Size: 4.8277MB
****************************************
Index Name: compressiontest-compression
Storage Size: 17.7604MB
Vector Size: 1.2242MB
****************************************
Index Name: compressiontest-narrow
Storage Size: 16.5567MB
Vector Size: 2.4254MB
****************************************
Index Name: compressiontest-no-stored
Storage Size: 10.9224MB
Vector Size: 4.8277MB
****************************************
Index Name: compressiontest-all-options
Storage Size: 4.9192MB
Vector Size: 1.2242MB

Las API de búsqueda notifican el almacenamiento y el tamaño de vector en el nivel de índice, por lo que los índices y no los campos deben ser la base de la comparación. Use las estadísticas de índice GET o una API equivalente en los SDK de Azure para obtener el tamaño del vector.

Consulta de un campo vectorial cuantificado mediante el sobremuestreo

La sintaxis de consulta para un campo vectorial comprimido o cuantificado es la misma que para los campos vectoriales no comprimidos, a menos que desee invalidar los parámetros asociados con el sobremuestreo o el reequilibrado con vectores originales.

Recuerde que la definición de compresión vectorial del índice tiene la configuración de rerankWithOriginalVectors y defaultOversampling para mitigar los efectos de un índice vectorial más pequeño. Puede invalidar los valores predeterminados para variar el comportamiento en el momento de la consulta. 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/demo-index/docs/search?api-version=2024-07-01   
  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