跳到内容

多模态数据处理

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

以下是 BaseMultiModalProcessor 的主要功能:

提示词更新检测

HF 处理器的主要职责之一是用占位符 Token 更新提示词。例如:

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

了解哪些 Token 已更新是找到占位符特征 Token 与多模态输入之间对应关系的关键。

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

Token化提示词输入

为了支持在单独的进程中进行 Token 化,我们支持在多模态数据之外传递输入 Token ID。

问题所在

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

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

我们要求:

  • 对于文本 + 多模态输入,应用步骤 1-3。
  • 对于已 Token 化的文本 + 多模态输入,仅应用步骤 2-3。

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

  • 对于文本 + 多模态输入,直接调用 HF 处理器。
  • 对于已 Token 化的文本 + 多模态输入,仅在多模态输入上调用处理器。

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

此外,由于 Token 化后的文本未经过 HF 处理器,我们必须自己执行步骤 3,以保持输出 Token 与多模态数据的一致性。

占位文本

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

自动提示词更新

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

摘要

借助占位文本和自动提示词更新,我们的多模态处理器最终可以接受文本提示词和 Token 提示词,并包含多模态数据。详细逻辑展示在 _apply_hf_processor_main 中。

处理器输出缓存

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

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

由于我们只处理缺失的多模态数据项,输入占位符 Token 的数量不再对应多模态输入的数量,因此它们不能与文本提示词一起传递给 HF 处理器。因此,我们分别处理文本和多模态输入,使用 占位文本 来避免 HF 错误。由于这跳过了 HF 的提示词更新代码,我们随后应用 自动提示词更新 来保持输出 Token 与多模态数据的一致性。