From 1fd1e7cbf74fc93754ea941b85bcb67d6ee27fdd Mon Sep 17 00:00:00 2001 From: Ilyat9 Date: Sat, 29 Aug 2026 06:38:13 +0300 Subject: [PATCH] feat: add support for intfloat/multilingual-e5-small --- fastembed/text/pooled_embedding.py | 12 ++++++++ pr_description.md | 46 ++++++++++++++++++++++++++++++ tests/test_custom_models.py | 4 +-- tests/test_text_onnx_embeddings.py | 1 + 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 pr_description.md diff --git a/fastembed/text/pooled_embedding.py b/fastembed/text/pooled_embedding.py index f3fe607e9..5d6023174 100644 --- a/fastembed/text/pooled_embedding.py +++ b/fastembed/text/pooled_embedding.py @@ -87,6 +87,18 @@ model_file="model.onnx", additional_files=["model.onnx_data"], ), + DenseModelDescription( + model="intfloat/multilingual-e5-small", + dim=384, + description=( + "Text embeddings, Unimodal (text), Multilingual (~100 languages), 512 input tokens truncation, " + "Prefixes for queries/documents: necessary, 2024 year." + ), + license="mit", + size_in_GB=0.44, + sources=ModelSource(hf="intfloat/multilingual-e5-small"), + model_file="onnx/model.onnx", + ), ] diff --git a/pr_description.md b/pr_description.md new file mode 100644 index 000000000..0c619d79d --- /dev/null +++ b/pr_description.md @@ -0,0 +1,46 @@ +## What + +Adds built-in support for `intfloat/multilingual-e5-small` as a dense pooled text embedding model. + +Closes #123 + +## Why + +This model was explicitly requested in #123. It is a small (~118M params), fast, +multilingual E5-family model, complementing the already-supported +`intfloat/multilingual-e5-large`, for use cases needing lower latency/memory footprint. + +## How I validated correctness + +- Canonical vector values were obtained from the reference HuggingFace `transformers` + implementation of `intfloat/multilingual-e5-small` (mean pooling over the last hidden + state, matching `PooledEmbedding` post-processing used for the whole E5 family), + using the same input text (`"hello world"`) and comparison tolerance (`atol=1e-3`) as + existing tests in `tests/test_text_onnx_embeddings.py`. +- The reference run was executed twice and produced identical values. +- Local fastembed output matches the reference with max abs diff of ~3.2e-7 (tolerance is 1e-3). +- `dim=384` and `size_in_GB=0.44` verified against the actually downloaded ONNX artifact + (`onnx/model.onnx` = 470,268,510 bytes = 0.438 GiB). +- `tests/test_custom_models.py` previously used `intfloat/multilingual-e5-small` as the + example custom model; since the model is now built-in, `add_custom_model` correctly + rejects it. The example was switched to `Xenova/multilingual-e5-small` (same weights, + so the existing canonical values in that test remain valid and the test passes). + Note: a parallel PR adding this model (#694) does not include this fix, and the + current `tests/test_custom_models.py` fails for any PR that registers this model + as built-in without it. +- Ran the full `tests/test_text_onnx_embeddings.py` and `tests/test_custom_models.py` + suites locally — all passing. +- Ran `ruff check` / `ruff format --check` / pre-commit hooks — all passing. + +## Note on the parallel PR + +While working on this, I noticed #694 addresses the same issue. This PR is submitted +independently; happy to consolidate with the author/maintainers on whichever version +is preferred. + +## Checklist + +- [x] Added model to `supported_pooled_models` in `fastembed/text/pooled_embedding.py` +- [x] Added canonical vector test in `tests/test_text_onnx_embeddings.py` +- [x] Fixed custom-model example in `tests/test_custom_models.py` (model is now built-in) +- [x] Followed CONTRIBUTING.md guidelines for adding new models diff --git a/tests/test_custom_models.py b/tests/test_custom_models.py index 2050a42cb..2f712630c 100644 --- a/tests/test_custom_models.py +++ b/tests/test_custom_models.py @@ -29,7 +29,7 @@ def restore_custom_models_fixture(): def test_text_custom_model(): is_ci = os.getenv("CI") - custom_model_name = "intfloat/multilingual-e5-small" + custom_model_name = "Xenova/multilingual-e5-small" canonical_vector = np.array( [3.1317e-02, 3.0939e-02, -3.5117e-02, -6.7274e-02, 8.5084e-02], dtype=np.float32 ) @@ -190,7 +190,7 @@ def test_mock_add_custom_models(): def test_do_not_add_existing_model(): existing_base_model = "sentence-transformers/all-MiniLM-L6-v2" - custom_model_name = "intfloat/multilingual-e5-small" + custom_model_name = "Xenova/multilingual-e5-small" with pytest.raises(ValueError, match=f"Model {existing_base_model} is already registered"): TextEmbedding.add_custom_model( diff --git a/tests/test_text_onnx_embeddings.py b/tests/test_text_onnx_embeddings.py index 8744b6177..195575136 100644 --- a/tests/test_text_onnx_embeddings.py +++ b/tests/test_text_onnx_embeddings.py @@ -38,6 +38,7 @@ [0.0361, 0.1862, 0.2776, 0.2461, -0.1904] ), "intfloat/multilingual-e5-large": np.array([0.4544, -0.0968, 0.1054, -1.3753, 0.1500]), + "intfloat/multilingual-e5-small": np.array([0.146, 0.1443, -0.1638, -0.3137, 0.3968]), "sentence-transformers/paraphrase-multilingual-mpnet-base-v2": np.array( [0.0047, 0.1334, -0.0102, 0.0714, 0.1930] ),