前言
之所以写本文,源于以下两点
- 在此文《基于LangChain+LLM的本地知识库问答:从企业单文档问答到批量文档问答》的3.5节中,我们曾分析过langchain-chatchat项目中文本分割相关的代码,当时曾提到该项目中的文档语义分割模型为达摩院开源的:nlp_bert_document-segmentation_chinese-base (这是其论文)
- 在此文《知识库问答LangChain+LLM的二次开发:商用时的典型问题及其改进方案》中,我们再次提到,langchain-chatchat的默认分块大小是chunk_size:250 (详见configs/model_config.py,但该系统也有个可选项,可以选择达摩院开源的语义分割模型:nlp_bert_document-segmentation_chinese-base)
考虑到在RAG中,embedding和文档语义分割、段落分割都是绕不开的关键点,故本文重点梳理下各类典型的语义分割模型
- 一方面,更好的促进我司第三项目组知识库问答项目的进度
- 二方面,把我司在这个方向上的探索、经验一定程度的通过博客分享给大家(更多深入细节则见我司的大模型项目开发线上营)
第一部分 基于Cross Segment Attention的文本分割
RAG场景下,目前比较常用的文本切块方法还都是基于策略的,例如大模型应用开发框架提供的RecursiveCharacterTextSplitter方法,定义多级分割符,用上一级切割符分割后的文本块如果还是超过最大长度限制,再用第二级切割符进一步切割
Lukasik等人在论文《Text Segmentation by Cross Segment Attention》提出了三种基于transformer的分割模型架构。其中一种仅利用每个候选断点(candidate break)周围的局部上下文,而另外两种则利用来自输入的完整上下文(所谓候选断点指任何潜在的段边界,即any potential segment boundary)
1.1 Cross-segment BERT
分割模型旨在完成文档分割任务,以预测每个句子是否是文本分段的边界。
在 Cross-segment BERT模型中,我们将围绕潜在段落断点的局部上下文输入到模型中:左边k个标记和右边k个标记。
啥意思呢,其实很简单
在预训练BERT模型过程中,为了让模型学到两个句子之间的关系,设计了一个二分类任务,同时向BERT中输入两个句子,预测第二个句子是否是第一个句子的下一句。基于这个原理,我们可以设计一种最朴素的文本切分方法,其中最小的切分单位是句子。
在完整的文本上,用滑动窗口的方式分别将相邻的两个句子输入到BERT模型中做二分类,如果预测分值较小,说明这两个句子之间的语义关系比较弱,可以作为一个文本切分点,示意图如下。然而,这种方法判断是否是文本切分点时只考虑了前后各一个句子,没有利用到距离更远位置的文本信息。此外,该方法的预测效率也相对较低(下图:图源)
1.2 BERT+Bi-LSTM
在BERT+Bi-LSTM模型中,我们首先使用BERT对每个句子进行编码,然后将句子表示输入到Bi-LSTM中
的
1.3 Hierarchical BERT
而在分层BERT模型中,我们首先使用BERT对每个句子进行编码,然后将输出的句子表示输入到基于Transformer的另一个模型中
第二部分 阿里语义分割模型SeqModel
Cross-Segment模型对每个句子进行独立向量化,没有考虑更长的上下文信息,Zhang等人在论文《Sequence Model with Self-Adaptive Sliding Window for Efficient Spoken Document Segmentation》中提出的SeqModel进行了进一步改进
- SeqModel利用BERT对多个句子同时编码,建模了更长的上下文之间依赖关系之后再计算句向量,最后预测每个句子后边是否进行文本分割
- 此外,该模型还使用了自适应滑动窗口方法,在在不牺牲准确性的情况下进一步加快推理速度
SeqModel的示意图如下所示
SeqModel模型权重已公开在魔搭社区上,支持中文,地址为:https://modelscope.cn/models/damo/nlp_bert_document-segmentation_chinese-base/summary,可通过如下代码使用:
from modelscope.outputs import OutputKeys
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasksp = pipeline(task=Tasks.document_segmentation,model='damo/nlp_bert_document-segmentation_chinese-base')result = p(documents='......')
print(result[OutputKeys.TEXT])
这就是本文前言中所说的阿里开源的语义分割模型了呐
参考文献与推荐阅读
- 检索增强生成(RAG)有什么好的优化方案?