【RAG系列】多模态RAG的三种实现思路和代码

目录

前言

一、文本RAG的介绍

二、多模态

三、多模态RAG

方法一:共享向量空间

方法二:统一模态

方法三:分离检索

四、多模态RAG代码示例

总结


前言

RAG工程的出现是为了弥补LLM专业知识的不足以及减少LLM幻觉问题,目前最常见的是文本RAG,但随着场景越来越复杂,对多模态RAG的需求开始变多。本文先简要介绍多模态基础,然后详细介绍多模态RAG的三种实现思路,以及代码实现。


一、文本RAG的介绍

我们知道文本RAG工程的关键是索引构建和文档检索,这两者都需要借助embedding模型将文本编码成向量以构建索引,然后在检索时计算用户查询向量(文本)和文档向量(文本)在同一个向量空间计算距离,距离最近的文档被认为最相关。

同样的,在构建多模态RAG时,最关键的也是为多模态数据构建索引,以及如何检索相关数据。索引构建同样需要借助embedding模型,但有一个问题,多模态数据各自所处的向量空间不同,该使用什么方法将两者的向量联系在一起,就又涉及到了深度学习中的多模态。

二、多模态

在数据科学中,“模态”本质上是一种数据类型。文本、图像、音频、视频、表格,这些都可以被视为不同的“模态”。长期以来,这些不同类型的数据被视为彼此独立,需要分别创建一个模型来处理文本,一个模型来处理视频等。但随着多模态模型的出现,这种传统范式已经慢慢消失,能够理解和处理多种模态的模型变得更加高效和更易获取。

多模态模型的概念通常围绕着“联合embedding”的想法。基本上,联合embedding是一种模型建模策略,强制模型同时学习不同类型的数据。在这一领域的里程碑论文之一是 CLIP,它能够执行与图像和文本相关的任务。  

CLIP主要包括两个部分:1)图像编码器:通常采用预训练的卷积神经网络(CNN)或Vision Transformer(ViT)作为图像编码器。这个编码器负责将输入图像转换为一个高维的向量表示。2)文本编码器:文本编码器一般采用Transformer结构,将输入文本(例如描述图像的句子)转换为一个高维的向量表示。

这两个编码器的输出是嵌入空间中的向量,CLIP将这两个空间进行对齐。

CLIP的训练方法:1)数据集:CLIP使用了一个大规模的图像-文本对数据集进行训练。这些数据对来自于互联网,涵盖了丰富的视觉和语言信息。2)训练方法:CLIP采用对比学习的方式进行训练,具体而言,对于每一个图像-文本对,模型会计算图像和文本之间的相似度,训练目标是最大化匹配的图像和文本对的相似度,同时最小化不匹配对的相似度。

三、多模态RAG

了解多模态的基本概念后,应用到多模态RAG的关键就是如何对齐不同模态数据的向量空间,以支持向量检索。目前,有三种流行的方法可以实现多模态RAG。

方法一:共享向量空间

类CLIP的方法,对齐不同模态数据的向量空间,然后使用多模态数据的向量构建索引和检索,检索出所有和用户查询最相关的数据。

方法二:统一模态

首先将所有模态转化成相同模态,通常是文本,在很多需要精确策略的时候经常会使用该方法(我们称之为“多模态转换”)。虽然这种策略在理论上存在着信息在转换过程中可能会丢失的微妙风险,但实际上我们发现,对于许多应用来说,这种方法可以实现非常高质量的结果,而复杂度相对较低。另外就是方便debug。

方法三:分离检索

第三种方法是使用一系列设计用于处理不同形式的模型。在这种情况下,在不同的模型之间进行多次检索,然后将它们的结果合并。    

四、多模态RAG代码示例

git:https://github.com/DanielWarfield1/MLWritingAndResearch.git

在对多模态 RAG 有了一个大致的了解后,用一个简单的例子来实验一下:

  1. 一个音频文件,例如竖琴演奏家是 Turlough O'Carolan

  2. 一张包含洛伦兹吸引子图片的图像

  3. 《西线无战事》维基百科文章的摘录

利用这些数据,构建一个简单的多模态RAG系统,回答“谁是我的最喜欢的竖琴演奏家?”

我们采用方法二,使用Audio to Text模型将Audio转换为Text,然后使用类CLIP的模型编码image和text,使用余弦相似度用于检索。

下载保存图像文件:

import requests
from PIL import Image
from IPython.display import display
import os

