HUOXIU

上級RAG 07: RAGシステムにおける表形式データ処理への新しいアプローチ

編集者注:現在、検索拡張(RAG)システムは、膨大な知識を大規模モデルに組み込むための重要な技術の一つとなっています。しかし、半構造化データや非構造化データ、特に文書内の表形式データを効率的に処理する方法は、RAGシステムにとって依然として大きな課題となっています。

本稿では、表形式データの処理における新たなソリューションを提案することで、この問題点を解決します。著者らはまず、表の解析やインデックス構造の設計など、RAG​​システムにおける表処理の中核技術を体系的にレビューし、既存のオープンソースソリューションについても解説します。これらの基盤を基に、著者らは革新的な手法を提示します。具体的には、Nougatツールを使用して文書内の表の内容を正確かつ効率的に解析し、言語モデルを用いて表とその見出しを要約し、最後に、新たな文書要約インデックス構造を構築します。また、完全なコード実装の詳細も提供します。

この手法の利点は、表を効率的に解析できること、表の要約と表の関係を包括的に考慮できること、そしてマルチモーダルLLMを必要としないことで解析コストを削減できることです。この手法が今後どのように応用され、実際に発展していくのか、今後の展開を見守りたいと思います。

著者 | フロリアン・ジューン

編纂者:岳陽

RAGシステムの実装は非常に困難な作業であり、特に非構造化文書内の表の解析と理解が必要な場合は困難です。スキャンされた文書や画像形式の文書の場合はさらに困難です。少なくとも3つの主要な課題があります。

  • スキャンされた文書や画像形式の文書は複雑であり、文書構造が多様で、非テキスト要素が存在する可能性があり、手書きと印刷されたコンテンツが混在しています。これらの要因は、表形式の情報の正確かつ自動的な抽出に課題をもたらします。不正確な文書解析は表構造を乱す可能性があり、不完全な表情報をベクトル表現(埋め込み)に変換すると、表の意味情報を効果的に取得できないだけでなく、RAGの最終出力に問題が生じやすくなります。
  • 各テーブルのヘッダーを抽出し、それらを対応する特定のテーブルに関連付ける方法。
  • 合理的なインデックス構造設計を通じて、重要なセマンティック情報をテーブルに効率的に整理して保存する方法。

本稿ではまず、検索拡張生成(RAG)モデルにおける表形式データの管理と処理方法を紹介します。次に、既存のオープンソースソリューションをいくつかレビューし、最後に、最新の技術に基づいて表形式データを管理するための新しい手法を設計・実装します。

01 RAGテーブルデータに関連するコア技術の紹介

1.1 テーブル解析

このモジュールの主な機能は、非構造化ドキュメントまたは画像から表構造を正確に抽出することです。

追加要件:理想的には、開発者がテーブル タイトルをテーブルに簡単に関連付けることができるように、対応するテーブル タイトルを抽出する必要があります。

私の現在の理解に基づくと、図 1 に示すように、いくつかの方法があります。

図1: テーブルパーサー。画像は原著者より提供。

(a)マルチモーダルLLM(GPT-4V[1]など)を使用して表を識別し、各PDFページから情報を抽出します。

  • 入力: 画像形式のPDFページ
  • 出力: JSONまたはその他の形式の表形式データ。マルチモーダルLLMが表形式データを抽出できない場合は、PDF画像を要約し、コンテンツサマリーを返す必要があります。

(b)専門的な表検出モデル(Table Transformer[2]など)を使用して表の構造を識別する。

  • 入力: PDFページ画像
  • 出力: テーブルイメージ

(c)オープンソースフレームワーク(非構造化[3]や、オブジェクト検出モデルを採用した他のフレームワークなど)を使用する(非構造化における表検出プロセスについては、この記事[4]で詳しく説明されている)。これらのフレームワークは、文書全体を完全に解析し、解析結果から表に関連するコンテンツを抽出することができる。

  • 入力: PDFまたは画像形式のドキュメント
  • 出力: プレーンテキストまたは HTML 形式の表 (ドキュメント全体の解析結果から取得)

(d) Nougat[5]やDonut[6]などのエンドツーエンドモデルを用いて文書全体を解析し、表に関連するコンテンツを抽出します。この手法ではOCRモデルは必要ありません。

  • 入力: PDFまたは画像形式のドキュメント
  • 出力: LaTeX または JSON 形式の表 (ドキュメント全体の解析結果から取得)。

表情報の抽出方法に関わらず、表のタイトルも抽出する必要があることに注意が必要です。これは、ほとんどの場合、表のタイトルは文書または論文の著者による表の簡潔な説明であり、表全体の内容を概ね要約できるためです。

上記の4つの方法のうち、方法(d)はテーブルヘッダーを取得する最も便利な方法です。これは、テーブルヘッダーをテーブル自体に関連付けることができるため、開発者にとって非常に便利です。次の実験で、この点をさらに詳しく説明します。

