「松ぼっくりベクトルデータベースとAmazon SageMaker JumpStartのLlama-2を使用したリトリーバル増強生成によって幻覚を軽減する」

「松ぼっくりベクトルデータベースとAmazon SageMaker JumpStartのLlama-2を使った幻覚の軽減に役立つリトリーバル増強生成」

さまざまな産業でのLLMの普及は止まることなく進んでいますが、それらは新たなAIの波を推進する広範な技術エコシステムの一部です。多くの対話型AIの使用例では、ユーザのクエリに応答するためにLlama 2、Flan T5、BloomなどのLLMが必要です。これらのモデルは、質問に答えるためにパラメータ化された知識を利用します。モデルはトレーニング中にこの知識を習得し、モデルパラメータにエンコードします。この知識を更新するには、LLMを再トレーニングする必要があり、それには多くの時間と費用がかかります。

幸いなことに、ソースの知識を使用してLLMに情報を提供することもできます。ソースの知識は、入力プロンプトを介してLLMに供給される情報です。ソースの知識を提供する人気のあるアプローチの1つは、Retrieval Augmented Generation(RAG)です。RAGを使用すると、外部のデータソースから関連する情報を取得し、それをLLMに送ることができます。

このブログ記事では、Amazon Sagemaker JumpStartを使用してLlama-2などのLLMを展開し、Pineconeベクトルデータベースを使用して関連情報を取得することで、AIの幻想を防ぐためにLLMを最新の状態に保つ方法について探ってみましょう。

Amazon SageMakerでのRetrieval Augmented Generation(RAG)

RAGの取得コンポーネントはPineconeが担当しますが、LLMの推論を実行する場所と埋め込みモデルを実行する場所がさらに2つ必要です。

Amazon SageMaker Studioは、すべての機械学習(ML)開発を実行するための特別なツールにアクセスできる単一のWebベースのビジュアルインターフェースを提供する統合開発環境(IDE)です。SageMaker JumpStartを提供し、ユーザは独自のSageMakerアカウントで特定のモデルを検索、プレビュー、および起動できるモデルハブを利用できます。これには、Foundation Modelsなどの事前に学習済みで一般に利用可能なモデルが含まれています。

Amazon SageMaker Studioは、RAGを利用したLLMパイプラインを開発するための理想的な環境を提供します。まず、AWSコンソールを使用して、Amazon SageMakerに移動し、SageMaker Studioドメインを作成し、Jupyter Studioノートブックを開きます。

前提条件

次の前提条件を満たしてください:

  1. Amazon SageMaker Studioをセットアップします。
  2. Amazon SageMakerドメインに登録します。
  3. 無料のPineconeベクトルデータベースに登録します。
  4. 前提条件のライブラリ:SageMaker Python SDK、Pinecone Client

ソリューションの手順

SageMaker Studioノートブックを使用して、まず前提条件のライブラリをインストールする必要があります:

!pip install -qU sagemaker pinecone-client==2.2.1 ipywidgets==7.0.0 

LLMの展開

この記事では、LLMを展開するための2つのアプローチについて説明します。最初の方法は、HuggingFaceModelオブジェクトを使用する方法です。これは、Hugging FaceモデルハブからLLM(および埋め込みモデル)を直接展開する場合に使用できます。

たとえば、次のスクリーンキャプチャに示すように、google/flan-t5-xlモデルの展開可能な構成を作成できます:

