著者 | フロリアン・ジューン 編纂者:岳陽 文書解析が完了すると、構造化データまたは半構造化データが得られます。ここでの主なタスクは、このデータを小さなチャンクに分割し、特徴を抽出し、抽出した特徴を意味を捉える形式に変換することです。RAGシステムにおける位置付けは図1に示されています。 図1: RAGシステムにおけるデータ分割プロセス(赤でマーク)の位置。画像は原著者提供。 最も一般的に使用されるデータチャンク化手法はルールベースであり、固定チャンクサイズや隣接するチャンクのオーバーラップといった手法を採用しています。複数の階層構造を持つ文書の場合は、Langchainが提供するRecursiveCharacterTextSplitter[1]を使用できます。これにより、文書を異なるレベルに応じて分割できます。 しかし、実際のアプリケーションでは、定義済みのルール(チャンクのサイズや重複部分のサイズなど)が厳しすぎるため、ルールベースのデータチャンク化方法では、検索コンテキストが不完全になったり、ノイズ(翻訳者注:分析や処理を妨害したり誤解を招く可能性のある、不要で干渉する情報またはデータを指す)を含むデータチャンクが過度に大きくなったりするなどの問題が簡単に発生する可能性があります。 したがって、最も洗練されたデータチャンキング手法は、明らかにセマンティックベースのデータチャンキングです。セマンティックチャンキングの目的は、各データチャンクに含まれる情報が意味的に独立していることで、より適切に分析・処理できるようにすることです。 この記事では、テキストに内在する意味情報に基づいたデータセグメンテーション手法について考察し、その原理と実用的な応用例を説明します。具体的には以下の3つの手法を紹介します。
01 埋め込みベースの方法LlamaIndex[2]とLangchain[3]はどちらも埋め込みベースのセマンティックチャンカーを提供しています。アルゴリズムの概念はほぼ同じであるため、この記事ではLlamaIndexを例として解釈します。 LlamaIndexのセマンティックチャンカーを使用するには、最新バージョンのLlamaIndexをインストールする必要があります。以前のLlamaIndexバージョンは0.9.45でしたが、このアルゴリズムは含まれていませんでした。そのため、新しいconda仮想環境を作成し、新しいバージョンのLlamaIndex(0.10.12)をインストールしました。 pipでllama-index-coreをインストールする pip で llama-index-readers-file をインストールし、pip で llama-index-embeddings-openai をインストールします。 なお、LlamaIndex バージョン 0.10.12 では、必要なコンポーネントまたはモジュールを必要に応じてインストールできるため、この記事ではいくつかの主要コンポーネントのみをインストールします。 (llamaindex_010) Florian:~ Florian$ pip list | grep llamallama-index-core 0.10.12llama-index-embeddings-openai 0.1.6llama-index-readers-file 0.1.5llamaindex-py-client 0.1.13 テストコードは以下のとおりです。 llama_index.core.node_parser からインポート (
センテンススプリッター
セマンティックスプリッターノードパーサー、
)llama_index.embeddings.openaiからOpenAIEmbeddingをインポートし、llama_index.coreからSimpleDirectoryReaderをインポートし、osをインポートします。
os.environ["OPENAI_API_KEY"] = "YOUR_OPEN_AI_KEY"# ドキュメントをロードdir_path = "YOUR_DIR_PATH" documents = SimpleDirectoryReader(dir_path).load_data()
埋め込みモデル = OpenAI埋め込み()
スプリッター = セマンティックスプリッターノードパーサー(
buffer_size=1、breakpoint_percentile_threshold=95、embed_model=embed_model
)
nodes = splitter.get_nodes_from_documents(documents) ノード内のノードに対して:
印刷('-' * 100)
印刷(node.get_content()) 私は 図2: splitter.get_nodes_from_documents[4]の主なロジック。画像は原著者提供。 図 2 で言及されている「文」は Python リストであり、各メンバーは 4 つのキーと値のペアを含む辞書であり、各キーの意味は次のとおりです。
上記の分析から、埋め込みベクトルに基づくセマンティックチャンキング(意味情報に基づいてテキストまたはデータを意味のあるセグメントまたはブロックに分割するプロセス)が、本質的にはスライディングウィンドウ(combined_sentence)に基づいてテキストの類似性を計算する手法であることが明確に示されています。閾値を満たす隣接する文は、セマンティックブロックにグループ化されます。 プロジェクトパスにはBERT論文文書が1つだけあります[5]。結果は次のとおりです。 (llamaindex_010) フロリアン:~ フロリアン$ python /Users/Florian/Documents/june_pdf_loader/test_semantic_chunk.py ... ...------------------------------------------------------------------------------------------------現在の技術では、 事前学習済み表現の力、特に 特に微調整のアプローチについては、 制限は、標準言語モデルが 一方向性であり、アーキテクチャの選択肢が制限される。 事前トレーニング中に使用できる構造。 例えば、OpenAI GPTでは、著者らは左から右へのアーキテクチャを使用しており、すべてのトークンは、 Transformerの自己注意層では、以前のトークンに傾向する傾向がある(Vaswani et al., 2017)。このような再 制限は文レベルのタスクには最適ではなく、細かいルールを適用するときに非常に有害となる可能性がある。 質問応答などのトークンレベルのタスクに対するチューニングベースのアプローチでは、 双方向から文脈を分析する。本論文では、微調整に基づく BERTを提案するアプローチ:双方向 トランスフォーマーからのエンコーダー表現。 BERTは前述の単一性を軽減します。 マスクされたランを使用して、 ゲージモデル(MLM)の事前トレーニング目標、 クローズ課題(Taylor, 1953)にヒントを得た。 マスク言語モデルは、入力からいくつかのトークンをランダムにマスクし、そのトークンの元の語彙IDを予測することを目的とします。 maskedarXiv:1810.04805v2 [cs.CL] 2019年5月24日--------------------------------------------------------------------------------------------------------------------------------単語の文脈のみに基づいて単語を分類する。左から右への言語モデルの事前学習とは異なり、MLMは 射影表現は左と右の文脈を融合させ、それによって予測することを可能にする。 双方向の深層Transformerをトレーニングします。さらに マスク言語モデルに加えて、「次の文の予測」タスクも使用し、 テキストペア表現を訓練する。本論文の貢献は以下の通りである。 • 双方向性の重要性を示します 言語表現の事前学習。Radford et al. (2018) とは異なり、unidirec- 事前学習のための言語モデル、BERT マスクされた言語モデルを使用して事前学習を可能にする 学習済みの深層双方向表現。これもPetersらとは対照的である。----------------------------------------------------------------------------------------------------------------... ... テスト結果によると、このデータ分割方法を使用して取得されるデータ ブロックの粒度は比較的粗いことが示されています。 図 2 は、この方法がページベースであることも示しています (翻訳者注: この方法では、文章や段落などの他の小さな単位ではなく、ページに従ってテキストをデータ チャンクに処理します)。また、複数のページにまたがるデータ チャンクの問題を直接解決するものではありません。 通常、埋め込みベースのデータ分割手法のパフォーマンスは埋め込みモデルに大きく依存します。実際の有効性を評価するには、さらなる評価が必要です。 02 モデルベース手法2.1 ナイーブBERT: データ分割にBERTモデルを直接適用するBERT[5]の事前学習プロセスを振り返ってみましょう。二項分類タスクの一つである「次文予測(NSP)」は、モデルが2つの文の関係性を理解できるように設計されています。この場合、 2つの文が同時にBERTに入力されると、モデルは2つの文が連続しているかどうかを予測します。 この原理を応用すれば、直接的なデータチャンク化手法を設計できます。まず、文書を複数の文に分割します。次に、スライディングウィンドウを用いて、隣接する文をBERTモデルに入力し、NSP判定(訳注:BERTモデルの予測結果に基づいて、2つの文が連続しているかどうかを判定すること)を行います(図3)。 図3: BERTを使用したデータチャンク化。画像は原著者提供。 BERTモデルの予測スコアが予め設定された閾値よりも低い場合、2つの文間の意味的関係が弱いことを示します。予測結果は、図3の文2と文3の間の破線で示されているように、テキスト分割点(翻訳者注:予測結果に基づいてテキストを分割できる位置、つまり2つの文を分割する位置)として利用できます。 この方法の利点は、追加のトレーニングや微調整なしで直接使用できることです。 しかし、この手法では、テキスト分割点を決定する際に、現在の文の直後の文のみを考慮し、より遠い段落の情報は無視されます。さらに、予測効率は比較的低いです。 2.2 クロスセグメントアテンションに基づくデータセグメンテーション技術論文「クロスセグメントアテンションによるテキストセグメンテーション」[6]では、図4に示すように、クロスセグメントアテンションに基づいた3つのテキストセグメンテーションモデルが提案されています。 図4:クロスセグメントBERTモデル(a)では、テキスト分割の可能性のあるポイント付近のローカルコンテキスト(左側にkトークン、右側にkトークン)をモデルに入力します。BERT+Bi-LSTMモデル(b)では、まず各文をBERTモデルでエンコードし、その文の表現をBi-LSTMに入力します。階層型BERTモデル(c)では、まず各文をBERTでエンコードし、その出力文の表現を別のトランスフォーマーベースモデルに入力します。出典:クロスセグメントアテンションによるテキストセグメンテーション[6] 図4(a)に示すクロスセグメントBERTモデルは、テキストセグメンテーションを文単位の分類タスクとして定義しています。テキストセグメンテーションの可能性のあるポイント付近のローカルコンテキスト(両側のk個のトークン)がモデルに入力されます。[CLS]に対応する隠れ状態はソフトマックス分類器に渡され、ソフトマックス分類器は、セグメンテーションの可能性のあるポイントでセグメンテーションを実行するかどうかを決定します。 本論文では、さらに2つのモデルも紹介します。1つは、BERTモデルを用いて各文のベクトル表現を取得します。連続する複数の文をベクトル表現に変換し、Bi-LSTMモデル(図4(b))または別のBERTモデル(図4(c))に入力して、各文がテキスト分割点の位置であるかどうかを予測します。 図 5 に示すように、当時は 3 つのモデルすべてが良好な結果を達成しました。 図5:テキストセグメンテーションと談話セグメンテーションタスクのテストセットの評価結果。出典:クロスセグメントアテンションによるテキストセグメンテーション[6] しかし、現在までにわかっているのは、この論文[7]で公開された訓練方法のみであり、公開されていて推論に使用できるオープンソースモデルは見つかっていない。 2.3 SeqModelに基づくデータ分割技術クロスセグメントモデルは、文間の関係性や文脈情報を考慮せずに、各文をベクトル表現に変換します。さらに改良された手法であるSeqModelが、論文「効率的な音声文書セグメンテーションのための自己適応型スライディングウィンドウを備えたシーケンスモデル」[8]で提案されています。 SeqModel[9]はBERTを用いて複数の文を同時に符号化する。文をベクトル表現に変換する前に、まず文の文脈を考慮し、文中の意味的依存関係を捉えようとする。次に、各文を分析し、その文がテキスト段落内のセグメンテーションポイントであるかどうかを判定しようとする。さらに、SeqModelは自己適応型スライディングウィンドウ法を用いることで、精度に影響を与えずに推論速度を向上させる。SeqModelの概略図を図6に示す。 図 6: SeqModel アーキテクチャと推論のための適応スライディング ウィンドウ方式。 出典:効率的な音声文書セグメンテーションのための自己適応型スライディングウィンドウを備えたシーケンスモデル[8] SeqModelはModelScope[10]フレームワークを通じて利用できます。コードは以下の通りです。 modelscope.outputsからOutputKeysをインポートする
modelscope.pipelinesからパイプラインをインポート
modelscope.utils.constantからタスクをインポート
p = パイプライン(
タスク = Tasks.document_segmentation、
モデル = 'damo/nlp_bert_document-segmentation_english-base'
印刷('-' * 100)
result = p(documents='言語表現における双方向事前学習の重要性を示します。Radford et al. (2018) では事前学習に単方向言語モデルを使用しますが、BERT ではマスクされた言語モデルを使用して事前学習済みの深い双方向表現を可能にします。これは、独立して学習された左から右への言語モデルと右から左への言語モデルを浅く連結する Peters et al. (2018a) とも対照的です。• 事前学習済みの表現によって、多くの高度に設計されたタスク固有のアーキテクチャの必要性が軽減されることを示します。BERT は、多数の文レベルおよびトークンレベルのタスクで最先端のパフォーマンスを達成し、多くのタスク固有のアーキテクチャよりも優れたパフォーマンスを発揮する、最初の微調整ベースの表現モデルです。今日は良い日です')print(result[OutputKeys.TEXT]) 「Today is a good day」という文がテストデータの末尾に追加されましたが、テキスト分割後の結果変数では「Today is a good day」がまったく分離されませんでした。 (モデルスコープ) フロリアン:~ フロリアン$ python /Users/Florian/Documents/june_pdf_loader/test_seqmodel.py 2024-02-24 17:09:36,288 - modelscope - INFO - PyTorch バージョン 2.2.1 が見つかりました。 2024-02-24 17:09:36,288 - modelscope - 情報 - /Users/Florian/.cache/modelscope/ast_indexer から ast インデックスを読み込んでいます ... ...----------------------------------------------------------------------------------------------------------------... ... 言語表現における双方向事前学習の重要性を示す。Radfordら (2018) が事前学習に単方向言語モデルを用いるのに対し、BERTはマスク言語モデルを用いて事前学習済みの深い双方向表現を実現する。これは、独立して学習された左から右への言語モデルと右から左への言語モデルを浅く連結したPetersら (2018a) とも対照的である。• 事前学習済みの表現を用いることで、多くの高度に設計されたタスク固有のアーキテクチャの必要性が軽減されることを示す。BERTは、文レベルおよびトークンレベルのタスクの大規模なスイートにおいて最先端の性能を達成し、多くのタスク固有のアーキテクチャを凌駕する、初めての微調整ベースの表現モデルである。今日は良い日だ。 全体的に、モデルベースのセマンティック チャンキング手法には、まだ大幅な改善の余地があります。 私が提案する改善点の一つは、特定のプロジェクトやタスクに特化したトレーニングデータを作成し、ドメイン固有のミクロスコープを実行することです。これにより、モデルのパフォーマンスが向上します。さらに、モデルアーキテクチャの最適化も改善の余地があります。 特定のビジネス シナリオに適した優れたモデルが見つかる限り、モデルベースの手法を使用して関連する問題を解決し続けることができます。 03 LLMベースの方法「Dense X 検索:どのような検索粒度を使用すべきか?」と題された本論文では、「命題」と呼ばれる新しい検索単位を紹介しています。命題とは、テキスト内の原子表現(それ以上分解できず、より大きな意味単位を形成するために使用できる単一の意味要素)として定義され、テキスト内の固有の事実や特定の概念を検索・表現するために使用されます。命題は概念や事実を簡潔に表現し、解釈のために追加情報を必要とせずに、自然言語で完全に提示することができます。 では、いわゆる命題はどのようにして得られるのでしょうか?この記事では、プロンプトを作成し、LLMと対話することで、命題を得る方法について説明します。 LlamaIndex と Langchain はどちらも関連するアルゴリズムを実装しており、以下のデモンストレーションでは LlamaIndex が使用されます。 LlamaIndex の実装アイデアは、論文で提供されているプロンプト語を使用して命題を生成することです。 PROPOSITIONS_PROMPT = プロンプトテンプレート(
「コンテンツ」を明確かつシンプルな命題に分解し、
コンテクスト。
1. 複文を単文に分割する。入力時の元の表現を維持する。
可能な限り。
2. 追加の説明情報が付随する名前付きエンティティについては、これを
情報を独自の明確な命題に変換します。
3. 名詞や文全体に必要な修飾語を追加して、命題の文脈を分離する
代名詞(例:「それ」「彼」「彼女」「彼ら」「これ」「あれ」)を、
参照先の実体。4. 結果をJSON形式の文字列リストとして提示する。入力:タイトル:¯Eostre。セクション:理論と解釈、イースターのウサギとの関連。内容:
イースターウサギ(オスターハーゼ)に関する最も古い証拠は、1678年にドイツ南西部で医学教授ゲオルク・フランク・フォン・フランケナウによって記録されましたが、ドイツの他の地域では18世紀まで知られていませんでした。学者のリチャード・サーモンは、「ウサギは
春の庭でよく見られるので、
そこに隠された子供のための色付き卵の起源。あるいは、ヨーロッパの伝統もある。
ノウサギが卵を産んだのは、ノウサギの引っかき傷や形とタゲリの巣が非常に似ているためであり、
どちらも草原に生息し、春に初めて見られる。19世紀には、
イースターカード、おもちゃ、本などのイースターのウサギをヨーロッパ中に広めることが目的でした。
その後、ドイツ移民はこの習慣をイギリスとアメリカに輸出し、そこでそれは
イースターバニー。出力: [「イースターウサギの最も古い証拠は、南西ドイツで記録されました。
1678年にゲオルク・フランク・フォン・フランケナウによって設立された。"、"ゲオルク・フランク・フォン・フランケナウは、
医学。」, 「イースターウサギの証拠はドイツの他の地域では知られていなかったが、
18世紀。リチャード・サーモンは学者だった。リチャード・サーモンは、
ウサギとイースターの伝統とのつながりについての考えられる説明」、「ウサギ
春には庭でよく見かけられた。」「野ウサギは都合の良い説明として役立ったかもしれない
庭に隠された子供用の色付き卵の起源については、「ヨーロッパの伝統があります
ノウサギが卵を産んだ。」, 「ノウサギの傷跡や形とタゲリの巣は非常によく似ている。」, 「どちらも
ノウサギやタゲリの巣は草原に発生し、春に初めて見られる。
19世紀にはイースターカード、おもちゃ、本の影響でイースターウサギが人気になった。
ヨーロッパ全土に広まった。」「ドイツ移民はイースターのウサギの習慣を
イギリスとアメリカでイースターのウサギの習慣がイースターバニーに進化しました。
イギリスとアメリカ。"]入力: {node_text}出力:"""
) 前の章「01 埋め込みベースの手法」では、LlamaIndex 0.10.12の主要コンポーネントを既にインストールしました。ただし、DenseXRetrievalPackを使用する場合は、`pip install llama-index-llms-openai` を実行してインストールする必要があります。インストール後、LlamaIndexの現在のコンポーネントは以下のとおりです。 (llamaindex_010) Florian:~ Florian$ pip list | grep llamallama-index-core 0.10.12llama-index-embeddings-openai 0.1.6llama-index-llms-openai 0.1.6llama-index-readers-file 0.1.5llamaindex-py-client 0.1.13 LlamaIndexでは、DenseXRetrievalPackは別途ダウンロードする必要があるパッケージです。ここでは、テストコード内で直接ダウンロードします。テストコードは以下のとおりです。 llama_index.core.readers から SimpleDirectoryReader をインポートします
llama_index.core.llama_pack から download_llama_pack をインポート
インポートOS
os.environ["OPENAI_API_KEY"] = "YOUR_OPENAI_KEY"# 依存関係をダウンロードしてインストールするDenseXRetrievalPack = download_llama_pack(
"DenseXRetrievalPack", "./dense_pack")# すでにDenseXRetrievalPackをダウンロードしている場合は、直接インポートできます。# from llama_index.packs.dense_x_retrieval import DenseXRetrievalPack# ドキュメントをロードしますdir_path = "YOUR_DIR_PATH" documents = SimpleDirectoryReader(dir_path).load_data()# LLMを使用して、すべてのドキュメント/ノードから命題を抽出しますdense_pack = DenseXRetrievalPack(documents)
レスポンス = dense_pack.run("YOUR_QUERY") このテストコードは主にDenseXRetrievalPackクラスのコンストラクタを使用しているため、DenseXRetrievalPackクラス[11]のソースコードを解析する必要がある。 クラスDenseXRetrievalPack(BaseLlamaPack): def __init__(
自己、
ドキュメント: リスト[ドキュメント],
proposition_llm: オプション[LLM] = なし、
query_llm: オプション[LLM] = なし、
埋め込みモデル: オプション[BaseEmbedding] = なし、
テキストスプリッター: TextSplitter = SentenceSplitter(),
similarity_top_k: int = 4,
) -> なし: """初期パラメータ。""" self._proposition_llm = proposition_llm または OpenAI(
モデル="gpt-3.5-turbo",
温度=0.1、
最大トークン数=750、
)
embed_model = embed_model または OpenAIEmbedding(embed_batch_size=128)
ノード = text_splitter.get_nodes_from_documents(ドキュメント)
sub_nodes = self._gen_propositions(ノード)
all_nodes = ノード + サブノード
all_nodes_dict = {n.node_id: n (all_nodes 内の n の場合)}
service_context = ServiceContext.from_defaults(
llm=query_llm または OpenAI()、
埋め込みモデル=埋め込みモデル、
num_output=self._proposition_llm.metadata.num_output、
)
self.vector_index = VectorStoreIndex(
all_nodes、service_context=サービスコンテキスト、show_progress=True )
self.retriever = RecursiveRetriever(
"ベクター"、
レトリーバー辞書={
"ベクター": self.vector_index.as_retriever(
類似度トップk=類似度トップk
)
},
node_dict=すべてのノードのdict、
)
self.query_engine = RetrieverQueryEngine.from_args(
self.retriever、service_context=サービスコンテキスト
) コードに示されているように、コンストラクタはまず `text_splitter` を使用して文書を プロジェクトパスにはBERT論文文書が1つだけ存在します。デバッグの結果、sub_nodes[].textの内容が元のテキストではなく、書き換えられていることが判明しました。 > /Users/Florian/anaconda3/envs/llamaindex_010/lib/python3.11/site-packages/llama_index/packs/dense_x_retrieval/base.py(91)__init__()
90
---> 91 all_nodes = ノード + サブノード
92 all_nodes_dict = {n.node_id: n (all_nodes 内の n の場合)}
ipdb>サブノード[20]
IndexNode(id_='ecf310c7-76c8-487a-99f3-f78b273e00d9', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationship={}, text='本論文は、言語表現における双方向事前学習の重要性を実証しています。', start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}', metadata_template='{key}: {value}', metadata_seperator='\n', index_id='8deca706-fe97-412c-a13f-950a19a594d1', obj=None)
ipdb>サブノード[21]
IndexNode(id_='4911332e-8e30-47d8-a5bc-ed7cbaa8e042', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationship={}, text='Radford et al. (2018) uses unidirectional language models for pre-training.', start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}', metadata_template='{key}: {value}', metadata_seperator='\n', index_id='8deca706-fe97-412c-a13f-950a19a594d1', obj=None)
ipdb>サブノード[22]
IndexNode(id_='83aa82f8-384a-4b06-92c8-d6277c4162bf', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationship={}, text='BERTはマスクされた言語モデルを使用して、事前学習済みの深層双方向表現を実現します。', start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}', metadata_template='{key}: {value}', metadata_seperator='\n', index_id='8deca706-fe97-412c-a13f-950a19a594d1', obj=None)
ipdb>サブノード[23]
IndexNode(id_='2ac635c2-ccb0-4e62-88c7-bcbaef3ef38a', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationship={}, text='Peters et al. (2018a) は、独立して訓練された左から右への学習モデルと右から左への学習モデルを浅く連結したものを使用しています。', start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}', metadata_template='{key}: {value}', metadata_seperator='\n', index_id='8deca706-fe97-412c-a13f-950a19a594d1', obj=None)
ipdb> サブノード[24]
IndexNode(id_='e37b17cf-30dd-4114-a3c5-9921b8cf0a77', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationship={}, text='事前学習済みの表現により、多くの高度なタスク固有のアーキテクチャの必要性が軽減されます。', start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}', metadata_template='{key}: {value}', metadata_seperator='\n', index_id='8deca706-fe97-412c-a13f-950a19a594d1', obj=None) sub_nodes と nodes の関係を図 7 に示します。このインデックス構造は、小さいものから大きいものの順にソートされ、整理されています。 図7: 小さい順から大きい順に並べられたインデックス構造。画像は著者提供。 このインデックス構造は、次のコードに示すように、self._gen_propositions[12]を使用して構築されます。 非同期 def _aget_proposition(self, node: TextNode) -> List[TextNode]:
「命題を取得します。」 inital_output = await self._proposition_llm.apredict(
PROPOSITIONS_PROMPT、node_text=node.text
)
出力 = initial_output.split("\n")
all_propositions = [] 出力の場合、output.strip() で出力されない場合: 続行
output.strip().endswith("]") でない場合: output.strip().endswith('"') でない場合、output.strip().endswith( ","
):
出力 = 出力 + '"' 出力 = 出力 + " ]"
output.strip().startswith("[") でない場合: output.strip().startswith('"'): でない場合
出力 = '"' + 出力
出力 = "[ " + 出力を試してください:
propositions = json.loads(output) except Exception: # yaml にフォールバック
試す:
propositions = yaml.safe_load(output) except Exception: # 次の出力にフォールバック
続く
isinstance(propositions, list)でない場合: all_propositions.extend(propositions)を続行し、isinstance(all_propositions, list)をアサートする
nodes = [TextNode(text=prop) for prop in all_propositions if prop] return [IndexNode.from_text_node(n, node.node_id) for n in nodes] def _gen_propositions(self, nodes: List[TextNode]) -> List[TextNode]:
「命題を取得します。」sub_nodes = asyncio.run(
ジョブの実行(
[ノード内のノードのself._aget_proposition(node)],
show_progress=True、
労働者=8、
)
# リストをフラット化する
[sub_nodes 内の sub_node のノード、sub_node 内のノードのノード] を返します。 各オリジナルノードに対して、`self._aget_proposition` が非同期的に呼び出されます。LLM から返される `initial_output` は `PROPOSITIONS_PROMPT` を通じて取得されます。次に、`initial_output` に基づいて命題が取得され、`TextNode` が構築されます。最後に、これらの `TextNode` は `[IndexNode.from_text_node(n, node.node_id) for n in nodes]` を使用してオリジナルノードに関連付けられます。 もう一つ付け加えると、原論文ではLLMによって生成された命題を学習データとして用いて、テキスト生成モデルを微調整しました。このテキスト生成モデルは現在公開されており[13]、興味のある読者は試してみることができます。 全体として、 LLMを用いて命題を構築するこのデータチャンキング手法は、より洗練されたデータチャンキングを可能にします。元のノードを用いて小規模から大規模までのインデックス構造を形成できるため、セマンティックチャンキングへの新たなアプローチを提供します。 しかし、この方法は比較的高価な LLM に依存しています。 条件が許せば、この LLM ベースのデータ分割方法は継続的に追跡および監視できます。 04 結論この記事では、3つのセマンティックチャンキング手法の原理と実装を解説し、いくつかの解説を加えます。セマンティックチャンキングはより洗練されたアプローチであり、RAGを最適化する上で重要な要素の一つです。 如果您对 RAG 技术感兴趣,欢迎阅读本系列的其他文章!如有任何问题,请在评论区提出。 読んでくれてありがとう! —— フロリアン・ジューン An artificial intelligence researcher, mainly write articles about Large Language Models, data structures and algorithms, and NLP. 終わり 参考文献 [1] https://github.com/langchain-ai/langchain/blob/v0.1.9/libs/langchain/langchain/text_splitter.py#L851C1-L851C6 [2] https://docs.llamaindex.ai/en/stable/examples/node_parsers/semantic_chunking.html [3] https://python.langchain.com/docs/modules/data_connection/document_transformers/semantic-chunker [4] https://github.com/run-llama/llama_index/blob/v0.10.12/llama-index-core/llama_index/core/node_parser/text/semantic_splitter.py [5] https://arxiv.org/pdf/1810.04805.pdf [6] https://arxiv.org/abs/2004.14535 [7] https://github.com/aakash222/text-segmentation-NLP/ [8] https://arxiv.org/pdf/2107.09278.pdf [9] https://github.com/alibaba-damo-academy/SpokenNLP [10] https://github.com/modelscope/modelscope/ [11] https://github.com/run-llama/llama_index/blob/v0.10.12/llama-index-packs/llama-index-packs-dense-x-retrieval/llama_index/packs/dense_x_retrieval/base.py [12] https://github.com/run-llama/llama_index/blob/v0.10.12/llama-index-packs/llama-index-packs-dense-x-retrieval/llama_index/packs/dense_x_retrieval/base.py#L161 [13] https://github.com/chentong0/factoid-wiki この記事は、原著者の許可を得てBaihai IDPによって翻訳されました。翻訳の転載をご希望の場合は、お問い合わせください。 オリジナルリンク: https://medium.com/towards-artificial-intelligence/advanced-rag-05-exploring-semantic-chunking-97c12af20a4d 本系列其他文章: Advanced RAG 01:讨论未经优化的RAG 系统存在的问题与挑战 Advanced RAG 02:揭开PDF 文档解析的神秘面纱 Advanced RAG 03:运用RAGAs 与LlamaIndex 评估RAG 应用 Advanced RAG 04:重排序(Re-ranking)技术探讨 |