Поделиться через


Уменьшение размера вектора с помощью квантизации, узких типов данных и параметров хранения

В этой статье объясняется, как использовать векторную квантизацию и другие методы снижения векторного размера в службе "Поиск ИИ Azure". Индекс поиска задает определения векторного поля, включая свойства для хранимых и узких типов данных. Квантизация также указывается в индексе и назначается поле вектора через его профиль вектора.

Эти функции обычно доступны в REST API 2024-07-01 и в пакетах sdk Azure, предназначенных для этой версии. Пример в конце этой статьи показывает вариации размера вектора для каждого из подходов, описанных в этой статье.

Оценка параметров

В первую очередь рассмотрим три подхода к сокращению объема хранилища, используемого полями векторов. Эти подходы не являются взаимоисключающими и могут объединяться для максимального уменьшения размера вектора.

Мы рекомендуем встроенную квантизацию, так как она сжимает размер вектора в памяти и на диске с минимальными усилиями, и, как правило, обеспечивает большую выгоду в большинстве сценариев. В отличие от этого, узкие типы (за исключением float16) требуют особых усилий для их создания и stored экономии на диске, что не так дорого, как память.

Подход Зачем использовать эту опцию
Добавление скалярной или двоичной квантизации Используйте квантизацию для сжатия собственных значений float32 или float16 внедрения в int8 (scalar) или Byte (binary). Этот параметр сокращает объем хранилища в памяти и на диске без снижения производительности запросов. Небольшие типы данных, такие как int8 или Byte, создают векторные индексы, которые менее богаты содержимым, чем те, у которых больше внедрения. Для смещения потери информации встроенная сжатие включает параметры обработки после запроса с помощью несжатых внедренных внедренных и перераспределений, чтобы вернуть более релевантные результаты. Повторное использование и перезагружение являются конкретными функциями встроенной квантизации полей float32 или float16 и не могут использоваться при внедрении, которые проходят настраиваемую квантизацию.
Назначение небольших примитивных типов данных полям векторов Узкие типы данных, такие как float16, int16, int8 и Byte (binary), потребляют меньше места в памяти и на диске, но у вас должна быть модель внедрения, которая выводит векторы в узком формате данных. Кроме того, у вас должна быть пользовательская логика квантизации, которая выводит небольшие данные. Третий вариант использования, требующий меньше усилий, — переадресовка собственных внедренных операций float32, созданных большинством моделей в float16. Дополнительные сведения о двоичных векторах см. в разделе "Двоичные векторы индекса".
Исключение необязательного хранилища извлекаемых векторов Векторы, возвращаемые в ответе запроса, хранятся отдельно от векторов, используемых во время выполнения запроса. Если вам не нужно возвращать векторы, вы можете отключить извлекаемое хранилище, уменьшая общий объем хранилища дисков на поле до 50 процентов.

Все эти параметры определены в пустом индексе. Чтобы реализовать любой из них, используйте портал Azure, REST API или пакет azure SDK, предназначенный для этой версии API.

После определения индекса можно загрузить и индексировать документы в виде отдельного шага.

Вариант 1. Настройка квантизации

Квантизация рекомендуется уменьшить размер вектора, так как она снижает требования к памяти и хранилищу дисков для внедрения float16 и float32. Чтобы смещать эффекты меньшего индекса, можно добавить чрезмерное выполнение и повторное выполнение над несжатыми векторами.

Квантизация применяется к полям векторов, получающих векторы с плавающей запятой. В примерах в этой статье тип данных поля предназначен Collection(Edm.Single) для входящих внедрения float32, но float16 также поддерживается. При получении векторов в поле с настроенным сжатием подсистема автоматически выполняет квантизацию, чтобы уменьшить объем векторных данных в памяти и на диске.

Поддерживаются два типа квантизации:

  • Скалярная квантизация сжимает значения с плавающей запятой в более узкие типы данных. Поиск ИИ в настоящее время поддерживает int8, который составляет 8 битов, уменьшая размер векторного индекса четыре раза.

  • Двоичная квантизация преобразует с плавающей запятой в двоичные биты, которая занимает 1 бит. Это приводит к сокращению размера индекса вектора до 28 раз.

