高スループット・低遅延でEmbeddings・Rerankなどを提供できる「Infinity」を試す
以前に取り上げたSTAPI、Embeddingモデルをお手軽にOpenAI互換API化できてよいのだが、
たまたまPRを見てたら、作者の方がオススメしていたのが「Infinity」。
ちょっと気になるので試してみようと思う。
GitHubレポジトリ
GitHubレポジトリのREADMEからポイントをピックアップ
Infinity ♾️
Infinityは、テキスト埋め込み、再ランキングモデル、clip、clapおよびcolpali向けの高スループット・低遅延RESTAPIです。InfinityはMITライセンスの下で開発されています。
なぜInfinity
- HuggingFaceの任意のモデルをデプロイ: HuggingFaceから任意のembedding、reranking、clipおよびsentence-transformerモデルをデプロイ
- 高速推論バックエンド: 推論サーバーはPyTorch、optimum (ONNX/TensorRT)、CTranslate2上に構築されており、FlashAttentionを使用してNVIDIA CUDA、AMD ROCM、CPU、AWS INF2、APPLE MPSアクセラレータを最大限に活用します。Infinityは動的バッチ処理とワーカースレッドでの専用トークン化を使用します。
- マルチモーダルおよびマルチモデル: 複数のモデルを組み合わせて使用できます。Infinityがそれらを調整します。
- テスト済みの実装: ユニットテストとエンドツーエンドテスト済み。Infinityによる埋め込みは正確に埋め込まれます。APIユーザーは無限に、そしてそれ以上に埋め込みを作成できます。
- 使いやすさ: FastAPI上に構築。Infinity CLI v2は環境変数または引数を介してすべての引数を起動できます。OpenAIのAPIの仕様に準拠したOpenAPI。https://michaelfeil.github.io/infinityでドキュメントを確認して、始め方を学んでください。
Infinityがサポートするタスクとモデル
Infinityはembeddings、reranking、および関連するRAGタスクの機能をほとんどサポートすることを目指しています。以下のInfinityはGithub CIで15+のアーキテクチャとすべての以下のケースをテストしています。
テキスト埋め込み
テキスト埋め込みはテキスト文字列の関連性を測定します。埋め込みは検索、クラスタリング、レコメンデーションのために使用されます。
OpenAIのテキスト埋め込みのプライベートデプロイバージョンと考えてください。https://platform.openai.com/docs/guides/embeddingsテスト済みの埋め込みモデル:
- mixedbread-ai/mxbai-embed-large-v1
- WhereIsAI/UAE-Large-V1
- BAAI/bge-base-en-v1.5
- Alibaba-NLP/gte-large-en-v1.5
- jinaai/jina-embeddings-v2-base-code
- sentence-transformers/all-MiniLM-L6-v2
- intfloat/multilingual-e5-large-instruct
- intfloat/multilingual-e5-small
- jinaai/jina-embeddings-v3
- BAAI/bge-m3, スパースなし
- デコーダーベースのモデル。これらはbert-smallモデルよりも約20-100倍大きい(&遅い)ことに注意してください:
その他のモデル:
- ほとんどの埋め込みモデルはサポートされています:https://huggingface.co/models?pipeline_tag=feature-extraction&other=text-embeddings-inference&sort=trending
- モデルについてはMTEBリーダーボードを確認してください https://huggingface.co/spaces/mteb/leaderboard
リランキング
クエリと文書のリストが与えられると、リランキングはクエリに対して最も意味的に関連のある文書を、最も少ないものまでインデックス付けします。
https://docs.cohere.com/reference/rerankのローカルにデプロイされたバージョンのようなものですテスト済みの再ランキングモデル:
- mixedbread-ai/mxbai-rerank-xsmall-v1
- Alibaba-NLP/gte-multilingual-reranker-base
- BAAI/bge-reranker-base
- BAAI/bge-reranker-large
- BAAI/bge-reranker-v2-m3
- jinaai/jina-reranker-v1-turbo-en
その他の再ランキングモデル:
- infinityでサポートされる再ランキングモデルは、1つのカテゴリを持つbert-style分類モデルです。
- ほとんどの再ランキングモデルがサポートされています:https://huggingface.co/models?pipeline_tag=text-classification&other=text-embeddings-inference&sort=trending
- https://huggingface.co/models?pipeline_tag=text-classification&sort=trending&search=rerank
マルチモーダルおよびクロスモーダル - 画像および音声埋め込み
画像<->テキストまたは画像<->音声検索を可能にする特殊な埋め込みモデル。
通常、これらのモデルはテキスト<->テキスト、テキスト<->その他、およびその他<->その他の検索を可能にし、クロスモーダルに移行するとトレードオフのある精度を提供します。画像<->テキストモデルは、例えばフォトギャラリー検索に使用でき、ユーザーはキーワードを入力して写真を検索したり、写真を使用して関連画像を見つけたりできます。
音声<->テキストモデルはあまり一般的ではなく、テキスト説明に基づいて音楽曲を見つけたり、関連する音楽曲を見つけたりするために使用できます。テスト済みの画像<->テキストモデル:
- wkcn/TinyCLIP-ViT-8M-16-Text-3M-YFCC15M
- jinaai/jina-clip-v1
- google/siglip-so400m-patch14-384
config.json
のタイプ:ClipModel / SiglipModelテスト済みの音声<->テキストモデル:
- LAION製Clapモデル
- 限られた数のオープンソース組織がこれらのモデルをトレーニングしています
- 注:音声データのサンプリングレートはモデルと一致する必要があります *
サポートされていないもの:
- nomic-ai/nomic-embed-vision-v1.5のような単純なビジョンモデル
ColBertスタイルのlate-interaction埋め込み
ColBert埋め込みは特別なプーリング方法を実行せず、生のトークン埋め込みを返します。
トークン埋め込みはVectorDB(Qdrant / Vespa)でMaxSimメトリックでスコアリングされますRestAPI経由で使用する場合、後期インタラクション埋め込みは
base64
エンコーディングを介して最適に転送できます。
サンプルノートブック:https://colab.research.google.com/drive/14FqLc0N_z92_VgL_zygWV5pJZkaskyK7?usp=sharingテスト済みのcolbertモデル:
ColPali-スタイルのlate-interaction画像<->テキスト埋め込み
ColBertと同様の使用法ですが、テキストのみではなく画像<->テキスト間のスキャンに使用します。
RestAPI経由で使用する場合、後期インタラクション埋め込みは
base64
エンコーディングを介して最適に転送できます。
サンプルノートブック:https://colab.research.google.com/drive/14FqLc0N_z92_VgL_zygWV5pJZkaskyK7?usp=sharingテスト済みのColPali/ColQwenモデル:
- vidore/colpali-v1.2-merged
- michaelfeil/colqwen2-v0.1
- loraアダプターはサポートされていません。「merged」モデルのみです。
テキスト分類
BERTスタイルのマルチラベルテキスト分類。異なるカテゴリに分類します。
テスト済みモデル:
- ProsusAI/finbert、金融ニュース分類
- SamLowe/roberta-base-go_emotions、テキストから感情カテゴリへの分類
config.json
で1つ以上のラベルを持つbertスタイルのテキスト分類モデル
インテグレーション
- RunpodでのServerlessデプロイメント
- Truefoundry Cognita
- Langchain例
- imitater - vlllmとinfinityの上に構築された統一言語モデルサーバー
- Dwarves Foundation:Modal.comを使用したデプロイメント例
- infiniflow/Ragflow
- SAP Core AI
- gpt_server - LLM(大規模言語モデル)または埋め込みの本番レベルのデプロイメント用に設計されたオープンソースフレームワーク
- KubeAI:インフェレンス用のKubernetes AIオペレーター
- LangChain
- Batched、InfinityのBatchingアルゴリズムの修正
ドキュメント
https:///michaelfeil.github.io/infinityでドキュメントを確認し、始め方を学びましょう。
起動後、Swagger UIは{url}:{port}/docs
(この場合http://localhost:7997/docs
)で利用可能になります。また、インタラクティブなプレビューはhttps://infinity.modal.michaelfeil.eu/docs (および https://michaelfeil-infinity.hf.space/docs)で確認できます。
Getting Started
今回はローカルのMacで試す。利用方法はざっと見た感じ、以下がある様子。
- Infinity CLI
- Docker
- Python API
- Pythonクライアント
とりあえずCLIからまずは初めてみる。
CLIのインストール
CLIはPythonパッケージをインストールする。ということで、uvで環境を作成。
uv init -p 3.12.9 infinity-work && cd infinity-work
CLIのパッケージをインストール
uv add "infinity-emb[all]"
+ infinity-emb==0.0.76
これでinfinity_emb
というコマンドが使えるようになる。まずはUsage。
uv run infinity_emb v2 --help
INFO 2025-04-18 02:36:38,754 datasets INFO: PyTorch version 2.6.0 config.py:54
available.
Usage: infinity_emb v2 [OPTIONS]
Infinity API ♾️ cli v2. MIT License. Copyright (c) 2023-now Michael Feil
Multiple Model CLI Playbook:
- 1. cli options can be overloaded i.e. `v2 --model-id model/id1 --model-id model/id2
--batch-size 8 --batch-size 4`
- 2. or adapt the defaults by setting ENV Variables separated by `;`:
INFINITY_MODEL_ID="model/id1;model/id2;" && INFINITY_BATCH_SIZE="8;4;"
- 3. single items are broadcasted to `--model-id` length, making `v2 --model-id model/id1
--model-id/id2 --batch-size 8` both models have batch-size 8.
╭─ Options ────────────────────────────────────────────────────────────────────────────────╮
│ --model-id TEXT Huggingface model │
│ repo id. Subset of │
│ possible models: │
│ https://huggingface… │
│ [env var: │
│ `INFINITY_MODEL_ID`] │
│ [default: │
│ michaelfeil/bge-sma… │
│ --served-model-name TEXT the nickname for the │
│ API, under which the │
│ model_id can be │
│ selected │
│ [env var: │
│ `INFINITY_SERVED_MO… │
│ --batch-size INTEGER maximum batch size │
│ for inference │
│ [env var: │
│ `INFINITY_BATCH_SIZ… │
│ [default: 32] │
│ --revision TEXT huggingface model │
│ repo revision. │
│ [env var: │
│ `INFINITY_REVISION`] │
│ --trust-remote-code --no-trust-remote-… if potential remote │
│ modeling code from │
│ huggingface repo is │
│ trusted. │
│ [env var: │
│ `INFINITY_TRUST_REM… │
│ [default: │
│ trust-remote-code] │
│ --engine [torch|ctranslate2| Which backend to │
│ optimum|neuron|debu use. `torch` uses │
│ gengine] Pytorch GPU/CPU, │
│ optimum uses ONNX on │
│ GPU/CPU/NVIDIA-Tens… │
│ `CTranslate2` uses │
│ torch+ctranslate2 on │
│ CPU/GPU. │
│ [env var: │
│ `INFINITY_ENGINE`] │
│ [default: torch] │
│ --model-warmup --no-model-warmup if model should be │
│ warmed up after │
│ startup, and before │
│ ready. │
│ [env var: │
│ `INFINITY_MODEL_WAR… │
│ [default: │
│ model-warmup] │
│ --vector-disk-cache --no-vector-disk-c… If │
│ hash(request)/resul… │
│ should be cached to │
│ SQLite for latency │
│ improvement. │
│ [env var: │
│ `INFINITY_VECTOR_DI… │
│ [default: │
│ vector-disk-cache] │
│ --device [cpu|cuda|mps|tenso device to use for │
│ rrt|auto] computing the model │
│ forward pass. │
│ [env var: │
│ `INFINITY_DEVICE`] │
│ [default: auto] │
│ --device-id TEXT device id defines │
│ the model placement. │
│ e.g. `0,1` will │
│ place the model on │
│ MPS/CUDA/GPU 0 and 1 │
│ each │
│ [env var: │
│ `INFINITY_DEVICE_ID… │
│ --lengths-via-token… --no-lengths-via-t… if True, returned │
│ tokens is based on │
│ actual tokenizer │
│ count. If false, │
│ uses len(input) as │
│ proxy. │
│ [env var: │
│ `INFINITY_LENGTHS_V… │
│ [default: │
│ lengths-via-tokeniz… │
│ --dtype [float32|float16|bf dtype for the model │
│ loat16|int8|fp8|aut weights. │
│ o] [env var: │
│ `INFINITY_DTYPE`] │
│ [default: auto] │
│ --embedding-dtype [float32|int8|uint8 dtype post-forward │
│ |binary|ubinary] pass. If != │
│ `float32`, using │
│ Post-Forward Static │
│ quantization. │
│ [env var: │
│ `INFINITY_EMBEDDING… │
│ [default: float32] │
│ --pooling-method [mean|cls|auto] overwrite the │
│ pooling method if │
│ inferred │
│ incorrectly. │
│ [env var: │
│ `INFINITY_POOLING_M… │
│ [default: auto] │
│ --compile --no-compile Enable usage of │
│ `torch.compile(dyna… │
│ if engine relies on │
│ it. │
│ [env var: │
│ `INFINITY_COMPILE`] │
│ [default: compile] │
│ --bettertransformer --no-bettertransfo… Enables varlen │
│ flash-attention-2 │
│ via the │
│ `BetterTransformer` │
│ implementation. If │
│ available for this │
│ model. │
│ [env var: │
│ `INFINITY_BETTERTRA… │
│ [default: │
│ bettertransformer] │
│ --preload-only --no-preload-only If true, only │
│ downloads models and │
│ verifies setup, then │
│ exit. Recommended │
│ for pre-caching the │
│ download in a │
│ Dockerfile. │
│ [env var: │
│ `INFINITY_PRELOAD_O… │
│ [default: │
│ no-preload-only] │
│ --host TEXT host for the FastAPI │
│ uvicorn server │
│ [env var: │
│ `INFINITY_HOST`] │
│ [default: 0.0.0.0] │
│ --port INTEGER port for the FastAPI │
│ uvicorn server │
│ [env var: │
│ `INFINITY_PORT`] │
│ [default: 7997] │
│ --url-prefix TEXT prefix for all │
│ routes of the │
│ FastAPI uvicorn │
│ server. Useful if │
│ you run behind a │
│ proxy / cascaded │
│ API. │
│ [env var: │
│ `INFINITY_URL_PREFI… │
│ --redirect-slash TEXT where to redirect │
│ `/` requests to. │
│ [env var: │
│ `INFINITY_REDIRECT_… │
│ [default: /docs] │
│ --log-level [critical|error|war console log level. │
│ ning|info|debug|tra [env var: │
│ ce] `INFINITY_LOG_LEVEL… │
│ [default: info] │
│ --permissive-cors --no-permissive-co… whether to allow │
│ permissive cors. │
│ [env var: │
│ `INFINITY_PERMISSIV… │
│ [default: │
│ no-permissive-cors] │
│ --api-key TEXT api_key used for │
│ authentication │
│ headers. │
│ [env var: │
│ `INFINITY_API_KEY`] │
│ --proxy-root-path TEXT Proxy prefix for the │
│ application. See: │
│ https://fastapi.tia… │
│ [env var: │
│ `INFINITY_PROXY_ROO… │
│ --help Show this message │
│ and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────╯
APIサーバの起動
では試しに intfloat/multilingual-e5-small を使ってEmbeddingのAPIを建ててみる
uv run infinity_emb v2 --model-id intfloat/multilingual-e5-small
以下のように起動してくるが、多分裏でモデルのダウンロード+ロードをしていると思うのでちょっと時間がかかる。
INFO 2025-04-18 02:45:16,447 datasets INFO: PyTorch version 2.6.0 available. config.py:54
INFO: Started server process [89325]
INFO: Waiting for application startup.
INFO 2025-04-18 02:45:17,099 infinity_emb INFO: Creating 1engines: infinity_server.py:84
engines=['intfloat/multilingual-e5-small']
INFO 2025-04-18 02:45:17,100 infinity_emb INFO: Anonymized telemetry can be disabled via telemetry.py:30
environment variable `DO_NOT_TRACK=1`.
INFO 2025-04-18 02:45:17,102 infinity_emb INFO: model=`intfloat/multilingual-e5-small` select_model.py:64
selected, using engine=`torch` and device=`None`
INFO 2025-04-18 02:45:17,765 sentence_transformers.SentenceTransformer INFO: Load SentenceTransformer.py:218
pretrained SentenceTransformer: intfloat/multilingual-e5-small
しばらく待ってると、とりあえずAPIが起動したみたい。Warningにもある通り、Apple Siliconだと本来の性能は出ないかも。
WARNING 2025-04-18 02:46:18,352 infinity_emb WARNING: BetterTransformer is not available for acceleration.py:56
MPS device. Continue without bettertransformer modeling code.
INFO 2025-04-18 02:46:20,837 infinity_emb INFO: Getting timings for batch_size=32 and avg select_model.py:97
tokens per sentence=2
0.37 ms tokenization
12.12 ms inference
0.06 ms post-processing
12.55 ms total
embeddings/sec: 2549.07
INFO 2025-04-18 02:46:22,211 infinity_emb INFO: Getting timings for batch_size=32 and avg select_model.py:103
tokens per sentence=512
11.23 ms tokenization
472.62 ms inference
0.11 ms post-processing
483.96 ms total
embeddings/sec: 66.12
INFO 2025-04-18 02:46:22,212 infinity_emb INFO: model warmed up, between 66.12-2549.07 select_model.py:104
embeddings/sec at batch_size=32
INFO 2025-04-18 02:46:22,213 infinity_emb INFO: creating batching engine batch_handler.py:456
INFO 2025-04-18 02:46:22,214 infinity_emb INFO: ready to batch requests. batch_handler.py:525
INFO 2025-04-18 02:46:22,214 infinity_emb INFO: infinity_server.py:98
♾️ Infinity - Embedding Inference Server
MIT License; Copyright (c) 2023-now
Infinity OSS-Project: github.com/michaelfeil.infinity
Maintained by @michaelfeil @wirthual
Version 0.0.76
Open the Docs via Swagger UI:
http://0.0.0.0:7997/docs
Access all deployed models via 'GET':
curl http://0.0.0.0:7997/models
Visit the docs for more information:
https://michaelfeil.github.io/infinity
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:7997 (Press CTRL+C to quit)
APIの利用
とりあえずcurlでモデルの一覧を取得してみる。
curl http://127.0.0.1:7997/models | jq -r .
{
"data": [
{
"id": "intfloat/multilingual-e5-small",
"stats": {
"queue_fraction": 0.0,
"queue_absolute": 0,
"results_pending": 0,
"batch_size": 32
},
"object": "model",
"owned_by": "infinity",
"created": 1744912188,
"backend": "torch",
"capabilities": [
"embed"
]
}
],
"object": "list"
}
http://localhost:7997/docs
で確認する限りはOpenAI互換っぽい。
テキストのEmbeddingsを生成してみる。
curl -X POST http://127.0.0.1:7997/embeddings \
-H "Content-Type: application/json" \
-d '{
"input": ["おはようございます"]
}' | jq -r .
{
"object": "list",
"data": [
{
"object": "embedding",
"embedding": [
0.05275781825184822,
-0.022957203909754753,
-0.06776507198810577,
-0.05877435579895973,
0.08515320718288422,
(snip)
-0.0194106325507164,
0.08340593427419662,
0.07239586114883423,
0.04821839928627014,
0.03272527828812599
],
"index": 0
}
],
"model": "intfloat/multilingual-e5-small",
"usage": {
"prompt_tokens": 9,
"total_tokens": 9
},
"id": "infinity-8c03815c-0b5a-4c42-9845-a46e2df1a96a",
"created": 1744912650
}
複数のモデルを同時にホストできるらしいので、出たばっかりの以下の2モデルで試してみる。
CLIを止めて、以下のようにして実行。
uv run infinity_emb v2 \
--model-id pfnet/plamo-embedding-1b\
--model-id cl-nagoya/ruri-v3-30m
INFO 2025-04-18 03:08:22,492 infinity_emb INFO: Creating 2engines: infinity_server.py:84
engines=['pfnet/plamo-embedding-1b', 'cl-nagoya/ruri-v3-30m']
INFO 2025-04-18 03:08:22,492 infinity_emb INFO: Anonymized telemetry can be disabled via telemetry.py:30
environment variable `DO_NOT_TRACK=1`.
INFO 2025-04-18 03:08:22,494 infinity_emb INFO: model=`pfnet/plamo-embedding-1b` selected, select_model.py:64
using engine=`torch` and device=`None`
INFO 2025-04-18 03:08:23,667 sentence_transformers.SentenceTransformer INFO: Load SentenceTransformer.py:218
pretrained SentenceTransformer: pfnet/plamo-embedding-1b
WARNING 2025-04-18 03:08:23,860 sentence_transformers.SentenceTransformer WARNING: No SentenceTransformer.py:1524
sentence-transformers model found with name pfnet/plamo-embedding-1b. Creating
a new one with mean pooling.
(snip)
ModuleNotFoundError: No module named 'sentencepiece'
ERROR: Application startup failed. Exiting.
pfnet/plamo-embedding-1b の方は sentencepiece が必要みたい。ということで追加。
uv add sentencepiece
が、残念。
WARNING 2025-04-18 03:10:45,420 sentence_transformers.SentenceTransformer WARNING: No SentenceTransformer.py:1524
sentence-transformers model found with name pfnet/plamo-embedding-1b. Creating
a new one with mean pooling.
Asking to truncate to max_length but no maximum length is provided and the model has no predefined maximum length. Default to no truncation.
(snip)
TypeError: 'NoneType' object is not iterable
ERROR: Application startup failed. Exiting.
とりあえず cl-nagoya/ruri-v3-30m の別のサイズで。
uv run infinity_emb v2 \
--model-id cl-nagoya/ruri-v3-30m \
--model-id cl-nagoya/ruri-v3-130m
今度はうまく行った。
(snip)
INFO 2025-04-18 03:13:34,908 infinity_emb INFO: Creating 2engines: infinity_server.py:84
engines=['cl-nagoya/ruri-v3-30m', 'cl-nagoya/ruri-v3-130m']
(snip)
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:7997 (Press CTRL+C to quit)
ではcurlで。
curl http://127.0.0.1:7997/models | jq -r .
{
"data": [
{
"id": "cl-nagoya/ruri-v3-30m",
"stats": {
"queue_fraction": 0.0,
"queue_absolute": 0,
"results_pending": 0,
"batch_size": 32
},
"object": "model",
"owned_by": "infinity",
"created": 1744913768,
"backend": "torch",
"capabilities": [
"embed"
]
},
{
"id": "cl-nagoya/ruri-v3-130m",
"stats": {
"queue_fraction": 0.0,
"queue_absolute": 0,
"results_pending": 0,
"batch_size": 32
},
"object": "model",
"owned_by": "infinity",
"created": 1744913768,
"backend": "torch",
"capabilities": [
"embed"
]
}
],
"object": "list"
}
それぞれのモデルがリストアップされている。
テキストのEmbeddingsを生成。
curl -X POST http://127.0.0.1:7997/embeddings \
-H "Content-Type: application/json" \
-d '{
"input": ["おはようございます"]
}' | jq -r .
複数のモデルをホストする場合はモデル名が必要になる。
{
"error": {
"message": "Invalid model: Engine for model name `default/not-specified` not found. Available model names are ['cl-nagoya/ruri-v3-30m', 'cl-nagoya/ruri-v3-130m']",
"type": null,
"param": null,
"code": 400
}
}
curl -X POST http://127.0.0.1:7997/embeddings \
-H "Content-Type: application/json" \
-d '{
"model": "cl-nagoya/ruri-v3-30m",
"input": ["おはようございます"]
}' | jq -r .
{
"object": "list",
"data": [
{
"object": "embedding",
"embedding": [
-0.045119766145944595,
-0.003127568867057562,
-0.049851853400468826,
0.036303646862506866,
0.07206321507692337,
(snip)
0.03493461757898331,
-0.0219422560185194,
-0.06379549950361252,
0.0026309911627322435,
-0.0014501155819743872
],
"index": 0
}
],
"model": "cl-nagoya/ruri-v3-30m",
"usage": {
"prompt_tokens": 9,
"total_tokens": 9
},
"id": "infinity-a73c0195-5b63-4804-93a4-cc900e12c9e9",
"created": 1744914017
}
curl -X POST http://127.0.0.1:7997/embeddings \
-H "Content-Type: application/json" \
-d '{
"model": "cl-nagoya/ruri-v3-130m",
"input": ["おはようございます"]
}' | jq -r .
{
"object": "list",
"data": [
{
"object": "embedding",
"embedding": [
-0.004650148097425699,
0.012932839803397655,
-0.009189369156956673,
0.018922852352261543,
-0.008427134715020657,
(snip)
-0.008729965426027775,
0.01514500007033348,
0.03178422525525093,
-0.02900286205112934,
-0.01114029623568058
],
"index": 0
}
],
"model": "cl-nagoya/ruri-v3-130m",
"usage": {
"prompt_tokens": 9,
"total_tokens": 9
},
"id": "infinity-0c07d3de-9260-4e13-b967-04c86dc0d241",
"created": 1744914025
}
とりあえず日本語に特化したEmbeddingモデルをいくつか簡単に試してみた。
以下は動いた
以下は動かなかった(原因は確認してない)
Embedding以外についても、いくつか試してみる。
リランキング
以下で試してみる。
リランキングモデルの場合でもCLIの使い方は変わらない。
uv run infinity_emb v2 \
--model-id cl-nagoya/ruri-v3-reranker-310m
curlはちょっと面倒なので、Pythonで。
import requests
import json
url = "http://127.0.0.1:7997/rerank"
payload = {
"query": "瑠璃色はどんな色?",
"documents": [
(
"ワシ、タカ、ハゲワシ、ハヤブサ、コンドル、フクロウが代表的である。"
"これらの猛禽類はリンネ前後の時代(17~18世紀)には鷲類・鷹類・隼類及び"
"梟類に分類された。ちなみにリンネは狩りをする鳥を単一の目(もく)にまとめ、"
"vultur(コンドル、ハゲワシ)、falco(ワシ、タカ、ハヤブサなど)、strix"
"(フクロウ)、lanius(モズ)の4属を含めている。"
),
(
"瑠璃、または琉璃(るり)は、仏教の七宝の一つ。サンスクリットの vaiḍūrya"
" またはそのプラークリット形の音訳である。金緑石のこととも、ラピスラズリで"
"あるともいう[1]。"
),
(
"瑠璃色(るりいろ)は、紫みを帯びた濃い青。名は、半貴石の瑠璃(ラピスラズリ"
"、英: lapis lazuli)による。JIS慣用色名では「こい紫みの青」(略号 dp-pB)"
"と定義している[1][2]。"
)
],
"return_documents": True,
}
response = requests.post(url, json=payload)
if response.status_code == 200:
print(json.dumps(response.json(), indent=4, ensure_ascii=False))
else:
print(f"エラー: {response.status_code}")
print(response.text)
実行結果
{
"object": "rerank",
"results": [
{
"relevance_score": 0.9999963045120239,
"index": 2,
"document": "瑠璃色(るりいろ)は、紫みを帯びた濃い青。名は、半貴石の瑠璃(ラピスラズリ、英: lapis lazuli)による。JIS慣用色名では「こい紫みの青」(略号 dp-pB)と定義している[1][2]。"
},
{
"relevance_score": 0.08069775253534317,
"index": 1,
"document": "瑠璃、または琉璃(るり)は、仏教の七宝の一つ。サンスクリットの vaiḍūrya またはそのプラークリット形の音訳である。金緑石のこととも、ラピスラズリであるともいう[1]。"
},
{
"relevance_score": 0.00035695568658411503,
"index": 0,
"document": "ワシ、タカ、ハゲワシ、ハヤブサ、コンドル、フクロウが代表的である。これらの猛禽類はリンネ前後の時代(17~18世紀)には鷲類・鷹類・隼類及び梟類に分類された。ちなみにリンネは狩りをする鳥を単一の目(もく)にまとめ、vultur(コンドル、ハゲワシ)、falco(ワシ、タカ、ハヤブサなど)、strix(フクロウ)、lanius(モズ)の4属を含めている。"
}
],
"model": "cl-nagoya/ruri-v3-reranker-310m",
"usage": {
"prompt_tokens": 390,
"total_tokens": 390
},
"id": "infinity-d81faa3f-aa4a-403a-bcdf-5d617059aeb2",
"created": 1744970505
}
日本語のリランキングモデルはそんなに多くないけど、いくつか確認した限り以下は動いた。
以下は動かなかった
マルチ/クロスモーダルのEmbeddingや、ColBert/ColPali、テキスト分類モデルなども同様に使える様子。実際に動くかどうかは試してみないとわからないが、興味があればお試しあれ。
Docker
公式のオススメはDockerイメージを使う方法の様子。
Dockerイメージは、GPU・CPUなど複数のイメージが用意されているようで、このあたりはドキュメントを確認して、各自の環境やユースケースに合わせて選択されたし・・・
port=7997
model1=cl-nagoya/ruri-v3-30m
model2=cl-nagoya/ruri-v3-reranker-310m
volume=$PWD/data
docker run --rm -it \
-v $volume:/app/.cache \
-p $port:$port \
michaelf34/infinity:latest \
v2 \
--model-id $model1 \
--model-id $model2 \
--port $port
なのだが、どうもモデルによってはダウンロードが上手くいかないことがあった。例えば上の例だと cl-nagoya/ruri-v3-30m はすぐにダウンロードされるのだが、cl-nagoya/ruri-v3-reranker-310m はなかなかダウンロードされない。ダウンロードされるディレクトリをウォッチしてても全然変更されない。CPUイメージも試してみたけどこちらも上手くいかず・・・
Ubuntuサーバでも試してみたけど、そちらだと問題なかったので、自分のMacの環境に問題があるのかも知れない。
とりあえずUbuntuサーバで起動したDockerコンテナで試してみる。
embedding
import requests
import json
url = "http://192.X.X.X:7997/embeddings"
payload = {
"model": "cl-nagoya/ruri-v3-30m",
"input": ["瑠璃色はどんな色?"]
}
response = requests.post(url, json=payload)
if response.status_code == 200:
print(json.dumps(response.json(), indent=4, ensure_ascii=False))
else:
print(f"エラー: {response.status_code}")
print(response.text)
{
"object": "list",
"data": [
{
"object": "embedding",
"embedding": [
0.025892337784171104,
-0.0017613227246329188,
0.01595025323331356,
0.011587179265916348,
0.07839227467775345,
(snip)
-0.0017702634213492274,
-0.021028583869338036,
-0.015378046780824661,
-0.023746564984321594,
0.007545971777290106
],
"index": 0
}
],
"model": "cl-nagoya/ruri-v3-30m",
"usage": {
"prompt_tokens": 9,
"total_tokens": 9
},
"id": "infinity-a8343ced-6ad5-4550-bd33-cb25a4faf0d2",
"created": 1744977250
}
reranking
import requests
import json
url = "http://rtx4090.local:7997/rerank"
payload = {
"model": "cl-nagoya/ruri-v3-reranker-310m",
"query": "瑠璃色はどんな色?",
"documents": [
(
"ワシ、タカ、ハゲワシ、ハヤブサ、コンドル、フクロウが代表的である。"
"これらの猛禽類はリンネ前後の時代(17~18世紀)には鷲類・鷹類・隼類及び"
"梟類に分類された。ちなみにリンネは狩りをする鳥を単一の目(もく)にまとめ、"
"vultur(コンドル、ハゲワシ)、falco(ワシ、タカ、ハヤブサなど)、strix"
"(フクロウ)、lanius(モズ)の4属を含めている。"
),
(
"瑠璃、または琉璃(るり)は、仏教の七宝の一つ。サンスクリットの vaiḍūrya"
" またはそのプラークリット形の音訳である。金緑石のこととも、ラピスラズリで"
"あるともいう[1]。"
),
(
"瑠璃色(るりいろ)は、紫みを帯びた濃い青。名は、半貴石の瑠璃(ラピスラズリ"
"、英: lapis lazuli)による。JIS慣用色名では「こい紫みの青」(略号 dp-pB)"
"と定義している[1][2]。"
)
],
"return_documents": True,
}
response = requests.post(url, json=payload)
if response.status_code == 200:
print(json.dumps(response.json(), indent=4, ensure_ascii=False))
else:
print(f"エラー: {response.status_code}")
print(response.text)
{
"object": "rerank",
"results": [
{
"relevance_score": 0.9999963045120239,
"index": 2,
"document": "瑠璃色(るりいろ)は、紫みを帯びた濃い青。名は、半貴石の瑠璃(ラピスラズリ、英: lapis lazuli)による。JIS慣用色名では「こい紫みの青」(略号 dp-pB)と定義している[1][2]。"
},
{
"relevance_score": 0.07807817310094833,
"index": 1,
"document": "瑠璃、または琉璃(るり)は、仏教の七宝の一つ。サンスクリットの vaiḍūrya またはそのプラークリット形の音訳である。金緑石のこととも、ラピスラズリであるともいう[1]。"
},
{
"relevance_score": 0.000368297885870561,
"index": 0,
"document": "ワシ、タカ、ハゲワシ、ハヤブサ、コンドル、フクロウが代表的である。これらの猛禽類はリンネ前後の時代(17~18世紀)には鷲類・鷹類・隼類及び梟類に分類された。ちなみにリンネは狩りをする鳥を単一の目(もく)にまとめ、vultur(コンドル、ハゲワシ)、falco(ワシ、タカ、ハヤブサなど)、strix(フクロウ)、lanius(モズ)の4属を含めている。"
}
],
"model": "cl-nagoya/ruri-v3-reranker-310m",
"usage": {
"prompt_tokens": 390,
"total_tokens": 390
},
"id": "infinity-97f384c7-f776-4b8d-937f-a08e6d18d84e",
"created": 1744977256
}
embeddingの方はOpenAI SDKでも試してみる。
from openai import OpenAI
client = OpenAI(
api_key="dummy",
base_url="http://192.X.X.X:7997/"
)
response = client.embeddings.create(
input="瑠璃色はどんな色?",
model="cl-nagoya/ruri-v3-30m",
)
print(response.data[0].embedding[:5])
[0.025892337784171104, -0.0017613227246329188, 0.01595025323331356, 0.011587179265916348, 0.07839227467775345]
ローカルダウンロード済みモデルを使うこともできるようなので、それで再度Mac上で試してみた。
まずモデルをダウンロード。
git lfs install
mkdir models && cd models
git clone https://huggingface.co/cl-nagoya/ruri-v3-30m
git clone https://huggingface.co/cl-nagoya/ruri-v3-reranker-310m
cd ..
コンテナ起動。モデルのディレクトリをマウントして、モデルIDの指定をパスで行えばよい。上のスクリプトにあわせていくつかオプションもつけてみた。あと、起動時にウォームアップが走るのだけど、結構長いのでスキップさせている。
docker run --rm -it \
-v ./models:/models \
-p 7997:7997 \
michaelf34/infinity:latest \
v2 \
--model-id "/models/ruri-v3-30m" \
--served-model-name "cl-nagoya/ruri-v3-30m" \
--model-id "/models/ruri-v3-reranker-310m" \
--served-model-name "cl-nagoya/ruri-v3-reranker-310m" \
--port 7997 \
--no-model-warmup
今度は起動して、一つ上のスクリプトもきちんと動作した。
その他
- Python APIで直接モデルを扱うこともできる。
- 一応OpenAI互換API(といってもrerankingなどOpenAIが提供していないものもあるが)なので、OpenAIクライアントも使えるし、REST APIでアクセスすればいいのだけど、専用のクライアントライブラリも用意されている様子。
まとめ
EmbeddingモデルをローカルでAPI立てる場合、以下のようなものがある。
これらと比較した場合に、Infinityにどのようなメリットがあるか?については、以下のIssueやベンチマークに記載されている。
高速性についてはまあその通りなんだろうと思うけど、CPU推論でも速いってのは強みかも(モデルにもよるだろうけど)。あと、個人的には、rerankingやColPaliなんかも含めて、まとめてホストできるってのは良いなと思ったところ。
ただ、オープンウェイトのモデルはいろいろあって、モデルによって動く・動かない、というかツールによってサポートしている・していないってのは結局ある。動くように直せるならいいんだけどね、自分は流石に直せる気がしないので、いろいろなツールを使い分けることにはなりそう。