最先端の検索拡張LLM: bge-large-en-v1.5

最先端の検索拡張LLM: bge-large-en-v1.5

はじめに

最先端の検索拡張LLM『bge-large-en-v1.5』に興味はありませんか?このブログでは、このモデルを深く掘り下げていきます。埋め込みモデルの役割とその実用的な応用を明らかにします。コードでの『bge-large-en-v1.5』のデプロイ、ファインチューニング、そしてLLM APIとのシームレスな統合を解説します。埋め込みモデルとLLMの交差点で新たな可能性を開く準備をしましょう!

bge-large-en-v1.5 とは?

簡単に言えば、bge-large-en-v1.5 は BAAI によって作成されたオープンソースの埋め込みモデルです。

具体的には、『bge-large-en-v1.5』の『bge』は『BAAI General Embedding』を意味します。BAAI は Github では『FlagEmbedding』としても知られ、AI の研究開発に専念する民間の非営利団体です。BAAI は検索拡張大規模言語モデル (LLM) に焦点を当て、いくつかの関連プロジェクトを立ち上げています。これには、長文脈 LLM (Activation Beacon)、LM ファインチューニング (LM-Cocktail)、高密度検索 (BGE-M3、LLM Embedder、BGE Embedding)、リランカーモデル (BGE Reranker)、ベンチマーク (C-MTEB) が含まれます。bge-large-en-v1.5 は BGE Embedding モデルシリーズに属し、特に高密度検索のために開発されました。

高密度検索のための埋め込みモデルは何をするのか?

高密度検索のための埋め込みモデルは、テキストデータを、入力の意味と文脈を捉えた高密度な意味表現に変換します。これらの高密度表現は、高密度検索器によって関連情報を効率的に取得するために使用されます。以下にその仕組みと例を示します。

テキストを高密度表現に変換する

埋め込みモデルは、文、段落、文書全体を入力として受け取り、固定長のベクトル(埋め込み)に変換します。これらのベクトルはテキストに関する意味情報をエンコードし、単純なキーワードマッチングを超えた、より微妙な理解を可能にします。

LLM はしばしば、そのアーキテクチャの一部として埋め込みモデルを取り入れています。例えば、BERT は埋め込み技術を使用して、トランスフォーマー層で処理する前に単語や入力シーケンスを表現します。LLM は、意味的な関係や文脈のニュアンスを捉える埋め込みモデルの能力を活用することで、対話生成や機械翻訳などのタスクにおいて、一貫性があり文脈に適した応答を生成するのに役立てています。

高密度検索器の役割

高密度検索器は、これらの埋め込みを利用して検索タスクを実行します。正確なキーワードマッチングやインデックスに依存する従来のスパース検索方法とは異なり、高密度検索器はクエリ埋め込みと文書埋め込みの間の類似度スコアを直接計算します。このアプローチにより、短い文から長い文書まで、さまざまな長さのテキスト入力に対してより正確な検索が可能になります。

応用例

情報検索タスク(検索エンジンや質問応答システムなど)では、これらの高密度表現により、関連する文書やパッセージを効率的かつ正確に取得できます。

例えば、「COVID-19の症状は何ですか?」というクエリは埋め込みベクトルに変換されます。同様に、COVID-19の症状について議論している文書も埋め込みに変換されます。クエリ埋め込みと文書埋め込みの間の類似度(コサイン類似度などの手法を使用)を比較することで、最も関連性の高い文書を迅速に識別しランク付けできます。

別の例はレコメンデーションシステムです。この場合、埋め込みはユーザーの好みやコンテンツの類似性を理解することで、製品、記事、動画のレコメンドに役立ちます。

全体として、高密度検索のための埋め込みモデルは、高密度検索器と組み合わせることで、テキストを意味のある表現に変換し、意味的類似性に基づいて関連情報を効率的に取得することで、現代の AI アプリケーションにおいて重要な役割を果たします。

コードで bge-large-en-v1.5 を使用するには?

Langchain で bge-large-en-v1.5 を使用する

langchain で bge を次のように使用できます。

from langchain.embeddings import HuggingFaceBgeEmbeddings
model_name = "BAAI/bge-large-en-v1.5"
model_kwargs = {'device': 'cuda'}
encode_kwargs = {'normalize_embeddings': True} # コサイン類似度を計算するには True に設定
model = HuggingFaceBgeEmbeddings(
    model_name=model_name,
    model_kwargs=model_kwargs,
    encode_kwargs=encode_kwargs,
    query_instruction="関連記事の検索に使用するために、この文の表現を生成してください:"
)
model.query_instruction = "関連記事の検索に使用するために、この文の表現を生成してください:"

