e
gcw_GSiqzzLf/wenet-u2pp-conformer-aishell-onnx-offline-npu
模型介绍文件和版本Pull Requests讨论分析
下载使用量0

WeNet U2++ Conformer AISHELL ASR (离线版) - 昇腾 NPU 适配

模型介绍

本模型是基于 WeNet 框架训练的 U2++ Conformer 端到端语音识别模型,使用 AISHELL-1 中文普通话数据集训练。模型导出为 ONNX 格式,支持离线语音识别。

  • 任务类型:自动语音识别 (ASR / Automatic Speech Recognition)
  • 模型架构:U2++ Conformer (12 层 Encoder + CTC + Attention Decoder)
  • 输入:80 维 FBank 特征
  • 输出:中文文本(4233 个汉字 + 特殊标记)

原始模型地址

  • ModelScope: manyeyes/wenet-u2pp-conformer-aishell-onnx-offline-20210601

模型框架

属性说明
原始框架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 适配说明

本模型通过以下方式完成昇腾 NPU 适配:

  1. 使用 onnx2torch 将 ONNX 模型转换为 PyTorch 模型
  2. 利用 torch_npu 将模型及数据迁移到昇腾 NPU 设备
  3. 在 NPU 上完成 Encoder + CTC Decoder 推理
  4. 与 CPU 推理结果进行精度对比验证

适配流水线:

  • 原始模型:ONNX 格式 → onnx2torch 转换 → PyTorch 模型 → .npu() → NPU 推理

环境准备

# 安装依赖
pip install torch torchaudio torch_npu
pip install onnx onnx2torch onnxruntime
pip install soundfile librosa modelscope numpy Pillow

推理命令

CPU 推理

python3 inference.py --device cpu

NPU 推理

python3 inference.py --device npu

CPU/NPU 精度对比

python3 compare_cpu_npu.py

推理结果

使用模型自带的 5 个测试音频进行推理(16kHz 采样率,中文普通话):

音频文件时长CPU 推理结果NPU 推理结果
0.wav13.05s正是因为存在绝对症...正是因为存在绝对症...
1.wav5.10s日第加重焦恩与欧外斯外斯人日第加重焦恩与欧外斯外斯人
2.wav4.60s蒋友伯被拍到带着女儿出游蒋友伯被拍到带着女儿出游
3.wav4.15s周望军就落实控物价周望军就落实控物价
4.wav31.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)

完整推理命令

  1. 运行 CPU 推理:python3 inference.py --device cpu
  2. 运行 NPU 推理:python3 inference.py --device npu
  3. 执行精度对比:python3 compare_cpu_npu.py

CPU/NPU 精度测试方法

精度测试流程:

  1. 对每个测试音频提取 FBank 特征(80 维,帧移 10ms,帧长 25ms)
  2. 在 CPU 上完成 Encoder 和 CTC 推理,得到编码器输出和 CTC 概率
  3. 在 NPU 上完成相同推理,使用相同输入
  4. 对比编码器输出和 CTC 概率的数值差异
  5. 对比最终识别文本

评估指标:

  • 余弦相似度(Cosine Similarity)
  • 平均绝对误差(Mean Absolute Error)
  • L1/L2 误差
  • 最大绝对误差(Max Absolute Error)
  • 文本一致率

CPU/NPU 精度测试结果

编码器输出对比

音频余弦相似度平均相对误差最大绝对误差结论
0.wav1.0000000.497%3.61e-03PASS
1.wav1.0000000.302%2.58e-03PASS
2.wav1.0000000.192%1.42e-03PASS
3.wav1.0000000.141%4.28e-03PASS
4.wav1.0000000.244%5.56e-03PASS

CTC 概率输出对比

音频余弦相似度平均相对误差最大绝对误差结论
0.wav1.0000000.009%4.64e-02PASS
1.wav1.0000000.008%2.02e-02PASS
2.wav1.0000000.005%2.11e-02PASS
3.wav1.0000000.004%6.23e-02PASS
4.wav1.0000000.007%4.81e-02PASS

文本识别结果对比

音频CPU 文本NPU 文本匹配
0.wav正是因为存在绝对症...正是因为存在绝对症...✓ 完全一致
1.wav日第加重焦恩与欧外斯外斯人日第加重焦恩与欧外斯外斯人✓ 完全一致
2.wav蒋友伯被拍到带着女儿出游蒋友伯被拍到带着女儿出游✓ 完全一致
3.wav周望军就落实控物价周望军就落实控物价✓ 完全一致
4.wav每当青年的中身敲响了时候...每当青年的中身敲响了时候...✓ 完全一致

结论:NPU 与 CPU 推理结果误差 < 1%,精度满足要求。

性能测试结果

音频帧数CPU 推理时间NPU 推理时间加速比
0.wav13033.841s4.450s0.86x
1.wav5083.458s3.159s1.09x
2.wav4583.262s3.114s1.05x
3.wav4133.315s3.089s1.07x
4.wav31025.156s3.173s1.62x

分析:

  • 短音频(< 10s)NPU 推理与 CPU 推理时间接近
  • 长音频(> 30s)NPU 推理显著快于 CPU(最高加速 1.62x)
  • NPU 对于长序列推理的并行计算优势明显

模拟终端输出截图

终端输出截图

推理成功证据

本仓库提供完整的推理脚本,支持 CPU 和 NPU 双平台推理:

# NPU 推理
python3 inference.py --device npu

# CPU 推理
python3 inference.py --device cpu

推理完成后会输出推理结果和耗时,表明模型在 NPU 上推理成功。

模型标签

  • #+NPU
  • #+语音
  • #+语音识别
  • #+ASR
  • #+WeNet
  • #+Conformer
  • #+昇腾
  • #+AISHELL
  • #+中文语音识别
  • #+ONNX