超小型な多言語ベクトル検索モデル Bekko Embedding を公開
昨今、ベクトル(文章埋め込み)モデルは性能向上とともにサイズも巨大になってきました。総パラメータ数が100M〜600Mの多言語モデルでは、EmbeddingGemma、Granite Embedding R2 311M、gte-multilingual-base、BGE-M3、Arctic Embed などがあります。さらに大きなモデルとしてLLMを基盤にした Nemotron-3-Embed-8B、Qwen3-Embedding-8B、pplx-embed-v1-4b など、数Bのモデルも出てきました。十分な速度で動かせるGPU環境があるなら、こうした大きな高性能モデルを使うと良いですね。
ただ、自分が興味を持ったのは巨大な高性能化とは反対の、どこまで小型にできるかというアプローチです。実際の検索に使える性能を残したまま、どこまで小さくできるのか。そこで作ってみたのが Bekko Embedding です。 bekko-embedding-v1-a8m と bekko-embedding-v1-a25m の2モデルでMITライセンスで公開しています。以下では短く bekko-a8m、bekko-a25m と表記します。
小さい方(a8m)のモデルは、Active Parameters(AP)がわずか 7.67Mです。APとはトークン埋め込み参照テーブルを除いた、Transformer演算で使う重みの部分のパラメータです。検索性能も公式の MMTEB Multilingual v2 に含まれる18の検索タスクでは平均スコアをa8m では56.2を記録し、APが約3〜40倍ある multilingual-e5 系の全モデルと BGE-M3 を上回りました。またよりパラメータが大きい bekko-a25m はより良いスコアを出しています。

| bekko-embedding-v1-a8m | bekko-embedding-v1-a25m | |
|---|---|---|
| Active Parameters | 7.67M | 24.93M |
| 総パラメータ数 | 106M | 123M |
| 出力次元 | 384 (→ 256 / 128 / 64) | 384 (→ 256 / 128 / 64) |
| 最大入力長 | 8,192トークン | 8,192トークン |
| MMTEB Multilingual v2、検索18タスク | 56.2 | 57.5 |
| MMTEB Multilingual v2、全131タスク | 56.7 | 58.3 |
| CPUスループット (Ryzen 9 7950X、OpenVINO) | 364 docs/s | 134 docs/s |
| 軽量 ONNX ファイル | 124 MiB | 190 MiB |
| query / document prefix | なし | なし |
インストールせずに試すこともできます。bekko-embedding-web のデモはモデルをブラウザに読み込み、そのままブラウザ上で実行します。
小型モデルを作った理由
コーディング・AIエージェントの台頭により、PCの使い方が変わりました。LLMの推論はAPIの先にあるフロンティアモデルが行うため、その部分においては手元のマシン性能は以前ほど気になりません。一方、エージェントが情報を探すための処理は、今も手元のマシンで動かします。ドキュメントの埋め込み(ベクトルに変換)、インデクス作成、コンテキストの探索等々です。
手元のマシンにGPUがないことも多く、低スペックなマシン(Raspberry Piなど)で動かすこともあります。その際 multilingual-e5-large で1万件の文書を埋め込むと、高速なデスクトップCPUでも約8分、Raspberry Pi 5 では2時間近くかかります。しかもクエリの埋め込みはインデックス作成時に一度計算すれば終わりではなく、検索のたびにも推論が必要です。
小さな埋め込みモデル、たとえばAPが30M未満のモデルの選択肢はかなり少ないです。自分が調べた範囲では、オープンなライセンスで利用でき、文脈を考慮する多言語埋め込みモデルのうち、Bekko以外で30M未満かつ検索に使える性能だったのは2つだけでした。2020年に蒸留された MiniLM を初期値にした multilingual-e5-small と、2026年に公開されたAP 28.3Mの granite-embedding-97m-r2 です。
なおModel2Vec などの 静的埋め込み Static Embeddings はさらに小さくできます。ただし、Transformers のような文脈を理解するモデルではなく、性能も低くなります。
モデルパラメータと演算量
多言語埋め込みモデルの演算量は、総パラメータ数だけでは見積もれません。モデルが118Mパラメータと書かれていると、そのパラメータすべてを使って計算するように思えます。しかし、多言語エンコーダでは、その大半が多言語のためのトークン埋め込みテーブルです。Bekkoの場合はこの埋め込みテーブルが256,000トークンありますが、推論時にはこのテーブルを参照するだけです。トークンごとに1つを取り出すため行列積はなく、このルックアップテーブルから読み込むだけです。
各トークンで実際に行列積を行うのは、Transformerブロックに含まれるパラメータです。スケーリング則で用いられるパラメータの数え方にならい、ここではこれらを Active Parameters(AP) と呼びます。総パラメータ数よりもより推論コストを考える際に重要な指標となります。
この Active Parameters (AP) という言葉は別の意味でも使われるため、補足します。ここでいう AP は、ルータがトークンごとに異なるエキスパートを選び、全重みの一部だけを動かす Mixture-of-Experts(MoE) の文脈のAPではありません。Bekko は MoE ではない通常のエンコーダで、7.67Mのパラメータすべてを推論時に使います。パラメータ数から除いているのは、埋め込みのルックアップだけです。
たとえば、multilingual-e5-small は総パラメータ数118Mのうち、APが21.6Mです。bekko-a8m は総パラメータ数106M、AP 7.67Mです。この差が推論時間に表れます。なおこのAPだけで速度が決まるわけではありませんが、小さいほど基本的に推論が高速です。
Bekko Embedding
Bekko は、22層の mmBERT-small エンコーダを4層(a8m)と13層(a25m)にそれぞれ pruning し、これらの2モデルを約11億の多言語ペアで学習しています。
- 100以上の言語を含むデータで、言語横断検索ができるように学習しました。翻訳を挟まず、日本語のクエリから英語の文書を検索できます。後述する言語別評価では、そのうち14言語を扱います。
- どちらのモデルも8,192トークンまで入力できます。
- 出力は384次元です。Matryoshka学習により、256 / 128 / 64次元へ切り詰めて使えます。bekko-a25m を256次元にすると、検索性能は HAKARI-Bench Overall が相対で約1.3%、128次元では約6.2%低下します。
- モデルの重みはMITライセンスです。
- 学習データも、第一段階のコーパスとマイニングしたhard negativesを公開しています。
ベンチマーク結果
下の図には6つの列があります。最初の2列は、同じ MMTEB Multilingual v2 評価を異なる切り口で集計したものです。ALLは全131タスクの平均、Retはそのうち18の検索タスクだけの平均です。比較モデルのスコアには公式に公開されているスナップショットを使い、Bekkoも同じタスク集合と集計方法で評価しました。
残る4列は、すべて検索タスクのベンチマーク評価です。Multilingual NanoBEIR は、英語版のオリジナル NanoBEIR に、コミュニティが公開した13の翻訳版を加えたものです。これらの翻訳版は私が作ったものではありませんが、他の Nano-set は後述の HAKARI-Bench 用に私が作った物です。NanoRTEB は、実運用に近い検索データセットを集めた RTEB の小型版です。NanoCoIR はコード検索、NanoLongEmbed は長文入力を扱います。この4つは、私が作った HAKARI-Bench(arXiv)で同じ設定を使って評価しました。語彙一致のベースラインとして、BM25も含めています。

