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. La quantisation est recommandée, car elle réduit à la fois la mémoire et le stockage 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.

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 nouveau champ vectoriel avec le nouveau profil vectoriel.
  • Charger l’index avec des données float32 ou float16 quantifiées pendant l’indexation par la configuration définie
  • Si vous le souhaitez, interrogez des données quantifiées à l’aide du paramètre de surachantillonnage. Si le champ de vecteur ne spécifie pas de suréchantillonnage dans sa définition, vous pouvez l’ajouter au moment de la requête.

Conseil / Astuce

Recherche Azure AI : Réduire les coûts vectoriels jusqu’à 92,5% avec de nouvelles techniques de compression compare les stratégies de compression et explique les économies dans le stockage et les coûts. Il inclut également des métriques pour mesurer la pertinence en fonction du gain cumulatif normalisé réduit (NDCG), démontrant que vous pouvez compresser vos données sans sacrifier la qualité de la recherche.

Prérequis

  • Champs vectoriels dans un index de recherche, avec une vectorSearch configuration spécifiant l’algorithme HNSW (Hierarchical Navigable Small Worlds) ou l’algorithme complet K-nearest voisin (eKNN) et 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. Lorsque les vecteurs sont reçus sur un champ avec compression configurée, le moteur effectue la quantisation pour réduire l’empreinte des données vectorielles en 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 IA prend actuellement en charge int8, qui est 8 bits, réduisant ainsi la taille de l'index vectoriel de quatre fois.

  • 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.

Remarque

Bien que les services gratuits prennent en charge la quantisation, ils ne montrent pas les économies de stockage complètes en raison du quota de stockage limité.

Le rescoring est une technique utilisée pour compenser la perte d’informations en raison de la compression vectorielle. Il utilise le suréchantillonnage pour récupérer des vecteurs supplémentaires et des informations supplémentaires pour rescoreer les résultats initiaux trouvés par la requête. Les informations supplémentaires sont soit des vecteurs d'origine non compressés et à pleine précision, soit uniquement pour la quantification binaire, avec la possibilité de recalculer le score en utilisant les candidats de documents quantifiés binaires contre le vecteur de requête. Les options de rescoring sont spécifiées dans l’index, mais vous pouvez déclencher le rescoring lors de l’exécution de la requête si l’index le prend en charge.

Les versions d’API déterminent quel comportement de rescoring est opérationnel pour votre code. L’API de préversion la plus récente prend en charge une nouvelle approche de rescoring pour la quantisation binaire. Les index créés avec 2025-03-01-preview peuvent utiliser les nouveaux comportements de rescoring.

Version de l’API Type de quantisation Propriétés du rescoring
2024-07-01 Quantisation scalaire et binaire, sur les index vectoriels créés à l’aide de graphiques HNSW (Hierarchical Navigable Small World) pour la recherche de similarité rerankWithOriginalVectors
2024-11-01-preview Quantisation scalaire et binaire sur les graphiques HNSW rescoringOptions.enableRescoring et rescoreStorageMethod.preserveOriginals
2025-03-01-preview Quantisation binaire sur les graphiques HNSW Les combinaisons de paramètres précédentes sont toujours prises en charge, mais la quantification binaire peut maintenant être rescorée si les incorporations d’origine sont supprimées : rescoringOptions.enableRescoring et rescoringOptions.rescoreStorageMethod=discardOriginals

Seuls les graphiques HNSW autorisent le rescoring. Exhaustive K Nearest Neighbors (eKNN) ne prend pas en charge le rescoring.

Le processus généralisé de rescoring est le suivant :

  1. La requête vectorielle s’exécute sur des champs vectoriels compressés.
  2. La requête vectorielle retourne les candidats suréchantillonné du top k.
  3. Les candidats k suréchantillonnés sont réévalués à l’aide des vecteurs d’origine non compressés ou du produit scalaire de la quantification binaire. 1. Après le rescoring, les résultats sont ajustés afin que les correspondances plus pertinentes apparaissent en premier.

Ajouter « compressions » à un index de recherche

Cette section explique comment spécifier une vectorsSearch.compressions section dans l’index. L’exemple suivant montre une définition d’index partielle avec une collection de champs qui inclut un champ vectoriel.

L’exemple de compression inclut les deux 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, la version préliminaire ajoutant des options supplémentaires pour l'optimisation du stockage, en plus des modifications de la syntaxe existante. La compatibilité descendante est conservée par le biais de mappages d’API internes, mais nous vous recommandons d’adopter les propriétés plus récentes dans le code qui cible 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": [ 
      {
          "name": "vector-profile-1",
          "algorithm": "use-hnsw",
          "compression": "use-scalar"
      }
    ],
    "algorithms": [ 
      {
        "name": "use-hnsw",
        "kind": "hnsw",
        "hnswParameters": { },
        "exhaustiveKnnParameters": null
      }
    ],
    "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 ou ultérieure. Pour la version stable, utilisez uniquement HNSW. Si vous souhaitez recalculer les scores, vous devez choisir 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. En outre, nous avons trouvé que la quantisation binaire fonctionne très bien lorsque les incorporations sont centrées autour de 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 identique à celle des champs de vecteur non compressés, sauf si vous souhaitez remplacer les paramètres associés à l’échantillonnage et à la rescoring. Vous pouvez ajouter un paramètre oversampling pour appeler le suréchantillonnage et la réévaluation des scores au moment de la requête.

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.