Late Chunking×Milvus:如何提高RAG准确率

news2024/11/6 21:25:12

a08e7d6538cf8e9dcd3e7b41a8a4f65a.png

bc6b0a51ecec2d2e6a695808628b856d.png

01.

背景

在RAG应用开发中,第一步就是对于文档进行chunking(分块),高效的文档分块,可以有效的提高后续的召回内容的准确性。而对于如何高效的分块是个讨论的热点,有诸如固定大小分块,随机大小分块,滑动窗口重新采样,递归分块,基于内容语义分块等方法。而Jina AI提出的Late Chunking从另外一个角度来处理分块问题,让我们来具体看看。

02.

Late Chunking是什么

传统的分块在处理长文档时可能会丢失文档中长距离的上下文依赖关系,这对于信息检索和理解是一大隐患。即当关键信息散落在多个文本块中,脱离上下文的文本分块片段很可能失去其原有的意义,导致后续的召回效果比较差。

以Milvus 2.4.13 release note为例,假如分为如下两个文档块,如果我们要查询Milvus 2.4.13有哪些新功能?,直接相关内容在分块2里,而Milvus版本信息在分块1里,此时,Embedding 模型很难将这些指代正确链接到实体,从而产生质量不高的Embedding。

0ba5b5387e94376a38b9856e89cfd366.png

由于功能描述与版本信息不在同一个分块里,且缺乏更大的上下文文档,LLM 难以解决这样的关联问题。尽管有一些启发式算法试图缓解这一问题,如滑动窗口重新采样、重叠的上下文窗口长度以及多次文档扫描等,然而,像所有启发式算法一样,这些方法时灵时不灵,它们可能在某些情况下有效,但是没有理论上的保证。

传统的分块采用一种预先分块的策略,即先分块,再过 Embedding 模型。首先依据句子、段落或预设的最大长度等参数对文本进行切割。然后Embedding 模型会对这些分块逐一进行处理,通过平均池化等方法,将 token 级的 Embedding 聚合成单一的块 Embedding 向量。而Late Chunking则是先过 Embedding 模型再分块(late的含义就是在于此,先向量化再分块),我们先将 Embedding 模型的 transformer 层应用到整个文本,为每个 token 生成一个包含丰富上下文信息的向量表示序列。然后,再对这些 token 向量序列进行平均池化,最终得到考虑了整个文本上下文的块 Embedding。

9b73787186a59c3873f5410a9afc50a7.png

