この記事では、ベクトル検索におけるベクトル埋め込み(vector embedding)技術について説明します。
ベクトル埋め込みとは?
ベクトル埋め込みは、非構造化データを数値ベクトルに変換する技術です。これらのベクトルは非構造化データの持つ意味情報(セマンティクス)を捉えることができるため、コンピュータがその意味を「理解」し、処理することが可能になります。具体的には:
ベクトル埋め込みは、テキスト、画像、音声・動画などの非構造化データを高次元ベクトル空間上の一点にマッピングします。
このベクトル空間では、意味的に類似したテキストは、互いに近い位置にマッピングされます。
ベクトルは通常、数百の数字で構成されます(例えば、512次元、1024次元など)。
ベクトル間の類似度は、コサイン類似度などの数学的手法を用いて計算することができます。
よく見られるベクトル埋め込みモデルには、Word2Vec、BERT、BGEなどが含まれます。例えば、RAGアプリケーションを開発する際には、通常、テキストデータに埋め込み処理を行いベクトルデータに変換した上でベクトルデータベースに格納し、その他の構造化データはリレーショナルデータベースに格納します。
OceanBase 4.3.3バージョンから、ベクトルデータをデータ型の一種としてリレーショナルテーブルに格納できるようになりました。これにより、ベクトルと従来のスカラーデータをOceanBaseという単一のデータベースに、順序立てて効率的に格納することが可能になります。
よくあるテキスト埋め込み方法
このセクションでは、テキストの埋め込み方法について説明します。
操作準備
pip コマンドを事前にインストールしておく必要があります。
オフライン・ローカルの事前学習済み埋め込みモデルの使用
事前学習済みモデルを用いてローカルでテキスト埋め込みを行うことは、最も柔軟な方法ですが、相当量の計算リソースを必要とします。代表的なモデルには以下のようなものがあります:
Sentence Transformersの使用
Sentence Transformersは自然言語処理(NLP)に用いられるモデルで、文章や段落をベクトル埋め込みに変換することを目的としています。深層学習技術、特にTransformerアーキテクチャをベースにしており、テキストの意味情報を効果的に捉えることができます。なお、中国国内から直接Hugging Faceのドメイン名にアクセスすると、タイムアウトすることが多いため、事前にHugging Faceのイメージアドレス export HF_ENDPOINT=https://hf-mirror.com を設定してください。設定後、以下のコードを実行します:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3")
sentences = [
"That is a happy person",
"That is a happy dog",
"That is a very happy person",
"Today is a sunny day"
]
embeddings = model.encode(sentences)
print(embeddings)
# [[-0.01178016 0.00884024 -0.05844684 ... 0.00750248 -0.04790139
# 0.00330675]
# [-0.03470375 -0.00886354 -0.05242309 ... 0.00899352 -0.02396279
# 0.02985837]
# [-0.01356584 0.01900942 -0.05800966 ... 0.00523864 -0.05689549
# 0.00077098]
# [-0.02149693 0.02998871 -0.05638731 ... 0.01443702 -0.02131325
# -0.00112451]]
similarities = model.similarity(embeddings, embeddings)
print(similarities.shape)
# torch.Size([4, 4])
Hugging Face Transformersの使用
Hugging Face Transformersはオープンソースのライブラリで、特に自然言語処理(NLP)タスク向けの事前学習済みディープラーニングモデルを多数提供しています。中国国内から直接Hugging Faceのドメイン名にアクセスすると、タイムアウトになることが多いため、事前にHugging Faceのイメージアドレスexport HF_ENDPOINT=https://hf-mirror.comを設定してください。設定後、以下のコードを実行します:
from transformers import AutoTokenizer, AutoModel
import torch
# モデルとトークナイザーのロード
tokenizer = AutoTokenizer.from_pretrained("BAAI/bge-m3")
model = AutoModel.from_pretrained("BAAI/bge-m3")
# 入力の準備
texts = ["これはサンプルテキストです"]
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
# 埋め込みの生成
with torch.no_grad():
outputs = model(**inputs)
embeddings = outputs.last_hidden_state[:, 0] # [CLS] tokenの出力を使用
print(embeddings)
# tensor([[-1.4136, 0.7477, -0.9914, ..., 0.0937, -0.0362, -0.1650]])
print(embeddings.shape)
# torch.Size([1, 1024])
Ollama
Ollamaは、ローカル環境で大規模言語モデルを手軽に実行、管理、利用できるようにするオープンソースのツールです。Llama 3やMistralなどのオープンソース言語モデルに加え、bge-m3などの埋め込みモデルもサポートしています。
Ollamaをデプロイする
macOSおよびWindowsでは、公式サイトからインストールパッケージを直接ダウンロードしてインストールできます。インストール方法については、Ollamaの公式サイトを参照してください。インストールが完了すると、Ollamaはサービスとしてバックグラウンドで実行されます。
Linux上でOllamaをインストールする:
curl -fsSL https://ollama.ai/install.sh | sh埋め込みモデルをプルする
Ollamaは、テキスト埋め込みにbge-m3モデルの使用をサポートしています:
ollama pull bge-m3Ollamaを使用してテキスト埋め込みを実行する
Ollamaの埋め込み機能は、HTTP APIやPython SDKなどの方法で利用できます:
HTTP API方式
import requests def get_embedding(text: str) -> list: """OllamaのHTTP APIを使用してテキスト埋め込みを取得する""" response = requests.post( 'http://localhost:11434/api/embeddings', json={ 'model': 'bge-m3', 'prompt': text } ) return response.json()['embedding'] # 使用例 text = "これはサンプルテキストです" embedding = get_embedding(text) print(embedding) # [-1.4269912242889404, 0.9092104434967041, ...]Python SDK方式
まず、OllamaのPython SDKをインストールします:
pip install ollama次に、このように使用できます:
import ollama # 使用例 texts = ["最初の文", "2番目の文"] embeddings = ollama.embed(model="bge-m3", input=texts)['embeddings'] print(embeddings) # [[0.03486196, 0.0625187, ...], [...]]
Ollamaの長所と短所
長所:
- 完全ローカルデプロイメントで、ネットワーク接続は不要
- オープンソースで無料、API Keyは不要
- 複数のモデルをサポートし、切り替えと比較が容易
- リソースの占有が比較的小さい
短所:
- 埋め込みモデルの選択肢は少ない
- パフォーマンスは商用サービスに劣る可能性がある
- 自社で保守や更新を行う必要がある
- エンタープライズ向けのサポートが不足している
Ollamaを使用するかどうかを判断する際には、これらの要素を考慮する必要があります。プライバシー要件が厳しいアプリケーションシナリオの場合、または完全にオフラインで動作させたい場合は、Ollamaは優れた選択肢です。しかし、より安定したサービス品質とパフォーマンスが必要な場合は、商用サービスを検討する必要があるかもしれません。
オンライン・リモート型の埋め込みサービスの使用
ローカル環境で埋め込みモデルを運用する場合、マシンのスペックに高い要件が課されるほか、モデルの読み込み・アンロードなどの管理もユーザー側に負担がかかります。そのため、多くのユーザーがオンラインで利用できる埋め込みサービスを求めており、現在はさまざまなAI推論サービス事業者が対応するテキスト埋め込みサービスを提供しています。例えば、Qwenのテキスト埋め込みサービスを利用する場合、まずAlibaba Cloud Model Studioアカウントに登録し、API Keyを取得したら、公開されているAPIを呼び出すことで、テキスト埋め込みの結果を得ることができます。
HTTP呼び出し
取得が完了したら、以下のコードでテキスト埋め込みを試すことができます。Python環境にrequestsパッケージがインストールされていない場合は、pip install requests でインストールしてからネットワークリクエストを送信する必要があります。
import requests
from typing import List
class RemoteEmbedding():
def __init__(
self,
base_url: str,
api_key: str,
model: str,
dimensions: int = 1024,
**kwargs,
):
self._base_url = base_url
self._api_key = api_key
self._model = model
self._dimensions = dimensions
"""
OpenAI compatible embedding API. Tongyi, Baichuan, Doubao, etc.
"""
def embed_documents(
self,
texts: List[str],
) -> List[List[float]]:
"""Embed search docs.
Args:
texts: List of text to embed.
Returns:
List of embeddings.
"""
res = requests.post(
f"{self._base_url}",
headers={"Authorization": f"Bearer {self._api_key}"},
json={
"input": texts,
"model": self._model,
"encoding_format": "float",
"dimensions": self._dimensions,
},
)
data = res.json()
embeddings = []
try:
for d in data["data"]:
embeddings.append(d["embedding"][: self._dimensions])
return embeddings
except Exception as e:
print(data)
print("Error", e)
raise e
def embed_query(self, text: str, **kwargs) -> List[float]:
"""Embed query text.
Args:
text: Text to embed.
Returns:
Embedding.
"""
return self.embed_documents([text])[0]
embedding = RemoteEmbedding(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings", # https://bailian.console.aliyun.com/#/model-market/detail/text-embedding-v3?tabKey=sdkを参照してください
api_key="your-api-key", # API Keyを入力します
model="text-embedding-v3",
)
print("Embedding result:", embedding.embed_query("今日の天気はいいね"), "\n")
# Embedding result: [-0.03573227673768997, 0.0645645260810852, ...]
print("Embedding results:", embedding.embed_documents(["今日の天気はいいね", "明日は?"]), "\n")
# Embedding results: [[-0.03573227673768997, 0.0645645260810852, ...], [-0.05443647876381874, 0.07368793338537216, ...]]
Qwen SDKの使用
Qwenは、モデルの能力を迅速に呼び出すためのdashscopeというSDKを提供しています。pip install dashscope を実行してインストールすると、テキスト埋め込みの内容を取得できます。
import dashscope
from dashscope import TextEmbedding
# API Keyの設定
dashscope.api_key = "your-api-key"
# 入力テキストの準備
texts = ["これは最初の文です", "これは2番目の文です"]
# 埋め込みサービスの呼び出し
response = TextEmbedding.call(
model="text-embedding-v3",
input=texts
)
# 埋め込み結果の取得
if response.status_code == 200:
print(response.output['embeddings'])
# [{"embedding": [-0.03193652629852295, 0.08152323216199875, ...]}, {"embedding": [...]}]
よくある画像の埋め込み方法
このセクションでは、画像の埋め込み方法について説明します。
オフラインのローカルな事前学習済み埋め込みモデルを使用する
CLIPの使用
CLIP (Contrastive Language-Image Pretraining)は、OpenAIによって提案された、画像とテキストを組み合わせてマルチモーダル学習を行うことを目的としたモデルです。CLIPは画像とテキストの関係を理解し処理することができるため、画像分類、画像検索、テキスト生成など、さまざまなタスクで優れた性能を発揮します。
from PIL import Image
from transformers import CLIPProcessor, CLIPModel
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
# 入力画像の準備
image = Image.open("path_to_your_image.jpg")
texts = ["これは一つ目の文です", "これは二つ目の文です"]
# 埋め込みサービスを呼び出す
inputs = processor(text=texts, images=image, return_tensors="pt", padding=True)
outputs = model(**inputs)
# 埋め込み結果の取得
if outputs.status_code == 200:
print(outputs.output['embeddings'])
# [{"embedding": [-0.03193652629852295, 0.08152323216199875, ...]}, {"embedding": [...]}]