Advanced RAG 07:在RAG系统中进行表格数据处理的新思路

编者按: 目前,检索增强生成(RAG)系统成为了将海量知识赋能于大模型的关键技术之一。然而,如何高效地处理半结构化和非结构化数据,尤其是文档中的表格数据,仍然是 RAG 系统面临的一大难题。

本文作者针对这一痛点,提出了一种处理表格数据的新颖解决方案。作者首先系统性地梳理了RAG系统中表格处理的核心技术,包括表格解析、索引结构设计等,并评述了现有的一些开源解决方案。在此基础上,作者提出了自己的创新之处——利用Nougat工具准确高效地解析文档中的表格内容,使用语言模型对表格及其标题进行内容摘要,最后构建一种新型的document summary索引结构,并给出了完整的代码实现细节。

这种方法的优点是既能有效解析表格,又能全面考虑表格摘要与表格之间的关系,且无须使用多模态 LLM ,能够节省解析成本。让我们拭目以待该方案在实践中的进一步应用和发展。

作者 | Florian June

编译 | 岳扬

RAG 系统的实现是一项极具挑战性的任务,特别是需要解析和理解非结构化文档中的表格时。而对于经过扫描操作数字化的文档(scanned documents)或图像格式的文档(documents in image format)来说,实现这些操作就更加困难了。至少有三个方面的挑战:

  • 经过扫描操作数字化的文档(scanned documents)或图像格式的文档(documents in image format)比较复杂,如文档结构的多样性、文档中可能包含一些非文本元素(non-text elements)以及文档中可能同时存在手写和印刷内容,都会为表格信息的准确自动化提取带来挑战。不准确的文档解析会破坏表格结构,将不完整的表格信息转换为向量表征(embedding)不仅无法有效捕捉表格的语义信息,还很容易导致 RAG 的最终输出结果出现问题。
  • 如何提取每个表格的标题,如何将它们与对应的那个具体表格关联起来。
  • 如何通过合理的索引结构设计,将表格中的关键语义信息高效组织和存储起来。

本文首先介绍了如何在检索增强生成(Retrieval Augmented Generation, RAG)模型中管理和处理表格数据。然后回顾了一些现有的开源解决方案,最后在当前的技术基础上,设计和实现了一种新颖的表格数据管理方法。

01 RAG表格数据相关核心技术介绍

1.1 Table Parsing 表格数据的解析

该模块的主要功能是从非结构化文档或图像中准确提取表格结构(table structure)。

附加需求: 最好能提取出相应的表格标题,方便开发人员将表格标题与表格关联起来。

根据我目前的理解,有以下几种方法,如图 1 所示:

图 1:Table parser(表格解析器)。图片由原文作者提供。

(a).  利用多模态LLM(如GPT-4V[1])识别表格,并从每个 PDF 页面中提取信息。

  • 输入:图像格式的 PDF 页面
  • 输出:JSON或其他格式的表格数据。如果多模态 LLM 无法提取表格数据,则应对 PDF 图像进行总结并返回内容摘要。

(b). 利用专业的表格检测模型(如Table Transformer[2])来识别表格结构。

  • 输入:PDF 页面图像
  • 输出:表格图像

©.  使用开源框架,如 unstructured[3] 或其他也采用目标检测模型(object detection models)的框架(这篇文章[4]详细介绍了 unstructured 的表格检测过程)。这些框架可以对整个文档进行全面解析,并从解析结果中提取与表格相关的内容。

  • 输入:PDF或图像格式的文档
  • 输出:纯文本或 HTML 格式的表格(从整个文档的解析结果中获得)

(d).  使用 Nougat[5]、Donut[6] 等端到端模型(end-to-end models),解析整个文档并提取与表格相关的内容。这种方法不需要 OCR 模型。

  • 输入:PDF 或图像格式的文档
  • 输出:LaTeX 或 JSON 格式的表格(从整个文档的解析结果中获得)

需要说明的是,无论使用哪种方法提取表格信息,都应同时提取出表格标题。因为在大多数情况下,表格标题是文档作者或论文作者对表格的简要描述,可以在很大程度上概括整个表格的内容。

在上述四种方法中,方法(d)可以较为方便地检索表格标题。 这对开发人员来说大有裨益,因为他们可以将表格标题与表格关联起来。下面的实验将对此作进一步说明。

