EN

VisRAG:基于 VLM 的 RAG 流水线

VisRAG 是基于视觉语言模型(VLM)的 RAG 流水线;EVisRAG(VisRAG 2.0)是面向多图像问题的证据引导视觉检索增强生成框架。

核验日期

核心信息

以下信息由程序从官方接口读取,不经模型改写。

许可证
Apache-2.0
语言
Python
维护方
OpenBMB
核验日期

它是什么

VisRAG 是基于视觉语言模型(VLM)的 RAG 流水线。在该流水线中,文档不先解析为文本,而是直接用 VLM 作为图像嵌入,再被检索,用以增强 VLM 的生成。EVisRAG(VisRAG 2.0)是证据引导的视觉检索增强生成框架,先以语言方式观察检索到的图像以收集每张图像的证据,再基于这些线索推理作答,用于多图像问题。VisRAG-Ret 是基于 MiniCPM-V 2.0 构建的文档嵌入模型,MiniCPM-V 2.0 是以 SigLIP 为视觉编码器、以 MiniCPM-2B 为语言模型的视觉语言模型。

主要能力

  1. EVisRAG 使用 Reward-Scoped GRPO 训练,通过细粒度的 token 级奖励联合优化视觉感知与推理。

  2. 项目方称,与传统基于文本的 RAG 相比,VisRAG 最大限度地保留并利用原始文档中的数据信息,消除了解析过程带来的信息损失。

  3. 项目方将 EVisRAG 描述为端到端框架,在多图像场景的推理过程中为 VLM 提供精确的视觉感知。

  4. GitHub 上的 VisRAG Pipeline 支持跨多个 PDF 文档的视觉理解。

  5. VisRAG-Gen 的生成有三种设置:基于文本的生成、基于单图像 VLM 的生成和基于多图像 VLM 的生成。

  6. 在基于单图像 VLM 的生成下,另有两种设置:页面拼接和加权选择。

怎么上手

  1. Google Colab 上的 VisRAG Pipeline 同时包含 VisRAG-Ret 和 VisRAG-Gen,可作为演示。

  2. EVisRAG 的训练采用两阶段策略。

  3. EVisRAG 训练的第一阶段是基于 LLaMA-Factory 的 SFT。

  4. EVisRAG 训练的第二阶段是基于 Easy-R1 的 RS-GRPO。

  5. 运行 EVisRAG 评测时,先执行 predict 脚本。

  6. EVisRAG 评测会直接报告 EM、Accuracy 和 F1 指标。

摘自 README · bash
git clone https://github.com/OpenBMB/VisRAG.git
conda create --name EVisRAG python==3.10
conda activate EVisRAG
cd EVisRAG
pip install -r EVisRAG_requirements.txt
摘自 README · bash
git clone https://github.com/OpenBMB/VisRAG.git
conda create --name VisRAG python==3.10.8
conda activate VisRAG
conda install nvidia/label/cuda-11.8.0::cuda-toolkit
cd VisRAG
pip install -r requirements.txt
pip install -e .
cd timm_modified
pip install -e .
cd ..
摘自 README · python
from transformers import AutoProcessor
from vllm import LLM, SamplingParams
from qwen_vl_utils import process_vision_info

def evidence_promot_grpo(query):
    return f"""You are an AI Visual QA assistant. I will provide you with a question and several images. Please follow the four steps below:

Step 1: Observe the Images
First, analyze the question and consider what types of images may contain relevant information. Then, examine each image one by one, paying special attention to aspects related to the question. Identify whether each image contains any potentially relevant information.
Wrap your observations within <observe></observe> tags.

Step 2: Record Evidences from Images
After reviewing all images, record the evidence you find for each image within <evidence></evidence> tags.
If you are certain that an image contains no relevant information, record it as: [i]: no relevant information(where i denotes the index of the image).
If an image contains relevant evidence, record it as: [j]: [the evidence you find for the question](where j is the index of the image).

Step 3: Reason Based on the Question and Evidences
Based on the recorded evidences, reason about the answer to the question.
Include your step-by-step reasoning within <think></think> tags.

Step 4: Answer the Question
Provide your final answer based only on the evidences you found in the images.
Wrap your answer within <answer></answer> tags.
Avoid adding unnecessary contents in your final answer, like if the question is a yes/no question, simply answer "yes" or "no".
If none of the images contain sufficient information to answer the question, respond with <answer>insufficient to answer</answer>.

Formatting Requirements:
Use the exact tags <observe>, <evidence>, <think>, and <answer> for structured output.
It is possible that none, one, or several images contain relevant evidence.
If you find no evidence or few evidences, and insufficient to help you answer the question, follow the instruction above for insufficient information.

Question and images are provided below. Please follow the steps as instructed.
Question: {query}
"""

