Skip to main content

libembedding

Forked from pacifio/libembedding. This fork adds Windows support (native DLL), PyPI packaging under the name libembedding-ng, local model loading, runtime introspection, similarity helpers, streaming, a multi-worker pool, an autotuner and automatic model selection. Imported as libembedding.

Fast ONNX-based text, image, and sparse embeddings for Python. Dynamic INT8 ONNX models are ~4x smaller, ~2x lighter in memory and ~1.7-2.0x faster than FP32 on CPU (measured; see Benchmarks below).

Built on a C/C++ backend using ONNX Runtime, exposed to Python via zero-overhead cffi bindings. The wheel bundles the compiled shared library (libembedding.so / .dylib / .dll) together with ONNX Runtime and libcurl, so no system ONNX Runtime install is required at runtime. Supports 44 text embedding models, 5 image models, 2 sparse models, and 4 rerankers with automatic model downloading from HuggingFace Hub.

Installation

pip install libembedding-ng

The PyPI package is named libembedding-ng (to avoid clashing with the original libembedding on PyPI); it is imported as libembedding. The wheel already bundles the native shared library and ONNX Runtime, so no separate system install is required.

Requirements: ONNX Runtime must be installed on your system only if you build the package from source.

# macOS
brew install onnxruntime

# Ubuntu/Debian
apt install libonnxruntime-dev

# Or set ONNXRUNTIME_ROOT to your installation path

Quick Start

Text Embeddings

from libembedding import TextEmbedding

model = TextEmbedding("BAAI/bge-small-en-v1.5")
embeddings = model.embed(["Hello world", "How are you?"])

print(embeddings.shape)  # (2, 384)
print(embeddings.dtype)  # float32

Sparse Embeddings

from libembedding import SparseTextEmbedding

model = SparseTextEmbedding()
results = model.embed(["machine learning algorithms"])

for r in results:
    print(r.indices.shape, r.values.shape)

Image Embeddings

from libembedding import ImageEmbedding

model = ImageEmbedding()
embeddings = model.embed_files(["photo.jpg", "diagram.png"])

Reranking

from libembedding import Reranker

reranker = Reranker("BAAI/bge-reranker-base")
results = reranker.rerank(
    "What is deep learning?",
    [
        "Deep learning uses neural networks with many layers",
        "The weather is sunny today",
        "Neural networks are inspired by biological brains",
    ],
)
for r in results:
    print(f"doc[{r.index}] score={r.score:.4f}")

Model Discovery

import libembedding

for m in libembedding.list_text_models():
    print(f"{m.model_name:45} dim={m.dim:<5} {m.pooling}")

API Reference

Provider

TextEmbedding(
    model_name="BAAI/bge-small-en-v1.5",  # HuggingFace model name, repo code, or local dir path
    provider="cpu",  # "cpu", "cuda", "coreml", "directml", "tensorrt", "llamacpp"
    device_id=0,
    cache_dir=None,  # None = ~/.cache/libembedding
    max_length=0,  # 0 = model default
    threads=0,  # 0 = auto
    batch_size=256,  # internal batch size for embedding
    offline=False,  # True = use cache only, never download
    show_download_progress=True,
    dim=0,  # embedding dim for local models without config.json
    pooling="mean",  # "cls" or "mean" for local models
    num_threads=0,  # deprecated, use threads
)
Method Returns Description
embed(texts, batch_size=None) np.ndarray (n, dim) L2-normalized dense embeddings
embed_stream(texts, batch_size=None) generator Yields one embedding at a time (low memory)
dim int Embedding dimension
name str Model name or local path
info() ModelDesc Runtime model descriptor
max_length() int Max token length for the model
stats() Stats Runtime statistics (texts, batches, latency)
close() None Release resources
from_gguf(repo, filename=None, provider="llamacpp", ...) TextEmbedding Load a GGUF model from HuggingFace (requires llama.cpp build)
supports_llamacpp() bool (static) Check if llama.cpp backend is available

SparseTextEmbedding

SparseTextEmbedding(model_name="prithvida/SPLADE_PP_en_v1", ...)
Method Returns Description
embed(texts, batch_size=0) list[SparseEmbedding] Sparse vectors with .indices and .values
embed_stream(texts, batch_size=None) generator Yields one embedding at a time
dim int Embedding dimension (0 = dynamic)
name str Model name or local path
info() ModelDesc Runtime model descriptor
max_length() int Max token length
stats() Stats Runtime statistics

ImageEmbedding

ImageEmbedding(model_name="Qdrant/clip-ViT-B-32-vision", ...)
Method Returns Description
embed_files(paths, batch_size=0) np.ndarray (n, dim) Embed from file paths
embed_bytes(images, batch_size=0) np.ndarray (n, dim) Embed from raw bytes
dim int Embedding dimension
name str Model name or local path
info() ModelDesc Runtime model descriptor
stats() Stats Runtime statistics

