Repository navigation
Conversation
|
Before you submit for review:
If you did not complete any of these, then please explain below. |
7aec240 to
9ee1486
Compare
|
To do:
|
jshook
left a comment
There was a problem hiding this comment.
This PR needs to be updated.
- merge conflicts need to be addressed
- the base commit this branch depends on should probably determine the target of the merge, rather than main, since there are direct dependencies.
9ee1486 to
4c789ac
Compare
Fixed, it is now rebased with the latest changes in main.
This is no longer a problem since it includes the commits in #708 |
|
Marking this as draft until I resolve the question of leveraging NVQ for INT8. |
2515d75 to
09c4e3c
Compare
09c4e3c to
ecc9edd
Compare
ecc9edd to
b0ad5cd
Compare
ae41d3d to
2964864
Compare
MarkWolters
left a comment
There was a problem hiding this comment.
Thanks for addressing my requested changes!
|
@r-devulap this missing acceptance criteria and evidence that it is met. It involves new scoring on a new vector type. We either need the requester(s) to provide some dataset benchmarks and metrics (what is acceptable recall and performance?), or we need to create int8 datasets and set our own standards. How do you want to proceed? |
@lvca is it possible to provide some datasets that we can you use to measure recall and performance? |
|
@tae898 Can you help on this? |
|
I've been benchmarking ArcadeDB's jvector-backed vector index on SIFT-1M and DEEP-10M, fp32 and int8, for both build and search. The datasets I've been using are not int8:
So each vector db used their own quantization function to turn fp32 into int8. If you are looking for more "formal" int8 vector dataset, perhaps these two are not the best ones. Worth knowing what "int8" means on the ArcadeDB side: the index writes an int8 copy of each vector into its own pages, then dequantizes back to float32 on the read path, so jvector always receives float32. That's the gap filed in #665. My results: https://humem.ai/projects/arcadedb. Those are databases, not libraries, so it isn't a direct comparison with jvector on its own. Let me know if there's anything else I can help you with. |
…ByteSequence) Add a new static factory byteVectorScoreProvider(RandomAccessByteVectorValues, ByteVectorSimilarityFunction) that performs exact byte×byte scoring with no float32 round-trip. The returned BuildScoreProvider implements isExact()=true, approximateCentroid(), searchProviderFor(ByteSequence), searchProviderFor(int), diversityProviderFor(int), and diversityScoreFunctionFor(int), using two independent threadLocalSupplier() handles for thread-safe concurrent builds. Also adds a default searchProviderFor(ByteSequence<?>) to the interface that throws UnsupportedOperationException, so existing float-based providers are unaffected.
Add builder(RandomAccessByteVectorValues, ByteVectorSimilarityFunction, int M) and builder(..., List<Integer> maxDegrees) factory overloads so callers can build a graph over int8 byte vectors without touching the builder core. Generalize build(RandomAccessVectorValues) to build(VectorValues<?>) and switch the parallel addGraphNode loop to use scoreProvider.searchProviderFor(node) directly, removing the float-only getVector path that was incompatible with byte-vector score providers. Add addGraphNode(int node, ByteSequence<?> vector) as a public single-node insertion entry point for byte vectors. Update TestVectorGraph to add explicit casts (RandomAccessVectorValues, VectorSimilarityFunction) on the null arguments so the compiler resolves the correct overload now that the new byte-vector builder() overloads exist.
Replace scalar loop implementations of dotProduct, squareDistance, and
cosine for ByteSequence with Panama Vector API implementations in
PanamaVectorUtilSupport, and native AVX-512/AVX2 kernels wired through
NativeVectorUtilSupport -> NativeSimdOps JNI bindings.
Java (Panama) path:
- Widen signed bytes to int32 via B2I conversion, accumulate products
in IntVector lanes, then reduce.
- Dispatch on PREFERRED_BIT_SIZE:
512-bit: load 16 bytes (SPECIES_128) -> IntVector.SPECIES_512
256-bit: load 8 bytes (SPECIES_64) -> IntVector.SPECIES_256
128-bit: scalar fallback
- cosine variants accumulate dot/norm products in long after reduction
to avoid int32 overflow on large vectors.
Native path (C++):
- New kernels in jvector_simd_kernels.cpp and
jvector_avx3_dl_kernels.cpp: dot_product_i8, euclidean_i8,
cosine_i8 using Highway SIMD (AVX-512 / AVX2 dispatch).
- Registered in jvector_simd_kernel_list.h and exported via
jvector_simd.cpp.
- Microbenchmarks added in bench_similarity_i8.cpp.
- C++ unit tests added in test_similarity_i8.cpp using a prime-length
(107-element) vector to exercise tail handling.
Java tests:
- TestVectorizationProvider.testSimilarityMetricsByte cross-checks
SIMD results against scalar DefaultVectorUtilSupport baseline.
Introduces InlineByteVectors, a new Feature that stores signed int8 vectors inline in an OnDiskGraphIndex at 1 byte per component — 4x more compact than the float32 InlineVectors representation. Changes: - InlineByteVectors.java: new Feature implementation backed by VectorTypeSupport.writeByteSequence / readByteSequence - FeatureId: add INLINE_BYTE_VECTORS as ordinal 5 (backward-compatible) - AbstractGraphIndexWriter.Builder: accept INLINE_BYTE_VECTORS as the canonical source for the vector dimension in the file header - OnDiskGraphIndex.View: add getByteVector(int) to read a stored int8 vector from disk, and byteVectorRerankerFor(ByteSequence, ByteVectorSimilarityFunction) to wire byte-by-byte disk scoring directly into the search path
Demonstrates the full int8 pipeline using the siftsmall dataset: - Read siftsmall_base.fvecs and convert float32 vectors to signed int8 - Build a graph index with byte-by-byte scoring (no float32 round-trip) - Save the graph to disk using InlineByteVectors (1 byte/component) - Load the index from disk - Search with random int8 query vectors, scoring directly from disk byte vectors Also registers the tutorial under the 'int8' key in TutorialRunner.
…graph build, and disk round-trip
…ilingual-v3 (1M) to BenchYAML
- RandomAccessVectorValues/RandomAccessByteVectorValues: covariant threadLocalSupplier() overrides; VectorValues returns Supplier<? extends ...> - BuildScoreProvider: drop asRandomAccessSupplier now that the supplier is typed - GraphIndexBuilder.build: read float sources through per-thread views so borrowed vectors are not shared across workers - AbstractGraphIndexFormat: v6 supports INLINE_BYTE_VECTORS (test updated) - NativeVectorUtilSupport: remove leftover merge conflict marker and fix braces - provider-selection fixtures: export dot_product_i8, euclidean_i8, cosine_i8
…peline New types and APIs: - BaseDataSet: common interface for all dataset types (size(), getQueryCount(), getDimension(), getName(), getGroundTruth()); DataSet and the new ByteDataSet both extend it, replacing the previous DataSet-only hierarchy - ByteDataSet: interface for signed int8 vector datasets (getBaseRavv, getSimilarityFunction, getBaseVectors, getQueryVectors) - ByteSimpleDataSet: concrete in-memory implementation of ByteDataSet - DataSetProperties.isInt8() / KEY_IS_INT8: metadata flag that signals a dataset stores native byte vectors - SiftLoader.readBvecs(): reads .bvecs files into List<ByteSequence<?>> Dataset loading: - DataSetLoaderSimpleMFD: branches on isInt8() to call readBvecs and return a ByteSimpleDataSet; buffered loading is rejected for int8 datasets - DataSetInfo.getDataSet() is now generic (<T extends BaseDataSet>) to avoid unchecked casts at call sites Index build and write: - Grid: new int8 build path uses BuildScoreProvider.byteVectorScoreProvider, writes INLINE_BYTE_VECTORS feature; the existing float path is preserved and selected via instanceof dispatch - ConfiguredSystem.ds typed as BaseDataSet; scoreProviderFor(ByteSequence, View) added for int8 queries; exactVectors is null for int8 datasets Query execution and benchmarks: - QueryExecutor.executeQuery dispatches to float or int8 path based on dataset type; new overload for ByteSequence queries - ThroughputBenchmark warm-up generates random signed byte queries for int8 datasets instead of random float vectors - AccuracyBenchmark, CountBenchmark, ExecutionTimeBenchmark, LatencyBenchmark: switched from getQueryVectors().size() to getQueryCount() YAML config validation: - ConstructionParameters: reranking and fusedGraph default to ["FP"] / [false] when absent, so int8 YAML configs need not specify them - MultiConfig.validateForInt8Dataset(): throws if reranking is set or any compression type is not "None"; called in BenchYAML and AutoBenchYAML immediately after the dataset is loaded Reporting: - DatasetInfoWriter.createRow() and RunArtifacts.registerDataset() accept BaseDataSet; similarity function is resolved via instanceof - AutoBenchYAML: compaction benchmark is skipped for int8 datasets; ds.size() used in place of getBaseVectors().size() Dataset metadata: - dataset-metadata.yml: new int8 dataset entries added
- RandomAccessVectorValues: redeclare VectorFloat<?> getVector(int) so the float-vector binary signature is retained for existing callers and implementations. - GraphIndexBuilder: keep build(RandomAccessVectorValues) as a forwarding overload of build(VectorValues<?>) for binary compatibility. - ByteVectorSimilarityFunction.EUCLIDEAN: use 1 / (1 + squaredL2) like the float version. Dividing by n * 255^2 collapsed nearby distances to the same float score (e.g. squared distances 0..3 at 1024 dimensions) and broke ratio-based diversity pruning. - BuildScoreProvider.byteVectorScoreProvider: copy the reference vector when the source shares its buffer, mirroring the float provider, so creating another scorer no longer changes earlier comparisons.
- PanamaVectorUtilSupport: support sliced byte inputs in the 256/512-bit dot product, squared distance and cosine paths. fromByteSequence no longer casts to ArrayByteSequence (which threw ClassCastException for slices), and the loads now start at offset() + i. - BuildScoreProvider.byteVectorScoreProvider: skip null vectors in approximateCentroid, matching the float provider. - SiftLoader: rename readBvecs to readInt8Bvecs and document that only signed int8 payloads are supported, not the conventional unsigned uint8 .bvecs format. Clarify the same contract on DataSetProperties.isInt8/KEY_IS_INT8, in dataset-metadata.yml and at the DataSetLoaderSimpleMFD call site. Also move the isValid Javadoc back onto isValid. - VectorUtil.cosine(ByteSequence, ByteSequence): mirror the float overload with a dimension check and an assertion that the result is finite; zero vectors are documented as unsupported.
… for disk reranking - DefaultVectorUtilSupport: accumulate byte dotProduct and squareDistance in int and byte cosine in long/double, converting to float only at the end. This matches the Panama and native implementations and avoids float rounding differences above 2^24 in high dimensions. - OnDiskGraphIndex.View: add getByteVectorInto, mirroring getVectorInto, and have byteVectorRerankerFor reuse one scratch ByteSequence instead of allocating a new vector for every comparison. getByteVector now delegates to getByteVectorInto. The reranker is documented as not thread-safe.
- TestByteVectorSimilarityFunction: update the EUCLIDEAN known value for the un-normalized 1 / (1 + squaredL2) mapping; add tests that small squared distances stay distinct at 1024 dimensions, sliced inputs match a scalar reference, the Default implementation accumulates exactly at 4096 dimensions, and cosine rejects mismatched dimensions and (under -ea) zero vectors. - BuildScoreProviderTest: add shared-buffer tests for byte search/diversity score functions and a test that approximateCentroid skips null vectors. - TestOnDiskGraphIndex: add a test that the disk reranker's reused scratch vector gives correct scores in any order and that getByteVectorInto matches getByteVector.
Replace the n*128^2 normalisation, which collapsed adjacent dot products to the same float32 score at ~1,024 dimensions, with a monotone mapping (dot < 0 ? 1/(1-dot) : dot+1). Update tests and add a high-dimension distinctness test.
Use it in the byte BuildScoreProvider to fill the private anchor copy directly. Relax the on-disk end-to-end score range check for the unbounded int8 DOT_PRODUCT mapping.
…ults getFeatureSets() now fails with a clear message when reranking or fusedGraph is missing. Int8 datasets get their own feature set (INLINE_BYTE_VECTORS) and reject fusedGraph: [Yes]. Also drop a redundant same-package VectorValues import in GraphIndexBuilder.
…float path The byte branch previously used the argument only for size() and took vectors from the score provider. It now reads them through a per-thread view and rejects unsupported VectorValues types.
575dcee to
ae896f4
Compare
|
Updates:
|
RandomizedTest's nextBytes is biased toward zero runs, so short slices can be the zero vector, for which cosine is undefined. Skip the cosine check in the sliced-input test when a norm is zero, and draw non-zero vectors in the other random cosine tests.
INT8 (Byte-Vector) Support for JVector
Overview
This branch adds full INT8 (byte-vector) support to JVector — from the math primitives all the way through graph building, on-disk storage, SIMD acceleration, and end-to-end tests.
Commits
1. fd131a7 — Add random-access int8 vector value support
Introduces a new
VectorValuessuper-interface that captures shared random-access behavior, then refactorsRandomAccessVectorValues(float) to extend it, and addsRandomAccessByteVectorValuesand its list-backed implementationListRandomAccessByteVectorValuesas the byte-vector counterpart. Also updatesBuildScoreProviderto use the generalized thread-local supplier.2. c55574c — Add byte-similarity methods to VectorUtilSupport / VectorUtil / DefaultVectorUtilSupport
Adds
dotProduct,squaredL2, andcosineforbyte[]/ByteSequenceto the vector utility stack.3. 9ba737a — Add ByteVectorSimilarityFunction enum
Mirrors the float
VectorSimilarityFunctionenum; wraps the three byte similarity metrics with acompare()API and score normalization.4. 5652b46 — Add BuildScoreProvider.byteVectorScoreProvider and searchProviderFor(ByteSequence)
Adds
byteVectorScoreProvider()factory andsearchProviderFor(ByteSequence)so the graph builder can score byte-vector candidates.5. 389c391 — Wire byteVectorScoreProvider into GraphIndexBuilder
GraphIndexBuildernow acceptsRandomAccessByteVectorValuesand routes to the byte score provider, enabling full graph construction over int8 data.6. c6dfea0 — Vectorize ByteSequence similarity metrics with SIMD
Panama SIMD and AVX-512 native kernels for int8 dot-product, L2, and cosine; adds native benchmarks and C++ unit tests.
7. 3d4dada — Add InlineByteVectors feature for native int8 on-disk storage
New
FeatureIdandInlineByteVectorsclass for serializing byte vectors into the graph index file format, plusOnDiskGraphIndexreader support.8. 974f508 — Add INT8 end-to-end tutorial (Int8Example)
End-to-end walkthrough showing how to build, serialize, and query a byte-vector graph index; registered in
TutorialRunner.9. b0ad5cd — Add int8 test coverage for byte-vector similarity, RABVV, BSP, SIMD, graph build, and disk round-trip
Unit tests for
ByteVectorSimilarityFunction,BuildScoreProvider,TestVectorizationProvider(SIMD),TestVectorGraph(build),TestOnDiskGraphIndex(round-trip), andListRandomAccessByteVectorValues.