Added PQ INT8 quantizer in Turbo - #554
Conversation
…efactor/turbo_preprocessor
…rocessor # Conflicts: # .gitignore
…o refactor/turbo_pq
6a04997 to
bedd5c3
Compare
42bbd1b to
bedd5c3
Compare
| //! via quantize_query(). Distance between a PQ code and a | ||
| //! query uses ADC (LUT look-up); distance between two PQ codes uses | ||
| //! SDC (centroid-to-centroid distance table). | ||
| class PqInt8Quantizer : public Quantizer { |
There was a problem hiding this comment.
PqInt8Quantizer 这个命名严谨吗?我理解只是每个子量化使用8bit code
There was a problem hiding this comment.
预计一共实现PqInt8Quantizer,PqInt4Quantizer和PqFastQuantizer三个量化器,对齐计划中的其他量化器取名:
- RecordInt8Quantizer,RecordInt4Quantizer
There was a problem hiding this comment.
PqInt4Quantizer和PqFastQuantizer是什么区别?
| //! SDC (centroid-to-centroid distance table). | ||
| class PqInt8Quantizer : public Quantizer { | ||
| public: | ||
| PqInt8Quantizer() { |
There was a problem hiding this comment.
- 为啥优先支持8bit?
- 除了支持8bit,后面还会支持其他数量的bit吗?
There was a problem hiding this comment.
- 当前的HNSW中最适用的就是8bit,比如faiss支持8bit和16bit,vsag支持4bit和8bit
- 后续会支持其他数量的bit,由于把4bit也一起改了会导致一次性更改的文件太多,不太好review,计划是分两次pr提交
There was a problem hiding this comment.
好奇问问 为什么HNSW中最适用的就是8bit?
# Conflicts: # src/include/zvec/core/interface/index_param.h
| return DistanceImpl{}; | ||
| } | ||
|
|
||
| virtual DistanceImpl sym_distance(const void *query, |
There was a problem hiding this comment.
in quantizer base class, calc_distance_dp_dp is used for calculating datapoint distance. is there any need to define a new interface for symmetric distance? or can define it within pq quantizer then be exposed as calc_distance_dp_dp?
| const void *dist_table_v, size_t num_chunk, | ||
| float *out) { | ||
| constexpr size_t kNumCentroids = 256; | ||
| constexpr size_t kTablePerSub = kNumCentroids * kNumCentroids; // 65536 |
There was a problem hiding this comment.
kTablePerSub,我们改成chunk吧这里,和外面统一
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Simple Lloyd's KMeans for one sub-quantizer (templated on data type T). |
|
|
||
| void PqInt8Quantizer::quantize_data(const void *input, void *output) const { | ||
| uint8_t *code = reinterpret_cast<uint8_t *>(output); | ||
| const uint32_t elem_sz = element_size(); |
The basic PQ has been implemented, but its QPS requires further optimization. The recall test results for the current implementation are as follows:
HNSW
Configuration:
M: 50efConstruction: 500efSearch: 400topk: 50L2 Metric
643216480240120The results are generally consistent with previous tests. Under the int8 condition, using one subquantizer per 4 dimensions yields the best performance.
Cosine Metric
Option 1: Normalization + IP Metric
Option 2: Normalization + L2 Metric
192+ Option 2384+ Option 2The performance of both options is nearly identical. Option 2 was ultimately adopted because the L2 metric also supports operations specific to L2, such as
decentralization.Inner Product Metric
Option 1: L2 for k-means + L2 encoding + IP for SDC calculation + IP for ADC calculation
Option 2: L2 for k-means + L2 encoding + L2 for SDC calculation + IP for ADC calculation |<---- faiss approach
Option 3: L2 for k-means + IP encoding + IP for SDC calculation + IP for ADC calculation
Option 4: IP for k-means(sp) + IP encoding + IP for SDC calculation + IP for ADC calculation |<---- ivf porting approach
192+ Option 1384+ Option 1192+ Option 2384+ Option 2Option 1 performs slightly better and is more semantically coherent: L2 is used for encoding, while IP is used for distance calculation.
Decentralization
3232+ decentralization192192+ decentralization384384+ decentralizationDecentralization does not yield significant improvements, but support for it is retained nonetheless.
IVF
Configuration:
centroid_count: 128nprobe: 16topk: 50ScaleFactor: 4Option 1: Build codebooks using residuals, with each cluster assigned an independent codebook.
Option 2: Build codebooks using residuals, with all clusters sharing a single codebook. |<--- faiss approach
L2 Metric
int8+32+ Option 1int8+32+ Option 2int8+240+ Option 1int8+240+ Option 2Cosine Metric
int8+192+ Option 1int8+192+ Option 2int8+384+ Option 1int8+384+ Option 2Inner Product Metric
int8+192+ Option 1int8+192+ Option 2The original IVFPQ+IP implementation uses MIPS, which results in lower recall.
Although Option 2 shows a slight decrease in Recall compared to Option 1, it significantly reduces training time and storage requirements while maintaining comparable Refiner Recall. Therefore, Option 2 was ultimately adopted.