MMTEBの2列を並べると、順位がかなり違います。特に分かりやすいのが granite-embedding-97m-r2 で、18の検索タスクでは60.3と比較中4位ですが、全131タスクでは51.9と最下位です。検索タスクを集中して学習すると、そのほかのタスクで性能を落とすことがあります。Bekkoも検索向けに学習したモデルですが、全タスクの平均も悪くはありません。
bekko-a8m は6つの列すべてで multilingual-e5-small を上回り、multilingual-e5-small のAPは2.8倍と約3倍の大きさです。bekko-a25m は、APが約12分の1でありながら、MMTEBの検索18タスクでは multilingual-e5-large と BGE-M3 を上回ります。ただしMMTEB全131タスクでは、どちらのモデルも bekko-a25m より高いスコアです。
18の検索タスクでは、5モデルが bekko-a25m を上回ります。harrier-oss-v1-270m、granite-embedding-311m-r2、EmbeddingGemma-300M、granite-embedding-97m-r2、snowflake-arctic-embed-l-v2.0 です。全131タスクでは4モデルが上回ります。harrier-oss-v1-270m と EmbeddingGemma-300M に加え、BGE-M3 と multilingual-e5-large です。gte-multilingual-base は同点でした。
ここで bekko-a25m を上回ったモデルは、granite-embedding-97m-r2 を除き、bekko-a25m の4〜13倍のAPを持ちます。検索精度を最優先し、十分な計算資源があるなら、どれも優れたモデルと言えるでしょう。
コード検索では、bekko-a25m は78.6で、multilingual-e5-large と BGE-M3 を上回る一方、84.7の EmbeddingGemma-300M と81.4の granite-embedding-311m-r2 には届きません。長文入力の結果は、もう少し意外でした。長い文書の中から1つの箇所を探す場合、語彙一致は強く、BM25が82.2で全モデルを上回ります。しかし12の密ベクトルモデルの中では、bekko-a25m が70.6で1位、bekko-a8m が3位でした。
言語別の結果
平均値だけを見ると、特定の言語でモデルの性能が崩れていても気づけません。以下は、Multilingual NanoBEIR の14言語を個別に見た結果です。

