技術 約10分で読めます

Sentence Transformers v5.4でテキスト・画像・音声・動画の統合Embeddingが可能に

いけさん目次

HuggingFaceが開発するSentence Transformersのv5.4が2026年4月9日にリリースされた。
最大の変更点は、これまでテキスト専用だった SentenceTransformerCrossEncoder のAPIがマルチモーダル入力に対応したこと。
テキスト、画像、音声、動画を同じ model.encode() に渡すだけで、共通のベクトル空間に埋め込める。

Sentence Transformersはテキストの意味的類似度検索やクラスタリングの定番ライブラリで、月間3000万回以上ダウンロードされている。
TRL v1.0のようなHuggingFaceエコシステムの一角を担うプロジェクトが、モダリティの壁を越えた形だ。

何が変わったのか

従来のSentence Transformersはテキスト同士の類似度計算に特化していた。
画像検索をやりたければCLIPモデルを別途扱う必要があったし、音声や動画に至ってはスコープ外だった。
v5.4では、VLM(Vision Language Model)ベースのモデルをSentence Transformersの統一インターフェースにラップすることで、モダリティを問わず同じAPIで埋め込みを生成できるようになった。

主な変更点は3つある。

  • マルチモーダルEmbeddingモデルの統合。SentenceTransformer クラスで画像・音声・動画をそのまま encode() に渡せる
  • マルチモーダルRerankerの追加。CrossEncoder クラスで異なるモダリティのペアをスコアリングできる
  • tokenizer_kwargsprocessor_kwargs にリネーム。テキストだけでなく画像のリサイズや音声のサンプリングレートなど、前処理パラメータを統一的に渡すための変更。旧名も後方互換で動く

対応モデル一覧

v5.4時点で統合されているモデルを整理した。

Embeddingモデル

モデルパラメータ数対応モダリティ備考
Qwen3-VL-Embedding-2B2Bテキスト, 画像, 動画Qwen3-VLベース
Qwen3-VL-Embedding-8B8Bテキスト, 画像, 動画高精度版
NVIDIA Nemotron Embed VL 1B v21.7Bテキスト, 画像軽量
NVIDIA Omni Embed Nemotron 3B4.7Bテキスト, 画像NVIDIAの汎用モデル
BGE-VL-base0.1Bテキスト, 画像BAAIの超軽量モデル
BGE-VL-large0.4Bテキスト, 画像BGE-VLの大型版
BGE-VL-MLLM-S1/S28Bテキスト, 画像MLLM統合版

Rerankerモデル

モデルパラメータ数対応モダリティ
Qwen3-VL-Reranker-2B2Bテキスト, 画像, 動画
Qwen3-VL-Reranker-8B8Bテキスト, 画像, 動画
NVIDIA Nemotron Rerank VL 1B v22Bテキスト, 画像
jina-reranker-m02Bテキスト, 画像

Qwen3-Omniが「入力から出力まで全モダリティをカバーする推論モデル」だとすれば、Qwen3-VL-Embedding/Rerankerは「検索と情報取得に特化したマルチモーダルモデル」という位置づけになる。
同じQwen3-VLアーキテクチャを基盤にしつつ、用途がまったく異なる。

EmbeddingとRerankerの使い分け

検索システムでEmbeddingモデルとRerankerは別の役割を担う。

flowchart TD
    A[ユーザークエリ] --> B[Embeddingモデルで<br/>クエリをベクトル化]
    B --> C[コーパス全体から<br/>Top-K候補を高速検索]
    C --> D[Rerankerで<br/>候補を精密スコアリング]
    D --> E[最終ランキング結果]
    
    F[コーパス<br/>テキスト/画像/動画] --> G[事前にEmbeddingで<br/>ベクトル化して保存]
    G --> C

Embeddingモデルは各入力を固定長のベクトルに変換する。
数百万件のドキュメントを事前にベクトル化しておけば、クエリのベクトルとの距離計算だけで高速に候補を絞り込める。
ただしベクトル同士の距離だけで測るため、微妙なニュアンスの違いは拾いにくい。

Rerankerはクエリとドキュメントのペアを直接入力として受け取り、関連度スコアを出力する。
ペアごとに推論を走らせるため遅いが、精度は高い。
数百万件に対して全ペアでRerankerを回すのは非現実的なので、Embeddingで絞った上位数十件にRerankerをかける二段構えが定石だ。

この二段構えのパイプラインは、NVIDIA NeMo RetrieverがViDoRe v3で1位を取った構成とも共通する。
NeMo Retrieverはさらにエージェントが検索クエリを自律的に書き換えるReACTループを加えていたが、基本構造は同じRetrieve & Rerank。

実際のコード