(图片来源:https://jina.ai/news/late-chunking-in-long-context-embedding-models/)

Late Chunking生成的块Embedding,每个块都编码了更多的上下文信息,从而提高了编码的质量和准确性。我们可以通过支持长上下文的 Embedding 模型,如 jina-embeddings-v2-base-en,它能够处理长达8192个token 的文本(相当于 10 页 A4 纸),基本满足了大多数长文本的上下文需求。

综上所述,我们可以看到Late Chunking在RAG应用中的优势:

  • 提高准确性:通过保留上下文信息,与简单分块相比,Late Chunking为查询返回了相关度更高的内容。

  • 高效的LLM调用:Late Chunking可以减少传递给LLM的文本量,因为它返回的分块更少且相关度更高。

03.

测试Late Chunking

3.1. Late Chunking基础实现

函数sentence_chunker对于原始文档以段落进行分块,返回分块内容以及分块标记信息span_annotations(即分块的开始和结束标记)

def sentence_chunker(document, batch_size=10000):
    nlp = spacy.blank("en")
    nlp.add_pipe("sentencizer", config={"punct_chars": None})
    doc = nlp(document)

    docs = []
    for i in range(0, len(document), batch_size):
        batch = document[i : i + batch_size]
        docs.append(nlp(batch))

    doc = Doc.from_docs(docs)

    span_annotations = []
    chunks = []
    for i, sent in enumerate(doc.sents):
        span_annotations.append((sent.start, sent.end))
        chunks.append(sent.text)

    return chunks, span_annotations

函数 document_to_token_embeddings 通过模型 jinaai/jina-embeddings-v2-base-en 的模型以及tokenizer,返回整个文档的Embedding。

def document_to_token_embeddings(model, tokenizer, document, batch_size=4096):
    tokenized_document = tokenizer(document, return_tensors="pt")
    tokens = tokenized_document.tokens()

    outputs = []
    for i in range(0, len(tokens), batch_size):
        
        start = i
        end   = min(i + batch_size, len(tokens))

        batch_inputs = {k: v[:, start:end] for k, v in tokenized_document.items()}

        with torch.no_grad():
            model_output = model(**batch_inputs)

        outputs.append(model_output.last_hidden_state)

    model_output = torch.cat(outputs, dim=1)
    return model_output

函数 late_chunking 对整个文档的Embedding以及原始分块的标记信息span_annotations进行分块。

def late_chunking(token_embeddings, span_annotation, max_length=None):
    outputs = []
    for embeddings, annotations in zip(token_embeddings, span_annotation):
        if (
            max_length is not None
        ):
            annotations = [
                (start, min(end, max_length - 1))
                for (start, end) in annotations
                if start < (max_length - 1)
            ]
        pooled_embeddings = []
        for start, end in annotations:
            if (end - start) >= 1:
                pooled_embeddings.append(
                    embeddings[start:end].sum(dim=0) / (end - start)
                )
                    
        pooled_embeddings = [
            embedding.detach().cpu().numpy() for embedding in pooled_embeddings
        ]
        outputs.append(pooled_embeddings)

    return outputs

如使用模型jinaai/jina-embeddings-v2-base-en进行Late Chunking

tokenizer = AutoTokenizer.from_pretrained('jinaai/jina-embeddings-v2-base-en', trust_remote_code=True)
model     = AutoModel.from_pretrained('jinaai/jina-embeddings-v2-base-en', trust_remote_code=True)

# First chunk the text as normal, to obtain the beginning and end points of the chunks.
chunks, span_annotations = sentence_chunker(document)
# Then embed the full document.
token_embeddings = document_to_token_embeddings(model, tokenizer, document)
# Then perform the late chunking
chunk_embeddings = late_chunking(token_embeddings, [span_annotations])[0]

3.2. 与传统Embedding方法对比

我们以milvus 2.4.13 release note 这一段内容为例,

Milvus 2.4.13 introduces dynamic replica load, allowing users to adjust the number of collection replicas without needing to release and reload the collection.

This version also addresses several critical bugs related to bulk importing, expression parsing, load balancing, and failure recovery.

Additionally, significant improvements have been made to MMAP resource usage and import performance, enhancing overall system efficiency.

We highly recommend upgrading to this release for better performance and stability.

分别进行传统Embedding,即先分块,然后进行Embedding。以及Late Chunking方式Embedding,即先Embedding,然后再分块。然后,把 milvus 2.4.13 分别与这两种Embedding方式的结果进行对比

cos_sim = lambda x, y: np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y))

milvus_embedding = model.encode('milvus 2.4.13')

for chunk, late_chunking_embedding, traditional_embedding in zip(chunks, chunk_embeddings, embeddings_traditional_chunking):
    print(f'similarity_late_chunking("milvus 2.4.13", "{chunk}")')
    print('late_chunking: ', cos_sim(milvus_embedding, late_chunking_embedding))
    print(f'similarity_traditional("milvus 2.4.13", "{chunk}")')
    print('traditional_chunking: ', cos_sim(milvus_embedding, traditional_embeddings))

从结果来看,词语 milvus 2.4.13 与分块文档Late Chunking结果相似度高于传统Embedding。原因是Late Chunking先对于全部文本段落进行Embedding,使得整个文本段落得到了 milvus 2.4.13 信息,进而在后续的文本比较中显著的提高了相似度。

similarity_late_chunking("milvus 2.4.13", "Milvus 2.4.13 introduces dynamic replica load, allowing users to adjust the number of collection replicas without needing to release and reload the collection.")
late_chunking: 0.8785206
similarity_traditional("milvus 2.4.13", "Milvus 2.4.13 introduces dynamic replica load, allowing users to adjust the number of collection replicas without needing to release and reload the collection.")
traditional_chunking: 0.8354263