Reranker

Reranker(model_name="BAAI/bge-reranker-base", ...)
Method Returns Description
rerank(query, documents, batch_size=0) list[RerankResult] Sorted by score descending
name str Model name or local path
info() ModelDesc Runtime model descriptor
max_length() int Max token length
stats() Stats Runtime statistics

All classes support context managers (with TextEmbedding(...) as model:).

Similarity Functions

from libembedding import cosine_similarity, dot_product, euclidean_distance
import numpy as np

a = np.array([1.0, 2.0, 3.0], dtype=np.float32)
b = np.array([1.0, 2.0, 3.0], dtype=np.float32)

print(cosine_similarity(a, b))  # 1.0 (identical)
print(dot_product(a, b))  # 14.0
print(euclidean_distance(a, b))  # 0.0

Streaming Embeddings

Process large document sets without allocating a single result array:

from libembedding import TextEmbedding

with TextEmbedding("BAAI/bge-small-en-v1.5") as model:
    for embedding in model.embed_stream(["doc1", "doc2", ...], batch_size=32):
        # Each iteration yields a single (dim,) numpy array
        process(embedding)

Runtime Statistics

with TextEmbedding("BAAI/bge-small-en-v1.5") as model:
    model.embed(["text 1", "text 2", "text 3"])
    stats = model.stats()
    print(
        f"Embedded {stats.texts_embedded} texts "
        f"({stats.batches_run} batches), "
        f"avg latency {stats.avg_latency_ms:.2f}ms"
    )

Data Types

ModelDesc — runtime model descriptor (returned by info()):

Field Type Description
name str Model name or local path
dimension int Embedding dimension
max_length int Max token length
pooling str "cls" or "mean"
num_threads int Threads configured
batch_size int Batch size configured
provider str Execution provider ("cpu", "cuda", "directml", "coreml", "llamacpp")
device_id int Device ID

Stats — runtime statistics (returned by stats()):

Field Type Description
texts_embedded int Total texts processed
batches_run int Total ONNX inference batches
avg_latency_ms float Average milliseconds per embed call

Local Model Loading

from libembedding import TextEmbedding

# Load from a local directory containing model.onnx + tokenizer.json (+ config.json)
model = TextEmbedding("/path/to/model_dir")

Available Models

44 text models including BGE, MiniLM, Nomic, E5, CLIP, Jina, GTE, Snowflake, ModernBERT (with quantized variants).

6 image models including CLIP ViT-B/32 (FP32 + INT8 quantized), ResNet-50, Unicom, Nomic Vision.

2 sparse models: SPLADE++, BGE-M3.

5 reranker models: BGE Reranker, Jina Reranker (including INT8 quantized variant).

GGUF/llama.cpp models: Run quantized GGUF models (Q4_K_M, Q8_0) via the llama.cpp backend.

Benchmarks

Comparison with fastembed — withdrawn

An earlier version of this file published a table claiming libembedding is 6.5-8.6x faster than fastembed, stated as "measured on Apple M-series". It has been removed. All four measurement harnesses hardcoded "platform": "macOS arm64" in their output, so no run could be traced to a machine, and the maintainer has no Mac to reproduce it on. The harnesses now report the real platform. See docs/archive/benchmarks/cross-implementation-macos-claim/ for the withdrawn figures and the reasoning.

Treat any cross-implementation speed claim about libembedding as unsubstantiated until it is re-measured on an identified machine.

Quantization — measured and reproducible

The quantization benchmark in the main README reports its full environment (CPU, ONNX Runtime version, execution provider) and reads the weight dtypes from the ONNX files, so its provenance is verifiable.

Unified Auto-Tuning

Auto-tune threads, batch_size, and workers for any task type:

from libembedding import (
    autotune,
    autotune_unified,
    LEMBED_TASK_RERANKING,
    LEMBED_AUTOTUNE_QUICK,
    LEMBED_AUTOTUNE_FULL,
)

# Quick text embedding tune (5-15s)
result = autotune("BAAI/bge-small-en-v1.5", LEMBED_AUTOTUNE_QUICK)

# Unified API for any task type
result = autotune_unified(
    task=LEMBED_TASK_RERANKING,
    model_name="BAAI/bge-reranker-base",
    mode=LEMBED_AUTOTUNE_QUICK,
)

Results are cached by hardware fingerprint — subsequent runs load instantly.

Error Handling

from libembedding import LembedError, LlamaError
from libembedding.exceptions import (
    ModelNotFoundError,
    OnnxRuntimeError,
    DownloadError,
)

try:
    model = TextEmbedding("nonexistent/model")
except ModelNotFoundError as e:
    print(f"Model not found: {e.detail}")
except LlamaError as e:
    print(f"llama.cpp error: {e.detail}")