# Loading image
url = 'https://github.com/DanielWarfield1/MLWritingAndResearch/blob/main/Assets/Multimodal/MMRAG/Lorenz_Ro28-200px.png?raw=true'
response = requests.get(url, stream=True)
image = Image.open(response.raw).convert('RGB')

# Save the image locally as JPG
save_path = 'image.jpg'
image.save(save_path, 'JPEG')
display(image)

下载保存音频文件:

"""Downloading audio waveform from multimodal dataset
"""
from pydub import AudioSegment
import numpy as np
import io
import matplotlib.pyplot as plt
import wave
import requests

url = "https://github.com/DanielWarfield1/MLWritingAndResearch/blob/main/Assets/Multimodal/MMRAG/audio.mp3?raw=true"  # 音频文件的URL
response = requests.get(url)  # 发送HTTP请求获取音频文件
audio_data = io.BytesIO(response.content)  # 将音频文件内容存储在内存中

audio_segment = AudioSegment.from_file(audio_data, format="mp3")  # 从内存中读取MP3格式的音频文件

# 将采样率降到16000 Hz
# (这是必要的,因为未来的模型需要它在16000Hz)
sampling_rate = 16000  # 设定采样率为16000Hz
audio_segment = audio_segment.set_frame_rate(sampling_rate)  # 设置音频段的采样率

wav_data = io.BytesIO()  # 创建一个内存字节流对象
audio_segment.export(wav_data, format="wav")  # 将音频段导出为WAV格式并存储在内存中
wav_data.seek(0)  # 将内存字节流的指针重置到开始位置
wav_file = wave.open(wav_data, 'rb')  # 打开内存中的WAV文件

frames = wav_file.readframes(-1)  # 读取所有音频帧
audio_waveform = np.frombuffer(frames, dtype=np.int16).astype(np.float32)  # 将音频帧转换为浮点数数组

plt.plot(audio_waveform)  # 绘制音频波形图
plt.title("Audio Waveform")  # 设置图表标题
plt.xlabel("Sample Index")  # 设置X轴标签
plt.ylabel("Amplitude")  # 设置Y轴标签
plt.show()  # 显示图表

下载文本

"""Downloading text from multimodal dataset
"""
import requests

# URL of the text file
url = "https://github.com/DanielWarfield1/MLWritingAndResearch/blob/main/Assets/Multimodal/MMRAG/Wiki.txt?raw=true"
response = requests.get(url)
text_data = response.text

# truncating length for compatability with an encoder that accepts a small context
# a different encoder could be used which allows for larger context lengths
text_data = text_data[:300]
print(text_data)

使用 s2t-medium-librispeech-asr模型将预处理的Audio转化为Text

import torch
from transformers import Speech2TextProcessor, Speech2TextForConditionalGeneration

#the model that generates text based on speech audio
model = Speech2TextForConditionalGeneration.from_pretrained("facebook/s2t-medium-librispeech-asr")
#a processor that gets everything set up
processor = Speech2TextProcessor.from_pretrained("facebook/s2t-medium-librispeech-asr")

#passing through model
inputs = processor(audio_waveform, sampling_rate=sampling_rate, return_tensors="pt")
generated_ids = model.generate(inputs["input_features"], attention_mask=inputs["attention_mask"])

#turning model output into text
audio_transcription = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]

Query:

query = 'who is my favorite harpist?'

Embedding data

# Embedding Data
Using a clip style model, which can embed images and text, to embed the image, text, and audio grounded in text.

from transformers import CLIPProcessor, CLIPModel

# Load the model and processor
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")

# Encode the image
inputs = processor(images=image, return_tensors="pt")
image_embeddings = model.get_image_features(**inputs)

# Encode the text
inputs = processor(text=[query, audio_transcription, text_data], return_tensors="pt", padding=True)
text_embeddings = model.get_text_features(**inputs)

# Print or use the embeddings
print("Image Embeddings:", image_embeddings)
print("Text Embeddings:", text_embeddings)

Calculating cosine similarity

image_embedding = image_embeddings[0]
query_embedding = text_embeddings[0]
audio_embedding = text_embeddings[1]
text_embedding = text_embeddings[2]

import torch
from torch.nn.functional import cosine_similarity

# Calculate cosine similarity
cos_sim_query_image = cosine_similarity(query_embedding.unsqueeze(0), image_embedding.unsqueeze(0)).item()
cos_sim_query_audio = cosine_similarity(query_embedding.unsqueeze(0), audio_embedding.unsqueeze(0)).item()
cos_sim_query_text = cosine_similarity(query_embedding.unsqueeze(0), text_embedding.unsqueeze(0)).item()

