多模态数据处理#
为了在 vLLM 中启用各种优化,例如 分块预填充 和 前缀缓存,我们使用 BaseMultiModalProcessor
来提供占位符特征 token(例如 <image>
)和多模态输入(例如原始输入图像)之间的对应关系,这基于 HF 处理器的输出。
BaseMultiModalProcessor
的主要特性如下
提示替换检测#
HF 处理器的主要职责之一是用特征占位符 token(例如 <image><image>...<image>
,其数量等于特征大小)替换输入占位符 token(例如单个图像的 <image>
)。关于哪些 token 已被替换的信息是找到占位符特征 token 和多模态输入之间对应关系的关键。
在 vLLM 中,此信息使用 PromptReplacement
在 _get_prompt_replacements()
中指定。给定此规范,我们可以通过检查提示中是否存在特征占位符 token 来自动检测 HF 是否已替换输入占位符 token。
分词提示输入#
为了在单独的进程中启用分词,我们支持传递输入 token ID 以及多模态数据。
问题#
考虑 HF 处理器遵循以下主要步骤
对文本进行分词
处理多模态输入
执行提示替换
我们要求
对于文本 + 多模态输入,应用所有步骤 1–3。
对于分词 + 多模态输入,仅应用步骤 2–3。
如何在不重写 HF 处理器的情况下实现此目的?我们可以尝试对不同的输入多次调用 HF 处理器
对于文本 + 多模态输入,只需直接调用 HF 处理器。
对于分词 + 多模态输入,仅对多模态输入调用处理器。
虽然 HF 处理器本身支持文本 + 多模态输入,但对于分词 + 多模态输入则不然:如果输入占位符 token 的数量与多模态输入的数量不对应,则会抛出错误。
此外,由于分词文本尚未通过 HF 处理器,因此我们必须自行应用步骤 3,以使输出 token 和多模态数据彼此保持一致。
虚拟文本#
我们通过要求每个模型定义如何基于多模态输入的数量生成虚拟文本来解决第一个问题,通过 get_dummy_processor_inputs()
。这使我们能够生成与多模态输入相对应的虚拟文本,并将它们一起输入以获得处理后的多模态数据。
自动提示替换#
我们通过在 _apply_prompt_replacements()
中实现模型无关的代码来解决第二个问题,以基于 _get_prompt_replacements()
输出的规范自动将输入占位符 token 替换为特征占位符 token。
总结#
借助虚拟文本和自动提示替换,我们的多模态处理器最终可以接受带有文本和 token 提示以及多模态数据。详细逻辑在 _apply_hf_processor_main()
中显示。
处理器输出缓存#
某些 HF 处理器,例如 Qwen2-VL 的处理器,非常慢。为了缓解这个问题,我们缓存 HF 处理器的多模态输出,以避免再次处理相同的多模态输入(例如图像)。
当传入新数据时,我们首先检查哪些项在缓存中,哪些项缺失。缺失的项在一个批次中传递到 HF 处理器并缓存,然后再与缓存中的现有项合并。
由于我们只处理缺失的多模态数据项,因此输入占位符 token 的数量不再与多模态输入的数量相对应,因此它们不能与文本提示一起传递给 HF 处理器。因此,我们分别处理文本和多模态输入,使用 虚拟文本 以避免 HF 错误。由于这跳过了 HF 的提示替换代码,因此我们在之后应用 自动提示替换,以使输出 token 和多模态数据彼此保持一致。