Share via


Configurer la quantification vectorielle et le stockage réduit pour les vecteurs plus petits dans Azure AI Search

Important

Ces fonctionnalités sont en préversion publique sous Conditions d'utilisation supplémentaires. L'API REST 2024-03-01-Preview fournit les nouveaux types de données, les propriétés de compression vectorielle et la propriété stored.

Cet article décrit la quantification vectorielle et d’autres techniques de compression des index vectoriels dans Azure AI Search.

Évaluer les options

Pour commencer, passez en revue les trois options permettant de réduire la quantité de stockage utilisée par les champs vectoriels. Ces options ne s’excluent pas mutuellement.

Nous recommandons la quantification scalaire, car elle compresse la taille des vecteurs en mémoire et sur le disque avec un minimum d'effort, ce qui tend à offrir le plus d'avantages dans la plupart des scénarios. En revanche, les types étroits (à l’exception de Float16) nécessitent un effort spécial pour les rendre, et stored enregistre sur le stockage sur disque, ce qui n’est pas aussi coûteux que la mémoire.

Approche Pourquoi utiliser cette option
Attribuer des types de données primitifs plus petits aux champs vectoriels Les types de données restreints, tels que Float16, Int16 et Int8, consomment moins d'espace en mémoire et sur le disque, mais vous devez disposer d'un modèle d'intégration qui génère des vecteurs dans un format de données étroit. Ou bien, vous devez disposer d’une logique de quantification personnalisée qui génère de petites données. Un troisième cas d’usage nécessitant moins d’efforts consiste à rediffusion des incorporations natives Float32 produites par la plupart des modèles pour Float16.
Éliminez le stockage facultatif des vecteurs récupérables Les vecteurs renvoyés dans une réponse à une requête sont stockés séparément des vecteurs utilisés lors de l'exécution de la requête. Si vous n’avez pas besoin de retourner des vecteurs, vous pouvez désactiver le stockage récupérable, ce qui réduit le stockage global par disque par champ de jusqu’à 50 %.
Ajouter une quantification scalaire Utilisez la quantification scalaire intégrée pour compresser les intégrations Float32 natives au format Int8. Cette option réduit le stockage en mémoire et sur disque sans dégradation des performances des requêtes. Les types de données plus petits, par exemple, Int8 produisent des index vectoriels moins riches en contenu que ceux avec intégrations Float32. Pour compenser la perte d'informations, la compression intégrée inclut des options de traitement post-requête utilisant des intégrations non compressées et un suréchantillonnage pour renvoyer des résultats plus pertinents. Le reclassement et le suréchantillonnage sont des fonctionnalités spécifiques de la quantification scalaire intégrée des champs Float32 ou Float16 et ne peuvent pas être utilisés sur les intégrations soumises à une quantification personnalisée.

Toutes ces options sont définies sur un index vide. Pour implémenter l’un d’entre eux, utilisez le Portail Microsoft Azure, les API REST 2024-03-01-preview ou un package bêta du SDK Azure.

Une fois l'index défini, vous pouvez charger et indexer les documents dans le cadre d'une étape distincte.

Option 1 : attribuer des types de données restreints aux champs vectoriels

Les champs vectoriels stockent des représentations vectorielles vectorielles, qui sont représentées sous la forme d'un tableau de nombres. Lorsque vous spécifiez un type de champ, vous spécifiez le type de données primitif sous-jacent utilisé pour contenir chaque nombre dans ces tableaux. Le type de données affecte l’espace occupé par chaque numéro.