1.2 インデックス構造: 表形式データのインデックス作成方法

インデックスの作成方法には、おおよそ以下の種類があります。

(e)画像形式の表のみのインデックス。

(f)プレーンテキストまたは JSON 形式のテーブルのみをインデックスします。

(g) LaTeX形式の表のみの索引。

(h)表の概要のみを索引付けします。

(i).小規模から大規模へ(翻訳者注:これには、各行や表の要約をインデックスするなどの細粒度のインデックスと、画像、プレーンテキスト、LaTeXデータの表全体をインデックスするなどの粗粒度のインデックスの両方が含まれ、階層的な小規模から大規模までのインデックス構造を形成します。)または、図2に示すように、表の要約を使用してインデックス構造を構築します。

小さなチャンク(翻訳者注:細粒度インデックス レベルに対応するデータ ブロック)の内容は、たとえば、テーブルまたはサマリー情報の各行を独立した小さなデータ ブロックとして扱います。

大きなチャンク (翻訳者注: 粗粒度のインデックス レベルに対応するデータ ブロック) の内容は、画像形式、プレーン テキスト形式、または LaTeX 形式のテーブル全体である場合があります。

図2:小規模から大規模へのアプローチを用いた索引作成(上)と表要約を用いた索引作成(中と下)。画像は原著者提供。

前述のように、テーブル サマリーは通常、LLM 処理を使用して生成されます。

  • 入力: 画像、テキスト、または LaTeX 形式の表。
  • 出力: 表の概要

1.3 テーブルの解析、インデックスの作成、RAGテクノロジの使用を必要としない方法

一部のアルゴリズムでは、表形式のデータの解析は必要ありません。

(j)関連する画像(PDF文書ページ)とユーザーのクエリをVQAモデル(DAN[7]など)またはマルチモーダルLLMに送信し、回答を返します。

  • インデックス対象となるコンテンツ: 画像形式のドキュメント
  • VQAモデルまたはマルチモーダルLLMに送信されるコンテンツ:クエリ+対応するドキュメントページ(画像形式)

(k)関連するテキスト形式の PDF ページとユーザーのクエリを LLM に送信し、回答を返します。

  • インデックス対象となるコンテンツ: テキスト形式のドキュメント
  • LLMに送信されるコンテンツ: クエリ + 対応するドキュメントページ (テキスト形式)

(l).関連する文書画像(PDF文書ページ)、テキストブロック、ユーザークエリをマルチモーダルLLM(GPT-4Vなど)に送信し、直接回答を返します。

  • インデックスされるコンテンツ: 画像形式のドキュメントとテキスト形式のドキュメント チャンク。
  • マルチモーダル LLM に送信されるコンテンツは、クエリ、対応する画像形式のドキュメント、および対応するテキスト チャンクで構成されます。

さらに、図 3 と 4 に示すように、インデックス作成を必要としない方法もいくつかあります。

図3:カテゴリー(m)(訳者注:以下の第1段落で紹介されている内容を指す)。画像は原著者提供。

(m)まず、(a)から(d)のいずれかの手法を用いて、文書内のすべての表を画像形式に変換します。次に、すべての表画像とユーザーのクエリをマルチモーダルLLM(GPT-4Vなど)に直接送信し、回答を返します。

  • インデックスするコンテンツ: なし
  • マルチモーダルLLMに送信されるコンテンツ: クエリ + 画像形式に変換されたすべてのテーブル

図4:カテゴリー(n)(訳者注:以下の最初の段落で紹介されている内容)。画像は原著者提供。

(n) (m)の方法で抽出した画像形式の表を使用し、OCRモデルを使用して表内のすべてのテキストを認識し、表内のすべてのテキストとユーザーのクエリを直接LLMに送信して回答を直接返します。

  • インデックスするコンテンツ: なし
  • LLM に送信されるコンテンツ: ユーザーのクエリ + すべてのテーブル コンテンツ (テキスト形式で送信)

いくつかの方法では、ドキュメント内の表を処理するときに RAG (Retrieval-Augmented Generation) テクノロジを使用しないことに注意してください。

  • 最初のタイプのアプローチはLLMを使用せず、特定のデータセットでトレーニングしてAIモデル(Transformerアーキテクチャに基づいてBERTに触発された他の言語モデルなど)がTAPAS [8]などの表理解タスクの処理をより適切にサポートできるようにします。
  • 2つ目の方法は、事前トレーニング、微調整法、またはキューワードエンジニアリングを採用したLLMを使用して、GPT4Table[9]などの表理解タスクをLLMで完了できるようにすることです。

02 テーブル処理のための既存のオープンソースソリューション

前のセクションでは、RAGシステムにおける表形式データ処理の主要なテクノロジーをまとめ、分類しました。この記事で実装するソリューションを提案する前に、オープンソースソリューションをいくつか見ていきましょう。