similarity_late_chunking("milvus 2.4.13", "This version also addresses several critical bugs related to bulk importing, expression parsing, load balancing, and failure recovery.")
late_chunking: 0.84828955
similarity_traditional("milvus 2.4.13", "This version also addresses several critical bugs related to bulk importing, expression parsing, load balancing, and failure recovery.")
traditional_chunking: 0.7222632

similarity_late_chunking("milvus 2.4.13", "Additionally, significant improvements have been made to MMAP resource usage and import performance, enhancing overall system efficiency.")
late_chunking: 0.84942204
similarity_traditional("milvus 2.4.13", "Additionally, significant improvements have been made to MMAP resource usage and import performance, enhancing overall system efficiency.")
traditional_chunking: 0.6907381

similarity_late_chunking("milvus 2.4.13", "We highly recommend upgrading to this release for better performance and stability.")
late_chunking: 0.85431844
similarity_traditional("milvus 2.4.13", "We highly recommend upgrading to this release for better performance and stability.")
traditional_chunking: 0.71859795

3.3. Milvus中测试Late Chunking

导入Late Chunking数据到Milvus

batch_data=[]
for i in range(len(chunks)):
    data = {
            "content": chunks[i],
            "embedding": chunk_embeddings[i].tolist(),
        }

    batch_data.append(data)

res = client.insert(
    collection_name=collection,
    data=batch_data,
)

查询测试

我们定义cosine相似度查询方法,以及使用Milvus原生查询方法分别对于Late Chunking进行查询。

def late_chunking_query_by_milvus(query, top_k = 3):
    query_vector = model(**tokenizer(query, return_tensors="pt")).last_hidden_state.mean(1).detach().cpu().numpy().flatten()

    res = client.search(
                collection_name=collection,
                data=[query_vector.tolist()],
                limit=top_k,
                output_fields=["id", "content"],
            )

    return [item.get("entity").get("content") for items in res for item in items]

def late_chunking_query_by_cosine_sim(query, k = 3):
    cos_sim = lambda x, y: np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y))
    query_vector = model(**tokenizer(query, return_tensors="pt")).last_hidden_state.mean(1).detach().cpu().numpy().flatten()

    results = np.empty(len(chunk_embeddings))
    for i, (chunk, embedding) in enumerate(zip(chunks, chunk_embeddings)):
        results[i] = cos_sim(query_vector, embedding)

    results_order = results.argsort()[::-1]
    return np.array(chunks)[results_order].tolist()[:k]

从结果来看,两个方法返回内容是一致的,这表明Milvus中对于Late Chunking查询结果是准确。

> late_chunking_query_by_milvus("What are new features in milvus 2.4.13", 3)

