You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 050bb59
Browse filesBrowse the repository at this point in the historyBrowse files
distance_cosine_float() and distance_cosine_int8() had no NEON kernel,
so cosine KNN queries in NEON builds, which include the darwin-arm64
binary, ran the scalar loop.
asg017/sqlite-vec 0de765f added cosine_float_neon() and
cosine_int8_neon(), dispatched above 16 and 15 dimensions. This ports
them with two changes. asg017's float32 kernel sums in float32, the
loss asg017#324 reported and 2.1.0 fixed in the scalar loop by summing
in double: vectors with elements below about 3e-23 or above about 2e19
get wrong distances. Here each float32x4 load is widened to two
float64x2 halves before it is multiplied and added, in asg017's
16-element blocks with four accumulators per sum. And both kernels
return 1.0 for a zero vector, as the scalar loops do, where asg017's
return NaN.
On Linux arm64 (GCC 14, -O3), one 768-dimension float32 distance takes
about 155 ns instead of 895 ns, and a KNN query on a 100,000-row
float[768] table takes 25.9 ms instead of 94.4 ms for k = 10 and
30.1 ms instead of 98.9 ms for k = 100 (medians of 20 queries),
returning the same rows. The float32 distances match the scalar loop's
on 12,000 random pairs of 16 to 1,536 dimensions, except that a
vector's distance to itself, 0 or about 2e-16 in either, can change
between the two. The int8 kernel sums products exactly in 32-bit
lanes, and the scalar loop sums them in float, which is exact while a
sum stays below 2^24: their distances match up to 1,024 dimensions,
and past that the kernel's are closer to the exact value for vectors
whose squares sum past 2^24 (a mean error of 2.3e-8 instead of 2.5e-7
at 2,048 dimensions).
The cosine tests used vectors of 2 and 3 elements, below both kernels'
thresholds, and pass against asg017's kernels as they are.
test_vec_distance_cosine now checks lengths of 17 to 768, with and
without a remainder past the 16-element blocks, against a reference
computed in float64, since numpy sums int8 products in int8; the
zero-vector and extreme-magnitude tests repeat at 40 dimensions.
asg017's float32 kernel fails both, and with a zero-vector check added
it still fails the extreme-magnitude test. The full suite passes on
the NEON build and on the scalar one, and make test-unit, which builds
without SIMD, passes too.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,6 +6,7 @@
6
6
7
7
- Reading a vector column without a KNN query, as in `select embedding from v`, reads each chunk's vectors through one blob handle instead of opening the chunk's blob again for every row: selecting every vector of a 10,000-row `float[768]` table took 25 ms instead of 2,080 ms, and `select vec_distance_cosine(embedding, ?) from v` 41 ms instead of 2,093 ms.
8
8
- The linux-arm64 and linux-arm64-musl binaries use NEON, as the darwin-arm64 binary does: `make` enables it on Linux arm64, and `OMIT_SIMD=1` builds without it. An L2 KNN query on a 100,000-row `float[768]` table took 19 ms instead of 57 ms there. Hamming and `int8` L1 distances are unchanged; `float32` L1 distances can differ in the last digit when their double-precision sum rounds, and `float32` L2 distances can differ from 2.1.1's in the last digits, closer to the exact value (at 768 dimensions, a mean relative error of 3.0e-8 instead of 1.7e-7), so a KNN query can order rows with nearly equal distances differently; `int8` L2 distances whose squared differences sum past 2^24 are computed from the exact sum.
9
+
- Cosine distance between `float32` vectors of more than 16 dimensions, or `int8` vectors of more than 15, uses NEON in NEON builds, which include the darwin-arm64 binary: a KNN query on a 100,000-row `float[768]` table took 26 ms instead of 94 ms on Linux arm64. `float32` distances match the scalar code's on random vectors, though a vector's distance to an identical vector, 0 or about 2e-16 in either, can change between the two. `int8` distances match up to 1,024 dimensions; past that, vectors whose squared elements sum past 2^24 get distances closer to the exact value, as NEON sums them exactly. Ported from [asg017@0de765f](https://github.com/asg017/sqlite-vec/commit/0de765f), except that `float32` sums stay in `double` ([asg017#324](https://github.com/asg017/sqlite-vec/issues/324)); asg017's kernel sums them in `float32`.
0 commit comments