Skip to main content

mantissa-embed

License Python Base Engine

Learning what "similar" means, with a C engine. A classifier answers which class; an embedder answers how alike — it maps each image to a point in a vector space where same-thing images land close together and different-thing images land far apart. That single geometry powers similarity search, verification ("are these two the same?") and retrieval ("show me the nearest matches"), for classes the model was never trained to name.

mantissa-embed trains that embedding with metric learning — the contrastive and triplet losses — on top of a mantissa-cnn trunk: its Conv2D / MaxPool2D / Flatten / Dense layers, its mantissa C-engine and pure-numpy backends, and its dataset loaders are reused, not reimplemented. This package adds only what metric learning needs on top of a classifier: the two losses, an Embedder that trains a trunk with them, and the four things embeddings buy you — fit / embed / retrieve / verify.

The mantissa family

Part of the mantissa family: a low-precision engine written in C, with small Python packages built on top. Each package sits under the one it depends on — ⭐ marks where you are, and every other name links to its repo.

  • mantissa — low-precision neural-network engine in C (the core)
    • mantissa-perceptron — perceptron & ADALINE, the linear classics
    • mantissa-nn — shared neural-net primitives (layers, engine binding)
      • mantissa-cnn — convolutional networks for images
        • mantissa-auto-encoder — autoencoders for denoising & super-resolution
        • mantissa-interpret — CNN interpretability (occlusion, saliency, Grad-CAM)
        • ⭐ mantissa-embed — CNN metric learning (image embeddings for similarity & retrieval) (you are here)
      • mantissa-mlp — multilayer perceptrons, fully-connected nets

New to metric learning?

A classifier learns a fixed set of labels and a decision boundary between them. Metric learning learns something more basic and more reusable: a distance. It trains the network so that the Euclidean distance between two images' embeddings is a measure of how similar they are — and it does that using only the relation between examples ("these two are the same kind", "these two are not"), never a class name. Two consequences follow:

  • It generalizes to classes it never trained on. Because the loss only ever says "closer" or "farther", a model trained on some identities produces useful distances for identities it has never seen — the basis of face verification, where you cannot retrain for every new person.
  • One embedding serves many tasks. Compute it once per image, then: verify by thresholding a distance, retrieve by nearest-neighbour search, cluster by feeding the vectors to any clustering method.

Two classic losses do the training, and this package implements both:

  • Contrastive loss works on pairs. A same-class pair pays its squared distance (pulled together); a different-class pair pays a hinge that is zero once the pair is at least a margin apart (pushed apart, but only until far enough) — Hadsell, Chopra & LeCun (2006), "Dimensionality Reduction by Learning an Invariant Mapping", CVPR.
  • Triplet loss works on triples of (anchor, positive, negative). It asks only that the negative be farther from the anchor than the positive, by at least a margin — a relative constraint, which is often easier to satisfy and to scale than pinning absolute distances — Schroff, Kalenichenko & Philbin (2015), "FaceNet: A Unified Embedding for Face Recognition and Clustering", CVPR.

A Siamese/triplet network is just one network run more than once. The two legs of a pair (or three of a triplet) share the same weights, so there is no second network to manage: stack the legs into one batch, run a single forward pass, compute the loss and its per-row gradient on the resulting embeddings, and backpropagate that gradient through the one trunk. That is exactly what Embedder.fit does — the same custom forward/loss/backward loop the rest of the family uses, with a metric loss where the classifier's softmax would be.

Install

pip install mantissa-embed

Pulls in mantissa-cnn >= 0.2.2 (and transitively mantissa-nn + the mantissa-core engine). For the demo's plots, pip install mantissa-embed[viz].

From checkouts (works today, no PyPI needed): clone this repo, cnn, mantissa-nn and mantissa side by side, build the engine (make dist there), then here:

pip install -e ../mantissa -e ../mantissa-nn -e ../cnn && pip install -e ".[viz]"

mantissa-cnn finds the sibling engine checkout automatically, and its dataset loaders find a data/ directory via MANTISSA_CNN_DATA (the demo points this at the sibling cnn/data/ for you).

Quickstart

# datasets are mantissa-cnn's; nothing downloads implicitly — fetch once:
python -m mantissa_cnn.datasets download mnist
from mantissa_cnn import datasets
from mantissa_embed import Embedder, models

