Repository navigation
eeANE 1.3.0
eeANE 1.3.0 teaches the ModernBERT compile backend to read the pooling a model actually declares. Until now it baked mean pooling into every embedding graph, so a ModernBERT embedding model that uses CLS pooling was compiled with the wrong pooling — and, worse, it looked fine: the accuracy self-check compares the compiled artifact against eeANE's own reading of the same model, so both sides made the same mistake and agreed with each other. The BERT and XLM-RoBERTa backends had read the declaration since they were added; ModernBERT now does too.
If you serve ModernBERT models that use mean pooling (ruri-v3 and friends), nothing about their output changes — this was verified by reproducing the pre-change comparison against sentence-transformers to the eighth decimal place. What changes is that a family of models that could not be compiled correctly now can be.
Pooling is detected, not assumed
eeane compile reads 1_Pooling/config.json from the model directory before it loads any weights, compiles the matching graph, and prints which pooling it picked:
kind / buckets : embedding / 128, 512, 1024
pooling : cls
An embedding model that does not declare a supported pooling mode is now rejected with an error rather than compiled on a guess. A wrongly-pooled artifact returns plausible-looking vectors that mean something else, which is a worse outcome than a failed compile. If you hit this on a model you expect to work, check that it ships the sentence-transformers pooling module; Troubleshooting in the README covers it.
The resolved pooling is also recorded in the artifact metadata and in model_info.json, and a cached variant whose recorded pooling no longer matches what the model declares is reconverted instead of silently reused.
Rerankers are unaffected: their pooling belongs to the model's own classification head, not to a sentence-transformers module.
Five newly verified models
All five declare CLS pooling and could not be compiled correctly before this release. Each compiles with a single eeane compile <HF ID>, passed its self-check with unchanged thresholds, and had its output compared against the reference sentence-transformers implementation on an M2 Mac (per-text cosine 0.99976–0.99999869, Neural Engine placement 98.0–98.9%):
- ibm-granite/granite-embedding-small-english-r2 — 47M, 384 dimensions, about 2 ms warm for a 128-token request
- ibm-granite/granite-embedding-english-r2 — 149M, 768 dimensions
- ibm-granite/granite-embedding-97m-multilingual-r2 — 97M, 384 dimensions
- ibm-granite/granite-embedding-311m-multilingual-r2 — 311M, 768 dimensions
- Alibaba-NLP/gte-modernbert-base — 149M, 768 dimensions
The verified catalogue grows from 46 to 51 models. The Verified models table in the README lists them all.
Verification
- 961 tests pass, up from 928. The new ones cover pooling detection, every way the declaration can be unreadable, wrapper selection, the FP32 baseline following the detected pooling, and a full conversion of a synthetic CLS-pooling model.
- Seven previously verified ModernBERT models were recompiled: every embedding model resolved to mean pooling as declared, and the default configuration passes its end-to-end server verification with a rerank median of 5.629 s, in line with previous releases.
- Eight models were served at once, with each one's HTTP responses matched against direct Core ML inference (cosine 1.00000000).
Install
uv tool install eeane
Full changelog: v1.2.0...v1.3.0