Чтобы использовать встроенную квантизацию, выполните следующие действия.

  • Использование индекса создания или обновления индекса для указания сжатия векторов
  • Добавление vectorSearch.compressions в индекс поиска
  • scalarQuantization Добавление или binaryQuantization настройка и присвоение ему имени
  • Задайте необязательные свойства для устранения последствий индексирования потери
  • Создание нового профиля вектора, использующего именованную конфигурацию
  • Создание поля вектора с новым профилем вектора
  • Загрузите индекс с данными float32 или float16, которые квантизованы во время индексирования с заданной конфигурацией
  • При необходимости запросите квантизованные данные с помощью параметра oversampling, если требуется переопределить значение по умолчанию.

Добавление "сжатия" в индекс поиска

В следующем примере показано частичное определение индекса с коллекцией полей, включающей векторное поле и vectorSearch.compressions раздел.

Этот пример включает оба scalarQuantization или binaryQuantization. Можно указать столько конфигураций сжатия, сколько вам нужно, а затем назначить нужные векторным профилям.

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

Основные моменты:

  • kind необходимо задать значение scalarQuantization или binaryQuantization

  • rerankWithOriginalVectors использует исходные несжатые векторы для пересчета сходства и повторного вычисления верхних результатов, возвращаемых первоначальным поисковым запросом. Несжатые векторы существуют в индексе поиска, даже если stored значение false. Это необязательное свойство. Значение по умолчанию — "истина".

  • defaultOversampling рассматривает более широкий набор потенциальных результатов для смещения сокращения информации от квантизации. Формула для потенциальных результатов состоит из k запроса с чрезмерным умножением. Например, если запрос указывает k значение 5, а превышение составляет 20, запрос фактически запрашивает 100 документов для повторного использования, используя исходный несжатый вектор для этой цели. Возвращаются только самые лучшие k результаты. Это необязательное свойство. Значение по умолчанию — 4.

  • quantizedDataType является необязательным и применяется только к скалярной квантизации. Если вы добавите его, его необходимо задать в значение int8. Это единственный примитивный тип данных, поддерживаемый для скалярной квантизации в настоящее время. По умолчанию — int8.

Добавление алгоритма HNSW

Убедитесь, что индекс имеет алгоритм иерархических навигаций по небольшим мирам (HNSW). Встроенная квантизация не поддерживается с исчерпывающим KNN.

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

Создание и назначение нового профиля вектора

Чтобы использовать новую конфигурацию квантизации, необходимо создать новый профиль вектора. Создание нового профиля вектора необходимо для создания сжатых индексов в памяти. Новый профиль использует HNSW.

  1. В том же определении индекса создайте новый профиль вектора и добавьте свойство сжатия и алгоритм. Ниже приведены два профиля, по одному для каждого подхода квантизации.

    "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. Назначьте профиль вектора новому полю вектора. Тип данных поля — float32 или float16.

    В службе "Поиск ИИ Azure" эквиваленты модели данных сущностей (EDM) типов float32 и float16, Collection(Edm.Single) Collection(Edm.Half)соответственно.

    {
       "name": "vectorContent",
       "type": "Collection(Edm.Single)",
       "searchable": true,
       "retrievable": true,
       "dimensions": 1536,
       "vectorSearchProfile": "vector-profile-hnsw-scalar",
    }
    
  3. Загрузите индекс с помощью индексаторов для индексирования модели извлечения или API-интерфейсов для индексации модели принудительной отправки.

Скалярная квантизация уменьшает разрешение каждого числа в каждом векторном внедрении. Вместо описания каждого числа в виде 16-разрядного или 32-разрядного числа с плавающей запятой используется 8-разрядное целое число. Он определяет диапазон чисел (обычно 99-й процентиль минимального и максимального) и делит их на конечное число уровней или ячейки, присваивая каждому ячейке идентификатор. В 8-разрядной скалярной квантизации существует 2^8 или 256, возможные ячейки.

