本文档记录 Qwen3-ForcedAligner-0.6B 在 vLLM-Ascend 0.18.0 环境的适配与验证结果。
Qwen3-ForcedAligner-0.6B 是基于 Qwen3ASRForConditionalGeneration 架构的语音强制对齐模型,核心特点为:
classify_num: 5000)thinker.lm_head 被替换为 [5000, hidden_size] 的分类头,而非 [vocab_size, hidden_size] 的语言模型头适配要点:
Qwen3ASRForConditionalGeneration 架构,但尚未处理 classify_num 场景vllm/model_executor/models/qwen3_asr.py,在检测到 classify_num 时自动将 lm_head 替换为 RowParallelLinear 分类头,并绕过 LogitsProcessor相关获取地址:
quay.io/ascend/vllm-ascend:v0.18.0参考文档:
| 组件 | 版本 |
|---|---|
vllm-ascend | 0.18.0 |
vllm | 0.18.0+empty |
transformers | 4.57.6 |
torch-npu | 2.9.0.post1+gitee7ba04 |
cann | 8.5.1 |
2 逻辑卡(Ascend910,A2)/tmp/models/Qwen/Qwen3-ForcedAligner-0___6B/8000仅修改 vllm/model_executor/models/qwen3_asr.py,最小化差异如下:
--- a/vllm/model_executor/models/qwen3_asr.py
+++ b/vllm/model_executor/models/qwen3_asr.py
@@ -33,8 +33,10 @@
from vllm.config import ModelConfig, SpeechToTextConfig, VllmConfig
from vllm.config.multimodal import BaseDummyOptions
+from vllm.distributed import get_pp_group
from vllm.inputs.data import PromptType, TokensPrompt
from vllm.logger import init_logger
+from vllm.model_executor.layers.linear import RowParallelLinear
from vllm.model_executor.models.interfaces import (
MultiModalEmbeddings,
SupportsMRoPE,
@@ -312,6 +314,18 @@
prefix=maybe_prefix(prefix, "language_model"),
)
+ # ForcedAligner uses a classification head instead of full vocab lm_head
+ self.classify_num = getattr(thinker_config, "classify_num", None)
+ if self.classify_num is not None and get_pp_group().is_last_rank:
+ self.language_model.lm_head = RowParallelLinear(
+ thinker_config.text_config.hidden_size,
+ self.classify_num,
+ bias=False,
+ quant_config=quant_config,
+ prefix=maybe_prefix(prefix, "language_model.lm_head"),
+ )
+ self.language_model.logits_processor = None
+
self.make_empty_intermediate_tensors = (
self.language_model.make_empty_intermediate_tensors
)
@@ -431,6 +445,9 @@
self,
hidden_states: torch.Tensor,
) -> torch.Tensor | None:
+ if self.classify_num is not None:
+ logits, _ = self.language_model.lm_head(hidden_states)
+ return logits
return self.language_model.compute_logits(hidden_states)
def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:已验证通过的启动命令(单卡):
export KERNEL_META_DIR=/tmp/kernel_meta
export ASCEND_CACHE_PATH=/tmp/ascend_cache
export ASCEND_WORK_PATH=/tmp/ascend_work
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
vllm serve /path/to/Qwen3-ForcedAligner-0.6B \
--host 0.0.0.0 \
--port 8000 \
--dtype bfloat16 \
--max-model-len 8192 \
--max-num-seqs 4 \
--limit-mm-per-prompt '{"audio":1}'注意:若启动时遇到
Read-only file system: '/vllm-workspace/vllm/kernel_meta',请确保设置可写的KERNEL_META_DIR环境变量。
基础检查:
# 服务就绪检查
curl -sf http://127.0.0.1:8000/v1/models
# 文本推理(分类输出,非自然文本)
curl -sf http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "/path/to/Qwen3-ForcedAligner-0.6B",
"messages": [{"role": "user", "content": "test"}],
"temperature": 0,
"max_tokens": 8
}'验证结果:
| 检查项 | 结果 |
|---|---|
/v1/models | ✅ 返回 200 |
/v1/chat/completions | ✅ 返回 200,模型可正常前向推理 |
| Dummy weight loading | ✅ 通过 |
| Real weight loading | ✅ 通过 |
| ACL Graph capture | ✅ 通过 |
| 音频模态初始化 | ✅ 通过 |
| 特性 | 状态 | 说明 |
|---|---|---|
| 文本推理 | ✅ | 分类头输出,需业务层后处理 |
| 音频输入 | ✅ | 通过 --limit-mm-per-prompt '{"audio":1}' 启用 |
| 多卡并行 (TP) | ⚠️ | 未验证,理论支持 |
| 流水线并行 (PP) | ⚠️ | 未验证,理论支持 |
| 量化 (AWQ/GPTQ) | ❌ | 框架未支持 |
| Prefix Caching | ✅ | 默认开启 |
| Chunked Prefill | ✅ | 默认开启 |
transformers 或 tokenizer 修复。Qwen3-ForcedAligner-0.6B 的 lm_head 输出为 5000 类时间戳分类,需在业务侧实现对应的后处理逻辑(将分类 ID 映射为时间戳),vLLM 层仅负责前向推理。transcription endpoint 针对 ASR 设计,ForcedAligner 需通过 chat/completions 传入音频和参考文本使用。Qwen3-ForcedAligner-0.6B 在 Ascend NPU (A2) 上通过最小化代码修改即可完成适配,核心改动为在 qwen3_asr.py 中支持 classify_num 分类头。模型可正常完成权重加载、ACL Graph 编译与服务启动,基础推理验证通过。