文件 VectorTransform.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

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

struct VectorTransform
#include <VectorTransform.h>

应用于一组向量的任何变换

faiss::CenteringTransform, faiss::ITQTransform, faiss::LinearTransform, faiss::NormalizationTransform, faiss::RemapDimensionsTransform 继承

公共函数

inline explicit VectorTransform(int d_in = 0, int d_out = 0)

! 输出维度

virtual void train(idx_t n, const float *x)

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const = 0

应用转换,并在提供的矩阵中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

  • xt – 输出向量,大小为 n * d_out

virtual void reverse_transform(idx_t n, const float *xt, float *x) const

反向转换。可能未实现,或者可能返回近似结果

virtual void check_identical(const VectorTransform &other) const = 0
inline virtual ~VectorTransform()

公共成员

int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct LinearTransform : public faiss::VectorTransform
#include <VectorTransform.h>

通用线性变换,在输出上应用偏置项 y = A * x + b

faiss::ITQMatrix, faiss::OPQMatrix, faiss::PCAMatrix, faiss::RandomRotationMatrix 继承

公共函数

explicit LinearTransform(int d_in = 0, int d_out = 0, bool have_bias = false)

支持 d_in > d_out 和 d_out < d_in

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

与 apply 相同,但结果是预先分配的

void transform_transpose(idx_t n, const float *y, float *x) const

如果 A 具有标准正交线,则计算 x = A^T * (x - b) 是反向变换

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

仅当 is_orthonormal 为真时有效。

void set_is_orthonormal()

计算 A^T * A 来设置 is_orthonormal 标志。

void print_if_verbose(const char *name, const std::vector<double> &mat, int n, int d) const
virtual void check_identical(const VectorTransform &other) const override
inline ~LinearTransform() override
virtual void train(idx_t n, const float *x)

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

bool have_bias
bool is_orthonormal

! 是否使用偏置项

检查矩阵 A 是否为正交矩阵 (启用 reverse_transform)

std::vector<float> A

变换矩阵,大小为 d_out * d_in。

std::vector<float> b

偏置向量,大小为 d_out

bool verbose
int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct RandomRotationMatrix : public faiss::LinearTransform
#include <VectorTransform.h>

随机旋转一组向量。

公共函数

inline RandomRotationMatrix(int d_in, int d_out)

支持 d_in > d_out 和 d_out < d_in

void init(int seed)

必须在使用变换之前调用

virtual void train(idx_t n, const float *x) override

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

inline RandomRotationMatrix()
virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

与 apply 相同,但结果是预先分配的

void transform_transpose(idx_t n, const float *y, float *x) const

如果 A 具有标准正交线,则计算 x = A^T * (x - b) 是反向变换

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

仅当 is_orthonormal 为真时有效。

void set_is_orthonormal()

计算 A^T * A 来设置 is_orthonormal 标志。

void print_if_verbose(const char *name, const std::vector<double> &mat, int n, int d) const
virtual void check_identical(const VectorTransform &other) const override
float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

bool have_bias
bool is_orthonormal

! 是否使用偏置项

检查矩阵 A 是否为正交矩阵 (启用 reverse_transform)

std::vector<float> A

变换矩阵,大小为 d_out * d_in。

std::vector<float> b

偏置向量,大小为 d_out

bool verbose
int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct PCAMatrix : public faiss::LinearTransform
#include <VectorTransform.h>

对一组向量应用主成分分析,可以选择进行白化和随机旋转。

公共函数

explicit PCAMatrix(int d_in = 0, int d_out = 0, float eigen_power = 0, bool random_rotation = false)
virtual void train(idx_t n, const float *x) override

训练n个向量。 如果 n < d_in,则特征向量矩阵将用 0 补全

void copy_from(const PCAMatrix &other)

复制预训练的PCA矩阵

void prepare_Ab()

在计算均值,PCAMat和特征值后调用

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

与 apply 相同,但结果是预先分配的