1.2 Index Structure 如何索引表格数据

大致有以下几类建立索引的方法:

(e).  只为图像格式的表格建立索引。

(f).  只为纯文本或JSON格式的表格建立索引。

(g).  只为LaTeX格式的表格建立索引。

(h).  只为表格的摘要建立索引。

(i).  Small-to-big(译者注:既包含细粒度索引,比如对每一行或表格摘要建立索引,也包含粗粒度索引,比如索引整个表格的图像、纯文本或 LaTeX 类型数据,形成一种分层的、从小到大的索引结构。) 或使用表格摘要建立索引结构,如图2所示。

The content of the small chunk(译者注:细粒度索引层级对应的数据块)比如将表格的每一行或摘要信息作为一个独立的小数据块。

The content of the big chunk(译者注:粗粒度索引层级对应的数据块)可能是图像格式、纯文本格式或LaTeX格式的整个表格。

图 2:以 small-to-big 的方式建立索引(上)和使用表格摘要建立索引(中、下)。图片由原文作者提供。

如上所述,表格摘要通常是使用 LLM 处理生成的:

  • 输入:图像格式、文本格式或 LaTeX 格式的表格
  • 输出:表格摘要

1.3 无需解析表格、建立索引或使用 RAG 技术的方法

有些算法不需要进行表格数据的解析。

(j).  将相关图像(PDF文档页)和用户的 query 发送给 VQA 模型(如 DAN[7] 等)(译者注:视觉问答(Visual Question Answering)模型的简称。是一种结合了计算机视觉和自然语言处理技术的模型,可用于回答关于图像内容的自然语言问题。)或多模态 LLM,并返回答案。

  • 要被索引的内容: 图像格式的文档
  • 发送给 VQA 模型或多模态 LLM 的内容:Query + 图像形式的相应文档页面

(k).  向 LLM 发送相关文本格式的 PDF 页面和用户的 query ,然后返回答案。

  • 要被索引的内容: 文本格式文档
  • 发送给 LLM 的内容:Query + 文本格式的相应文档页面

(l).  向多模态 LLM(如 GPT-4V 等)发送相关文档图像(PDF 文档页面)、文本块和用户的 Query,然后直接返回答案。

  • 要被索引的内容: 图像格式的文档和文本格式的文档块(document chunks)
  • 发送给多模态 LLM 的内容:Query + 相应图像格式的文档 + 相应文本块(text chunks)

此外,下面还有一些不需要建立索引的方法,如图 3 和图 4 所示:

图 3:Category (m)(译者注:下面第一段介绍的内容)。图片由原文作者提供。

(m).  首先,使用(a)至(d)中的任何一种方法,将文档中的所有表格解析为图像形式。然后,将所有表格图像和用户的 query 直接发送给多模态 LLM(如 GPT-4V 等),并返回答案。

  • 要被索引的内容: 无
  • 发送给多模态 LLM 的内容:Query + 所有已经转换为图像格式的表格

图 4:Ctegory (n)(译者注:下面第一段介绍的内容)。图片由原文作者提供。

(n).  使用通过(m)方法提取到的图像格式的表格,然后使用 OCR 模型识别表格中的所有文本,然后直接将表格中的所有文本和用户的 Query 发送到 LLM,并直接返回答案。

  • 需要索引的内容: 无
  • 发送给 LLM 的内容:用户的 Query + 所有表格内容(以文本格式发送)

值得注意的是,在处理文档中的表格时,有些方法并没有使用 RAG(Retrieval-Augmented Generation)技术:

  • 第一类方法没有使用 LLM,而是在特定数据集上进行训练,使得 AI 模型(如基于 Transformer 架构并受到 BERT 启发的其他语言模型)来更好地支持表格理解任务的处理,比如 TAPAS [8]。
  • 第二类方法是使用 LLM,采用预训练、微调方法或提示词工程,使得 LLM 能够完成表格理解任务,如 GPT4Table[9]。

02 现有的表格处理开源解决方案

上一节总结并归类了 RAG 系统中表格数据处理的关键技术。在提出本文要实现的解决方案之前,我们先来探索一些开源解决方案。