LlamaIndexは4つの方法[10]を提案しており、最初の3つはすべてマルチモーダルモデルを使用していました。

  • 関連する PDF ページ画像を取得し、GPT-4V 応答ユーザー クエリに送信します。
  • 各PDFページは画像形式に変換され、GPT-4Vは各ページで画像推論を実行できます。画像推論プロセス用にテキストベクターストアインデックスが作成され(訳注:画像から推論されたテキスト情報をベクター形式に変換し、インデックスを作成します)、その後、画像推論ベクターストア(訳注:これは事前に作成されたインデックスであり、事前に作成されたテキストベクターストアインデックスを参照します)に基づいて回答が取得されます。
  • Table Transformer は、取得した画像からテーブル情報を切り取るために使用され、切り取られたテーブル画像は GPT-4V に送信され、クエリ応答が取得されます。
  • 切り取られたテーブル画像に OCR を適用し、データを GPT4/GPT-3.5 に送信してユーザーのクエリに回答します。

上記の 4 つの方法を要約すると次のようになります。

  • 最初の方法は、本論文で説明した方法(j)に似ており、テーブル解析を必要としません。しかし、結果を見ると、答えが画像内に存在する場合でも、正しい答えを生成できないことがわかります。
  • 2つ目の方法は、表を解析する方法で、方法(a)に相当します。インデックス付けされるコンテンツは、GPT-4Vによって返される結果に応じて、表の内容またはコンテンツの要約とな​​る可能性があり、方法(f)または(h)に相当します。この方法の欠点は、GPT-4Vが表を識別し、文書画像からその内容を抽出する能力に一貫性がないことです。特に、文書画像に表、テキスト、その他の画像が含まれている場合(PDF文書ではよくあることです)、その傾向が顕著です。
  • 3 番目の方法は方法 (m) に似ており、インデックスは必要ありません。
  • 4番目の方法は方法(n)に類似しており、インデックス作成を必要としません。その結果、誤答の原因は画像から表形式の情報を効果的に抽出できないことにあることが示唆されました。

テストの結果、3番目の方法が全体的に最も優れたパフォーマンスを発揮することがわかりました。しかし、私のテストでは、3番目の方法は表の検査に苦労し、表のタイトルと内容を正しく抽出して結合することはなおさら困難でした。

Langchainは、半構造化データのための半構造化RAG[11]技術のソリューションもいくつか提案しており、その中核技術には以下が含まれます。

  • テーブル解析に非構造化を使用するのはクラス (c) メソッドです。
  • 索引方式は文書要約索引(訳者注:文書要約情報を索引内容とする)であり、クラス(i)方式に属する。細粒度索引レベルに対応するデータブロックは表要約内容であり、粗粒度索引レベルに対応するデータブロックは元の表内容(テキスト形式)である。

図5に示すように:

図5:Langchainの半構造化RAGスキーム。出典:半構造化RAG[11]

半構造化およびマルチモーダルRAG[12]は3つのソリューションを提案しており、そのアーキテクチャを図6に示す。

図6: Langchainの半構造化・マルチモーダルRAGスキーム。出典: 半構造化・マルチモーダルRAG[12]。

オプション1は、上記の方法(l)に似ています。この方法では、マルチモーダル埋め込み(CLIP[13]など)を用いて画像とテキストを埋め込みベクトルに変換し、類似性検索アルゴリズムを用いて両者を取得し、未処理の画像とテキストデータをマルチモーダルLLMに渡して一緒に処理し、質問への回答を生成します。

オプション2は、マルチモーダルLLM(GPT-4V[14]、LLaVA[15]、FUYU-8b[16]など)を用いて画像を処理することでテキスト要約を生成します。テキストデータは埋め込みベクトルに変換され、ユーザーのクエリに一致するテキストコンテンツを検索または取得するために使用され、これらのテキストコンテンツはLLMに渡されて回答を生成します。

  • 表形式データの解析には、クラス (d) メソッドに属する非構造化メソッドが使用されます。
  • 索引方式は文書要約索引(訳者注:文書要約情報を索引内容とする)であり、クラス(i)の方式に属する。細粒度索引レベルに対応するデータブロックは表要約内容であり、粗粒度索引レベルに対応するデータブロックはテキスト形式の表内容である。

オプション3は、マルチモーダルLLM(GPT-4V[14]、LLaVA[15]、FUYU-8b[16]など)を用いて画像データからテキスト要約を生成し、これらのテキスト要約をベクトルに埋め込みます。これらの埋め込みベクトルを用いることで、画像要約を効率的に取得することができます。取得された各画像要約には、生画像への参照が保持されます。これは上記のクラス(i)の手法に属します。最後に、未処理の画像データとテキストブロックをマルチモーダルLLMに渡して、回答を生成します。

03 この論文で提案された解決策

これまでの文章では、主要な技術と既存のソリューションを要約、分類、議論してきました。これに基づき、図7に示すようなソリューションを提案します。図では、簡略化のため、再ランキングやクエリ書き換えなどの一部のRAGモジュールを省略しています。