void transform_transpose(idx_t n, const float *y, float *x) const

如果 A 具有标准正交线,则计算 x = A^T * (x - b) 是反向变换

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

仅当 is_orthonormal 为真时有效。

void set_is_orthonormal()

计算 A^T * A 来设置 is_orthonormal 标志。

void print_if_verbose(const char *name, const std::vector<double> &mat, int n, int d) const
virtual void check_identical(const VectorTransform &other) const override
float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

float eigen_power

变换后,组件乘以 eigenvalues^eigen_power

>=0:不白化 =-0.5:完全白化

float epsilon

添加到特征值的值,以避免在白化时除以0

bool random_rotation

PCA之后的随机旋转

size_t max_points_per_d

训练向量数量与维度的比率

int balanced_bins

尝试将输出特征向量分配到这么多 bins 中

std::vector<float> mean

均值, 大小为 d_in。

std::vector<float> eigenvalues

协方差矩阵的特征值 (= 平方奇异值)

std::vector<float> PCAMat

PCA矩阵,大小为 d_in * d_in。

bool have_bias
bool is_orthonormal

! 是否使用偏置项

检查矩阵 A 是否为正交矩阵 (启用 reverse_transform)

std::vector<float> A

变换矩阵,大小为 d_out * d_in。

std::vector<float> b

偏置向量,大小为 d_out

bool verbose
int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct ITQMatrix : public faiss::LinearTransform
#include <VectorTransform.h>

ITQ 实现来自

Iterative quantization: A procrustean approach to learning binary codes for large-scale image retrieval,

Yunchao Gong, Svetlana Lazebnik, Albert Gordo, Florent Perronnin, PAMI’12.

公共函数

explicit ITQMatrix(int d = 0)
virtual void train(idx_t n, const float *x) override

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

与 apply 相同,但结果是预先分配的

void transform_transpose(idx_t n, const float *y, float *x) const

如果 A 具有标准正交线,则计算 x = A^T * (x - b) 是反向变换

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

仅当 is_orthonormal 为真时有效。

void set_is_orthonormal()

计算 A^T * A 来设置 is_orthonormal 标志。

void print_if_verbose(const char *name, const std::vector<double> &mat, int n, int d) const
virtual void check_identical(const VectorTransform &other) const override
float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

int max_iter
int seed
std::vector<double> init_rotation
bool have_bias
bool is_orthonormal

! 是否使用偏置项

检查矩阵 A 是否为正交矩阵 (启用 reverse_transform)

std::vector<float> A

变换矩阵,大小为 d_out * d_in。

std::vector<float> b

偏置向量,大小为 d_out

bool verbose
int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct ITQTransform : public faiss::VectorTransform
#include <VectorTransform.h>

完整的 ITQ 变换,包括归一化和 PCA 变换

公共函数

explicit ITQTransform(int d_in = 0, int d_out = 0, bool do_pca = false)
virtual void train(idx_t n, const float *x) override

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

应用转换,并在提供的矩阵中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

  • xt – 输出向量,大小为 n * d_out

virtual void check_identical(const VectorTransform &other) const override
float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

virtual void reverse_transform(idx_t n, const float *xt, float *x) const

反向转换。可能未实现,或者可能返回近似结果

公共成员

std::vector<float> mean
bool do_pca
ITQMatrix itq
int max_train_per_dim

每个维度的最大训练点数

LinearTransform pca_then_itq
int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct OPQMatrix : public faiss::LinearTransform
#include <VectorTransform.h>

应用旋转来使维度与 PQ 对齐,从而最小化重建误差。 可在 IndexPQIndexIVFPQ 之前使用。 该方法是下面文章中描述的非参数版本

“用于近似最近邻搜索的优化乘积量化” Tiezheng Ge, Kaiming He, Qifa Ke, Jian Sun, CVPR’13

公共函数

explicit OPQMatrix(int d = 0, int M = 1, int d2 = -1)