LlamaIndex 提出了四种方法[10],其中前三种均使用了多模态模型(multimodal models)。

  • 检索相关的PDF 页面图像并将其发送给 GPT-4V 响应用户 Query 。
  • 将每个 PDF 页面均转换为图像格式,让 GPT-4V 对每个页面进行图像推理(image reasoning)。为图像推理过程建立 Text Vector Store index(译者注:将从图像中推理出的文本信息转换成向量形式,并建立索引),然后根据 Image Reasoning Vector Store(译者注:应当就是前面的索引,对前文建立的 Text Vector Store index 进行查询。) 查询答案。
  • 使用 Table Transformer 从检索到的图像中裁剪表格信息,然后将这些裁剪后的表格图像发送到 GPT-4V 获取 query responses (译者注:向模型发送 Query 并获取模型返回的答案)。
  • 在裁剪后的表格图像上应用 OCR,并将数据发送给 GPT4/ GPT-3.5 来回答用户的 query 。

总结一下上述四种方法:

  • 第一种方法类似于本文中介绍的(j)方法,不需要进行表格解析。但结果表明,即使答案就在图像中,也无法产生正确答案。
  • 第二种方法涉及到表格的解析,对应于方法(a)。索引内容可能是表格内容或内容摘要,完全取决于 GPT-4V 返回的结果,可能对应于方法 (f) 或 (h)。这种方法的缺点是,GPT-4V 从文档图像中识别表格并提取其内容的能力不稳定,尤其是当文档图像中包含表格、文本和其他图像(在 PDF 文档中这种情况很常见)时。
  • 第三种方法与方法(m)类似,不需要编制索引。
  • 第四种方法与方法(n)相似,也不需要编制索引。其结果表明,产生错误答案的原因是无法从图像中有效提取表格信息。

通过进行测试发现,第三种方法的整体效果最好。不过,根据我进行的测试,第三种方法在检测表格这方面就很吃力,更不用说正确提取并关联合并表格标题和表格内容了。

Langchain 也对半结构化数据的 RAG(Semi-structured RAG)[11] 技术提出了一些解决方案,核心技术包括:

  • 使用 unstructured 进行表格解析,这属于(c)类方法。
  • 索引方法是 document summary index (译者注:将文档摘要信息作为索引内容),属于(i)类方法。细粒度索引层级对应的数据块:表格摘要内容,粗粒度索引层级对应的数据块:原始表格内容(文本格式)。

如图 5 所示:

图 5 :Langchain 的 Semi-structured RAG 方案 。Source: Semi-structured RAG[11]

Semi-structured and Multi-modal RAG[12] 提出了三种解决方案,其架构如图 6 所示。

图 6:Langchain 的 semi-structured and multi-modal RAG 方案。Source: Semi-structured and Multi-modal RAG[12].

Option 1 类似于前文的方法(l)。这种方法涉及使用多模态嵌入(multimodal embeddings)(如CLIP[13]),将图像和文本转换为嵌入向量,然后使用相似性搜索算法(similarity search)检索两者,并将未经处理的图像和文本数据传递给多模态 LLM ,让它们一起处理并生成问题答案。

Option 2 利用多模态 LLM (如 GPT-4V[14] 、LLaVA[15] 或 FUYU-8b[16]),处理图像生成文本摘要(text summaries)。然后,将文本数据转换为嵌入向量,再使用这些向量来搜索或检索与用户提出的 Query 相匹配的文本内容,并将这些文本内容传递给 LLM 生成答案。

  • 表格数据的解析使用 unstructured,属于(d)类方法。
  • 索引方法是 document summary index (译者注:将文档摘要信息作为索引内容),属于(i)类方法,细粒度索引层级对应的数据块:表格摘要内容,粗粒度索引层级对应的数据块:文本格式的表格内容。

Option 3 使用多模态 LLM (如 GPT-4V[14] 、LLaVA[15] 或 FUYU-8b[16])从图像数据中生成文本摘要,然后将这些文本摘要嵌入向量化,利用这些嵌入向量,可以对图像摘要进行高效检索(retrieve),在检索到的每个图像摘要中,都保留有一个对应的原始图像的引用(reference to the raw image),这属于上文的 (i) 类方法,最后将未经处理的图像数据和文本块传递给多模态 LLM 以便生成答案。

03 本文提出的解决方案