import sagemakerfrom sagemaker.huggingface import (HuggingFaceModel, get_huggingface_llm_image_uri)role = sagemaker.get_execution_role()hub_config = {'HF_MODEL_ID':'google/flan-t5-xl', # model_id from hf.co/models'HF_TASK':'text-generation' # NLP task you want to use for predictions# retrieve the llm image urillm_image = get_huggingface_llm_image_uri("huggingface", version="0.8.2"&)huggingface_model = HuggingFaceModel(env=hub_config, role=role, # iam role with permissions to create an Endpoint image_uri=llm_image)

Hugging Faceからモデルを展開する場合、my_model_configurationを次のように初期化します:

  • env構成は、どのモデルを使用してどのタスクを実行するかを示します。
  • SageMakerの実行roleには、モデルを展開するための権限が与えられます。
  • image_uriは、Hugging FaceからLLMを展開するための特定のイメージ構成です。

<!–または、SageMakerにはよりシンプルなJumpStartModelオブジェクトと直接互換性のあるモデルのセットがあります。多くの人気のあるLLM(Large Language Model)は、このモデルによってサポートされており、以下のスクリーンキャプチャで示されるように初期化することができます。

import sagemaker from sagemaker.jumpstart.model import JumpStartModel role = sagemaker.get_execution_role() my_model = JumpStartModel(model_id = "meta-textgeneration-llama-2-7b-f")

my_modelの両バージョンについて、以下のスクリーンキャプチャに示されるようにデプロイします。

predictor = my_model.deploy(    initial_instance_count=1, instance_type="ml.g5.4xlarge", endpoint_name="llama-2-generator")

事前学習済みLLMのクエリ

初期化されたLLMのエンドポイントを使用してクエリを開始できます。クエリの形式は異なる場合がありますが(特に会話型と非会話型のLLMの間で)、プロセスは一般的に同じです。Hugging Faceモデルの場合、以下の手順を実行します:

# https://aws.amazon.com/blogs/machine-learning/llama-2-foundation-models-from-meta-are-now-available-in-amazon-sagemaker-jumpstart/prompt = """CONTEXTを基に次の質問に回答してください。回答がわからない場合や、回答がCONTEXTに含まれていない場合は「回答がわかりません」と正直に回答してください。質問:{question}"""payload = {    "inputs":        [        [         {"role": "system", "content": prompt},         {"role": "user", "content": question},        ]         ],   "parameters":{"max_new_tokens": 64, "top_p": 0.9, "temperature": 0.6, "return_full_text": False}}out = predictor.predict(payload, custom_attributes='accept_eula=true')out[0]['generation']['content']

このGitHubリポジトリでソリューションを見つけることができます。

ここで受け取る生成された回答はあまり意味をなさないものです – 幻覚です。

LLMへの追加のコンテキストの提供

Llama 2は、内部パラメータの知識だけを元に質問に回答しようとします。明らかに、モデルパラメータはSageMakerでの管理されたスポットトレーニングに対応するインスタンスの知識を保持していません。

この質問に正しく答えるためには、ソースの知識を使用する必要があります。つまり、追加の情報をプロンプトを介してLLMに提供します。その情報を直接モデルの追加コンテキストとして追加しましょう。

context = """Amazon SageMakerでサポートされているすべてのインスタンスで管理されたスポットトレーニングを使用することができます。Amazon SageMakerが現在利用可能なすべてのAWSリージョンで管理されたスポットトレーニングがサポートされています。"""prompt_template = """CONTEXTを基に次の質問に回答してください。回答がわからない場合や、回答がCONTEXTに含まれていない場合は「回答がわかりません」と正直に回答してください。CONTEXT:{context}質問:{question}"""text_input = prompt_template.replace("{context}", context).replace("{question}", question)payload = {    "inputs":        [        [         {"role": "system", "content": text_input},         {"role": "user", "content": question},        ]         ],   "parameters":{"max_new_tokens": 64, "top_p": 0.9, "temperature": 0.6, "return_full_text": False}}out = predictor.predict(payload, custom_attributes='accept_eula=true')generated_text = out[0]['generation']['content']print(f"[入力]: {question}\n[出力]: {generated_text}")[入力]: Amazon SageMakerでManaged Spot Trainingを使用できるインスタンスはどれですか?[出力]: 与えられたコンテキストに基づくと、Amazon SageMakerでサポートされているすべてのインスタンスでManaged Spot Trainingが使用できます。したがって、回答は:Amazon SageMakerでサポートされているすべてのインスタンスです。

これで質問の正しい回答がわかりました。簡単でしたね!ただし、ユーザーは通常、プロンプトにコンテキストを挿入することはありません。彼らはすでに質問の回答を知っています。

単一のコンテキストを手動で挿入する代わりに、より広範囲な情報データベースから関連情報を自動的に特定します。そのためには、情報検索を補完した生成が必要です。

検索拡張生成

検索拡張生成では、情報データベースをベクトル空間にエンコードすることができます。ベクトル間の近接性は、それらの関連性/意味的類似性を表します。このベクトル空間を知識ベースとして使用して、新しいユーザークエリを同じベクトル空間にエンコードし、以前にインデックスされた最も関連性の高いレコードを抽出できます。

これらの関連レコードを取得した後、いくつかを選択し、LLMプロンプトに追加のコンテキストとして含めることで、LLMに非常に関連性の高いソース知識を提供します。これは2つのステップのプロセスです。

  • インデックス作成は、データセットから情報をベクトルインデックスに埋め込むステップです。
  • 検索はクエリの際に行われ、ベクトルインデックスから関連情報を取得するステップです。

両方のステップには、埋め込みモデルが必要であり、人間が読み取れるテキストを意味的なベクトル空間に変換するために使用されます。以下のスクリーンキャプチャに示されているように、Hugging Faceの高効率なMiniLMセンテンストランスフォーマーを使用します。このモデルはLLMではなく、LLama 2モデルと同じ方法で初期化されないため、異なる方法で初期化する必要があります。

hub_config = {    "HF_MODEL_ID": "sentence-transformers/all-MiniLM-L6-v2",  # hf.co/modelsから取得したmodel_id    "HF_TASK": "feature-extraction",}huggingface_model = HuggingFaceModel(    env=hub_config,    role=role,    transformers_version="4.6",  # 使用するtransformersのバージョン    pytorch_version="1.7",  # 使用するpytorchのバージョン    py_version="py36",  # ディープラーニングコンテナのPythonのバージョン)

hub_config内でモデルIDを指定します。タスクにはfeature-extractionを使用します。それは、LLMとは異なり、テキストではなくベクトル埋め込みを生成しているためです。その後、前と同じようにHuggingFaceModelでモデル構成を初期化しますが、今回はLLMイメージは使わず、いくつかのバージョンパラメータを指定します。

encoder = huggingface_model.deploy(    initial_instance_count=1, instance_type="ml.t2.large", endpoint_name="minilm-embedding")

deployを使ってモデルを再びデプロイし、より小さな(CPU専用)インスタンスml.t2.largeを使用します。MiniLMモデルは非常に小さいため、多くのメモリを必要とせず、GPUも必要ありません。CPU上でも迅速に埋め込みを作成することができます。好みに応じて、モデルをGPU上でより高速に実行することもできます。

埋め込みを作成するには、predictメソッドを使用し、inputsキーを介してエンコードするコンテキストのリストを渡します。

out = encoder.predict({"inputs": ["some text here", "some more text goes here too"]})

2つの入力コンテキストが渡され、2つのコンテキストベクトル埋め込みが返されます。

len(out)

2

MiniLMモデルの埋め込み次元は384です。つまり、MiniLMが出力する各ベクトル埋め込みは384の次元であるはずです。しかし、埋め込みの長さを見ると、以下のようになっています:

len(out[0]), len(out[1])

(8, 8)

2つのリストがそれぞれ8つの項目を含んでいます。MiniLMは最初にトークン化ステップでテキストを処理します。このトークン化により、人間が読み取れるプレーンテキストがモデルが読み取れるトークンIDのリストに変換されます。モデルの出力特徴では、トークンレベルの埋め込みが表示されます。次のように、埋め込みの長さが期待どおり384になります:

len(out[0][0])

384

これらのトークンレベルの埋め込みを、各次元のベクトルの平均値を使用してドキュメントレベルの埋め込みに変換してください。以下のイラストで示します。

平均プーリング操作により、1つの384次元ベクトルを取得します。

import numpy as np embeddings = np.mean(np.array(out), axis=1)embeddings.shape(2, 384)

2つの384次元ベクトル埋め込みを使います。各入力テキストに対して1つずつです。私たちの生活を簡単にするために、エンコーディングプロセスを次のスクリーンキャプチャに示すように、1つの関数でラップします:

from typing import Listdef embed_docs(docs: List[str]) -> List[List[float]]:    out = encoder.predict({"inputs": docs})    embeddings = np.mean(np.array(out), axis=1)    return embeddings.tolist()

データセットのダウンロード

データセットにAmazon SageMaker FAQsをダウンロードして、質問と回答の列を含むデータを取得します。

Amazon SageMaker FAQsのダウンロード

検索を実行する際には、質問の列を削除できるように、回答のみを対象にしてください。詳細についてはノートブックを参照してください

データセットと埋め込みパイプラインは準備ができています。これらの埋め込みを保存する場所が必要です。

インデックス化

Pineconeベクトルデータベースは、ベクトル埋め込みを保存し、効率的にスケーリングできます。データベースを作成するには、Pineconeから無料のAPIキーが必要です。

import pineconeimport os# add Pinecone API key from app.pinecone.ioapi_key = os.environ.get("PINECONE_API_KEY") or "YOUR_API_KEY"# set Pinecone environment - find next to API key in consoleenv = os.environ.get("PINECONE_ENVIRONMENT") or "YOUR_ENV"pinecone.init(api_key=api_key, environment=env)

Pineconeベクトルデータベースに接続した後、単一のベクトルインデックス(伝統的なDBのテーブルに類似)を作成します。インデックスの名前をretrieval-augmentation-awsとし、インデックスのdimensionmetricパラメータを埋め込みモデル(この場合はMiniLM)で必要なものに合わせて設定します。

import timeindex_name = "retrieval-augmentation-aws"if index_name in pinecone.list_indexes():    pinecone.delete_index(index_name)pinecone.create_index(name=index_name, dimension=embeddings.shape[1], metric="cosine")# indexの初期化が完了するまで待機while not pinecone.describe_index(index_name).status["ready"]:    time.sleep(1)

データの挿入を開始するには、次のコードを実行します:

from tqdm.auto import tqdmbatch_size = 2  # インスタンスのメモリが不足する場合は、増やすこともできますvector_limit = 1000answers = df_knowledge[:vector_limit]index = pinecone.Index(index_name)for i in tqdm(range(0, len(answers), batch_size)):    # バッチの終了位置を検索    i_end = min(i + batch_size, len(answers))    # IDのバッチを作成    ids = [str(x) for x in range(i, i_end)]    # メタデータのバッチを作成    metadatas = [{"text": text} for text in answers["Answer"][i:i_end]]    # 埋め込みを作成    texts = answers["Answer"][i:i_end].tolist()    embeddings = embed_docs(texts)    # upsert用のレコードリストを作成    records = zip(ids, embeddings, metadatas)    # Pineconeにupsert    index.upsert(vectors=records)

以前の質問でインデックスへのクエリを開始できます。

# 質問の埋め込みを抽出query_vec = embed_docs(question)[0]# Pineconeにクエリを実行res = index.query(query_vec, top_k=1, include_metadata=True)# 結果を表示res{'matches': [{'id': '90','metadata': {'text': 'Managed Spot Training can be used with all ''instances supported in Amazon ''SageMaker.\r\n'},'score': 0.881181657,'values': []}],'namespace': ''}

上記の出力は、質問に対して関連するコンテキストを返して質問に答えるための助けとなります。 top_k = 1なので、index.queryはトップの結果とメタデータを返しています。メタデータはManaged Spot Training can be used with all instances supported in Amazonという内容です。

プロンプトの拡張

取得したコンテキストを使用してプロンプトを拡張し、LLMにフィードするコンテキストの最大量を決定します。返された各コンテキストをプロンプトに追加してコンテンツ長を超えるまで、1000文字の制限を使用して反復的に追加します。

プロンプトの拡張

プロンプトの拡張

次の画面キャプチャに示すように、context_strをLLMプロンプトにフィードします。

payload = create_payload(question, context_str)out = predictor.predict(payload, custom_attributes='accept_eula=true')generated_text = out[0]['generation']['content']print(f"[入力]: {question}\n[出力]: {generated_text}")

[入力]: SageMakerでManaged Spot Trainingと一緒に使用できるインスタンスはどれですか?[出力]: 提供されたコンテキストに基づいて、Amazon SageMakerでサポートされているすべてのインスタンスでManaged Spot Trainingを使用できます。したがって、答えは次のとおりです:Amazon SageMakerでサポートされているすべてのインスタンス。

ロジックが機能するので、すべてを1つの関数にまとめて整理しましょう。

def rag_query(question: str) -> str:    # クエリベクトルを作成    query_vec = embed_docs(question)[0]    # Pineconeにクエリを送信    res = index.query(query_vec, top_k=5, include_metadata=True)    # コンテキストを取得    contexts = [match.metadata["text"] for match in res.matches]    # 複数のコンテキスト文字列を構築    context_str = construct_context(contexts=contexts)    # 拡張されたプロンプトを作成    payload = create_payload(question, context_str)    # 予測を行う    out = predictor.predict(payload, custom_attributes='accept_eula=true')    return out[0]["generation"]["content"]

次のような質問をすることができます:

rag_query("SageMakerはスポットインスタンスをサポートしていますか?")' はい、Amazon SageMakerはマネージドスポットトレーニングのスポットインスタンスをサポートしています。提供されたコンテキストによると、Managed Spot TrainingはAmazon SageMakerでサポートされているすべてのインスタンスで使用でき、Managed Spot TrainingはAmazon SageMakerが現在利用可能なすべてのAWSリージョンでサポートされています。\n\nしたがって、あなたの質問の答えは次のとおりです:\n\nはい、SageMakerはAmazon SageMakerが利用可能なすべてのリージョンでスポットインスタンスをサポートしています。'

クリーンアップ

追加料金が発生しないようにするために、モデルとエンドポイントを削除します。

encoder.delete_model()encoder.delete_endpoint()

結論

この記事では、SageMaker上のオープンアクセスLLMを使用したRAGについて紹介しました。また、Llama 2とAmazon SageMaker Jumpstartモデル、Flan T5とHugging Face LLMs、およびMiniLMと埋め込みモデルのデプロイ方法も紹介しました。

オープンアクセスモデルとPineconeベクターインデックスを使用して、完全なエンドツーエンドのRAGパイプラインを実装しました。これにより、幻覚を最小限に抑え、LLMの知識を最新の状態に保ち、最終的にユーザーエクスペリエンスとシステムへの信頼を向上させることができます。

この例を独自の環境で実行するには、このGitHubリポジトリをクローンし、GitHub上のQuestion Answeringノートブックの手順を実行してください。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more