developmentseed / developmentseed/bioacoustics-api

Index strategy benchmarking

Open
#10 0 comments 4 reactions 0 assignees View on GitHub
Dominant language
Jupyter Notebook
Stars
1
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Milvus uses a variety of Approximate Nearest Neighbor (ANN) algorithms in order to allow users to play with the search speed, search accuracy and memory footprint of the vector search. The idea is that if we accept a small decrease in search accuracy, and some additional pre-computation time when setting up the API/Index, we can achieve drastic reduction in search time and memory cost.

This issue will explore a different indexing strategies for the Milvus vector database, comparing the memory footprint (directly relates to cost), recall (search accuracy) and search time for each option.

### Background:
A couple notes on some indexing strategies/terms:
- IVF: Inverted File Index is the most common ANN strategy. It creates a number of regions (defined by the `nlist`) parameter, and clusters the vectors within those regions. At search time, the input vector is first compared to the centroid of each region to find the region within which the search vector falls, and then only the vectors belonging to that region (and possibly a small number of neighboring regions, set the `nprobe` search params) need to be compared to the search vector. Thus the number of comparisons for a search of `n` vectors becomes: ` (approximately) nlist + ( nprobe * n/list )` ( the calculation is approximate because the vectors are guaranteed to be 100% evenly distributed) . For 100,000 vectors clustered within 1024 regions with an nprobe value of 16, we go from `100000` comparisons to `(approximately) 1024 + (16 * 100000/1024) = ~ 2587` comparisons, an almost 97% reduction in vector comparisons. The memory footprint is the same as the original vectors, with a small additional memory consumption due to the storage of the list of region centroids --> vector_ids mapping.
- SQ8: Scalar Quantization to 8 bits. Converts each 32 bit float within each vector to an 8 bit integer. 8 bit integers take up 25% as much memory as 32 bit floats and are [significantly faster to perform matrix calculations with](https://arxiv.org/abs/2208.07339), and, especially with high dimensional vectors, do not decrease accuracy significantly.
- PQ: Product Quantization breaks each vector into `m` subvectors. The subvectors are all then clustered using a similar process to the IVF, such that each subvector can be replaced with the centroid of the region it belongs without significant decrease in accuracy. The memory footprint is then, approximately, the original dimensionality of the vector, D, divided by the number of subregions the vector is broken into, multiplied by the number of bits used to store the centroid of each subvector
- PCA: Primary Component Analysis is a dimensionality reduction technique which identifies the principal dimensions of the data or the subset of axes along which the data is least "noisy".

### A note on interpreting recall:
The metric we used, `recall@100` is the fraction of vectors (out of 100) returned by an index, which are contained within the reference set. The reference set is generated using a `FLAT` index, which is no indexing strategy at all. It is a brute force search, which compares the input vector to _every single_ database vector and has no memory optimizations. It's not surprising that the `FLAT` index search time is so slow.

An important thing to note is that if an index achieves a `recall@100` value of `0.8`, the remaining 20% of vectors included in the index's result set, which are _not_ in the reference set will not be "wrong". In fact they're likely to still be _very_ similar to the input vector, just perhaps within the top 200 or 300 most similar vectors rather than the top 100. In that sense, I would caution against considering a recall of `0.8` as only 80% "good", but rather sharing 80% of overlap with the reference set with the remaining 20% still be very similar.

## Results:

Note: these experiments were performed on a test set of ~93k vectors
Note: see [this comment](https://github.com/milvus-io/milvus/discussions/18719#discussioncomment-3428862) for the original memory consumption calculations provided by the Milvus library maintainers

### Reference set:

| Index Type | PCA Dim. Reduction | Build Params | Recall (%) | Memory (Mb) | Memory (% of reference index) | Build Time (s) | Search Time (s) | Load Time (s) |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|FLAT | | | 100.0 | 475.1 | 100.0 | 0.68 | 8.68 | 29.13 |

### Result set:
| Index Type | PCA Dim. Reduction | Build Params | Recall (%) | Memory (Mb) | Memory (% of reference index) | Build Time (s) | Search Time (s) | Load Time (s) |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|IVF_FLAT | | nlist:1024 | 88.38 | 480.34 | 101.1 | 155.49 | 0.99 | 25.28 |
|IVF_SQ8 | | nlist:1024 | 88.01 | 124.02 | 26.1 | 153.71 | 0.88 | 20.22 |
|IVF_PQ | | nlist:1024, m:32, nbits:4 | 47.87 | 6.81 | 1.43 | 143.62 | 0.57 | 17.32 |
|IVF_PQ | | nlist:1024, m:32, nbits:8 | 59.35 | 9.52 | 2.0 | 431.66 | 0.85 | 20.16 |
|IVF_PQ | | nlist:1024, m:64, nbits:4 | 54.95 | 8.29 | 1.75 | 145.09 | 1.87 | 15.77 |
|IVF_PQ | | nlist:1024, m:64, nbits:8 | 67.45 | 12.49 | 2.63 | 707.45 | 0.78 | 14.59 |
|IVF_PQ | | nlist:1024, m:128, nbits:4 | 63.2 | 11.26 | 2.37 | 147.51 | 0.72 | 22.36 |
|IVF_PQ | | nlist:1024, m:128, nbits:8 | 76.45 | 18.43 | 3.88 | 866.46 | 1.42 | 15.32 |
|IVF_PQ | | nlist:1024, m:256, nbits:4 | 72.33 | 17.2 | 3.62 | 159.4 | 1.03 | 21.44 |
|IVF_PQ | | nlist:1024, m:256, nbits:8 | 82.93 | 30.31 | 6.38 | 1268.6 | 1.08 | 24.35 |
|FLAT | 64 | | 63.53 | 23.76 | 5.0 | 0.68 | 0.46 | 21.74 |
|IVF_FLAT | 64 | nlist:1024 | 62.4 | 24.02 | 5.06 | 8.85 | 0.1 | 18.42 |
|IVF_SQ8 | 64 | nlist:1024 | 62.41 | 6.2 | 1.31 | 9.78 | 0.11 | 17.54 |
|IVF_PQ | 64 | nlist:1024, m:8, nbits:4 | 62.41 | 0.64 | 0.13 | 8.67 | 0.11 | 18.3 |
|IVF_PQ | 64 | nlist:1024, m:8, nbits:8 | 55.04 | 1.07 | 0.23 | 31.82 | 0.12 | 15.49 |
|IVF_PQ | 64 | nlist:1024, m:16, nbits:4 | 55.04 | 1.01 | 0.21 | 8.78 | 0.22 | 18.7 |
|IVF_PQ | 64 | nlist:1024, m:16, nbits:8 | 59.7 | 1.81 | 0.38 | 40.11 | 0.11 | 17.46 |
|IVF_PQ | 64 | nlist:1024, m:32, nbits:4 | 58.72 | 1.75 | 0.37 | 9.14 | 0.11 | 18.2 |
|IVF_PQ | 64 | nlist:1024, m:32, nbits:8 | 62.11 | 3.3 | 0.69 | 47.0 | 0.11 | 20.42 |
|FLAT | 128 | | 74.69 | 47.51 | 10.0 | 0.69 | 0.62 | 15.21 |
|IVF_FLAT | 128 | nlist:1024 | 71.97 | 48.03 | 10.11 | 11.97 | 0.13 | 15.28 |
|IVF_SQ8 | 128 | nlist:1024 | 71.94 | 12.4 | 2.61 | 12.99 | 0.12 | 14.19 |
|IVF_PQ | 128 | nlist:1024, m:16, nbits:4 | 52.4 | 1.27 | 0.27 | 11.4 | 0.13 | 21.5 |
|IVF_PQ | 128 | nlist:1024, m:16, nbits:8 | 62.23 | 2.14 | 0.45 | 57.53 | 0.14 | 19.2 |
|IVF_PQ | 128 | nlist:1024, m:32, nbits:4 | 59.35 | 2.02 | 0.42 | 12.54 | 0.13 | 14.14 |
|IVF_PQ | 128 | nlist:1024, m:32, nbits:8 | 68.66 | 3.62 | 0.76 | 74.98 | 0.13 | 21.49 |
|IVF_PQ | 128 | nlist:1024, m:64, nbits:4 | 68.66 | 3.5 | 0.74 | 13.03 | 0.12 | 14.16 |
|IVF_PQ | 128 | nlist:1024, m:64, nbits:8 | 71.53 | 6.59 | 1.39 | 89.27 | 0.13 | 18.32 |
|FLAT | 256 | | 84.14 | 95.02 | 20.0 | 0.69 | 1.08 | 18.6 |
|IVF_FLAT | 256 | nlist:1024 | 79.42 | 96.07 | 20.22 | 19.15 | 0.18 | 17.5 |
|IVF_SQ8 | 256 | nlist:1024 | 79.36 | 24.8 | 5.22 | 19.81 | 0.18 | 15.26 |
|IVF_PQ | 256 | nlist:1024, m:32, nbits:4 | 54.44 | 2.55 | 0.54 | 20.0 | 0.18 | 15.45 |
|IVF_PQ | 256 | nlist:1024, m:32, nbits:8 | 66.39 | 4.28 | 0.9 | 134.1 | 0.21 | 22.14 |
|IVF_PQ | 256 | nlist:1024, m:64, nbits:4 | 66.39 | 4.03 | 0.85 | 20.95 | 0.19 | 15.3 |
|IVF_PQ | 256 | nlist:1024, m:64, nbits:8 | 74.33 | 7.25 | 1.53 | 184.09 | 0.24 | 22.08 |
|IVF_PQ | 256 | nlist:1024, m:128, nbits:4 | 72.5 | 7.0 | 1.47 | 23.32 | 0.29 | 13.07 |
|IVF_PQ | 256 | nlist:1024, m:128, nbits:8 | 78.91 | 13.19 | 2.78 | 224.87 | 0.22 | 21.58 |
|FLAT | 512 | | 92.74 | 190.04 | 40.0 | 0.71 | 2.5 | 19.5 |
|IVF_FLAT | 512 | nlist:1024 | 83.29 | 192.14 | 40.44 | 38.63 | 0.34 | 20.43 |
|IVF_SQ8 | 512 | nlist:1024 | 83.18 | 49.61 | 10.44 | 41.03 | 0.31 | 14.8 |
|IVF_PQ | 512 | nlist:1024, m:64, nbits:4 | 56.66 | 5.1 | 1.07 | 38.06 | 0.3 | 18.1 |
|IVF_PQ | 512 | nlist:1024, m:64, nbits:8 | 69.48 | 8.56 | 1.8 | 281.7 | 0.36 | 14.37 |
|IVF_PQ | 512 | nlist:1024, m:128, nbits:4 | 67.19 | 8.07 | 1.7 | 40.97 | 0.33 | 15.43 |
|IVF_PQ | 512 | nlist:1024, m:128, nbits:8 | 77.88 | 14.5 | 3.05 | 392.08 | 0.36 | 14.25 |
|IVF_PQ | 512 | nlist:1024, m:256, nbits:4 | 75.87 | 14.01 | 2.95 | 46.74 | 0.57 | 19.84 |
|IVF_PQ | 512 | nlist:1024, m:256, nbits:8 | 82.52 | 26.38 | 5.55 | 483.06 | 0.45 | 14.16 |

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.