Repository navigation
[0.9.3] - 2026-09-09
Pre-release
Pre-release
Added
- Every similarity metric now takes a
batch_sizeargument, exposes it as the
batch_sizeattribute and takes a new value throughset_batch_size. It
defaults to16everywhere;-1turns the splitting off and processes the
whole input as one batch, whatever its size. - Serializable embedders store their batch size, so a reloaded embedder runs
with the batch size it was saved with. VLADEmbedderandFisherVectorEmbeddertake abatch_size. The images of
a batch are extracted, reduced, assigned and normalized as one matrix instead
of one image at a time, and an iterable input stays a stream.FeatureExtractorBase.extract_batchextracts a batch of images and returns
one feature array per image. Extractors that can do a whole batch in one go
override it; the default extracts one image at a time.DeepConvFeaturepushes a whole batch through its backbone in one forward
pass. A customtransformthat keeps the input size leaves the images
unstackable, and they are then extracted one at a time as before.ClipEmbedder,ContrastiveSiameseNetwork,TripletNeuralNetworkand
BCESiameseNetworktake abatch_sizethat splits their forward passes and
bounds the activation memory of each.Pipelinetakes abatch_sizebounding how many images it hands its
embedders at a time. Each embedder still applies its own batch size within.InMemoryImageEmbeddingStoreembeds its gallery one batch at a time, sized by
thebatch_sizeof the embedder it is given, instead of one image per call.InMemoryImageEmbeddingStoretakes anum_workers(default4) reading and
decoding the gallery files on worker threads while the embedder works on the
previous batch.InMemoryImageEmbeddingStoretakes anum_prefetch_batches(default4)
controlling how many batches of images the reading threads may run ahead of
the embedder.InMemoryImageEmbeddingStore.retrieve_top_k_similartakesquery_expansion,
expansion_alphaandexpansion_neighboursto refine every query with the
alpha query expansion of Radenović et al. (2019) before the final search. It
is off by default, since it costs one extra search per query.KReciprocalReranker(inpyvisim.image_store): re-ranks the candidates of a
query with the k-reciprocal encoding of Zhong et al. (2017) through
rerank(candidates, top_k), reading their embeddings back from the store.InMemoryImageEmbeddingStore.embeddings_of(paths)andvectors_at(ids)on
every index read a few gallery vectors back without decoding the whole
gallery.Candidate.arrayreads the matched image as an RGBuint8array on first
access and keeps it, andCandidate.clear_bufferdrops it again.scripts/benchmark_reranking.pymeasures plain retrieval, alpha query
expansion and k-reciprocal re-ranking on the Oxford Flower dataset. The
results are in the README.
Performance
Building a store over all 6149 train images of the Oxford Flower dataset, before
and after the batched gallery build, measured with
a benchmark script on
the CPU with PYVISIM_NUM_THREADS=4. Only the store constructor is timed.
from pyvisim.datasets import OxfordFlowerDataset
from pyvisim.image_store import InMemoryImageEmbeddingStore
from pyvisim.neural_networks import ClipEmbedder
train_dataset = OxfordFlowerDataset()
train_image_paths = train_dataset.image_paths
embedder = ClipEmbedder()
image_store = InMemoryImageEmbeddingStore(
image_paths=train_image_paths,
embedder=embedder,
search_index="hnsw",
index_params={"m": 16, "ef_construction": 200},
)| Before | After |
|---|---|
| 338 s | 249 s |
from pyvisim.classic import FisherVectorEmbedder
from pyvisim.datasets import OxfordFlowerDataset
from pyvisim.image_store import InMemoryImageEmbeddingStore
train_dataset = OxfordFlowerDataset()
train_image_paths = train_dataset.image_paths
# Fitted beforehand with learn(images, dim_reduction_factor=2)
embedder = FisherVectorEmbedder(n_components=32)
image_store = InMemoryImageEmbeddingStore(
image_paths=train_image_paths,
embedder=embedder,
search_index="hnsw",
index_params={"m": 16, "ef_construction": 200},
)| Before | After |
|---|---|
| 2936 s | 2706 s |
Removed
⚠️ DeepConvFeatureno longer appends normalized(x, y)coordinates to its
descriptors: thespatial_embeddingargument is gone andoutput_dimis now
the channel count of the selected conv layer.
Changed
⚠️ Candidateis a frozen dataclass instead of a named tuple, so it no longer
unpacks or indexes: readcandidate.pathandcandidate.score. It lives in
pyvisim.image_store.candidateand is still exported frompyvisim.image_store.- Added backbones resnet34, resnet50, resnet101, resnet152 under
pyvisim.neural_networks.backbones. ⚠️ HnswIndextakesgraph_degree,build_candidatesand
search_candidatesinstead ofm,ef_constructionandef_search, and
exposes them under those names. The old names are gone, inindex_params
too, so a store saved by an earlier release cannot be loaded by this one.- Every
save_to_diskrejects a destination whose directory does not exist
with anOSError, and everyload_from_diskreports a missing file as a
FileNotFoundError. The embedders reported both as a safetensors error. ⚠️ SSIMandMSSSIMscore 16 image pairs per batch instead of two, and
the neural embedders now embed 16 images per forward pass instead of the
whole input at once. Passbatch_size=-1for the previous behaviour.⚠️ PSNRtakesbatch_size=-1instead ofbatch_size=Noneto score the
whole input as one batch, and defaults to16rather than to the whole input.⚠️ PSNRraises on a batch holding no image instead of returning an empty
score matrix, which is what every other metric already did.⚠️ The batch size is a required key of the.embedderformat, so a file
written by an earlier release cannot be loaded by this one.
Removed
⚠️ pyvisim.serialization.save_embedder_stateandload_embedder_state.
They only calledsave_state/load_statewith the embedder metadata key,
which is now exported asEMBEDDER_METADATA_KEY.