['\n\n### Features\n\n- Dynamic replica adjustment for loaded collections ([#36417](https://github.com/milvus-io/milvus/pull/36417))\n- Sparse vector MMAP in growing segment types ([#36565](https://github.com/milvus-io/milvus/pull/36565))...
> late_chunking_query_by_cosine_sim("What are new features in milvus 2.4.13", 3)

['\n\n### Features\n\n- Dynamic replica adjustment for loaded collections ([#36417](https://github.com/milvus-io/milvus/pull/36417))\n- Sparse vector MMAP in growing segment types ([#36565](https://github.com/milvus-io/milvus/pull/36565))...

04.

总结

我们介绍了Late Chunking产生的背景,基本概念以及基础实现,然后通过在Mivlus测试发现,Late Chunking效果不错。总体来看,Late Chunking在准确性、效率和易于实施方面的结合,使其成为RAG应用的一个有效的方法。

参考文档:

  • https://stackoverflow.blog/2024/06/06/breaking-up-is-hard-to-do-chunking-in-rag-applications

  • https://jina.ai/news/late-chunking-in-long-context-embedding-models/

  • https://jina.ai/news/what-late-chunking-really-is-and-what-its-not-part-ii/

示例代码:

链接: https://pan.baidu.com/s/1cYNfZTTXd7RwjnjPFylReg?pwd=1234 提取码: 1234

代码在 aws g4dn.xlarge 机器上运行

作者介绍

3c2c4e21c504e468d0b29116615688df.jpeg

Milvus 黄金写手:臧伟


2024年非结构化数据峰会的报名通道现已开启!

作为备受瞩目的年度重磅盛会,本次大会以“数绘万象,智联八方”为主题,邀请广大AI产业伙伴,从生态构建、客户案例、技术前瞻、商业化落地等多个角度共同研讨智能化的新未来。

如果您对AI产业化落地充满热情,渴望加入这场智慧的盛宴,请移步至文章末尾,扫描二维码即刻报名参与!

5507e16736f2536a4093dbc6a45789bd.jpeg

62dcbab4e8f279cc23fc138ffe9a79a5.png

a8ca4a6e794a5df9d962a1d2585d3650.png

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

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

相关文章

大屏可视化:舞动数据与美观的“设计秘籍”

大屏可视化鉴赏&#xff1a;踏入软件系统产品设计之旅&#xff0c;让我们一同鉴赏那些闪耀在智慧农业、智慧园区、智慧社区及智慧港口等领域的大屏可视化杰作。每一帧画面&#xff0c;都是科技与创新的完美融合&#xff0c;数据跃然屏上&#xff0c;智慧触手可及。 >> 数…

基于STM32的智能声音跟随小车设计

引言 本项目基于STM32微控制器设计了一个智能声音跟随小车&#xff0c;通过集成麦克风阵列实现声音源定位和跟随功能。该系统可以检测环境中的声音信号&#xff0c;如手掌拍击声或语音指令&#xff0c;驱动小车向声源方向移动。项目涉及硬件设计、声音信号处理算法以及电机控制…

Bruno解决SSL验证问题

在测试接口的时候&#xff0c;我使用的是Bruno这个软件&#xff0c;开源离线的API测试软件。 主页是这样子的 今天在测试一个HTTPS的接口时候&#xff0c;因为这个HTTPS接口是用的是自签证书&#xff0c;所以就报错误了。 Error invoking remote method send-http-request: …

【论文速读】| APOLLO:一种基于 GPT 的用于检测钓鱼邮件并生成警告用户的解释的工具

基本信息 原文标题&#xff1a;APOLLO: A GPT-based tool to detect phishing emails and generate explanations that warn users 原文作者&#xff1a;Giuseppe Desolda, Francesco Greco, Luca Vigan 作者单位&#xff1a;University of Bari “A. Moro”, Italy, King’…

jfrog artifactory oss社区版,不支持php composer私库

一、docker安装 安装环境&#xff1a;centos操作系统&#xff0c;root用户。 如果是mac或ubuntu等操作系统的话&#xff0c;会有许多安装的坑等着你。 一切都是徒劳&#xff0c;安装折腾那么久&#xff0c;最后还是不能使用。这就是写本文的初衷&#xff0c;切勿入坑就对了。 …

WindowsDocker安装到D盘,C盘太占用空间了。

Windows安装 Docker Desktop的时候,默认位置是安装在C盘,使用Docker下载的镜像文件也是保存在C盘,如果对Docker使用评率比较高的小伙伴,可能C盘空间,会被耗尽,有没有一种办法可以将Docker安装到其它磁盘,同时Docker的数据文件也保存在其他磁盘呢? 答案是有的,我们可以…

vue常见题型(1-10)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 2.2双向绑定的原理是什么vue框架采用的是数据双向绑定的方式&#xff0c;由三个重要部分构成2.2.1.ViewModel2.2.2 双向绑定2.2.3.1.编译Compile2.2.3.2.依赖收集 3…

python怎么将字符串转换为数字

python如何将列表中的字符串转为数字&#xff1f;具体方法如下&#xff1a; 有一个数字字符的列表&#xff1a; numbers [1, 5, 10, 8] 想要把每个元素转换为数字&#xff1a; numbers [1, 5, 10, 8] 用一个循环来解决&#xff1a; new_numbers []; for n in numbers:new_n…

大数据新视界 -- 大数据大厂之 Impala 性能优化:解锁大数据分析的速度密码(上)(1/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

Flutter 插件 sliding_up_panel 实现从底部滑出的面板

前言 sliding_up_panel 是一个 Flutter 插件&#xff0c;用于实现从底部滑出的面板。它在设计上非常灵活&#xff0c;能够适应多种 UI 场景&#xff0c;比如从底部滑出的菜单、可拖动的弹出面板等。以下是 sliding_up_panel 的详细用法&#xff0c;包括常用的参数说明和示例代…

大客户营销数字销售实战讲师培训讲师唐兴通专家人工智能大模型销售客户开发AI大数据挑战式销售顾问式销售专业销售向高层销售业绩增长创新

唐兴通 销售增长策略专家、数字销售实战导师 专注帮助企业构建面向AI数字时代新销售体系&#xff0c;擅长运用数字化工具重塑销售流程&#xff0c;提升销售业绩。作为《挑战式销售》译者&#xff0c;将全球顶尖销售理论大师马修狄克逊等理论导入中国销售业界。 核心专长&…

es数据同步(仅供自己参考)

数据同步的问题分析&#xff1a; 当MySQL进行增删改查的时候&#xff0c;数据库的数据有所改变&#xff0c;这个时候需要修改es中的索引库的值&#xff0c;这个时候就涉及到了数据同步的问题 解决方法&#xff1a; 1、同步方法&#xff1a; 当服务对MySQL进行增删改的时候&…

入门车载以太网(3) -- 网络层

目录 1. 网络通信示例 2. IP地址类别 3. IP数据报 4. 小结 今天继续车载以太网&#xff0c;聊聊网络层。 1. 网络通信示例 我们首先回顾车载以太网的数据传输模型。 从7层开始(车载以太网模糊了5-7层&#xff0c;统称应用层)&#xff0c;每个中间层都为上层提供功能&…

六个核桃斥资千万研究脑健康,核桃健脑作用科学具象化了

健康&#xff0c;是这两年热度居高不下的社会话题。对健康的追求影响了诸多领域的发展&#xff0c;上至尖端科研&#xff0c;下至日常接触的食品饮料&#xff0c;都已被卷入大势。 其中&#xff0c;“脑健康”这个听起来更前沿的话题&#xff0c;又已经成为格外重要的一个领域…

基于Multisim光控夜灯LED电路(含仿真和报告)

【全套资料.zip】光控夜灯LED电路设计Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 1.采用纯数字电路&#xff0c;非单片机。 2.通过检测周围光线&#xff0c;光线暗且有声音时自动开灯…

【go从零单排】go中的基本数据类型和变量

Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 基本类型 go中的string、int、folat都可以用连接boolen可以用逻辑表达式计算 package mainimport "fmt&quo…

前端学习笔记—Vue3特性

一、 Vue3与Vite构建工具简介 image.png image.png image.png image.png Vite构建工具&#xff08;其他的打包工具有webpack&#xff0c;grunt&#xff0c;gulp&#xff09; image.png image.png 构建 二、创建Vue3项目 vite在TypeScript结合使用上&#xff0c;直接开箱即用&am…

DICOM标准:DICOM图像核心属性概念详解——关于参考帧、病人位置、病人方位、图像位置和图像方向、切片位置、图像像素等重要概念解析

目录 1、参考帧模块属性 2、模态(Modality): 3、病人位置(Patient Position): 4、 病人方位(Patient Orientation): 5、 图像位置和图像方向: 6、切片位置 7、图像像素模块 7.1 图像像素属性描述 7.1.1 每个像素的样本 7.1.2 光度解释 7.1.3 平面结构 7.1.…

短视频矩阵系统的源码, OEM贴牌源码

针对矩阵短视频系统的源码功能设计&#xff0c;我们开发设计了以下核心模块&#xff1a; 1. 短视频一键发布功能&#xff1a;允许用户快速、便捷地发布短视频内容 2. 批量图文剪辑&#xff1a;支持同时编辑和处理多张图片与文本的组合&#xff0c;提高编辑效率 3. 批量剪辑短…

6款IntelliJ IDEA插件,让Spring和Java开发如虎添翼

文章目录 1、SonarLint2、JRebel for IntelliJ3、SwaggerHub插件4、Lombok插件5、RestfulTool插件6、 Json2Pojo插件7、结论 对于任何Spring Boot开发者来说&#xff0c;两个首要的目标是最大限度地提高工作效率和确保高质量代码。IntelliJ IDEA 是目前最广泛使用的集成开发环境…