Qwen3-ASR-CTC
一个 48.3M 参数的 CTC 头,接在冻结的 Qwen3-ASR-1.7B 音频编码器后面,做首遍
(first-pass) 转写和强制对齐。编码器不含在本仓库,运行时从
Qwen/Qwen3-ASR-1.7B 加载。
用途是给"CTC 首遍 + LLM 二遍"这类流水线提供快速首遍:贪心解码 RTF 0.0002 (8× 昇腾 910B3,91.3 小时音频 1.1 分钟解完),并且天然能出帧级时间戳。
先说结论:什么时候别用它
同一批数据、同一套超参训出来的 GLM-ASR-Nano 版 CTC 头,在五个干净的 held-out 测试集上全面更好:
| 测试集 | 指标 | GLM-ASR-Nano 版 | 本模型 |
|---|---|---|---|
| AISHELL-1 test | CER | 4.71% | 5.31% |
| AISHELL-1 dev | CER | 4.09% | 4.37% |
| LibriSpeech test-clean | WER | 4.88% | 6.93% |
| LibriSpeech test-other | WER | 9.99% | 12.40% |
| ASCEND test(中英混说) | MER | 11.84% | 14.53% |
差距是个与语速无关、近乎恒定的倍数(英文 1.3–1.5×、中文 1.1–1.2×)。 最可能的原因不是编码器,而是优化配方:本模型用 512 样本/更新、只训了 56,916 次更新;GLM 那版是 256 样本/更新、134,140 次更新,而两者 LR 同为 5e-4 (batch 翻倍却没按线性缩放规则放大)。对照实验尚未完成。
所以:这是一个研究产物,不是当前最好的 CTC 首遍模型。 想要最好的转写质量 请用 GLM 那版;想要 Qwen3 编码器的表征、或者要做 13 fps 帧率的对比实验,用这个。
时间戳精度(对 Montreal Forced Aligner 真值实测)
在 LibriSpeech test-clean/other 的 1,500 句 / 29,621 词上,对
gilkeyio/librispeech-alignments
的 MFA 词级对齐:
| 本模型(13 fps) | GLM 版(50 fps) | |
|---|---|---|
| 词起始 中位偏置 | +100.0 ms | +105.0 ms |
| 词结束 中位偏置 | −78.5 ms | −100.0 ms |
| 起始 去偏置后 中位|误差| | 50.8 ms | 40.0 ms |
| 起始 去偏置后 ≤100 ms | 77.6% | 82.4% |
| 结束 去偏置后 中位|误差| | 60.0 ms | 50.0 ms |
两点要注意:
- 有一个系统性偏置,减掉它。 词起始一致偏晚约 100 ms、结束偏早约 80 ms。 这是 CTC 尖峰式发射的固有性质(概率集中在词的中间),不是模型缺陷,是个常数。
- 帧率不是精度的主导误差项。 帧移相差 3.85 倍(76.9 vs 20.0 ms), 去偏置后的中位误差只差约 10 ms。单帧量化的理论下限是 ±38 ms, 实测 50.8 ms 只有它的 1.3 倍 —— 主要误差来自模型对词边界的不确定性。
时间轴本身是准的:在音频前面接 1.00 秒数字静音后,98.6% 的字时间戳整体平移 恰好 1.00 秒(中位误差 0.0 ms)。
训练
| 编码器 | Qwen3-ASR-1.7B audio tower,全程冻结 |
| CTC 头 | 2048→2048→512,5 层 Transformer block(8 头,FFN 128),72,468 类 |
| 参数量 | 48,344,468 |
| 数据 | 26 个 manifest / 7,434,437 条(train 7,285,749 / val 148,688),15 个语种 |
| 语料 | AISHELL-1、WenetSpeech M、MAGICDATA、Common Voice (yue/zh-HK/zh-TW/ja)、LibriSpeech、GigaSpeech M、KsponSpeech、MLS (de/nl/fr/es/it/pt/pl)、TALCS、CS-Dialogue、ASCEND(后三个中英混说语料 3 倍上采样) |
| 硬件 | 8× 昇腾 910B3,CANN 9.0.1,torch_npu 2.8.0 |
| 配方 | batch 64/卡、grad_accum 1、lr 5e-4 余弦、1 个 warmup epoch(blocks 冻结)+ 3 个满 epoch |
| 步数 / 时长 | 56,916 次更新 / 11 小时 56 分 |
| 最终 loss | train 0.4958 / val 0.6150 |
vocab_compact.json 是从 Qwen3 原生的 151,705 词表压出来的紧凑词表:在全部
662 万条语料上只有 72,377 个 token 被用到(47.7%),另外 52.3% 一次都没出现过 ——
那些行的 ctc_lo 权重从头到尾拿不到正梯度,只在 softmax 分母里被反复压低。
压到 72,468 类后省掉 40.6M 参数,实测零 unk、零往返漂移。
用法
pip install torch transformers qwen-asr safetensors soundfile
from modeling_ctc import Qwen3CtcAsr
asr = Qwen3CtcAsr(".", device="cuda") # 会自动拉 Qwen/Qwen3-ASR-1.7B
print(asr.transcribe([waveform_16k_float32]))
离线环境把本地编码器目录给 QWEN3_ASR_ENCODER。完整示例(含 CTC 强制对齐出
字级时间戳)见 example.py:
python example.py audio.wav
# 转写: 甚至出现交易几乎停滞的情况
# 字级时间戳(帧移 76.9 ms):
# '甚至' 0.77 - 0.85 s
# '出现' 1.23 - 1.31 s
# ...
三个会让你静默拿到错误结果的坑
modeling_ctc.py 里都处理了,自己重写时务必照做:
编码器输入是时间维拼接的 2D 张量
[128, ΣT_mel]加feature_lens, 不是[B, 128, T]。传 3D 会报split_with_sizes的错。帧率是 13 fps(76.9 ms/帧),不是 Whisper/GLM 的 50 fps。 编码器用 3 层 stride-2 conv2d 做 8 倍降采样,但官方长度公式是"每 100 个 mel 帧出 13 帧" (
qwen3_output_lengths(),已对 9 次真实前向逐条核对)。沿用 50 fps 的算法 会把可用帧数高估 4 倍 —— CTC 以为容量充足,实际 log_probs 只有 1/4 长, loss 看着能降但对齐全是错的。必须打 attention mask 补丁。
qwen-asr0.0.6 里_prepare_attention_mask定义了却从来没被调用,cu_seq_lens_q/k只有 flash_attention_2 后端认。 不打补丁时同一条音频单条推理 vs 批推理的余弦相似度只有 0.81–0.88,打完 0.9998+。CUDA 上同样中招,不是昇腾特有的问题。patch_qwen3_attention_mask()是幂等的,Qwen3CtcAsr会自动调用。
已知局限
- 训练语料里 TALCS / MAGICDATA / CS-Dialogue 的官方 test split 混进了训练集, 所以本模型在这三个 test 上的数字不能当泛化指标。上面表格里的五个测试集都是 实测确认干净的。
- 中文时间戳没有真值可校。本模型在 AISHELL 上比 GLM 版系统性晚约 303 ms, 但英文上两者只差 30.5 ms 且都对得上 MFA —— 中文那个偏差是真实存在的, 只是缺少中文的词级真值,无法判断哪一边更准。
- 日语只训了 Common Voice ja,覆盖偏窄。
训练与评测代码
https://gitea.cemp.top/jju/glm-asr-ctc-trn-dev
scripts/evaluate.py(CER/WER/MER)、scripts/ctc_align.py(强制对齐 + 三种
验证模式)、scripts/build_test_manifests.py(建 held-out 测试集并实测污染)。
许可
CTC 头权重按基础模型 Qwen3-ASR-1.7B 的 Apache-2.0 发布。训练语料各自的许可 归各自所有者,本仓库不含任何语料数据。
- Downloads last month
- 8
Model tree for JazerJu/qwen3-asr-ctc
Base model
Qwen/Qwen3-ASR-1.7B