Xtr, ytr, Xte, yte = datasets.subset("mnist", 6000, 2000, seed=0)

emb = Embedder(models.small_cnn_embedder(embed_dim=16), loss="triplet")  # or "contrastive"
emb.fit(Xtr, ytr, epochs=8, batch_size=64, lr=0.05, verbose=True)

Z = emb.embed(Xte)                       # (2000, 16) embedding vectors
idx, dist = emb.retrieve(Xte[0], Z, k=5) # 5 nearest test images to query 0
same = emb.verify(Xte[0], Xte[1], threshold=1.0)   # same identity? (bool)

Or compose your own trunk from mantissa-cnn's layers — any Conv/Pool/Flatten stack ending in Dense(embed_dim, act="identity"):

from mantissa_cnn import Conv2D, MaxPool2D, Flatten, Dense
from mantissa_embed import Embedder

emb = Embedder(
    [Conv2D(16, 3, pad=1), MaxPool2D(2), Flatten(), Dense(32)],  # 32-D embedding
    loss="contrastive", margin=1.0, seed=0)

The API

Embedder(layers, loss="triplet"|"contrastive", margin=None, seed=0, backend="mantissa"), then:

method does returns
fit(X, y, epochs, batch_size, lr, verbose) trains the trunk by metric learning; y only decides same/different self (history_["loss"] per epoch)
embed(X) one forward pass, chunked (n, embed_dim) embeddings
retrieve(query, gallery, k) k nearest gallery items in embedding space (numpy argpartition, no sklearn) (indices, distances), nearest-first
verify(a, b, threshold=None) embedding distance between a and b; with threshold, a boolean same/different distance, or bool

retrieve and verify accept raw images or a pre-computed (., embed_dim) matrix, so a fixed gallery is embedded once and reused across queries.

Deliberately minimal, like the rest of the family: NCHW float32 images, plain SGD, the two classic losses, plain Euclidean distances. No autograd graph, no optimizer zoo, no ANN index. The trunk's convolutions run in C on zero-copy float32 buffers; the losses are memory-bound reductions over embedding vectors and honestly stay in numpy (mantissa_embed.losses, importable and gradient- checked on their own). Layers allocate scratch once per batch shape and reuse it.

Results

A small_cnn_embedder (52,528 params, 16-D embedding) trained on a 6k-image MNIST subset with the triplet loss and the mantissa C engine (8 epochs, triplet loss 0.090 → 0.016), then embedding the held-out 2k test set. Reproduce with python examples/embeddings_demo.py.

The embedding separates the digits with no label ever entering the loss — colour is the true digit, shown only for the plot:

MNIST test embeddings, 2-D PCA, coloured by true digit — visible per-digit clusters

And nearest-neighbour retrieval returns same-digit images (green border = a correct match, i.e. the neighbour's true digit equals the query's):

retrieval gallery: five query digits, each with its five nearest neighbours in embedding space

License

MIT — © Tekin Ertekin. Base package: mantissa-cnn; engine: mantissa — same author, MIT.

Metadata

Release files for mantissa-embed 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mantissa-embed 0.1.0
File Size Uploaded Provenance
mantissa_embed-0.1.0.tar.gz 16.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mantissa-embed 0.1.0
File Interpreter ABI Platform
mantissa_embed-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.0 kB

Release files / mantissa_embed-0.1.0.tar.gz

Download URL mantissa_embed-0.1.0.tar.gz
Size 16.5 kB
Tags Source
SHA-256 checksum
How to use checksums
51ab79c82f9365b6da0a1eae2c87eb96634e0e9abec9cd74dbe044adb43f31d0
BLAKE2b-256 checksum
How to use checksums
756ce830f32a4cd0a316bdca777bbe415743e043304e839b88b903ee1426b85c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Release files / mantissa_embed-0.1.0-py3-none-any.whl

Download URL mantissa_embed-0.1.0-py3-none-any.whl
Size 14.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
df931e052c87d423e780b779ff773dc63088c77426287ad414ddee2b776cb26d
BLAKE2b-256 checksum
How to use checksums
5ab018ae1100690bdcbff8ae61bf2c55ac6584c0ba11ec67458b5e9ca43a9755
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Security for mantissa-embed 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mantissa_embed-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page