多模态数据处理¶
为了在 vLLM 中实现各种优化,例如 分块预填充 和 前缀缓存,我们使用 BaseMultiModalProcessor,该处理器根据 HF 处理器的输出,提供占位符特征令牌(例如 `<image>`)与多模态输入(例如原始输入图像)之间的对应关系。
以下是 BaseMultiModalProcessor 的主要特性:
提示更新检测¶
HF 处理器的主要职责之一是更新带有占位符令牌的提示。例如:
- 在字符串开头插入特征占位符令牌(例如 `<image><image>...<image>`,数量等于特征大小)。
- 将现有的输入占位符令牌(例如单个图像的 `<image>`)替换为特征占位符令牌(例如 `<image><image>...<image>`,数量等于特征大小)。
有关哪些令牌已更新的信息是查找占位符特征令牌与多模态输入之间对应关系的关键。
在 vLLM 中,此信息使用 `_get_prompt_updates` 中的 PromptUpdate 来指定。通过检查更新后的令牌是否存在,我们可以自动检测 HF 是否已更新提示。
分词后的提示输入¶
为了在单独的进程中进行分词,我们支持在传递多模态数据时一并传递输入令牌 ID。
问题所在¶
考虑到 HF 处理器的主要步骤如下:
- 分词
- 处理多模态输入
- 执行提示更新
而我们的要求是:
- 对于文本 + 多模态输入,应用所有步骤 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 的提示更新代码,因此我们之后应用 自动提示更新 来使输出令牌和多模态数据保持一致。