À l’aide des API d’aperçu, vous pouvez attribuer des types de données primitifs étroits pour réduire les besoins de stockage des champs vectoriels.

  1. Passez en revue les types de données pour les champs vectoriels :

    • Collection(Edm.Single) Virgule flottante 32 bits (par défaut)
    • Collection(Edm.Half) Virgule flottante 16 bits
    • Collection(Edm.Int16) Entier signé 16 bits
    • Collection(Edm.SByte) Entier signé de 8 bits

    Remarque

    Les types de données binaires ne sont actuellement pas pris en charge.

  2. Choisissez un type de données valide pour la sortie de votre modèle d'intégration ou pour les vecteurs soumis à une quantification personnalisée.

    La plupart des modèles d'intégration génèrent des nombres à virgule flottante de 32 bits, mais si vous appliquez une quantification personnalisée, votre sortie peut être Int16 ou Int8. Vous pouvez désormais définir des champs vectoriels acceptant le format le plus petit.

    Les modèles d’incorporation de texte ont un format de sortie natif Float32, qui correspond à Collection(Edm.Single) dans Azure AI Search. Vous ne pouvez pas mapper cette sortie Int8 car la conversion de float vers int est interdite. Cependant, vous pouvez diffuser de Float32 vers Float16 (ou Collection(Edm.Half)), ce qui constitue un moyen simple d'utiliser des types de données restreints sans travail supplémentaire.

    Le tableau suivant fournit des liens vers plusieurs modèles d'intégration qui utilisent les types de données restreints.

    Modèle d'intégration Sortie native Types valides dans Azure AI Search
    text-embedding-ada-002 Float32 Collection(Edm.Single) ou Collection(Edm.Half)
    text-embedding-3-small Float32 Collection(Edm.Single) ou Collection(Edm.Half)
    text-embedding-3-large Float32 Collection(Edm.Single) ou Collection(Edm.Half)
    Modèles d'intégration Cohere V3 avec int8 embedding_type Int8 Collection(Edm.SByte)
  3. Assurez-vous de comprendre les compromis d’un type de données restreint. Collection(Edm.Half) contient moins d’informations, ce qui entraîne une résolution plus faible. Si vos données sont homogènes ou denses, la perte de détails ou de nuances supplémentaires pourrait conduire à des résultats inacceptables au moment de la requête, car moins de détails peuvent être utilisés pour distinguer les vecteurs proches.

  4. Définir et construire l'index. Vous pouvez utiliser le Portail Microsoft Azure, 2024-03-01-preview ou un package bêta du SDK Azure pour cette étape.

  5. Vérifier les résultats. En supposant que le champ vectoriel est marqué comme récupérable, utilisez l'explorateur de recherche ou l'API REST pour vérifier que le contenu du champ correspond au type de données. Assurez-vous d'utiliser la version d'API 2024-03-01-preview correcte pour la requête, sinon les nouvelles propriétés ne s'afficheront pas.

Pour vérifier la taille de l'index vectoriel, utilisez le Portail Microsoft Azure ou l'aperçu 2024-03-01.

Remarque

Le type de données du champ est utilisé pour créer la structure physique des données. Si vous souhaitez modifier un type de données ultérieurement, supprimez et reconstruisez l'index ou créez un deuxième champ avec la nouvelle définition.

Option 2 : définir la propriété stored pour supprimer le stockage récupérable

La propriété stored est un nouveau booléen sur une définition de champ vectoriel qui détermine si le stockage est alloué au contenu de champ vectoriel récupérable. Si vous n'avez pas besoin de contenu vectoriel dans une réponse à une requête, vous pouvez économiser jusqu'à 50 % de stockage par champ en définissant la valeur stored sur false.

Étant donné que les vecteurs ne sont pas lisibles par l’homme, ils sont généralement omis dans une réponse à une requête affichée sur une page de recherche. Toutefois, si vous utilisez des vecteurs dans le traitement en aval, par exemple en transmettant des résultats de requête à un modèle ou à un processus qui consomme du contenu vectoriel stored, vous devez conserver la valeur true et choisir une technique différente pour minimiser la taille du vecteur.

L'exemple suivant montre la collection de champs d'un index de recherche. Définissez stored sur false pour supprimer définitivement le stockage récupérable pour le champ vectoriel.

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" 
         } 
       ] 
     } 

Points essentiels :

  • S'applique uniquement aux champs vectoriels.

  • Affecte le stockage sur disque, pas la mémoire, et n'a aucun effet sur les requêtes. L'exécution de la requête utilise un index vectoriel distinct qui n'est pas affecté par la propriété stored.

  • La propriété stored est définie lors de la création de l'index sur les champs vectoriels et est irréversible. Si vous souhaitez que le contenu soit récupérable ultérieurement, vous devez supprimer et reconstruire l'index, ou créer et charger un nouveau champ doté de la nouvelle attribution.

  • Les valeurs par défaut sont stored définies sur true et retrievable sur false. Dans une configuration par défaut, une copie récupérable est stockée, mais elle n'est pas automatiquement renvoyée dans les résultats. Lorsque stored c'est vrai, vous pouvez basculer retrievable entre vrai et faux à tout moment sans avoir à reconstruire un index. Quand stored est faux, retrievable doit être faux et ne peut pas être modifié.