テキストと画像のクロスモーダル検索

from sentence_transformers import SentenceTransformer

model = SentenceTransformer(
    "Qwen/Qwen3-VL-Embedding-2B",
    revision="refs/pr/23"
)

# 画像をエンコード(URL、ファイルパス、PILオブジェクトに対応)
img_embeddings = model.encode([
    "https://example.com/car.jpg",
    "https://example.com/bee.jpg",
])

# テキストクエリをエンコード
text_embeddings = model.encode([
    "黄色い建物の前に停まった緑の車",
    "花に止まったハチ",
])

# クロスモーダル類似度を計算
similarities = model.similarity(text_embeddings, img_embeddings)

テキストも画像も同じ encode() に渡すだけ。
入力の型を見て自動的にモダリティを判別する。
URLの場合は自動ダウンロード、ローカルファイルパスの場合は直接読み込み、PIL.Imageオブジェクトの場合はそのまま処理される。

Rerankerで精密スコアリング

from sentence_transformers import CrossEncoder

model = CrossEncoder(
    "Qwen/Qwen3-VL-Reranker-2B",
    revision="refs/pr/11"
)

query = "黄色い建物の前に停まった緑の車"
documents = [
    "https://example.com/car.jpg",           # 画像
    "https://example.com/bee.jpg",           # 画像
    "ヨーロッパの街並みに停まるビンテージカー",  # テキスト
    {                                         # テキスト+画像の複合入力
        "text": "ヨーロッパの都市にある車",
        "image": "https://example.com/car.jpg",
    },
]

rankings = model.rank(query, documents)

Rerankerは画像単体、テキスト単体、テキスト+画像の複合入力を混在させたリストをそのまま受け取れる。
辞書形式 {"text": ..., "image": ...} でテキストと画像を1つのドキュメントとして結合する使い方は、OCRが困難なスライドやスクリーンショットの検索で有効だろう。

モダリティ対応の確認

model = SentenceTransformer("Qwen/Qwen3-VL-Embedding-2B", revision="refs/pr/23")

print(model.modalities)
# ['text', 'image', 'video', 'message']

print(model.supports("audio"))
# False

modalities プロパティでそのモデルが対応しているモダリティの一覧を取得できる。
Qwen3-VLベースのモデルは音声には未対応で、テキスト・画像・動画の3モダリティをカバーする。

モダリティギャップの問題

マルチモーダルEmbeddingには「モダリティギャップ」と呼ばれる既知の課題がある。
テキスト同士やテキストと画像のベクトル間の類似度が、モダリティが異なるペアでは系統的に低くなる現象だ。

例えば、車の画像と「緑の車」というテキストの類似度が0.51だったとする。
テキスト同士なら似た意味の文で0.8を超えることも珍しくない。
これはモデルの欠陥ではなく、異なるモダリティの埋め込みがベクトル空間内で別のクラスタを形成するために起きる。

実用上は、絶対値ではなく相対的な順序が保たれていれば検索には使える。
「車の画像」は「車のテキスト」との類似度が「ハチのテキスト」より高い、という順序関係は維持される。
ただし、テキスト検索とクロスモーダル検索を混ぜて使う場合にスコアの直接比較ができない点は設計時に意識が必要だ。

入力フォーマットの対応表

各モダリティで受け付ける入力形式を整理した。

モダリティ受け入れ形式
テキスト文字列
画像PIL.Image、ファイルパス、URL、numpy配列、torchテンソル
音声ファイルパス、URL、numpy配列、torchテンソル、{"array": ..., "sampling_rate": ...} 辞書、torchcodec.AudioDecoder
動画ファイルパス、URL、numpy配列、torchテンソル、{"array": ..., "video_metadata": ...} 辞書、torchcodec.VideoDecoder
複合{"text": ..., "image": ...} のようなモダリティ名をキーとする辞書

画像や動画のURL入力に対応しているのは開発時に便利だが、本番環境では事前ダウンロードしてローカルパスかPILオブジェクトで渡すほうがエラー処理の面で安全だ。

RAGパイプラインへのインパクト

これまでマルチモーダルRAGを構築するには、テキスト用のEmbeddingモデル(e.g. all-MiniLM-L6-v2)と画像検索用のCLIPモデルを別々に管理する必要があった。
検索インデックスもモダリティごとに分かれ、結果のマージロジックも自前で書く必要があった。

v5.4のマルチモーダルEmbeddingなら、テキストも画像も同じモデル・同じインデックスに入れられる。
MintlifyがRAGからChromaFsに切り替えた背景にはRAGの精度問題があったが、マルチモーダル対応は精度改善とは別の軸で、従来のRAGパイプラインの構成をシンプルにする。
PDFのスクリーンショットやスライド画像をテキストと同じ検索インデックスに投入してクエリできるのは、ドキュメント検索の実務で地味に効く。