Huggingface Transformers で bge-large-en-v1.5 を使用する

Transformers パッケージを使用すると、次のようにモデルを使用できます。まず、入力データをトランスフォーマーモデルに通し、次に最初のトークン(つまり [CLS])の最後の隠れ状態を文の埋め込みとして選択します。

from transformers import AutoTokenizer, AutoModel
import torch
# 文埋め込みを取得したい文
sentences = ["サンプルデータ-1", "サンプルデータ-2"]

# HuggingFace Hub からモデルをロード
tokenizer = AutoTokenizer.from_pretrained('BAAI/bge-large-en-v1.5')
model = AutoModel.from_pretrained('BAAI/bge-large-en-v1.5')
model.eval()
# 文をトークン化
encoded_input = tokenizer(sentences, padding=True, truncation=True, return_tensors='pt')
# s2p (短いクエリから長いパッセージへの検索) タスクの場合、クエリに指示を追加 (パッセージには指示を追加しない)
# encoded_input = tokenizer([instruction + q for q in queries], padding=True, truncation=True, return_tensors='pt')
# トークン埋め込みを計算
with torch.no_grad():
    model_output = model(**encoded_input)
    # プーリングを実行。この場合は cls プーリング。
    sentence_embeddings = model_output[0][:, 0]
# 埋め込みを正規化
sentence_embeddings = torch.nn.functional.normalize(sentence_embeddings, p=2, dim=1)
print("文埋め込み:", sentence_embeddings)

bge モデルの使用方法の詳細については、Github の FlagEmbedding を参照してください。

bge-large-en-v1.5 をファインチューニングするには?

ステップ 1 インストール

  • pip を使用してインストール: pip install -U FlagEmbedding
  • または、リポジトリをクローンして移動した後、ソースからインストール: pip install .
  • 開発の場合は、編集可能インストールを使用: pip install -e .

ステップ 2 データ準備

  • トレーニングデータは JSON 形式で、各行が querypos (正例テキストのリスト)、neg (負例テキストのリスト) を含む辞書である必要があります。
  • 負例テキストが利用できない場合は、コーパスからランダムにサンプリングできます。

ステップ 3 ハードネガティブのマイニング

  • スクリプトを使用してハードネガティブをマイニングし、文埋め込みの品質を向上させます。
  • 次のコマンドでハードネガティブをマイニングできます。
python -m FlagEmbedding.baai_general_embedding.finetune.hn_mine \
--model_name_or_path BAAI/bge-base-en-v1.5 \
--input_file toy_finetune_data.jsonl \
--output_file toy_finetune_data_minedHN.jsonl \
--range_for_sampling 2-200 \
--negative_number 15 \
--use_gpu_for_searching
  • 入力ファイル: ファインチューニング用データを含む JSON ファイル。スクリプトはクエリごとに上位 k 個の文書を特定し、それらの上位 k 個の結果から、既に提供されている正例を除外した上で負例をランダムに選択します。
  • 出力ファイル: 新たにサンプリングされたハードネガティブで拡充された JSON ファイルを保存する先。ファインチューニングプロセスで使用します。
  • ネガティブ数: 収集する負例サンプルの数を指定します。
  • サンプリング範囲: 負例サンプルを抽出する範囲を定義します。例えば、範囲を 2–100 とすると、上位 2 から上位 200 の文書から負例が取得されます。範囲を 60–300 などに広げると、より広い文書セットを考慮するため、負例の選択が難易度の低いものになります。
  • 検索プール: スクリプトが検索のために文書を抽出するソース。デフォルトでは入力ファイル内のすべての負例のセットで、事前学習データと同様の形式です。特定の検索プールが指定された場合、スクリプトはそのセットを使用して負例を見つけます。
  • GPU ベースの検索: GPU 高速化の faiss-gpu を使用して負例検索プロセスの効率を向上させるかどうかを示すオプション。

ステップ 4 トレーニング

