-
Notifications
You must be signed in to change notification settings - Fork 20
[MOD-8198] Introduce INT8 distance functions #560
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
[MOD-8198] Introduce INT8 distance functions #560
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## meiravg_feature_int_uint_8 #560 +/- ##
==============================================================
- Coverage 96.97% 96.91% -0.06%
==============================================================
Files 100 103 +3
Lines 5287 5444 +157
==============================================================
+ Hits 5127 5276 +149
- Misses 160 168 +8 ☔ View full report in Codecov by Sentry. |
add cosine to spaces fix typos in calculator
add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils
change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name
change create_int8_vec to populate_int8_vec add compute norm
minimal dim = 32
d427c81
to
3586a76
Compare
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.
💪
Few small comments/questions
return ret_dist_func; | ||
} | ||
|
||
dist_func_t<float> Cosine_INT8_GetDistFunc(size_t dim, unsigned char *alignment, |
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 function has the exact same logic as the above except for the call to Choose_INT8_Cosine_implementation_AVX512F_BW_VL_VNNI
eight. Consider doing a consolidation for the common logic
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.
The only common code is the alignment intizliation, which we duplicate in all the functions in this file, how is this function different?
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.
btw note to self: check coverage
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.
coverage: added cosine to small dimension spaces unit tests
// Multiply groups of 2 adjacent pairs of signed 16-bit integers in `a` with corresponding | ||
// 16-bit integers in `b`, producing 2 intermediate signed 32-bit results. Sum these 2 results | ||
// with the corresponding 32-bit integer in src, and store the packed 32-bit results in dst. | ||
sum = _mm512_dpwssd_epi32(sum, va, vb); |
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.
Why not use _mm512_dpbusd_epi32
, avoiding loading only 32 elements and converting them to int16?
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.
nice catch!
Unfortunately, _mm512_dpbusd_epi32
expects a
to be unsigned 8-bit integers vecor, and b
to be signed 8-bit vector
Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in a with corresponding signed 8-bit integers in b
So although indeed faster, it gives the wrong results
Benchmark Time CPU Iterations UserCounters...
--------------------------------------------------------------------------------------------
IP_dpwssd/Dim:512 5.41 ns 5.41 ns 128425185 dist=-1.024k
IP_dpbusd/Dim:512 3.26 ns 3.26 ns 218138693 dist=130.048k
IP_sanity_bm/Dim:512/iterations:1 490 ns 360 ns 1 dist=-1.024k
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.
Bummer... So there is no function for multiplying int8int8 or uint8uint8? Only an unsigned by a signed?
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.
nope
we might want to consider using _mm512_unpackhi_epi8
and _mm512_unpacklo_epi8
for uint8_t
align to vector size ncluding the norm in cosine dist unit test cover small dim in cosine chooser
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.
🤯
* naive implementation of L2 * update * implment naive disatnce for int8 add cosine to spaces fix typos in calculator * imp choose L2 int8 with 256bit loop add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils * imp space bm for int8 change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name * fix INITIALIZE_BENCHMARKS_SET_L2_IP and add include to F_BW_VL_VNNI * rename unit/test_utuils to unit_test_utils * seed create vec * format * implmenet IP + unit test * ip bm * format * implement cosine in ip API change create_int8_vec to populate_int8_vec add compute norm * use mask sub instead of msk load * loop size = 512 minimal dim = 32 * add int8 to bm * reanme to simd64 * convert to int before multiplication * review comments: align to vector size ncluding the norm in cosine dist unit test cover small dim in cosine chooser * use sizeof(float)instead of 4 * remove int conversion in test_utils::compute_norm * REVERT!!! malicious test to see if we get to the code * assert dummt * fix alignemnt test * remove assert * remove cosine alignment (cherry picked from commit afb5250)
Successfully created backport PR for |
* [MOD-8198] Introduce INT8 distance functions (#560) * naive implementation of L2 * update * implment naive disatnce for int8 add cosine to spaces fix typos in calculator * imp choose L2 int8 with 256bit loop add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils * imp space bm for int8 change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name * fix INITIALIZE_BENCHMARKS_SET_L2_IP and add include to F_BW_VL_VNNI * rename unit/test_utuils to unit_test_utils * seed create vec * format * implmenet IP + unit test * ip bm * format * implement cosine in ip API change create_int8_vec to populate_int8_vec add compute norm * use mask sub instead of msk load * loop size = 512 minimal dim = 32 * add int8 to bm * reanme to simd64 * convert to int before multiplication * review comments: align to vector size ncluding the norm in cosine dist unit test cover small dim in cosine chooser * use sizeof(float)instead of 4 * remove int conversion in test_utils::compute_norm * REVERT!!! malicious test to see if we get to the code * assert dummt * fix alignemnt test * remove assert * remove cosine alignment * Override missing intrinsincs in gcc <11 (#572) * override _mm256_loadu_epi8 with mm256_maskz_loadu_epi8 if gcc < 11 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95483 * fix * disable flow temp * add comment * [MOD-8200] [MOD-8202] INT8 index (#566) * naive implementation of L2 * update * implment naive disatnce for int8 add cosine to spaces fix typos in calculator * imp choose L2 int8 with 256bit loop add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils * imp space bm for int8 change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name * fix INITIALIZE_BENCHMARKS_SET_L2_IP and add include to F_BW_VL_VNNI * rename unit/test_utuils to unit_test_utils * seed create vec * format * implmenet IP + unit test * ip bm * format * implement cosine in ip API change create_int8_vec to populate_int8_vec add compute norm * use mask sub instead of msk load * loop size = 512 minimal dim = 32 * add int8 to bm * reanme to simd64 * convert to int before multiplication * introduce IntegralType_ComputeNorm * move preprocessor logic to choose if cosine preprocessor is needed to CreateIndexComponents: pass bool is_normalized get distnce function according to original metric get pp according to is_normalized && metric == VecSimMetric_Cosine, and remove this logic from the indexes factories. add dataSize member to AbstractIndexInitParams add VecSimType_INT8 type introduce VecSimParams_GetDataSize: returns datasize introduce and implement GetNormalizeFunc<int8_t> thtat returns int8_normalizeVector int8_normalizeVector computes the norm and stores it at the emd of argument vector. * add int8 tests * fix include unint_test_utils * add int 8 to index factories remove normalize_func from VecSimIndexAbstract members tests: int8 unit test create int8 indexes unit_test_utils: CalcIndexDataSize: casts VecSimIndex * to VecSimIndexAbstract<dist_t, data_t> * and calls VecSimIndexAbstract<dist_t, data_t>::getDataSize() cast_to_tiered_index<data_t, dist_t>: takes VecSimIndex * ans casts to TieredHNSWIndex<data_t, dist_t> * * add EstimateInitialSize for int8 to indexes factories 2 new function to test_utils:: CreateTieredParams CreateNewTieredHNSWIndex add test_initial_size_estimation to CommonTypeMetricTests use CommonTypeMetricTieredTests for tiered tests * add int8 unit tests add int8 to * VecSimDebug_GetElementNeighborsInHNSWGraph * VecSim_Normalize *HNSW NewIndex from file * remove duplicated GetDistFunc<int8_t, float> move ASSERT_DEBUG_DEATH of CalcIndexDataSize to a separate test * remove assert test, the statement is excuted and causes crash * imporve normalize test * rename test_utils::compute_norm -> test_utils::integral_compute_norm remove test_normalize.cpp file * use stack allocation instead of heap allocation in tests * fix float comparison in test_serialization avoid evaluating statement in typeid to avoid clang warnig * renae CalcIndexDataSize -> CalcVectorDataSize move components tests from test_common to test_components * add comment to INSTANTIATE_TEST_SUITE_P * [MOD-8206] INT8 flow tests (#573) * test_hnsw.py intiital * int8 hnsw tests * general tests class * flow_bruteforce.py: introduce GeneralTest call from TestINT8 common.py: introduce create_flat_index create_add_vectors move fp32_expand_and_calc_cosine_dist to common.py * tiered flow tests: * add optional create_data_func to IndexCtx, use for special datatypes *inntroduce test_create_int8 and test_search_insert_int8 create_int8_vectors expectes shape (tuple) * use query.flat * revert using flat (not helping in int8) fix float16 calling query.flat * revert changes in Data class in bf tests revert test_bf_float16_range_query change * fix merge
* [MOD-8198] Introduce INT8 distance functions (#560) * naive implementation of L2 * update * implment naive disatnce for int8 add cosine to spaces fix typos in calculator * imp choose L2 int8 with 256bit loop add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils * imp space bm for int8 change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name * fix INITIALIZE_BENCHMARKS_SET_L2_IP and add include to F_BW_VL_VNNI * rename unit/test_utuils to unit_test_utils * seed create vec * format * implmenet IP + unit test * ip bm * format * implement cosine in ip API change create_int8_vec to populate_int8_vec add compute norm * use mask sub instead of msk load * loop size = 512 minimal dim = 32 * add int8 to bm * reanme to simd64 * convert to int before multiplication * review comments: align to vector size ncluding the norm in cosine dist unit test cover small dim in cosine chooser * use sizeof(float)instead of 4 * remove int conversion in test_utils::compute_norm * REVERT!!! malicious test to see if we get to the code * assert dummt * fix alignemnt test * remove assert * remove cosine alignment * Override missing intrinsincs in gcc <11 (#572) * override _mm256_loadu_epi8 with mm256_maskz_loadu_epi8 if gcc < 11 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95483 * fix * disable flow temp * add comment * [MOD-8200] [MOD-8202] INT8 index (#566) * naive implementation of L2 * update * implment naive disatnce for int8 add cosine to spaces fix typos in calculator * imp choose L2 int8 with 256bit loop add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils * imp space bm for int8 change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name * fix INITIALIZE_BENCHMARKS_SET_L2_IP and add include to F_BW_VL_VNNI * rename unit/test_utuils to unit_test_utils * seed create vec * format * implmenet IP + unit test * ip bm * format * implement cosine in ip API change create_int8_vec to populate_int8_vec add compute norm * use mask sub instead of msk load * loop size = 512 minimal dim = 32 * add int8 to bm * reanme to simd64 * convert to int before multiplication * introduce IntegralType_ComputeNorm * move preprocessor logic to choose if cosine preprocessor is needed to CreateIndexComponents: pass bool is_normalized get distnce function according to original metric get pp according to is_normalized && metric == VecSimMetric_Cosine, and remove this logic from the indexes factories. add dataSize member to AbstractIndexInitParams add VecSimType_INT8 type introduce VecSimParams_GetDataSize: returns datasize introduce and implement GetNormalizeFunc<int8_t> thtat returns int8_normalizeVector int8_normalizeVector computes the norm and stores it at the emd of argument vector. * add int8 tests * fix include unint_test_utils * add int 8 to index factories remove normalize_func from VecSimIndexAbstract members tests: int8 unit test create int8 indexes unit_test_utils: CalcIndexDataSize: casts VecSimIndex * to VecSimIndexAbstract<dist_t, data_t> * and calls VecSimIndexAbstract<dist_t, data_t>::getDataSize() cast_to_tiered_index<data_t, dist_t>: takes VecSimIndex * ans casts to TieredHNSWIndex<data_t, dist_t> * * add EstimateInitialSize for int8 to indexes factories 2 new function to test_utils:: CreateTieredParams CreateNewTieredHNSWIndex add test_initial_size_estimation to CommonTypeMetricTests use CommonTypeMetricTieredTests for tiered tests * add int8 unit tests add int8 to * VecSimDebug_GetElementNeighborsInHNSWGraph * VecSim_Normalize *HNSW NewIndex from file * remove duplicated GetDistFunc<int8_t, float> move ASSERT_DEBUG_DEATH of CalcIndexDataSize to a separate test * remove assert test, the statement is excuted and causes crash * imporve normalize test * rename test_utils::compute_norm -> test_utils::integral_compute_norm remove test_normalize.cpp file * use stack allocation instead of heap allocation in tests * fix float comparison in test_serialization avoid evaluating statement in typeid to avoid clang warnig * renae CalcIndexDataSize -> CalcVectorDataSize move components tests from test_common to test_components * add comment to INSTANTIATE_TEST_SUITE_P * [MOD-8206] INT8 flow tests (#573) * test_hnsw.py intiital * int8 hnsw tests * general tests class * flow_bruteforce.py: introduce GeneralTest call from TestINT8 common.py: introduce create_flat_index create_add_vectors move fp32_expand_and_calc_cosine_dist to common.py * tiered flow tests: * add optional create_data_func to IndexCtx, use for special datatypes *inntroduce test_create_int8 and test_search_insert_int8 create_int8_vectors expectes shape (tuple) * use query.flat * revert using flat (not helping in int8) fix float16 calling query.flat * revert changes in Data class in bf tests revert test_bf_float16_range_query change * fix merge (cherry picked from commit babfbe0)
[MOD-8198] Introduce INT8 (#560) (#571) * [MOD-8198] Introduce INT8 distance functions (#560) * naive implementation of L2 * update * implment naive disatnce for int8 add cosine to spaces fix typos in calculator * imp choose L2 int8 with 256bit loop add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils * imp space bm for int8 change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name * fix INITIALIZE_BENCHMARKS_SET_L2_IP and add include to F_BW_VL_VNNI * rename unit/test_utuils to unit_test_utils * seed create vec * format * implmenet IP + unit test * ip bm * format * implement cosine in ip API change create_int8_vec to populate_int8_vec add compute norm * use mask sub instead of msk load * loop size = 512 minimal dim = 32 * add int8 to bm * reanme to simd64 * convert to int before multiplication * review comments: align to vector size ncluding the norm in cosine dist unit test cover small dim in cosine chooser * use sizeof(float)instead of 4 * remove int conversion in test_utils::compute_norm * REVERT!!! malicious test to see if we get to the code * assert dummt * fix alignemnt test * remove assert * remove cosine alignment * Override missing intrinsincs in gcc <11 (#572) * override _mm256_loadu_epi8 with mm256_maskz_loadu_epi8 if gcc < 11 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95483 * fix * disable flow temp * add comment * [MOD-8200] [MOD-8202] INT8 index (#566) * naive implementation of L2 * update * implment naive disatnce for int8 add cosine to spaces fix typos in calculator * imp choose L2 int8 with 256bit loop add spaces unit tests for int8 L2 add compilation flags introduce tests/utils for general utils * imp space bm for int8 change INITIALIZE_BENCHMARKS_SET to INITIALIZE_BENCHMARKS_SET_L2_IP introduce INITIALIZE_BENCHMARKS_SET_COSINE fix typos in Choose_INT8_L2_implementation_AVX512F_BW_VL_VNNI name * fix INITIALIZE_BENCHMARKS_SET_L2_IP and add include to F_BW_VL_VNNI * rename unit/test_utuils to unit_test_utils * seed create vec * format * implmenet IP + unit test * ip bm * format * implement cosine in ip API change create_int8_vec to populate_int8_vec add compute norm * use mask sub instead of msk load * loop size = 512 minimal dim = 32 * add int8 to bm * reanme to simd64 * convert to int before multiplication * introduce IntegralType_ComputeNorm * move preprocessor logic to choose if cosine preprocessor is needed to CreateIndexComponents: pass bool is_normalized get distnce function according to original metric get pp according to is_normalized && metric == VecSimMetric_Cosine, and remove this logic from the indexes factories. add dataSize member to AbstractIndexInitParams add VecSimType_INT8 type introduce VecSimParams_GetDataSize: returns datasize introduce and implement GetNormalizeFunc<int8_t> thtat returns int8_normalizeVector int8_normalizeVector computes the norm and stores it at the emd of argument vector. * add int8 tests * fix include unint_test_utils * add int 8 to index factories remove normalize_func from VecSimIndexAbstract members tests: int8 unit test create int8 indexes unit_test_utils: CalcIndexDataSize: casts VecSimIndex * to VecSimIndexAbstract<dist_t, data_t> * and calls VecSimIndexAbstract<dist_t, data_t>::getDataSize() cast_to_tiered_index<data_t, dist_t>: takes VecSimIndex * ans casts to TieredHNSWIndex<data_t, dist_t> * * add EstimateInitialSize for int8 to indexes factories 2 new function to test_utils:: CreateTieredParams CreateNewTieredHNSWIndex add test_initial_size_estimation to CommonTypeMetricTests use CommonTypeMetricTieredTests for tiered tests * add int8 unit tests add int8 to * VecSimDebug_GetElementNeighborsInHNSWGraph * VecSim_Normalize *HNSW NewIndex from file * remove duplicated GetDistFunc<int8_t, float> move ASSERT_DEBUG_DEATH of CalcIndexDataSize to a separate test * remove assert test, the statement is excuted and causes crash * imporve normalize test * rename test_utils::compute_norm -> test_utils::integral_compute_norm remove test_normalize.cpp file * use stack allocation instead of heap allocation in tests * fix float comparison in test_serialization avoid evaluating statement in typeid to avoid clang warnig * renae CalcIndexDataSize -> CalcVectorDataSize move components tests from test_common to test_components * add comment to INSTANTIATE_TEST_SUITE_P * [MOD-8206] INT8 flow tests (#573) * test_hnsw.py intiital * int8 hnsw tests * general tests class * flow_bruteforce.py: introduce GeneralTest call from TestINT8 common.py: introduce create_flat_index create_add_vectors move fp32_expand_and_calc_cosine_dist to common.py * tiered flow tests: * add optional create_data_func to IndexCtx, use for special datatypes *inntroduce test_create_int8 and test_search_insert_int8 create_int8_vectors expectes shape (tuple) * use query.flat * revert using flat (not helping in int8) fix float16 calling query.flat * revert changes in Data class in bf tests revert test_bf_float16_range_query change * fix merge (cherry picked from commit babfbe0) Co-authored-by: meiravgri <109056284+meiravgri@users.noreply.github.com>
This PR introduces naive and optimized distance calculation functions for vectors of
INT8
type elements, for all distance metrics.Since
INT8
vectors store integral values, we can't normalize these vectors in place.Because of this, unlike other types,
INT8
requires a dedicated implementation for cosine distance.float
number.Optimized distance functions
Requirments
Optimization is available for CPUs and compilers supporting all of the following flags:
Supported dimensions
Optimization is available for vector dimensions larger than 32.
Vectors with smaller dimensions will be calculated using naive implementation.
alignment
IP and L2
The vectors memory is aligned to memory addresses divisible by
32 * sizeof(int8)
since In each step we load 32-int8 elementsCosine
We skip aligning the vector's memory address for int8 vectors with cosine distance due to the extra float stored at the end for the norm.
This changes the alignment requirement to
(dim + sizeof(float)) % 32
for the vector's address to be aligned to 256 bits.Since vectors that meet this condition necessarily have a residual (since dim % 32 ≠ 0), subsequent loads will be offset during distance calculation.
To avoid adding complexity to the distance function, we do not align the vectors in this case,
assuming the performance impact is negligible.
Changes in tests