ハードウェア要件

VLMベースのモデルはそれなりのGPUリソースを要求する。

モデルサイズ必要VRAM備考
0.1B(BGE-VL-base)1GB未満CPU推論も実用的
1-2B約8GBRTX 3060/4060クラス
8B約20GBRTX 4090、A100等

CPU推論は「極端に遅い」と公式が明記しており、GPU環境かGoogle Colabの利用が推奨されている。
Apple Siliconでの動作はドキュメントに明記がないが、PyTorchのMPS対応が進んでいるため、小型モデルなら動く可能性はある。

CLIPモデルとの関係

Sentence Transformersは以前からCLIPモデル(clip-ViT-L-14等)を SentenceTransformer クラスで扱えた。
v5.4でもCLIPのサポートは継続される。

CLIPとVLMベースのモデルの使い分けとしては、CLIPはImageNet Zero-Shot精度75.4%(ViT-L-14)でテキストと画像の2モダリティに限定されるが軽量で高速。
VLMベースのモデルは動画にも対応し、ドキュメント理解のような複雑なタスクに強いが重い。
既にCLIPでシステムを組んでいるなら無理に移行する必要はなく、動画対応やドキュメント画像の理解が必要になった段階で検討すればいい。

導入手順

基本インストール

pip install "sentence-transformers>=5.4.0"

これで torchtransformershuggingface-hub など主要な依存パッケージも一緒に入る。
既存環境にSentence Transformersが入っている場合は pip install -U sentence-transformers でアップグレードすればいい。

マルチモーダルモデルの追加依存

マルチモーダル機能を使うには、モデルごとに追加パッケージが必要になる。

Qwen3-VLベースのモデル(Embedding/Reranker両方):

pip install qwen-vl-utils

qwen-vl-utils は画像・動画の前処理を担うユーティリティで、Qwen3-VLモデルの processor が内部的に依存している。
これがないと encode() に画像を渡した時点でImportErrorになる。

動画入力を扱う場合:

pip install torchcodec

torchcodec はPyTorch公式の動画デコーダで、動画ファイルからフレームを抽出する。
動画を使わないならインストール不要。

NVIDIAモデル(Nemotron系):

pip install timm

timm(PyTorch Image Models)はNVIDIAのEmbeddingモデルが画像エンコーダとして利用する。

GPU環境のセットアップ

前述の通り、VLMベースのモデルはGPU推論がほぼ必須。
CUDAツールキットが入った環境なら、PyTorchをCUDA対応版で入れ直す。

# CUDA 12.1の場合
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121

# CUDA 12.4の場合
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124

Google Colabを使うならGPUランタイムを選択するだけでCUDA環境は構築済みなので、追加のPyTorchインストールは不要。

最小構成で動作確認する

まずは最軽量のBGE-VL-base(0.1B)で環境が正しくセットアップできているか確認する。

from sentence_transformers import SentenceTransformer

# 最軽量モデルで動作確認(初回はモデルダウンロードが走る)
model = SentenceTransformer("BAAI/BGE-VL-base")

# テキストEmbedding
text_emb = model.encode(["テスト文章"])
print(f"テキスト: shape={text_emb.shape}")

# 対応モダリティの確認
print(f"対応モダリティ: {model.modalities}")

# 画像Embedding(URLで渡す例)
from PIL import Image
import requests
from io import BytesIO

url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
img = Image.open(BytesIO(requests.get(url).content))
img_emb = model.encode([img])
print(f"画像: shape={img_emb.shape}")

# クロスモーダル類似度
similarity = model.similarity(text_emb, img_emb)
print(f"類似度: {similarity}")

BGE-VL-baseは1GB未満のVRAMで動くのでCPU環境でもギリギリ試せる。
ここで問題なければ、用途に合わせてQwen3-VLやNemotronの大きいモデルに切り替える流れになる。

依存パッケージの全体像

最終的にどのパッケージが必要かはモデルの選択次第で変わる。
整理するとこうなる。

用途必須パッケージ備考
テキストのみsentence-transformers>=5.4.0追加依存なし
Qwen3-VLモデル+ qwen-vl-utils画像・動画の前処理
Qwen3-VLで動画+ torchcodecフレーム抽出
NVIDIAモデル+ timm画像エンコーダ
GPU推論CUDA対応 torch2B以上はほぼ必須

要件定義ファイル(requirements.txt)にまとめるなら、こんな形になる。

sentence-transformers>=5.4.0
qwen-vl-utils
torchcodec
timm

全部入れても競合は起きないので、迷ったら全部入れて使わないものは放置でいい。