前文对关键技术和现有解决方案进行了总结、分类和讨论。在此基础上,我们提出了以下解决方案,如图 7 所示。为简化起见,图中省略了一些 RAG 模块,如 Re-ranking 和 query rewriting 。

图 7:本文提出的解决方案。图片由原文作者提供。

  • 表格解析技术:使用 Nougat ( (d) 类方法)。 根据我的测试,这种工具的表格检测能力比 unstructured( © 类技术)更有效。此外,Nougat 还能很好地提取表格标题,非常方便与表格进行关联。
  • 用于索引和检索文档摘要的索引结构( (i) 类方法): 细粒度索引层级对应的内容包括表格内容摘要,粗粒度索引层级对应的内容包括 LaTeX 格式的相应表格和文本格式的表格标题。我们使用 multi-vector retriever[17] (译者注:一种用于检索文档摘要索引中内容的检索器,该检索器可以同时处理多个向量,以便有效地检索与 Query 相关的文档摘要。)来实现。
  • 表格内容摘要的获取方法:  将表格和表格标题发送给 LLM 进行内容摘要。

这种方法的优点是既能有效解析表格,又能全面考虑表格摘要与表格之间的关系。省去了使用多模态 LLM 的需求,从而节省了成本。

3.1 Nougat 的工作原理

Nougat[18] 基于 Donut[19] 架构开发,这种方法使用的算法能够在没有任何与 OCR 相关的输入或模块的情况下,通过隐式的方式自动识别文本。

图 8 :遵循 Donut[19] 的端到端架构(End-to-end architecture)。 Swin Transformer 编码器接收文档图像并将其转换为 latent embeddings (译者注:在一个潜在空间中编码了图像的信息),然后以自回归的方式将其转换为一系列 tokens 。来源:Nougat: Neural Optical Understanding for Academic Documents.[18]

Nougat 在解析公式方面的能力令人印象深刻[20],但它解析表格的能力也非常出色。如图 9 所示,它可以关联表格标题,非常方便:

图 9 :Nougat 的运行结果,结果文件为 Mathpix Markdown 格式(可通过 vscode 插件打开),表格以 LaTeX 格式呈现。

在我对十几篇论文进行的一项测试中,我发现表格标题总是固定在表格的下一行。这种一致性表明这并非偶然。因此,我们比较感兴趣 Nougat 是如何实现这种功能的。

鉴于这是一个缺乏中间结果的端到端模型,它的效果很可能严重依赖于其训练数据。

根据代码分析,表格标题部分的存储位置和方式,似乎与训练数据中表格的组织格式是相符的(紧随 \end{table} 之后就是 caption_parts )。

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......

3.2 Nougat 的优点和缺点

优点:

  • Nougat 可以将以前的解析工具难以解析的部分(如公式和表格)准确地解析为 LaTeX 源代码。
  • Nougat 的解析结果是一种类似于 Markdown 的半结构化文档。
  • 能够轻松获取表格标题,并方便地与表格进行关联。

缺点:

  • Nougat 的解析速度较慢,这一点可能会在大规模应用时造成困难。
  • 由于 Nougat 的训练数据集基本上都是科学论文,因此在具有类似结构的文档上这种技术表现出色。而在处理非拉丁文本文档时,其性能就会下降。
  • Nougat 模型每一次只训练一篇科学论文的一页,缺乏对其他页面的了解。这可能会导致解析内容中存在一些前后不一致的现象。因此,如果识别效果不佳,可以考虑将 PDF 分成单独的几页,然后逐页进行解析。
  • 双栏论文(two-column papers)中的表格解析不如单栏论文(single-column papers)的解析效果好。

3.3 代码实现

首先,安装相关的 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

建立工作环境并导入软件包:

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》[21] 下载到路径 YOUR_PDF_PATH,运行 nougat 来解析 PDF 文件,并从解析结果中获取 latex 格式的表格数据和文本格式的表格标题。第一次执行该程序会下载必要的模型文件到本地环境。

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)

函数 june_get_tables_from_mmd 用于从一个 mmd 文件中提取所有内容(从 \begin{table} 到 \end{table},还包括 \end{table} 后的第一行),如图10所示。

图 10:Nougat 的运行结果,结果文件为 Mathpix Markdown 格式(可通过 vscode 插件打开),解析出来的表格内容为 latex 格式。函数 june_get_tables_from_mmd 的功能是提取红框中的表格信息。图片由原文作者提供。