# Print the results
print(f"Cosine Similarity between query and image embedding: {cos_sim_query_image:.4f}")
print(f"Cosine Similarity between query and audio embedding: {cos_sim_query_audio:.4f}")
print(f"Cosine Similarity between query and text embedding: {cos_sim_query_text:.4f}")

RAG根据最相关结果进行回答:

similarities = [cos_sim_query_image, cos_sim_query_audio, cos_sim_query_text]

result = None
if max(similarities) == cos_sim_query_image:
    #image most similar, augmenting with image
    model = genai.GenerativeModel('gemini-1.5-pro')
    result = model.generate_content([query, Image.open('image.jpeg')])

elif max(similarities) == cos_sim_query_audio:
    #audio most similar, augmenting with audio. Here I'm using the transcript
    #rather than the audio itself
    model = genai.GenerativeModel('gemini-1.5-pro')
    result = model.generate_content([query, 'audio transcript (may have inaccuracies): '+ audio_transcription])

elif max(similarities) == cos_sim_query_text:
    #text most similar, augmenting with text
    model = genai.GenerativeModel('gemini-1.5-pro')
    result = model.generate_content([query, text_data])

print(result.text)

result.text = "It sounds like you're trying to say **Turlough O'Carolan**. He was a famous Irish harpist and composer. It's easy to get his name a little mixed up - it's quite unique!"


总结

多模态RAG的难点和多模态本身类似,还是如何对其不同模态数据的表示,以保证和用户查询的相似度计算的正确率。好在目前有很多开源的Audio to Text模型、Image to Text模型和 Image-Text双模态模型,效果也都很不错。如果需要针对具体场景的多模态模型,可以根据数据进行进一步微调。

### 多模态RAG概述 多模态RAG(Retrieval-Augmented Generation)旨在增强传统文本生成模型的能力,使其能够处理多种数据形式。通过引入视觉、音频以及其他类型的输入,这些系统可以提供更丰富的上下文理解能力[^2]。 ### 实现方式 为了构建一个多模态RAG系统,通常会采用如下策略: #### 数据预处理阶段 在这个过程中,来自不同源的数据被转换成统一表示形式以便于后续处理。对于图像视频这样的非结构化数据来说,这一步骤尤为重要。例如,在处理图片时可能会先提取特征向量作为其代表;而对于语音信号,则可以通过声谱图等方式将其转化为适合机器学习算法使用的格式。 ```python from transformers import CLIPProcessor, CLIPModel model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") def preprocess_image(image_path): image = Image.open(image_path) inputs = processor(images=image, return_tensors="pt", padding=True) outputs = model.get_image_features(**inputs) return outputs.detach().numpy() ``` #### 跨模态融合机制设计 当面对包含多个感官通道的任务需求时,如何有效地整合各类感知信息成为了一个挑战。一种常见的做法是在编码器内部建立共享参数空间来促进不同类型表征之间的交互作用;另一种则是利用注意力机制让解码端动态调整对各路输入的关注程度[^1]。 #### 检索模块优化 考虑到实际应用场景下的效率考量,针对大规模数据库快速定位最相关条目的技术也得到了重视发展。比如借助近似最近邻搜索(ApNN)算法可以在不影响精度的前提下显著缩短查询时间开销。 ### 研究论文推荐 有关此主题的研究成果层出不穷,以下是几篇具有代表性的工作: - **Multimodal Retrieval Augmented Generation for Complex Reasoning over Text and Images**: 探讨了结合文本与图像进行复杂推理的方法论创新。 - **VL-BERT: Pre-training of Generic Visual-Linguistic Representations from Scratch via Multi-task Learning**: 提出了一个可以从头训练通用视语义联合表达框架的新颖思路。 - **Unicoder-VL: A Universal Encoder for Vision and Language by Cross-modal Pre-training with Hard Negative Examples**: 阐述了一种用于跨媒体任务的有效解决方案——即通过困难负样本辅助的交叉模式预训练得到广泛适用性的编码网络架构。 ### 应用案例展示 目前已有不少成功的商业产品服务采用了类似的原理技术路线: - **搜索引擎改进**:现代互联网巨头们正积极尝试将多媒体元素融入自家平台的核心功能当中去,从而改善用户体验并提高广告投放精准度; - **虚拟助手升级**:新一代AI聊天机器人不仅限于文字对话交流,还能识别用户上传的照片甚至实时捕捉周围环境变化作出回应; - **医疗影像分析工具开发**:医生可借助此类软件迅速获取病历资料摘要的同时查看对应的X光片或CT扫描结果,进而做出更加准确诊断决策。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值