前言
之所以写本文,源于以下两点
- 在此文《》的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和文档语义分割、段落分割都是绕不开的关键点,故本文重点梳理下各类典型的语义分割模型
- 一方面,更好的促进我司第三项目组知识库问答项目的进度
- 二方面,把我司在这个方向上的探索、经验一定程度的通过博客分享给大家(更多深入细节则见我司的大模型项目开发线上营)
第一部分 基于BERT的朴素文本切分方法
RAG场景下,目前比较常用的文本切块方法还都是基于策略的,例如大模型应用开发框架提供的RecursiveCharacterTextSplitter方法,定义多级分割符,用上一级切割符分割后的文本块如果还是超过最大长度限制,再用第二级切割符进一步切割
在预训练BERT模型过程中,为了让模型学到两个句子之间的关系,设计了一个二分类任务,同时向BERT中输入两个句子,预测第二个句子是否是第一个句子的下一句。基于这个原理,我们可以设计一种最朴素的文本切分方法,其中最小的切分单位是句子。
在完整的文本上,用滑动窗口的方式分别将相邻的两个句子输入到BERT模型中做二分类,如果预测分值较小,说明这两个句子之间的语义关系比较弱,可以作为一个文本切分点,示意图如下。然而,这种方法判断是否是文本切分点时只考虑了前后各一个句子,没有利用到距离更远位置的文本信息。此外,该方法的预测效率也相对较低。
第二部分 Cross-Segment模型
Lukasik等人在论文《》提出了提出了Cross-Segment模型,该方法充分利用了更长的上下文信息,预测效率也有提升。首先,利用BERT模型分别获取每个句子的向量表示。然后,将连续的多个句子的向量表示同时输入到另一个BERT或LSTM模型中,一次性预测每个句子是否是文本分段的边界。论文提供的示意图如下。
Cross-Segment模型示意图
第三部分 阿里语义分割模型SeqModel
Cross-Segment模型对每个句子进行独立向量化,没有考虑更长的上下文信息,Zhang等人在论文《Sequence Model with Self-Adaptive Sliding Window for Efficient Spoken Document Segmentation》中提出的SeqModel进行了进一步改进。SeqModel利用BERT对多个句子同时编码,建模了更长的上下文之间依赖关系之后再计算句向量,最后预测每个句子后边是否进行文本分割。此外,该模型还使用了自适应滑动窗口方法,在在不牺牲准确性的情况下进一步加快推理速度。SeqModel的示意图如下所示。
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])