vLLM Token Classification 推理指南:NER、强制对齐与 Token 级分类模型的离线/在线调用

发布时间:2026/9/7 18:38:48
vLLM Token Classification 推理指南:NER、强制对齐与 Token 级分类模型的离线/在线调用 vLLM Token Classification 推理指南NER、强制对齐与 Token 级分类模型的离线/在线调用【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllmvLLM 的 Pooling 模型体系在提供classify序列分类、embed向量化等序列级任务之外还通过token_classify这一token 级token-wise池化任务为命名实体识别NER、语音强制对齐forced alignment、稀疏检索与逐 token 奖励打分等场景提供支撑。本文以 vLLM 仓库中 Token Classification 使用文档 为主体结合 官方示例 与 池化参数实现 等源码完整讲解token_classify支持哪些模型、如何用LLM.encode离线推理、如何用/pooling在线服务以及use_activation、--pooler-config等关键参数背后的实现细节。任务概览与序列分类的粒度差异序列分类sequence classification池化任务为classify与Token 分类token classification池化任务为token_classify的本质区别在于输出粒度序列分类对一个完整的输入序列输出一个结果Token 分类则对序列中的每一个 token分别输出一个结果。以 NER 为例一条 Barack Obama visited Microsoft … 的序列经过token_classify后每个 token 都会得到一个标签概率分布随后通过argmax即可还原出 Barack → B-PER、Obama → I-PER 等逐 token 标注。这与序列分类一次只给出一条整体的类别分布形成鲜明对比。token_classify的使用入口可归纳如下模型用途token classificationToken 级分类池化任务Pooling Tasktoken_classify离线 APILLM.encode(..., pooling_tasktoken_classify)在线 APIPooling API/pooling需在请求体中显式声明task: token_classify。注意vLLM 自 v0.21 起移除了池化多任务支持。当模型的默认池化任务通常为classify不是你想要的任务时必须在离线侧通过PoolerConfig(tasktoken_classify)、在线侧通过--pooler-config.task token_classify手动指定否则不会自动执行 Token 级分类。许多分类模型同时支持序列分类与 Token 分类其池化类型Pooling Type也分别对应CLS/LAST/MEAN序列级与ALL/STEPtoken 级详见 Pooling Models 总览。典型应用场景与官方示例命名实体识别NERNER 是token_classify最经典的应用对每个 token 预测其在实体标注体系如 PER/ORG/LOC 与 BIO 前缀中的类别。仓库提供了离线与在线两套可直接运行的脚本离线examples/pooling/token_classify/ner_offline.py在线examples/pooling/token_classify/ner_online.py离线示例 展示了完整链路——用LLM.encode(..., pooling_tasktoken_classify)取回每个 token 的 logits再做argmax并通过模型自身的id2label映射为可读标签from vllm import LLM, EngineArgs from vllm.utils.argparse_utils import FlexibleArgumentParser parser FlexibleArgumentParser() parser EngineArgs.add_cli_args(parser) parser.set_defaults( modelboltuix/NeuroBERT-NER, # 一个 NER 微调的 BERT 模型 runnerpooling, enforce_eagerTrue, trust_remote_codeTrue, ) args parser.parse_args() llm LLM(**vars(args)) tokenizer llm.get_tokenizer() label_map llm.llm_engine.vllm_config.model_config.hf_config.id2label outputs llm.encode( [Barack Obama visited Microsoft headquarters in Seattle on January 2025.], pooling_tasktoken_classify, ) for prompt, output in zip(prompts, outputs): logits output.outputs.data # 形状为 [num_tokens, num_labels] predictions logits.argmax(dim-1) tokens tokenizer.convert_ids_to_tokens(output.prompt_token_ids) labels [label_map[p.item()] for p in predictions] for token, label in zip(tokens, labels): if token not in tokenizer.all_special_tokens: print(f{token:15} → {label})值得注意的细节output.outputs.data拿到的是逐 token 的概率/logits 二维张量需结合output.prompt_token_ids与 tokenizer 还原文本对齐关系由于分词粒度子词与人类词边界不一致通常在打印时过滤掉[CLS]、[SEP]等特殊 token。在线脚本 ner_online.py 的结构与之对称差别仅在于 logits 来自 HTTP 返回的 JSONoutput[data][0][data]需要客户端自行用torch.tensor(...)还原后处理。语音强制对齐Forced Alignment强制对齐接收「音频 参考文本」输出词级时间戳。这是 token 级分类在多模态上的典型应用模型在timestamp特殊 token 位置逐一预测时间分箱time bin预测值乘以timestamp_segment_time即得到毫秒级时间戳。官方示例同样给出离线/在线两版离线examples/pooling/token_classify/forced_alignment_offline.py在线examples/pooling/token_classify/forced_alignment_online.py以离线版为例核心是把参考文本构造成形如|audio_start||audio_pad||audio_end|word1timestamptimestampword2timestamptimestamp…的提示词并把音频以多模态输入传入from vllm import LLM, EngineArgs from vllm.utils.argparse_utils import FlexibleArgumentParser parser FlexibleArgumentParser() parser EngineArgs.add_cli_args(parser) parser.set_defaults( modelQwen/Qwen3-ForcedAligner-0.6B, runnerpooling, enforce_eagerTrue, hf_overrides{architectures: [Qwen3ASRForcedAlignerForTokenClassification]}, ) args parser.parse_args() llm LLM(**vars(args)) config llm.llm_engine.vllm_config.model_config.hf_config timestamp_token_id config.timestamp_token_id timestamp_segment_time config.timestamp_segment_time words [Hello, world] prompt f|audio_start||audio_pad||audio_end|Hellotimestamptimestampworldtimestamptimestamp sample_rate 16000 audio np.zeros(sample_rate * 5, dtypenp.float32) # 以 5 秒静音占位实际请替换为真实音频 outputs llm.encode( [{prompt: prompt, multi_modal_data: {audio: audio}}], pooling_tasktoken_classify, ) for output in outputs: logits output.outputs.data # [num_tokens, classify_num] predictions logits.argmax(dim-1) ts_predictions [ pred.item() * timestamp_segment_time for tid, pred in zip(output.prompt_token_ids, predictions) if tid timestamp_token_id ] for i, word in enumerate(words): # 每词对应一对 开始/结束 时间戳 print(f{word:15s} {ts_predictions[i * 2] / 1000:.3f}s - {ts_predictions[i * 2 1] / 1000:.3f}s)运行强制对齐有一个硬性前置条件必须通过--hf-overrides覆写模型的 architecture 声明为Qwen3ASRForcedAlignerForTokenClassification模型本身以 ASR 生成模型形式发布需要转换为 Token 分类模型文档在 在线服务一节 给出了对应的vllm serve启动命令。稀疏检索词法匹配BAAI/bge-m3模型利用 Token 分类能力实现稀疏检索sparse/lexical retrieval它通过 token 级分类头输出稀疏权重从而把文本映射为带权词项向量用于 BM25 类词法召回。vLLM 文档将其归入「特定模型示例」详见 specific_models.md 中 bge-m3 条目。支持的模型矩阵纯文本 Token 分类模型架构Architecture模型族示例 HF 模型LoRAPPBertForTokenClassificationBERT 系boltuix/NeuroBERT-NER见注等ModernBertForTokenClassificationModernBERT 系disham993/electrical-ner-ModernBERT-baseOpenAIPrivacyFilterForTokenClassificationgpt-oss 系编码器openai/privacy-filterQwen3ForTokenClassificationCQwen3 系bd2lcco/Qwen3-0.6B-finetunedRobertaForTokenClassificationRoBERTa 系Jean-Baptiste/roberta-large-ner-englishXLMRobertaForTokenClassificationXLM-RoBERTa 系Davlan/xlm-roberta-base-ner-hrl*ModelC、*ForCausalLMC等生成式模型N/A**上表角标含义C表示该架构会经由--convert classify自动转换为分类模型\*表示特性支持与原始模型一致。关于模型转换Model Conversion的机制见下文小节。多模态 Token 分类模型架构模型输入示例 HF 模型LoRAPPQwen3ASRForcedAlignerForTokenClassificationQwen3-ForcedAlignerT A文本 音频Qwen/Qwen3-ForcedAligner-0.6B见注✅︎注使用强制对齐须加--hf-overrides {architectures: [Qwen3ASRForcedAlignerForTokenClassification]}完整示例见 forced_alignment_offline.py。多模态模型的通用输入规范可参考 supported_models.md 中的多模态语言模型清单。用 Token 分类模型充当奖励模型token_classify的另一重要用途是奖励模型reward model。奖励模型为 LLM 输出质量打分、充当人类偏好的代理其中tokenoutcome奖励模型与过程奖励模型process reward modelPRM都依赖逐 token 输出。根据 reward.md 中嵌入到本文档的模型表架构模型族示例 HF 模型LoRAPPInternLM2ForRewardModelInternLM2 系internlm/internlm2-1_8b-reward、internlm/internlm2-7b-reward等✅︎✅︎Qwen2ForRewardModelQwen2 系Qwen/Qwen2.5-Math-RM-72B等✅︎✅︎*ModelC、*ForCausalLMC等生成式模型N/A**除 outcome 型奖励外PRM 也走 token 级输出、对中间推理步骤逐步打分这类模型往往需要结合STEP池化与step_tag_id/returned_token_ids提取特定 token 位置的分数例如--pooler-config {pooling_type: STEP, step_tag_id: 123, returned_token_ids: [456, 789]}。这些内容在 Reward Models 文档 中有完整说明本文不再展开。模型自动转换列表中找不到你的模型怎么办如果模型不在上表vLLM 会尝试用as_seq_cls_model将其自动转换为序列分类模型源码位于vllm.model_executor.models.adapters转换后模型同样具备token_classify能力。默认情况下类别概率取自最后一个 token 对应的 softmax 化隐藏状态。自动转换依赖--runner pooling与--convert两个开关协同工作若显式或自动设置了--runner pooling但模型并未实现VllmModelForPooling接口vllm.model_executor.modelsvLLM 会按下表按架构名尝试转换详见 Pooling Models 配置文档架构名模式自动采用的--convert支持的池化任务*ForTextEncoding、*EmbeddingModel、*Modelembedtoken_embed、embed*ForRewardModeling、*RewardModelembedtoken_embed、embed*For*Classification、*ClassificationModelclassifytoken_classify、classify也可以显式指定--convert classify对应文档角标C把生成式模型如Qwen3ForCausalLM、LlamaForCausalLM等转成带分类头的模型。对于转换得到的模型与使用标准 DispatchPooler 适配器的预定义模型classify/token_classify任务会构造「分类激活头」默认采用基于标签数量选定的 sigmoid 或 softmaxembed/token_embed则构造 L2 归一化头。二者的头是否生效都由use_activation统一控制。离线推理LLM.encode(..., pooling_tasktoken_classify)支持的池化参数Pooling ParametersPoolingParams中token_classify任务可用的公开参数集中在use_activation# --8-- common-pooling-paramsvllm/pooling_params.py use_activation: bool | None None其含义是是否对池化器输出施加激活函数分类任务的 sigmoid/softmax。None表示使用池化器的默认行为。可以对照源码中按任务分组的合法参数表来理解不同任务的差异vllm/pooling_params.py#L77-L84property def valid_parameters(self): return { embed: [dimensions, use_activation], classify: [use_activation], token_embed: [dimensions, use_activation], token_classify: [use_activation], # 仅 use_activation 有效 }几点源码级事实token_classify与classify一样不支持dimensions那是 embedding/Matryoshka 维度裁剪用的传入会被参数校验拒绝若use_activation未显式设置_set_default_parameters会在classify/token_classify分支下将其默认置为True即默认施加 softmax/所选激活由于逐 token 输出要求每个输入位置都被真实计算任务为token_classify的请求会把skip_reading_prefix_cache置为True即跳过 prefix cache 读取以免缓存命中导致输出 token 数不足见 vllm/pooling_params.py#L129-L132。调用示例文档给出了最小可运行示例以runnerpooling方式初始化 LLM通过pooling_tasktoken_classify请求逐 token 结果from vllm import LLM llm LLM(modelboltuix/NeuroBERT-NER, runnerpooling) (output,) llm.encode(Hello, my name is, pooling_tasktoken_classify) data output.outputs.data # 形状为 [token 数, 类别数] 的张量 print(fData: {data!r})需要澄清的是目前没有一个独立的LLM.token_classify(...)快捷方法——正如 README 的 API 对照表 所示Token 分类用途的专用离线 API 一栏为 N/A统一走通用的LLM.encode该方法对所有 pooling 模型可用并显式传入pooling_task。若模型默认任务不是token_classify离线侧还可以通过PoolerConfig(tasktoken_classify)指定。在线服务Pooling API/pooling在线场景下请使用Pooling API/pooling并在请求体中显式携带task: token_classify。该 API 的输入格式与 OpenAI 兼容的 Embeddings API 一致但输出data可以容纳任意嵌套列表因为逐 token 输出天然是二维结构这一点与序列级接口有本质差异。服务端启动以 NER 模型为例vllm serve boltuix/NeuroBERT-NER \ --runner pooling \ --enforce-eager \ --pooler-config.task token_classify若模型需要trust_remote_code或架构覆写按需追加相应参数如强制对齐场景需携带--hf-overrides {architectures: [Qwen3ASRForcedAlignerForTokenClassification]}。客户端调用在线示例 ner_online.py 展示了标准请求结构——单个字符串会按单条文本返回服务器日志会给出 token 数与标签数import requests api_url http://localhost:8000/pooling prompt { model: boltuix/NeuroBERT-NER, input: Barack Obama visited Microsoft headquarters in Seattle on January 2025., task: token_classify, } response requests.post(api_url, jsonprompt) output response.json()[data][0] logits torch.tensor(output[data]) # 二维逐 token 的类别分布 predictions logits.argmax(dim-1)等价地用 curl 也可直接调试curl http://127.0.0.1:8000/pooling \ -H Content-Type: application/json \ -d { model: boltuix/NeuroBERT-NER, input: Barack Obama visited Microsoft headquarters in Seattle., task: token_classify }对于多模态的强制对齐在线请求需要在messages中用audio_url承载 base64 音频、并配合chat_template字段发送裸文本提示词完整实现见 forced_alignment_online.py。服务端usage.prompt_tokens可与客户端本地分词长度互相校验以检测--trust-request-chat-template等启动参数是否配置正确。池化配置解析--pooler-config与字段优先级指定任务与池化方式当模型默认池化任务不是token_classify时在线侧通过--pooler-config.task token_classify覆盖等价于离线侧PoolerConfig(tasktoken_classify)。若模型自带可接受pooler_config的Poolervllm.model_executor.layers.pooler还可以覆写其池化属性。PoolerConfig的核心字段包括pooling_type快捷设置池化类型如CLS或分别用seq_pooling_type/tok_pooling_type精细控制序列级与 token 级池化use_activation布尔值控制是否施加该任务构造的归一化或分类激活头例如{use_activation: false}可返回裸 logits而非概率task声明的池化任务。逐字段的解析优先级根据 Pooling 总览文档PoolingParams/PoolerConfig的解析是逐字段独立进行的遵循以下优先级链池化方式pooling_type--pooler-config Sentence Transformersmodules.json中 Pooling 模块的pooling_mode兼容 5.4 的紧凑字段与旧布尔字段 架构默认序列级默认LAST、token 级默认ALL架构可覆写use_activation--pooler-config Sentence Transformers 模块存在 Normalize 模块则为true否则false 池化任务默认未找到 Pooling 模块时为true分类激活函数由 HFproblem_type Sentence Transformers 激活元数据 按标签数选择 sigmoid/softmax 决定——该函数不能通过--pooler-config直接选择只能靠{use_activation: false}关闭激活以取得 logits。如果不想加载权重即检查解析结果文档提供了基于ModelConfigPoolerConfig的离线检查脚本docs/models/pooling_models/README.md可以打印seq_pooling_type、tok_pooling_type、use_activation与最终选用的分类激活名。token_classify与分类任务的特性对齐Token 分类所支持的特性与序列分类保持一致具体可展开为三类详见 classify.md 的 Supported Features 章节激活开关通过use_activation开启/关闭激活返回概率或 logitsproblem_type修改 HF config 中的problem_type支持single_label_classification、multi_label_classification、regression与 transformers 的ForSequenceClassificationLoss对齐仿射分数校准Affine Score Calibration即 Platt Scaling变换为activation((logit - logit_mean) / logit_sigma)其中logit_mean默认None减均值居中与logit_sigma默认None除标准差缩放均可配置。示例--pooler-config {use_activation: true, logit_mean: 4.5, logit_sigma: 1.0}。与其他池化用途的边界为避免混淆这里澄清token_classify在 vLLM 池化体系中的定位相关总览见 Pooling Models README与classify的关系同一分类模型可同时具备序列与 token 两种粒度能力classify输出每序列一条概率向量token_classify输出每 token 一条。只有当分类模型num_labels 1时才能充当交叉编码器reranker并使用打分类 API与token_embed的关系vLLM 已把早期的encode任务拆分为token_embed逐 token 向量激活为归一化与token_classify逐 token 概率默认激活为 softmax。抽取隐藏状态优先用token_embed而 NER 与奖励模型优先用token_classify与奖励/评分的关系token 奖励模型与过程奖励模型走token_classify评分模型cross-encoder/late-interaction/bi-encoder则与之无关对应score_type为 N/A。延伸阅读examples/pooling/token_classify 目录本文全部示例脚本的离线/在线完整实现Pooling Models 总览池化任务、池化类型、模型转换与--pooler-config优先级的总纲分类用途文档序列分类与特性激活、problem_type、分数校准的细节奖励模型文档token 奖励模型与 PRM 的配置特定模型示例BAAI/bge-m3等特殊模型的用法池化参数实现PoolingParams的字段定义、任务级参数校验与默认值逻辑。【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考