文件 pq4_fast_scan.h

namespace faiss

实现具有多种变体的 k-means 聚类。

版权所有 (c) Facebook, Inc. 及其附属公司。

此源代码已根据 MIT 许可证获得许可,该许可证位于此源树的根目录中的 LICENSE 文件中。

IDSelector 旨在定义要处理的向量子集(用于删除或作为搜索子集)

PQ4 SIMD 压缩和累加函数

基本内核使用 bbs = nb * 2 * 16 向量累加 nq 查询向量,并为此生成一个输出矩阵。 这对于 nq * nb <= 4 很有用,否则寄存器溢出变得太大。

这些函数的实现分布在 3 个 cpp 文件中,以减少并行编译时间。 模板被显式实例化。

此文件包含用于计算距离的内核的回调。

在整个库中,向量以 float * 指针的形式提供。 当在批处理中一起处理(添加/搜索)多个向量时,大多数算法都可以优化。 在这种情况下,它们作为矩阵传递。 当大小为 d 的 n 个向量作为 float * x 提供时,向量 i 的分量 j 是

x[ i * d + j ]

其中 0 <= i < n 且 0 <= j < d。 换句话说,矩阵始终是紧凑的。 当指定矩阵的大小时,我们称它为 n*d 矩阵,这意味着行优先存储。

I/O 函数可以读取/写入文件名、文件句柄或抽象介质的对象。

读取函数返回应该用 delete 释放的对象。 这些对象中的所有引用都归该对象所有。

反向列表的定义 + 一些实现该接口的常见类。

由于 IVF(倒排文件)索引对于大规模用例非常有用,我们将与它们相关的一些函数分组到这个小型库中。 大多数函数都适用于 IndexIVF 和嵌入在 IndexPreTransform 中的 IndexIVF。

在此文件中实现了 L2 和内积之外的额外度量

实现了一些神经网络层,主要用于支持 QINCo

定义了一些对一组向量应用转换的对象。 这些通常是预处理步骤。

函数

void pq4_pack_codes(const uint8_t *codes, size_t ntotal, size_t M, size_t nb, size_t bbs, size_t nsq, uint8_t *blocks)

打包代码以供 SIMD 内核使用。 未使用的字节设置为 0。

参数:
  • codes – 输入代码,大小 (ntotal, ceil(M / 2))

  • ntotal – 输入代码的数量

  • nb – 输出代码的数量(ntotal 四舍五入为 bbs 的倍数)

  • nsq – 子量化器的数量(= M 四舍五入为 2 的倍数)

  • bbs – 数据库块的大小(32 的倍数)

  • blocks – 输出数组,大小为 nb * nsq / 2。

void pq4_pack_codes_range(const uint8_t *codes, size_t M, size_t i0, size_t i1, size_t bbs, size_t nsq, uint8_t *blocks)

与 pack_codes 相同,但写入输出的给定范围,保持其余部分不变。 假设分配的条目在输入时为 0。

参数:
  • codes – 输入代码,大小为 (i1 - i0, ceil(M / 2))

  • i0 – 要写入的第一个输出代码

  • i1 – 要写入的最后一个输出代码

  • blocks – 输出数组,大小至少为 ceil(i1 / bbs) * bbs * nsq / 2

uint8_t pq4_get_packed_element(const uint8_t *data, size_t bbs, size_t nsq, size_t vector_id, size_t sq)

从打包的代码表中获取单个元素

参数:
  • vector_id – 向量 ID

  • sq – 子量化器 (< nsq)

void pq4_set_packed_element(uint8_t *data, uint8_t code, size_t bbs, size_t nsq, size_t vector_id, size_t sq)

将单个元素 “code” 设置到打包的代码表中

参数:
  • vector_id – 向量 ID

  • sq – 子量化器 (< nsq)

void pq4_pack_LUT(int nq, int nsq, const uint8_t *src, uint8_t *dest)

打包查找表以供内核使用。

参数:
  • nq – 查询的数量

  • nsq – 子量化器的数量(2 的倍数)

  • src – 输入数组,大小为 (nq, 16)

  • dest – 输出数组,大小为 (nq, 16)

void pq4_accumulate_loop(int nq, size_t nb, int bbs, int nsq, const uint8_t *codes, const uint8_t *LUT, SIMDResultHandler &res, const NormTableScaler *scaler)

循环遍历数据库元素并将结果累积到结果处理程序中

参数:
  • nq – 查询的数量

  • nb – 数据库元素的数量

  • bbs – 数据库块的大小(32 的倍数)

  • nsq – 子量化器的数量(2 的倍数)

  • codes – 打包的代码数组

  • LUT – 打包的查找表

  • scaler – 用于缩放编码范数的缩放器

int pq4_qbs_to_nq(int qbs)
int pq4_preferred_qbs(int nq)

返回查询数量 nb 的首选块分解。

int pq4_pack_LUT_qbs(int fqbs, int nsq, const uint8_t *src, uint8_t *dest)

打包查找表以供内核使用。

参数:
  • qbs – 4 位编码的查询块数,处理的总查询数 (nq) 由此推导得出

  • nsq – 子量化器的数量(2 的倍数)

  • src – 输入数组,大小为 (nq, 16)

  • dest – 输出数组,大小为 (nq, 16)

返回:

nq

int pq4_pack_LUT_qbs_q_map(int qbs, int nsq, const uint8_t *src, const int *q_map, uint8_t *dest)

与 pq4_pack_LUT_qbs 相同,只是源向量使用 q_map 重新映射

void pq4_accumulate_loop_qbs(int qbs, size_t nb, int nsq, const uint8_t *codes, const uint8_t *LUT, SIMDResultHandler &res, const NormTableScaler *scaler = nullptr)

运行累加循环。

参数:
  • qbs – 4 位编码的查询数量

  • nb – 数据库代码数量(bbs 的倍数)

  • nsq – 子量化器的数量

  • codes – 编码的数据库向量(打包)

  • LUT – 查找表(打包)

  • res – resutls 的回调

  • scaler – 用于缩放编码范数的缩放器

struct CodePackerPQ4 : public faiss::CodePacker
#include <pq4_fast_scan.h>

用于 PQ4 快速扫描的 CodePacker API

公共函数

CodePackerPQ4(size_t nsq, size_t bbs)
virtual void pack_1(const uint8_t *flat_code, size_t offset, uint8_t *block) const final
virtual void unpack_1(const uint8_t *block, size_t offset, uint8_t *flat_code) const final

公共成员

size_t nsq