如果 d2 != -1,则输出此维度的向量

virtual void train(idx_t n, const float *x) override

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

与 apply 相同,但结果是预先分配的

void transform_transpose(idx_t n, const float *y, float *x) const

如果 A 具有标准正交线,则计算 x = A^T * (x - b) 是反向变换

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

仅当 is_orthonormal 为真时有效。

void set_is_orthonormal()

计算 A^T * A 来设置 is_orthonormal 标志。

void print_if_verbose(const char *name, const std::vector<double> &mat, int n, int d) const
virtual void check_identical(const VectorTransform &other) const override
float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

int M

子量化器的数量

int niter = 50

外部训练迭代的次数。

int niter_pq = 4

PQ 的训练迭代次数。

int niter_pq_0 = 40

对于第一个外部迭代,同样适用

size_t max_train_points = 256 * 256

如果训练点过多,则重新采样

bool verbose = false
ProductQuantizer *pq = nullptr

如果非 NULL,使用这个乘积量化器进行训练,应使用 (d_out, M, _) 构建

bool have_bias
bool is_orthonormal

! 是否使用偏置项

检查矩阵 A 是否为正交矩阵 (启用 reverse_transform)

std::vector<float> A

变换矩阵,大小为 d_out * d_in。

std::vector<float> b

偏置向量,大小为 d_out

int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct RemapDimensionsTransform : public faiss::VectorTransform
#include <VectorTransform.h>

为输入向量重新映射维度,可能插入 0。严格来说,这也是一种线性变换,但我们不想用矩阵乘法来计算它。

公共函数

RemapDimensionsTransform(int d_in, int d_out, const int *map)
RemapDimensionsTransform(int d_in, int d_out, bool uniform = true)

根据需要重新映射输入到输出,跳过或插入维度。如果 uniform: 均匀地分布维度,否则只取前 d_out 个。

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

应用转换,并在提供的矩阵中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

  • xt – 输出向量,大小为 n * d_out

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

只有当映射是排列时,逆变换才是正确的

inline RemapDimensionsTransform()
virtual void check_identical(const VectorTransform &other) const override
virtual void train(idx_t n, const float *x)

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

std::vector<int> map

从输出维度到输入的映射,大小为 d_out。 -1 -> 将输出设置为 0

int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct NormalizationTransform : public faiss::VectorTransform
#include <VectorTransform.h>

逐向量归一化

公共函数

explicit NormalizationTransform(int d, float norm = 2.0)
NormalizationTransform()
virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

应用转换,并在提供的矩阵中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

  • xt – 输出向量,大小为 n * d_out

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

由于范数不可逆,因此为恒等变换。

virtual void check_identical(const VectorTransform &other) const override
virtual void train(idx_t n, const float *x)

在具有代表性的向量集合上执行训练。默认情况下不执行任何操作。

参数:
  • n – 训练向量的数量

  • x – 训练向量,大小为 n * d

float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

float norm
int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练

struct CenteringTransform : public faiss::VectorTransform
#include <VectorTransform.h>

从向量中减去每个分量的平均值。

公共函数

explicit CenteringTransform(int d = 0)
virtual void train(idx_t n, const float *x) override

在 n 个向量上进行训练。

virtual void apply_noalloc(idx_t n, const float *x, float *xt) const override

减去平均值

virtual void reverse_transform(idx_t n, const float *xt, float *x) const override

加上平均值

virtual void check_identical(const VectorTransform &other) const override
float *apply(idx_t n, const float *x) const

应用转换,并在分配的指针中返回结果

参数:
  • n – 要转换的向量的数量

  • x – 输入向量,大小为 n * d_in

返回值:

输出向量,大小为 n * d_out

公共成员

std::vector<float> mean

平均值,大小 d_in = d_out。

int d_in
int d_out

! 输入维度

bool is_trained

设置 VectorTransform 是否不需要训练,或者是否已经完成训练