简介
在标准 RAG 中,输入文档由文本数据组成。LLM 利用上下文内学习的优势,通过检索与所问查询的上下文相匹配的文本文档块来提供更相关、更准确的答案。
如果文档中除了文本数据还包含图片、表格、图表等,该怎么办呢?
不同的文档格式
每种格式都有自己的结构和难题,但真正的困难来自于这些格式中的各种变化。例如,PDF 可以是单栏或多栏,可以包含表格或图表,可以有页眉、页脚、图像或图表。这种广泛的可能性使得创建一个通用的解决方案变得不切实际。
处理此类文档的主要挑战:
标准的 LLM 会忽略这些附加信息。在这里,RAG 系统必须依靠 OCR 工具从表格、图像等中提取信息。虽然近年来 OCR 技术有了很大的进步,并被普遍用于从扫描图像中提取文本。然而,它仍然会产生错误,尤其是在扫描质量较差的情况下,而且在处理复杂布局(如多列 PDF 或包含文本和图像的混合文档)时也很吃力。这将导致不相关或信息错误的文本块被索引,当检索这些文本块并将其添加到 LLM 的上下文中时,会对 LLM 合成答案的质量产生负面影响。
随着大型语言模型及其理解文本和图像能力的快速发展,我们可以利用它们的能力从图像、图表中推断信息。
在这里,我们将使用多模态 LLM ColPali 从复杂的 PDF 文档中推断信息。
什么是 ColPali?
ColPali 是一种基于视觉语言模型(VLMs)的新颖模型架构和训练策略,可有效地从视觉特征中为文档编制索引。它是 PaliGemma-3B 的扩展,可生成 ColBERT 风格的文本和图像多向量表示。
在 RAG 系统中,它被用作视觉检索器。
ColPali 的一项关键创新是将图像补丁映射到与文本相似的潜在空间中,并利用 COLBERT 策略实现文本与图像之间的高效交互。
ColPali 基于两个观察结果:
ColPali 用于将多模态文档转换为图像表示法,然后计算其多向量表示法,并将其存储为索引。VLM 可以进一步利用它来回答问题。
什么是 COLBERT?
ColBERT是Contextualized Late Interaction over BERT的缩写,是一种为高效信息检索而设计的创新模型。
ColBERT 的主要特点:
ColBERT 特别适用于对搜索任务的精确度要求较高的应用,是自然语言处理和信息检索等领域的重要工具。
早期交互会增加计算复杂度,因为它需要考虑所有可能的查询-文档配对,从而降低了大规模应用的效率。
ColBERT 等后期交互模型允许预先计算文档表示法,并在最后采用更轻量级的交互步骤,将重点放在已编码的表示法上,从而优化了效率和可扩展性。这种设计选择可以加快检索速度,降低计算需求,使其更适合处理大型文档集。
什么是视觉语言模型?
视觉语言模型(VLM)是一种先进的人工智能系统,它集成了视觉信息和文本信息,能够执行各种需要根据图像理解和生成文本的任务。下面将概述它们的主要特点和应用:
定义和功能
主要功能
多模态 RAG 实现步骤:
有几种矢量数据库支持多矢量架构或 ColBERT 风格的表示法,可以高效地索引和检索高维矢量数据。下面是一些值得注意的选择:
所需技术栈
代码实现
!pip install -qU byaldi
!pip install -qU accelerate
!pip install -qU flash_attn
!pip install -qU qwen_vl_utils
!pip install -qU pdf2image
!pip install -qU groq
!python -m pip install git+https://github.com/huggingface/transformers
!sudo apt-get update
!apt-get install poppler-utils
!mkdir Data
!wget https://arxiv.org/pdf/2409.06697 -O Data/input.pdf
from byaldi import RAGMultiModalModel
from transformers import Qwen2VLForConditionalGeneration, AutoTokenizer, AutoProcessor
from qwen_vl_utils import process_vision_info
import torch
from pdf2image import convert_from_path
import groq
RAG = RAGMultiModalModel.from_pretrained("vidore/colpali")
model = Qwen2VLForConditionalGeneration.from_pretrained("Qwen/Qwen2-VL-7B-Instruct",
torch_dtype=torch.bfloat16,
attn_implementation="flash_attention_2",
device_map="cuda")
RAG.index(input_path="Data/input.pdf",
index_name="multimodal_rag",
store_collection_with_index=False,
overwrite=True,)
text_query = "What is the type of star hosting thge kepler-51 planetary system?"
results = RAG.search(text_query,k=3)
results
###### RESPOSNE #####
[{'doc_id': 1, 'page_num': 1, 'score': 25.125, 'metadata': {}, 'base64': None},
{'doc_id': 1, 'page_num': 8, 'score': 24.875, 'metadata': {}, 'base64': None},
{'doc_id': 1, 'page_num': 9, 'score': 24.125, 'metadata': {}, 'base64': None}]
images = convert_from_path("Data/input.pdf")
image_index = results[0]["page_num"] -1
from IPython.display import Image,display
display(images[image_index])
from IPython.display import Image,display
display(images[1])
from PIL import Image
# Assuming 'img' is your image object
images[image_index].save('image1.jpg')
from google.colab import userdata
import os
os.environ["GROQ_API_KEY"] = userdata.get("GROQ_API_KEY")
LLaVA V1.5 7B(预览版)-GROQ
限制
from groq import Groq
import base64
# Function to encode the image
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
# Path to your image
image_path = "/content/image1.jpg"
# Getting the base64 string
base64_image = encode_image(image_path)
client = Groq()
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": text_query},
{
"type": "image_url",
"image_url": {
"url": f_"data:image/jpeg;base64,{base64_image}",
},
},
],
}
],
model="llava-v1.5-7b-4096-preview",
)
print(chat_completion.choices[0].message.content)
## Response ##
The type of star hosting the Kepler-51 planetary system is a F-type main-sequence star, known as Fp Lacertae. This star is located at roughly 3,090 light-years from Earth. Fp Lacertae is considered a B-type dwarf star, meaning it emits a relatively larger amount of intense light, and the planet Kepler 51i is seen orbitsing the star.
messages = [
{"role":"user",
"content":[{"type":"image",
"image":images[image_index]
},
{"type":"text","text":text_query}
]
}
]
#
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
#
image_inputs,video_inputs = process_vision_info(messages)
#
inputs = processor(text=[text],
images=image_inputs,
videos=video_inputs,
padding=True,
return_tensors="pt")
inputs = inputs.to("cuda")
#
generate_ids = model.generate(**inputs,
max_new_tokens=256)
#
generated_ids_trimmed = [out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generate_ids)]
#
output_text = processor.batch_decode(generated_ids_trimmed,
skip_special_tokens=True,
clean_up_tokenization_spaces=False)
#
print(output_text[0])
#### RESPONSE ####
'The host star of the Kepler-51 planetary system is a G-type star.'
在这里,我们看到 Qwen2-VL 提供了更准确、更好的结果。
text_query = "What is the age of the star hosting the kepler-51 planetary system?"
#
messages = [
{"role":"user",
"content":[{"type":"image",
"image":images[image_index]
},
{"type":"text","text":text_query}
]
}
]
#
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
#
image_inputs,video_inputs = process_vision_info(messages)
#
inputs = processor(text=[text],
images=image_inputs,
videos=video_inputs,
padding=True,
return_tensors="pt")
inputs = inputs.to("cuda")
#
generate_ids = model.generate(**inputs,
max_new_tokens=256)
#
generated_ids_trimmed = [out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generate_ids)]
#
output_text = processor.batch_decode(generated_ids_trimmed,
skip_special_tokens=True,
clean_up_tokenization_spaces=False)
#
print(output_text[0])
#
################ RESPONSE ##################################
The host star is a G-type star of age ~500 Myr.
结论
ColPali 是多模式文档检索领域的一大进步,它将 VLM 的优势与创新的架构选择相结合。它能够高效地处理和检索复杂文档中的信息,在不断发展的人工智能驱动的数据分析和检索系统中,它被定位为一种有价值的工具。