Partager via


Compresser des vecteurs à l’aide de la quantification scalaire ou binaire

La recherche Azure AI prend en charge la quantification scalaire et binaire pour réduire la taille des vecteurs dans un index de recherche. Nous recommandons la quantification pour réduire la taille de vecteurs, car elle diminue la consommation de mémoire et de disque pour les incorporations float16 et float32. Pour compenser les effets de la compression avec perte, vous pouvez ajouter un suréchantillonnage et un rescoring sur les vecteurs non compressés.

Pour utiliser la quantification intégrée, suivez ces étapes :

  • Commencer par des champs vectoriels et une vectorSearchconfiguration à un index
  • Ajouter vectorSearch.compressions
  • Ajouter une configuration scalarQuantization ou binaryQuantization et lui donner un nom
  • Définir des propriétés facultatives pour atténuer les effets de l’indexation avec perte
  • Créer un profil vectoriel qui utilise la configuration nommée
  • Créer un profil vectoriel ayant le nouveau profil vectoriel
  • Charger l’index avec des données float32 ou float16 quantifiées pendant l’indexation par la configuration définie
  • Vous pouvez également interroger des données quantifiées en utilisant le paramètre de suréchantillonnage si vous voulez remplacer la valeur par défaut

Prérequis

  • Champs vectoriels dans un index de recherche avec une vectorSearch configuration, à l’aide des algorithmes HNSW (Hierarchical Navigable Small Worlds) ou des algorithmes de plus proche voisin K (eKNN) complets et d’un nouveau profil vectoriel.

Techniques de quantification prises en charge

La quantification s’applique aux champs vectoriels recevant des vecteurs de type float. Dans les exemples de cet article, le type de données du champ est Collection(Edm.Single) pour les incorporations float32 entrantes, mais float16 est également pris en charge. Quand les vecteurs sont reçus sur un champ ayant la compression configurée, le moteur effectue automatiquement une quantification pour réduire l’empreinte mémoire des données vectorielles dans la mémoire et sur le disque.

Deux types de quantification sont pris en charge :

  • La quantification scalaire compresse les valeurs flottantes en types de données plus étroits. Recherche Azure AI prend actuellement en charge int8, qui est 8 bits, ce qui réduit la taille d’index vectoriel par quatre.

  • La quantification binaire convertit des floats en bits binaires qui prennent jusqu’à 1 bit. Ce qui se traduit par une taille d’index vectoriel réduite jusqu’à 28 fois.

Ajouter « compressions » à un index de recherche

L’exemple suivant montre une définition d’index partiel avec une collection de champs qui inclut un champ vectoriel et une section vectorSearch.compressions.

Elles comprennent scalarQuantization ou binaryQuantization. Vous pouvez spécifier autant de configurations de compression que nécessaire, puis attribuez celles souhaitées au profil vectoriel.

La syntaxe pour vectorSearch.Compressions varie entre les API REST stables et en préversion, avec la préversion ajoutant de nouvelles options pour l’optimisation du stockage, ainsi que les modifications apportées à la syntaxe existante. La rétrocompatibilité est préservée par les mappings internes de l'API, mais vous devez adopter la nouvelle syntaxe dans le code qui cible la version 2024-11-01-preview et les versions ultérieures.

Utilisez l'API REST Créer un index ou Créer ou mettre à jour un index pour configurer les paramètres de compression.

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, "dimensions": 1536,"vectorSearchProfile": "vector-profile-1"},
  ],
  "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
          }
        ]
    }
}

Points essentiels :

  • kind doit être défini sur scalarQuantization ou binaryQuantization.

  • rerankWithOriginalVectors utilise les vecteurs originaux non compressés pour recalculer la similarité et reclasser les meilleurs résultats renvoyés par la requête de recherche initiale. Les vecteurs non compressés existent dans l'index de recherche même si stored sont faux. Cette propriété est facultative. La valeur par défaut est true.

  • defaultOversampling considère un ensemble plus large de résultats potentiels pour compenser la réduction des informations résultant de la quantification. La formule des résultats potentiels consiste en le k dans la requête, avec un multiplicateur de suréchantillonnage. Par exemple, si la requête spécifie un k de 5 et que le suréchantillonnage est de 20, alors la requête demande effectivement 100 documents à utiliser dans le reclassement, en utilisant le vecteur non compressé d'origine à cette fin. Seuls les résultats k les mieux classés sont renvoyés. Cette propriété est facultative. La valeur par défaut est 4.

  • quantizedDataType est facultatif et s’applique à la quantification scalaire uniquement. Si vous l’ajoutez, il doit être défini sur int8. Il s’agit du seul type de données primitif pris en charge pour la quantification scalaire à l’heure actuelle. La valeur par défaut est int8.

Ajouter l’algorithme de recherche vectorielle

