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.

Platforms: wheels exist for Windows x86-64, Linux x86-64 (manylinux), Linux aarch64 (manylinux_2_31: Raspberry Pi 3/4/5 under 64-bit Raspberry Pi OS, Ubuntu 20.04+, Graviton) and macOS arm64 (Apple Silicon, macOS 14 or later). The x86-64 wheels run on any x86-64 CPU, no AVX/AVX2 required: GGUF models load the ggml CPU library matching the machine at run time (libembedding.ggml_cpu_features() names it), and the aarch64 wheel does the same across eight ARM levels (armv8.0 to armv9.2). 32-bit ARM (armv7l) is not supported yet. On Linux, HTTPS downloads use the system CA bundle (SSL_CERT_FILE or CURL_CA_BUNDLE override it). The macOS wheel bundles its dependencies (ONNX Runtime, llama.cpp/ggml) under libembedding/.dylibs/ and uses the system libcurl.

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 and batch_size (plus workers for text, max_tokens for the reranker) for any task type:

from libembedding import autotune, autotune_unified, clear_autotune_cache_unified

# Text embedding tune (QUICK by default; ~13 s cold on an i7-1065G7, indicative)
result = autotune("BAAI/bge-small-en-v1.5")

# Unified API for any task: "embedding", "reranking", "sparse", "image"
result = autotune_unified("embedding", "BAAI/bge-small-en-v1.5")

# Objective, custom workload and constraints (reranking: last text = the query)
result = autotune_unified(
    "reranking",
    "jinaai/jina-reranker-v1-turbo-en-quantized",
    objective="latency",              # "latency" | "throughput" | "balanced" | "memory"
    texts=[*documents, query],
    max_latency_ms=300.0,             # p95 budget for one tuning call (0 = none)
    min_tokens=128,                   # reranking only: floor for max_tokens
)
# Over budget? The best unconstrained config is returned: check result.p95_latency_ms.

clear_autotune_cache_unified("reranking")   # purge one task's cache

Results are cached per model, hardware, runtime, workload, objective, mode and constraints — a repeated call returns in milliseconds. For sparse models, top_k, min_weight and storage_format are not tuned (they change the output); the result reports the model defaults. See docs/performance_tuning.md for grids, methodology and measurements.

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.12.2

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.12.2
File Actions
libembedding_ng-1.12.2-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for libembedding_ng-1.12.2-py3-none-win_amd64.whl
libembedding_ng-1.12.2-py3-none-manylinux_2_34_x86_64.whl Python 3 none Linux glibc 2.34+ x86-64 Details for libembedding_ng-1.12.2-py3-none-manylinux_2_34_x86_64.whl
libembedding_ng-1.12.2-py3-none-manylinux_2_31_aarch64.whl Python 3 none Linux glibc 2.31+ ARM64 Details for libembedding_ng-1.12.2-py3-none-manylinux_2_31_aarch64.whl
libembedding_ng-1.12.2-py3-none-macosx_14_0_arm64.whl Python 3 none macOS 14.0+ ARM64 Details for libembedding_ng-1.12.2-py3-none-macosx_14_0_arm64.whl

Total release size: 96.9 MB

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

Download URL libembedding_ng-1.12.2-py3-none-win_amd64.whl
Size 11.9 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
d2d7a379bd0ec4523442512d332af946b24858d3f098f6d5c420b8933fe0b24c
BLAKE2b-256 checksum
How to use checksums
2a324d63b919566e6bc0f1455278e4de5c34329c1ffcb870f4e3b07d578b81c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

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

Download URL libembedding_ng-1.12.2-py3-none-manylinux_2_34_x86_64.whl
Size 38.9 MB
Tags Linux glibc 2.34+ x86-64 Python 3
SHA-256 checksum
How to use checksums
4944ecfe4cdc6777a8a0548f27a1f4f5c4164767097fbae48ec02ac9157182bd
BLAKE2b-256 checksum
How to use checksums
c60966d683c3de9cfa30ca0c358c64cb71457da231af689c6640fcb15a608359
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / libembedding_ng-1.12.2-py3-none-manylinux_2_31_aarch64.whl

Download URL libembedding_ng-1.12.2-py3-none-manylinux_2_31_aarch64.whl
Size 30.2 MB
Tags Linux glibc 2.31+ ARM64 Python 3
SHA-256 checksum
How to use checksums
724e1034fcbceb3253857ee9968719662839aa2eea39eb136c7d35207640d852
BLAKE2b-256 checksum
How to use checksums
9509b19ad4c61ccc68b628713c0d0e9c3f03dbfe9d0e35e115aa4185c4f44d0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / libembedding_ng-1.12.2-py3-none-macosx_14_0_arm64.whl

Download URL libembedding_ng-1.12.2-py3-none-macosx_14_0_arm64.whl
Size 15.9 MB
Tags Python 3 macOS 14.0+ ARM64
SHA-256 checksum
How to use checksums
479ee5d60ab8cfb41ed446f0137efa3e3d47c8b48b6d594c7170ea7aa2de990d
BLAKE2b-256 checksum
How to use checksums
7b5d50fa58806f44c7bc343a3fe261b6a6abc0d77f1487250a52f314e08b53b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for libembedding-ng 1.12.2

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