如何找做網(wǎng)站的公司網(wǎng)絡(luò)廣告的形式
摘要
本文詳細討論了實現(xiàn) Retrieval-Augmented Generation(RAG)時對表格進行處理的挑戰(zhàn),特別是在非結(jié)構(gòu)化文檔中自動準(zhǔn)確地提取和理解表格信息。
首先介紹了RAG中管理表格的關(guān)鍵技術(shù),包括表格解析和索引結(jié)構(gòu)設(shè)計。
接著,文章回顧了一些現(xiàn)有的開源解決方案,如LlamaIndex和Langchain提出的方法。
然后,文章提出了一種新的解決方案,使用Nougat模型進行表格解析,能夠準(zhǔn)確地提取表格和表格標(biāo)題,并通過多向量檢索器構(gòu)建文檔摘要索引結(jié)構(gòu),以便更有效地存儲和檢索表格的語義信息。
此外,文章還探討了Nougat模型的原理和優(yōu)缺點,以及如何使用LLM(如GPT-3.5)對表格進行摘要,最后構(gòu)建了一個簡單的RAG管道來回答關(guān)于表格內(nèi)容的查詢。
文章觀點
- 表格解析的重要性: 文章強調(diào)了在RAG中準(zhǔn)確解析表格的重要性,尤其是在處理非結(jié)構(gòu)化文檔時。
- Nougat模型的優(yōu)勢: Nougat模型在解析復(fù)雜表格和提取表格標(biāo)題方面表現(xiàn)出色,能夠不依賴于OCR模型。
- 多向量檢索器的作用: 通過使用多向量檢索器,可以更有效地構(gòu)建文檔摘要索引結(jié)構(gòu),提高檢索表格信息的準(zhǔn)確性。
- LLM在表格處理中的應(yīng)用: 文章展示了如何利用LLM(如GPT-3.5)對表格進行摘要,以便更好地理解和檢索表格內(nèi)容。
- RAG管道的構(gòu)建: 文章提供了一個簡單的RAG管道示例,展示了如何使用提出的解決方案來回答具體的查詢問題。
- 對現(xiàn)有解決方案的評估: 文章對比了不同的開源解決方案,并對它們的優(yōu)缺點進行了評估,以此來支持提出的新解決方案的有效性。
- 對未來研究的建議: 文章提出了對于未來研究的建議,包括尋找更快和更有效的表格解析工具,以及處理超出LLM上下文長度的表格內(nèi)容的方法。
實施 RAG 是一項挑戰(zhàn),尤其是在有效解析和理解非結(jié)構(gòu)化文檔中的表格時。這對于掃描文檔或圖像格式的文檔尤其困難。這些挑戰(zhàn)至少有三個方面:
- 掃描文檔或圖像文檔的復(fù)雜性,如結(jié)構(gòu)的多樣性、非文本元素的包含以及手寫和印刷內(nèi)容的結(jié)合,都給自動準(zhǔn)確提取表格信息帶來了挑戰(zhàn)。不準(zhǔn)確的解析會破壞表格結(jié)構(gòu),使用不完整的表格進行嵌入不僅無法捕捉到表格的語義信息,還很容易破壞 RAG 結(jié)果。
- 如何提取表格標(biāo)題并將其有效鏈接到相應(yīng)的表格。
- 如何設(shè)計索引結(jié)構(gòu),以有效存儲表的語義信息。
本文首先介紹了在 RAG 中管理表格的關(guān)鍵技術(shù)。然后,在提出并實施一個新的解決方案之前,回顧了一些現(xiàn)有的開源解決方案。
關(guān)鍵技術(shù)
表格解析(Table Parsing)
該模塊的主要功能是從非結(jié)構(gòu)化文檔或圖像中準(zhǔn)確提取表格結(jié)構(gòu)。最好能提取相應(yīng)的表格標(biāo)題,方便開發(fā)人員將表格標(biāo)題與表格關(guān)聯(lián)起來。
根據(jù)我目前的理解,有幾種方法,如圖 1 所示:
**(a)**利用多模式 LLM(如 GPT-4V)來識別表格,并從每個 PDF 頁面提取信息。
- 輸入:圖像格式的 PDF 頁面
- 輸出:JSON 或其他格式的表格。如果多模態(tài) LLM 無法提取表格數(shù)據(jù),則應(yīng)總結(jié)圖像并返回摘要。
**(b)**利用專業(yè)的表格檢測模型(如 Table Transformer)來識別表格結(jié)構(gòu)。
- 輸入:PDF 頁圖像
- 輸出:表格圖像
**(c)**使用開源框架,如 unstructured 和其他也采用對象檢測模型的框架(本文將詳細介紹 unstructured 的表格檢測過程)。這些框架可以對整個文檔進行全面解析,并從解析結(jié)果中提取與表格相關(guān)的內(nèi)容。
- 輸入:PDF 或圖像格式的文件
- 輸出:從整個文檔的解析結(jié)果中獲得純文本或 HTML 格式的表格
**(d)**使用 Nougat、Donut 等端到端模型解析整個文檔并提取與表格相關(guān)的內(nèi)容。這種方法不需要 OCR 模型。
- 輸入:PDF 或圖像格式的文件
- 輸出:從整個文檔的解析結(jié)果中獲得 LaTeX 或 JSON 格式的表格
值得一提的是,無論使用哪種方法提取表格信息,都應(yīng)包含表格標(biāo)題。這是因為在大多數(shù)情況下,表格標(biāo)題是文檔或論文作者對表格的簡要描述,可以在很大程度上概括整個表格。
在上述四種方法中,(d) 方法可以方便地檢索表格標(biāo)題。這對開發(fā)人員非常有利,因為他們可以將表格標(biāo)題與表格聯(lián)系起來。這一點將在下面的實驗中進一步說明。
索引結(jié)構(gòu)(Index Structure)
根據(jù)指數(shù)的結(jié)構(gòu),解決方案可大致分為以下幾類:
**(e)**只有圖像格式的索引表。
**(f)**只有純文本或 JSON 格式的索引表。
**(g)**只有 LaTeX 格式的索引表。
**(h)**只為表格摘要編制索引。
**(i)**從小到大或文件摘要索引結(jié)構(gòu),如圖 2 所示。
- 小塊內(nèi)容可以是表格中每一行的信息,也可以是表格的摘要。
- 大塊內(nèi)容可以是圖像格式、純文本格式或 LaTeX 格式的表格。
如上所述,表格摘要通常使用 LLM 生成:
- 輸入:圖像格式、文本格式或 LaTeX 格式的表格
- 輸出:表格摘要
不需要表解析、索引或 RAG 的算法
有些算法不需要進行表格解析。
**(j)**向 VQA 模型(如 DAN 等)或多模態(tài) LLM 發(fā)送相關(guān)圖像(PDF 頁)和用戶查詢,并返回答案。
- 要編入索引的內(nèi)容:圖像格式文件
- 發(fā)送給 VQA 模型或多模態(tài) LLM 的內(nèi)容:查詢 + 圖像形式的相應(yīng)頁面
**(k)**向 LLM 發(fā)送相關(guān)文本格式的 PDF 頁面和用戶的查詢,然后返回答案。
- 索引內(nèi)容:文本格式文件
- 發(fā)送到 LLM 的內(nèi)容:查詢 + 文本格式的相應(yīng)頁面
**(l)**向多模態(tài) LLM(如 GPT-4V 等)發(fā)送相關(guān)圖像(PDF 頁面)、文本塊和用戶查詢,并直接返回答案。
- 需要索引的內(nèi)容:圖像格式的文檔和文本格式的文檔塊
- 發(fā)送給多模態(tài) LLM 的內(nèi)容:查詢 + 文檔的相應(yīng)圖像形式 + 相應(yīng)文本塊
此外,下面是一些不需要編制索引的方法,如圖 3 和圖 4 所示:
**(m)**圖3 首先,應(yīng)用(a)至(d)中的一種方法,將文檔中的所有表格解析為圖像形式。然后,將所有表格圖像和用戶的查詢直接發(fā)送到多模態(tài) LLM(如 GPT-4V 等),并返回答案。
- 要索引的內(nèi)容:無
- 發(fā)送至多模態(tài) LLM 的內(nèi)容:查詢 + 所有解析表(圖像格式)
**(n)**圖4 使用(m)提取的圖像格式的表格,然后使用 OCR 模型識別表格中的所有文本,然后直接將表格中的所有文本和用戶的查詢發(fā)送到 LLM,并直接返回答案。
- 要索引的內(nèi)容:無
- 發(fā)送到 LLM 的內(nèi)容:用戶查詢 + 所有表格內(nèi)容(文本格式)
值得注意的是,有些方法并不依賴于 RAG 流程:
- 第一種方法不使用 LLM,在特定數(shù)據(jù)集上進行訓(xùn)練,使模型(如類似 BERT 的轉(zhuǎn)換器)能夠更好地支持表格理解任務(wù),如 TAPAS。
- 第二種方法使用 LLM,采用預(yù)培訓(xùn)、微調(diào)方法或提示,使 LLM 能夠執(zhí)行表格理解任務(wù),如 GPT4Table。
現(xiàn)有開源解決方案
上一節(jié)總結(jié)并歸類了 RAG 中表格的關(guān)鍵技術(shù)。在提出本文實現(xiàn)的解決方案之前,讓我們先來探索一些開源解決方案。
LlamaIndex 提出了四種方法,其中前三種使用多模態(tài)模型。
- 檢索相關(guān)圖像(PDF 頁面)并將其發(fā)送到 GPT-4V 以回復(fù)查詢。
- 將每個 PDF 頁面視為圖像,讓 GPT-4V 對每個頁面進行圖像推理。為圖像推理建立文本向量存儲索引。根據(jù)圖像推理向量存儲查詢答案。
- 使用表格轉(zhuǎn)換器從檢索到的圖像中裁剪表格信息,然后將這些裁剪后的圖像發(fā)送到 GPT-4V 進行查詢響應(yīng)。
- 對裁剪后的表格圖像進行 OCR 識別,并將數(shù)據(jù)發(fā)送到 GPT4/ GPT-3.5 以回答查詢。
根據(jù)本條的分類:
- 第一種方法類似于本文中的(j)類,不需要進行表格解析。然而,結(jié)果表明,即使答案在圖像中,它也無法得出正確答案。
- 第二種方法涉及表格解析,屬于 (a) 類。根據(jù) GPT-4V 返回的結(jié)果,索引內(nèi)容要么是表格內(nèi)容,要么是摘要,這可能對應(yīng)于類別 (f) 或 (h)。這種方法的缺點是,GPT-4V 從圖像中識別表格并提取其內(nèi)容的能力不穩(wěn)定,尤其是當(dāng)圖像包含表格、文本和其他圖像的混合時(這在 PDF 格式中很常見)。
- 第三種方法與(m)類相似,不需要編制索引。
- 第四種方法與(n)類似,也不需要索引。其結(jié)果表明,錯誤答案的產(chǎn)生是由于無法從圖像中提取表格信息。
通過測試發(fā)現(xiàn),第三種方法的整體效果最好。不過,根據(jù)我的測試,第三種方法在檢測表格方面很吃力,更不用說正確合并表格標(biāo)題和表格了。
Langchain 也提出了一些解決方案,Semi-structured RAG 的關(guān)鍵技術(shù)包括
- 表格解析使用非結(jié)構(gòu)化,屬于 ? 類。
- 索引方法是文檔摘要索引,屬于第(i)類,小塊內(nèi)容:表格摘要,大塊內(nèi)容:原始表格內(nèi)容(文本格式)。
如圖 5 所示:
Semi-structured and Multi-modal RAG 提出了三種解決方案,其架構(gòu)如圖 6 所示。
- 方案 1 類似于本文的(l)類。它包括使用多模態(tài)嵌入(如 CLIP)來嵌入圖像和文本,使用相似性搜索來檢索兩者,并將原始圖像和塊傳遞給多模態(tài) LLM 進行答案合成。
- 方案 2 利用多模態(tài) LLM(如 GPT-4V、LLaVA 或 FUYU-8b)從圖像中生成文本摘要。然后,嵌入和檢索文本,并將文本塊傳遞給 LLM 進行答案合成。
- 表格解析使用非結(jié)構(gòu)化,屬于 (d) 類。
- 索引結(jié)構(gòu)為文檔摘要索引(目錄 (i)),小塊內(nèi)容:表格摘要,大塊內(nèi)容:文本格式表格
- 方案 3 使用多模態(tài) LLM(如 GPT-4V、LLaVA 或 FUYU-8b)從圖像中生成文本摘要,然后嵌入并檢索帶有原始圖像引用的圖像摘要(分類 (i)),然后將原始圖像和文本塊傳遞給多模態(tài) LLM 進行答案合成。
建議的解決方案
本文對關(guān)鍵技術(shù)和現(xiàn)有解決方案進行了總結(jié)、分類和討論。在此基礎(chǔ)上,我們提出了以下解決方案,如圖 7 所示。為簡化起見,圖中省略了一些 RAG 模塊,如重新排序和查詢重寫。
- 表格解析:使用 Nougat(catogery (d))。根據(jù)我的測試,它的表格檢測比非結(jié)構(gòu)化(catogery ?)更有效。此外,Nougat 還能很好地提取表格標(biāo)題,非常方便與表格關(guān)聯(lián)。
- 文件摘要索引結(jié)構(gòu)(catogery (i)):小塊內(nèi)容包括表格摘要,大塊內(nèi)容包括 LaTeX 格式的相應(yīng)表格和文本格式的表格標(biāo)題。我們使用multi-vector retriever來實現(xiàn)它。
- 表格摘要獲取方法:將表格和表格標(biāo)題發(fā)送至 LLM 進行匯總。
這種方法的優(yōu)勢在于,它既能高效地解析表格,又能全面考慮表格摘要與表格之間的關(guān)系。它還消除了對多模式 LLM 的需求,從而節(jié)省了成本。
Nougat 的原理
Nougat 是基于 Donut 架構(gòu)開發(fā)的。如圖 8 所示,它通過網(wǎng)絡(luò)隱式識別文本,不需要任何與 OCR 相關(guān)的輸入或模塊。
Nougat’s ability to parse formulas is impressive. 它在解析表格方面也很出色。如圖 9 所示,它可以關(guān)聯(lián)表格標(biāo)題,非常方便:
在我對十幾篇論文的測試中,我發(fā)現(xiàn)表格標(biāo)題總是固定在表格后的一行。這種一致性表明這并非偶然。因此,我們有興趣了解Nougat 是如何實現(xiàn)這一效果的。
鑒于這是一個缺乏中間結(jié)果的端到端模型,它可能在很大程度上依賴于訓(xùn)練數(shù)據(jù)。
根據(jù)訓(xùn)練數(shù)據(jù)的格式化代碼,對于表格而言,緊跟在 \end{table} 之后的一行是 caption_parts,這似乎與所提供的訓(xùn)練數(shù)據(jù)格式一致:
def format_element(element: Element, keep_refs: bool = False, latex_env: bool = False
) -> List[str]:"""Formats a given Element into a list of formatted strings.Args:element (Element): The element to be formatted.keep_refs (bool, optional): Whether to keep references in the formatting. Default is False.latex_env (bool, optional): Whether to use LaTeX environment formatting. Default is False.Returns:List[str]: A list of formatted strings representing the formatted element."""......if isinstance(element, Table):parts = ["[TABLE%s]\n\\begin{table}\n"% (str(uuid4())[:5] if element.id is None else ":" + str(element.id))]parts.extend(format_children(element, keep_refs, latex_env))caption_parts = format_element(element.caption, keep_refs, latex_env)remove_trailing_whitespace(caption_parts)parts.append("\\end{table}\n")if len(caption_parts) > 0:parts.extend(caption_parts + ["\n"])parts.append("[ENDTABLE]\n\n")return parts......
Nougat 的利與弊
優(yōu)勢
- Nougat 可以將以前的解析工具難以解析的部分(如公式和表格)準(zhǔn)確地解析為 LaTeX 源代碼。
- Nougat 的解析結(jié)果是類似于 markdown 的半結(jié)構(gòu)化文檔。
- 輕松獲取表格標(biāo)題,并方便地與表格關(guān)聯(lián)。
缺點
- Nougat 的解析速度較慢,這可能會給大規(guī)模部署帶來挑戰(zhàn)。
- 由于 Nougat 是針對科學(xué)論文進行訓(xùn)練的,因此在處理類似結(jié)構(gòu)的文檔時表現(xiàn)出色。在非拉丁文本文檔中,它的性能會有所下降。
- Nougat 模型每次只對科學(xué)論文的一頁進行訓(xùn)練,缺乏對其他頁面的了解。這可能會導(dǎo)致解析的內(nèi)容不一致。因此,如果識別效果不佳,可以考慮將 PDF 分成單獨的幾頁,然后逐頁進行解析。
- 解析雙欄論文中的表格不如解析單欄論文有效。
代碼執(zhí)行
首先,安裝相關(guān)的 Python 軟件包
pip install langchain
pip install chromadb
pip install 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.1chroma-hnswlib 0.7.3
chromadb 0.4.24nougat-ocr 0.1.17
設(shè)置環(huán)境并導(dǎo)入:
import os
os.environ["OPENAI_API_KEY"] = "YOUR_OPEN_AI_KEY"import subprocess
import uuidfrom langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.storage import InMemoryStore
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
from langchain_core.runnables import RunnablePassthrough
將論文 Attention Is All You Need 下載到 YOUR_PDF_PATH,運行 nougat 來解析 PDF 文件,并從解析結(jié)果中獲取 latex 格式的表格和文本格式的表格標(biāo)題。第一次執(zhí)行將下載必要的模型文件。
def june_run_nougat(file_path, output_dir):# Run Nougat and store results as Mathpix Markdowncmd = ["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.returncodeelse: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 resfile_path = "YOUR_PDF_PATH"
output_dir = "YOUR_OUTPUT_DIR_PATH"if june_run_nougat(file_path, output_dir) == 1:import syssys.exit(1)mmd_path = output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd"
tables = june_get_tables_from_mmd(mmd_path)
函數(shù) june_get_tables_from_mmd
用于從圖 10 所示的 mmd
文件中提取從開始{table}到結(jié)束{table}
的所有內(nèi)容,包括結(jié)束{table}
后面的一行。的所有內(nèi)容,包括圖 10 所示 mmd
文件中 \end{table}
后面的一行。
值得注意的是,目前還沒有官方文件規(guī)定表格標(biāo)題必須放在表格下方,或者表格應(yīng)以 \begin{table}
開始,以 \end{table}
結(jié)束。因此,june_get_tables_from_mmd
是啟發(fā)式的。
以下是解析 PDF 文件中表格的結(jié)果:
Operation Completed!
----------------------------------------------------------------------------------------------------
\begin{table}
\begin{tabular}{l c c c} \hline \hline Layer Type & Complexity per Layer & Sequential Operations & Maximum Path Length \\ \hline Self-Attention & \(O(n^{2}\cdot d)\) & \(O(1)\) & \(O(1)\) \\ Recurrent & \(O(n\cdot d^{2})\) & \(O(n)\) & \(O(n)\) \\ Convolutional & \(O(k\cdot n\cdot d^{2})\) & \(O(1)\) & \(O(log_{k}(n))\) \\ Self-Attention (restricted) & \(O(r\cdot n\cdot d)\) & \(O(1)\) & \(O(n/r)\) \\ \hline \hline \end{tabular}
\end{table}
Table 1: Maximum path lengths, per-layer complexity and minimum number of sequential operations for different layer types. \(n\) is the sequence length, \(d\) is the representation dimension, \(k\) is the kernel size of convolutions and \(r\) the size of the neighborhood in restricted self-attention.----------------------------------------------------------------------------------------------------
\begin{table}
\begin{tabular}{l c c c c} \hline \hline \multirow{2}{*}{Model} & \multicolumn{2}{c}{BLEU} & \multicolumn{2}{c}{Training Cost (FLOPs)} \\ \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 Ensemble [39] & & 40.4 & & \(8.0\cdot 10^{20}\) \\ GNMT + RL Ensemble [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 (base model) & 27.3 & 38.1 & & \(\mathbf{3.3\cdot 10^{18}}\) \\ Transformer (big) & **28.4** & **41.8** & & \(2.3\cdot 10^{19}\) \\ \hline \hline \end{tabular}
\end{table}
Table 2: The Transformer achieves better BLEU scores than previous state-of-the-art models on the English-to-German and English-to-French newstest2014 tests at a fraction of the training cost.----------------------------------------------------------------------------------------------------
\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}}\) & \(h\) & \(d_{k}\) & \(d_{v}\) & \(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 & 25.4 & \\ \hline (B) & \multicolumn{1}{c}{} & & \multicolumn{1}{c}{} & & 16 & & & & & 5.16 & 25.1 & 58 \\ & & & & & 32 & & & & & 5.01 & 25.4 & 60 \\ \hline \multirow{4}{*}{(C)} & 2 & \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}
Table 3: Variations on the Transformer architecture. Unlisted values are identical to those of the base model. All metrics are on the English-to-German translation development set, newstest2013. Listed perplexities are per-wordpiece, according to our byte-pair encoding, and should not be compared to per-word perplexities.----------------------------------------------------------------------------------------------------
\begin{table}
\begin{tabular}{c|c|c} \hline
**Parser** & **Training** & **WSJ 23 F1** \\ \hline Vinyals \& Kaiser et al. (2014) [37] & WSJ only, discriminative & 88.3 \\ Petrov et al. (2006) [29] & WSJ only, discriminative & 90.4 \\ Zhu et al. (2013) [40] & WSJ only, discriminative & 90.4 \\ Dyer et al. (2016) [8] & WSJ only, discriminative & 91.7 \\ \hline Transformer (4 layers) & WSJ only, discriminative & 91.3 \\ \hline Zhu et al. (2013) [40] & semi-supervised & 91.3 \\ Huang \& Harper (2009) [14] & semi-supervised & 91.3 \\ McClosky et al. (2006) [26] & semi-supervised & 92.1 \\ Vinyals \& Kaiser el al. (2014) [37] & semi-supervised & 92.1 \\ \hline Transformer (4 layers) & semi-supervised & 92.7 \\ \hline Luong et al. (2015) [23] & multi-task & 93.0 \\ Dyer et al. (2016) [8] & generative & 93.3 \\ \hline \end{tabular}
\end{table}
Table 4: The Transformer generalizes well to English constituency parsing (Results are on Section 23 of WSJ)* [5] Kyunghyun Cho, Bart van Merrienboer, Caglar Gulcehre, Fethi Bougares, Holger Schwenk, and Yoshua Bengio. Learning phrase representations using rnn encoder-decoder for statistical machine translation. _CoRR_, abs/1406.1078, 2014.
然后使用 LLM 對表格進行匯總:
# Prompt
prompt_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 chain
model = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")
summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()
# Get table summaries
table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})
print(table_summaries)
下面是《Attention Is All You Need》中四個表格的摘要,如圖 11 所示:
使用多向量檢索器構(gòu)建文檔摘要索引結(jié)構(gòu)。
# The vectorstore to use to index the child chunks
vectorstore = Chroma(collection_name = "summaries", embedding_function = OpenAIEmbeddings())# The storage layer for the parent documents
store = 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 tables
table_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)))
一切就緒后,建立一個簡單的 RAG 管道并執(zhí)行查詢:
# Prompt template
template = """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)# LLM
model = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")# Simple RAG pipeline
chain = ({"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
執(zhí)行結(jié)果如下,表明幾個問題都得到了準(zhǔn)確的回答,如圖 12 所示:
整體代碼如下
import os
os.environ["OPENAI_API_KEY"] = "YOUR_OPEN_AI_KEY"import subprocess
import uuidfrom langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.storage import InMemoryStore
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
from langchain_core.runnables import RunnablePassthroughdef june_run_nougat(file_path, output_dir):# Run Nougat and store results as Mathpix Markdowncmd = ["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.returncodeelse: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 resfile_path = "YOUR_PDF_PATH"
output_dir = "YOUR_OUTPUT_DIR_PATH"if june_run_nougat(file_path, output_dir) == 1:import syssys.exit(1)mmd_path = output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd"
tables = june_get_tables_from_mmd(mmd_path)# Prompt
prompt_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 chain
model = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")
summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()
# Get table summaries
table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})
print(table_summaries)# The vectorstore to use to index the child chunks
vectorstore = Chroma(collection_name = "summaries", embedding_function = OpenAIEmbeddings())# The storage layer for the parent documents
store = 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 tables
table_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 template
template = """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)# LLM
model = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")# Simple RAG pipeline
chain = ({"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
結(jié)論
本文討論了 RAG 流程中表格處理的關(guān)鍵技術(shù)和現(xiàn)有解決方案,并提出了一種解決方案及其實施方法。
我們在本文中使用 nougat 來解析表格。不過,如果有更快、更有效的解析工具,我們會考慮替換 nougat。我們對工具的態(tài)度是先有正確的想法,然后再找工具來實現(xiàn)它,而不是依賴于某個工具。
在本文中,我們將所有表格內(nèi)容都輸入到 LLM 中。然而,在實際場景中,我們應(yīng)該考慮到表格超出 LLM 上下文長度的情況。我們可以使用有效的分塊方法來解決這個問題。
本文為翻譯,原文地址:https://ai.plainenglish.io/advanced-rag-07-exploring-rag-for-tables-5c3fc0de7af