Repository navigation
Matching: opt-in crop detection via SSCD embeddings - #538
Merged
Merged
Conversation
- matching/embeddings.py: SSCD (MIT) embeddings via onnxruntime (optional
extra "embeddings", lazy import), model downloaded on demand into a cache
dir with SHA-256 verification or given by path, SQLite embedding cache,
brute force cosine search, EmbeddingStage (pipeline option, default off)
adding MatchReason.EMBEDDING matches ("crop/embedding similarity 0.xx")
- crop relations per group (DuplicateGroup.crops/has_crops): crop and source
go to review, rank_crops_first as default ranking hint
- tools/export_sscd_onnx.py: export of the official TorchScript model
- matching/crop_benchmark.py: generated crops of tests/images, recall
21.8% -> 100% at 100% precision
- docs, TODO, AGENTS.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the owner decision "AI embeddings to catch crops: yes" for the experimental matching pipeline (
py_image_dedup/matching/, not wired in).Changes
matching/embeddings.pyOnnxEmbeddingExtractor: SSCD (sscd_disc_mixup, Meta, MIT) viaonnxruntimeon the CPU.onnxruntimeis a new optional extra (embeddings) and is imported lazily, the package works without it.ensure_model(): downloads the model on demand into$PY_IMAGE_DEDUP_MODEL_CACHE(default~/.cache/py-image-dedup/models) and verifies its SHA-256. A model can also be given by path. The model is not bundled in the repo or the Docker image.EmbeddingStore: SQLite cache, invalidated by size, mtime and model id.find_similar_pairs(): brute force cosine similarity search with numpy, block-wise.EmbeddingStage: pipeline option, default off. It matches only pairs the hash stages did not match, asMatchReason.EMBEDDINGwith the notecrop/embedding similarity 0.xxand confidence 0.50 .. 0.75. The burst veto applies.DuplicateGroup.crops,has_crops): the largest member is the reference. Members that reach it through same-framing hash matches show the full frame. All other members are crops. This is needed because a pairwise "fewer pixels" check confuses a crop with a downscaled messenger copy.rank_crops_first()is the default ranking hint. Groups with crops are review-only.models.py/pipeline.py: minimal hooks (MatchReason.EMBEDDING,Match.embedding_similarity,CropRelation,MatchingPipeline(embedding_stage=...),annotate_cropsafter clustering).tools/export_sscd_onnx.py: exports the official TorchScript release to ONNX. Needs PyTorch in a throw-away venv. It checks the SHA-256 and compares the onnxruntime output with the PyTorch output.matching/crop_benchmark.py: generates crops oftests/imagesin a temp dir (none are committed) and compares the pipeline with and without the embedding stage.docs/matching-prototype.md, plus updates to TODO.md and AGENTS.md.Model source
The default download is
nutszebra/sscd_onnxon Hugging Face, pinned to revision0f03b67with its sha256. It is a third-party ONNX export of Meta's official file (dl.fbaipublicfiles.com, sha2569f26bd4c...). I verified that its embeddings match my own export from the official file (max abs diff 1e-7). That repo has no license tag, but the weights themselves are MIT. For production, prefer a local export withtools/export_sscd_onnx.pyand pass the file by path.Benchmark (tests/images + 21 generated crops: 10/25/40 %, square, 16:9, portrait, corner crop as a messenger copy)
Tests
poetry run pytest: 188 passed, 1 skipped. The Docker build passes; the image does not include the extra.🤖 Generated with Claude Code