Skip to content

Latest commit

 

History

History
206 lines (158 loc) · 5.23 KB

5-数据预处理.md

File metadata and controls

206 lines (158 loc) · 5.23 KB

ID映射

默认情况下,faiss会为每个输入的向量记录一个次序id(该ID为数组ID),在使用中也可以为向量指定任意我们需要的结构化id。 部分index类型有add_with_ids方法,可以为每个向量对应一个64-bit的id,搜索的时候返回这个指定的id。

add_with_ids 添加索引

# 导入faiss
import sys
import faiss
import numpy as np 

# 获取数据和Id
d = 512
n_data = 2000
data = np.random.rand(n_data, d).astype('float32')
ids = np.arange(100000, 102000)  #id设定为6位数整数

nlist = 10
quantizer = faiss.IndexFlatIP(d)
index = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)
index.train(data)

# add_with_ids 添加
index.add_with_ids(data, ids)
d, i = index.search(data[:5], 1)
print(i)  #自定义ID

IndexIDMap

但是对有些Index类型,并不支持add_with_ids,因此需要与其他Index类型结合,将默认的id映射到指定id,用IndexIDMap类实现。 指定的ids不能是字符串,只能是整数。

 err : add_with_ids not implemented for this type of index
#导入faiss
import sys
import faiss
import numpy as np 

#获取数据和Id
d = 512
n_data = 2000
data = np.random.rand(n_data, d).astype('float32')
ids = np.arange(100000, 102000)  #id设定为6位数整数


index = faiss.IndexFlatL2(d)

# index.add_with_ids(data, ids)

index2 = faiss.IndexIDMap(index)  
index.add(data)
index2.add_with_ids(data, ids)  #将index的id映射到index2的id,会维持一个映射表

d, i = index2.search(data[:5], 1)
print(i)  #自定义ID

数据转换

有些时候需要在索引之前转换数据。转换类继承了VectorTransform类,将输入向量转换为输出向量。
1)随机旋转,类名RandomRotationMatri,用以均衡向量中的元素,一般在IndexPQ和IndexLSH之前;
2)PCA,类名PCAMatrix,降维;
3)改变维度,类名RemapDimensionsTransform,可以升高或降低向量维数

PCB降维度

import faiss
import numpy as np 

size = 1024
d = 2048
to_d = 256
n_centroids = 16

data = np.random.rand(size, d).astype('float32')
# the IndexIVFPQ will be in 256D
coarse_quantizer = faiss.IndexFlatL2(to_d)
sub_index = faiss.IndexIVFPQ(coarse_quantizer, to_d, n_centroids, 8, 8)

# PCA 2048->256
# 降维后随机旋转 (第四个参数)
pca_matrix = faiss.PCAMatrix(2048, 256, 0, False)

#- the wrapping index
index = faiss.IndexPreTransform(pca_matrix, sub_index)

# will also train the PCA
index.train(data)  #数据需要是2048维
# PCA will be applied prior to addition
index.add(data)
WARNING clustering 1024 points to 256 centroids: please provide at least 9984 training points

官方解释 : the clustering complains that it does not have enough training data, there is not much we can do about this.

升维

有时候需要在向量中插入0升高维度,一般是我们需要

1:d是4的整数倍,有利于举例计算

2:d是M的整数倍。

#升维
import faiss
import numpy as np 

size = 512
d = 124
n_centroids = 16
data = np.random.rand(size, d).astype('float32')

M = 8   #M是在维度方向上分割的子空间个数
d2 = int((d + M - 1) / M) * M

print(d2)

# RemapDimensionsTransform 升维
remapper = faiss.RemapDimensionsTransform(d, d2, True)
index_pq = faiss.IndexPQ(d2, M, 8)
index = faiss.IndexPreTransform (remapper, index_pq)#后续可以添加数据/索引

index.train(data)  
index.add(data)

d, i = index.search(data[:5], 1)
print(i)  #自定义ID

对搜索结果重新排序

当查询向量时,可以用真实距离值对结果进行重新排序。 在下面的例子中,搜索阶段会首先选取4*10个结果,然后对这些结果计算真实距离值,再从中选取10个结果返回。IndexRefineFlat保存了全部的向量信息,内存开销不容小觑。


# 数据压缩
import faiss
import numpy as np 

size = 1024 * 10
d = 128
M = 8
data = np.random.rand(size, d).astype('float32')

# ids = np.arange(100000, 100000 + size)  #id设定为6位数整数

nbits_per_index = 8
q = faiss.IndexPQ(d, M, nbits_per_index)
rq = faiss.IndexRefineFlat(q)

rq.train (data)
rq.add (data)
rq.k_factor = 4

dis, ind = rq.search (data[:5], 10)
print(ind)

分片

连接多个子索引结果的索引

import faiss
import numpy as np

size = 1024 * 4
d = 32
ni = 4-1
data = np.random.rand(size, d).astype('float32')
ids = np.arange(99999, 99999+size)  # id设定为6位数整数


# threaded	do we use one thread per sub_index or do queries sequentially?
# successive_ids	should we shift the returned ids by the size of each sub-index or return them as they are?

shard_index = faiss.IndexShards(d, False, True)

for i in range(ni):
    i0 = int(size/(ni+1))*i
    i1 = int(size/(ni+1))*(i+1)
    index = faiss.IndexFlatL2(d)
    irm = faiss.IndexIDMap(index)
    irm.add_with_ids(data[i0:i1], ids[i0:i1])  #将index的id映射到index2的id,会维持一个映射表
    shard_index.add_shard(irm)

# shard_index.add(data)
dis, ind = shard_index.search(data[2000:2002], 1)
print(ind)



# shard_index = faiss.IndexShards(d,True, True)

# for i in range(ni):
#     i0 = int(size/(ni+1))*i
#     i1 = int(size/(ni+1))*(i+1)
#     index = faiss.IndexFlatL2(d)
#     index.add(data[i0:i1])
#     shard_index.add_shard(index)

# dis, ind = shard_index.search(data[2000:2002], 1)
# print(ind)