一文掌握文本语义分割:从朴素切分、Cross-Segment到阿里SeqModel
前言
之所以写本文,源于以下两点
- 在此文《基于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中,具体而言
- 当用BERT编码每个句子时,所有序列都以[CLS]标记开始
如果分割决定是在句子级别sentence level做出的(例如,文档分割document segmentation),我们使用[CLS]token作为LSTM的输入
在分词决策是在词级word level做出的情况下(例如,话语分词discourse segmentation),我们获得BERT的完整序列输出,并使用每个词的最左边的词段作为LSTM的输入(use the left-most word-piece of each word as an input to LSTM)
需要注意的是,在话语分割(discourse segmentation)任务中,由于上下文较短,可以仅使用一次BERT进行完全编码(Note that,due to the context being short for the discourse seg-mentation task, it is fully encoded in a single passusing BERT. );
或者可以独立地对每个单词进行编码。考虑到许多单词由single word-piece组成,使用深度transformer编码器来对它们进行编码可能会比较费计算资源,毕竟transformer的计算成本(特别是自注意力)随着输入长度呈二次增长
故在使用这个模型的时候,一般将BERT的输入减少到最大句子大小为64个token,以减少训练和推理时间 - 然后,LSTM负责处理具有线性计算复杂度的多样化和潜在的大型句子序列(Then, the LSTM isresponsible for handling the diverse and potentiallylarge sequence of sentences with linear computa-tional complexity)。在实践中,我们将最大文档长度设定为128个句子,更长的文档会被分割成连续且非重叠的128个句子块,并作为独立的文档进行处理
// 待更
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 Tasks
p = pipeline(
task=Tasks.document_segmentation,
model='damo/nlp_bert_document-segmentation_chinese-base')
result = p(documents='......')
print(result[OutputKeys.TEXT])
这就是本文前言中所说的阿里开源的语义分割模型了呐
// 待更..