Каждый компонент вектора сопоставляется с ближайшим репрезентативным значением в этом наборе уровней квантизации в процессе с округлением реального числа до ближайшего целого числа. В квантизованном 8-разрядном векторе номер идентификатора стоит вместо исходного значения. После квантизации каждый вектор представлен массивом идентификаторов для ячеек, к которым принадлежат его компоненты. Эти квантизованные векторы требуют гораздо меньше битов для хранения по сравнению с исходным вектором, что снижает требования к хранилищу и объем памяти.

Двоичная квантизация сжимает высокомерные векторы путем представления каждого компонента в виде одного бита либо 0, либо 1. Этот метод резко сокращает объем памяти и ускоряет операции сравнения векторов, которые являются важными для задач поиска и извлечения. Тесты теста теста показывают до 96 % уменьшения размера векторного индекса.

Это особенно эффективно для внедрения с измерениями больше 1024. Для небольших измерений рекомендуется протестировать качество двоичной квантизации или попробовать скалярную. Кроме того, мы обнаружили, что BQ работает очень хорошо, когда внедрение сосредоточено около нуля. Большинство популярных моделей внедрения, таких как OpenAI, Cohere и Mistral, сосредоточены около нуля.

Вариант 2. Назначение узких типов данных полям векторов

Простой способ уменьшить размер вектора — хранить внедрения в меньший формат данных. Большинство моделей внедрения выводят 32-разрядные числа с плавающей запятой, но если вы квантизируете векторы или если модель внедрения поддерживает ее в собственном коде, выходные данные могут быть float16, int16 или int8, что значительно меньше float32. Эти небольшие векторные размеры можно разместить, назначив узкий тип данных в поле вектора. В векторном индексе узкие типы данных используют меньше хранилища.

  1. Просмотрите типы данных, используемые для векторных полей , для рекомендуемого использования:

    • Collection(Edm.Single) 32-разрядная плавающая точка (по умолчанию)
    • Collection(Edm.Half) 16-разрядная плавающая точка (узкий)
    • Collection(Edm.Int16) 16-разрядное целое число со знаком (узкое)
    • Collection(Edm.SByte) 8-разрядное целое число со знаком (узкое)
    • Collection(Edm.Byte) 8-разрядное целое число без знака (разрешено только с упакованными двоичными типами данных)
  2. Из этого списка определите, какой тип данных является допустимым для выходных данных модели внедрения или для векторов, которые проходят настраиваемую квантизацию.

    В следующей таблице приведены ссылки на несколько моделей внедрения, которые могут использовать узкий тип данных (Collection(Edm.Half)) без дополнительной квантизации. Вы можете приведения от float32 к float16 (using Collection(Edm.Half)) без дополнительной работы.

    Модель внедрения Собственные выходные данные Назначение этого типа в поиске ИИ Azure
    text-embedding-ada-002 Float32 Collection(Edm.Single) или Collection(Edm.Half)
    text-embedding-3-small Float32 Collection(Edm.Single) или Collection(Edm.Half)
    text-embedding-3-large Float32 Collection(Edm.Single) или Collection(Edm.Half)
    Модели внедрения Cohere версии 3 с помощью int8 embedding_type Int8 Collection(Edm.SByte)

    Другие узкие типы данных можно использовать, если модель выдает внедрение в меньший формат данных или если у вас есть настраиваемая квантизация, которая преобразует векторы в меньший формат.

  3. Убедитесь, что вы понимаете компромиссы узкого типа данных. Collection(Edm.Half) имеет меньше информации, что приводит к снижению разрешения. Если данные являются однородными или плотными, потеря дополнительных деталей или нюансов может привести к неприемлемым результатам во время запроса, так как есть меньше деталей, которые можно использовать для разбиений близлежащих векторов.

  4. Определите и создайте индекс. Для этого шага можно использовать портал Azure, создать или обновить индекс (REST API) или пакет azure SDK.

  5. Проверьте результаты. Если поле вектора помечается как извлекаемое, используйте обозреватель поиска или поиск — POST для проверки соответствия содержимого поля типу данных.

    Чтобы проверить размер векторного индекса, используйте портал Azure или GET Statistics (REST API).

Примечание.

