本文为我参加Datawhale AI夏令营第三期:科大讯飞AI大赛(多模态RAG方向)Task3的学习笔记,该方向对应“iFLYTEK AI 开发者大赛”中“多模态RAG图文问答挑战赛”赛题,Datawhale提供了ModelScope版GitHub版的Baseline代码仓库,在此感谢教程作者!

在Task2中,我已经对Baseline做了少量修改,详见:Task2学习笔记

在此基础上,我使用mineru_pipeline_all.py代替fitz_pipeline_all.py,这样不仅能提取PDF文件中的文本,还能提取图表信息,从源头上提升知识库的质量。在此过程中也遇到了一些问题。

在ModelScope Notebook中持久化存储Conda环境

因为电脑配置不够,我是在ModelScope的Notebook上运行的代码,在安装MinerU时,MinerU所依赖的包版本与ModelScope Notebook自带的包版本发生了冲突,于是需要新建一个环境。考虑到用MinerU解析PDF时间较长,很难在ModelScope Notebook所给的单次实例最大运行时间10小时内运行完毕,所以环境需要持久化存储,这里我参考了ModelScope提供的文档配置和使用Conda环境,使得开发环境配置能够在ModelScope Notebook不同的实例间得到延续。

下面给出主要代码,可以一行一行复制到Terminal中粘贴后回车运行,有几行回车运行后有安装过程提示,按照提示输入a(表示accept)后回车,或者输入y(表示yes)后回车,或者直接回车就行。

安装Conda,新建环境,安装所需要的库:

# 下载安装包
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

# 添加执行权限
chmod +x Miniconda3-latest-Linux-x86_64.sh

# 安装到/mnt/worksapce/miniconda3目录下
bash Miniconda3-latest-Linux-x86_64.sh -b -p /mnt/workspace/miniconda3

# 初始化
/mnt/workspace/miniconda3/bin/conda init

# 在此之后需要重新打开一个Terminal

# 创建新环境(以 Python 3.11.11 为例)
conda create --name myenv python=3.11.11

# 激活环境
conda activate myenv

# 安装所需要的库
pip install -r requirements.txt

这里的myenv是环境名,可以取一个别的名字,Python版本也可以自行选取。

 退出环境:

conda deactivate

在实例关闭后,重新打开新的实例,需要恢复之前新建的环境时:

# 初始化
/mnt/workspace/miniconda3/bin/conda init

# 在此之后需要重新打开一个Terminal

# 激活环境
conda activate myenv

之后运行mineru_pipeline_all.py就没出现版本问题了,不过因为我使用的是CPU环境,运行时间较长,将所有文件解析完成估计需要20小时,所以中途实例会因超时而关闭,需要在关闭后重新打开新的实例,继续运行。

运行完成后再运行rag_from_page_chunks.py文件,获得提交文件,提交后分数相对于使用PyMuPDF解析的反而略有降低,这或许是因为解析出来的图表信息反而引入了更多噪声。

引入重排

为了减少噪声,提高检索质量,我尝试在检索环节后增加一个重排步骤,选出最相关的几个结果,提高给大语言模型的文本质量。

具体来说,我先用向量检索召回一个Top 20的较宽泛的候选集,把相关的都找出来,再用BAAI/bge-reranker-large模型对这20个候选项进行打分排序,然后选出分数最高的5个。将这Top 5作为最终大模型的输入,提高了信噪比。

不同于教程中使用FlagEmbedding中的FlagReranker,我使用的是sentence_transformers中的CrossEncoder。

主要代码:

class Reranker:
    """
    使用 Cross-Encoder 对召回结果做重排
    """
    def __init__(self, model_name_or_path, max_length):
        self.model = CrossEncoder(model_name_or_path, max_length=max_length)

    def rerank(self, query: str, passages: List[str], top_k: int = 5) -> List[int]:
        """
        返回排序后前 top_k 的索引
        """
        pairs = [(query, p) for p in passages]
        scores = self.model.predict(pairs)
        ranked_indices = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)
        return ranked_indices[:top_k]

该操作有效减少了噪声,MinerU解析PDF取得的最终结果文件相对于PyMuPDF分数略有提高。

未来计划

虽然夏令营即将结束,但是比赛在8月25日17:00才结束,调整方案的时间仍然足够。在未来,我打算加入反思重写,改变Top K中K的值,改变三个模型,观察是否能够提高分数。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