不过,目前还没有官方文件规定表格标题必须放在表格下方,或者表格应以 \begin{table} 开始,以 \end{table} 结束。因此,june_get_tables_from_mmd 是一种启发式的方法(heuristic)。

以下是对 PDF 文档的表格解析结果:

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》[21]中四个表格的内容摘要,如图11所示:

图 11:《Attention Is All You Need》[21]中四个表格的内容摘要。

使用 Multi-Vector Retriever (译者注:一种用于检索文档摘要索引中内容的检索器,该检索器可以同时处理多个向量,以便有效地检索与 Query 相关的文档摘要。)构建 document summary index structure [17](译者注:一种索引结构,用于存储文档的摘要信息,并可根据需要检索或查询这些摘要信息)。

# 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 pipeline 并执行用户的 queries :

# 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

运行结果如下,这几个问题都得到了准确的回答,如图 12 所示:

图 12 :对三个用户 queries 的回答结果。第一行对应于《Attention Is All You Need》中的表 1,第二行对应于表 2,第三行对应于表 4。

总体代码如下:

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

04 Conclusion

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

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

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

Thanks for reading!

——

Florian June

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

END

参考资料

[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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/12666.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中国仓储物流装备产业链上最全产品资料大全(目前238家公司产品资料……)...

导语 大家好,我是社长,老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 知识星球【智能仓储物流技术研习社】内已经收录了如下中国230多家仓储物流装备和技术相关产业链的公司的产品手册,请星球会员…

好文推荐:基于热红外的双源能量平衡(TSEB)模型--从植物到全球尺度的蒸散诊断简史

文献 近日,美国农业部农业研究服务局(USDA-ARS)的科学家们发表了一篇重要的研究论文——“Agricultural and Forest Meteorology” (https://www.sciencedirect.com/journal/agricultural-and-forest-meteorology)&…

智慧公厕系统:改变“上厕所”体验的科技革新

公共厕所是城市建设中不可或缺的基础设施,然而,由于较为落后的管理模式,会常常存在着管理不到位、脏乱差的问题。为了改善公厕的使用体验,智慧公厕系统应运而生,并逐渐成为智慧城市建设的重要组成部分。本文将以智慧公…

AI工具如何简化日常生活?从论文到PPT,AI助手大集合

AI助手大集合,猛戳进来! 在工作和生活中,我经常使用各种各样的人工智能工具,如AI写作软件、AI语音助手、AI绘图工具等。我发现,这些工具能够极大地提高工作效率并简化日常生活。作为一名AI工具的忠实爱好者&#xff0…

Python爬虫——如何使用urllib的HTTP基本库

怎样通过 urllib库 发送 HTTP 请求? urllib库主要由四个模块组成: urllib.request 打开和读取 URLurllib.error 包含 urllib.request 抛出的异常urllib.parse 用于解析 URLurllib.robotparser 用于解析 robots.txt 文件 1. 使用urllib.parse解析URL 使用urlparse(…

【3dmax笔记】022:文件合并、导入、导出

文章目录 一、合并二、导入三、导出四、注意事项一、合并 只能合并 max 文件(高版本能够合并低版本模型,低版本不能合并高版本的模型)。点击【文件】→【导入】→【合并】: 选择要合并的文件,后缀名为3dmax默认的格式,max文件。 二、导入 点击【文件】→【导入】→【导…

【ZYNQ】Vivado 封装自定义 IP

在 FPGA 开发设计中,IP 核的使用通常是不可缺少的。FPGA IP 核是指一些已经过验证的、可重用的模块或者组件,可以帮助构建更加复杂的系统。本文主要介绍如何使用 Vivado 创建与封装用户自定义 IP 核,并使用创建的 IP 核进行串口回环测试。 目…

为什么只有const-static-枚举/整型才可以类内初始化

在C中,静态数据成员(static member)是类的所有对象共享的一个变量。由于它们不是与类的任何特定对象实例相关联的,因此不能在类的构造函数中初始化它们。静态数据成员的初始化必须在类定义之外进行,除非它们满足特定的…

谷歌I/O 2024大会全面硬刚OpenAI

🦉 AI新闻 🚀 谷歌发布升级版Gemini机器人 竞争OpenAI ChatGPT-4 摘要:谷歌展示了升级版的 Gemini 聊天机器人,其支持实时处理视频和语音输入,并准确回答问题。此次发布时机与 OpenAI 公布 ChatGPT-4o 新模型几乎同步…

pycharm导入项目,创建虚拟环境,下载依赖

1、安装conda,此处省略 2、管理员身份打开CMD命令行,创建虚拟环境 conda create --name env_name python3.7 -y 其中,env_name替换为自己想要的环境名字,python3.7表示指定python版本为3.7,-y意味着遇到询问直接回复…

Redis经典问题:BigKey问题

大家好,我是小米,今天来和大家聊聊Redis中的一个经典问题:BigKey问题。在互联网系统中,我们经常需要保存大量的用户数据,比如用户的个人信息、粉丝列表、发表的微博内容等等。这些数据往往会被存储在Redis这样的缓存系统中,以提高系统的性能和响应速度。但是,在处理这些…

什么样的开放式耳机好用舒服?五款高人气质量绝佳产品力荐!

​随着人们越来越注重个人的身体健康问题,掀起了一股运动浪潮,现在大家都会喜欢跑跑步,运动一下使自己的身体更好,那么在运动时候如果能有音乐听的话,人们的运动状态就能达到更好的水平。鉴于传统入耳式耳机给用户带来…

基于梯度流的扩散映射卡尔曼滤波算法的信号预处理matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 扩散映射(Diffusion Maps) 4.2 卡尔曼滤波 4.3 基于梯度流的扩散映射卡尔曼滤波(GFDMKF) 5.完整程序 1.程序功能描述 基于梯度流的扩散…

一文全解聚碳酸酯PC材料在汽车灯罩制造中的诸多显著优势!汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

聚碳酸酯PC材料在汽车灯罩制造中具有诸多显著优势。除了优异的抗冲击性、透明性、耐热性和稳定性外,还有以下一些重要优势: 出色的光学性能:PC材料的光学性能优异,能够确保灯罩内的光源均匀分布,减少光斑和眩光&#…

从0到1,百亿级任务调度平台的架构与实现

尼恩:百亿级海量任务调度平台起源 在40岁老架构师 尼恩的读者交流群(50)中,经常性的指导小伙伴们改造简历。 经过尼恩的改造之后,很多小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试机会&#x…

软件库V1.5版本iApp源码V3

软件库V1.5版本iApp源码V3 配置教程在【mian.iyu】的【载入事件】 更新内容: 1、分类对接蓝奏(免费,付费,会员,广告),支持蓝奏文件描述设置为简介(改动:首页.iyu&#…

Pikachu 靶场 SQL 注入通关解析

前言 Pikachu靶场是一种常见的网络安全训练平台,用于模拟真实世界中的网络攻击和防御场景。它提供了一系列的实验室环境,供安全专业人士、学生和爱好者练习和测试他们的技能。 Pikachu靶场的目的是帮助用户了解和掌握网络攻击的原理和技术,…

【美团面试2024/05/14】前端面试题滑动窗口

一、题目描述 设有一字符串序列 s&#xff0c;确定该序列中最长的无重复字母的子序列&#xff0c;并返回其长度。 备注 0 < s.length < 5 * 104 s 由英文字母、数字、符号和空格组成 示例1 输入 s "abcabcbb" 输出 3 二、原题链接 这道题在LeetCode上的原题链…

场景文本检测识别学习 day09(SSM、S4、Mamba、S6)

SSM&#xff08;State Space Model&#xff09; SSM是一个针对连续函数的模型&#xff0c;即输入是连续函数&#xff0c;输出也是连续函数。上图为状态方程和输出方程&#xff0c;其中h(t)是当前时刻的状态&#xff0c;x(t)是当前时刻的输入&#xff0c;h’(t)是下一个时刻的状…

训练集、测试集与验证集:机器学习模型评估的基石

在机器学习中&#xff0c;为了评估模型的性能&#xff0c;我们通常会将数据集划分为训练集&#xff08;Training Set&#xff09;、验证集&#xff08;Validation Set&#xff09;和测试集&#xff08;Test Set&#xff09;。这种划分有助于我们更好地理解模型在不同数据上的表…