model_path = "xxx"
processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True, padding_side='left')

imgs, query = ["imgpath1", "imgpath2", ..., "imgpathX"], "What xxx?"
input_prompt = evidence_promot_grpo(query)

content = [{"type": "text", "text": input_prompt}]
for imgP in imgs:
    content.append({
        "type": "image",
        "image": imgP
    })
msg = [{
          "role": "user",
          "content": content,
      }]

llm = LLM(
    model=model_path,
    tensor_parallel_size=1,
    dtype="bfloat16",
    limit_mm_per_prompt={"image":5, "video":0},
)

sampling_params = SamplingParams(
    temperature=0.1,
    repetition_penalty=1.05,
    max_tokens=2048,
)

prompt = processor.apply_chat_template(
    msg,
    tokenize=False,
    add_generation_prompt=True,
)

image_inputs, _ = process_vision_info(msg)

msg_input = [{
    "prompt": prompt,
    "multi_modal_data": {"image": image_inputs},
}]

output_texts = llm.generate(msg_input,
    sampling_params=sampling_params,
)

print(output_texts[0].outputs[0].text)
摘自 README · python
from transformers import AutoModel, AutoTokenizer
import torch
import torch.nn.functional as F
from PIL import Image
import os

def weighted_mean_pooling(hidden, attention_mask):
    attention_mask_ = attention_mask * attention_mask.cumsum(dim=1)
    s = torch.sum(hidden * attention_mask_.unsqueeze(-1).float(), dim=1)
    d = attention_mask_.sum(dim=1, keepdim=True).float()
    reps = s / d
    return reps

@torch.no_grad()
def encode(text_or_image_list):
    
    if (isinstance(text_or_image_list[0], str)):
        inputs = {
            "text": text_or_image_list,
            'image': [None] * len(text_or_image_list),
            'tokenizer': tokenizer
        }
    else:
        inputs = {
            "text": [''] * len(text_or_image_list),
            'image': text_or_image_list,
            'tokenizer': tokenizer
        }
    outputs = model(**inputs)
    attention_mask = outputs.attention_mask
    hidden = outputs.last_hidden_state

    reps = weighted_mean_pooling(hidden, attention_mask)   
    embeddings = F.normalize(reps, p=2, dim=1).detach().cpu().numpy()
    return embeddings

model_name_or_path = "openbmb/VisRAG-Ret"
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, trust_remote_code=True)
model = AutoModel.from_pretrained(model_name_or_path, torch_dtype=torch.bfloat16, trust_remote_code=True)
model.eval()

script_dir = os.path.dirname(os.path.realpath(__file__))
queries = ["What does a dog look like?"]
passages = [
    Image.open(os.path.join(script_dir, 'test_image/cat.jpeg')).convert('RGB'),
    Image.open(os.path.join(script_dir, 'test_image/dog.jpg')).convert('RGB'),
]

INSTRUCTION = "Represent this query for retrieving relevant documents: "
queries = [INSTRUCTION + query for query in queries]

embeddings_query = encode(queries)
embeddings_doc = encode(passages)

scores = (embeddings_query @ embeddings_doc.T)
print(scores.tolist())
摘自 README · bash
git clone https://github.com/hiyouga/LLaMA-Factory.git 
bash evisrag_scripts/full_sft.sh
摘自 README · bash
bash evisrag_scripts/run_rsgrpo.sh

适合谁

本仓库中的代码以 Apache-2.0 许可发布。使用 VisRAG-Ret 模型权重必须严格遵循 MiniCPM Model License.md。VisRAG-Ret 的模型和权重可免费用于学术研究。

填写登记问卷后,VisRAG-Ret 权重也可免费用于商业用途。VisRAG-Gen 的生成部分不使用微调,而是直接使用现成的 LLM/VLM 进行生成。VisRAG-Ret 的训练数据集包含 362,110 个查询-文档(Q-D)对,由公开学术数据集的训练集(34%)和合成数据集(66%)组成,合成数据集由网络爬取的 PDF 文档页面构成,并以 VLM(GPT-4o)生成的伪查询增强。

VisRAG-Ret 的训练框架基于 OpenMatch 修改而来。已训练并发布的、采用 EVisRAG 的 VLRM 基于 Qwen2.5-VL-7B-Instruct 和 Qwen2.5-VL-3B-Instruct 构建。VisRAG-Ret 的评测脚本默认使用来自 Hugging Face 的数据集。

来源

本页内容整理自以下官方来源,点击可核对原文。

核验日期 ·

本页由 AI 依据上述官方来源整理,并经自动核对,未经本站实测。 发现错误?告诉我们。