前言
多模态检索增强生成_(Multimodal Retrieval Augmented Generation,简称RAG)_是一种新兴的设计范式,允许AI模型与文本、图像、视频等多种信息存储接口进行交互。
在探讨这个主题时,我们首先会介绍什么是检索增强生成_(RAG)_,多模态的概念,以及如何将两者结合以构建现代多模态RAG系统。在理解了多模态RAG的基本概念后,我们将使用Google Gemini和一种类似CLIP的编码模型来构建一个多模态RAG系统。
检索增强生成简介
在介绍多模态RAG之前,我们先简单了解一下传统的检索增强生成 (RAG)。基本上,RAG的概念是找到与用户查询相关的信息,然后将这些信息注入到提示中并传递给语言模型。
RAG系统的基本原理是根据用户的查询检索相关信息,然后将这些信息与用户的查询结合_(称为增强)_后传递给语言模型。
RAG系统的检索通常是通过“嵌入”实现的。基本上,为了嵌入某些内容,我们使用高级AI模型将信息转换为代表该信息的向量。
嵌入的概念图,AI模型会提取一些文本序列并创建一个代表该文本序列的向量。
这个过程是通过一组参考文档以及用户的查询来完成的。可以计算这些向量之间的距离,文档与用户查询之间距离最小的被认为是最相关的。
检索的概念图。这里,事件列表被认为是最相关的,因为它与用户查询的距离最小。
一旦RAG系统检索到足够相关的信息,用户的查询和相关文档将用于构建一个增强提示,然后将其传递给语言模型进行生成。
"Answer the customers prompt based on the folowing context:
==== context: {document title} ====
{document content}
...
prompt: {prompt}"
这种通用系统通常预设整个知识库由可以传递给语言模型的文本组成,但许多知识来源不仅仅是文本。可能还有音频、视频、图像等。这就是多模态RAG的作用。
在讨论多模态RAG之前,让我们简要探讨一下多模态的概念。
多模态
在数据科学中,“模态”本质上是数据的一种类型。文本、图像、音频、视频、表格等都可以被视为不同的“模态”。长期以来,这些不同类型的数据被视为彼此分离,数据科学家需要为文本、视频等分别创建模型。近年来,这种概念逐渐消失,能够理解和处理多种模态的模型变得更加高效且易于访问。这些能够理解多种数据类型的模型通常被称为“多模态模型”。
多模态模型的概念通常围绕“联合嵌入”展开。基本上,联合嵌入是一种建模策略,迫使模型同时学习不同类型的数据。这个领域的标志性论文之一是CLIP,它创建了一个能够处理图像和文本任务的强大模型。
CLIP风格的模型使用复杂的训练过程使多个模型组件协同工作,以理解图像和文本。
自CLIP以来,各种建模策略已被创建,以某种方式对齐图像和文本。我介绍了这个领域的各种模型,但这些只是冰山一角。到处都有可以处理多种类型的数据新模型问世。
多模态和RAG的演变引发了AI的新趋势:在多模态中进行RAG。
多模态RAG
多模态RAG的概念是允许RAG系统以某种方式将多种形式的信息注入多模态模型中。因此,多模态 RAG 系统不仅可以根据用户提示检索文本片段,还可以检索文本、图像、视频和其他不同模态的数据。
多模态RAG的核心概念。它与普通RAG类似,但现在可以检索来自多种模态的信息并传递给语言模型。
目前有三种流行的方法可以实现多模态RAG。
方法一:共享向量空间
多模态RAG的一种方法是使用能够处理多种模态的嵌入_(类似于前面讨论的CLIP)_。基本上,你可以通过一组设计为相互协作的编码器传递数据,然后在所有模态中检索与用户查询最相似的数据。
使用多模态嵌入系统的多模态RAG,例如Google Vertex提供的编码器。这些编码器旨在协同工作,将来自不同模态的数据放置在同一个嵌入中。以更好地了解其实际应用。
方法二:单一基础模态
多模态RAG的另一种方法是将所有数据模态转换为单一模态,通常是文本。
使用基础模态的多模态RAG。所有模态在传递到单个编码器之前都会转换为单个模态。
我在一家公司工作,该公司在一个更大的产品中采用了这种策略_(我们称之为“多模态转换”)_。虽然这种策略在理论上存在信息在转换过程中丢失的风险,但实际上我们发现对于许多应用来说,这种方法以相对较小的复杂性实现了非常高质量的结果。
方法三:独立检索
第三种方法是使用一组旨在处理不同模态的模型。在这种情况下,你会在不同的模型上多次进行检索,然后结合它们的结果。
使用独立检索的多模态RAG。有多种方法可以将独立检索结果合并为一个用于增强和生成的检索结果。最简单的方法是将它们全部合并并传递给多模态模型。更常见的是使用一个“重新排序”模型或系统,设计用于根据与查询的相关性组织数据。我计划在未来的文章中介绍重新排序。
如果你希望能够构建和优化多种模型以适应不同的模态,或者你只是使用现有建模解决方案中不可用的模态,那么这将很有用。
在Google Vertex中实现多模态RAG
现在我们已经对多模态 RAG 有了大致的了解,让我们用一个简单的例子来实验一下。我们将对三部分信息进行检索:
-
我用不佳的发音说“我最喜欢的竖琴家是Turlough O’Carolan”的音频文件
-
包含Lorenz Attractor图片的图像
-
维基百科文章《西线无战事》的摘录
使用这些数据,我们将构建一个简单的RAG系统来回答问题“谁是我最喜欢的竖琴家?”
完整代码可在此找到:
https://github.com/DanielWarfield1/MLWritingAndResearch/blob/main/MultimodalRAG.ipynb。
设置
首先让我们进行一些准备工作。我们将使用pydub来处理音频:
!pip install pydub
然后我们可以配置API密钥以使用Google Gemini。
import os
import google.generativeai as genai
from google.colab import userdata
os.environ["GOOGLE_API_KEY"] = userdata.get('GeminiAPIKey')
genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
下载数据
我把所有文件都放在我的 GitHub repo 中,所以我们可以直接从那里下载。首先,我们可以从数据集中下载图像,并将其保存到文件系统以备后用。
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)
然后我们可以下载音频文件:
from pydub import AudioSegment
import numpy as np
import io
import matplotlib.pyplot as plt
import wave
import requests
# Downloading audio file
url = "https://github.com/DanielWarfield1/MLWritingAndResearch/blob/main/Assets/Multimodal/MMRAG/audio.mp3?raw=true"
response = requests.get(url)
audio_data = io.BytesIO(response.content)
# Converting to wav and loading
audio_segment = AudioSegment.from_file(audio_data, format="mp3")
# Downsampling to 16000 Hz
#(this is necessary because a future model requires it to be at 16000Hz)
sampling_rate = 16000
audio_segment = audio_segment.set_frame_rate(sampling_rate)
# Exporting the downsampled audio to a wav file in memory
wav_data = io.BytesIO()
audio_segment.export(wav_data, format="wav")
wav_data.seek(0) # Back to beginning of IO for reading
wav_file = wave.open(wav_data, 'rb')
# converting the audio data to a numpy array
frames = wav_file.readframes(-1)
audio_waveform = np.frombuffer(frames, dtype=np.int16).astype(np.float32)
# Rendering audio waveform
plt.plot(audio_waveform)
plt.title("Audio Waveform")
plt.xlabel("Sample Index")
plt.ylabel("Amplitude")
plt.show()
最后是我们的维基百科文本摘录:
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)
现在,我们有了一个音频文件_(其中包含我说出我最喜欢的竖琴家是谁)_,以及一个图像和文本文件。
将音频转换为文本
可以找到支持音频、图像和文本的编码器,但它们比仅支持图像和文本的编码器要复杂一些。我计划写一篇关于Google Vertex的综合文章,测试这些不太常见的数据科学应用/模态的极限。为了简化我们的操作,现在我们将使用语音转文本模型将音频转为文本。
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]
audio_transcription
如你所见,语音转文本的翻译效果并不理想。Turlough O’Carolan 是17世纪的凯尔特竖琴家,我根本不知道怎么发音。我尝试了几次,因此转录结果非常荒谬。
嵌入
现在我们已经将音频转换为文本表示,可以使用CLIP风格模型对图像和文本进行编码。如果你不熟悉CLIP风格模型,它们是一种理解如何表示图像和文本,使得相似的事物具有相似向量的模型。我有一篇关于这个主题的文章:
CLIP,直观且详尽地解释:
https://towardsdatascience.com/clip-intuitively-and-exhaustively-explained-1d02c07dbf40
我们可以使用其中一种来编码我们的图像和文本。首先,让我们定义我们的查询:
query = 'who is my favorite harpist?'
然后让我们用 huggingface 的CLIP风格模型嵌入所有内容。
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)
接下来,我们可以解包这些结果,获取文本、图像、音频和查询的编码,并计算数据与查询之间的差异。在这种情况下,我们将使用余弦相似度,它本质上是两个向量之间角度的度量。对于余弦相似度,如果两个向量指向相同的方向,它们的余弦相似度就很高。
import torch
from torch.nn.functional import cosine_similarity
# unpacking individual embeddings
image_embedding = image_embeddings[0]
query_embedding = text_embeddings[0]
audio_embedding = text_embeddings[1]
text_embedding = text_embeddings[2]
# 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(检索增强生成)
现在我们有了每个数据的嵌入,我们可以进行“检索增强生成”。
-
检索:找到与查询最相关的内容。
-
增强:将这些内容与查询一起放入语言模型的提示中。
-
生成:将其传递给语言模型生成答案。
在这个简化的示例中,我们可以使用一些if语句来实现这一点:
# putting all the similarities in a list
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)
Gemini确实得为你爆料一下。
结论
虽然在这个快速变化的领域很难说任何事情,但似乎多模态RAG可能是即将到来的人工智能产品化浪潮中的一项关键技能。我认为可以公平地说,RAG作为一个整体,无论是多模式还是其他方式,都将随着技术的需求将技术水平推向新的高度,并且新的构建范式会变得更加容易接近。
在目前的多模态RAG中,我们触及了所有的重点:
-
我们简要探讨了RAG和多模态。
-
我们探讨了三种多模态RAG的方法:共享向量空间、单一基础模态和独立检索。
-
然后我们使用基础模态和共享向量空间方法的组合自己实现了一个简单的多模态RAG示例。
最后的最后
感谢你们的阅读和喜欢,我收藏了很多技术干货,可以共享给喜欢我文章的朋友们,如果你肯花时间沉下心去学习,它们一定能帮到你。
因为这个行业不同于其他行业,知识体系实在是过于庞大,知识更新也非常快。作为一个普通人,无法全部学完,所以我们在提升技术的时候,首先需要明确一个目标,然后制定好完整的计划,同时找到好的学习方法,这样才能更快的提升自己。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
![](https://img-blog.csdnimg.cn/img_convert/20982f66383fdbd3945b47dc923e2729.jpeg)
大模型知识脑图
为了成为更好的 AI大模型 开发者,这里为大家提供了总的路线图。它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
经典书籍阅读
阅读AI大模型经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习AI大模型开发的读者来说,阅读经典书籍是非常有必要的。
实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
面试资料
我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下
640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
![](https://img-blog.csdnimg.cn/img_convert/20982f66383fdbd3945b47dc923e2729.jpeg)