跳过内容

多模态数据处理

为了在 vLLM 中启用各种优化,例如 分块预填充前缀缓存,我们使用 BaseMultiModalProcessor 来提供占位符特征标记(例如 <image>)与多模态输入(例如原始输入图像)之间的对应关系,该对应关系基于 HF 处理器的输出。

以下是 BaseMultiModalProcessor 的主要功能

提示更新检测

HF 处理器的一项主要职责是使用占位符标记更新提示。例如

  • 在字符串的开头插入特征占位符标记(例如 <image><image>...<image>,其数量等于特征大小)。
  • 将现有的输入占位符标记(例如用于单张图像的 <image>)替换为特征占位符标记(例如 <image><image>...<image>,其数量等于特征大小)。

关于哪些标记已更新的信息是找到占位符特征标记与多模态输入之间对应关系的关键。

在 vLLM 中,此信息通过 PromptUpdate_get_prompt_updates 中指定。我们可以通过检查更新后的标记是否存在来自动检测 HF 是否已更新提示。

分词后的提示输入

为了在单独的进程中启用分词,我们支持在传递多模态数据的同时传递输入标记 ID。

问题

考虑 HF 处理器遵循以下主要步骤

  1. 对文本进行分词
  2. 处理多模态输入
  3. 执行提示更新

并且我们要求

  • 对于文本 + 多模态输入,应用所有步骤 1-3。
  • 对于分词后 + 多模态输入,仅应用步骤 2-3。

如何在不重写 HF 处理器的情况下实现这一点?我们可以尝试对不同的输入多次调用 HF 处理器

  • 对于文本 + 多模态输入,直接调用 HF 处理器即可。
  • 对于分词后 + 多模态输入,仅对多模态输入调用处理器。

虽然 HF 处理器原生支持文本 + 多模态输入,但对于分词后 + 多模态输入并非如此:如果输入占位符标记的数量与多模态输入的数量不对应,就会抛出错误。

此外,由于分词后的文本尚未通过 HF 处理器,我们必须自己应用步骤 3,以保持输出标记和多模态数据之间的一致性。

占位文本

我们通过要求每个模型通过 get_dummy_text 定义如何根据多模态输入的数量生成占位文本来解决第一个问题。这使我们能够生成与多模态输入对应的占位文本,并将它们一起输入以获得处理后的多模态数据。

自动提示更新

我们通过在 _apply_prompt_updates 中实现模型无关的代码来解决第二个问题,以便根据 _get_prompt_updates 输出的规范自动使用特征占位符标记更新提示。

总结

借助占位文本和自动提示更新,我们的多模态处理器最终可以接受带有多模态数据的文本和标记化提示。详细逻辑显示在 _apply_hf_processor_main 中。

处理器输出缓存

一些 HF 处理器,例如用于 Qwen2-VL 的处理器, 非常慢。为了缓解这个问题,我们缓存 HF 处理器的多模态输出,以避免再次处理相同的多模态输入(例如图像)。

当传入新数据时,我们首先检查哪些项目在缓存中,哪些项目缺失。缺失的项目会以单个批次传入 HF 处理器并缓存,然后与缓存中的现有项目合并。

由于我们仅处理缺失的多模态数据项,输入占位符标记的数量不再与多模态输入的数量对应,因此无法与文本提示一起传递给 HF 处理器。因此,我们使用 占位文本 分开处理文本和多模态输入,以避免 HF 错误。由于这跳过了 HF 的提示更新代码,我们在之后应用 自动提示更新 以保持输出标记和多模态数据之间的一致性。