埋め込み (opens new window)は、単語やフレーズの意味的な本質を捉えたデータの数値表現です。これらの埋め込みは、高次元ベクトルとしてエンコードされており、さまざまなデータアプリケーションで効率的な処理が可能です。埋め込みは使用するモデルによって異なる場合があります。同じテキストでも、異なるモデルを使用して生成すると、異なる埋め込みが得られる場合があります。テキストデータが主な焦点ですが、埋め込みはテキスト情報に限定されず、画像やグラフなどの他のデータタイプにも適用することができます。
埋め込みは、ベクトルデータベース (opens new window)の文脈ではさらに価値があります。これらの埋め込みに基づいて基本的な類似性/距離の測定を適用することで、テキスト(または他のデータ)のペアがどれだけ類似しているか、または異なっているかを確認することができます。また、最も関連性の高いサンプルを見つけるためにも使用することができます。これらの使用法は、背景知識をほとんど必要とせずに基本的な重要性を持っています。
このブログでは、OpenAI、Jina、Bedrockなどの人気のあるモデルを使用して埋め込みを生成および使用する方法について説明します。MyScaleのEmbedText()関数を使用すると、特に大規模なデータを扱う場合に埋め込みを効率的に操作することができます。このツールを活用することで、埋め込みベースの検索やその他のテキスト処理機能をアプリケーションにシームレスに統合することができます。また、MyScaleのパフォーマンスとコスト効率の利点を享受することもできます。
# 埋め込みモデル
従来、Word2Vec、GloVe、LSAなどの古典的な埋め込みモデルがありました。後に、これらは徐々にRNN/LSTMベースのモデルに置き換えられました。トランスフォーマーの非凡な能力により、トランスフォーマーが埋め込みの事実上のモデルとなりました。埋め込みを生成するためには、いくつかの方法があります。
- モデルのトレーニング: 高い計算リソースがある場合やデータプライバシーの問題がある場合など、ローカルでのトレーニングは良い選択肢です。ここでのトレーニングは、必ずしもゼロからモデルをトレーニングすることを意味せず、微調整も含まれます(ほとんどの場合はそうです)。トレーニングが完了したら、このモデルを使用して埋め込みを生成することができます。
- 事前学習済みモデルの使用: 通常、埋め込みのためにモデルをトレーニングする必要はありません。ほとんどの場合、埋め込み生成には標準的なモデルセットが使用されます。たとえば、GPTシリーズ、Phiシリーズ、Titan、Llama、FalconなどのいくつかのSLMがあります。
事前学習済みモデルを使用する場合、いくつかのオプションがあります。HuggingFaceモデルは、ローカルで実行する場合には優れたオプションです(推論には必ずしもGPUが必要ではないため、通常のノートパソコンでも動作します)。一方、クラウドベースのサービスも多数あります。OpenAI、Cohere、Jinaなどが良い例です。これらのサービスが有用な理由のもう一つは、一部の最先端モデル(GPT-4ファミリーなど)が利用できないことです。
# HuggingFaceモデルの使用
Hugging Face (opens new window)には、特に埋め込みに使用されるモデルを含む、多数のトランスフォーマーモデルがホストされています。Hugging Faceモデルを使用するには、対応するモデルとトークナイザーを呼び出す必要があります。これらのモデルのダウンロードには時間がかかる場合があります。ダウンロードが完了すると、キャッシュに保存され、PyCharmのHugging Faceコンソールを使用して管理することができます。
from transformers import AutoModel, AutoTokenizer
modelName = "TencentBAC/Conan-embedding-v1"
tokenizer = AutoTokenizer.from_pretrained(modelName)
model = AutoModel.from_pretrained(modelName)
text = "All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood."
inputs = tokenizer(text, return_tensors="pt")
tokenEmbeddings = model(**inputs).last_hidden_state
これらのトークン埋め込みをプーリングして文の埋め込みに変換すると便利です。
sentenceEmbedding = tokenEmbeddings.mean(dim=1)
sentenceEmbedding[0]
Hugging Faceを使用した埋め込みは非常に良いですが、いくつかの場合には問題が発生することがあります。
- リソースの制約: 通常、HFモデルはあまりスペースを取りません(平均1 GB程度)、しかし、ディスクやメモリが不足している場合は実行できません。
- 一部のモデルの利用不可: Hugging Faceには多くのモデルがホストされていますが、まだ一部のモデルは専用のサービス(GPT-4など)にホストされています。
これらのモデルをリモートで使用するには、OpenAI、Amazon Bedrock、Cohereなどのさまざまなサービスを使用します。これらをMyScaleと組み合わせて使用することができます。
# MyScaleでの埋め込みの取得
先述のように、埋め込みはベクトルデータベースアプリケーションにおいて中心的な役割を果たします。MyScaleは、OpenAI、Cohere、Jinaなどのさまざまなサービスを含む、さまざまなサービスを使用して埋め込み(現時点ではテキストのみ)を計算する機能、EmbedText関数を提供しています。この統合は非常に便利で、テキストをベクトルに変換する作業を簡素化します。高スループットのための自動バッチ処理をサポートし、リアルタイムの検索やバッチ処理に役立ちます。この関数にはいくつかの重要なパラメータがあります。
text
: 埋め込みを計算したいテキスト文字列。例えば、'Thou canst not then be false to any man.'
。provider
: 埋め込みモデルのプロバイダの名前(8つのプロバイダがサポートされています。大文字小文字を区別しません)。例えば、OpenAI
。api_key
: 各プロバイダアカウントのAPIキー。サービスから直接提供され、MyScaleとは関係ありません。
注意: これらの埋め込みサービスはトークンの使用に基づいて料金が発生するため、同じ埋め込みを繰り返し計算することを避けることが重要です。代わりに、一度生成した埋め込みは効率的な再利用のためにデータベースに保存する必要があります。
これらのパラメータに加えて、オプションのパラメータとしてbase_url
もあります(ほとんどのプロバイダでは必要ありません)。
# OpenAIモデルの使用
次のコードスニペットは、OpenAIの埋め込みをEmbedText()
を使用してどのように使用するかを示しています。
SELECT EmbedText('<input-text>', 'openAI', '', '<Access Key>', '{"model":"text-embedding-3-small", "batch_size":"50"}')
ここでは、API URL、出力ベクトルの次元、ユーザーIDのオプション引数もあります。OpenAIは3つの埋め込みモデルを提供しています。Ada-002とEmbedding-3(smallとlarge)です。大きいバージョンは3072次元の埋め込みベクトルを生成し、解像度が高く、より大きなドキュメントを扱う際に非常に役立ちます。
モデル | 説明 | 出力次元 |
---|---|---|
text-embedding-3-large | 英語および非英語のタスクのための最も能力のある埋め込みモデル | 3,072 |
text-embedding-3-small | 2世代目のAda埋め込みモデルよりも高いパフォーマンス | 1,536 |
text-embedding-ada-002 | 最も能力のある2世代の埋め込みモデルで、16の1世代目モデルを置き換える | 1,536 |
さらに、小さいモデルでもその能力を示すために、大量のテキスト(1つの章全体)を取り、その埋め込みを生成します。
service_provider = 'OpenAI'
textInput = 'We will leave Danglars struggling with the demon of hatred, and\\r\\nendeavoring to insinuate in the ear of the shipowner some evil...' #ここでは意図的に切り詰めています
parameters = {'sampleString': textInput, 'serviceProvider': service_provider}
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', 'sk-xxxxxxxx', '{"model":"text-embedding-3-small", "batch_size":"50"}')
""", parameters=parameters)
print(x.result_rows[0][0])
注意: EmbedText()
は最大5600文字のテキストを受け取ることができます。
ここでは、result_rows[0][0]
を取得しています。result_rows
を直接使用すると、リストとタプルの不要なネストが生じます。
# Bedrockモデルの使用
Amazon Bedrockは、ユーザーにさまざまな基礎モデルへのアクセスを提供します。モデルを使用する前に、まずアクセスを取得する必要があります(非常に簡単です)。その後、MyScaleから直接呼び出すことができます。
SELECT EmbedText('<input-text>', 'Bedrock', '', '<SECRET_ACCESS_KEY>', '{"model":"amazon.titan-embed-text-v1", "region_name":"us-east-1", "access_key_id":"ACCESS_KEY_ID"}')
次の例がそれを詳しく説明します。
client.command("""
CREATE TABLE IF NOT EXISTS EmbeddingsCollection (
id UUID,
sentences String, -- テキストデータを保存するためのテキストフィールド
embeddings Array(Float32),
--CONSTRAINT check_data_length CHECK length(embeddings) = 1536
) ENGINE = MergeTree()
ORDER BY id;
""")
EmbeddingsCollection
は、生成された埋め込みを保存するためにすぐに役立ちます。いくつかのランダムなテキストサンプルを取り、それらの埋め込みを計算します。
service_provider = 'Bedrock'
embeddingModel = 'amazon.titan-embed-text-v1'
embeddingsList = []
for i in range(500, 1000, 30):
randomLine = hamletLines[i]
parameters = {'sampleString': randomLine, 'serviceProvider': service_provider, 'model': embeddingModel}
if len(randomLine) < 30: #小さすぎるパッセージは無視します。
continue
else:
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', '12PXA8xxxxxxxxxxx', '{"model":"amazon.titan-embed-text-v1", "region_name":"us-east-1", "access_key_id":"AKIxxxxxxxx"}')
""", parameters=parameters)
_id = client.query("""SELECT generateUUIDv4()
""")
embeddingsList.append((_id.result_rows[0][0], randomLine, x.result_rows[0][0]))
埋め込みベクトルを抽出する際にUUIDを取得する方法と同じように、埋め込みベクトルを追加する際にもUUIDを取得しています(UUIDは単一のオブジェクトです)。このembeddingsList
はテーブルに挿入され、類似性検索などのさまざまなタスクにさらに使用することができます。
# Jinaモデルの使用
Jinaは比較的新しいサービスです。Jinaサービスを使用するには、入力テキスト、アクセスキー、モデルを指定することができます。MyScaleのデフォルトモデルはjina-embeddings-v2-base-en
で、768次元の埋め込みを返します。これは他のモデルと比較して解像度が低いです。
SELECT EmbedText('<input-text>', 'jina', '', '<access key>', '{"model":"jina-embeddings-v2-base-en"}')
以下は例です。他のプロバイダを使用した場合とほぼ同じです。EmbedText()
を使用することで、プロバイダをカプセル化することができ、より同じサービスを使用しているように感じることができます。
service_provider = 'jina'
textInput = "The Astronomer's Telegram (ATel) is an internet-based short-notice publication service for quickly disseminating information on new astronomical observations.[1][2] Examples include gamma-ray bursts,[3][4] gravitational microlensing, supernovae, novae, or X-ray transients, but there are no restrictions on content matter. Telegrams are available instantly on the service's website, and distributed to subscribers via email digest within 24 hours' #ここでは意図的に切り詰めています
parameters = {'sampleString': textInput, 'serviceProvider': service_provider}
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', 'jina_faxxxxxxx', '{"model":"jina-embeddings-v2-base-en"}')
""", parameters=parameters)
x.result_rows[0][0]
# MyScaleでの埋め込みの処理
埋め込みを取得する方法を知ったので、それらをどのように使用するかを見てみましょう。これらの埋め込みを生成するのにコストがかかるため、生成後すぐにデータベースに保存する必要があります。MyScaleではこれが非常に簡単です。テーブルを作成し、そこに埋め込みを挿入します。
client.command("""
CREATE TABLE IF NOT EXISTS EmbeddingsCollection (
id UUID,
sentences String, -- テキストデータを保存するためのテキストフィールド
embeddings Array(Float32),
--CONSTRAINT check_data_length CHECK length(embeddings) = 1536
) ENGINE = MergeTree()
ORDER BY id;
""")
すでにIDと入力テキスト、それに対応する埋め込みの形式でデータフレームがあるため、itertuples()
を呼び出して対応するメソッドを使用して挿入するだけです。
df_records = list(df.itertuples(index=False, name=None))
client.insert("EmbeddingsCollection", df_records, column_names=["id", "sentences", "embeddings"])
これでデータがテーブルに保存されたので、ベクトルインデックスを追加することができます。このインデックスは、類似性検索で役立ちます。
client.command("""
ALTER TABLE EmbeddingsCollection
ADD VECTOR INDEX cosine_idx embeddings
TYPE MSTG
('metric_type=Cosine')
""")
# 効率性
主要な作業が完了したので、なぜ埋め込みが非常に有用であり、MyScaleがどれだけ効率的であるかが非常に簡単に理解できます。たとえば、本全体に対して類似性検索を行うと、わずか数秒で結果が得られます。
service_provider = 'jina'
queryString = "
parameters = {'sampleString': queryString, 'serviceProvider': service_provider}
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', 'jina_faxxxxxxx', '{"model":"jina-embeddings-v2-base-en"}')
""", parameters=parameters)
queryEmbeddings = x.result_rows[0][0]
results = client.query(f"""
SELECT id, sentences, embeddings,
distance(embeddings, {queryEmbeddings}) as dist
FROM BookEmbeddings
ORDER BY dist LIMIT 3
""")
df = pd.DataFrame(results.result_rows)
結果として、上位3つの結果が得られます。
埋め込みモデルのシームレスな統合、印象的なパフォーマンス、コスト削減というこれらの重要な利点により、MyScaleはモダンなデータアプリケーションに対する強力なプラットフォームとなっています。
# 結論
MyScaleのEmbedText()
関数を活用することで、OpenAI、Bedrock、Jinaなどの人気のある埋め込みモデルをアプリケーションにシームレスに統合する方法を説明しました。MyScale内で埋め込みを生成し、処理することで、ワークフローが簡素化されるだけでなく、大規模なデータを扱う場合でも印象的なパフォーマンスを実現することができます。
例えば、800ページ以上の本を数秒で類似性検索することは、MyScaleの効率と速度を示すものです。このような迅速な処理は、従来のNLPモデルでは困難でした。さらに、MyScaleの機能はテキストに限定されるものではありません。画像や他のデータタイプの埋め込みも扱うことができ、多くのアプリケーションの可能性を広げることができます。
MyScaleの特徴は、パフォーマンスだけでなく、コスト効率も優れている点です。他のベクトルデータベースとは異なり、MyScaleは高い柔軟性と機能を提供しますが、高額な価格設定はありません。8000万のベクトルを管理するためにスケールアップしても、コストは非常に低く抑えられます。8つのポッドを実行しても、1時間あたりのコストは$0.10以下です。
この手頃な価格設定により、MyScaleはスタートアップ企業や既存のビジネスにとっても理想的な選択肢となります。要するに、MyScaleは埋め込みの可能性を最大限に活用し、モダンなデータアプリケーションに対する強力でスケーラブルかつ経済的なソリューションを提供します。