bekko-a25m は、14言語すべてで multilingual-e5-small と BM25 を上回りました。BGE-M3 との差が最も大きい言語でも2.7ポイントです。14言語の中ではタイ語、アラビア語、セルビア語が弱く、まだ改善の余地があります。
推論速度
APはスループットを大まかに見積もる目安になります。Raspberry Pi 5 から RTX 5090 まで、4つの環境で6モデルを同じ条件で測定しました。

bekko-a8m は、どの環境でも6モデル中もっとも高速でした。実際のインデックス作成で、Ryzen 9 7590X CPUで10万文書を埋め込みベクトルに変換すると、bekko-a8m なら約5分ですが、multilingual-e5-large なら約80分かかります。
自分がより面白いと思ったのは、Raspberry Pi 5 の結果です。1秒あたり33文書はGPUに比べれば圧倒的に遅いですが、1万文書のインデックスなら約5分で作成可能です。これぐらいの速度なら、用途によっては実用的でしょう。同じ Raspberry Pi 5 で multilingual-e5-large を使うと、2時間近くかかります。
図の2つのCPUパネルでは、それぞれのモデルが公開している PyTorch のバックエンドに OpenVINO を使う版を使っています。6モデルとも、CPUでは OpenVINO が最速だったためです。一部のモデルだけOpenVINO を使わずに動かすと公平な比較になりません。同等の OpenVINO 版がないモデルに、ここでの数値をそのまま当てはめることはできません。Bekko は両サイズとも OpenVINO 版を公開しています。
APだけですべての速度差を説明できるわけではありません。multilingual-e5-small のAPは bekko-a25m の87%ですが、CPUでは1.7倍高速です。granite-embedding-97m-r2 はAPが14%多いものの、速度はほぼ変わりません。
自分は、アーキテクチャの違いが効いているのではないかと思っています。ModernBERT のアーキテクチャでは、unpadding、可変長 FlashAttention カーネル、global attention と local attention の相互配置など、GPUカーネルを意識した高速化を行っています。一方、素直な XLM-R 系エンコーダアーキテクチャは、CPUバックエンドに載せやすそうです。原因を切り分けるところまではできていないので、ここは実際の実装を真に確認した結果ではなく自分の解釈です。ただこうした違いがあっても、bekko-a8m は十分に小さく、今回の比較では最速でした。
124 MiB の配布サイズとブラウザ実行
総パラメータ数を大きくしている語彙埋め込みテーブルは、ダウンロードサイズも大きくします。このテーブルは静的なルックアップなので、ONNX 版と OpenVINO 版では行ごとの int8 量子化で保存し、Transformer の重みは fp32 のままにしました。リリース時の検証では、PyTorch 版とのコサイン類似度は最小でも0.9994でした。
これにより bekko-a8m は124 MiB、bekko-a25m は190 MiBになり、ブラウザへ配れるサイズになりました。なおTransformer の重み自体をさらに小さくfloatから int8 にしサイズ削減もできるのですが、精度劣化が激しいため行なっておりません。
| bekko-a8m | bekko-a25m | |
|---|---|---|
| ブラウザ、WebGPU | 187 docs/s | 89 docs/s |
| ブラウザ、WASM (CPU) | 51 docs/s | 16 docs/s |
| ネイティブ、Apple GPU (MPS) | 592 docs/s | 351 docs/s |
上の速度図と同じ Natural Questions の入力を使っています。最後の行はブラウザでの結果ではなく、比較用に同じモデルをネイティブ実行した値です。
ブラウザデモは huggingface.co/spaces/hotchpotch/bekko-embedding-web で試せます。埋め込みの計算はブラウザ内で行うため、入力した文章をサーバーへ送ることはありません。
ほかのモデルを選んだ方がよい場合
- 日本語のみを扱いたい場合、ruri-v3 シリーズは小さく Bekko より高性能です。ruri-v3-30mは AP 10M、出力次元が 256 と小型ながら必要十分な性能のことも多いでしょう
- 計算資源に余裕があり、この比較で最も高い検索精度を求める場合は、harrier-oss-v1-270m、granite-embedding-311m-r2、EmbeddingGemma-300M の方が高いスコアです。
- 検索以外にも広く使える文章埋め込みモデルが必要な場合、Bekko の分類とクラスタリング性能はは中位から下位です。検索ではない目的なら、他のモデルの方が適していることも多いでしょう。
Bekko Embedding の使い方
どちらのモデルを試すか迷ったら、CPUでのインデックス作成やブラウザ検索には a8m、Apple MPS やGPUが使え速度より検索性能を優先するなら a25m がよいでしょう。
PyTorchでそのまま動かすほか、CPUでは OpenVINO、ブラウザでは Transformers.js を使えます。3つとも同じモデルIDで動き、prefixも不要です。実行環境ごとにAPIが異なります。
pip install -U "sentence-transformers>=5.0" "transformers>=5.12"
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer("hotchpotch/bekko-embedding-v1-a8m")
query = "What are the characteristics of sushi?"
docs = [
"A warm noodle soup served in broth with sliced toppings.",
"天ぷらは魚や野菜に衣をつけて揚げた料理です。",
"Une fine crepe garnie de sucre, de beurre ou de fruits.",
"A Japanese dish made with vinegared rice, often shaped with seafood, vegetables, or egg.",
]
scores = util.cos_sim(
model.encode(query, normalize_embeddings=True),
model.encode(docs, normalize_embeddings=True),
)[0]
print("best doc:", docs[int(scores.argmax())])
prefix やタスク指示は不要で、クエリと文書はどちらも同じ encode 呼び出しで処理します。上の条件では、a8m の OpenVINO 実装は PyTorch より x86 で約2.8倍、Raspberry Pi 5 で約1.7倍高速です。
CPU で OpenVINO を使う
pip install -U \
"sentence-transformers[openvino]>=5.0" \
"transformers>=4.57,<5"
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer(
"hotchpotch/bekko-embedding-v1-a8m",
backend="openvino",
device="cpu",
model_kwargs={"file_name": "openvino/openvino_model.xml", "device": "CPU"},
)
query = "What are the characteristics of sushi?"
docs = [
"A warm noodle soup served in broth with sliced toppings.",
"A Japanese dish made with vinegared rice, often shaped with seafood, vegetables, or egg.",
]
scores = util.cos_sim(
model.encode(query, normalize_embeddings=True),
model.encode(docs, normalize_embeddings=True),
)[0]
print("best doc:", docs[int(scores.argmax())])
OpenVINO 連携は Transformers を5.1未満に固定するため、先ほどの transformers>=5.12 と同じ環境には入れられません。別環境を用意するか、両方とも Transformers 4.57 を使ってください。通常の PyTorch の例も4.57で動きます。
Transformers.js でも、同じモデルをブラウザ内で動かせます。対応しているブラウザでは WebGPU を使います。
ブラウザで Transformers.js を使う
npm install @huggingface/transformers
import { pipeline } from "@huggingface/transformers";
// Browser: use WebGPU when available, otherwise fall back to WASM.
// Node.js: replace this line with `const device = "cpu";`.
const device = navigator.gpu ? "webgpu" : "wasm";
const extractor = await pipeline(
"feature-extraction",
"hotchpotch/bekko-embedding-v1-a8m",
{ device, dtype: "fp32" },
);
const embedding = await extractor("What are the characteristics of sushi?", {
pooling: "mean",
normalize: true,
});
console.log(embedding.dims); // [1, 384]
リソースへのリンク
- モデル:bekko-embedding-v1-a8m と bekko-embedding-v1-a25m
- ブラウザデモ:bekko-embedding-web
- 学習データ:第一段階のコーパス と hard negatives
モデルの学習方法
使い方を中心にした記事なので、学習については簡単に。mmBERT-small の22層を4層と13層に削り、先頭側の層と、深い位置にある global attention の層を1つ残しました。削った後のチェックポイントを、そのまま基盤モデルとして使っています。
そこから2段階の対照学習を行いました。第一段階では、公開しているコーパスの約11億多言語ペア(合成データセットなども多様して作成)を使っています。性質の異なる2系統の LLM 合成クエリも含まれます。続いて、8,192トークンの長文も含む hard negative を使ってファインチューニングしました。どちらの段階でも教師モデルや蒸留は使っていません。
両モデルとも、RTX PRO 6000 Blackwell Max-Q 1枚のみで学習しました。所要時間は a8m が約3日、a25m が約8日です。一般的な規模の多言語埋め込みモデルは GPU クラスターで学習され、BGE-M3 の論文では最大96基の GPU を使ったと報告されています。APを小さくすると推論コストが下がり、学習もワークステーション GPU 1枚で行えます。RTX5090でも学習時間は増えますが、学習可能です。大量のGPUが必要ないことも、自分がこのサイズのモデルに取り組む大きな理由の1つです。
今回のモデルは、かなり多くの研究や実装を参考にしています。基盤モデルには mmBERT と ModernBERT、学習方法には E5、GTE、BGE-M3、Qwen3 Embedding、Ruri、実装には sentence-transformers を使いました。これだけ小さなモデルで、どうやって多言語検索の性能を保ったのか。残す層を選ぶ実験、損失、約11億ペアの収集・合成方法、詳しい評価結果をまとめた野良論文は以下で公開しています。
- arXiv: Bekko Embedding: Parameter-Efficient Multilingual Retrieval with Ultra-Compact Encoders
- 日本語版: Bekko Embedding: 超小型エンコーダによるパラメータ効率の高い多言語検索
小さな多言語検索モデルを探している方に、Bekko Embedding が一つの選択肢になれば幸いです。

