usearch 0.8.0 → 0.8.1
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.
- package/Cargo.toml +1 -1
- package/VERSION +1 -1
- package/conanfile.py +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/python/scripts/bench.py +86 -49
- package/python/scripts/bench_params.py +1 -0
package/Cargo.toml
CHANGED
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.8.
|
|
1
|
+
0.8.1
|
package/conanfile.py
CHANGED
|
@@ -4,7 +4,7 @@ from conans import ConanFile
|
|
|
4
4
|
class USearchConan(ConanFile):
|
|
5
5
|
|
|
6
6
|
name = 'USearch'
|
|
7
|
-
version = '0.8.
|
|
7
|
+
version = '0.8.1'
|
|
8
8
|
license = 'Apache 2.0'
|
|
9
9
|
url = 'https://github.com/unum-cloud/usearch'
|
|
10
10
|
description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -10,7 +10,7 @@ filterwarnings = ["error"]
|
|
|
10
10
|
|
|
11
11
|
[tool.cibuildwheel]
|
|
12
12
|
test-requires = ["pytest", "numpy"]
|
|
13
|
-
test-command = "pytest {project}/python/test.py"
|
|
13
|
+
test-command = "pytest {project}/python/scripts/test.py"
|
|
14
14
|
build-verbosity = 0
|
|
15
15
|
skip = ["*musllinux*", "*i686*", "pp*"]
|
|
16
16
|
|
package/python/scripts/bench.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import time
|
|
2
2
|
import numpy as np
|
|
3
|
-
import
|
|
3
|
+
import math
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
from numba import cfunc, types, carray
|
|
5
|
+
import fire
|
|
7
6
|
|
|
8
7
|
from usearch.index import Index
|
|
9
8
|
from usearch.io import load_matrix
|
|
@@ -51,25 +50,6 @@ def bench_usearch(index, vectors: np.array, queries: np.array, neighbors: np.arr
|
|
|
51
50
|
recall_at_one /= queries.shape[0]
|
|
52
51
|
print(f'- Recall@1: {recall_at_one * 100:.2f} %')
|
|
53
52
|
|
|
54
|
-
# Showcases how to use Numba to JIT-compile similarity measures for USearch.
|
|
55
|
-
# https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
signature_f32 = types.float32(
|
|
59
|
-
types.CPointer(types.float32),
|
|
60
|
-
types.CPointer(types.float32),
|
|
61
|
-
types.size_t, types.size_t)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
@cfunc(signature_f32)
|
|
65
|
-
def inner_product_f32(a, b, n, m):
|
|
66
|
-
a_array = carray(a, n)
|
|
67
|
-
b_array = carray(b, n)
|
|
68
|
-
c = types.float32(0)
|
|
69
|
-
for i in range(n):
|
|
70
|
-
c += a_array[i] * b_array[i]
|
|
71
|
-
return types.float32(1 - c)
|
|
72
|
-
|
|
73
53
|
|
|
74
54
|
def main(
|
|
75
55
|
vectors: str,
|
|
@@ -94,16 +74,6 @@ def main(
|
|
|
94
74
|
)
|
|
95
75
|
bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
|
|
96
76
|
|
|
97
|
-
print('USearch: HNSW + Numba JIT')
|
|
98
|
-
index = Index(
|
|
99
|
-
ndim=dim,
|
|
100
|
-
expansion_add=expansion_add,
|
|
101
|
-
expansion_search=expansion_search,
|
|
102
|
-
connectivity=connectivity,
|
|
103
|
-
metric_pointer=inner_product_f32.address,
|
|
104
|
-
)
|
|
105
|
-
bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
|
|
106
|
-
|
|
107
77
|
print('USearch: HNSW + Half Precision')
|
|
108
78
|
index = Index(
|
|
109
79
|
ndim=dim,
|
|
@@ -124,27 +94,94 @@ def main(
|
|
|
124
94
|
)
|
|
125
95
|
bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
|
|
126
96
|
|
|
97
|
+
# Showcases how to use Numba to JIT-compile similarity measures for USearch.
|
|
98
|
+
# https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
|
|
99
|
+
try:
|
|
100
|
+
from numba import cfunc, types, carray
|
|
101
|
+
|
|
102
|
+
signature_f32 = types.float32(
|
|
103
|
+
types.CPointer(types.float32),
|
|
104
|
+
types.CPointer(types.float32),
|
|
105
|
+
types.size_t, types.size_t)
|
|
106
|
+
|
|
107
|
+
@cfunc(signature_f32)
|
|
108
|
+
def inner_product_f32(a, b, n, m):
|
|
109
|
+
a_array = carray(a, n)
|
|
110
|
+
b_array = carray(b, n)
|
|
111
|
+
c = types.float32(0)
|
|
112
|
+
for i in range(n):
|
|
113
|
+
c += a_array[i] * b_array[i]
|
|
114
|
+
return types.float32(1 - c)
|
|
115
|
+
|
|
116
|
+
signature_f8 = types.float32(
|
|
117
|
+
types.CPointer(types.int8),
|
|
118
|
+
types.CPointer(types.int8),
|
|
119
|
+
types.size_t, types.size_t)
|
|
120
|
+
|
|
121
|
+
@cfunc(signature_f8)
|
|
122
|
+
def cos_f8(a, b, n, m):
|
|
123
|
+
a_array = carray(a, n)
|
|
124
|
+
b_array = carray(b, n)
|
|
125
|
+
c = types.int32(0)
|
|
126
|
+
a_sq = types.int32(0)
|
|
127
|
+
b_sq = types.int32(0)
|
|
128
|
+
for i in range(n):
|
|
129
|
+
ai = types.int16(a_array[i])
|
|
130
|
+
bi = types.int16(b_array[i])
|
|
131
|
+
c += ai * bi
|
|
132
|
+
a_sq += ai * ai
|
|
133
|
+
b_sq += bi * bi
|
|
134
|
+
a_norm = math.sqrt(types.float32(a_sq))
|
|
135
|
+
b_norm = math.sqrt(types.float32(b_sq))
|
|
136
|
+
c_norm = types.float32(c) / (a_norm * b_norm)
|
|
137
|
+
return types.float32(1 - c_norm)
|
|
138
|
+
|
|
139
|
+
print('USearch: HNSW + Numba JIT')
|
|
140
|
+
index = Index(
|
|
141
|
+
ndim=dim,
|
|
142
|
+
expansion_add=expansion_add,
|
|
143
|
+
expansion_search=expansion_search,
|
|
144
|
+
connectivity=connectivity,
|
|
145
|
+
metric_pointer=inner_product_f32.address,
|
|
146
|
+
)
|
|
147
|
+
bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
|
|
148
|
+
|
|
149
|
+
print('USearch: HNSW + Quarter Precision + Numba JIT')
|
|
150
|
+
index = Index(
|
|
151
|
+
ndim=dim,
|
|
152
|
+
dtype='f8',
|
|
153
|
+
expansion_add=expansion_add,
|
|
154
|
+
expansion_search=expansion_search,
|
|
155
|
+
connectivity=connectivity,
|
|
156
|
+
metric_pointer=cos_f8.address,
|
|
157
|
+
)
|
|
158
|
+
bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
|
|
159
|
+
except ImportError:
|
|
160
|
+
print('Skipping Numba benchmarks')
|
|
161
|
+
|
|
127
162
|
# Don't depend on the FAISS installation for benchmarks
|
|
128
163
|
try:
|
|
129
164
|
from faiss import IndexHNSWFlat, IndexIVFPQ
|
|
165
|
+
|
|
166
|
+
print('FAISS: HNSW')
|
|
167
|
+
index = IndexHNSWFlat(dim, connectivity)
|
|
168
|
+
index.hnsw.efSearch = expansion_search
|
|
169
|
+
index.hnsw.efConstruction = expansion_add
|
|
170
|
+
bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
|
|
171
|
+
|
|
172
|
+
print('FAISS: HNSW + IVFPQ')
|
|
173
|
+
# Number of inverted lists (number of partitions or cells).
|
|
174
|
+
nlist = 10000
|
|
175
|
+
nsegment = 16 # Number of segments for PQ (number of subquantizers).
|
|
176
|
+
nbit = 8 # Number of bits to encode each segment.
|
|
177
|
+
coarse_quantizer = IndexHNSWFlat(dim, connectivity)
|
|
178
|
+
index = IndexIVFPQ(coarse_quantizer, dim, nlist, nsegment, nbit)
|
|
179
|
+
index.train(vectors_mat)
|
|
180
|
+
index.nprobe = 10
|
|
181
|
+
bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
|
|
182
|
+
|
|
130
183
|
except ImportError:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
print('FAISS: HNSW')
|
|
134
|
-
index = IndexHNSWFlat(dim, connectivity)
|
|
135
|
-
index.hnsw.efSearch = expansion_search
|
|
136
|
-
index.hnsw.efConstruction = expansion_add
|
|
137
|
-
bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
|
|
138
|
-
|
|
139
|
-
print('FAISS: HNSW + IVFPQ')
|
|
140
|
-
nlist = 10000 # Number of inverted lists (number of partitions or cells).
|
|
141
|
-
nsegment = 16 # Number of segments for PQ (number of subquantizers).
|
|
142
|
-
nbit = 8 # Number of bits to encode each segment.
|
|
143
|
-
coarse_quantizer = IndexHNSWFlat(dim, connectivity)
|
|
144
|
-
index = IndexIVFPQ(coarse_quantizer, dim, nlist, nsegment, nbit)
|
|
145
|
-
index.train(vectors_mat)
|
|
146
|
-
index.nprobe = 10
|
|
147
|
-
bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
|
|
184
|
+
print('Skipping FAISS benchmarks')
|
|
148
185
|
|
|
149
186
|
|
|
150
187
|
if __name__ == '__main__':
|