vlmeval/api和vlmeval/vlm文件夹下分别是api接口和本地运行的大模型的代码 基类都是base
vlmeval/dataset是数据集处理代码
vlmeval/inference.py是推理代码
run.py的整个流程
1 vlmeval/api/base.py
主要为需要与外部API交互的系统提供了一个通用的框架
-
类属性
allowed_types:定义了API允许处理的数据类型(在本例中是text和image)。
INTERLEAVE:一个布尔值,表示是否允许文本和图片的交错输入(例如,某些API可能允许同时传入文本和图片)。
INSTALL_REQ:是否需要额外安装API运行时的依赖,默认为 False。 -
初始化方法 (init)
这个方法负责初始化类实例时的配置,主要参数如下:retry:表示如果调用API失败,最多重试的次数(默认10次)。
wait:表示在每次失败后需要等待的时间(默认3秒)。
system_prompt:用于配置系统提示符(如果有的话),可以在调用API时携带给模型的上下文提示。
verbose:控制是否打印详细的调试信息。
fail_msg:当API调用失败时,返回的错误信息。
此外,它还初始化了一个日志记录器 logger,用于记录调试和错误信息。其中self.data = data为pd.read_csv加载的数据[7299 rows x 11 columns]经过处理后如下所示 只有2行数据
index question
hint A
B … D category
image l2-category split 0 243 识别出艾琳的实验能最好回答的问题。
下面的文章描述了一个实验。阅读文章,然后按照以下说明进行操作。\n\n艾琳将番茄和西兰花植物…
蛞蝓会从番茄叶子上吃更多还是从西兰花叶子上吃更多? 蛞蝓在吃了番茄叶子或西兰花叶子后会更重吗? … NaN
identity_reasoning /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBw…
attribute_reasoning test 1 245 请确定Josh和Mark的实验最能回答的问题是什么。
下面的文章描述了一个实验。阅读文章,然后按照以下说明进行操作。\n\n乔什将一个乒乓球放在弹…
乒乓球从30¬∞角度或45¬∞角度发射后,是否更快停止在地面上滚动? 与从45¬∞角度发射相比,乒乓球从30¬∞角度发射是否能飞得更远?
… NaN identity_reasoning
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBw… attribute_reasoning
test
[2 rows x 11 columns]
-
抽象方法 generate_inner
这是一个抽象方法,具体的API子类需要实现这个方法来完成与实际API的交互。该方法会返回三个结果:
ret_code:返回码,表示成功 (0) 或失败的状态。
answer:API返回的实际答案。
log:用于记录过程日志。
此方法的设计确保了所有API子类都要实现自己的生成逻辑。 -
工作状态检测 (working)
这个方法用于检测API是否工作正常。它会尝试发送简单的输入(如"hello"),如果能够正常返回非空响应且不包含失败信息,则认为API是正常工作的。
它也带有超时处理(timeout),以确保在API响应过慢时能够自动调整超时时间。 -
输入检查 (check_content)
该方法用于检查输入数据的类型,支持的类型有字符串 (str)、字典 (dict)、字符串列表 (liststr) 和字典列表 (listdict)。它能够检测传入的数据格式是否符合API的要求。
例如,当输入是 str 时,它会被识别为 text 类型;当输入是字典时,则需要检查其中是否有 type 和 value 字段。 -
内容预处理 (preproc_content)
这个方法将原始输入转换为可以供API使用的格式(一般是字典列表)。它会对输入进行解析和判断,将其转换成API可以理解的标准格式(如type和value键值对)。
如果输入是文件路径,它会尝试通过 parse_file 函数来识别文件的类型(如文本文件或图片),并将其解析为相应的内容。 -
聊天功能 (chat 和 chat_inner)
chat 方法用于处理多轮对话,传入的 messages 参数是一个多轮会话消息的列表。这个方法会调用 chat_inner,它是主要的聊天核心逻辑。
在 chat_inner 中,如果一次生成请求失败,会递归地减少输入的上下文长度,直到找到可以生成响应的输入。通过这种递归方式,可以避免因为上下文长度过长而导致的生成失败问题。 -
生成功能 (generate)
generate 是主要的生成方法,它调用 generate_inner 来生成答案。它首先会对输入进行类型检查和预处理,确保输入符合API的要求。
通过重试机制,多次尝试调用API并处理失败情况。
它还会通过随机延迟 (rd.random() 产生0-0.5秒的随机延迟) 来模拟真实环境中调用API的行为。 -
图片处理 (message_to_promptimg)
该方法用于处理包含图片的输入消息。它会从消息列表中提取图片和文本,然后将其组织为适合API使用的格式(如拼接多个图片)。如果API不支持交错输入图片和文本,它会发出警告,并仅使用第一个图片和所有文本作为输入。
2 vlmeval/dataset/image_base.py
从远程地址下载数据集、解析数据集、处理图像(如加载、解码、存储),并准备好数据供模型或API使用。提供了对数据集的图像处理、数据预处理、提示构建(build_prompt),以及评估功能的接口(evaluate 需要子类实现)
- 类属性
MODALITY = ‘IMAGE’:该类处理的主要模式是图像,这意味着它专注于图像相关的数据处理。
DATASET_URL:用于存储每个数据集的下载地址。
DATASET_MD5:用于存储每个数据集的MD5哈希值,用于校验数据集文件的完整性。 - 初始化方法 (init)
dataset:指定要使用的数据集的名称,默认为 MMBench。
skip_noimg:是否跳过没有图像的数据记录(默认为 True)。如果数据集中有些条目缺少图像,这些条目将被跳过。
img_root:图像保存的路径,通过 img_root_map(dataset) 获取具体路径。
初始化时,调用了 load_data 来加载数据集,具体内容包括:
加载数据并检查图像字段是否为空,跳过没有图像的数据(如果 skip_noimg=True)。
将图像和索引字段转换为字符串,以便处理和存储。
设置 meta_only 标志,表明是否只处理元数据(如图像的路径,而非图像本身)。
3. len 和 getitem
len:返回数据集的长度,供数据迭代时使用。
getitem:根据索引返回数据集中的某一条记录,返回的是一个包含数据记录的字典形式。
4. 准备TSV文件 (prepare_tsv)
这个方法负责从远程URL下载数据集,支持文件的MD5校验,以确保下载的文件没有损坏或被篡改。
如果文件大小超过1GB,还会调用 LOCALIZE 方法进行本地化处理(如文件分割)。
load:加载并返回TSV文件的数据。
5. 图像处理功能
dump_image:这个方法负责将数据中的图像部分存储到本地磁盘。如果图像是Base64编码,它会将其解码并存储为图像文件。它支持处理单张或多张图像,并返回图像的文件路径。
display:显示数据记录中的图像或文本信息,依赖外部的 mmqa_display 方法来实现具体的展示功能。可以通过索引或直接传入数据记录来调用此方法。
- 支持的数据集 (supported_datasets)
这是一个类方法,返回该类支持的数据集名称列表(通过 DATASET_URL 字典来定义)。 - 加载数据集 (load_data)
该方法根据给定的数据集名称,下载并加载数据。具体实现是调用 prepare_tsv 来下载并加载TSV格式的数据集文件。 - 构建提示信息 (build_prompt)
该方法根据给定的数据记录生成多模态提示信息(即包含图像和文本的输入)。对于图像,先通过 dump_image 方法获取图像的存储路径,然后将图像与对应的问题一起打包成消息列表(msgs),供模型或API调用时使用。 - 评估方法 (evaluate)
这是一个抽象方法,必须在子类中实现,用于根据给定的预测文件对模型的表现进行评估。其输入通常是一个预测文件和其他可选参数(judge_kwargs),返回值可以是字典或 pandas DataFrame。 - 钩子函数 (post_build)
该方法是一个钩子函数,允许子类在数据集加载完成后执行特定的操作。子类可以通过重写这个方法,在数据加载完成后进行额外的处理
3 vlmeval/dataset/image_mcq.py
ImageMCQDataset 类是继承自 ImageBaseDataset 的一个具体实现类,专注于处理包含多项选择问题(MCQ,Multiple Choice Questions)的图像数据集。该类添加了特定于多项选择问题的功能,如生成问题选项提示、处理提示中的答案选项,以及提供专门的评估函数来计算模型的准确性。
3.1 类属性
TYPE = ‘MCQ’:这个类的类型标识为 MCQ,即多项选择问题类型的数据集。
DATASET_URL 和 DATASET_MD5:这些字典存储了不同数据集的下载链接以及对应的MD5哈希值,用于下载和校验数据文件。这里定义了几个用于下载MMBench数据集的链接,并将外部定义的 MMMB_URLS 和 MTL_MMBench_URLS 字典更新到其中,使得类可以支持更多数据集。
3.2 build_prompt 方法
这个方法负责构建用于模型推理的提示信息,特别是多模态(图像+文本)问题中的多项选择题。
输入:line 是数据集中的一条记录,可以是一个索引(int)或是一个具体的数据条目(字典或pandas行)。
功能:
图像处理:通过 self.dump_image(line) 函数处理图像部分,如果记录包含多个图像,会把它们转换成相应的文件路径。
问题和选项构建:从 line 中提取问题文本,并生成对应的选项。选项通过字母(如 A, B, C 等)进行标识,函数会根据选项生成一个提示字符串,包含问题、选项和提示(如果有的话)。
返回:返回一个包含图像和文本的消息列表(msgs),这个列表是供多模态模型输入的格式,通常每个消息是一个字典,包含 type 和 value 两个字段。
其中tgt_path = self.dump_image(line)#‘/LMUData/images/MMBench_V11/243.jpg’
返回的msgs的值如下
[{‘type’: ‘image’, ‘value’: ‘/LMUData/images/MMBench_V11/243.jpg’}, {‘type’: ‘text’, ‘value’: ‘Hint: 下面的文章描述了一个实验。阅读文章,然后按照以下说明进行操作。\n\n艾琳将番茄和西兰花植物的叶子切成一英寸的正方形。在12个容器中,她放置了六个叶子正方形:三个番茄叶子正方形和三个西兰花叶子正方形。她在每个容器中放入一只来自她花园的蛞蝓。两天后,艾琳测量了每个叶子正方形被蛞蝓吃掉的数量。她比较了番茄叶子正方形被吃掉的数量与西兰花叶子正方形被吃掉的数量。\n图:一只蛞蝓在一片叶子上。\nQuestion: 识别出艾琳的实验能最好回答的问题。\nOptions:\nA. 蛞蝓会从番茄叶子上吃更多还是从西兰花叶子上吃更多?\nB. 蛞蝓在吃了番茄叶子或西兰花叶子后会更重吗?\nPlease select the correct answer from the options above. \n’}]
3.3 decode_base64_to_image_file 方法
def decode_base64_to_image(base64_string, target_size=-1):image_data = base64.b64decode(base64_string)image = Image.open(io.BytesIO(image_data))if image.mode in ('RGBA', 'P'):image = image.convert('RGB')if target_size > 0:image.thumbnail((target_size, target_size))return image
- 该函数用于将 Base64 编码的图像字符串解码为
PIL.Image
图像对象,同时根据需要调整图像的大小。
Base64 解码:
image_data = base64.b64decode(base64_string)
- 使用
base64.b64decode
将 Base64 编码的图像字符串解码为二进制数据(image_data
)。
生成图像对象:
image = Image.open(io.BytesIO(image_data))
- 使用
PIL.Image.open
方法将二进制数据转换为图像对象。这里通过io.BytesIO
将二进制数据封装成类似文件对象的流,供Image.open
读取。
模式转换:
if image.mode in ('RGBA', 'P'):image = image.convert('RGB')
- 如果图像的模式是
RGBA
(带透明度的 RGB 图像)或P
(调色板模式的图像),将其转换为标准的RGB
模式。这一步通常用于确保图像保存时兼容更多格式。
调整图像大小:
if target_size > 0:image.thumbnail((target_size, target_size))