図7:本論文で提案された解決策。画像は原著者提供。

  • 表解析技術:Nougat((d)クラスメソッド)を使用。私のテストでは、このツールは非構造化((c)クラスメソッド)よりも表検出において効率的であることが確認されました。さらに、Nougatは表ヘッダーを非常に正確に抽出するため、表との関連付けに非常に便利です。
  • 文書要約の索引作成と検索に用いる索引構造((i)クラスメソッド):細粒度索引レベルに対応するコンテンツには表内容要約が含まれ、粗粒度索引レベルに対応するコンテンツにはLaTeX形式の表とテキスト形式の表タイトルが含まれる。これを実装するために、マルチベクトル検索器[17](訳者注:文書要約索引の内容検索に用いられる検索器で、複数のベクトルを同時に処理することでクエリに関連する文書要約を効率的に検索できるもの)を用いる。
  • 表の内容の概要を取得する方法:内容の概要を取得するには、表と表のタイトルを LLM に送信します。

この手法の利点は、表を効率的に解析し、表の要約と表の関係を包括的に考慮できることです。マルチモーダルLLMが不要になるため、コストを削減できます。

3.1 ヌガーの仕組み

Nougat[18]はDonut[19]アーキテクチャに基づいて開発されています。この手法で使用されるアルゴリズムは、OCR関連の入力やモジュールを必要とせずに、暗黙的にテキストを自動認識できます。

図8:Donut[19]に倣ったエンドツーエンドのアーキテクチャ。Swin Transformerエンコーダは文書画像を受け取り、それを潜在的埋め込みに変換し、さらに自己回帰的に一連のトークンに変換します。出典:Nougat: Neural Optical Understanding for Academic Documents[18]

Nougatは数式解析能力に優れていますが[20]、表の解析にも優れています。図9に示すように、表のヘッダーを関連付けることができ、非常に便利です。

図9: Nougatの実行結果。結果ファイルはMathpix Markdown形式(VS Codeプラグインで開くことができます)で、表はLaTeX形式で表示されます。

12以上の論文で行ったテストでは、表のヘッダーが常に表の下の次の行に固定されていることがわかりました。この一貫性は、偶然ではないことを示唆しています。そのため、Nougatがこの機能をどのように実現しているのか、非常に興味があります。

これは中間結果のないエンドツーエンドのモデルであるため、そのパフォーマンスはトレーニング データに大きく依存する可能性があります。

コード分​​析に基づくと、テーブルヘッダーセクションの保存場所と方法は、トレーニングデータ内のテーブル構成形式と一致しているようです( caption_parts \end{table}直後にあります)。

デフフォーマット要素(
要素: 要素、keep_refs: bool = False、latex_env: bool = False
) -> リスト[str]:
「」
指定された要素をフォーマットされた文字列のリストにフォーマットします。
引数:
要素 (Element): フォーマットする要素。
keep_refs (bool, オプション): 書式設定で参照を保持するかどうか。デフォルトはFalseです。
latex_env (bool, オプション): LaTeX環境フォーマットを使用するかどうか。デフォルトはFalseです。
戻り値:
List[str]: フォーマットされた要素を表すフォーマットされた文字列のリスト。
「」
...
...isinstance(要素、テーブル)の場合:
parts = [ "[TABLE%s]\n\begin{table}\n"
% (str(uuid4())[:5]、element.idがNoneの場合、そうでない場合は ":" + str(element.id))
]
parts.extend(format_children(要素、keep_refs、latex_env))
caption_parts = format_element(element.caption, keep_refs, latex_env)
末尾の空白を削除(キャプション部分)
len(caption_parts) > 0 の場合、parts.append("\end{table}\n") を追加します。
parts.extend(caption_parts + ["\n"])
parts.append("[ENDTABLE]\n\n") 部品を返す
...
... 

3.2 ヌガーの長所と短所

アドバンテージ:

  • Nougat は、以前の解析ツールでは困難だった部分 (数式や表など) を LaTeX ソース コードに正確に解析できます。
  • Nougat の解析により、Markdown に似た半構造化ドキュメントが生成されます。
  • テーブルタイトルを簡単に取得し、テーブルに簡単に関連付けることができます。

欠点:

  • Nougat の解析速度は比較的遅いため、大規模なアプリケーションでは問題が発生する可能性があります。
  • Nougatのトレーニングデータセットは主に科学論文で構成されているため、この手法は類似した構造を持つ文書に対して非常に優れたパフォーマンスを発揮します。ただし、ラテン文字以外のテキスト文書を処理する場合はパフォーマンスが低下します。
  • Nougatモデルは、科学論文の1ページのみを学習するため、他のページに関する知識がありません。そのため、解析結果に矛盾が生じる可能性があります。したがって、認識性能が不十分な場合は、PDFを複数のページに分割し、ページごとに解析することを検討してください。
  • 2 列の論文での表の解析は、1 列の論文の場合ほど良好ではありません。

3.3 コードの実装

