【大语言模型】NLP•检索增强生成之二
视频号
微信公众号
知识星球
Chinese, Simplified
- 概述
- 动机
- 神经检索
- 检索增强生成(RAG)流水线
- RAG的好处
- RAG与微调
- RAG合奏
- 使用特征矩阵选择矢量数据库
- 构建RAG管道
- 摄入
- Chucking
- 嵌入
- 句子嵌入:内容和原因
- 背景:与BERT等代币级别模型相比的差异
- 相关:句子转换器的训练过程与令牌级嵌入模型
- 句子变换器在RAG中的应用
- 句子嵌入:内容和原因
- 检索
- 标准/天真的方法
- 优势
- 缺点
- 语句窗口检索/从小到大分块
- 优势
- 缺点
- 自动合并检索器/层次检索器
- 优势
- 缺点
- 计算出理想的块大小
- 寻回器镶嵌和重新排列
- 使用近似最近邻进行检索
- 重新排序
- 标准/天真的方法
- 响应生成/合成
- 迷失在中间:语言模型如何使用长上下文
- “大海捞针”测试
- 摄入
- 组件式评估
- 检索度量
- 上下文精度
- 上下文回忆
- 上下文相关性
- 生成度量
- 脚踏实地
- 回答相关性
- 端到端评估
- 回答语义相似性
- 答案正确性
- 检索度量
- 多模式RAG
- 改进RAG系统
- 相关论文
- 知识密集型NLP任务的检索增强生成
- 主动检索增强生成
- 多模式检索增强生成器
- 假设文档嵌入(HyDE)
- RAGAS:检索增强生成的自动评估
- 微调还是检索?LLM中知识注入的比较
- 密集X检索:我们应该使用什么检索粒度?
- ARES:一种用于检索增强生成系统的自动评估框架
- 引用
构建RAG管道
下图(来源)直观地概述了RAG的三个不同步骤:摄入、检索和合成/反应生成。
在下面的部分中,我们将讨论这些关键领域。
摄入(Ingestion)
Chucking(分块)
- 分块是将提示和/或要检索的文档划分为更小的、可管理的段或块的过程。这些块可以通过固定的大小来定义,例如特定数量的字符、句子或段落。
- 在RAG中,每个块都被编码到嵌入向量中以供检索。更小、更精确的块会导致用户的查询和内容之间更精细的匹配,从而增强检索到的信息的准确性和相关性。
- 较大的块可能包括不相关的信息,从而引入噪声并可能降低检索准确性。通过控制区块大小,RAG可以在全面性和准确性之间保持平衡。
- 因此,接下来自然会出现的问题是,如何为您的用例选择正确的块大小?RAG中块大小的选择至关重要。它需要足够小以确保相关性并减少噪声,但要足够大以保持上下文的完整性。让我们看看下面从Pinecone中引用的几种方法:
- 固定大小的区块划分:只需决定区块中的代币数量,以及它们之间是否应该重叠。块之间的重叠保证了块之间的语义上下文损失最小。这个选项在计算上很便宜,而且实现起来很简单。
text = "..." # your text
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
separator = "\n\n",
chunk_size = 256,
chunk_overlap = 20
)
docs = text_splitter.create_documents([text])
- 上下文感知分块:内容感知分块利用文本的内在结构来创建更有意义和上下文相关性的分块。以下是实现这一目标的几种方法:
- 句子拆分。此方法与为嵌入句子级内容而优化的模型相一致。可以使用不同的工具和技术进行句子拆分:
- 朴素拆分:一种使用句号和换行来拆分句子的基本方法。实例
text = "..." # Your text
docs = text.split(".")
这种方法很快,但可能会忽略复杂的句子结构。
- NLTK(自然语言工具包):一个用于语言处理的综合Python库。NLTK包括一个句子标记器,可以有效地将文本拆分为句子。实例
text = "..." # Your text
from langchain.text_splitter import NLTKTextSplitter
text_splitter = NLTKTextSplitter()
docs = text_splitter.split_text(text)
- spaCy:一个用于NLP任务的高级Python库,spaCy提供了高效的句子分割。实例
text = "..." # Your text
from langchain.text_splitter import SpacyTextSplitter
text_splitter = SpacyTextSplitter()
docs = text_splitter.split_text(text)
- 递归分块:递归分块是一种使用各种分隔符分层分割文本的迭代方法。它适用于通过递归应用不同的标准来创建大小或结构相似的块。例如,使用LangChain:
text = "..." # Your text
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size = 256,
chunk_overlap = 20
)
docs = text_splitter.create_documents([text])
- 专用分块:对于Markdown或LaTeX等格式化内容,可以应用专用分块来保持原始结构:
- Markdown Chunking:识别Markdown语法并根据结构划分内容。实例
from langchain.text_splitter import MarkdownTextSplitter
markdown_text = "..."
markdown_splitter = MarkdownTextSplitter(chunk_size=100, chunk_overlap=0)
docs = markdown_splitter.create_documents([markdown_text])
- LaTeX分块:解析LaTeX命令和环境以分块内容,同时保留其逻辑组织。
“根据经验,如果文本块在没有周围上下文的情况下对人类有意义,那么它对语言模型也有意义。因此,在语料库中找到文档的最佳块大小对于确保搜索结果的准确性和相关性至关重要。”(来源)
嵌入
- 一旦你的提示被适当地分块,下一步就是嵌入它。在RAG中嵌入提示和文档包括将用户的查询(提示)和知识库中的文档转换为一种可以有效比较相关性的格式。这一过程对于RAG响应用户查询从其知识库中检索最相关信息的能力至关重要。以下是它的典型工作方式:
- 帮助选择最适合您任务的嵌入模型的一个选项是查看HuggingFace的海量文本嵌入基准(MTEB)排行榜。。有一个问题是可以使用密集嵌入还是稀疏嵌入,所以让我们看看下面每种嵌入的好处:
- 稀疏嵌入:像TF-IDF这样的稀疏嵌入非常适合在提示和文档之间进行词法匹配。最适合关键字相关性至关重要的应用程序。它的计算强度较低,但可能无法捕捉到文本中更深层次的语义。
- 语义嵌入:语义嵌入,如BERT或句子BERT,自然地适用于RAG用例。
- BERT:适用于捕捉文档和查询中的上下文细微差别。与稀疏嵌入相比,需要更多的计算资源,但提供了语义更丰富的嵌入。
- 句子ERT:非常适合于句子层面的上下文和意义很重要的场景。它在对BERT的深刻上下文理解和对简洁、有意义的句子表达的需求之间取得了平衡。这通常是RAG的首选路线。
句子嵌入:内容和原因
背景:与BERT等代币级别模型相比的差异
- 作为一个概述,让我们看看句子转换器与BERT等令牌级嵌入模型相比有何不同。
- 句子转换器是对传统BERT模型的修改,专门为生成完整句子的嵌入(即句子嵌入)而定制。他们培训方法的主要区别在于:
- 目的:训练BERT来预测一句话中的掩蔽词和下一句话的预测。它是为理解一个句子中的单词及其上下文而优化的。另一方面,句子转换器被专门训练来理解整个句子的含义。它们生成具有相似含义的句子在嵌入空间中接近的嵌入。
- 嵌入级别:主要区别在于嵌入级别。BERT为句子中的每个标记(单词或子单词)提供嵌入,而句子转换器为整个句子提供单个嵌入。
- 训练数据和任务:虽然BERT主要在大型文本语料库上进行训练,任务侧重于理解上下文中的单词,但句子转换器通常在包括句子对的数据集上进行训练。这项培训的重点是相似性和相关性,教模型如何理解和比较整个句子的含义。
- 暹罗和三元组网络结构:句子变换器经常使用暹罗或三元组的网络结构。这些网络包括处理成对或三元组的句子,并调整模型,使相似的句子具有相似的嵌入,而不同的句子具有不同的嵌入。这与BERT的训练不同,后者本质上不涉及单独句子的直接比较。
- 针对特定任务的微调:句子转换器通常针对特定任务进行微调,如语义相似性、转述识别或信息检索。与BERT相比,这种微调更侧重于句子层面的理解,BERT可能会针对更广泛的NLP任务进行微调,如问答、情绪分析等,侧重于单词或短语层面的理解。
- 适用性:BERT和类似模型更适用于需要在标记级别理解的任务(如命名实体识别、问答),而句子转换器更适用于依赖于句子级别理解(如语义搜索、句子相似性)的任务。
- 生成句子嵌入或相似性任务的效率:在标准BERT中,生成句子嵌入通常涉及将其中一个隐藏层(通常是第一个标记[CLS])的输出作为整个句子的表示。然而,对于句子级别的任务,这种方法并不总是最优的。句子转换器经过专门优化,可以生成更有意义和有用的句子嵌入,因此对于涉及句子相似性计算的任务更有效。由于它们为每个句子生成一个向量,因此与令牌级模型相比,计算句子之间的相似性得分在计算上不那么密集。
- 总之,虽然BERT是一种专注于单词级上下文的通用语言理解模型,但句子转换器专门用于理解和比较整个句子的含义,使其更有效地执行需要句子级语义理解的任务。
相关:句子转换器的训练过程与令牌级嵌入模型
- 让我们来看看与BERT等令牌级嵌入模型相比,句子转换器是如何以不同的方式进行训练的。
- 句子转换器被训练为在句子级别生成嵌入,这是一种与BERT等令牌级别嵌入模型不同的方法。以下是他们的培训概述,以及它与代币级别模型的区别:
- 模型架构:句子转换器通常从类似于BERT或其他转换器架构的基本模型开始。然而,重点是为整个输入句子输出单个嵌入向量,而不是单个标记。
- 训练数据:它们在各种数据集上进行训练,通常包括已知句子之间关系(如相似性、转述)的成对或成组句子。
- 训练目标:BERT是在掩蔽语言建模(预测缺失单词)和下一句预测等目标上进行预训练的,这些目标侧重于在表征水平上理解上下文。另一方面,句子转换器是专门训练来理解句子层面的上下文和关系的。他们的训练目标通常是最小化语义相似句子的嵌入之间的距离,同时最大化不相似句子的插入之间的距离。这是通过对比损失函数实现的,如三元组损失、余弦相似性损失等。
- 输出表示:在BERT中,句子级表示通常来源于特殊令牌的嵌入(如[CLS])或通过池化令牌嵌入(以及平均、MaxPooling或串联它们)。句子转换器被设计为直接输出有意义的句子级表示。
- 下游任务的微调:句子转换器可以在特定任务上进行微调,例如语义文本相似性,在这些任务中,模型学习生成嵌入,捕捉整个句子的细微含义。
- 总之,句子转换器专门针对在句子级别生成表示进行了优化,侧重于捕捉句子的整体语义,这使得它们在涉及句子相似性和聚类的任务中特别有用。这与BERT等标记级别模型形成了对比,其更侧重于在更广泛的上下文中理解和表示单个令牌的含义。
句子变换器在RAG中的应用
- 现在,让我们来看看为什么句子转换器是生成RAG嵌入的首选模型。
- RAG利用句子转换器来理解和比较句子的语义内容。这种集成在模型需要在生成响应之前检索相关信息的场景中特别有用。以下是句子转换器在RAG设置中的作用:
- 改进的文档检索:句子转换器经过训练,可以生成捕捉句子语义的嵌入。在RAG设置中,这些嵌入可以用于将查询(如用户的问题)与数据库中最相关的文档或段落进行匹配。这是至关重要的,因为生成的响应的质量通常取决于检索到的信息的相关性。
- 高效的语义搜索:传统的基于关键字的搜索方法可能难以理解查询的上下文或语义细微差别。句子转换器通过提供语义上有意义的嵌入,实现了超越关键字匹配的更细微的搜索。这意味着RAG的检索组件可以找到与查询语义相关的文档,即使它们不包含确切的关键字。
- 上下文理解以获得更好的响应:通过使用句子转换器,RAG模型可以更好地理解输入查询和潜在源文档内容的上下文和细微差别。这导致了更准确、更适合上下文的响应,因为模型的生成组件有更相关、更容易理解的信息可供使用。
- 信息检索中的可伸缩性:句子转换器可以通过预计算所有文档的嵌入来有效地处理大型文档数据库。这使得检索过程更快、更具可扩展性,因为模型只需要在运行时计算查询的嵌入,然后快速找到最接近的文档嵌入。
- 增强生成过程:在RAG设置中,生成组件受益于检索组件提供相关的、语义丰富的信息的能力。这使得语言模型生成的响应不仅在上下文上准确,而且比模型本身所训练的信息范围更广。
- 总之,句子转换器通过实现更有效的信息语义搜索和检索,增强了具有LLM的RAG模型的检索能力。这提高了需要理解和基于大量文本数据生成响应的任务的性能,如问答、聊天机器人和信息提取。
本文地址
https://architect.pub/nlp-retrieval-augmented-generation-part2
- 15 次浏览
SEO Title
NLP • Retrieval Augmented Generation : part2