-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Implement IndexFlatL2Panorama
#4645
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| """Test when n_levels doesn't evenly divide dimension""" | ||
| test_cases = [(65, 4), (63, 8), (100, 7)] | ||
|
|
||
| # TODO(aknayar): Test functions like get_single_code(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will add these tests in a follow-up PR.
|
I rebuilt with AVX2 on Linux and was unable to reproduce the failing tests seen here, any ideas what may have happened? |
|
Hey, let me just copy what @mnorris11 said and we can resume the thread from there.
Do you have faiss installed with numpy2? It's a recent integration, and that could be the reason for the difference. Let me know the conda steps you took to repro! |
|
@limqiying Thank you for the ideas! It seems like it was, in fact, some weird case involving a tie. Panorama also suffers from floating-point imprecision due to how we calculate squared L2 norm: Faiss does |
|
Hi @aknayar , when doing some benchmarks, I cannot seem to get a speedup from IndexFlatPanorama. It could be due to my configuration for |
|
Hi @mnorris11, this is interesting—your parameters seem fine. The theoretical ideal for
I tried your setup on our server and observed a 6.98x speedup on GIST1M: Do you mind sharing your benchmarking script so I could give it a try locally? I'm also curious what |
Thanks for the info. I was checking some internal datasets, along with the SyntheticDataset present within Faiss. It looks something like this, piecemeal from the actual script. The Flat results are all around 3000ms for this configuration for SyntheticDataset. Panorama results vary from 5000 to 8000. Definitely let me know if you see issues in the methodology here, this was whipped together somewhat quickly. I can check the cvar a bit later. |
|
@mnorris11 Thank you so much for sharing your code—I now notice something super important that I completely forgot to mention: When That being said, Panorama shines when any of the following is true:
The third point is most important since this is exactly what In the meantime, to properly gauge |
I actually do not see this line of code being hit in Run_search_L2sqr at all when debugging the search() section. progressive_filter_batch seems to just call fvec_inner_product. Am I missing something? I tried to just pass but this did not result in any change. (nq still 1000). |
|
@mnorris11 The issue is that |
|
My mistake. Thanks for the swift replies. I see great speedup on all datasets now after passing the params correctly to the Panorama index! It would be great if we can make this the default for Panorama. What do you think about the Panorama passing IDSelectorAll inside SearchParameters if they are not specified? |
|
@mnorris11 No worries! I'm very glad you're now seeing some speedups! So it turns out that Panorama actually doesn't need the Just as a test, if you change your code to the following, you should still observe speedups: |
|
you can also change the variable Line 278 in 29f8e72
|
mdouze
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
| } | ||
|
|
||
| // IndexFlatL2Panorama | ||
| if (match("FlatL2Panorama([0-9]+)(_[0-9]+)?")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be documented in the Faiss wiki https://github.com/facebookresearch/faiss/wiki/The-index-factory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add IndexFlatPanorama and IndexFlatL2Panorama to the wiki. Should this be done post-merge? I'm also unsure on which section in the wiki this would fall into (besides the tree image that displays the hierarchy).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mdouze I can add to the wiki (both the Guidelines to Choosing an Index and the index factory) after merge.
|
@mdouze Thanks for the comments! I have addressed them and implemented |
| } | ||
|
|
||
| void IndexFlatPanorama::reconstruct_n(idx_t i, idx_t n, float* recons) const { | ||
| Index::reconstruct_n(i, n, recons); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This overrides IndexFlatCodes' implementation of reconstruct_n.
|
@mnorris11 merged this pull request in 9cd408b. |
|
@mnorris11 Thank you! I have a local build for |
This PR adds
IndexFlatL2Panorama, integrating Panorama (as specified in the paper) intoIndexFlatL2. This is the first step in creating anIndexRefinePanorama, which will useIndexFlatL2Panorama(or anIndexPreTransformwith anIndexFlatL2Panorama) as itsrefine_index.Refactoring
Since the bulk of Panorama's refinement logic would be duplicated between
IndexFlatL2PanoramaandIndexIVFFlatPanorama, it has been factored out into a newPanoramastruct. This struct contains key parameters (batch_size,d, etc.) and the following utility functions:copy_codes_to_level_layout: Writes new vectors tocodesfollowing Panorama's storage layoutcompute_cumulative_sums: Computes the cumulative sums for new vectorscompute_query_cum_sums: Computes the cumulative sums for a new queryprogressive_filter_batch: Performs Panorama refinement on a batch of vectorsThese utilities will be shared by most Panorama indexes, which is why I have refactored them into their own utility.
IndexRefinePanorama
While the
IndexFlatL2Panoramaimplemented in this PR technically contains all the functionality needed to implementIndexRefinePanorama(performingsearchon a subset of indices), it is not ready to be used as arefine_index. The current implementation is not optimized for the case ofIndexRefine, where we perform search on a very small subset of the datapoints. This leads to vastly scattered memory accesses during thesearch, to the point where the overhead of maintainingactive_indicesandexact_distancescan thwart Panorama's speedups.As such, to optimize for
IndexRefinewe will need a standalone implementation ofsearch_subsetwhich instead does the following:i, compute its distance alone by Panorama refinement (essentially havingbatch_size= 1. In fact, for this very reason I have madebatch_sizea parameter in the constructor—IndexRefinewill require it to be 1 due to noncontiguous memory accesses, but typical workloads would benefit from 128-1024.)This will unfortunately mean we cannot reuse the search utilities in the
Panoramastruct in this specific case, but will allow us to squeeze 2-5x speedups during the reordering phase ofIndexRefine.Testing
tests/test_flat_l2_panorama.pybenchs/bench_flat_l2_panorama.py, yielding the following results:The recall being less than 1.0 is perhaps due to discrepancies between faiss results and the

ground_truthvalues.