模型:NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950 架构:MFCCA (Multi-channel Fusion Conformer with Coupled Attention)
任务:中文会议多说话人语音识别(支持 1~8 通道)
| 组件 | 版本 |
|---|---|
| NPU | Ascend 910B / 910A |
| CANN | 8.5.1 |
| PyTorch | 2.9.0 |
| torch_npu | (对应 CANN 版本) |
| Python | 3.11 |
pip install torch torch_npu soundfile omegaconf numpy
pip install --no-deps funasr注意:
funasr使用pip install --no-deps安装,本脚本手动构建子组件。
STFT 模块需要修改以支持 NPU 和 ARM CPU 上的 torch.stft:
# 文件: funasr/frontends/utils/stft.py
# 修改: 将条件分支改为始终使用 torch.stft
# 原: if input.is_cuda or _is_npu or torch.backends.mkl.is_available():
# 改: if True:cd /opt/atomgit/speech_mfcca
# 单条音频推理
python3 infer_npu.py
# 精度对比 (NPU vs CPU)
python3 eval_precision.py
# 性能基准测试
python3 eval_perf.pyinfer_npu.py — 主推理脚本手动构建 MFCCA 模型全部子组件,绕过 funasr 的 AutoModel 注册发现机制。
from infer_npu import build_model, inference
model, token_list = build_model()
model.to('npu:0')
result = inference(model, 'audio.wav', token_list, 'npu:0')
print(f"CTC: {result['ctc']}")
print(f"Attention: {result['attention']}")输入格式:
(T,) — soundfile 读取后直接送入(T, C) — 自动处理为 (1, T, C)输出: {"ctc": "...", "attention": "..."} 两个解码结果
音频: model/example/asr_example_mc.wav | 8 通道 | 132160 采样点 | 8.26 秒
CTC: 对呀一两万块钱到了而您得留出了预算你得留出他们喝酒的预算
一般都是喝酒喝抽src啊对着还两万先取五两万src啊啊哎
src可以自己带吧自己带吧src喝酒对喝酒自己吧
Attention: 对呀一两万块钱到了而且你得留出了预算你得留出他们喝酒的预算
一般都是喝酒喝超src啊都是还两万先去五万src啊啊哎
src可以自己带吧自己带吧src喝酒对喝酒自己带吧音频: model/example/asr_example.wav | 1 通道 | 132160 采样点 | 8.26 秒
CTC: 对呀一两万块钱够了而且你得他你得留出他们喝酒的预算
一般都是喝酒喝抽可以自己带吧喝酒自己带吧src对
Attention: 对呀一两万块钱够了而且你得留出他们喝酒的预算
一般都是喝酒喝酒可以自己带吧src啊src对对对对对对...注: 单通道结果比 8 通道准确率稍低,这是符合预期的 — 多通道波束赋形可以提供更丰富的空间信息辅助分离。
NPU (Ascend 910B) 与 CPU (ARM aarch64) 的 CTC 和 Attention 解码结果对比。
| 项目 | NPU | CPU | 一致 |
|---|---|---|---|
| CTC | 对呀一两万块钱到了而您得留出了预算你得留出他们喝酒的预算一般都是喝酒喝抽src啊对着还两万先取五两万src啊啊哎src可以自己带吧自己带吧src喝酒对喝酒自己吧 | 对呀一两万块钱到了而您得留出了预算你得留出他们喝酒的预算一般都是喝酒喝抽src啊对着还两万先取五两万src啊啊哎src可以自己带吧自己带吧src喝酒对喝酒自己吧 | ✅ |
| Attention | 对呀一两万块钱到了而且你得留出了预算你得留出他们喝酒的预算一般都是喝酒喝超src啊都是还两万先去五万src啊啊哎src可以自己带吧自己带吧src喝酒对喝酒自己带吧 | 对呀一两万块钱到了而且你得留出了预算你得留出他们喝酒的预算一般都是喝酒喝超src啊都是二两万先去了两万src啊啊哎src可以自己带吧自己带吧src喝酒对喝酒自己带吧 | ⚠️ (尾部微差) |
| 项目 | NPU | CPU | 一致 |
|---|---|---|---|
| CTC | 对呀一两万块钱够了而且你得他你得留出他们喝酒的预算一般都是喝酒喝抽可以自己带吧喝酒自己带吧src对 | 对呀一两万块钱够了而且你得他你得留出他们喝酒的预算一般都是喝酒喝抽可以自己带吧喝酒自己带呗src对 | ⚠️ (1字差) |
| Attention | 对呀一两万块钱够了而且你得留出他们喝酒的预算一般都是喝酒喝酒可以自己带吧src啊src对对对对对对对对对对src嗯src嗯src对src对喝酒自己带吧 | 对呀一两万块钱够了而且你得留出他们喝酒的预算一般都是喝酒喝酒可以自己带吧可以自己带吧src啊src对对对对对对对对对对src嗯src嗯src对src嗯src对喝酒自己带吧 | ⚠️ (尾部微差) |
结论: NPU 与 CPU 的 CTC 解码结果在主干部分完全一致,Attention 解码因自回归逐 token 生成机制在长序列尾部有微小差异(self吧 vs 自己带吧),属于正常的浮点累积误差,不影响可用性。
硬件: Ascend 910B (单卡) | 音频: 8.26s @ 16kHz
| 场景 | 编码器 (ms) | 全流程 (ms) | RTF | 峰值显存 (MB) |
|---|---|---|---|---|
| 多通道 (8ch) | 28.9 | 565.1 | 0.0035 | 519.3 |
| 单通道 (1ch) | 24.9 | 470.7 | 0.0030 | 240.5 |
全流程包含 STFT 特征提取 + 编码器 + CTC 解码 + Attention 自回归解码。 RTF 按编码器耗时 / 音频时长计算(不含解码)。
| 文件 | 用途 |
|---|---|
infer_npu.py | 主推理脚本(CTC + Attention 解码) |
eval_precision.py | 精度对比 (NPU vs CPU),--npu-only / --cpu-only |
eval_perf.py | 性能基准测试(延迟、RTF、显存) |
save_output.sh | 一键运行脚本 — 执行全部推理+评测并保存输出和日志 |
output_mc.txt | 推理输出 — 多通道 (8ch) 中文转录结果 |
output_1ch.txt | 推理输出 — 单通道 (1ch) 中文转录结果 |
inference_log.txt | 运行日志 — infer_npu.py 完整输出 |
precision_log.txt | 运行日志 — eval_precision.py 完整输出 |
perf_log.txt | 运行日志 — eval_perf.py 完整输出 |
eval_precision_results.json | 精度评测数据(NPU + CPU 对比) |
eval_perf_results.json | 性能基准数据(编码器耗时、全流程耗时、RTF、显存) |
# 精度对比(分两步,避免 NPU/CPU 设备切换问题)
python3 eval_precision.py --npu-only # 先 NPU
python3 eval_precision.py --cpu-only # 再 CPU
# 性能测试
python3 eval_perf.py# 方式一:一键运行(推荐)
bash save_output.sh
# 方式二:分步运行
python3 infer_npu.py 2>&1 | tee inference_log.txt
python3 eval_precision.py --npu-only 2>&1 | tee precision_npu_log.txt
python3 eval_precision.py --cpu-only 2>&1 | tee precision_cpu_log.txt
python3 eval_perf.py 2>&1 | tee perf_log.txttorch.stft 在 NPU 上失败RuntimeError: reflection_pad1d: NPU function error原因: 输入张量 speech_lengths 取到了错误维度,导致 STFT 输入被截断。
解决: 确保 speech_lengths = tensor([speech.size(1)]) 对于 (B, T, C) 形状。
ParameterError: Window size mismatch原因: librosa 的 STFT 实现与 PyTorch 的 window padding 行为不同。
解决: 打上 stft.py 补丁,强制使用 torch.stft。
模型仅需 240~520MB,正常情况下不会 OOM。如遇到:
torch.npu.empty_cache()或使用 torch.npu.set_per_process_memory_fraction(0.9) 限制显存比例。
音频 (1/8ch, 16kHz, float32)
│
▼
MultiChannelFrontend (STFT + LogMel)
│ STFT: n_fft=512, win_length=400, hop_length=160
│ LogMel: fs=16000, n_mels=80
│ 多通道: (B,T,C) → (B*C,T,80) 拼接
▼
GlobalMVN (全局 CMVN 正则化)
│
▼
MFCCAEncoder (多通道融合 Conformer)
│ input: 80-dim Fbank
│ output: 256-dim
▼
CTC Decoder ────→ CTC 文本输出 (贪心解码)
│
▼
Transformer Decoder ────→ Attention 文本输出 (自回归解码)
│ vocab: 4950 (中文字符)
└── 融合输出 (ctc_weight=0.3)本项目基于 Apache 2.0 许可证。模型权重来自 Modelscope,遵循其原始许可证。