Тип данных поля используется для создания структуры физических данных. Если вы хотите изменить тип данных позже, удалите и перестроите индекс или создайте второе поле с новым определением.

Вариант 3. Установка stored свойства для удаления извлекаемого хранилища

Свойство stored является логическим определением векторного поля, которое определяет, выделяется ли хранилище для извлекаемого содержимого поля вектора. Свойство stored имеет значение true по умолчанию. Если в ответе запроса не требуется векторное содержимое, можно сохранить до 50 процентов хранилища на поле, установив stored значение false.

Рекомендации по настройке stored значения false:

  • Поскольку векторы не доступны для чтения, их можно опустить из результатов, отправленных в LLMs в сценариях RAG, и из результатов, отображаемых на странице поиска. Сохраните их, однако, если вы используете векторы в нижнем потоке, который потребляет векторное содержимое.

  • Однако если стратегия индексирования включает частичные обновления документов, такие как merge или mergeOrUpload в документе, следует учитывать, что значение stored false приведет к тому, что векторы в не хранимом поле будут опущены во время слияния. В каждой операции слияния или mergeOrUpload необходимо указать векторные поля в дополнение к другим полям невектора, которые вы обновляете, или вектор будет удален.

Помните, что возмездие stored необратимо. Он устанавливается во время создания индекса в векторных полях при создании структур физических данных. Если вы хотите получить векторное содержимое позже, необходимо удалить и перестроить индекс или создать и загрузить новое поле с новым атрибутом.

В следующем примере показана коллекция полей индекса поиска. Установите stored значение false, чтобы окончательно удалить извлекаемое хранилище для поля вектора.

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

Основные моменты:

  • Применяется только к полям векторов .

  • Влияет на хранилище на диске, а не на память, и он не влияет на запросы. Выполнение запроса использует отдельный векторный индекс, который не влияет на stored свойство.

  • Свойство stored задается во время создания индекса в векторных полях и является необратимым. Если вы хотите получить содержимое позже, необходимо удалить и перестроить индекс или создать и загрузить новое поле с новым атрибутом.

  • По умолчанию задано значение true и retrievable задано stored значение false. В конфигурации по умолчанию сохраняется извлекаемая копия, но она не возвращается автоматически в результатах. Если stored значение равно true, вы можете переключаться retrievable между true и false в любое время, не перестроив индекс. Если stored значение равно false, retrievable должно иметь значение false и не может быть изменено.

Пример: методы сжатия векторов

Ниже приведен код Python, демонстрирующий квантизацию, узкие типы данных и использование хранимого свойства: пример кода: векторная квантизация и параметры хранения с помощью Python.

Этот код создает и сравнивает размер хранилища и векторного индекса для каждого варианта:

****************************************
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

Api-интерфейсы поиска сообщают о хранении и векторе на уровне индекса, поэтому индексы и не поля должны быть основой сравнения. Используйте статистику индекса GET или эквивалентный API в пакетах SDK Azure для получения векторного размера.

Запрос к квантизованному полю вектора с помощью переполнения

Синтаксис запроса для сжатого или квантизованного векторного поля совпадает с не сжатыми векторными полями, если вы не хотите переопределять параметры, связанные с переузданием или повторной настройкой исходных векторов.

Помните, что определение сжатия векторов в индексе имеет параметры rerankWithOriginalVectors и defaultOversampling для устранения последствий меньшего векторного индекса. Значения по умолчанию можно переопределить, чтобы изменить поведение во время запроса. Например, если defaultOversampling значение равно 10.0, его можно изменить на что-то другое в запросе запроса.

Параметр oversampling можно задать, даже если индекс не имеет явного rerankWithOriginalVectors значения или defaultOversampling определения. Предоставление oversampling во время запроса переопределяет параметры индекса для этого запроса и выполняет запрос с эффективным значением rerankWithOriginalVectors 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   
            }
      ]    
    }

Основные моменты:

  • Применяется к полям векторов, которые проходят сжатие векторов на назначение профиля вектора.

  • Переопределяет defaultOversampling значение или вводит превышение значения во время запроса, даже если конфигурация сжатия индекса не указала параметры чрезмерного использования или повторного использования.

См. также