01
背景紹介
大規模言語モデルの効果が明らかに向上するにつれて、その関連アプリケーションが次々と登場し、ますます人気が高まる傾向を示しています。より広く懸念されている技術ルートの 1 つは、大規模言語モデル (LLM) + 知識想起 (知識検索) の方法です。これにより、プライベート ドメインの知識の質問応答の点で一般的な大規模言語モデルのいくつかの欠点を補い、問題を解決できます。一般的な大規模言語モデルの問題 言語モデルは、専門分野における根拠の欠如、幻覚、その他の質問に答えます。基本的なアイデアは、プライベート ドメインの知識ドキュメントをスライスし、ベクトル化してベクトル検索によって呼び出し、その後、それらをコンテキストとして大規模な言語モデルに入力して、帰納と要約を行うことです。
この技術的方向性の具体的な実践では、知識ベースは、知識の質問に答えるプロセスの知識想起ステップで重要な役割を果たす、反転とベクトルに基づく 2 つのインデックス方法と、通常のドキュメント インデックスまたはログ インデックスを使用して構築できます。 、知識のベクトル化には、ディープ モデルのセマンティック機能、ドキュメントのセグメント化、ベクトル モデルの展開と推論などの追加の手順が必要です。知識ベクトル化データベースの構築プロセスでは、元の文書の大きさだけでなく、セグメント化の粒度、ベクトル次元などの要素も考慮する必要があり、最終的にはベクトルデータベースによってインデックス付けされる知識項目の数が上限に達する可能性があります。非常に大きな大きさ。次の 2 つの側面によって引き起こされる可能性があります。
金融、医療、法律分野など、さまざまな業界で既存の文書の量が非常に多く、新規文書の量も膨大です。
想起効果を追求するために、文書のセグメント化では、文またはセグメントごとの多粒度の冗長ストレージが採用されることがよくあります。
これらの詳細は、知識ベクトル データベースの書き込みとクエリのパフォーマンスに特定の課題をもたらします. ベクトル化された知識ベースの構築と管理を最適化するために、この文書では、次の図に示すように、知識ベクトル データベースのサービスに基づいて知識ベース構築プロセスを構築します。アマゾンのクラウドテクノロジー:
S3 バケットのハンドラーを通じて Amazon Lambda をリアルタイムでトリガーし、対応するナレッジ ファイル ストレージの Amazon Glue ジョブを開始します。
ドキュメントの解析と分割は Glue ジョブで実行され、ベクトル化のために Amazon Sagemaker の埋め込みモデルが呼び出されます。
Bulk を通じて Amazon OpenSearch に挿入します。
また、知識をベクトル化する方法やベクトル データベースを最適化する方法など、プロセス全体に関わるさまざまな側面に関するいくつかのベスト プラクティスと経験もまとめています。
02
知識のベクトル化
2.1 文書の分割
知識のベクトル化の前段階は知識を分割することであり、セマンティックな整合性の維持が最も重要な考慮事項です。2 つの側面から議論します。次の 2 つの焦点を選択する方法は、いくつかの経験をそれぞれ要約したものです。
a. フラグメントの分割方法
この部分の作業に関しては、Langchain は人気のある大規模言語モデル統合フレームワークとして、多数の Document Loader と Text Spiltters を提供しており、その一部は参考価値がありますが、その多くは反復的です。
現在、最もよく使用されている基本的な方法は、Langchain の RecursiveCharacterTextSplitter を使用することです。これは、Langchain のデフォルトのスプリッターです。この複数レベルの区切り文字リスト ["\n\n", "\n", " ", ""] を使用して分割します。デフォルトでは、最初に段落に従って分割されます。分割結果の chunk_size が超過した場合は、 、その後、chunk_size 要件が満たされるまで、次のレベルの区切り文字を使用して分割を続けます。
ただし、このアプローチは比較的大まかであり、依然として一部の重要なコンテンツが逆アセンブルされる可能性があります。他の一部のドキュメント形式では、さらに微妙な慣行が必要になる場合があります。
FAQ ファイルは、1 つの質問と 1 つの回答の粒度に従って分割する必要があります。後続のベクトル化された入力では、質問のみ、または質問と回答を使用できます (詳細については、このブログ シリーズの後続の記事で説明します)。
Markdown ファイルの場合、「#」はタイトルを識別するために使用される特殊文字です。MarkdownHeaderTextSplitter をスプリッターとして使用すると、コンテンツとタイトルが対応して抽出されるようになります。
PDF ファイルには、より豊富な書式設定情報が含まれます。Langchain は多くのローダーを提供しますが、Langchain の PDFMinerPDFasHTMLLoader のセグメンテーション効果はより優れています. PDF を HTML に変換し、HTML <div> ブロックを介して分割します. このメソッドは各ブロックのコンテンツを保存できます. フォント サイズ情報各コンテンツの所属関係を推定することができ、段落のタイトルを前のレベルの親タイトルに関連付けて、情報をより完全なものにすることができます。以下の効果と同様です。
b. フラグメント長のモデルサポート
分割されたフラグメントはベクトル化モデルを通じて推論する必要があるため、ベクトル化モデルの Max_seq_length 制限を考慮する必要があります。この制限を超えると、切り捨てや不完全なセマンティクスが発生する可能性があります。Embedding モデルは、サポートされている Max_seq_length とは別に、現在下表の 2 種類があります (この 4 つは実務経験のあるモデルです)。
ここでの Max_seq_length はトークンの数を指し、文字数と等価ではありません。以前のテストの経験によれば、最初の 3 つのモデルのトークンは約 1.5 漢字です。chatglm などの大規模な言語モデルの場合、トークンは通常約 2 文字です。セグメント化中にトークンの数を計算するのが不便な場合は、この比率に従って単純に変換することで、切り捨てが発生しないようにすることができます。
最初の 3 つのモデルは Bert ベースの埋め込みモデルに属し、OpenAI の text-embedding-ada-002 モデルは GPT3 ベースのモデルです。前者は文章や短い段落のベクトル化に適しており、後者はOpenAIのSAASインターフェースで長文のベクトル化に適していますが、プライベートで導入することはできません。
検証の選択は、リコール効果に基づいて行うことができます。現在の実際の経験から、text-embedding-ada-002 は中国語の類似性スコアをランク付けできることがわかりますが、識別の程度が十分ではなく (濃度が約 0.7)、類似しているかどうかを直接判断するのには役立たないことがわかります。閾値を超えた知識の想起。
また、長さ制限の問題を改善するもう一つの方法として、分割したフラグメントに番号を付け、隣接するフラグメントの番号も近いものを呼び出す際に、ベクトルデータベースの範囲検索を利用することで、呼び出しにより、呼び出されたコンテンツの意味上の整合性も保証できます。
2.2 ベクトル化されたモデルの選択
前のセクションで説明した 4 つのモデルは、テキストの長さに対するモデルのサポートの違いについてのみ言及しており、現時点ではその効果について信頼できる結論はありません。リーダーボードを使用して、各モデルのパフォーマンスを理解できます。リスト上のほとんどのモデルの評価は、依然として公開データセットのベンチマークに基づいています。ベンチマークの結論が実際の運用現場で正しいかどうかを確認する必要がありますケースバイケース。ただし、原則として、共有できる経験には次のような側面があります。
垂直フィールドにおける Finetune のモデルには、元のベクトル モデルに比べて明らかな利点があります。
現在のベクトル化モデルは、対称と非対称の 2 つのカテゴリに分類されます。微調整を行わない場合は、FAQ に対して対称的な呼び出し、つまりクエリから質問への呼び出しを使用することをお勧めします。文書断片の知識については、非対称想起モデルを使用することをお勧めします。これは、クエリから回答 (文書断片) までの想起です。
効果に明らかな違いがない場合は、ベクトル次元が短いモデルを選択するようにしてください。高次元ベクトル (openai の text-embedding-ada-002 など) は、検索パフォーマンスとコストの点でベクトル データベースに負担をかけます。
詳細については、このシリーズのリコール最適化の部分で詳しく説明します。
2.3 ベクトル化された並列処理
実際のビジネス シナリオでは、ドキュメントのサイズは 100 から 100 万程度になります。冗長多段階想起法によれば、対応する知識項目は最大1億個の規模に達する可能性がある。オフライン計算全体は大規模であるため、同時に実行する必要があります。そうしないと、知識の追加とベクトル検索効果の反復の要件を満たすことができません。手順は主に以下の 3 つの計算段階に分かれます。
ドキュメントの分割の並列化
計算の同時実行粒度はファイルレベルであり、処理されるファイル形式もTXTプレーンテキスト、Markdown、PDFなど多様であり、対応するセグメンテーションロジックも異なります。並列処理に Spark などのビッグ データ フレームワークを使用するのは適切ではありません。マルチプロセスの同時処理にマルチコア インスタンスを使用するのは原始的すぎるため、タスクの観察や追跡には不便です。そのため、処理には Amazon Glue の Python シェル エンジンを選択できます。主な利点は次のとおりです。
ファイル粒度に従って同時実行を実行すると便利であり、同時実行の程度はシンプルで制御可能です。再試行やタイムアウトなどのメカニズムにより、タスクの追跡と観察が便利になり、ログは Amazon CloudWatch に直接接続されます。
–Additional-python-modules パラメーターを指定するだけで、依存パッケージをビルドして実行するのに便利です。Glue Python オペレーティング環境には、すでに opensearch_py およびその他の依存関係が付属しています。
次のコードを参照できます。
glue = boto3.client('glue')
def start_job(glue_client, job_name, bucket, prefix):
response = glue.start_job_run(
JobName=job_name,
Arguments={
'--additional-python-modules': 'pdfminer.six==20221105,gremlinpython==3.6.3,langchain==0.0.162,beautifulsoup4==4.12.2',
'--doc_dir': f'{prefix}',
'--REGION': 'us-west-2',
'--doc_bucket' : f'{bucket}',
'--AOS_ENDPOINT': 'vpc-aos-endpoint',
'--EMB_MODEL_ENDPOINT': 'emb-model-endpoint'
})
return response['JobRunId']
左にスワイプするとさらに表示されます
注: 各 Amazon Glue アカウントの同時実行ジョブのデフォルトの最大数は 200 です。さらに多くの同時ジョブが必要な場合は、対応するサービス クォータの増加を申請する必要があります。バックグラウンドでアカウント マネージャーに連絡できます。 。
ベクトル化された推論の並列処理
分割された段落や文は文書数に比べて何倍にも膨らむため、ベクトルモデルの推論スループットがプロセス全体のスループットを決定します。ここでは、SageMaker Endpoint を使用してベクトル化されたモデルをデプロイします。一般的に、モデルのスループット機能を提供するために、GPU インスタンス推論、マルチノード エンドポイント/エンドポイントの弾力的なスケーラビリティ、およびサーバーサイド/クライアントサイドのバッチ推論機能が提供されます。これらのいくつかの効果的な対策。オフラインのベクトル知識ベース構築の場面に特有の、次の戦略を採用できます。
GPUインスタンスのデプロイメント
ベクトル化されたモデルの CPU インスタンスは推論可能です。ただし、オフラインのシナリオでは推論の同時実行性が高く、GPU のスループットは CPU のスループットと比較して約 20 倍向上します。したがって、GPU 推論はオフライン シナリオで使用でき、CPU 推論の戦略はオンライン シナリオで使用できます。
マルチノードエンドポイント
一時的に大規模な同時ベクトル生成の場合は、マルチノード エンドポイントをデプロイすることで処理でき、処理後に閉じることができます(注: オフラインで生成されるリクエストの量は急激に増加し、Auto Scaling のコールド スタート時間は 5 ~ 6 分になります。これにより、初期のリクエストが間違いであるように見えます)
クライアント側バッチによる推論
クライアント側のバッチ構築は、オフライン推論にとって非常に簡単です。サーバー側のバッチ推論を有効にする必要はありません。一般に、サーバー側のバッチには 50 ミリ秒や 100 ミリ秒などの待ち時間があります。推論の遅延が大きい大規模な言語モデルにはより効果的ですが、ベクトル化された推論には適していません。次のコードを参照できます。
import hashlib
import itertools
import re
BATCH_SIZE = 30
paragraph_content='sentence1。sentence2。sentence3。sentence4。sentence5。sentence6.'
def sentence_generator(paragraph_content):
sentences = re.split('[。??.!!]', paragraph_content)
for sent in sentences:
yield sent
def batch_generator(generator, batch_size):
while True:
batch = list(itertools.islice(generator, batch_size))
if not batch:
break
yield batch
g = sentence_generator(paragraph_content)
sentence_batches = batch_generator(g, batch_size=BATCH_SIZE)
# iterate batch to infer
for idx, batch in enumerate(sentence_batches):
# client-side batch inference
embeddings = get_embedding(smr_client, batch, endpoint_name)
for sent_id, sent in enumerate(batch):
document = { "publish_date": publish_date, "idx":idx, "doc" : sent, "doc_type" : "Sentence", "content" : paragraph_content, "doc_title": header, "doc_category": "", "embedding" : embeddings[sent_id]}
yield {"_index": index_name, "_source": document, "_id": hashlib.md5(str(document).encode('utf-8')).hexdigest()}
左にスワイプするとさらに表示されます
OpenSearch バッチ インジェクション
Amazon OpenSearch の書き込み操作は、一括してバッチで実装できるため、単一の書き込みよりも大きな利点があります。次のコードを参照してください。
from opensearchpy import OpenSearch, RequestsHttpConnection,helpers
credentials = boto3.Session().get_credentials()
auth = AWSV4SignerAuth(credentials, region)
client = OpenSearch(
hosts = [{'host': aos_endpoint, 'port': 443}],
http_auth = auth,
use_ssl = True,
verify_certs = True,
connection_class = RequestsHttpConnection
)
gen_aos_record_func = None
if content_type == "faq":
gen_aos_record_func = iterate_QA(file_content, smr_client, index_name, EMB_MODEL_ENDPOINT)
elif content_type in ['txt', 'pdf', 'json']:
gen_aos_record_func = iterate_paragraph(file_content, smr_client, index_name, EMB_MODEL_ENDPOINT)
else:
raise RuntimeError('No Such Content type supported')
response = helpers.bulk(client, gen_aos_record_func)
return response
左にスワイプするとさらに表示されます
03
ベクトルデータベースの最適化
ベクトル データベースにどの近似検索アルゴリズムを選択するか、適切なクラスター サイズの選択、およびクラスター設定の最適化も、ナレッジ ベースの読み取りおよび書き込みパフォーマンスにとって重要です。次の側面を考慮する必要があります。
3.1 アルゴリズムの選択
OpenSearch では、HNSW (Hierarchical Navigable Small World) と IVF (Inverted File) という 2 つの k-NN アルゴリズムが提供されています。
k-NN 検索アルゴリズムを選択する際には、考慮すべき要素がいくつかあります。メモリが制限要因ではない場合は、HNSW アルゴリズムの使用を優先することをお勧めします。HNSW アルゴリズムはレイテンシとリコールの両方を保証できるためです。メモリ使用量を制御する必要がある場合は、HNSW のようなクエリ速度と品質を維持しながらメモリ使用量を削減する IVF アルゴリズムの使用を検討してください。ただし、メモリが主な制限要因である場合は、メモリ使用量をさらに削減するために HNSW または IVF アルゴリズムに PQ エンコーディングを追加することを検討してください。PQ エンコードを追加すると、精度が低下する可能性があることに注意してください。したがって、アルゴリズムと最適化方法を選択するときは、特定のアプリケーション要件を満たすために複数の要素を包括的に考慮する必要があります。
3.2 クラスターサイズの推定
アルゴリズムを選択した後、式に従って必要なメモリを計算し、k-NN クラスターのサイズを導き出すことができます。例として HNSW アルゴリズムを取り上げます。
占有メモリ = 1.1 * (4*d + 8*m) * num_vectors * (number_of_replicas + 1)
このうち、 d: ベクトルの次元 (768 など)、 m: 制御層の各ノードの接続数、 num_vectors: インデックス内のベクトル ドキュメントの数
3.3 バッチインジェクションの最適化
大量のデータをナレッジ ベクトル ライブラリに注入する場合は、いくつかの重要なパフォーマンスの最適化に注意を払う必要があります。主な最適化戦略は次のとおりです。
更新間隔を無効にする
初めて大量のデータを取り込む場合、より小さなセグメントが生成されるのを避けるために、取り込みフェーズ中にリフレッシュ間隔を増やすか、refresh_interval を直接オフ (-1 に設定) にすることができます。データのロードが完了するまで待ってから、refresh_interval を再度有効にします。
PUT /my_index/_settings
{
"index": {
"refresh_interval": "-1"
}
}
レプリカを無効にする
また、大量のデータを初めてロードするときは、取り込みを高速化するためにレプリカを一時的に無効にすることができます。これを行うとデータ損失のリスクが生じる可能性があるため、データのロードが完了した後、レプリカを再度有効にする必要があることに注意してください。
PUT /my_index/_settings
{
"index": {
"number_of_replicas": 0
}
}
インデックススレッドを増やす
knn を処理するスレッドは knn.algo_param.index_thread_qty で指定され、デフォルトでは 1 です。デバイスに十分な CPU リソースがある場合は、このパラメータを増やすことを試みることができます。これにより、k-NN インデックスの構築が高速化されます。ただし、これにより CPU への負荷が増加する可能性があるため、最初にノードの仮想コアの半分を構成し、CPU 負荷を観察することをお勧めします。
PUT /_cluster/settings
{
"transient": {
"knn.algo_param.index_thread_qty": 8 // c6g.4x的vcore为16, 给到 knn 一半
}
}
左にスワイプするとさらに表示されます
knn メモリ比率の増加
knn.memory.circuit_break.limit はメモリ使用量に関するパラメータで、デフォルト値は 50% です。必要に応じて、これを 70% に変更できます。このデフォルト値を例にとると、マシンに 100GB のメモリがある場合、プログラム アドレス指定の制限により、JVM のヒープ メモリは通常最大 32GB 割り当てられ、k-NN プラグインはメモリの半分を使用します。残りの 68GB、つまり 34GB は k-NN のインデックス キャッシュとして使用されます。メモリ使用量がこの値を超える場合、k-NN は最も最近使用されていないベクトルを削除します。このパラメーターは、クラスター サイズが変わらない場合の k-NN のキャッシュ ヒット率を向上させ、コストの削減と検索効率の向上に役立ちます。
PUT /_cluster/settings
{
"transient": {
"knn.memory.circuit_breaker.limit": "70%"
}
}
左にスワイプするとさらに表示されます
04
エピローグ
本記事「大規模言語モデルに基づく知識質問応答の応用実践 - 知識ベース構築(前編)」では、知識ベース構築の部分について予備的な考察を行い、知識ベース構築における文書分割手法のいくつかについて、実務経験に基づいて解説します。ベクトル モデルの選択、ベクトル データベースのチューニングなどのいくつかの主要な手順では経験を共有しますが、比較的抽象的なため、具体的な実践的な詳細については次の部分に注意してください。
さらに、この記事で説明されているコードの詳細は、サポート資料を参照できます。
コードリポジトリ aws-samples/private-llm-qa-bot
https://github.com/aws-samples/private-llm-qa-bot
ワークショップ <Amazon Open Search+Large Language Model に基づくインテリジェントな質問応答システム> (中国語版、英語版)
https://catalog.us-east-1.prod.workshops.aws/workshops/158a2497-7cbe-4ba4-8bee-2307cb01c08a/
この記事の著者
李元波
Amazon クラウド テクノロジー分析および AI/ML ソリューション アーキテクト。AI/ML シナリオのエンドツーエンドのアーキテクチャ設計とビジネス最適化に重点を置き、データ分析の観点から Amazon Clean Rooms 製品サービスを担当します。インターネット業界で長年働いており、ユーザーのポートレート、洗練された運用、推奨システム、ビッグデータ処理に関して豊富な実務経験を持っています。
孫堅
Amazon クラウドテクノロジーのビッグデータソリューションアーキテクト。Amazon クラウドテクノロジーに基づくビッグデータソリューションのコンサルティングとアーキテクチャ設計を担当し、ビッグデータの研究と推進に尽力しています。彼は、ビッグ データの運用とメンテナンスのチューニング、コンテナ ソリューション、レイクとウェアハウスの統合、ビッグ データ エンタープライズ アプリケーションに豊富な経験を持っています。
唐世建
Amazon クラウド テクノロジー データ分析ソリューション アーキテクト。顧客のビッグデータ ソリューションのコンサルティングとアーキテクチャ設計を担当。
郭仁
Amazon クラウド テクノロジー AI および機械学習ディレクション ソリューション アーキテクト。Amazon クラウド テクノロジーに基づく機械学習ソリューション アーキテクチャのコンサルティングと設計を担当し、ゲーム、電子商取引、インターネット メディア、その他の業界での機械学習ソリューションの実装と推進に専念。Amazon Cloud Technology に入社する前は、データ インテリジェンス関連テクノロジーのオープンソースと標準化に従事し、豊富な設計と実務経験を持っています。
聞いたので、下の 4 つのボタンをクリックしてください
バグに遭遇することはありません!