faiss 0.6.4 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/ext/faiss/extconf.rb +1 -1
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +175 -0
- data/vendor/faiss/faiss/Clustering.cpp +150 -60
- data/vendor/faiss/faiss/Clustering.h +29 -0
- data/vendor/faiss/faiss/IVFlib.cpp +99 -0
- data/vendor/faiss/faiss/IVFlib.h +15 -0
- data/vendor/faiss/faiss/Index.cpp +44 -0
- data/vendor/faiss/faiss/Index.h +19 -14
- data/vendor/faiss/faiss/IndexBinary.cpp +8 -0
- data/vendor/faiss/faiss/IndexBinary.h +8 -0
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +82 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +19 -0
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +34 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +33 -17
- data/vendor/faiss/faiss/IndexFastScan.h +6 -3
- data/vendor/faiss/faiss/IndexFlat.cpp +56 -0
- data/vendor/faiss/faiss/IndexFlat.h +31 -0
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +6 -1
- data/vendor/faiss/faiss/IndexHNSW.cpp +456 -10
- data/vendor/faiss/faiss/IndexHNSW.h +38 -0
- data/vendor/faiss/faiss/IndexIDMap.cpp +32 -0
- data/vendor/faiss/faiss/IndexIDMap.h +7 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +281 -31
- data/vendor/faiss/faiss/IndexIVF.h +53 -1
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +46 -14
- data/vendor/faiss/faiss/IndexIVFFastScan.h +4 -2
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +33 -0
- data/vendor/faiss/faiss/IndexIVFFlat.h +16 -0
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +1 -0
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +3 -20
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +50 -14
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -2
- data/vendor/faiss/faiss/IndexIVFSQFastScan.cpp +855 -0
- data/vendor/faiss/faiss/IndexIVFSQFastScan.h +145 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +0 -3
- data/vendor/faiss/faiss/IndexPiPNN.cpp +201 -0
- data/vendor/faiss/faiss/IndexPiPNN.h +83 -0
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +6 -3
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +10 -4
- data/vendor/faiss/faiss/IndexReplicas.cpp +20 -0
- data/vendor/faiss/faiss/IndexReplicas.h +9 -0
- data/vendor/faiss/faiss/IndexSQFastScan.cpp +648 -0
- data/vendor/faiss/faiss/IndexSQFastScan.h +129 -0
- data/vendor/faiss/faiss/IndexShards.cpp +10 -0
- data/vendor/faiss/faiss/IndexShards.h +5 -0
- data/vendor/faiss/faiss/SuperKMeans.cpp +57 -15
- data/vendor/faiss/faiss/SuperKMeans.h +9 -4
- data/vendor/faiss/faiss/VectorTransform.cpp +3 -2
- data/vendor/faiss/faiss/clone_index.cpp +24 -0
- data/vendor/faiss/faiss/gpu/Dataset.h +112 -0
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +16 -13
- data/vendor/faiss/faiss/gpu/GpuCloner.h +4 -0
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -0
- data/vendor/faiss/faiss/gpu/GpuIndex.h +4 -13
- data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +26 -13
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +45 -22
- data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +6 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuDatasetHeader.cpp +18 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +215 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +98 -0
- data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +11 -0
- data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +1 -1
- data/vendor/faiss/faiss/gpu_metal/MetalCloner.h +11 -0
- data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +92 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +4 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexBinaryFlat.h +69 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +38 -0
- data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +106 -0
- data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +10 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -6
- data/vendor/faiss/faiss/impl/ClusteringHelpers.cpp +134 -45
- data/vendor/faiss/faiss/impl/ClusteringHelpers.h +36 -0
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +286 -136
- data/vendor/faiss/faiss/impl/DistanceComputer.cpp +63 -0
- data/vendor/faiss/faiss/impl/DistanceComputer.h +3 -29
- data/vendor/faiss/faiss/impl/HNSW.cpp +46 -10
- data/vendor/faiss/faiss/impl/HNSW.h +72 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -19
- data/vendor/faiss/faiss/impl/NNDescent.cpp +2 -1
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -2
- data/vendor/faiss/faiss/impl/Panorama.h +3 -2
- data/vendor/faiss/faiss/impl/PiPNN.cpp +822 -0
- data/vendor/faiss/faiss/impl/PiPNN.h +122 -0
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +54 -11
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +1 -1
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +81 -57
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +15 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +29 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +1 -6
- data/vendor/faiss/faiss/impl/approx_topk/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/approx_topk/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHash_impl.h +5 -2
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/rvv.cpp +0 -4
- data/vendor/faiss/faiss/impl/expanded_scanners.h +88 -0
- data/vendor/faiss/faiss/impl/fast_scan/FastScanDistancePostProcessing.h +4 -0
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops.h +61 -64
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops_512.h +13 -14
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +17 -129
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +25 -19
- data/vendor/faiss/faiss/impl/fast_scan/fast_scan.cpp +5 -0
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/impl-neon.cpp +0 -88
- data/vendor/faiss/faiss/impl/fast_scan/impl-riscv.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/kernels_neon.h +155 -0
- data/vendor/faiss/faiss/impl/fast_scan/kernels_simd256.h +22 -1
- data/vendor/faiss/faiss/impl/fast_scan/kernels_simd512.h +3 -2
- data/vendor/faiss/faiss/impl/fast_scan/simd_result_handlers.h +41 -23
- data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/index_read.cpp +172 -0
- data/vendor/faiss/faiss/impl/index_write.cpp +95 -0
- data/vendor/faiss/faiss/impl/pipnn/HashPrune.cpp +159 -0
- data/vendor/faiss/faiss/impl/pipnn/HashPrune.h +69 -0
- data/vendor/faiss/faiss/impl/pipnn/Partition.cpp +587 -0
- data/vendor/faiss/faiss/impl/pipnn/Partition.h +93 -0
- data/vendor/faiss/faiss/impl/pipnn/kernels.cpp +326 -0
- data/vendor/faiss/faiss/impl/pipnn/kernels.h +92 -0
- data/vendor/faiss/faiss/impl/platform_macros.h +45 -0
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +79 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +6 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx2.h +4 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx512.h +4 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +19 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.h +6 -6
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +131 -6
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_rvv_kernel.h +89 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +21 -10
- data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +45 -18
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +2 -1
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +5 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +28 -52
- data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +59 -11
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +226 -77
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +482 -103
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +2 -149
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +3 -698
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +66 -57
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +101 -96
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +3185 -144
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_coefficients.h +48 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_rvv_kernel.h +546 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +2 -2
- data/vendor/faiss/faiss/impl/simd_dispatch.h +7 -0
- data/vendor/faiss/faiss/impl/simdlib/simdlib_avx2.h +14 -0
- data/vendor/faiss/faiss/impl/simdlib/simdlib_dispatch.h +7 -8
- data/vendor/faiss/faiss/impl/sq_fastscan_utils.h +232 -0
- data/vendor/faiss/faiss/index_factory.cpp +76 -0
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +3 -2
- data/vendor/faiss/faiss/utils/AlignedTable.h +6 -1
- data/vendor/faiss/faiss/utils/Heap.cpp +4 -3
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +16 -5
- data/vendor/faiss/faiss/utils/bf16.h +36 -0
- data/vendor/faiss/faiss/utils/distances.cpp +226 -15
- data/vendor/faiss/faiss/utils/distances.h +34 -0
- data/vendor/faiss/faiss/utils/distances_dispatch.h +6 -4
- data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +2 -5
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +0 -14
- data/vendor/faiss/faiss/utils/distances_fused/rvv.cpp +25 -0
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +0 -4
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_kernel-inl.h +2 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +9 -0
- data/vendor/faiss/faiss/utils/fp16-fp16c.h +4 -0
- data/vendor/faiss/faiss/utils/fp16-inl.h +26 -52
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +33 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h +15 -30
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-neon.h +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +2 -1
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_rvv.cpp +0 -4
- data/vendor/faiss/faiss/utils/pq_code_distance.h +8 -4
- data/vendor/faiss/faiss/utils/prefetch.h +1 -26
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +26 -27
- data/vendor/faiss/faiss/utils/quantize_lut.h +11 -0
- data/vendor/faiss/faiss/utils/rabitq_simd.h +51 -16
- data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +9 -4
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +37 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +64 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +64 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +353 -71
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv_kernel.h +68 -0
- data/vendor/faiss/faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h +93 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels.h +76 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx2.cpp +52 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx512.cpp +52 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_neon.cpp +48 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx2.h +44 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx512.h +43 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum.h +38 -0
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +54 -15
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +38 -21
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_vpopcnt.cpp +51 -14
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +297 -10
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx512.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_levels.cpp +19 -3
- data/vendor/faiss/faiss/utils/simd_levels.h +74 -1
- data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +0 -4
- data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +0 -4
- data/vendor/faiss/faiss/utils/utils.cpp +80 -0
- data/vendor/faiss/faiss/utils/utils.h +24 -0
- metadata +33 -1
|
@@ -83,5 +83,97 @@ bool runMetalIVFFlatFullSearch(
|
|
|
83
83
|
bool centroidsAreFP16 = false,
|
|
84
84
|
bool waitForCompletion = true);
|
|
85
85
|
|
|
86
|
+
/// Full IVF-PQ search on the GPU: builds per-(query, probe) PQ lookup tables,
|
|
87
|
+
/// scans the assigned inverted lists with 8-bit ADC, and merges the per-list
|
|
88
|
+
/// top-k into the final top-k. Coarse quantization is performed on the CPU and
|
|
89
|
+
/// the assignments are passed in via @p coarseAssign. @p coarseDist carries
|
|
90
|
+
/// the per-(query, probe) coarse scores, added for inner product (the IP
|
|
91
|
+
/// tables hold <q_m, pq_m> only); unused for L2.
|
|
92
|
+
bool runMetalIVFPQFullSearch(
|
|
93
|
+
id<MTLDevice> device,
|
|
94
|
+
id<MTLCommandQueue> queue,
|
|
95
|
+
id<MTLBuffer> queries,
|
|
96
|
+
id<MTLBuffer> coarseAssign,
|
|
97
|
+
id<MTLBuffer> coarseDist,
|
|
98
|
+
id<MTLBuffer> coarseCentroids,
|
|
99
|
+
id<MTLBuffer> pqCentroids,
|
|
100
|
+
id<MTLBuffer> lookupTable,
|
|
101
|
+
id<MTLBuffer> codes,
|
|
102
|
+
id<MTLBuffer> ids,
|
|
103
|
+
id<MTLBuffer> listOffset,
|
|
104
|
+
id<MTLBuffer> listLength,
|
|
105
|
+
int nq,
|
|
106
|
+
int d,
|
|
107
|
+
int M,
|
|
108
|
+
int k,
|
|
109
|
+
int nprobe,
|
|
110
|
+
int nlist,
|
|
111
|
+
int avgListLen,
|
|
112
|
+
bool lookupFp16,
|
|
113
|
+
bool isL2,
|
|
114
|
+
id<MTLBuffer> outDistances,
|
|
115
|
+
id<MTLBuffer> outIndices,
|
|
116
|
+
id<MTLBuffer> perListDistBuf,
|
|
117
|
+
id<MTLBuffer> perListIdxBuf,
|
|
118
|
+
bool waitForCompletion = true);
|
|
119
|
+
|
|
120
|
+
/// Build the query-independent precomputed term of the IVFPQ L2 distance
|
|
121
|
+
/// decomposition on the GPU: term2[l][m][c] = ||pq[m][c]||^2 +
|
|
122
|
+
/// 2 <coarse_l[m], pq[m][c]>, laid out as nlist * M * 256 floats. Run once
|
|
123
|
+
/// per trained index; consumed by runMetalIVFPQPrecompSearch.
|
|
124
|
+
bool runMetalIVFPQPrecomputeTerm2(
|
|
125
|
+
id<MTLDevice> device,
|
|
126
|
+
id<MTLCommandQueue> queue,
|
|
127
|
+
id<MTLBuffer> coarseCentroids,
|
|
128
|
+
id<MTLBuffer> pqCentroids,
|
|
129
|
+
id<MTLBuffer> outTerm2,
|
|
130
|
+
int nlist,
|
|
131
|
+
int d,
|
|
132
|
+
int M);
|
|
133
|
+
|
|
134
|
+
/// IVF-PQ search using the precomputed-table decomposition: a per-query
|
|
135
|
+
/// M*256 term is built once per batch (instead of a full residual LUT per
|
|
136
|
+
/// (query, probe)), combined with @p term2 in threadgroup memory by the scan
|
|
137
|
+
/// kernel, and the coarse distance is added as the constant ||x - c||^2 term.
|
|
138
|
+
/// The scan keeps an exact running top-k over arbitrarily long lists and the
|
|
139
|
+
/// merge runs in rounds, so there is no list-length or nprobe*k cap; the
|
|
140
|
+
/// remaining requirements are k <= 512, M <= 64 and d/M <= 256.
|
|
141
|
+
/// onTheFly evaluates encountered codes directly (d <= 256), using the
|
|
142
|
+
/// supplied coarse centroids; shortLists requires every list to have <= 128
|
|
143
|
+
/// entries and selects a smaller threadgroup and scratch allocation.
|
|
144
|
+
/// @p term2 may be nil for inner product (qterm is the whole table);
|
|
145
|
+
/// @p useDis0 adds the coarse distance (required for L2, by_residual for IP).
|
|
146
|
+
bool runMetalIVFPQPrecompSearch(
|
|
147
|
+
id<MTLDevice> device,
|
|
148
|
+
id<MTLCommandQueue> queue,
|
|
149
|
+
id<MTLBuffer> queries,
|
|
150
|
+
id<MTLBuffer> coarseAssign,
|
|
151
|
+
id<MTLBuffer> coarseDist,
|
|
152
|
+
id<MTLBuffer> term2,
|
|
153
|
+
id<MTLBuffer> qtermScratch,
|
|
154
|
+
id<MTLBuffer> pqCentroids,
|
|
155
|
+
id<MTLBuffer> codes,
|
|
156
|
+
id<MTLBuffer> ids,
|
|
157
|
+
id<MTLBuffer> listOffset,
|
|
158
|
+
id<MTLBuffer> listLength,
|
|
159
|
+
int nq,
|
|
160
|
+
int d,
|
|
161
|
+
int M,
|
|
162
|
+
int k,
|
|
163
|
+
int nprobe,
|
|
164
|
+
bool isL2,
|
|
165
|
+
bool useDis0,
|
|
166
|
+
id<MTLBuffer> outDistances,
|
|
167
|
+
id<MTLBuffer> outIndices,
|
|
168
|
+
id<MTLBuffer> perListDistBuf,
|
|
169
|
+
id<MTLBuffer> perListIdxBuf,
|
|
170
|
+
id<MTLBuffer> mergeScratchDistBuf,
|
|
171
|
+
id<MTLBuffer> mergeScratchIdxBuf,
|
|
172
|
+
bool waitForCompletion = true,
|
|
173
|
+
id<MTLBuffer> coarseCentroids = nil,
|
|
174
|
+
bool onTheFly = false,
|
|
175
|
+
bool shortLists = false,
|
|
176
|
+
bool compactMerge = true);
|
|
177
|
+
|
|
86
178
|
} // namespace gpu_metal
|
|
87
179
|
} // namespace faiss
|
|
@@ -24,6 +24,10 @@ struct MetalIndexConfig {
|
|
|
24
24
|
|
|
25
25
|
bool useFloat16CoarseQuantizer = false;
|
|
26
26
|
|
|
27
|
+
/// Build the IVF-PQ distance lookup tables in half precision. Halves LUT
|
|
28
|
+
/// bandwidth during the GPU scan at a small accuracy cost.
|
|
29
|
+
bool useFloat16 = false;
|
|
30
|
+
|
|
27
31
|
faiss::gpu::IndicesOptions indicesOptions = faiss::gpu::INDICES_64_BIT;
|
|
28
32
|
|
|
29
33
|
bool interleavedLayout = true;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// @lint-ignore-every LICENSELINT
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
|
|
11
|
+
#include <faiss/IndexBinaryFlat.h>
|
|
12
|
+
#include <faiss/gpu_metal/MetalResources.h>
|
|
13
|
+
#include <memory>
|
|
14
|
+
|
|
15
|
+
namespace faiss {
|
|
16
|
+
namespace gpu_metal {
|
|
17
|
+
|
|
18
|
+
/// Exhaustive Hamming search over GPU-resident binary vectors.
|
|
19
|
+
/// Every positive dimension divisible by 8 is supported. GPU search is exact
|
|
20
|
+
/// for k <= 512, with ties ordered by increasing label. Larger k, selectors,
|
|
21
|
+
/// and counts exceeding uint32_t use the CPU copy. GPU failures throw rather
|
|
22
|
+
/// than silently falling back. Range search and remove_ids are not supported.
|
|
23
|
+
/// As with other Metal indexes, callers must serialize mutation and search.
|
|
24
|
+
class MetalIndexBinaryFlat : public faiss::IndexBinary {
|
|
25
|
+
public:
|
|
26
|
+
static constexpr int kMaxGpuK = 512;
|
|
27
|
+
|
|
28
|
+
MetalIndexBinaryFlat(std::shared_ptr<MetalResources> resources, int d);
|
|
29
|
+
MetalIndexBinaryFlat(
|
|
30
|
+
std::shared_ptr<MetalResources> resources,
|
|
31
|
+
const faiss::IndexBinaryFlat* index);
|
|
32
|
+
~MetalIndexBinaryFlat() override;
|
|
33
|
+
|
|
34
|
+
MetalIndexBinaryFlat(const MetalIndexBinaryFlat&) = delete;
|
|
35
|
+
MetalIndexBinaryFlat& operator=(const MetalIndexBinaryFlat&) = delete;
|
|
36
|
+
|
|
37
|
+
void add(idx_t n, const uint8_t* x) override;
|
|
38
|
+
void reset() override;
|
|
39
|
+
void search(
|
|
40
|
+
idx_t n,
|
|
41
|
+
const uint8_t* x,
|
|
42
|
+
idx_t k,
|
|
43
|
+
int32_t* distances,
|
|
44
|
+
idx_t* labels,
|
|
45
|
+
const SearchParameters* params = nullptr) const override;
|
|
46
|
+
void reconstruct(idx_t key, uint8_t* recons) const override;
|
|
47
|
+
|
|
48
|
+
void copyFrom(const faiss::IndexBinaryFlat* index);
|
|
49
|
+
void copyTo(faiss::IndexBinaryFlat* index) const;
|
|
50
|
+
|
|
51
|
+
std::shared_ptr<MetalResources> getResources() const {
|
|
52
|
+
return resources_;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private:
|
|
56
|
+
std::shared_ptr<MetalResources> resources_;
|
|
57
|
+
faiss::IndexBinaryFlat cpuIndex_;
|
|
58
|
+
id<MTLBuffer> vectorsBuf_ = nil;
|
|
59
|
+
// Search is synchronous and callers serialize access, so scratch buffers
|
|
60
|
+
// can be reused after waitUntilCompleted. ARC releases them on destruction.
|
|
61
|
+
mutable id<MTLBuffer> queryBuf_ = nil;
|
|
62
|
+
mutable id<MTLBuffer> distanceBuf_ = nil;
|
|
63
|
+
mutable id<MTLBuffer> labelBuf_ = nil;
|
|
64
|
+
|
|
65
|
+
id<MTLBuffer> upload(const uint8_t* data, size_t bytes) const;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
} // namespace gpu_metal
|
|
69
|
+
} // namespace faiss
|
|
@@ -75,13 +75,51 @@ class MetalIndexIVFPQ : public MetalIndex {
|
|
|
75
75
|
std::unique_ptr<faiss::IndexIVFPQ> cpuIndex_;
|
|
76
76
|
std::unique_ptr<MetalIVFPQImpl> gpuIvf_;
|
|
77
77
|
|
|
78
|
+
// Reusable GPU scratch buffers for the search path, grown on demand.
|
|
79
|
+
mutable id<MTLBuffer> searchQueriesBuf_ = nil;
|
|
80
|
+
mutable id<MTLBuffer> searchCoarseBuf_ = nil;
|
|
81
|
+
mutable id<MTLBuffer> searchOutDistBuf_ = nil;
|
|
82
|
+
mutable id<MTLBuffer> searchOutIdxBuf_ = nil;
|
|
83
|
+
mutable id<MTLBuffer> searchPerListDistBuf_ = nil;
|
|
84
|
+
mutable id<MTLBuffer> searchPerListIdxBuf_ = nil;
|
|
85
|
+
mutable id<MTLBuffer> lookupTableBuf_ = nil;
|
|
86
|
+
mutable id<MTLBuffer> lookupTableHalfBuf_ = nil;
|
|
87
|
+
mutable id<MTLBuffer> searchCoarseDistBuf_ = nil;
|
|
88
|
+
mutable id<MTLBuffer> searchQTermBuf_ = nil;
|
|
89
|
+
mutable id<MTLBuffer> searchMergeDistBuf_ = nil;
|
|
90
|
+
mutable id<MTLBuffer> searchMergeIdxBuf_ = nil;
|
|
91
|
+
mutable size_t searchQueriesCap_ = 0;
|
|
92
|
+
mutable size_t searchCoarseCap_ = 0;
|
|
93
|
+
mutable size_t searchOutDistCap_ = 0;
|
|
94
|
+
mutable size_t searchOutIdxCap_ = 0;
|
|
95
|
+
mutable size_t searchPerListDistCap_ = 0;
|
|
96
|
+
mutable size_t searchPerListIdxCap_ = 0;
|
|
97
|
+
mutable size_t lookupTableCap_ = 0;
|
|
98
|
+
mutable size_t lookupTableHalfCap_ = 0;
|
|
99
|
+
mutable size_t searchCoarseDistCap_ = 0;
|
|
100
|
+
mutable size_t searchQTermCap_ = 0;
|
|
101
|
+
mutable size_t searchMergeDistCap_ = 0;
|
|
102
|
+
mutable size_t searchMergeIdxCap_ = 0;
|
|
103
|
+
|
|
104
|
+
// Coarse centroids mirrored on the GPU for the L2 lookup-table build.
|
|
105
|
+
mutable id<MTLBuffer> centroidBuf_ = nil;
|
|
106
|
+
|
|
107
|
+
// Query-independent term of the L2 precomputed-table decomposition
|
|
108
|
+
// (nlist * M * 256 floats), built once per trained index on the GPU.
|
|
109
|
+
mutable id<MTLBuffer> term2Buf_ = nil;
|
|
110
|
+
|
|
78
111
|
void verifyPQSettings_() const;
|
|
112
|
+
void precomputeTerm2_() const;
|
|
79
113
|
|
|
80
114
|
void encodeResidualAndAppend_(
|
|
81
115
|
idx_t n,
|
|
82
116
|
const float* x,
|
|
83
117
|
const idx_t* list_nos,
|
|
84
118
|
const idx_t* xids);
|
|
119
|
+
|
|
120
|
+
void ensureSearchBuf_(id<MTLBuffer>& buf, size_t& cap, size_t needed) const;
|
|
121
|
+
void uploadCentroids_() const;
|
|
122
|
+
void uploadPQCentroids_() const;
|
|
85
123
|
};
|
|
86
124
|
|
|
87
125
|
} // namespace gpu_metal
|
|
@@ -91,6 +91,112 @@ class MetalKernels {
|
|
|
91
91
|
id<MTLBuffer> paramsBuf,
|
|
92
92
|
int nq);
|
|
93
93
|
|
|
94
|
+
// ---- IVF-PQ ----
|
|
95
|
+
|
|
96
|
+
void encodeIVFPQBuildLookupTables(
|
|
97
|
+
id<MTLComputeCommandEncoder> enc,
|
|
98
|
+
bool isL2,
|
|
99
|
+
bool outFp16,
|
|
100
|
+
id<MTLBuffer> queries,
|
|
101
|
+
id<MTLBuffer> coarseAssign,
|
|
102
|
+
id<MTLBuffer> coarseCentroids,
|
|
103
|
+
id<MTLBuffer> pqCentroids,
|
|
104
|
+
id<MTLBuffer> outLookup,
|
|
105
|
+
int nq,
|
|
106
|
+
int d,
|
|
107
|
+
int M,
|
|
108
|
+
int nprobe);
|
|
109
|
+
|
|
110
|
+
void encodeIVFPQScanList(
|
|
111
|
+
id<MTLComputeCommandEncoder> enc,
|
|
112
|
+
bool useSmall,
|
|
113
|
+
bool useFp16Lookup,
|
|
114
|
+
id<MTLBuffer> lookupTable,
|
|
115
|
+
id<MTLBuffer> codes,
|
|
116
|
+
id<MTLBuffer> ids,
|
|
117
|
+
id<MTLBuffer> listOffset,
|
|
118
|
+
id<MTLBuffer> listLength,
|
|
119
|
+
id<MTLBuffer> coarseAssign,
|
|
120
|
+
id<MTLBuffer> perListDist,
|
|
121
|
+
id<MTLBuffer> perListIdx,
|
|
122
|
+
id<MTLBuffer> paramsBuf,
|
|
123
|
+
id<MTLBuffer> coarseDist,
|
|
124
|
+
int nq,
|
|
125
|
+
int nprobe);
|
|
126
|
+
|
|
127
|
+
// ---- IVF-PQ precomputed-table path ----
|
|
128
|
+
|
|
129
|
+
void encodeIVFPQPrecomputeTerm2(
|
|
130
|
+
id<MTLComputeCommandEncoder> enc,
|
|
131
|
+
id<MTLBuffer> coarseCentroids,
|
|
132
|
+
id<MTLBuffer> pqCentroids,
|
|
133
|
+
id<MTLBuffer> outTerm2,
|
|
134
|
+
int nlist,
|
|
135
|
+
int d,
|
|
136
|
+
int M);
|
|
137
|
+
|
|
138
|
+
void encodeIVFPQBuildQueryTerm(
|
|
139
|
+
id<MTLComputeCommandEncoder> enc,
|
|
140
|
+
id<MTLBuffer> queries,
|
|
141
|
+
id<MTLBuffer> pqCentroids,
|
|
142
|
+
id<MTLBuffer> outQTerm,
|
|
143
|
+
int nq,
|
|
144
|
+
int d,
|
|
145
|
+
int M,
|
|
146
|
+
bool isL2);
|
|
147
|
+
|
|
148
|
+
void encodeIVFPQScanListPrecomp(
|
|
149
|
+
id<MTLComputeCommandEncoder> enc,
|
|
150
|
+
id<MTLBuffer> term2, // nil when useTerm2 is false (IP path)
|
|
151
|
+
id<MTLBuffer> qterm,
|
|
152
|
+
id<MTLBuffer> coarseDist,
|
|
153
|
+
id<MTLBuffer> codes,
|
|
154
|
+
id<MTLBuffer> ids,
|
|
155
|
+
id<MTLBuffer> listOffset,
|
|
156
|
+
id<MTLBuffer> listLength,
|
|
157
|
+
id<MTLBuffer> coarseAssign,
|
|
158
|
+
id<MTLBuffer> perListDist,
|
|
159
|
+
id<MTLBuffer> perListIdx,
|
|
160
|
+
int nq,
|
|
161
|
+
int M,
|
|
162
|
+
int k,
|
|
163
|
+
int nprobe,
|
|
164
|
+
bool wantMin,
|
|
165
|
+
bool useTerm2,
|
|
166
|
+
bool useDis0,
|
|
167
|
+
id<MTLBuffer> queries,
|
|
168
|
+
id<MTLBuffer> coarseCentroids,
|
|
169
|
+
id<MTLBuffer> pqCentroids,
|
|
170
|
+
int d,
|
|
171
|
+
bool onTheFly,
|
|
172
|
+
bool shortLists);
|
|
173
|
+
|
|
174
|
+
void encodeIVFMergeListsGrouped(
|
|
175
|
+
id<MTLComputeCommandEncoder> enc,
|
|
176
|
+
id<MTLBuffer> inDist,
|
|
177
|
+
id<MTLBuffer> inIdx,
|
|
178
|
+
id<MTLBuffer> outDist,
|
|
179
|
+
id<MTLBuffer> outIdx,
|
|
180
|
+
int nq,
|
|
181
|
+
int numLists,
|
|
182
|
+
int groupSize,
|
|
183
|
+
int k,
|
|
184
|
+
bool wantMin,
|
|
185
|
+
bool compact);
|
|
186
|
+
|
|
187
|
+
// Exact Hamming top-k from the precompiled MetalDistance.metallib.
|
|
188
|
+
// Requires positive uint32-sized counts and 1 <= k <= 512.
|
|
189
|
+
void encodeHammingDistanceTopK(
|
|
190
|
+
id<MTLComputeCommandEncoder> enc,
|
|
191
|
+
id<MTLBuffer> queries,
|
|
192
|
+
id<MTLBuffer> database,
|
|
193
|
+
id<MTLBuffer> outDist,
|
|
194
|
+
id<MTLBuffer> outIdx,
|
|
195
|
+
uint32_t nq,
|
|
196
|
+
uint32_t nb,
|
|
197
|
+
uint32_t codeSize,
|
|
198
|
+
uint32_t k);
|
|
199
|
+
|
|
94
200
|
static int selectTopKVariantIndex(int k);
|
|
95
201
|
|
|
96
202
|
private:
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#pragma once
|
|
13
13
|
|
|
14
14
|
#include <faiss/Index.h>
|
|
15
|
+
#include <faiss/IndexBinary.h>
|
|
15
16
|
|
|
16
17
|
namespace faiss {
|
|
17
18
|
namespace gpu_metal {
|
|
@@ -41,5 +42,14 @@ faiss::Index* index_cpu_to_gpu(
|
|
|
41
42
|
/// Copy Metal index back to CPU. Caller owns returned index.
|
|
42
43
|
faiss::Index* index_gpu_to_cpu(const faiss::Index* index);
|
|
43
44
|
|
|
45
|
+
/// Clone CPU IndexBinaryFlat to Metal. Caller owns the returned index.
|
|
46
|
+
faiss::IndexBinary* index_binary_cpu_to_gpu(
|
|
47
|
+
StandardMetalResourcesHolder* res,
|
|
48
|
+
int device,
|
|
49
|
+
const faiss::IndexBinary* index);
|
|
50
|
+
|
|
51
|
+
/// Clone MetalIndexBinaryFlat back to CPU. Caller owns the returned index.
|
|
52
|
+
faiss::IndexBinary* index_binary_gpu_to_cpu(const faiss::IndexBinary* index);
|
|
53
|
+
|
|
44
54
|
} // namespace gpu_metal
|
|
45
55
|
} // namespace faiss
|
|
@@ -146,12 +146,7 @@ struct FAISS_API InterruptCallback {
|
|
|
146
146
|
|
|
147
147
|
static void clear_instance();
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
* - an interrupt callback is set
|
|
151
|
-
* - the callback returns true
|
|
152
|
-
* if this is the case, then throw an exception. Should not be called
|
|
153
|
-
* from multiple threads.
|
|
154
|
-
*/
|
|
149
|
+
/// Concurrent calls require a thread-safe want_interrupt().
|
|
155
150
|
static void check();
|
|
156
151
|
|
|
157
152
|
/// same as check() but return true if is interrupted instead of
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
#include <faiss/impl/ClusteringHelpers.h>
|
|
9
9
|
|
|
10
|
+
#include <algorithm>
|
|
11
|
+
#include <atomic>
|
|
10
12
|
#include <cassert>
|
|
11
13
|
#include <chrono>
|
|
12
14
|
#include <cinttypes>
|
|
@@ -20,11 +22,88 @@
|
|
|
20
22
|
|
|
21
23
|
#include <faiss/Index.h>
|
|
22
24
|
#include <faiss/impl/FaissAssert.h>
|
|
25
|
+
#include <faiss/impl/simd_dispatch.h>
|
|
23
26
|
#include <faiss/utils/random.h>
|
|
27
|
+
#include <faiss/utils/simd_impl/fp16_kernels.h>
|
|
24
28
|
|
|
25
29
|
namespace faiss {
|
|
26
30
|
namespace detail {
|
|
27
31
|
|
|
32
|
+
namespace {
|
|
33
|
+
|
|
34
|
+
#if defined(_OPENMP) && !defined(FAISS_USE_OMP_MOCK)
|
|
35
|
+
/// Below this many values, the fp16 finiteness check stays on one thread.
|
|
36
|
+
constexpr size_t fp16_parallel_threshold = size_t(1) << 16;
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
/** Shared body of compute_centroids and compute_centroids_fp16.
|
|
40
|
+
*
|
|
41
|
+
* `add_row(i, w, c, scratch)` adds training vector i to the fp32 vector c,
|
|
42
|
+
* scaled by *w when w is not null. `scratch` is a per-thread buffer of d
|
|
43
|
+
* floats.
|
|
44
|
+
*/
|
|
45
|
+
template <class AddRow>
|
|
46
|
+
void compute_centroids_impl(
|
|
47
|
+
size_t d,
|
|
48
|
+
size_t k,
|
|
49
|
+
size_t n,
|
|
50
|
+
size_t k_frozen,
|
|
51
|
+
const int64_t* assign,
|
|
52
|
+
const float* weights,
|
|
53
|
+
float* hassign,
|
|
54
|
+
float* centroids,
|
|
55
|
+
const AddRow& add_row) {
|
|
56
|
+
k -= k_frozen;
|
|
57
|
+
centroids += k_frozen * d;
|
|
58
|
+
|
|
59
|
+
memset(centroids, 0, sizeof(*centroids) * d * k);
|
|
60
|
+
|
|
61
|
+
std::atomic<bool> invalid_assignment{false};
|
|
62
|
+
const int64_t num_centroids = static_cast<int64_t>(k + k_frozen);
|
|
63
|
+
#pragma omp parallel
|
|
64
|
+
{
|
|
65
|
+
int nt = omp_get_num_threads();
|
|
66
|
+
int rank = omp_get_thread_num();
|
|
67
|
+
|
|
68
|
+
// this thread is taking care of centroids c0:c1
|
|
69
|
+
size_t c0 = (k * rank) / nt;
|
|
70
|
+
size_t c1 = (k * (rank + 1)) / nt;
|
|
71
|
+
std::vector<float> scratch(d);
|
|
72
|
+
|
|
73
|
+
for (size_t i = 0; i < n; i++) {
|
|
74
|
+
int64_t ci = assign[i];
|
|
75
|
+
if (ci < 0 || ci >= num_centroids) {
|
|
76
|
+
invalid_assignment.store(true, std::memory_order_relaxed);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
ci -= k_frozen;
|
|
80
|
+
if (ci >= static_cast<int64_t>(c0) &&
|
|
81
|
+
ci < static_cast<int64_t>(c1)) {
|
|
82
|
+
const float* w = weights ? weights + i : nullptr;
|
|
83
|
+
hassign[ci] += w ? *w : 1.0f;
|
|
84
|
+
add_row(i, w, centroids + ci * d, scratch.data());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
FAISS_THROW_IF_MSG(
|
|
89
|
+
invalid_assignment.load(std::memory_order_relaxed),
|
|
90
|
+
"invalid cluster assignment");
|
|
91
|
+
|
|
92
|
+
#pragma omp parallel for
|
|
93
|
+
for (idx_t ci = 0; ci < static_cast<idx_t>(k); ci++) {
|
|
94
|
+
if (hassign[ci] == 0) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
float norm = 1 / hassign[ci];
|
|
98
|
+
float* c = centroids + ci * d;
|
|
99
|
+
for (size_t j = 0; j < d; j++) {
|
|
100
|
+
c[j] *= norm;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
} // namespace
|
|
106
|
+
|
|
28
107
|
uint64_t get_actual_rng_seed(const int seed) {
|
|
29
108
|
return (seed >= 0)
|
|
30
109
|
? seed
|
|
@@ -109,66 +188,76 @@ void compute_centroids(
|
|
|
109
188
|
const float* weights,
|
|
110
189
|
float* hassign,
|
|
111
190
|
float* centroids) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// this thread is taking care of centroids c0:c1
|
|
125
|
-
size_t c0 = (k * rank) / nt;
|
|
126
|
-
size_t c1 = (k * (rank + 1)) / nt;
|
|
127
|
-
std::vector<float> decode_buffer(d);
|
|
128
|
-
|
|
129
|
-
for (size_t i = 0; i < n; i++) {
|
|
130
|
-
int64_t ci = assign[i];
|
|
131
|
-
FAISS_THROW_IF_NOT_MSG(
|
|
132
|
-
ci >= 0 && ci < k + k_frozen, "invalid cluster assignment");
|
|
133
|
-
ci -= k_frozen;
|
|
134
|
-
if (ci >= static_cast<int64_t>(c0) &&
|
|
135
|
-
ci < static_cast<int64_t>(c1)) {
|
|
136
|
-
float* c = centroids + ci * d;
|
|
191
|
+
const size_t line_size = codec ? codec->sa_code_size() : d * sizeof(float);
|
|
192
|
+
compute_centroids_impl(
|
|
193
|
+
d,
|
|
194
|
+
k,
|
|
195
|
+
n,
|
|
196
|
+
k_frozen,
|
|
197
|
+
assign,
|
|
198
|
+
weights,
|
|
199
|
+
hassign,
|
|
200
|
+
centroids,
|
|
201
|
+
[&](size_t i, const float* w, float* c, float* scratch) {
|
|
137
202
|
const float* xi;
|
|
138
203
|
if (!codec) {
|
|
139
204
|
xi = reinterpret_cast<const float*>(x + i * line_size);
|
|
140
205
|
} else {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
xi = xif;
|
|
206
|
+
codec->sa_decode(1, x + i * line_size, scratch);
|
|
207
|
+
xi = scratch;
|
|
144
208
|
}
|
|
145
|
-
if (
|
|
146
|
-
float
|
|
147
|
-
hassign[ci] += w;
|
|
209
|
+
if (w) {
|
|
210
|
+
const float wi = *w;
|
|
148
211
|
for (size_t j = 0; j < d; j++) {
|
|
149
|
-
c[j] += xi[j] *
|
|
212
|
+
c[j] += xi[j] * wi;
|
|
150
213
|
}
|
|
151
214
|
} else {
|
|
152
|
-
hassign[ci] += 1.0;
|
|
153
215
|
for (size_t j = 0; j < d; j++) {
|
|
154
216
|
c[j] += xi[j];
|
|
155
217
|
}
|
|
156
218
|
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
160
221
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
222
|
+
void compute_centroids_fp16(
|
|
223
|
+
size_t d,
|
|
224
|
+
size_t k,
|
|
225
|
+
size_t n,
|
|
226
|
+
size_t k_frozen,
|
|
227
|
+
const uint16_t* x,
|
|
228
|
+
const int64_t* assign,
|
|
229
|
+
const float* weights,
|
|
230
|
+
float* hassign,
|
|
231
|
+
float* centroids) {
|
|
232
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE>([&]<SIMDLevel SL>() {
|
|
233
|
+
compute_centroids_impl(
|
|
234
|
+
d,
|
|
235
|
+
k,
|
|
236
|
+
n,
|
|
237
|
+
k_frozen,
|
|
238
|
+
assign,
|
|
239
|
+
weights,
|
|
240
|
+
hassign,
|
|
241
|
+
centroids,
|
|
242
|
+
[&](size_t i, const float* w, float* c, float* /*scratch*/) {
|
|
243
|
+
// x * 1.0f is exact, so unweighted sums match the
|
|
244
|
+
// fp32 path.
|
|
245
|
+
fp16_madd<SL>(d, x + i * d, w ? *w : 1.0f, c);
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
bool fp16_all_finite(size_t n, const uint16_t* x) {
|
|
251
|
+
// binary16 NaNs and infinities are the values with all exponent bits set
|
|
252
|
+
constexpr uint16_t exponent_mask = 0x7c00;
|
|
253
|
+
std::atomic<bool> all_finite{true};
|
|
254
|
+
#pragma omp parallel for if (n > fp16_parallel_threshold)
|
|
255
|
+
for (int64_t i = 0; i < static_cast<int64_t>(n); i++) {
|
|
256
|
+
if ((x[i] & exponent_mask) == exponent_mask) {
|
|
257
|
+
all_finite.store(false, std::memory_order_relaxed);
|
|
170
258
|
}
|
|
171
259
|
}
|
|
260
|
+
return all_finite.load(std::memory_order_relaxed);
|
|
172
261
|
}
|
|
173
262
|
|
|
174
263
|
// a bit above machine epsilon for float16
|
|
@@ -51,6 +51,15 @@ idx_t subsample_training_set(
|
|
|
51
51
|
uint8_t** x_out,
|
|
52
52
|
float** weights_out);
|
|
53
53
|
|
|
54
|
+
/** Initialize non-random centroids directly from packed IEEE binary16 rows. */
|
|
55
|
+
void init_centroids_fp16(
|
|
56
|
+
const ClusteringInitialization& initializer,
|
|
57
|
+
size_t n,
|
|
58
|
+
const uint16_t* x,
|
|
59
|
+
float* centroids,
|
|
60
|
+
size_t n_existing_centroids = 0,
|
|
61
|
+
const float* existing_centroids = nullptr);
|
|
62
|
+
|
|
54
63
|
/** compute centroids as (weighted) sum of training points
|
|
55
64
|
*
|
|
56
65
|
* @param x training vectors, size n * code_size (from codec)
|
|
@@ -75,6 +84,33 @@ void compute_centroids(
|
|
|
75
84
|
float* hassign,
|
|
76
85
|
float* centroids);
|
|
77
86
|
|
|
87
|
+
/** Same as compute_centroids for training vectors stored as packed IEEE
|
|
88
|
+
* binary16 values.
|
|
89
|
+
*
|
|
90
|
+
* Rows are widened in registers and accumulated directly into the fp32
|
|
91
|
+
* centroids: there is no per-row decode call and no decode buffer.
|
|
92
|
+
*
|
|
93
|
+
* @param x training vectors, size n * d
|
|
94
|
+
*/
|
|
95
|
+
void compute_centroids_fp16(
|
|
96
|
+
size_t d,
|
|
97
|
+
size_t k,
|
|
98
|
+
size_t n,
|
|
99
|
+
size_t k_frozen,
|
|
100
|
+
const uint16_t* x,
|
|
101
|
+
const int64_t* assign,
|
|
102
|
+
const float* weights,
|
|
103
|
+
float* hassign,
|
|
104
|
+
float* centroids);
|
|
105
|
+
|
|
106
|
+
/** Check packed IEEE binary16 values for NaNs and infinities.
|
|
107
|
+
*
|
|
108
|
+
* The check runs on the bit patterns, without widening to fp32.
|
|
109
|
+
*
|
|
110
|
+
* @return true iff none of the `n` values is a NaN or an infinity
|
|
111
|
+
*/
|
|
112
|
+
bool fp16_all_finite(size_t n, const uint16_t* x);
|
|
113
|
+
|
|
78
114
|
/** Handle empty clusters by splitting larger ones.
|
|
79
115
|
*
|
|
80
116
|
* It works by slightly changing the centroids to make 2 clusters from
|