Repository navigation
v0.10.0
Pre-releaseRelease Notes
v0.10.0
Upgrade Notes
-
The British spelling
neighbouris replaced byneighborthroughout the library. One public name changes with it:InMemoryImageEmbeddingStore.retrieve_top_k_similarnow takesexpansion_neighborswhere it tookexpansion_neighbours. -
The British spelling
serialiseis replaced byserializethroughout the library. Only documentation, docstrings and comments are affected. -
DeepConvFeaturemoved topyvisim.neural_networks.features, sofrom pyvisim.features import DeepConvFeaturenow raisesImportError. If your code imports the class, change the import:# before from pyvisim.features import DeepConvFeature # after from pyvisim.neural_networks.features import DeepConvFeature
-
pyvisim.structuralandpyvisim.pixelwisemoved under the newpyvisim.densepackage. Imports ofSSIM,MSSSIMandPSNRfrom the old paths fail withModuleNotFoundError, so change them topyvisim.dense.structuralandpyvisim.dense.pixelwise:from pyvisim.dense.pixelwise import PSNR from pyvisim.dense.structural import MSSSIM, SSIM
-
pyvisim.features.feature_extractor_from_dictwas removed. Feature extractors are now rebuilt throughFeatureExtractorBase.from_dict, which takes the same mapping and returns the same extractor. You are affected if you import the function by name:# Before from pyvisim.features import feature_extractor_from_dict extractor = feature_extractor_from_dict(data) # After from pyvisim.base import FeatureExtractorBase extractor = FeatureExtractorBase.from_dict(data)
Saved
.embedderfiles are unaffected, since the serialized format did not change. -
The first parameter of
FeatureExtractorBase.from_dictwas renamed fromdatatostate. You are affected if you pass it by keyword, andfrom_dict(data=...)becomesfrom_dict(state=...). -
The mapping returned by a feature extractor's
to_dictnow also holds a"format_version"key. -
The
_serialization_confighook ofFeatureExtractorBasewas removed. A custom extractor that overrides it now overrides_stateinstead and returns{"config": ...}, otherwise its arguments are no longer saved. -
InMemoryImageEmbeddingStoreno longer embeds its gallery in the constructor, which affects every store built through it. Callbuild_store()right after the constructor, or passlazy_build=Falseto have the constructor build the store. -
Until
build_store()has run,search,retrieve_top_k_similar,embeddings,embeddings_of,index,dim,to_dictandsave_to_diskraiseRuntimeError. A store that adopts anExternalSearchIndexor is rebuilt byload_from_diskorfrom_dictcomes back built. -
build_store()now raises for an unreadable image file and for a gallery none of whose images could be embedded, which the constructor used to report. An unknownsearch_index, a rejectedindex_paramsentry, a non-string path and an empty gallery still raise in the constructor. -
pyvisim.neural_networksno longer re-exportsDeepConvFeature, sofrom pyvisim.neural_networks import DeepConvFeaturenow raisesImportError. Import the class frompyvisim.neural_networks.featuresinstead:# before from pyvisim.neural_networks import DeepConvFeature # after from pyvisim.neural_networks.features import DeepConvFeature
-
Importing
pyvisimno longer configures logging, and its loggers are named after their modules (e.g.pyvisim.datasets.datasets) instead ofData_Set,Feature_Extractor,PipelineandSimilarity_Metrics. Configure thepyvisimlogger to see the library's messages. -
from pyvisim import *no longer importsdatasets, which needs thennextra. Access it aspyvisim.datasetsor import it explicitly. -
VLADEmbedderandFisherVectorEmbedderdefault toraise_error_when_pca_incompatible=True, so a clustering model the fitted PCA cannot feed raises aRuntimeErrorinstead of silently dropping the PCA. PassFalseto keep the old behavior. -
pyvisim._base_classesis removed. ImportSimilarityMetric,FeatureExtractorBase,ImageEmbedderBaseandSerializableImageEmbedderfrompyvisim.baseinstead. -
VLADEmbedderandFisherVectorEmbedderno longer takeraise_error_when_pca_incompatible. A clustering model the fitted PCA cannot feed always raises aRuntimeError, so drop the argument. -
VLADEmbedderandFisherVectorEmbedderno longer takeflatten.embedalways returns one flat row per image, so drop the argument. -
Embedders saved by
VLADEmbedderandFisherVectorEmbedderare written under format version 4. Files of version 3 still load, files of version 4 do not load with an olderpyvisim. -
OxfordFlowerDatasetno longer accepts atransformargument. Passing one raisedNotImplementedErrorbefore, so only calls that spelled outtransform=Noneor passedpurposepositionally are affected: drop the argument and passpurposeby keyword. Every item stays the raw RGBuint8array that the embedders and metrics accept, and any preprocessing belongs to a wrappingDataset. -
save_to_diskwrites to the given path as is, and.embedderor.safetensorsis no longer appended to it. Code that saves under a name without a suffix and loads the file with the suffix added passes the same full file name to both calls. -
The
__file_format__class attribute is removed fromSerializerMixinand every serializable class. Subclasses outside the library drop their__file_format__. -
InMemoryImageEmbeddingStore.searchis removed. Code that searched a store by vectors callsstore.index.search(query_vectors, k)instead. -
EmbeddingStoreprotocol class declaresretrieve_top_k_similar(query_images, k)in place ofsearch(query_vectors, k). Custom stores implement the new method. -
pyvisim.image_storeis nowpyvisim.retrieval, split into the subpackagesimage_store(InMemoryImageEmbeddingStore,BruteForceIndex,HnswIndex,ExternalSearchIndex),reranking(KReciprocalReranker) anddata(Candidate), sofrom pyvisim.image_store import ...now raisesModuleNotFoundError. If your code imports frompyvisim.image_store, change the import:# before from pyvisim.image_store import ( Candidate, InMemoryImageEmbeddingStore, KReciprocalReranker, ) # after from pyvisim.retrieval.data import Candidate from pyvisim.retrieval.image_store import InMemoryImageEmbeddingStore from pyvisim.retrieval.reranking import KReciprocalReranker
-
The
vectorsparameter ofInMemoryImageEmbeddingStore.save_to_diskis renamed toembeddings. Code that passesvectors=...passesembeddings=...instead. -
Notebooks are committed without outputs. Run
make strip-notebooksbefore committing one, since the CI rejects notebooks that still carry outputs or execution metadata. -
Every
.embedderfile and image store file now names its class under"__class__", and their format versions go up by one. Files saved by 0.9.5 or earlier no longer load, so rebuild the embedder or store and save it again withsave_to_disk. -
The
__class_key__class attribute is removed fromSerializerMixinand every serializable class. Subclasses outside the library drop their__class_key__, since the class name is always stored under"__class__".
New Features
- Feature extractors can be saved on their own with
save_to_diskand loaded back withload_from_disk, as.safetensorsfiles. InMemoryImageEmbeddingStore.build_storeembeds the gallery and builds the search index. It does nothing on a store that is already built.InMemoryImageEmbeddingStore.is_builtreports whether the store has been built.
Enhancement Notes
-
The new tutorial
Custom Feature Extractor with ORBunder the classical methods shows how to write a feature extractor by inheriting fromFeatureExtractorBase, train aVLADEmbedderwith it and compare two images. -
The
tutorialsdependency group installsopencv-python-headless, which the custom feature extractor tutorial uses forORB. -
FeatureExtractorBasenow owns both halves of its serialization contract:to_dictand the newfrom_dict. Subclasses register themselves as they are defined, so a new feature extractor is rebuilt from a serialized description without being added to a hand-maintained table. Extractors that need more than their stored constructor arguments override the_from_confighook, asDeepConvFeaturedoes to rebuild its backbone by name. -
FeatureExtractorBase.from_dictforwards its keyword arguments to the_from_confighook, so a custom extractor can take objects its state cannot hold. -
A
DeepConvFeaturebuilt on a user-supplied model or a custom transform can be rebuilt by passing them back asbackbone=andtransform=. AFutureWarningis emitted if the transform differs from the saved one. -
VLADEmbedderandFisherVectorEmbeddertake afeature_extractor_paramsdict infrom_dictandload_from_disk, which is forwarded to the feature extractor. An embedder on aDeepConvFeaturewith a user-supplied model is loaded withfeature_extractor_params={"backbone": model}. -
The tutorial notebooks define their plotting helpers themselves instead of importing them from a shared module, so that a change to a helper no longer executes every notebook again.
-
OxfordFlowerDatasetreads its.matfiles withscipy.io.loadmatagain. The internal MAT-file readerpyvisim.datasets._matloaderwas removed since SciPy is a runtime dependency. -
Simplified the
[dependency-groups]inpyproject.toml:- Merged the
releasegroup intodocs, sincerenoanddulwichare only used to build the release notes pages of the documentation. - Merged
types,dead-codeandfmtinto a singlelintgroup, sincemypy,vultureandruffare all static analysis tools.
Contributors running
maketargets are unaffected. Anyone invokinguv run/uv syncwith--group release,--group types,--group dead-codeor--group fmtdirectly should use--group docsor--group lintinstead. - Merged the
-
The tutorial notebooks moved from the separate examples repository into
docs/tutorials/notebooks/, together with their plotting helpers. -
The Siamese, Triplet and VLAD/Fisher Vector tutorials train on a subset of Oxford Flowers, so that they also finish on a CPU.
-
The documentation renders every tutorial notebook as a page with its executed outputs.
-
The
Docsworkflow also builds pull requests, executes the tutorial notebooks they change and uploads the rendered HTML as thedocs-htmlartifact. -
The new
Tutorialsworkflow executes every tutorial notebook from scratch every three days and on demand. -
The clustering helper of the tutorials reports normalized mutual information under nmi instead of adjusted mutual information.
-
The image search tutorial builds its FAISS index from the embeddings of the store instead of embedding the gallery a second time.
-
The pipeline tutorial trains on every twelfth training image, which covers all 102 classes instead of the three the first 500 images belong to.
-
The Image Search and Retrieval Evaluation tutorials embed every fourth training image, and the evaluation queries every fourth validation and test image, so that they also finish on a CPU.
-
GitHub alert blocks such as > [!NOTE] in the tutorial notebooks render as admonitions in the documentation.
-
The tutorials are grouped into the numbered chapters Introduction, Classical methods, Metric learning methods and Image similarity search. Every notebook carries a single top-level heading, which the sidebar lists as
1.1 <heading>under its chapter. -
make docsrenders the tutorial notebooks as they are on disk instead of executing them.make test-notebookswrites the executed notebooks back in place, so that a followingmake docsshows their outputs.
Bug Fixes
- A
try-exceptblock is added in classOxfordFlowerDatasetso that it raises aTypeErrorwhen it is indexed with anything that is not an integer, for example a slice such asdataset[:20], instead of failing inside Pillow with anAttributeErrorabout alistobject, which made it hard to understand the cause. NumPy integers keep working as indices. - Importing
pyvisimno longer creates ares/logsfolder next to the installed package, which failed on read-only installs. from pyvisim import *works without thennextra, and submodules such aspyvisim.classicare reachable after a plainimport pyvisim.- The warning emitted when a clustering model resets an incompatible PCA is a
FutureWarningand namesraise_error_when_pca_incompatible=Trueas the way to raise instead. SIFTandRootSIFTkeep their constructor arguments when an embedder using them is saved and loaded, instead of coming back with the default arguments.Pipeline([])raises aValueErrorwhen it is built, instead of failing later insideembedwith a NumPy error.FisherVectorEmbedderraises aValueErrorfor an image that yields no descriptor, likeVLADEmbedderdoes, instead of returning a row of NaNs when that image shares a batch.top_k_mapdivides each average precision bymin(R, k), withRthe gallery images sharing the query label, instead of by the relevant images found in the topk. mAP@k values were inflated before and come out lower now.KMeans.fitrejects a feature matrix that is not 2-D or holds no sample, and a refit asks for the configured number of clusters again after SciPy dropped empty clusters on an earlier fit.- The source distribution now ships the Cython source of the PSNR kernel, so installing
pyvisimfrom it no longer fails with'pyvisim/pixelwise/_kernel/_ssd_kernel.pyx' doesn't match any files. InMemoryImageEmbeddingStore.from_dictaccepts the state returned byto_dict. Before, it only accepted a state read from a file and raisedTypeErrorotherwise.