まず、関連する Python パッケージをインストールします。

 pip で langchain をインストールし、pip で chromadbp をインストールし、pip で nougat-ocr をインストールします。 

インストール後、Python パッケージのバージョンを確認する必要があります。

 langchain 0.1.12、langchain-community 0.0.28、langchain-core 0.1.31、langchain-openai 0.0.8、langchain-text-splitters 0.0.1、chroma-hnswlib 0.7.3、chromadb 0.4.24、nougat-ocr 0.1.17 

作業環境を設定し、ソフトウェア パッケージをインポートします。

インポートOS
os.environ["OPENAI_API_KEY"] = "YOUR_OPEN_AI_KEY" サブプロセスをインポートしてUUIDをインポートする
langchain_core.output_parsers から StrOutputParser をインポートします
langchain_core.promptsからChatPromptTemplateをインポートします
langchain_openaiからChatOpenAIをインポート
langchain.retrievers.multi_vector から MultiVectorRetriever をインポートします
langchain.storageからInMemoryStoreをインポートする
langchain_community.vectorstores から Chroma をインポート
langchain_core.documentsからDocumentをインポートする
langchain_openaiからOpenAIEmbeddingsをインポート
langchain_core.runnables から RunnablePassthrough をインポートします

論文「Attention Is All You Need」[21]をYOUR_PDF_PATHにダウンロードし、Nougatを実行してPDFファイルを解析し、解析結果からLaTeX形式の表データとテキスト形式の表タイトルを取得します。プログラムの初回実行時には、必要なモデルファイルがローカル環境にダウンロードされます。

 june_run_nougat を定義します(ファイルパス、出力ディレクトリ):
# Nougat を実行し、結果を Mathpix Markdown として保存します。cmd = ["nougat", file_path, "-o", output_dir, "-m", "0.1.0-base", "--no-skipping"]
res = サブプロセス.run(cmd)
res.returncode != 0 の場合:
print("Nougat 実行中にエラーが発生しました。") return res.returncode else:
print("操作が完了しました!") return 0def june_get_tables_from_mmd(mmd_path): f = open(mmd_path)
行 = f.readlines()
解像度 = []
一時 = []
フラグ = ""
行内の行の場合: 行 == "\begin{table}\n" の場合:
            フラグ = "開始可能"
elif 行 == "\end{table}\n":
フラグ = "ENDTABLE"

フラグ == "BEGINTABLE" の場合:
tmp.append(line) elif flag == "ENDTABLE":
tmp.append(行)
フラグ = "キャプション"
elifフラグ == "CAPTION":
tmp.append(行)
フラグ = "MARKDOWN"
印刷('-' * 100)
print(''.join(tmp))
res.append(''.join(tmp))
tmp = [] resを返す
file_path = "YOUR_PDF_PATH" output_dir = "YOUR_OUTPUT_DIR_PATH" june_run_nougat(file_path, output_dir) == 1の場合: sysをインポート
sys.exit(1)
mmd_path = output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd" テーブル = june_get_tables_from_mmd(mmd_path) 

関数 june_get_tables_from_mmd は、図 10 に示すように、mmd ファイルからすべてのコンテンツ ( \begin{table} \end{table} \end{table}まで) を抽出するために使用されます。

図10: Nougatの実行結果。結果ファイルはMathpix Markdown形式(VS Codeプラグインで開くことができます)で、解析された表の内容はLaTeX形式です。関数「june_get_tables_from_mmd」は、赤い枠で囲まれた表の情報を抽出します。画像は原著者提供。

しかし、表のヘッダーを表の下に配置する必要があることや、表は\begin{table}で始まり\end{table}で終わる必要があることを規定した公式ドキュメントは現時点では存在しません。そのため、june_get_tables_from_mmdはヒューリスティックなアプローチです。

以下は PDF ドキュメントからの表解析結果です。