torchrun --nproc_per_node {GPU の数} \
-m FlagEmbedding.baai_general_embedding.finetune.run \
--output_dir {モデル保存先パス} \
--model_name_or_path BAAI/bge-large-en-v1.5 \
--train_data ./toy_finetune_data.jsonl \
--learning_rate 1e-5 \
--fp16 \
--num_train_epochs 5 \
--per_device_train_batch_size {大きいバッチサイズ; トイデータでは 1 に設定} \
--dataloader_drop_last True \
--normlized True \
--temperature 0.02 \
--query_max_len 64 \
--passage_max_len 256 \
--train_group_size 2 \
--negatives_cross_device \
--logging_steps 10 \
--save_steps 1000 \
--query_instruction_for_retrieval ""
  • デバイスごとのトレーニングバッチサイズ: 各トレーニングバッチで処理されるサンプル数。通常、バッチサイズを増やすとモデルのパフォーマンスが向上します。半精度トレーニング(--fp16)、DeepSpeed 設定(--deepspeed ./df_config.jsondf_config.jsonds_config.json とも表記)、勾配チェックポイント(--gradient_checkpointing)などのオプションを使用してサイズを拡大できます。
  • トレーニンググループサイズ: トレーニング中に各クエリに使用される正例と負例の総数を決定します。正例が必ず 1 つあるため、この設定は負例の数を決定します(train_group_size - 1 として計算)。この数はデータの neg リスト内の利用可能な負例を超えてはならないことに注意してください。これらのグループ負例に加えて、バッチ内の他の負例もファインチューニングプロセスに組み込まれます。
  • クロスデバイス負例共有: 利用可能なすべての GPU に負例を分散できるようにし、トレーニングで使用される負例の総数を実質的に増加させます。
  • 学習率: 特定のモデルに適した値を選択します。大規模、ベース、小規模モデルでは、一般的に 1e-5、2e-5、3e-5 などの値が推奨されます。
  • 温度: 類似度スコア分布の広がりに影響します。推奨される値の範囲は 0.01 から 0.1 です。
  • 最大クエリ長: クエリ長の上限。データセット内の平均クエリ長に対応する必要があります。
  • 最大パッセージ長: パッセージ長の上限。データ内のパッセージの平均長に応じて設定します。
  • 検索クエリ指示: 検索目的で各クエリに追加されるオプションの指示。追加のコンテキストが不要な場合は空の文字列に設定して空白にできます。
  • インバッチ負例使用: 同じバッチのパッセージをトレーニング中の負例と見なすかどうかを示すフラグ。デフォルトでは有効(True)です。
  • チェックポイント保存間隔: 完了したトレーニングステップ数に基づいてモデルチェックポイントを保存する頻度を定義します。

ステップ 5 モデルのロード

BGE モデルがファインチューニングされたら、この例のように簡単にロードできます。ファインチューニングフェーズで --query_instruction_for_retrieval ハイパーパラメータにユニークな値を指定した場合は、それに応じて query_instruction_for_retrieval を置き換えてください。

ステップ 6 モデルのロード

モデル評価には、FlagEmbedding が提供するこのスクリプトを実行できます。

ファインチューニングによるベースとなる bge モデルの調整は、タスク固有のパフォーマンス向上につながる可能性がありますが、対象領域外でのモデルの全体的な有効性(例えば c-mteb タスクでのパフォーマンス低下)の顕著な低下を引き起こす可能性もあります。解決策(LM-Cocktail の使用)とファインチューニングプロセスの詳細については、Github の「FlagEmbedding/examples/finetune」を確認してください。

bge-large-en-v1.5 を LLM API と統合するには?

埋め込みモデルを LLM と統合することで、AI の自然言語処理能力が強化され、より高度なセマンティック検索、文脈理解、パーソナライズされたインタラクションが可能になります。この統合は、コンテンツベースのレコメンデーション、文書クラスタリング、異常検知、多言語処理、ナレッジグラフ構築などのタスクの強化に特に役立ちます。また、高度なテキスト要約や機械学習モデルの特徴量強化もサポートし、感情分析やトピック分類のパフォーマンス向上につながります。

ステップ 1: 環境のセットアップ

まず、必要な Python 環境と必須パッケージがインストールされていることを確認します。

pip install openai
# その他の必要なパッケージ、例: requests、numpy などをインストール

ステップ 2: Novita AI API クライアントの初期化

Novita AI API クライアントを初期化するコードは既に提供されています。参照用に以下に示します。

from openai import OpenAI

