Description
IVFQueryParam(nprobe=...) appears to have no effect on IVF search in zvec
0.5.1. For both unquantized FP32 and INT8 100-list indexes, changing nprobe
from 1 through 100 produced identical top-10 IDs for every query and essentially
unchanged latency.
Expected: increasing nprobe should search more lists and normally affect
candidates, recall, or latency. In particular, unquantized nprobe=n_list
should search all lists and recover the one-list/exact FP32 result.
This report does not assume the root cause. The observations are consistent
with a fixed/default probe count being used internally, but the defect could be
elsewhere in parameter forwarding or IVF search configuration.
Steps to reproduce
Standalone PEP 723 script (OpenML MNIST; does not use private data or an
existing benchmark):
https://gist.github.com/SeanPedersen/dbb00e44566cbb44fbbb2219ada80d8e
uv run --python 3.11 reproduce_zvec_ivf_nprobe.py
The script:
- downloads and locally caches OpenML
mnist_784 v1;
- indexes exactly 10,000 contiguous normalized
float32 vectors;
- uses 100 deterministic, disjoint queries from the MNIST test partition;
- computes exact NumPy cosine top-10 ground truth;
- builds indexes only after loading the vectors and calls
collection.optimize();
- tests cosine IVF with
n_list=100, n_iters=15, use_soar=False, with no
quantization and with QuantizeType.INT8;
- tests
nprobe=1,5,10,25,50,100 and FP32/INT8 one-list controls;
- asserts
IVFQueryParam(nprobe=N).nprobe == N and that the native pybind11
parameter attached to Query retains N;
- removes temporary indexes in
finally blocks and writes machine-readable JSON.
Results
All 100 returned top-10 ID lists were identical at every nprobe within both
100-list indexes:
| index |
nprobe |
recall@10 |
mean ms |
p50 ms |
p95 ms |
IDs differ vs 1 |
| IVF FP32, no quantization |
1 |
0.9820 |
0.418 |
0.402 |
0.552 |
False |
| IVF FP32, no quantization |
5 |
0.9820 |
0.405 |
0.392 |
0.496 |
False |
| IVF FP32, no quantization |
10 |
0.9820 |
0.413 |
0.394 |
0.570 |
False |
| IVF FP32, no quantization |
25 |
0.9820 |
0.385 |
0.371 |
0.520 |
False |
| IVF FP32, no quantization |
50 |
0.9820 |
0.395 |
0.377 |
0.525 |
False |
| IVF FP32, no quantization |
100 |
0.9820 |
0.412 |
0.396 |
0.553 |
False |
| IVF INT8 |
1 |
0.6660 |
0.370 |
0.366 |
0.493 |
False |
| IVF INT8 |
5 |
0.6660 |
0.419 |
0.405 |
0.548 |
False |
| IVF INT8 |
10 |
0.6660 |
0.386 |
0.397 |
0.510 |
False |
| IVF INT8 |
25 |
0.6660 |
0.383 |
0.370 |
0.492 |
False |
| IVF INT8 |
50 |
0.6660 |
0.384 |
0.384 |
0.515 |
False |
| IVF INT8 |
100 |
0.6660 |
0.368 |
0.358 |
0.513 |
False |
| one-list FP32 control |
1 |
1.0000 |
2.375 |
2.308 |
3.082 |
n/a |
| one-list INT8 control |
1 |
0.9980 |
0.962 |
0.927 |
1.198 |
n/a |
The one-list FP32 result is exact, and the one-list INT8 result suggests INT8
quantization alone does not explain the low multi-list INT8 recall. IVF training
appears nondeterministic (the absolute INT8 recall varied between fresh index
builds), but within every build tested, IDs remained identical across all
nprobe values.
Operating system
Linux 7.0.11-zen1-1-zen x86_64 (glibc 2.43)
Build and runtime environment
- zvec 0.5.1 (published PyPI wheel)
- Python 3.11.13, installed/run by
uv
- NumPy 2.4.6
- CPU architecture: x86_64
- Dataset: OpenML
mnist_784 v1, 10,000 indexed vectors, dimension 784
Additional context
The issue involves the Python/native pybind11 boundary. The public Python
parameter and the native parameter attached to the query both display the
requested nprobe; no monkey-patching is used.
Description
IVFQueryParam(nprobe=...)appears to have no effect on IVF search in zvec0.5.1. For both unquantized FP32 and INT8 100-list indexes, changing
nprobefrom 1 through 100 produced identical top-10 IDs for every query and essentially
unchanged latency.
Expected: increasing
nprobeshould search more lists and normally affectcandidates, recall, or latency. In particular, unquantized
nprobe=n_listshould search all lists and recover the one-list/exact FP32 result.
This report does not assume the root cause. The observations are consistent
with a fixed/default probe count being used internally, but the defect could be
elsewhere in parameter forwarding or IVF search configuration.
Steps to reproduce
Standalone PEP 723 script (OpenML MNIST; does not use private data or an
existing benchmark):
https://gist.github.com/SeanPedersen/dbb00e44566cbb44fbbb2219ada80d8e
uv run --python 3.11 reproduce_zvec_ivf_nprobe.pyThe script:
mnist_784v1;float32vectors;collection.optimize();n_list=100,n_iters=15,use_soar=False, with noquantization and with
QuantizeType.INT8;nprobe=1,5,10,25,50,100and FP32/INT8 one-list controls;IVFQueryParam(nprobe=N).nprobe == Nand that the native pybind11parameter attached to
QueryretainsN;finallyblocks and writes machine-readable JSON.Results
All 100 returned top-10 ID lists were identical at every
nprobewithin both100-list indexes:
The one-list FP32 result is exact, and the one-list INT8 result suggests INT8
quantization alone does not explain the low multi-list INT8 recall. IVF training
appears nondeterministic (the absolute INT8 recall varied between fresh index
builds), but within every build tested, IDs remained identical across all
nprobevalues.Operating system
Linux 7.0.11-zen1-1-zen x86_64 (glibc 2.43)
Build and runtime environment
uvmnist_784v1, 10,000 indexed vectors, dimension 784Additional context
The issue involves the Python/native pybind11 boundary. The public Python
parameter and the native parameter attached to the query both display the
requested
nprobe; no monkey-patching is used.