Vous pouvez utiliser l’algorithme HNSW ou un KNN exhaustif dans l’API REST 2024-11-01-preview. Pour la version stable, utilisez uniquement HNSW.

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

Créer et attribuer un profil vectoriel

Pour utiliser une nouvelle configuration de quantification, vous devez créer un profil vectoriel. La création d'un nouveau profil vectoriel est nécessaire pour créer des index compressés en mémoire. Votre nouveau profil utilise HNSW.

  1. Dans la même définition d’index, créez un profil vectoriel et ajoutez une propriété de compression et un algorithme. Voici deux profils, un pour chaque approche de quantification.

    "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. Attribuez un profil vectoriel à un nouveau champ vectoriel. Le type de données du champ est soit float32 ou soit float16.

    Dans Recherche Azure AI, les équivalents EDM (Entity Data Model) des types float32 et float16 sont Collection(Edm.Single) et Collection(Edm.Half), respectivement.

    {
       "name": "vectorContent",
       "type": "Collection(Edm.Single)",
       "searchable": true,
       "retrievable": true,
       "dimensions": 1536,
       "vectorSearchProfile": "vector-profile-hnsw-scalar",
    }
    
  3. Chargez l'index à l'aide d'indexeurs pour l'indexation du modèle pull ou d'API pour l'indexation du modèle push.

La quantification scalaire réduit la résolution de chaque nombre dans chaque intégration vectorielle. Au lieu de décrire chaque nombre comme un nombre à virgule flottante de 16 bits ou 32 bits, il utilise un entier de 8 bits. Il identifie une plage de nombres (généralement le minimum et le maximum du 99e percentile) et les divise en un nombre fini de niveaux ou de catégories, en attribuant à chaque catégorie un identifiant. Dans la quantification scalaire 8 bits, il existe 2 ^ 8, soit 256, bacs possibles.

Chaque composante du vecteur est mappée à la valeur représentative la plus proche au sein de cet ensemble de niveaux de quantification dans un processus semblable à l'arrondi d'un nombre réel à l'entier le plus proche. Dans le vecteur quantifié de 8 bits, le numéro d'identification remplace la valeur d'origine. Après quantification, chaque vecteur est représenté par un tableau d'identifiants pour les bacs auxquels appartiennent ses composants. Ces vecteurs quantifiés nécessitent beaucoup moins de bits à stocker par rapport au vecteur d'origine, réduisant ainsi les besoins de stockage et l'empreinte mémoire.

La quantification binaire compresse des vecteurs hautement dimensionnels en représentant chaque composant en tant que bit unique, 0 ou 1. Cette méthode réduit considérablement l’empreinte mémoire et accélère les opérations de comparaison vectorielle qui sont essentielles pour les tâches de recherche et d’extraction. Les tests de point de référence montrent jusqu’à 96 % de réduction en taille d’index vectoriel.

C’est particulièrement efficace pour les incorporations ayant des dimensions supérieures à 1024. Pour les dimensions plus petites, nous vous recommandons de tester la qualité de la quantification binaire ou d’essayer le type scalaire à la place. De plus, nous avons constaté que la quantification binaire fonctionne très bien lorsque les incorporations sont centrées sur zéro. La plupart des modèles d’incorporation connus tels qu’OpenAI, Cohere et Mistral sont centrés sur zéro.

Interroger un champ vectoriel quantifié en utilisant le suréchantillonnage

La syntaxe de requête d’un champ vectoriel compressé ou quantifié est la même que pour des champs vectoriels non compressés, sauf si vous souhaitez remplacer les paramètres associés au suréchantillonnage ou au rescoring par les vecteurs d’origine.

N’oubliez pas que la définition de compression vectorielle dans l’index a des paramètres pour rerankWithOriginalVectors et defaultOversampling qui permettent d’atténuer les effets d’une compression avec perte. Vous pouvez remplacer les valeurs par défaut afin de faire varier le comportement au moment de la requête. Par exemple, si defaultOversampling est 10.0, vous pouvez le remplacer par autre chose dans la demande de requête.

Vous pouvez définir le paramètre de suréchantillonnage même si l'index n'a pas explicitement de définition rerankWithOriginalVectors ou defaultOversampling. Fournir oversampling au moment de la requête remplace les paramètres d'index pour cette requête et exécute la requête rerankWithOriginalVectors avec la valeur true.

POST https://[service-name].search.windows.net/indexes/demo-index/docs/search?api-version=2024-07-01

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

Points essentiels :

  • S'applique aux champs vectoriels soumis à une compression vectorielle, conformément à l'affectation du profil vectoriel.

  • Remplace la valeur defaultOversampling ou introduit un suréchantillonnage au moment de la requête, même si la configuration de compression de l'index ne spécifie pas d'options de suréchantillonnage ou de reclassement.