Model reference · open weights

moda-fashion-matryoshka

Embeddings HopitAI Image embed 1 build Open weights 1k dl/mo

moda-fashion-matryoshka is an open-weight embedding model from HopitAI. moda-fashion-matryoshka (BF16) weighs 813 MB; the smallest configuration that runs it is RTX 3060 12 GB.

For self-hosting, compare this build's requirements below with the GPU you plan to rent.

  • moda-fashion-matryoshka is an image-feature-extraction model by HopitAI that uses Matryoshka Representation Learning to generate nested embeddings with selectable dimensions from 64 to 768.
  • The model is based on a ViT-B/16-SigLIP architecture with 203.2M parameters and supports English.
  • It is released under the MIT license and provides L2-normalized float32 vectors, with 256 dimensions recommended for optimal performance and index size.

Summary of the HopitAI/moda-fashion-matryoshka model card, 2026-10-01

What it is

Released byHopitAI
Released2026-05-07
VRAM813 MB for the weights

What it runs on

Memory and cards for moda-fashion-matryoshka (BF16)

813 MBweights, file size
1.1 GBruntime overhead
CardRunsMemory
RTX 3060 12 GBfits11.6 GB
RTX 4060 Ti 16 GBfits15.4 GB
RTX 3090 24 GBfits23.4 GB
RTX 4090 24 GBfits23.4 GB
RTX 5090 32 GBfits31.0 GB
L40S 48 GBfits44.0 GB
A100 80 GBfits78.2 GB
H100 80 GBfits78.1 GB
RTX PRO 6000 Blackwell 96 GBfits93.8 GB
DGX Spark (GB10) 128 GB unifiedfits107 GB
H200 141 GBfits138 GB
B200 180 GBfits176 GB

From the model card

What HopitAI says about moda-fashion-matryoshka

Read the model card

Flexible-dimension fashion embeddings — choose your own size from 64 to 768.

MODA-Fashion-Matryoshka uses Matryoshka Representation Learning to produce nested embeddings where the leading N dimensions are themselves a valid embedding. This means you can use 256-d for 3× smaller indexes with virtually no quality loss, or 64-d for 12× compression while still beating FashionSigLIP.

Highlights

  • 256-d ties 768-d on Fine R@1 (67.42 vs 67.21) — 3× index reduction for free
  • 128-d still beats FashionSigLIP-768 by +2.39 R@1 at 6× smaller index
  • 64-d matches FashionSigLIP-768 (+0.21) at 12× smaller index
  • INT8 quantization at 256-d is lossless — 12× total compression over FashionSigLIP fp32

LookBench Results by Dimension

DimBytes/vecFine R@1vs FashionSigLIP-768Index (1M imgs)
7683,07267.21+3.372.93 GB
5122,04866.75+2.911.95 GB
3841,53667.07+3.231.46 GB
2561,02467.42+3.58977 MB
12851266.23+2.39488 MB
6425664.05+0.21244 MB

Quantization at 256-d (full LookBench protocol)

PrecisionBytes/vecFine R@1Index (1M imgs)
fp321,02467.16977 MB
fp1651267.08488 MB
int825667.16244 MB
binary+rerank32+51267.29~519 MB
binary (pure)3263.5030 MB

Model Spec

PropertyValue
ArchitectureViT-B/16-SigLIP (full CLIP: vision + text)
Parameters203.2M
Embedding Dimension768 (full) or 512 / 384 / 256 / 128 / 64
Recommended Dimension256 (sweet spot: best R@1, 3x smaller index)
OutputL2-normalized float32 vector
Model Size (safetensors)~775 MB
Input Resolution224 × 224
FrameworkOpenCLIP
Precisionfloat32

Inference — Quick Start

A standalone inference.py is included in this directory. It supports dimension selection and a full sweep.

# Default: encode at 256-d (recommended)
python inference.py --image query.jpg

# Specify dimension
python inference.py --image query.jpg --dim 128

# Two images + cosine similarity at 256-d
python inference.py --image img1.jpg img2.jpg --dim 256 --similarity

# Sweep all dimensions (64 → 768) with index cost
python inference.py --image img1.jpg --sweep

# Run on GPU/MPS
python inference.py --image query.jpg --device cuda

Python API — Truncate to Any Dimension

import open_clip
import torch
import torch.nn.functional as F
from PIL import Image

model, _, preprocess = open_clip.create_model_and_transforms(
    "ViT-B-16-SigLIP",
    pretrained="path/to/moda-fashion-matryoshka/open_clip_model.safetensors",
)
model.eval()

image = preprocess(Image.open("query.jpg")).unsqueeze(0)
with torch.no_grad():
    full_emb = model.encode_image(image)      # [1, 768]

dim = 256
emb_256 = F.normalize(full_emb[:, :dim], dim=-1)  # [1, 256]

INT8 Quantization

import numpy as np

emb = model.encode_image(images)[:, :256]
emb = F.normalize(emb, dim=-1).numpy()

emb_min = emb.min(axis=1, keepdims=True)
emb_max = emb.max(axis=1, keepdims=True)
emb_int8 = np.round((emb - emb_min) / (emb_max - emb_min + 1e-8) * 255).astype(np.uint8)

Requirements

open_clip_torch>=2.20.0
torch>=2.0
Pillow
safetensors

Training Details

  • Base model: MODA-Fashion-Distilled (the 768-d distilled student)
  • Method: Matryoshka Representation Learning with 6 nested slices {64, 128, 256, 384, 512, 768}
  • Loss: Per-slice RKD-Distance + similarity mimicry against the 2048-d ensemble teacher
  • Optimizer: AdamW, LR=5e-6, batch=128
  • Epochs: 2 (best at step 1000)
  • Wall time: 255 minutes on Apple M-series (MPS)

Related Models

ModelDimFine R@1Best for
MODA-Fashion-Distilled76867.63Best overall quality
MODA-Fashion-Matryoshka (this model)64-76867.42 (256d)Flexible dim, 3x smaller index
MODA-Fashion-Vision-FP1676867.42Smallest (186 MB), edge/mobile
MODA-Fashion-Distilled-512d51267.63Compact index, highest nDCG@5

License

MIT

Citation

If you use this model, please cite:

@software{moda2026,
  title  = {MODA: Open-source benchmark and models for fashion search},
  author = {Hopit AI},
  year   = {2026},
  url    = {https://github.com/hopit-ai/Moda}
}

Quoted from the model card on Hugging Face. The full card is behind the Hugging Face link above.

How it works

How embedding models work

Your textsentence / documentEncodermaps meaningVectorlist of numbersAn embedding model turns text into a vector, so similar meanings sit close together, which is the basis of search and RAG.
© 2026 AxForge · EU-hosted AI infrastructure Pricing Docs Trust Privacy Terms