上手推理 —— 在 T4 上跑通 Qwen3-ASR-0.6B
理论课全部结束,今天上真机。你的环境很明确:一张 T4 16GB,用来学习——好消息是 0.6B 的推理对 T4 绰绰有余:权重 fp16 只有 1.8GB,16GB 显存扣完还有 11GB+ 的 KV 空间。压测与多实例是工作场景的事(见插入专题),本课只关心把模型跑起来、看清每一行输出。
〇、课前准备(5 分钟)
# 1) 环境信息采集(填进你的笔记)
nvidia-smi # 驱动/CUDA 版本;T4 16GB 应可见
python3 --version # 建议 3.10+
pip show torch | grep Version # 建议 torch ≥ 2.1 CUDA 版
# 2) 模型下载(二选一;国内网络优先 ModelScope)
pip install -U huggingface_hub
huggingface-cli download Qwen/Qwen3-ASR-0.6B-hf --local-dir ./Qwen3-ASR-0.6B-hf
# 或 ModelScope:
# pip install modelscope && modelscope download --model Qwen/Qwen3-ASR-0.6B-hf --local_dir ./Qwen3-ASR-0.6B-hf
# 3) 一段测试音频(16kHz 单声道!没有就用麦克风录 30 秒)
sox my_call.wav -r 16000 -c 1 test16k.wav
sox -r 16000 重采样——这是数据准备的固定动作。
一、路线 A:官方 qwen-asr 包(最快跑通)
官方提供了推理包(底层封装 vLLM/transformers),三条命令跑通:
pip install qwen-asr
from qwen_asr import Qwen3ASRModel
model = Qwen3ASRModel.from_pretrained(
"./Qwen3-ASR-0.6B-hf",
dtype="float16", # ← T4 关键:BF16 权重转 fp16
)
result = model.transcribe(
"test16k.wav",
context="词表:幂等、回调、Qwen3-ASR", # 热词/上下文,自由文本
)
print(result.text) # 转写文本
print(result.language) # 检出的语言
跑通后做两个实验,亲眼验证第 6 课讲的机制:
- 热词实验:放一段含专有名词的音频,context 里写/不写该词,对比识别结果——这就是「上下文偏置」;
- 语言实验:换一段英文音频,观察
language标签自动变化(还记得输出格式language X<asr_text>…吗)。
dtype="float16" 写了;显存 OOM(几乎不可能)→ 检查是否有其他进程占卡;import 失败 → 按包文档核对依赖版本。
二、路线 B:vLLM serve(生产形态,压测的前置)
生产与压测都用服务形态。单实例学习配置:
vllm serve ./Qwen3-ASR-0.6B-hf \
--dtype float16 \
--gpu-memory-utilization 0.5 \
--port 9000
另开一个终端,用 OpenAI 兼容接口打它:
curl http://localhost:9000/v1/audio/transcriptions \
-F file=@test16k.wav \
-F model=Qwen3-ASR-0.6B-hf
启动日志里找 "Available KV cache memory" 一行——那是你的实测 KV 池,和下面第五节的估算对照。这条路线跑通后,压测方案(loadtest-plan)里的负载生成器就能直接打它了——但那是工作场景的事,学习阶段跑通即可。
cudaErrorNoKernelImageForDevice,已修复)。若 vLLM 路线折腾超过 30 分钟仍报内核类错误,先退回路线 A/C 完成学习目标,vLLM 环境问题留到压测时再治——不要卡死在一棵树上。
三、路线 C:transformers(读懂代码,微调课的地基)
import torch
from transformers import AutoProcessor, Qwen3ASRForConditionalGeneration
model_id = "./Qwen3-ASR-0.6B-hf"
processor = AutoProcessor.from_pretrained(model_id)
model = Qwen3ASRForConditionalGeneration.from_pretrained(
model_id, dtype=torch.float16, device_map="cuda",
)
inputs = processor.apply_transcription_request(
audio="test16k.wav",
language="Chinese",
format="wav",
return_tensors="pt",
).to("cuda")
out = model.generate(**inputs, max_new_tokens=256)
print(processor.batch_decode(out, skip_special_tokens=True)[0])
# 微调课的前菜:训练时只要一行换掉 generate
# labels 由 processor 自动生成:
# inputs = processor.apply_transcription_request(..., output_labels=True)
# loss = model(**inputs).loss
这条路线的价值:你看到的每个对象都对应前七课的知识——processor 切帧出 mel(第 3/5 课),<|audio_pad|> 位置被音频嵌入替换(第 6 课模板),generate 逐词元自回归(第 7 课第 7 站)。
四、逐键读懂 config.json(对照速查卡)
模型目录里的 config.json,现在每个键你都能读懂了(0.6B 的实际数值):
| 键 | 值(0.6B) | 你在哪学过 |
|---|---|---|
model_type | "qwen3_asr" | 模型家族标识 |
audio_config.encoder_layers | 18(d_model 896,14 头) | 第 2 课注意力堆叠;1.7B 版是 24 层/1024/16 头 |
audio_config.output_dim | 1024 | = LLM 隐藏维:投影器对齐的目标(第 6 课) |
text_config.num_hidden_layers | 28(hidden 1024,FFN 3072) | LLM 解码器深度 |
text_config.num_attention_heads / num_key_value_heads | 16 / 8 | GQA:16 查询头共享 8 组 KV(第 6 课新词) |
text_config.vocab_size | 151,936 | 输出层矩阵的列数(第 7 课第 6 站) |
audio_token_id | 151676 | <|audio_pad|> 占位符:音频嵌入替换处(第 6 课模板) |
timestamp_token_id | 151705 | ForcedAligner 的时间戳标记 |
dtype | bfloat16 | 存储精度;T4 上运行时转 float16(本课第一课) |
音频前端的 128 维 mel、25ms/10ms 帧参数在 preprocessor_config.json——数值与第 3/5 课的手算完全一致,打开对一遍。
五、显存预估器:你的通话在 T4 上占多少
把推理课的知识变成一个可运行的估算器(参数全部来自真实 config,已验证):
六、课后实战任务清单(可验证)
- □ 三条路线至少跑通一条(推荐 A+C),保存转写输出
- □ 用自己的一段真实通话(8k 重采样到 16k)转写,人工检查错误模式:错在哪类词?数字?专有名词?
- □ 热词实验:context 加/不加领域词表,对比同一段音频的输出
- □ 打开 config.json 与 preprocessor_config.json,把 8 个键的值讲给自己听(对照第四节表格)
- □ 运行显存预估器,把 dur_s 改成你最长的一段通话,记下 KV 占用
全部打勾 = 第 5 站通关,下一站进入数据准备 + LoRA 微调——在你的 T4 上,让模型学会你业务里的专有名词。
检索练习
本课主读材料
QwenLM/Qwen3-ASR 官方仓库 README(安装/推理/serve 全流程)与 0.6B-hf 模型卡(transformers 用法与训练配方)
读法:对照本课三路线的代码,重点确认你装的版本与文档一致;参数名有出入时以 --help 与模型卡为准。