Option 3 : Configurer la quantification scalaire

La quantification scalaire intégrée est recommandée car elle réduit les besoins en mémoire et en stockage sur disque, et elle ajoute un reclassement et un suréchantillonnage pour compenser les effets d'un index plus petit. La quantification scalaire intégrée peut être appliquée aux champs vectoriels contenant des données Float32 ou Float16.

Pour utiliser la compression vectorielle intégrée :

  • Ajouter vectorSearch.compressions à un index de recherche. L'algorithme de compression pris en charge dans cet aperçu est la quantification scalaire.
  • Définissez des propriétés facultatives pour atténuer les effets de l’indexation avec perte. Les deux rerankWithOriginalVectors et defaultOversampling fournissent des optimisations lors de l’exécution des requêtes.
  • Ajouter vectorSearch.profiles.compression à un nouveau profil vectoriel.
  • Attribuez le nouveau profil vectoriel à un nouveau champ vectoriel.

Ajouter des paramètres de compression et définir des propriétés facultatives

Dans une définition d'index créée à l'aide de l'API REST 2024-03-01-preview, ajoutez une section compressions. Utilisez le JSON suivant comme modèle.

"compressions": [

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

Points essentiels :

  • kind doit être défini sur scalarQuantization. Il s’agit de la seule méthode de quantification prise en charge pour le moment.

  • 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 doit être défini sur int8. Il s’agit du seul type de données primitif pris en charge pour le moment. Cette propriété est facultative. La valeur par défaut est int8.

Ajouter un paramètre de compression à un profil vectoriel

La quantification scalaire est spécifiée comme propriété dans un nouveau profil vectoriel. La création d'un nouveau profil vectoriel est nécessaire pour créer des index compressés en mémoire.

Dans le profil, vous devez utiliser l’algorithme HNSW (Hierarchical Navigable Small Worlds). La quantification intégrée n'est pas prise en charge avec KNN exhaustif.

  1. Créez un nouveau profil vectoriel et ajoutez une propriété de compression.

    "profiles": [
       {
          "name": "my-vector-profile",
          "compression": "my-scalar-quantization", 
          "algorithm": "my-hnsw-vector-config-1",
          "vectorizer": null
       }
     ]
    
  2. Attribuez un profil vectoriel à un nouveau champ vectoriel. La quantification scalaire réduit le contenu à Int8, alors assurez-vous que votre contenu est soit Float32 ou Float16.

    Dans Azure AI Search, les équivalents EDM (Entity Data Model) Float32 et Float16 les types sont Collection(Edm.Single) et Collection(Edm.Half), respectivement.

    {
       "name": "DescriptionVector",
       "type": "Collection(Edm.Single)",
       "searchable": true,
       "retrievable": true,
       "dimensions": 1536,
       "vectorSearchProfile": "my-vector-profile"
    }
    
  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 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.

Exemple d'index avec vectorCompression, types de données et propriété stockée

Voici un exemple composite d’index de recherche qui spécifie des types de données étroits, un stockage réduit et une compression vectorielle.

  • "HotelNameVector" fournit un exemple de type de données restreint, refondant les valeurs d'origine Float32 en Float16, exprimées comme Collection(Edm.Half) dans l'index de recherche.
  • « HotelNameVector » a également stored défini sur false. Les incorporations supplémentaires utilisées dans une réponse de requête ne sont pas stockées. Lorsque stored a la valeur false, retrievable doit également être false.
  • « DescriptionVector » fournit un exemple de compression vectorielle. La compression vectorielle est définie dans l’index, référencée dans un profil, puis affectée à un champ vectoriel. « DescriptionVector » a également stored défini sur 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" }
                    ]
                }
            }
        ]
    }
}

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

La syntaxe de requête dans cet exemple s'applique aux champs vectoriels utilisant la quantification scalaire intégrée. Par défaut, les champs vectoriels qui utilisent la quantification scalaire utilisent également rerankWithOriginalVectors et defaultOversampling pour atténuer les effets d'un index vectoriel plus petit. Ces paramètres sont spécifiés dans l'index de recherche.

Sur la requête, vous pouvez remplacer la valeur par défaut du suréchantillonnage. 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/[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   
            }
      ]    
    }

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.

Voir aussi