本模型是基于 WeNet 框架训练的 U2++ Conformer 端到端语音识别模型,使用 AISHELL-1 中文普通话数据集训练。模型导出为 ONNX 格式,支持离线语音识别。
| 属性 | 说明 |
|---|---|
| 原始框架 | PyTorch (WeNet) |
| 导出格式 | ONNX (opset 13) |
| 适配框架 | PyTorch + onnx2torch |
| NPU 推理 | torch_npu |
| 输入 | 形状 | 说明 |
|---|---|---|
| chunk | [1, T, 80] | 音频 FBank 特征,T 为帧数 |
| offset | [1] | 偏移量 |
| att_cache | [12, 4, 0, 128] | 注意力缓存(初始为空) |
| cnn_cache | [12, 1, 256, 7] | CNN 缓存(初始为零) |
| 输出 | 形状 | 说明 |
|---|---|---|
| output | [1, T', 256] | Encoder 输出 |
| probs | [1, T', 4233] | CTC 概率分布 |
| score | [N, L, 4233] | Decoder 得分 |
| 依赖 | 版本要求 |
|---|---|
| Python | >= 3.9 |
| torch | >= 2.0.0 |
| torch_npu | >= 2.0.0 |
| onnx2torch | >= 1.5.0 |
| onnxruntime | >= 1.15.0 |
| torchaudio | >= 2.0.0 |
| soundfile | >= 0.12.0 |
| numpy | >= 1.21.0 |
| modelscope | >= 1.0.0 |
本模型通过以下方式完成昇腾 NPU 适配:
onnx2torch 将 ONNX 模型转换为 PyTorch 模型torch_npu 将模型及数据迁移到昇腾 NPU 设备适配流水线:
# 安装依赖
pip install torch torchaudio torch_npu
pip install onnx onnx2torch onnxruntime
pip install soundfile librosa modelscope numpy Pillowpython3 inference.py --device cpupython3 inference.py --device npupython3 compare_cpu_npu.py使用模型自带的 5 个测试音频进行推理(16kHz 采样率,中文普通话):
| 音频文件 | 时长 | CPU 推理结果 | NPU 推理结果 |
|---|---|---|---|
| 0.wav | 13.05s | 正是因为存在绝对症... | 正是因为存在绝对症... |
| 1.wav | 5.10s | 日第加重焦恩与欧外斯外斯人 | 日第加重焦恩与欧外斯外斯人 |
| 2.wav | 4.60s | 蒋友伯被拍到带着女儿出游 | 蒋友伯被拍到带着女儿出游 |
| 3.wav | 4.15s | 周望军就落实控物价 | 周望军就落实控物价 |
| 4.wav | 31.04s | 每当青年的中身敲响了时候... | 每当青年的中身敲响了时候... |
CPU 与 NPU 推理文本完全一致,所有测试音频的识别结果完全相同。
import torch
from onnx2torch import convert as onnx2torch_convert
import torchaudio.compliance.kaldi as kaldi
import soundfile as sf
# 1. 加载 ONNX 模型并转换为 PyTorch
encoder = onnx2torch_convert("encoder.onnx").eval()
ctc = onnx2torch_convert("ctc.onnx").eval()
# 2. 将模型迁移到 NPU(如果可用)
if torch.npu.is_available():
encoder = encoder.npu()
ctc = ctc.npu()
# 3. 提取音频 FBank 特征
waveform, sr = sf.read("audio.wav")
waveform = torch.from_numpy(waveform).float().unsqueeze(0)
waveform = waveform * (1 << 15)
feats = kaldi.fbank(waveform, num_mel_bins=80, frame_length=25,
frame_shift=10, dither=0.0, sample_frequency=16000)
# feats: [T, 80]
# 4. 编码器推理
chunk = feats.unsqueeze(0) # [1, T, 80]
offset = torch.tensor([0], dtype=torch.long)
att_cache = torch.zeros(12, 4, 0, 128)
cnn_cache = torch.zeros(12, 1, 256, 7)
if torch.npu.is_available():
chunk = chunk.npu()
offset = offset.npu()
att_cache = att_cache.npu()
cnn_cache = cnn_cache.npu()
with torch.no_grad():
encoder_out = encoder(chunk, offset, att_cache, cnn_cache)[0]
# 5. CTC 解码获取字符概率
with torch.no_grad():
ctc_probs = ctc(encoder_out)
# 6. CTC 贪心解码
max_idx = torch.argmax(ctc_probs, dim=-1).squeeze(0).tolist()
# 去除 blank 和重复
result = []
prev = -1
for idx in max_idx:
if idx != prev and idx != 0: # 0 = blank
result.append(idx)
prev = idx
# 映射为文字
char_dict = {0: '', 1: '<unk>', 2: '一', ...}
text = ''.join([char_dict.get(i, '') for i in result])
print(text)python3 inference.py --device cpupython3 inference.py --device npupython3 compare_cpu_npu.py精度测试流程:
评估指标:
| 音频 | 余弦相似度 | 平均相对误差 | 最大绝对误差 | 结论 |
|---|---|---|---|---|
| 0.wav | 1.000000 | 0.497% | 3.61e-03 | PASS |
| 1.wav | 1.000000 | 0.302% | 2.58e-03 | PASS |
| 2.wav | 1.000000 | 0.192% | 1.42e-03 | PASS |
| 3.wav | 1.000000 | 0.141% | 4.28e-03 | PASS |
| 4.wav | 1.000000 | 0.244% | 5.56e-03 | PASS |
| 音频 | 余弦相似度 | 平均相对误差 | 最大绝对误差 | 结论 |
|---|---|---|---|---|
| 0.wav | 1.000000 | 0.009% | 4.64e-02 | PASS |
| 1.wav | 1.000000 | 0.008% | 2.02e-02 | PASS |
| 2.wav | 1.000000 | 0.005% | 2.11e-02 | PASS |
| 3.wav | 1.000000 | 0.004% | 6.23e-02 | PASS |
| 4.wav | 1.000000 | 0.007% | 4.81e-02 | PASS |
| 音频 | CPU 文本 | NPU 文本 | 匹配 |
|---|---|---|---|
| 0.wav | 正是因为存在绝对症... | 正是因为存在绝对症... | ✓ 完全一致 |
| 1.wav | 日第加重焦恩与欧外斯外斯人 | 日第加重焦恩与欧外斯外斯人 | ✓ 完全一致 |
| 2.wav | 蒋友伯被拍到带着女儿出游 | 蒋友伯被拍到带着女儿出游 | ✓ 完全一致 |
| 3.wav | 周望军就落实控物价 | 周望军就落实控物价 | ✓ 完全一致 |
| 4.wav | 每当青年的中身敲响了时候... | 每当青年的中身敲响了时候... | ✓ 完全一致 |
结论:NPU 与 CPU 推理结果误差 < 1%,精度满足要求。
| 音频 | 帧数 | CPU 推理时间 | NPU 推理时间 | 加速比 |
|---|---|---|---|---|
| 0.wav | 1303 | 3.841s | 4.450s | 0.86x |
| 1.wav | 508 | 3.458s | 3.159s | 1.09x |
| 2.wav | 458 | 3.262s | 3.114s | 1.05x |
| 3.wav | 413 | 3.315s | 3.089s | 1.07x |
| 4.wav | 3102 | 5.156s | 3.173s | 1.62x |
分析:

本仓库提供完整的推理脚本,支持 CPU 和 NPU 双平台推理:
# NPU 推理
python3 inference.py --device npu
# CPU 推理
python3 inference.py --device cpu推理完成后会输出推理结果和耗时,表明模型在 NPU 上推理成功。