Repository navigation
Releases
Releases · mikepapadim/mlxvs
mlxVS 0.12.0
mlxVS 0.12.0: CAGRA-Q, the graph search over VPQ codes.
pip install -U mlxvs- CAGRA-Q:
CagraIndex.compress()(C++vpq_build,graph_search_vpq) replaces the stored rows by cuVS's VPQ
codes: each row's nearest coarse center (sqrt(n)of them) plusceil(d / 4)codes of its residual in one
shared 256-entry codebook. The graph search computes distances from the codes (both single- and multi-CTA, filters
included);search(..., refine_ratio=4, dataset=rows)re-ranks exactly, from rows on the GPU or in a NumPy array
ornumpy.memmap. SIFT1M: 36 MB instead of 505 MB, compressed in 6.3 s; 234,000 queries/s from the codes alone
(recall@10 0.716), recall@10 0.981 at 103,000 queries/s refined (itopk_size128). search_kernels.h: the VPQ kernels are the same sources with the distance function swapped.
mlxVS 0.11.0
mlxVS 0.11.0: IvfPqIndex and refine.
pip install -U mlxvsIvfPqIndex(C++ivf_pq_build,ivf_pq_search,ivf_pq_extend), as cuVS's IVF-PQ: k-means lists, rows
stored aspq_dimcodes ofpq_bits(4 to 8) of their residual to the center, per-subspace codebooks, cuVS's
pq_dimheuristic (zero columns pad the dimension to a multiple ofpq_dim). Searches build a float32 lookup
table per (query, list) in chunks of subspaces and sum it over each row's codes. SIFT1M: 63 MB of codes for
505 MB of rows, built in 21.7 s; withrefine_ratio=4recall@10 0.954 at 18,300 queries/s (n_probes20) and
0.993 at 8,100 (50), as IVF-Flat's.refine(C++ and Python), as cuVS's: exact re-ranking of candidate ids. From Python the rows may be a NumPy
array ornumpy.memmap: only the candidates' rows are read, on the host.
mlxVS 0.10.0
mlxVS 0.10.0: CagraIndex.extend and IvfFlatIndex.
pip install -U mlxvsCagraIndex.extend(C++cagra_extend), as cuVS'scagra::extend: each new row's2 * degreenearest rows
come from a graph search and are pruned todegreeby rank-based detour counts; each of its firstdegree / 2
neighbors gives it the second-half slot of its neighbor with the most incoming edges; its list interleaves its
own neighbors with those displaced. 18,000 rows extended by 2,000 search as well as an index built on all
20,000 (recall@10 0.9994 against 0.9998).IvfFlatIndex(C++ivf_flat_build,ivf_flat_search,ivf_flat_extend), as cuVS's IVF-Flat: k-means lists,
then_probeslists of nearest center scanned exactly. The scan groups (query, list) pairs by list, so each
threadgroup reads a list's rows once for up to 16 queries. SIFT1M, 1024 lists, built in 9.5 s: recall@10 0.954
at 35,700 queries/s (n_probes20), 0.993 at 17,300 (50).saveandloadas one.safetensorsfile.
mlxVS 0.9.1
mlxVS 0.9.1: deterministic ties in brute_force_knn.
pip install -U mlxvsbrute_force_knn(and every exact k-NN built on it): when more candidates tie with the k-th score than are
kept, the ones of lowest id are kept. Before, the threads that arrived first decided, so ties (frequent with
float32 distances of data far from the origin) could give different neighbors from run to run. scikit-learn's
check_fit_idempotentcaught it through the sklearn-ann transformer.
mlxVS 0.9.0
mlxVS 0.9.0: a filter per query, and byte datasets in the C API.
pip install -U mlxvs- A filter per query, as cuVS's bitmap filter:
filter=also takes bool[nq, n]oruint32 [nq, ceil(n / 32)];
C APImlxvs_index_search_bitmap. - C API byte datasets:
mlxvs_index_build_typedwithMLXVS_INT8orMLXVS_UINT8rows, stored as they are. - The C API's search functions share one implementation.
mlxVS 0.8.0
mlxVS 0.8.0: hnswlib and JVector export from C++, C and Java.
pip install -U mlxvssave_hnswlibandsave_jvectorin C++ (include/mlxvs/mlxvs.h) and the C API (mlxvs_index_save_hnswlib,
mlxvs_index_save_jvector);CagraIndex.save_hnswlibandsave_jvectorcall them and write the same bytes as
before. From Java: build on the GPU through the C API and write a file JVector 4 searches
(examples/java_ffm, thenexamples/jvector).
mlxVS 0.7.0
mlxVS 0.7.0: int8 and uint8 datasets.
pip install -U mlxvs- Byte datasets, as cuVS's int8 and uint8 datasets:
graph_searchreadsint8anduint8rows as they are
(four columns per 32-bit load), andCagraIndex.build(..., dtype="uint8")(or"int8") stores rows that are
integers in range, a quarter of float32's memory. Results equal float32's on integer data. SIFT1M quantized to
uint8 (its file holds normalized floats, so this loses precision): 120 MB, 478,000 queries/s at recall@10 0.925
and 267,000 at 0.965 (float32: 481 MB, 259,000 at 0.935 and 148,000 at 0.980). bench_search.py --dtype uint8andint8.
mlxVS 0.6.0
mlxVS 0.6.0: filtered search and seed nodes, as cuVS.
pip install -U mlxvs- Filtered search, as cuVS's bitset filter:
graph_search(..., filter=)(andCagraIndex.search) takes a bool mask
[n]or a bitsetuint32 [ceil(n / 32)]. Rejected rows are still traversed but leave the list once expanded
and are never returned; multi-CTA's list grows with the filtering rate as cuVS's (filtering_rate, computed from
the filter by default). SIFT1M, 10% of rows allowed: recall@10 0.978 multi-CTA (single-CTA, as in cuVS, 0.74 at
itopk_size64 and 0.86 at 256). - Seed nodes, as cuVS's
seed_ptr:seeds=[nq, num_seeds]start nodes per query. - C API:
mlxvs_index_search_filteredandmlxvs_index_search_seeded. - The README's roadmap records an experiment left out: Vamana graphs from search-path candidates (DiskANN's) stay
below CAGRA's graph on SIFT1M for four to five times the build time.
mlxVS 0.5.0
mlxVS 0.5.0: a C API, and mlxvs from Java through the FFM API.
pip install -U mlxvs- A C API,
include/mlxvs/mlxvs_c.hinlibmlxvs_c.dylib: an index handle (mlxvs_index_build,_search,
_save,_load,_from_graph,_graph),mlxvs_brute_force_knn, parameter structs with cuVS's defaults,
status codes andmlxvs_last_error. Only themlxvs_*symbols are exported. Indexes areCagraIndex's
.safetensorsfiles: built in Python, they load in C, and the other way round. examples/java_ffm: mlxvs from Java 22+ through the Foreign Function and Memory API, no JNI.cmake --installinstalls the C library and header.
mlxVS 0.4.0
mlxVS 0.4.0: Vamana pruning with JVector's diversity rule on the GPU.
pip install -U mlxvsvamana_prune: Vamana's robust pruning with JVector's diversity rule (VamanaDiversityProvider: passes with
alpha = 1.0, 1.2, ... over the candidates by similarity, JVector's similarities) on the GPU; it equals a CPU
reference of JVector's rule on every row of the tests.vamana_build: k-NN graph,vamana_prune, then each node's list with its incoming edges of lowest rank pruned
again;CagraIndex.build(..., graph="vamana", alpha=1.2). SIFT1M, degree 32 from 64 candidates: built in 15 s,
recall@10 0.974 atitopk_size64 (CAGRA's graph 0.980), and the same in JVector aftersave_jvector.- The reverse-edge passes of
cagra_optimizeare shared withvamana_build.