池化模型¶
注意
我们目前支持 Pooling 模型主要是为了方便起见。这并不能保证比直接使用 Hugging Face Transformers
或 Sentence Transformers 带来任何性能上的提升。
We plan to optimize pooling models in vLLM. Please comment on [:octicons-mark-github-16: Issue #21796](https://github.com/vllm-project/vllm/issues/21796) if you have any suggestions!
什么是 Pooling 模型?¶
自然语言处理 (NLP) 主要可分为以下两类任务:
- 自然语言理解 (NLU)
- 自然语言生成 (NLG)
vLLM 支持的生成式模型涵盖了多种任务类型,例如我们熟悉的通用大语言模型 (LLM)、处理图像/视频/音频等多模态输入的多模态模型 (VLM)、语音转文字转录模型,以及支持流式输入的实时模型。它们的共同特征是具备文本生成能力。进一步而言,vLLM-Omni 还支持生成包括图像、视频和音频在内的多模态内容。
随着生成式模型能力的持续提升,这些模型的边界也在不断扩展。然而,某些应用场景仍需要专门的小型语言模型来高效地完成特定任务。这些模型通常具有以下特征:
- 它们不需要进行内容生成。
- 它们仅需执行非常有限的功能,不需要强大的泛化能力、创造力或高智能。
- 它们对延迟要求极低,并且可能运行在成本受限的硬件上。
- 纯文本模型通常参数量少于 10 亿,而多模态模型通常参数量少于 100 亿。
尽管这些模型规模相对较小,但它们仍然基于 Transformer 架构,与当今最先进的大语言模型相似甚至完全相同。许多近期发布的 Pooling 模型也是通过大语言模型微调而来,从而能够受益于大模型持续的性能提升。这种架构上的相似性使得它们能够复用 vLLM 的大部分基础设施。如果兼容,我们很乐意帮助它们利用 vLLM 的最新功能。
序列级任务与 Token 级任务¶
序列级任务与 Token 级任务的主要区别在于输出粒度:序列级任务为整个输入序列产生一个结果,而 Token 级任务则为序列中的每个单独 Token 产生一个结果。
许多 Pooling 模型同时支持序列级任务和 Token 级任务。当默认的 Pooling 任务(例如序列级任务)不是您所需时,您需要通过离线的 PoolerConfig(task=<task>) 或在线的 --pooler-config.task <task> 手动指定(例如 Token 级任务)。
当然,我们也有“插件 (plugin)”任务,允许用户自定义输入和输出处理器。更多信息,请参考 IO 处理器插件。
Pooling 任务¶
| 池化任务 | 粒度 | 输出 |
|---|---|---|
classify (见备注) | 序列级 | 每个序列的类别概率向量 |
embed | 序列级 | 每个序列的向量表示 |
token_classify | Token 级 | 每个 Token 的类别概率向量 |
token_embed | Token 级 | 每个 Token 的向量表示 |
注意
在分类任务中,存在一个特殊的子类:交叉编码器 (Cross-encoder,又称重排序器/reranker) 模型。
它们是分类模型的一个子集,接收两个提示 (prompt) 作为输入,并输出标签数量 (num_labels) 为 1 的结果。
评分类型¶
评分模型旨在计算两个输入提示之间的相似度得分。它支持三种模型类型(即 score_type):cross-encoder、late-interaction 和 bi-encoder。
| 池化任务 | 粒度 | 输出 | 评分类型 | 评分函数 |
|---|---|---|---|---|
classify (见备注) | 序列级 | 每个序列的重排序得分 | cross-encoder | 线性分类器 |
embed | 序列级 | 每个序列的向量表示 | bi-encoder | 余弦相似度 |
token_classify | Token 级 | 每个 Token 的类别概率向量 | 无 | 无 |
token_embed | Token 级 | 每个 Token 的向量表示 | late-interaction | 延迟交互 (MaxSim) |
注意
只有当分类模型的 num_labels 等于 1 时,它才能作为评分模型使用,并启用其评分 API。
Pooling 用途¶
| Pooling 用途 | 描述 |
|---|---|
| 分类用法 | 预测给定输入最对应的预定义类别、分类或标签。 |
| 嵌入用法 | 将非结构化数据(文本、图像、音频等)转换为结构化数值向量(Embedding)。 |
| Token 分类用法 | Token 级分类 |
| Token 嵌入用法 | Token 级 Embedding |
| 评分用法 | 计算两个输入之间的相似度得分。支持三种模型类型:cross-encoder、late-interaction 和 bi-encoder。 |
| 奖励模型用法 | 评估语言模型生成输出的质量,作为人类偏好的代理指标。 |
我们还有一些支持多种 Pooling 任务、具有特定使用场景或支持特殊输入输出的特殊模型。
欲了解更多详细信息,请参考下方链接。
离线推理¶
根据 Pooler.get_supported_tasks,vLLM 中的每个 Pooling 模型支持一个或多个此类任务,从而启用相应的 API。
Pooling 任务对应的离线 API¶
| 任务 | API |
|---|---|
embed | LLM.embed(...), LLM.encode(..., pooling_task="embed"), LLM.score(...)(见备注) |
classify | LLM.classify(...), LLM.encode(..., pooling_task="classify"), LLM.score(...) |
token_classify | LLM.reward(...), LLM.encode(..., pooling_task="token_classify") |
token_embed | LLM.encode(..., pooling_task="token_embed"), LLM.score(...) |
插件 (plugin) | |
注意
只有当分类模型的 num_labels 等于 1 时,它才能作为评分模型使用,并启用其评分 API。
LLM.classify¶
classify 方法为每个提示输出一个概率向量。它主要针对 分类模型 设计。关于 LLM.embed 的更多信息,请参阅 此页面。
LLM.embed¶
embed 方法为每个提示输出一个嵌入向量。它主要针对 Embedding 模型 设计。关于 LLM.embed 的更多信息,请参阅 此页面。
LLM.score¶
score 方法输出句子对之间的相似度得分。它主要针对 评分模型 设计。
LLM.encode¶
encode 方法适用于 vLLM 中的所有 Pooling 模型。
使用 LLM.encode 时,请使用更具体的方法或直接设置任务类型,详情参考 上表。
示例¶
from vllm import LLM
llm = LLM(model="intfloat/e5-small", runner="pooling")
(output,) = llm.encode("Hello, my name is", pooling_task="embed")
data = output.outputs.data
print(f"Data: {data!r}")
在线服务¶
我们的在线服务器提供了与离线 API 相对应的端点:
- 对应
LLM.embed- Cohere Embed API (
/v2/embed) - OpenAI 兼容 Embedding API (
/v1/embeddings)
- Cohere Embed API (
- 对应
LLM.classify- 分类 API(
/classify)
- 分类 API(
- 对应
LLM.score - Pooling API (
/pooling) 类似于LLM.encode,适用于所有类型的 Pooling 模型。
以下介绍 Pooling API。对于其他 API,请参考上方链接。
Pooling API¶
我们的 Pooling API (/pooling) 类似于 LLM.encode,适用于所有类型的 Pooling 模型。
其输入格式与 Embedding API 相同,但输出数据可以包含任意嵌套列表,而不仅仅是浮点数的一维列表。
使用 Pooling API 时,请使用更具体的 API 或直接设置任务类型,详情参考 上表。
代码示例:examples/pooling/pooling/pooling_online.py
示例¶
# start a supported embeddings model server with `vllm serve`, e.g.
# vllm serve intfloat/e5-small
import requests
host = "localhost"
port = "8000"
model_name = "intfloat/e5-small"
api_url = f"http://{host}:{port}/pooling"
prompts = [
"Hello, my name is",
"The president of the United States is",
"The capital of France is",
"The future of AI is",
]
prompt = {"model": model_name, "input": prompts, "task": "embed"}
response = requests.post(api_url, json=prompt)
for output in response.json()["data"]:
data = output["data"]
print(f"Data: {data!r} (size={len(data)})")
配置¶
在 vLLM 中,Pooling 模型实现了 VllmModelForPooling 接口。这些模型使用 Pooler 来提取输入序列的最终隐藏状态,然后再返回结果。
模型运行器 (Model Runner)¶
通过选项 --runner pooling 以 Pooling 模式运行模型。
提示
绝大多数情况下无需设置此选项,因为 vLLM 可以通过 --runner auto 自动检测合适的模型运行器。
模型转换¶
vLLM 可以通过选项 --convert <type> 适配各种 Pooling 任务的模型。
如果已设置 --runner pooling(手动或自动),但模型未实现 VllmModelForPooling 接口,vLLM 将尝试根据下表中的架构名称自动转换模型。
| 架构 | --convert | 支持的 Pooling 任务 |
|---|---|---|
*ForTextEncoding, *EmbeddingModel, *Model | embed | token_embed, embed |
*ForRewardModeling, *RewardModel | embed | token_embed, embed |
*For*Classification, *ClassificationModel | classify | token_classify, classify |
提示
您可以显式设置 --convert <type> 来指定模型转换方式。
Pooler 配置¶
预定义模型¶
如果模型定义的 Pooler 接受 pooler_config,您可以通过 --pooler-config 选项覆盖其部分属性。
已转换模型¶
如果模型已通过 --convert 转换(见上文),分配给每个任务的 Pooler 默认具有以下属性:
| 任务 | Pooling 类型 | 归一化 (Normalization) | Softmax |
|---|---|---|---|
embed | LAST (最后) | ✅︎ | ❌ |
classify | LAST (最后) | ❌ | ✅︎ |
加载 Sentence Transformers 模型时,其配置文件 (modules.json) 的优先级高于模型的默认设置。
您可以通过 --pooler-config 选项进一步自定义,该选项的优先级高于模型和 Sentence Transformers 的默认设置。
已移除的功能¶
编码任务¶
我们将 encode 任务拆分为两个更具体的 Token 级任务:token_embed 和 token_classify。
token_embed与embed相同,使用归一化 (normalization) 作为激活函数。token_classify与classify相同,默认使用 softmax 作为激活函数。
Pooling 模型现在支持 Token 级任务。
- 提取隐藏状态建议使用
token_embed任务。 - 命名实体识别 (NER) 和奖励模型建议使用
token_classify任务。
评分任务¶
score 任务已被弃用,并将于 v0.20 版本移除。请改用 classify。只有当分类模型的 num_labels 等于 1 时,它才能作为评分模型使用,并启用其评分 API。
Pooling 多任务支持¶
Pooling 多任务支持已被弃用,并将于 v0.20 版本移除。当默认的 Pooling 任务不是您所需时,您需要通过离线的 PoolerConfig(task=<task>) 或在线的 --pooler-config.task <task> 手动指定。