操作が完了しました!--------------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{l c c c} \hline \hline レイヤータイプ、レイヤーあたりの複雑さ、順次操作、最大パス長 \ \hline 自己注意 & (O(n^{2}\cdot d)) & (O(1)) & (O(n\cdot) \ 再帰 & (O(1)) d^{2})) & (O(n)) & (O(n)) \ 畳み込み & (O(k\cdot n\cdot d^{2})) & (O(1)) & (O(log_{k}(n))) \ 自己注意 (制限付き) & (O(r\cdot n\cdot d)) & (O(1)) & (O(n/r)) \ \hline \hline \end{tabular}\end{table}表 1: さまざまなレイヤー タイプの最大パス長、レイヤーごとの複雑さ、および最小の連続操作数。 (n) はシーケンス長、(d) は表現次元、(k) は畳み込みのカーネルサイズ、(r) は制限付き自己注意における近傍のサイズです。------------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{l c c c c} \hline \hline \multirow{2}{*}{モデル} & \multicolumn{2}{c}{BLEU} & \multicolumn{2}{c}{トレーニングコスト (FLOP)} \ \cline{2-5} & EN-DE & EN-FR & EN-DE & EN-FR \ \hline ByteNet [18] & 23.75 & & & \ Deep-Att + PosUnk [39] & & 39.2 & & (1.0\cdot 10^{20}) \ GNMT + RL [38] & 24.6 & 39.92 & (2.3\cdot 10^{19}) & (1.4\cdot 10^{20}) \ ConvS2S [9] & 25.16 & 40.46 & (9.6\cdot 10^{18}) & (1.5\cdot 10^{20}) \ MoE [32] & 26.03 & 40.56 & (2.0\cdot 10^{19}) & (1.2\cdot 10^{20}) \ \hline Deep-Att + PosUnk アンサンブル [39] & & 40.4 & & (8.0\cdot 10^{20}) \ GNMT + RL アンサンブル [38] & 26.30 & 41.16 & (1.8\cdot 10^{20}) & (1.1\cdot 10^{21}) \ ConvS2S Ensemble [9] & 26.36 & **41.29** & (7.7\cdot 10^{19}) & (1.2\cdot 10^{21}) \ \hline Transformer (基本モデル) & 27.3 & 38.1 & & (\mathbf{3.3\cdot 10^{18}}) \ Transformer (大規模) & **28.4** & **41.8** & & (2.3\cdot 10^{19}) \ \hline \hline \end{tabular}\end{table}表2: Transformerは、英語からドイツ語およびフランス語の翻訳において、従来の最先端モデルよりも優れたBLEUスコアを達成しています。英語からフランス語への newstest2014 テストをわずかなトレーニング コストで実行できます。----------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{c|c c c c c c c c|c c c c} \hline \hline & (N) & (d_{\text{model}}) & (d_{\text{ff}}) & (d_{\text{ff}}) & (h) & (d_{k}) & (d_{k}) & (P_{drop}) & (\epsilon_{ls}) & train steps & PPL & BLEU & params \ \hline base & 6 & 512 & 2048 & 8 & 64 & 64 & 0.1 & 0.1 & 100K & 4.92 & 25.8 & 65 \ \hline \multirow{4}{*}{(A)} & \multicolumn{1}{c}{} & & 1 & 512 & 512 & & & & 5.29 & 24.9 & \ & & & & 4 & 128 & 128 & & & & 5.00 & 25.5 & \ & & & 16 & 32 & 32 & & & & 4.91 & 25.8 & \ & & & & 32 & 16 & 16 & & & & 5.01 & \multicolumn{1}{c}{} & & & & & & & & 6.11 & 23.7 & 36 \ & 4 & & & & & & & & & & 5.19 & 25.3 & 50 \ & 8 & & & & & & & & & 4.88 & 25.5 & 80 \ & & 256 & & 32 & 32 & & & & 5.75 & 24.5 & 28 \ & 1024 & & 128 & 128 & & & & 4.66 & 26.0 & 168 \ & & 1024 & & & & & & 5.12 & 25.4 & 53 \ & & 4096 & & & & & & 4.75 & 26.2 & 90 \ \hline \multirow{4}{*}{(D)} & \multicolumn{1}{c}{} & & & & & 0.0 & & 5.77 & 24.6 & \ & & & & & & & 0.2 & & 4.95 & 25.5 & \ & & & & & & & 0.0 & 4.67 & 25.3 & \ & & & & & & & 0.2 & 5.47 & 25.7 & \ \hline (E) & \multicolumn{1}{c}{} & \multicolumn{1}{c}{} & & \multicolumn{1}{c}{} & & & & 4.92 & 25.7 & \ \hline big & 6 & 1024 & 4096 & 16 & & 0.3 & 300K & **4.33** & **26.4** & 213 \ \hline \hline \end{tabular}\end{table}表3:Transformerアーキテクチャのバリエーション。記載されていない値は基本モデルの値と同じです。すべてのメトリックは、英語からドイツ語への翻訳開発セットnewstest2013に基づいています。記載されているパープレキシティは、バイトペアエンコーディングに従った単語単位のものであり、単語単位のパープレキシティと比較すべきではありません。---------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{c|c|c} \hline**Parser** & **Training** & **WSJ 23 F1** \ \hline Vinyals & Kaiser et al. (2014) [37] & WSJ only, discriminative & Petrov et al. (2006) discriminative & 90.4 \ Zhu et al. (2013) [40] & WSJ only, discriminative & 90.4 \ Dyer et al. (2016) [8] & WSJのみ、識別 & 91.7 \ \hline Transformer(4層) & WSJのみ、識別 & 91.3 \ \hline Zhu et al. (2013) [40] & 半教師あり & 91.3 \ Huang & Harper (2009) [14] & 半教師あり & 91.3 \ McClosky et (2006) [26] & 半教師あり & 92.1 \ Vinyals & Kaiser el al. (2014) [37] & 半教師あり & 92.1 \ \hline Transformer(4層) & 半教師あり & 92.7 \ \hline Luong et al. (2015) [23] & マルチタスク & 93.0 \ Dyer et al. (2016) [8] & 生成 & 93.3 \ \hline \end{tabular}\end{table}表4: Transformerは英語の構成構文解析によく一般化します(結果はWSJのセクション23にあります)* [5] Kyunghyun Cho、Bart van Merrienboer、Caglar Gulcehre、Fethi Bougares、Holger Schwenk、およびYoshua Bengio。統計的機械翻訳のためのrnnエンコーダー-デコーダーを使用したフレーズ表現の学習。_CoRR_、abs/1406.1078、2014。 