except LembedError as e:
    print(f"Error [{e.status_code}]: {e.message}")

GGUF Models (llama.cpp)

Load quantized GGUF models:

from libembedding import TextEmbedding

# Check llama.cpp availability
if TextEmbedding.supports_llamacpp():
    model = TextEmbedding.from_gguf(
        repo="Xenova/all-MiniLM-L6-v2-GGUF",
        filename="all-MiniLM-L6-v2-Q4_K_M.gguf",
        provider="llamacpp",
    )
    embeddings = model.embed(["Hello world"])

Configuration

Environment Variable Purpose
LIBEMBEDDING_CACHE_DIR Override model cache directory
FASTEMBED_CACHE_DIR Alternative cache dir (fastembed compatibility)
HF_ENDPOINT Custom HuggingFace Hub endpoint

Building & Publishing

Prerequisites

pip install build twine

Build the shared library + wheel

cd python/

# Step 1: Build the C/C++ shared library and copy it into the package
./setup.sh --build-only

# Step 2: Build sdist and wheel
python -m build

This produces files in dist/ (versions follow the libembedding-ng package, e.g. 1.4.0):

dist/
  libembedding_ng-1.1.1.tar.gz                                # source distribution
  libembedding_ng-1.1.1-cp39-abi3-manylinux_2_28_x86_64.whl  # platform wheel (bundles libembedding.so + onnxruntime)

Upload to PyPI

# Upload to TestPyPI first to verify
twine upload --repository testpypi dist/*

# Install from TestPyPI to verify
pip install --index-url https://test.pypi.org/simple/ libembedding

# Upload to production PyPI
twine upload dist/*

One-liner (build + upload)

./setup.sh --build-only && python -m build && twine upload dist/*

Platform-specific wheels

The wheel is platform-tagged (e.g. manylinux, macosx, win_amd64) because it bundles the compiled shared library (libembedding.so / .dylib / .dll) along with ONNX Runtime and libcurl. python -m build produces a wheel for the current build platform. To build wheels for other platforms, build on that platform or use cibuildwheel:

# macOS (current arch)
./setup.sh --build-only
python -m build

# For other platforms, build on that platform or use cibuildwheel:
pip install cibuildwheel
cibuildwheel --platform linux   # builds manylinux wheels
cibuildwheel --platform macos   # builds macOS wheels

License

MIT

Metadata

Release files for libembedding-ng 1.10.1

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

Built distributions (wheels)

Table of built distributions (wheels) for libembedding-ng 1.10.1
File Interpreter ABI Platform Actions
libembedding_ng-1.10.1-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for libembedding_ng-1.10.1-py3-none-win_amd64.whl
libembedding_ng-1.10.1-py3-none-manylinux_2_34_x86_64.whl Python 3 none Linux glibc 2.34+ x86-64 Details for libembedding_ng-1.10.1-py3-none-manylinux_2_34_x86_64.whl
libembedding_ng-1.10.1-py3-none-macosx_14_0_universal2.whl Python 3 none macOS 14.0+ universal2 (ARM64, x86-64) Details for libembedding_ng-1.10.1-py3-none-macosx_14_0_universal2.whl

Total release size: 36.0 MB

Release files / libembedding_ng-1.10.1-py3-none-win_amd64.whl

Download URL libembedding_ng-1.10.1-py3-none-win_amd64.whl
Size 6.8 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
fcae870d364149275ecec5f7785d5978cddbb22ae5e113a643e4b9d878f11036
BLAKE2b-256 checksum
How to use checksums
3f0a119dd6e70a3e88e61fe414d0f0adf30a1582bafbfef71a261af616d7fdd3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / libembedding_ng-1.10.1-py3-none-manylinux_2_34_x86_64.whl

Download URL libembedding_ng-1.10.1-py3-none-manylinux_2_34_x86_64.whl
Size 22.0 MB
Tags Linux glibc 2.34+ x86-64 Python 3
SHA-256 checksum
How to use checksums
09b7eac81e314e02dee56f0a59248e2cdde85f3c8fc15f67b4f222fe538e1ad8
BLAKE2b-256 checksum
How to use checksums
10e71b072088ebe389da8a735e1e6bb576b5b05b85d02734e42354c93b2c15cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / libembedding_ng-1.10.1-py3-none-macosx_14_0_universal2.whl

Download URL libembedding_ng-1.10.1-py3-none-macosx_14_0_universal2.whl
Size 7.2 MB
Tags Python 3 macOS 14.0+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
c79d774a79919e472444aeb1fe9c3248824e5a60f2f6eaa3c58a249040d1d92e
BLAKE2b-256 checksum
How to use checksums
f4b63f4cd1edda7e8be0f1c3e8e325298cebec1b765a28b31395d5cff610c7e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for libembedding-ng 1.10.1

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

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