MMRAG(Multi-Modal Retrieval-Augmented Generation)是一个基于多模态大模型的文物检索与问答系统。该系统结合了图像识别、文本检索、向量数据库等技术,能够:
- 📸 智能图片问答:上传文物图片,系统自动识别并回答相关问题
- 🔍 多模态检索:支持图像和文本的联合检索
- 📚 知识库构建:从原始数据到可用知识库的完整构建流程
- 🧠 模型微调:包含Chinese-CLIP和Qwen-VL的微调流程
- 🎨 可视化界面:基于Gradio的友好Web界面
MMRAG/
├── README.md # 项目说明文档
├── requirements.txt # Python依赖
├── UI.py # 主界面启动文件
├── globals.py # 全局配置和模型管理
├── chat_page.py # 聊天界面组件
├── card_page.py # 卡片界面组件
│
├── part_1_1_crawler_baidu_images.py # 百度图片爬虫
├── part_1_2_merge_original_and_baidu.py # 数据合并
├── part_1_3_generate_descriptions.py # AI图片描述生成
│
├── part_2_1_processor_retrieval_train_data.py # 训练数据处理
├── part_2_2_build_lmdb_dataset.py # LMDB数据集构建
├── part_2_3_chinese_clip_trainer.py # Chinese-CLIP训练
│
├── part_3_1_milvus_util.py # Milvus工具类
├── part_3_2_text_chunk.py # 文本语义分块
├── part_3_3_text_embeddings.py # 文本向量化
├── part_3_4_image_embeddings.py # 图像向量化
│
├── part_4_1_split_question.py # 问答数据预处理
├── part_4_2_PEFT.py # LoRA微调
│
├── dataset/ # 数据集目录
│ ├── original/ # 原始数据
│ ├── baidu_download_images/ # 百度爬取图片
│ ├── cleaned_dataset/ # 清洗后数据
│ ├── final/ # 最终数据
│ | ├── chunks # 文本分块
│ | ├── images # 整合后的所有图片
│ | └── dataxxx.json # 格式化数据
│ ├── chinese_clip_format/ # CLIP训练格式
│ └── finetuning/ # 微调数据
│
├── model_cache/ # 模型缓存
├── clip_finetune/ # CLIP微调输出
├── milvus_db/ # Milvus数据库
└── fonts/ # 字体文件
- GPU: NVIDIA GPU (推荐24GB+显存)
- RAM: 32GB+ 系统内存
- 存储: 100GB+ 可用空间
- Python: 3.10
- CUDA: 12.4
- 操作系统: Linux
# 克隆项目
git clone <repository-url>
cd MMRAG
# 创建虚拟环境
conda create -n mmrag python=3.10
conda activate mmrag
# 安装 torch
pip install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 --index-url https://download.pytorch.org/whl/cu124
# 安装其他依赖
pip install transformers==4.53.1 scikit-image==0.24.0 scikit-learn==1.5.1 matplotlib==3.9.2 accelerate==1.9.0 qwen-vl-utils[decord] jupyter==1.1.1 cn_clip==1.5.1 fake_useragent==2.2.0 pymilvus==2.5.14 gradio==5.39.0 peft==0.16.0 openai==1.97.0 swanlab==0.6.7 datasets==4.0.0Qwen系列模型会自动下载
CN-CLIP模型在这里下载
# 启动Web界面
python UI.py访问 http://localhost:7860 即可使用系统。
从河南博物院官网爬取数据并整理成结构化格式。 共整理274个文物的数据,每条数据包含id、名称、材质、年代、[出土地]、图片、相关描述等字段。并且基于这些元信息和相关描述来整理问答数据对。
整理后的格式如下:
{
"artifact_id": "artifact008",
"name": "汉镂孔云纹铜染炉",
"alias": [],
"images": [
"58ee3d6d55fbb2fbd1997e003f5001a94623dc1d.jpg"
],
"description": "汉镂孔云纹铜染炉,温食器。现存高11.3厘米,宽10厘米,长17厘米。现藏河南博物院...",
"category": "青铜质",
"era": "汉代",
"origin": "",
"keywords": [
"鼎形温食器",
"青铜质",
"染食法"
],
"questions": [
{
"question": "汉镂孔云纹铜染炉的现存尺寸及收藏地点是哪里?",
"answer": "高11.3厘米,宽10厘米,长17厘米,现藏河南博物院。"
}
// 省略...
]
}python part_1_1_crawler_baidu_images.py- 功能:为现有文物数据爬取更多相关图片
- 输出:
dataset/baidu_download_images/ - 特点:支持自动去重、多线程下载、异常处理
python part_1_2_merge_original_and_baidu.py- 功能:合并原始数据和百度爬取的图片
- 输出:
dataset/final/ - 包含:图片重命名、统计报告、数据验证
# 生成所有图片描述(覆盖模式)
python part_1_3_generate_descriptions.py --overwrite
# 仅处理未标注图片
python part_1_3_generate_descriptions.py- 模型:Qwen2.5-VL-7B-Instruct
- 功能:为每张文物图片生成结构化描述
- 输出格式:JSON文件中的image_descriptions字段
dataset_info.ipynb 中统计了数据集的基本信息如下:
相关描述长度
Total artifacts: 274
Total images: 1617
Average images per artifact: 5.90
Max images for a single artifact: 16
Min images for a single artifact: 1
Total questions: 5138
Average description length: 4643.57
Max description length: 14660
Min description length: 110
朝代信息统计
Era counts: {'唐代': 39, '汉代': 48, '商代': 22, '南北朝': 18, '春秋时期': 18, '清代': 14, '宋代': 27, '西周': 19, '金代': 5, '未知': 15, '明代': 13, '夏代': 3, '隋代': 12, '战国': 8, '新石器时代': 3, '民国': 1, '辽代': 1, '三国时期': 2, '现代': 1, '秦朝': 1, '元代': 2, '西晋': 2}
各类型文物数量
Category counts: {'石质': 56, '陶质': 59, '青铜质': 61, '瓷质': 36, '玉质': 19, '木质': 9, '银质': 6, '绢地': 5, '金质': 6, '木制': 1, '土遗址': 1, '纸质': 7, '琉璃器': 1, '铁质': 1, '甲骨简牍': 2, '服饰': 1, '骨质': 2, '壁画': 1}
图片数量统计
Total images: 1617
Average images per artifact: 5.90
Max images for a single artifact: 16
Min images for a single artifact: 1
python part_2_1_processor_retrieval_train_data.py- 功能:将文物数据转换为Chinese-CLIP训练格式
- 输出:imgs.tsv、texts.jsonl、训练/验证集划分
- 格式:一图一文本配对
python part_2_2_build_lmdb_dataset.py --data_dir dataset/chinese_clip_format --splits train,valid- 功能:将标准格式数据转换为高效的LMDB格式
- 优势:大幅提升训练时的数据加载速度
python part_2_3_chinese_clip_trainer.py \
--train-data dataset/chinese_clip_format/lmdb/train \
--val-data dataset/chinese_clip_format/lmdb/valid \
--batch-size 32 \
--lr 5e-5 \
--max-epochs 10 \
--use-augment- 模型架构:ViT-B-16 + RoBERTa-wwm-ext-base-chinese
- 训练特性:支持梯度累积、断点恢复、自动保存最佳模型
- 输出:
clip_finetune/checkpoints/best.pt
语义分块(Semantic Chunking)是指将一段文本按照语义相关性进行分割,使每个分块都能表达一个相对完整的语义单元。这个过程在自然语言处理、信息检索、RAG(Retrieval-Augmented Generation)等任务中非常重要,尤其是在构建知识库、向量数据库或做文本检索时。
语义分块的主要过程如下:
-
句子分割:首先将输入文本分割成句子列表。按照句号、问号、感叹号等标点符号进行分割,并且去除句子中的空格。
-
生成上下文感知文本:对每个句子,构造以该句为中心、包含前后一定数量(由 buffer_size 控制)句子的上下文文本,形成新的文本列表。
-
获取嵌入向量:对上述每个上下文文本,计算其语义嵌入向量。
-
计算语义距离:依次计算相邻嵌入向量之间的余弦距离,得到距离序列。
-
识别断点:根据设定的断点识别方法(如百分位、标准差、四分位距或梯度),在距离序列中选出若干断点索引。
-
合并成块:按断点索引将句子列表切分为若干块。若某块长度超过最大限制,则优先在块中间的句号结尾处递归切分,使分块更均匀。
-
返回结果:返回所有分块文本,以及包含句子、距离、断点等信息的调试数据。
举例说明:
假设有一段博物馆文物介绍文本,先分句,然后用嵌入模型计算每句之间的语义相似度,当相似度低于某阈值时,认为语义发生了变化,进行分块。每个分块都能独立表达一个文物的相关信息。
python part_3_2_text_chunk.py- 模型:Qwen/Qwen3-Embedding-8B
- 算法:基于语义相似度的智能分块
- 输出:
chunks/目录下的分块文本文件
python part_3_3_text_embeddings.py- 功能:将文本分块转换为向量并存入Milvus
- 模型:微调后的Chinese-CLIP
- 集合:text_collection
python part_3_4_image_embeddings.py- 功能:提取图像特征并存入Milvus
- 模型:微调后的Chinese-CLIP
- 集合:image_embeddings
python part_4_1_split_question.py- 功能:划分训练/验证集,格式化问答数据
- 输出:
dataset/finetuning/train.json、val.json
python part_4_2_PEFT.py- 基础模型:Qwen2.5-VL-3B-Instruct
- 微调方法:LoRA (Low-Rank Adaptation)
- 监控:SwanLab实验管理平台
多路检索的作用是基于用户输入来检索用户正在基于哪一个文物进行提问。顺序流程如下:
-
首先使用与向量化一致的CLIP模型对用户的问题以及图片分别进行向量化得到图片向量
$\mathbf{i}$ 和 文本向量$\mathbf{t}$ 。 -
分别基于两个模态的向量在 Milvus 数据库中检索与之相似的文物信息,得到两组候选结果 $\mathbf{C_i} $ 和
$\mathbf{C_t} $ 。每一组候选结果中包含多个(默认5个)文物信息和相似度(0-1)。 -
遍历每个检索结果,按排名和模态权重计算加权综合得分,最终选取得分最高的文物作为用户当前关注的文物。排名权重计算方式为:排名/总数
示例:
基于用户输入查询到以下信息:
- 图像检索结果: [(id1,0.8), (id2,0.7), (id1,0.6), (id2,0.6), (id1,0.5)]
- 文本检索结果: [(id2,0.9), (id1,0.8), (id2,0.7), (id1,0.6), (id2,0.5)]
按照权重比为1:1来计算最终每个文物的权重为: $$ score(id1) = (0.81/1+0.61/3+0.51/5)1 + (0.81/2+0.61/3)1 =1.7 $$ $$ score(id2) = (0.71/2+0.61/4)1 + (0.91/1+0.71/3+0.5*1/5)*1 \approx 1.7333 $$ $$ score(id1) < score(id2) $$ 那么最终检索的结果为 id2 文物
基于查询的id2文物,从数据库中读取完所有 chunks=[chunk 1, chunk 2, ..., chunk n] 并且使用 Qwen3-Embedding 模型进行重排序,以获得最相关的文本片段,供后续大模型生成回答使用。
重排序的原理为:chunk文本和用户的提问与用户的提问进行相似度计算,得到每个chunk与用户提问的相关性得分。
假设重排序得到相关性从高到低的顺序为 [chunk 3, chunk 5, chunk 2, ..., chunk n],取前3相关的文本作为下一步的输入。
一个良好的提示词模板可以帮助模型更好地理解用户意图,从而生成更准确的回答。
本项目使用的提示词模板为:
'''你是一名专业的文物鉴定与解读专家。请根据下述参考资料,结合用户的问题,给出准确且通俗易懂的解答。
【参考资料】
[chunk 1]
[chunk 2]
[chunk 3]
【用户问题】
[question]
请基于参考资料和图片作答,若资料不足可适当推理,但不要编造无关内容。
'''使用Qwen-VL-2.5进行推理输出得到结果。