次に、LLM を使用して表形式のデータを要約します。

 # Promptprompt_text = """あなたは、表とテキストを要約する役割を担うアシスタントです。\
表またはテキストの簡潔な要約を記述してください。表はLaTeXでフォーマットされており、キャプションはプレーンテキスト形式です。{element} """prompt = ChatPromptTemplate.from_template(prompt_text)# Summary chainmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")
summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()# テーブルサマリーを取得table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})
print(table_summaries) 

以下は図11に示すように、『Attention Is All You Need』[21]の4つの表の内容を要約したものです。

図11:「Attention Is All You Need」[21]の4つの表の内容の要約。

文書要約索引構造[17]は、マルチベクトルリトリーバー(文書の要約情報を格納し、必要に応じてこの要約情報を検索または照会できる索引構造の一種)を使用して構築される。

 # 子チャンクのインデックスに使用するベクトルストアvectorstore = Chroma(collection_name = "summaries", embedding_function = OpenAIEmbeddings())# 親ドキュメントのストレージレイヤーstore = InMemoryStore()
id_key = "doc_id"# リトリーバー(最初は空)retriever = MultiVectorRetriever(
ベクターストア = ベクターストア、
ドキュメントストア = ストア、
id_key = id_key、
search_kwargs={"k": 1} # 要求された結果の数 4 がインデックス内の要素数より大きいため、n_results = 1 を更新します)# テーブルを追加しますtable_ids = [str(uuid.uuid4()) for _ in tables]
summary_tables = [
ドキュメント(ページコンテンツ = s、メタデータ = {id_key: table_ids[i]})
enumerate(table_summaries) の i, s について
]
retriever.vectorstore.add_documents(summary_tables)
retriever.docstore.mset(リスト(zip(テーブルID、テーブル))) 

すべての準備が整ったら、シンプルな RAG パイプラインを設定し、ユーザーのクエリを実行します。

 # プロンプトテンプレートテンプレート = """次のコンテキストのみに基づいて質問に答えます。これにはテキストと表を含めることができ、LaTeX 形式の表とプレーンテキスト形式の表のキャプションがあります。
{コンテクスト}
質問: {質問}
"""prompt = ChatPromptTemplate.from_template(template)# LLMmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")# シンプルなRAGパイプラインchain = (
{"context": リトリーバー、「question": RunnablePassthrough()}
| プロンプト
| モデル
| StrOutputParser()
)
print(chain.invoke("レイヤータイプがSelf-Attentionの場合、レイヤーあたりの複雑度はどれくらいですか?")) # テーブル1に関するクエリprint(chain.invoke("BLEU EN-DEの場合、どのパーサーのパフォーマンスが最悪ですか?")) # テーブル2に関するクエリprint(chain.invoke("WSJ 23 F1の場合、どのパーサーのパフォーマンスが最良ですか?")) # テーブル4に関するクエリ

結果は次のとおりです。図 12 に示すように、すべての質問に正確に回答しました。

図12: 3つのユーザークエリに対する回答結果。最初の行は「Attention Is All You Need」の表1、2行目は表2、3行目は表4に対応しています。

全体的なコードは次のとおりです。

インポートOS
os.environ["OPENAI_API_KEY"] = "YOUR_OPEN_AI_KEY" import subprocessimport uuidfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIfrom langchain.retrievers.multi_vector import MultiVectorRetrieverfrom langchain.storage import InMemoryStorefrom langchain_community.vectorstores import Chromafrom langchain_core.documents import Documentfrom langchain_openai import OpenAIEmbeddingsfrom langchain_core.runnables import RunnablePassthroughdef june_run_nougat(file_path, output_dir):
 # Run Nougat and store results as Mathpix Markdown    cmd = ["nougat", file_path, "-o", output_dir, "-m", "0.1.0-base", "--no-skipping"]
    res = subprocess.run(cmd)
  if res.returncode != 0:
 print("Error when running nougat.") return res.returncode else:
 print("Operation Completed!") return 0def june_get_tables_from_mmd(mmd_path):    f = open(mmd_path)
    lines = f.readlines()
    res = []
    tmp = []
    flag = ""
 for line in lines: if line == "\begin{table}\n":
            flag = "BEGINTABLE"
 elif line == "\end{table}\n":
            flag = "ENDTABLE"

  if flag == "BEGINTABLE":
            tmp.append(line) elif flag == "ENDTABLE":
            tmp.append(line)
            flag = "CAPTION"
 elif flag == "CAPTION":
            tmp.append(line)
            flag = "MARKDOWN"
 print('-' * 100)
 print(''.join(tmp))
            res.append(''.join(tmp))
            tmp = [] return res
file_path = "YOUR_PDF_PATH"output_dir = "YOUR_OUTPUT_DIR_PATH"if june_run_nougat(file_path, output_dir) == 1: import sys
    sys.exit(1)
mmd_path = output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd" tables = june_get_tables_from_mmd(mmd_path)# Promptprompt_text = """You are an assistant tasked with summarizing tables and text. \
 Give a concise summary of the table or text. The table is formatted in LaTeX, and its caption is in plain text format: {element}  """prompt = ChatPromptTemplate.from_template(prompt_text)# Summary chainmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")
summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()# Get table summariestable_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})
print(table_summaries)# The vectorstore to use to index the child chunksvectorstore = Chroma(collection_name = "summaries", embedding_function = OpenAIEmbeddings())# The storage layer for the parent documentsstore = InMemoryStore()
id_key = "doc_id"# The retriever (empty to start)retriever = MultiVectorRetriever(
    vectorstore = vectorstore,
    docstore = store,
    id_key = id_key,
    search_kwargs={"k": 1} # Solving Number of requested results 4 is greater than number of elements in index..., updating n_results = 1)# Add tablestable_ids = [str(uuid.uuid4()) for _ in tables]
summary_tables = [
    Document(page_content = s, metadata = {id_key: table_ids[i]}) for i, s in enumerate(table_summaries)
]
retriever.vectorstore.add_documents(summary_tables)
retriever.docstore.mset(list(zip(table_ids, tables)))# Prompt templatetemplate = """Answer the question based only on the following context, which can include text and tables, there is a table in LaTeX format and a table caption in plain text format:
{context}
Question: {question}
"""prompt = ChatPromptTemplate.from_template(template)# LLMmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")# Simple RAG pipelinechain = (
 {"context": retriever, "question": RunnablePassthrough()}
 | prompt
 | model
 | StrOutputParser()
)
print(chain.invoke("when layer type is Self-Attention, what is the Complexity per Layer?")) # Query about table 1print(chain.invoke("Which parser performs worst for BLEU EN-DE")) # Query about table 2print(chain.invoke("Which parser performs best for WSJ 23 F1")) # Query about table 4 

04 結論

本文讨论了在 RAG 系统中表格处理操作的关键技术和现有解决方案,并提出了一种解决方案及其实现方法。

在本文中,我们使用了 Nougat 来解析表格。不过,如果有更快、更有效的解析工具可用,我们会考虑替换掉 Nougat 。我们对工具的态度是先有正确的 idea ,然后再找工具来实现它,而不是依赖于某个工具。

在本文中,我们将所有表格内容输入到 LLM 。但是,在实际场景中,我们需要考虑到表格大小超出 LLM 上下文长度的情况。我们可以通过使用有效的分块(chunking)方法来解决这个问题。

読んでくれてありがとう!

——

フロリアン・ジューン

An artificial intelligence researcher, mainly write articles about Large Language Models, data structures and algorithms, and NLP.

終わり

参考文献

[1] https://openai.com/research/gpt-4v-system-card

[2] https://github.com/microsoft/table-transformer

[3] https://unstructured-io.github.io/unstructured/best_practices/table_extraction_pdf.html

[4] https://pub.towardsai.net/advanced-rag-02-unveiling-pdf-parsing-b84ae866344e

[5] https://github.com/facebookresearch/nougat

[6] https://github.com/clovaai/donut/

[7] https://arxiv.org/pdf/1611.00471.pdf

[8] https://aclanthology.org/2020.acl-main.398.pdf

[9] https://arxiv.org/pdf/2305.13062.pdf

[10] https://docs.llamaindex.ai/en/stable/examples/multi_modal/multi_modal_pdf_tables.html

[11] https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_Structured_RAG.ipynb?ref=blog.langchain.dev

[12] https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_structured_and_multi_modal_RAG.ipynb

[13] https://openai.com/research/clip

[14] https://openai.com/research/gpt-4v-system-card

[15] https://llava.hliu.cc/

[16] https://www.adept.ai/blog/fuyu-8b

[17] https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector

[18] https://arxiv.org/pdf/2308.13418.pdf

[19] https://arxiv.org/pdf/2111.15664.pdf

[20] https://medium.com/@florian_algo/unveiling-pdf-parsing-how-to-extract-formulas-from-scientific-pdf-papers-a8f126f3511d

[21] https://arxiv.org/pdf/1706.03762.pdf

この記事は、原著者の許可を得てBaihai IDPによって翻訳されました。翻訳の転載をご希望の場合は、お問い合わせください。

オリジナルリンク:

https://ai.plainenglish.io/advanced-rag-07-exploring-rag-for-tables-5c3fc0de7af6