client = OpenAI(
    base_url="https://api.novita.ai/v3/openai",
    api_key="<あなたの Novita AI API キー>",  # 実際の API キーに置き換えてください
)
model = "nousresearch/nous-hermes-llama2-13b"

ステップ 3: 埋め込みモデルの取得

bge-large-en-v1.5 モデルにアクセスできると仮定して、ロードします。Hugging Face モデルの場合は、次のように transformers ライブラリを使用します。

from transformers import AutoModel, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("BAAI/bge-large-en-v1.5")
model = AutoModel.from_pretrained("BAAI/bge-large-en-v1.5")

ステップ 4: 埋め込みを取得する関数の定義

bge-large-en-v1.5 モデルから埋め込みを取得する関数を作成します。

def get_embeddings(text):
    inputs = tokenizer(text, return_tensors="pt")
    with torch.no_grad():
        embeddings = model(**inputs)[0].mean(dim=1)
    return embeddings.numpy()

ステップ 5: Novita AI LLM API との統合

次に、埋め込みモデルを LLM API と統合して、API の応答を強化したり、セマンティック検索などのタスクを実行します。

def enhanced_llm_response(prompt):
    # LLM から初期応答を取得
    response = client.completions.create(
        model=model,
        prompt=prompt,
        stream=True,
        max_tokens=512,
    )
    
    # 応答を処理(例:テキストの抽出)
    # これは実際の応答処理のプレースホルダーです
    response_text = next(response)['choices'][0]['text'].content
    
    # 応答の埋め込みを取得
    response_embeddings = get_embeddings(response_text)
    
    # ここで、埋め込みを様々な目的(セマンティック検索、フィルタリングなど)に使用できます
    
    return response_text, response_embeddings

ステップ 6: 強化された関数の使用

これで enhanced_llm_response 関数を使用して LLM から応答を取得し、埋め込みモデルで処理できます。

prompt = "好奇心旺盛なユーザーと人工知能アシスタントの間のチャット"
response, embeddings = enhanced_llm_response(prompt)
print(response)
# 埋め込みを使って何かする(例:保存、類似テキストの検索など)

ステップ 7: エラーハンドリングとロギング

API 制限、リクエスト失敗、その他の潜在的な問題を管理するために、コードにエラーハンドリングとロギングを追加します。

ステップ 8: テストと反復

統合を徹底的にテストし、結果に基づいて反復します。パラメータの調整、より多くのエッジケースの処理、パフォーマンスの最適化が必要になる場合があります。

実際の実装の詳細は、Novita AI LLM API と bge-large-en-v1.5 モデルの具体的な機能と要件に応じて異なる場合があることに注意してください。技術サポートについては、Novita AI チームまでお問い合わせください: support@novita.ai

まとめ

要約すると、『bge-large-en-v1.5』の探求を通じて、高密度検索タスクにおけるその不可欠な役割が強調され、その機能、応用、実践的な実装についての深い洞察が提供されました。モデルの紹介と埋め込みの分野での重要性から、コードでの使用法とファインチューニングプロセスの実演まで、包括的なガイドを提示しました。さらに、Novita AI LLM API との統合は、LLM のセマンティック理解と検索精度を増幅するモデルの可能性を示しています。

LLM に関する今後のアップデートにご期待ください!

よくある質問

1. BGE リランカーはどのように機能しますか?

クエリとパッセージをリランカーに入力することで、関連性スコアを取得できます。このスコアは、シグモイド関数を使用して [0, 1] の範囲の浮動小数点値に変換できます。このプロセスは、上位ランクの結果がより関連性が高く高品質であることを保証し、全体的なシステムパフォーマンスを向上させることを目的としています。

2. BGE のコンテキスト長はどれくらいですか?

最新のモデル bge-m3 のコンテキスト長は 8KB です。

3. bge-m3 埋め込みのサイズはどれくらいですか?

短い文から最大 8192 トークンを含む長い文書まで、さまざまな長さの入力を処理できます。

Novita AI は、AI の野心を実現するためのオールインワンクラウドプラットフォームです。シームレスに統合された API、サーバーレスコンピューティング、GPU アクセラレーションにより、AI 駆動のビジネスを迅速に構築し拡張するためのコスト効率の高いツールを提供します。インフラストラクチャの悩みを解消し、無料で始めましょう — Novita AI はあなたの AI の夢を現実にします。

おすすめ記事

LLM 埋め込みとは: 知っておくべきすべて

BGE Large の力の解明: テキスト埋め込みの未来